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 (){
38 m_remaps = g_ptr_array_new();
39 m_shaders = g_ptr_array_new();
40 VectorSet( m_translate, 0,0,0 );
41 VectorSet( m_euler, 0,0,0 );
42 VectorSet( m_scale, 1,1,1 );
43 VectorSet( m_pivot, 0,0,0 );
44 m4x4_identity( m_transform );
45 m4x4_identity( m_inverse_transform );
48 typedef struct remap_s {
50 char m_remapbuff[64 + 1024];
54 CEntityMiscModel::~CEntityMiscModel (){
57 if ( m_name && *m_name != '\0' ) {
58 if ( !g_model_cache.DeleteByNameAndFrame( m_name,m_frame ) && m_model ) {
59 m_model->RemoveParent( this );
65 for ( i = 0; i < m_remaps->len; i++ )
66 delete (remap_t*)m_remaps->pdata[i];
67 g_ptr_array_free( m_remaps, FALSE );
69 for ( i = 0; i < m_shaders->len; i++ )
71 ( *(IShader**)m_shaders->pdata[i] )->DecRef();
72 delete (IShader**)m_shaders->pdata[i];
74 g_ptr_array_free( m_shaders, FALSE );
77 // This might be just an evasion of the actual problem
78 m_entity->model.pRender = NULL;
79 m_entity->model.pSelect = NULL;
80 m_entity->model.pEdit = NULL;
86 void CEntityMiscModel::Draw( int state, int rflags ) const {
90 memcpy( matrix, m_transform, sizeof( m4x4_t ) );
91 m4x4_transpose( matrix );
93 VectorAdd( m_pivot, m_translate, pivot );
96 // push the current modelview matrix
97 // FIXME: put in a check for stack recursion depth..
98 // or avoid recursion of opengl matrix stack
99 g_QglTable.m_pfn_qglPushMatrix();
100 // apply the parent-to-local transform
101 g_QglTable.m_pfn_qglMultMatrixf( matrix );
105 m_model->Draw( state, m_shaders, rflags );
108 g_QglTable.m_pfn_qglPopMatrix();
113 bool CEntityMiscModel::TestRay( const ray_t *ray, vec_t *dist ) const {
114 vec_t dist_start = *dist;
115 vec_t dist_local = *dist;
116 ray_t ray_local = *ray;
118 if ( !aabb_intersect_ray( &m_BBox, &ray_local, &dist_local ) ) {
123 ray_transform( &ray_local, m_inverse_transform );
124 dist_local = dist_start;
125 if ( m_model->TestRay( &ray_local, &dist_local ) ) {
129 else{*dist = dist_local; }
131 return *dist < dist_start;
137 void CEntityMiscModel::Translate( const vec3_t translation ){
138 VectorIncrement( translation, m_translate );
142 void CEntityMiscModel::Rotate( const vec3_t pivot, const vec3_t rotation ){
143 m4x4_t rotation_matrix;
145 m4x4_identity( rotation_matrix );
146 m4x4_pivoted_rotate_by_vec3( rotation_matrix, rotation, pivot );
147 m4x4_transform_point( rotation_matrix, m_translate );
149 VectorIncrement( rotation, m_euler );
154 void CEntityMiscModel::OnKeyChanged( entity_t *e, const char *key ){
157 // FIXME: keys are case-sensitive?
161 if ( strcmp( key,"model" ) == 0 ) {
162 SetName( ValueForKey( e,"model" ) );
164 else if ( strcmp( key,"_frame" ) == 0 ) {
165 SetFrame( IntForKey( e,"_frame" ) );
167 else if ( strcmp( key,"angle" ) == 0 || strcmp( key,"angles" ) == 0 ) {
168 VectorSet( m_euler, 0.f, 0.f, 0.f );
169 m_euler[2] = FloatForKey( e,"angle" );
170 value = ValueForKey( e,"angles" );
171 if ( value[0] != '\0' ) {
172 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 ) {
177 VectorSet( m_scale, 1.f, 1.f, 1.f );
178 value = ValueForKey( e,"modelscale" );
179 if ( value[0] != '\0' ) {
180 float f = atof( value );
182 VectorSet( m_scale, f, f, f );
185 Sys_FPrintf( SYS_WRN, "WARNING: ignoring 0 modelscale key\n" );
188 value = ValueForKey( e,"modelscale_vec" );
189 if ( value[0] != '\0' ) {
190 sscanf( value, "%f %f %f", &m_scale[0], &m_scale[1], &m_scale[2] );
191 if ( m_scale[0] == 0.0 && m_scale[1] == 0.0 && m_scale[2] == 0.0 ) {
192 VectorSet( m_scale, 1,1,1 );
193 Sys_FPrintf( SYS_WRN, "WARNING: ignoring 0 0 0 modelscale_vec key\n" );
198 else if ( strcmp( key,"origin" ) == 0 ) {
199 value = ValueForKey( e,"origin" );
200 sscanf( value, "%f %f %f", &m_translate[0], &m_translate[1], &m_translate[2] );
203 else if ( strncmp( key,"_remap",6 ) == 0 ) {
208 value = ValueForKey( e,key );
210 for ( i = 0; i < m_remaps->len; i++ )
212 pRemap = (remap_t*)m_remaps->pdata[i];
213 if ( strcmp( key,pRemap->m_key ) == 0 ) {
218 if ( i == m_remaps->len ) {
219 if ( value[0] == '\0' ) {
223 pRemap = new remap_t;
224 g_ptr_array_add( m_remaps, pRemap );
226 else if ( value[0] == '\0' ) {
227 g_ptr_array_remove_index_fast( m_remaps, i );
234 strncpy( pRemap->m_remapbuff,value,sizeof( pRemap->m_remapbuff ) );
235 strncpy( pRemap->m_key,key,sizeof( pRemap->m_key ) );
237 pRemap->m_remap[0] = ch = pRemap->m_remapbuff;
239 while ( *ch && *ch != ';' )
244 Sys_FPrintf( SYS_WRN, "WARNING: Shader _remap key found in misc_model without a ; character\n" );
245 g_ptr_array_remove_index_fast( m_remaps, i );
252 pRemap->m_remap[1] = ch + 1;
265 void CEntityMiscModel::SetName( const char *name ){
266 if ( m_name && *m_name != '\0' ) {
267 if ( strcmp( m_name, name ) == 0 ) {
270 if ( !g_model_cache.DeleteByNameAndFrame( m_name,m_frame ) && m_model ) {
271 m_model->RemoveParent( this );
277 m_name = new char[strlen( name ) + 1];
278 strcpy( m_name,name );
280 if ( *m_name != '\0' ) {
281 m_model = g_model_cache.GetByNameAndFrame( m_name, m_frame );
282 m_model->AddParent( this );
289 void CEntityMiscModel::SetFrame( const int frame ){
290 if ( m_frame == frame ) {
294 if ( m_name && *m_name != '\0' ) {
295 if ( !g_model_cache.DeleteByNameAndFrame( m_name,m_frame ) && m_model ) {
296 m_model->RemoveParent( this );
304 if ( *m_name != '\0' ) {
305 m_model = g_model_cache.GetByNameAndFrame( m_name, m_frame );
306 m_model->AddParent( this );
312 void CEntityMiscModel::UpdateCachedData(){
316 m4x4_identity( m_transform );
317 m4x4_pivoted_transform_by_vec3( m_transform, m_translate, m_euler, m_scale, m_pivot );
318 memcpy( m_inverse_transform, m_transform, sizeof( m4x4_t ) );
319 if ( m4x4_invert( m_inverse_transform ) == 1 ) {
320 Sys_Printf( "ERROR: Singular Matrix, cannot invert" );
323 aabb_clear( &aabb_temp );
326 aabb_extend_by_aabb( &aabb_temp, m_model->GetAABB() );
330 if ( m_entity->eclass ) {
331 VectorSet( aabb_temp.extents, m_entity->eclass->maxs[0], m_entity->eclass->maxs[1], m_entity->eclass->maxs[2] );
334 VectorSet( aabb_temp.extents, 8, 8, 8 );
338 // create an oriented BBox in world-space
339 bbox_for_oriented_aabb( &bbox_temp, &aabb_temp, m_transform, m_euler, m_scale );
340 // create an axis aligned bbox in world-space
341 aabb_for_bbox( &m_BBox, &bbox_temp );
343 aabb_update_radius( &m_BBox );
346 void CEntityMiscModel::UpdateShaders(){
347 unsigned int i, j, numSurfaces;
348 remap_t *pRemap, *pGlobRemap = NULL;
349 char *surfShaderName;
353 if ( m_shaders->len ) {
355 for ( i = 0; i < m_shaders->len; i++ )
357 g_ptr_array_remove_index_fast( m_shaders, i );
358 ( *(IShader**)m_shaders->pdata[i] )->DecRef();
359 delete (IShader**)m_shaders->pdata[i];
365 numSurfaces = m_model->GetNumSurfaces();
367 if ( numSurfaces < m_shaders->len ) {
368 // free unneeded shader pointers
369 for ( i = m_shaders->len - 1; i >= numSurfaces; i-- )
371 g_ptr_array_remove_index_fast( m_shaders, i );
372 ( *(IShader**)m_shaders->pdata[i] )->DecRef();
373 delete (IShader**)m_shaders->pdata[i];
377 // now go through our surface and find our shaders, remap if needed
378 for ( j = 0; j < numSurfaces; j++ )
380 surfShaderName = m_model->GetShaderNameForSurface( j );
382 if ( j < m_shaders->len ) {
383 pShader = (IShader **)m_shaders->pdata[j];
387 pShader = new (IShader *);
389 g_ptr_array_add( m_shaders, pShader );
392 if ( m_remaps->len ) {
393 for ( i = 0; i < m_remaps->len; i++ )
395 pRemap = (remap_t*)m_remaps->pdata[i];
396 if ( stricmp( pRemap->m_remap[0],surfShaderName ) == 0 ) {
397 // only do the shader lookups if really needed
398 if ( !( *pShader ) || stricmp( pRemap->m_remap[1],( *pShader )->getName() ) ) {
400 ( *pShader )->DecRef();
402 *pShader = QERApp_Shader_ForName( pRemap->m_remap[1] );
408 else if ( pRemap->m_remap[0][0] == '*' && pRemap->m_remap[0][1] == '\0' ) {
414 if ( !( *pShader ) || stricmp( pGlobRemap->m_remap[1],( *pShader )->getName() ) ) {
416 ( *pShader )->DecRef();
418 *pShader = QERApp_Shader_ForName( pGlobRemap->m_remap[1] );
421 else if ( i == m_remaps->len ) {
422 // Back to the default one, if needed
423 if ( !( *pShader ) || ( stricmp( surfShaderName,( *pShader )->getName() ) && !( surfShaderName[0] == '\0' ) ) ) {
425 ( *pShader )->DecRef();
427 *pShader = QERApp_Shader_ForName( surfShaderName );
433 // Model specified shader, if needed
434 if ( !( *pShader ) || ( stricmp( surfShaderName,( *pShader )->getName() ) && !( surfShaderName[0] == '\0' ) ) ) {
436 ( *pShader )->DecRef();
438 *pShader = QERApp_Shader_ForName( surfShaderName );