2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "entitymodel.h"
26 extern CModelManager g_model_cache;
29 // CEntityMiscModel implementation
32 CEntityMiscModel::CEntityMiscModel ()
39 m_remaps = g_ptr_array_new ();
40 m_shaders = g_ptr_array_new ();
41 VectorSet(m_translate, 0,0,0);
42 VectorSet(m_euler, 0,0,0);
43 VectorSet(m_scale, 1,1,1);
44 VectorSet(m_pivot, 0,0,0);
45 m4x4_identity(m_transform);
46 m4x4_identity(m_inverse_transform);
49 typedef struct remap_s {
51 char m_remapbuff[64+1024];
55 CEntityMiscModel::~CEntityMiscModel ()
59 if(m_name && *m_name != '\0') {
60 if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model )
61 m_model->RemoveParent( this );
66 for( i = 0; i < m_remaps->len; i++ )
67 delete (remap_t*)m_remaps->pdata[i];
68 g_ptr_array_free(m_remaps, FALSE);
70 for( i = 0; i < m_shaders->len; i++ )
72 (*(IShader**)m_shaders->pdata[i])->DecRef();
73 delete (IShader**)m_shaders->pdata[i];
75 g_ptr_array_free(m_shaders, FALSE);
78 // This might be just an evasion of the actual problem
79 m_entity->model.pRender = NULL;
80 m_entity->model.pSelect = NULL;
81 m_entity->model.pEdit = NULL;
87 void CEntityMiscModel::Draw(int state, int rflags) const
92 memcpy(matrix, m_transform, sizeof(m4x4_t));
93 m4x4_transpose(matrix);
95 VectorAdd(m_pivot, m_translate, pivot);
98 // push the current modelview matrix
99 // FIXME: put in a check for stack recursion depth..
100 // or avoid recursion of opengl matrix stack
101 g_QglTable.m_pfn_qglPushMatrix();
102 // apply the parent-to-local transform
103 g_QglTable.m_pfn_qglMultMatrixf(matrix);
107 m_model->Draw(state, m_shaders, rflags);
109 g_QglTable.m_pfn_qglPopMatrix();
114 bool CEntityMiscModel::TestRay(const ray_t *ray, vec_t *dist) const
116 vec_t dist_start = *dist;
117 vec_t dist_local = *dist;
118 ray_t ray_local = *ray;
120 if (!aabb_intersect_ray(&m_BBox, &ray_local, &dist_local))
124 ray_transform(&ray_local, m_inverse_transform);
125 dist_local = dist_start;
126 if(m_model->TestRay(&ray_local, &dist_local))
128 } else *dist = dist_local;
130 return *dist < dist_start;
136 void CEntityMiscModel::Translate(const vec3_t translation)
138 VectorIncrement(translation, m_translate);
142 void CEntityMiscModel::Rotate(const vec3_t pivot, const vec3_t rotation)
144 m4x4_t rotation_matrix;
146 m4x4_identity(rotation_matrix);
147 m4x4_pivoted_rotate_by_vec3(rotation_matrix, rotation, pivot);
148 m4x4_transform_point(rotation_matrix, m_translate);
150 VectorIncrement(rotation, m_euler);
155 void CEntityMiscModel::OnKeyChanged(entity_t *e, const char *key)
159 // FIXME: keys are case-sensitive?
163 if(strcmp(key,"model") == 0)
164 SetName(ValueForKey(e,"model"));
165 else if(strcmp(key,"_frame") == 0)
166 SetFrame(IntForKey(e,"_frame"));
167 else if(strcmp(key,"angle") == 0 || strcmp(key,"angles") == 0)
169 VectorSet(m_euler, 0.f, 0.f, 0.f);
170 m_euler[2] = FloatForKey(e,"angle");
171 value = ValueForKey(e,"angles");
172 if (value[0] != '\0')
173 sscanf (value, "%f %f %f", &m_euler[0], &m_euler[2], &m_euler[1]);
176 else if(strcmp(key,"modelscale") == 0 || strcmp(key,"modelscale_vec") == 0)
178 VectorSet(m_scale, 1.f, 1.f, 1.f);
179 value = ValueForKey(e,"modelscale");
180 if (value[0] != '\0')
182 float f = atof(value);
184 VectorSet(m_scale, f, f, f);
186 Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 modelscale key\n");
188 value = ValueForKey(e,"modelscale_vec");
189 if (value[0] != '\0')
191 sscanf (value, "%f %f %f", &m_scale[0], &m_scale[1], &m_scale[2]);
192 if (m_scale[0] == 0.0 && m_scale[1] == 0.0 && m_scale[2] == 0.0)
194 VectorSet(m_scale, 1,1,1);
195 Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 0 0 modelscale_vec key\n");
200 else if(strcmp(key,"origin") == 0)
202 value = ValueForKey(e,"origin");
203 sscanf(value, "%f %f %f", &m_translate[0], &m_translate[1], &m_translate[2]);
206 else if(strncmp(key,"_remap",6) == 0)
212 value = ValueForKey(e,key);
214 for(i=0; i<m_remaps->len; i++)
216 pRemap = (remap_t*)m_remaps->pdata[i];
217 if(strcmp(key,pRemap->m_key) == 0)
221 if( i == m_remaps->len )
223 if( value[0] == '\0' )
226 pRemap = new remap_t;
227 g_ptr_array_add(m_remaps, pRemap);
229 else if( value[0] == '\0' )
231 g_ptr_array_remove_index_fast(m_remaps, i);
238 strncpy(pRemap->m_remapbuff,value,sizeof(pRemap->m_remapbuff));
239 strncpy(pRemap->m_key,key,sizeof(pRemap->m_key));
241 pRemap->m_remap[0] = ch = pRemap->m_remapbuff;
243 while( *ch && *ch != ';' )
249 Sys_FPrintf(SYS_WRN, "WARNING: Shader _remap key found in misc_model without a ; character\n" );
250 g_ptr_array_remove_index_fast(m_remaps, i);
257 pRemap->m_remap[1] = ch + 1;
270 void CEntityMiscModel::SetName(const char *name)
272 if(m_name && *m_name != '\0') {
273 if(strcmp(m_name, name) == 0)
275 if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model )
276 m_model->RemoveParent( this );
281 m_name = new char[strlen(name)+1];
284 if(*m_name != '\0') {
285 m_model = g_model_cache.GetByNameAndFrame(m_name, m_frame);
286 m_model->AddParent( this );
293 void CEntityMiscModel::SetFrame(const int frame)
295 if( m_frame == frame )
298 if(m_name && *m_name != '\0') {
299 if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model )
300 m_model->RemoveParent( this );
307 if(*m_name != '\0') {
308 m_model = g_model_cache.GetByNameAndFrame(m_name, m_frame);
309 m_model->AddParent( this );
315 void CEntityMiscModel::UpdateCachedData()
320 m4x4_identity(m_transform);
321 m4x4_pivoted_transform_by_vec3(m_transform, m_translate, m_euler, m_scale, m_pivot);
322 memcpy(m_inverse_transform, m_transform, sizeof(m4x4_t));
323 if(m4x4_invert(m_inverse_transform) == 1) {
324 Sys_Printf("ERROR: Singular Matrix, cannot invert");
327 aabb_clear(&aabb_temp);
330 aabb_extend_by_aabb(&aabb_temp, m_model->GetAABB());
333 if (m_entity->eclass)
334 VectorSet(aabb_temp.extents, m_entity->eclass->maxs[0], m_entity->eclass->maxs[1], m_entity->eclass->maxs[2]);
336 VectorSet(aabb_temp.extents, 8, 8, 8);
339 // create an oriented BBox in world-space
340 bbox_for_oriented_aabb(&bbox_temp, &aabb_temp, m_transform, m_euler, m_scale);
341 // create an axis aligned bbox in world-space
342 aabb_for_bbox(&m_BBox, &bbox_temp);
344 aabb_update_radius(&m_BBox);
347 void CEntityMiscModel::UpdateShaders()
349 unsigned int i, j, numSurfaces;
350 remap_t *pRemap, *pGlobRemap = NULL;
351 char *surfShaderName;
359 for( i = 0; i < m_shaders->len; i++ )
361 g_ptr_array_remove_index_fast(m_shaders, i);
362 (*(IShader**)m_shaders->pdata[i])->DecRef();
363 delete (IShader**)m_shaders->pdata[i];
369 numSurfaces = m_model->GetNumSurfaces();
371 if( numSurfaces < m_shaders->len )
373 // free unneeded shader pointers
374 for( i = m_shaders->len - 1; i >= numSurfaces; i-- )
376 g_ptr_array_remove_index_fast(m_shaders, i);
377 (*(IShader**)m_shaders->pdata[i])->DecRef();
378 delete (IShader**)m_shaders->pdata[i];
382 // now go through our surface and find our shaders, remap if needed
383 for( j = 0; j < numSurfaces; j++ )
385 surfShaderName = m_model->GetShaderNameForSurface(j);
387 if( j < m_shaders->len )
389 pShader = (IShader **)m_shaders->pdata[j];
393 pShader = new (IShader *);
395 g_ptr_array_add(m_shaders, pShader);
400 for( i = 0; i < m_remaps->len; i++ )
402 pRemap = (remap_t*)m_remaps->pdata[i];
403 if( stricmp(pRemap->m_remap[0],surfShaderName) == 0 )
405 // only do the shader lookups if really needed
406 if( !(*pShader) || stricmp(pRemap->m_remap[1],(*pShader)->getName()) )
409 (*pShader)->DecRef();
410 *pShader = QERApp_Shader_ForName(pRemap->m_remap[1]);
416 else if( pRemap->m_remap[0][0] == '*' && pRemap->m_remap[0][1] == '\0' )
422 if( !(*pShader) || stricmp(pGlobRemap->m_remap[1],(*pShader)->getName()) )
425 (*pShader)->DecRef();
426 *pShader = QERApp_Shader_ForName(pGlobRemap->m_remap[1]);
429 else if( i == m_remaps->len )
431 // Back to the default one, if needed
432 if( !(*pShader) || (stricmp(surfShaderName,(*pShader)->getName()) && !(surfShaderName[0] == '\0')) )
435 (*pShader)->DecRef();
436 *pShader = QERApp_Shader_ForName(surfShaderName);
442 // Model specified shader, if needed
443 if( !(*pShader) || (stricmp(surfShaderName,(*pShader)->getName()) && !(surfShaderName[0] == '\0')) )
446 (*pShader)->DecRef();
447 *pShader = QERApp_Shader_ForName(surfShaderName);