]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/RenderWorld_demo.cpp
Use the same OpenAL headers on all platforms.
[icculus/iodoom3.git] / neo / renderer / RenderWorld_demo.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28 #include "../idlib/precompiled.h"
29 #pragma hdrstop
30
31 #include "tr_local.h"
32
33 //#define WRITE_GUIS
34
35 typedef struct {
36         int             version;
37         int             sizeofRenderEntity;
38         int             sizeofRenderLight;
39         char    mapname[256];
40 } demoHeader_t;
41
42
43 /*
44 ==============
45 StartWritingDemo
46 ==============
47 */
48 void            idRenderWorldLocal::StartWritingDemo( idDemoFile *demo ) {
49         int             i;
50
51         // FIXME: we should track the idDemoFile locally, instead of snooping into session for it
52
53         WriteLoadMap();
54
55         // write the door portal state
56         for ( i = 0 ; i < numInterAreaPortals ; i++ ) {
57                 if ( doublePortals[i].blockingBits ) {
58                         SetPortalState( i+1, doublePortals[i].blockingBits );
59                 }
60         }
61
62         // clear the archive counter on all defs
63         for ( i = 0 ; i < lightDefs.Num() ; i++ ) {
64                 if ( lightDefs[i] ) {
65                         lightDefs[i]->archived = false;
66                 }
67         }
68         for ( i = 0 ; i < entityDefs.Num() ; i++ ) {
69                 if ( entityDefs[i] ) {
70                         entityDefs[i]->archived = false;
71                 }
72         }
73 }
74
75 void idRenderWorldLocal::StopWritingDemo() {
76 //      writeDemo = NULL;
77 }
78
79 /*
80 ==============
81 ProcessDemoCommand
82 ==============
83 */
84 bool            idRenderWorldLocal::ProcessDemoCommand( idDemoFile *readDemo, renderView_t *renderView, int *demoTimeOffset ) {
85         bool    newMap = false;
86         
87         if ( !readDemo ) {
88                 return false;
89         }
90
91         demoCommand_t   dc;
92         qhandle_t               h;
93
94         if ( !readDemo->ReadInt( (int&)dc ) ) {
95                 // a demoShot may not have an endFrame, but it is still valid
96                 return false;
97         }
98
99         switch( dc ) {
100         case DC_LOADMAP:
101                 // read the initial data
102                 demoHeader_t    header;
103
104                 readDemo->ReadInt( header.version );
105                 readDemo->ReadInt( header.sizeofRenderEntity );
106                 readDemo->ReadInt( header.sizeofRenderLight );
107                 for ( int i = 0; i < 256; i++ )
108                         readDemo->ReadChar( header.mapname[i] );
109                 // the internal version value got replaced by DS_VERSION at toplevel
110                 if ( header.version != 4 ) {
111                                 common->Error( "Demo version mismatch.\n" );
112                 }
113
114                 if ( r_showDemo.GetBool() ) {
115                         common->Printf( "DC_LOADMAP: %s\n", header.mapname );
116                 }
117                 InitFromMap( header.mapname );
118
119                 newMap = true;          // we will need to set demoTimeOffset
120
121                 break;
122
123         case DC_RENDERVIEW:
124                 readDemo->ReadInt( renderView->viewID );
125                 readDemo->ReadInt( renderView->x );
126                 readDemo->ReadInt( renderView->y );
127                 readDemo->ReadInt( renderView->width );
128                 readDemo->ReadInt( renderView->height );
129                 readDemo->ReadFloat( renderView->fov_x );
130                 readDemo->ReadFloat( renderView->fov_y );
131                 readDemo->ReadVec3( renderView->vieworg );
132                 readDemo->ReadMat3( renderView->viewaxis );
133                 readDemo->ReadBool( renderView->cramZNear );
134                 readDemo->ReadBool( renderView->forceUpdate );
135                 // binary compatibility with win32 padded structures
136                 char tmp;
137                 readDemo->ReadChar( tmp );
138                 readDemo->ReadChar( tmp );
139                 readDemo->ReadInt( renderView->time );
140                 for ( int i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ )
141                         readDemo->ReadFloat( renderView->shaderParms[i] );
142
143                 if ( !readDemo->ReadInt( (int&)renderView->globalMaterial ) ) {
144                          return false;
145                  }
146                                                                                                  
147                 if ( r_showDemo.GetBool() ) {
148                         common->Printf( "DC_RENDERVIEW: %i\n", renderView->time );
149                 }
150
151                 // possibly change the time offset if this is from a new map
152                 if ( newMap && demoTimeOffset ) {
153                         *demoTimeOffset = renderView->time - eventLoop->Milliseconds();
154                 }
155                 return false;
156
157         case DC_UPDATE_ENTITYDEF:
158                 ReadRenderEntity();
159                 break;
160         case DC_DELETE_ENTITYDEF:
161                 if ( !readDemo->ReadInt( h ) ) {
162                         return false;
163                 }
164                 if ( r_showDemo.GetBool() ) {
165                         common->Printf( "DC_DELETE_ENTITYDEF: %i\n", h );
166                 }
167                 FreeEntityDef( h );
168                 break;
169         case DC_UPDATE_LIGHTDEF:
170                 ReadRenderLight();
171                 break;
172         case DC_DELETE_LIGHTDEF:
173                 if ( !readDemo->ReadInt( h ) ) {
174                         return false;
175                 }
176                 if ( r_showDemo.GetBool() ) {
177                         common->Printf( "DC_DELETE_LIGHTDEF: %i\n", h );
178                 }
179                 FreeLightDef( h );
180                 break;
181
182         case DC_CAPTURE_RENDER:
183                 if ( r_showDemo.GetBool() ) {
184                         common->Printf( "DC_CAPTURE_RENDER\n" );
185                 }
186                 renderSystem->CaptureRenderToImage( readDemo->ReadHashString() );
187                 break;
188
189         case DC_CROP_RENDER:
190                 if ( r_showDemo.GetBool() ) {
191                         common->Printf( "DC_CROP_RENDER\n" );
192                 }
193                 int     size[3];
194                 readDemo->ReadInt( size[0] );
195                 readDemo->ReadInt( size[1] );
196                 readDemo->ReadInt( size[2] );
197                 renderSystem->CropRenderSize( size[0], size[1], size[2] != 0 );
198                 break;
199
200         case DC_UNCROP_RENDER:
201                 if ( r_showDemo.GetBool() ) {
202                         common->Printf( "DC_UNCROP\n" );
203                 }
204                 renderSystem->UnCrop();
205                 break;
206
207         case DC_GUI_MODEL:
208                 if ( r_showDemo.GetBool() ) {
209                         common->Printf( "DC_GUI_MODEL\n" );
210                 }
211                 tr.demoGuiModel->ReadFromDemo( readDemo );
212                 break;
213
214         case DC_DEFINE_MODEL:
215                 {
216                 idRenderModel   *model = renderModelManager->AllocModel();
217                 model->ReadFromDemoFile( session->readDemo );
218                 // add to model manager, so we can find it
219                 renderModelManager->AddModel( model );
220
221                 // save it in the list to free when clearing this map
222                 localModels.Append( model );
223
224                 if ( r_showDemo.GetBool() ) {
225                         common->Printf( "DC_DEFINE_MODEL\n" );
226                 }
227                 break;
228                 }
229         case DC_SET_PORTAL_STATE:
230                 {
231                         int             data[2];
232                         readDemo->ReadInt( data[0] );
233                         readDemo->ReadInt( data[1] );
234                         SetPortalState( data[0], data[1] );
235                         if ( r_showDemo.GetBool() ) {
236                                 common->Printf( "DC_SET_PORTAL_STATE: %i %i\n", data[0], data[1] );
237                         }
238                 }
239                 
240                 break;
241         case DC_END_FRAME:
242                 return true;
243
244         default:
245                 common->Error( "Bad token in demo stream" );
246         }
247
248         return false;
249 }
250
251 /*
252 ================
253 WriteLoadMap
254 ================
255 */
256 void    idRenderWorldLocal::WriteLoadMap() {
257
258         // only the main renderWorld writes stuff to demos, not the wipes or
259         // menu renders
260         if ( this != session->rw ) {
261                 return;
262         }
263
264         session->writeDemo->WriteInt( DS_RENDER );
265         session->writeDemo->WriteInt( DC_LOADMAP );
266
267         demoHeader_t    header;
268         strncpy( header.mapname, mapName.c_str(), sizeof( header.mapname ) - 1 );
269         header.version = 4;
270         header.sizeofRenderEntity = sizeof( renderEntity_t );
271         header.sizeofRenderLight = sizeof( renderLight_t );
272         session->writeDemo->WriteInt( header.version );
273         session->writeDemo->WriteInt( header.sizeofRenderEntity );
274         session->writeDemo->WriteInt( header.sizeofRenderLight );
275         for ( int i = 0; i < 256; i++ )
276                 session->writeDemo->WriteChar( header.mapname[i] );
277         
278         if ( r_showDemo.GetBool() ) {
279                 common->Printf( "write DC_DELETE_LIGHTDEF: %s\n", mapName.c_str() );
280         }
281 }
282
283 /*
284 ================
285 WriteVisibleDefs
286
287 ================
288 */
289 void    idRenderWorldLocal::WriteVisibleDefs( const viewDef_t *viewDef ) {
290         // only the main renderWorld writes stuff to demos, not the wipes or
291         // menu renders
292         if ( this != session->rw ) {
293                 return;
294         }
295
296         // make sure all necessary entities and lights are updated
297         for ( viewEntity_t *viewEnt = viewDef->viewEntitys ; viewEnt ; viewEnt = viewEnt->next ) {
298                 idRenderEntityLocal *ent = viewEnt->entityDef;
299
300                 if ( ent->archived ) {
301                         // still up to date
302                         continue;
303                 }
304
305                 // write it out
306                 WriteRenderEntity( ent->index, &ent->parms );
307                 ent->archived = true;
308         }
309
310         for ( viewLight_t *viewLight = viewDef->viewLights ; viewLight ; viewLight = viewLight->next ) {
311                 idRenderLightLocal *light = viewLight->lightDef;
312
313                 if ( light->archived ) {
314                         // still up to date
315                         continue;
316                 }
317                 // write it out
318                 WriteRenderLight( light->index, &light->parms );
319                 light->archived = true;
320         }
321 }
322
323
324 /*
325 ================
326 WriteRenderView
327 ================
328 */
329 void    idRenderWorldLocal::WriteRenderView( const renderView_t *renderView ) {
330         int i;
331
332         // only the main renderWorld writes stuff to demos, not the wipes or
333         // menu renders
334         if ( this != session->rw ) {
335                 return;
336         }
337         
338         // write the actual view command
339         session->writeDemo->WriteInt( DS_RENDER );
340         session->writeDemo->WriteInt( DC_RENDERVIEW );
341         session->writeDemo->WriteInt( renderView->viewID );
342         session->writeDemo->WriteInt( renderView->x );
343         session->writeDemo->WriteInt( renderView->y );
344         session->writeDemo->WriteInt( renderView->width );
345         session->writeDemo->WriteInt( renderView->height );
346         session->writeDemo->WriteFloat( renderView->fov_x );
347         session->writeDemo->WriteFloat( renderView->fov_y );
348         session->writeDemo->WriteVec3( renderView->vieworg );
349         session->writeDemo->WriteMat3( renderView->viewaxis );
350         session->writeDemo->WriteBool( renderView->cramZNear );
351         session->writeDemo->WriteBool( renderView->forceUpdate );
352         // binary compatibility with old win32 version writing padded structures directly to disk
353         session->writeDemo->WriteUnsignedChar( 0 );
354         session->writeDemo->WriteUnsignedChar( 0 );
355         session->writeDemo->WriteInt( renderView->time );
356         for ( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ )
357                 session->writeDemo->WriteFloat( renderView->shaderParms[i] );
358         session->writeDemo->WriteInt( (int&)renderView->globalMaterial );
359         
360         if ( r_showDemo.GetBool() ) {
361                 common->Printf( "write DC_RENDERVIEW: %i\n", renderView->time );
362         }
363 }
364
365 /*
366 ================
367 WriteFreeEntity
368 ================
369 */
370 void    idRenderWorldLocal::WriteFreeEntity( qhandle_t handle ) {
371
372         // only the main renderWorld writes stuff to demos, not the wipes or
373         // menu renders
374         if ( this != session->rw ) {
375                 return;
376         }
377
378         session->writeDemo->WriteInt( DS_RENDER );
379         session->writeDemo->WriteInt( DC_DELETE_ENTITYDEF );
380         session->writeDemo->WriteInt( handle );
381
382         if ( r_showDemo.GetBool() ) {
383                 common->Printf( "write DC_DELETE_ENTITYDEF: %i\n", handle );
384         }
385 }
386
387 /*
388 ================
389 WriteFreeLightEntity
390 ================
391 */
392 void    idRenderWorldLocal::WriteFreeLight( qhandle_t handle ) {
393
394         // only the main renderWorld writes stuff to demos, not the wipes or
395         // menu renders
396         if ( this != session->rw ) {
397                 return;
398         }
399
400         session->writeDemo->WriteInt( DS_RENDER );
401         session->writeDemo->WriteInt( DC_DELETE_LIGHTDEF );
402         session->writeDemo->WriteInt( handle );
403
404         if ( r_showDemo.GetBool() ) {
405                 common->Printf( "write DC_DELETE_LIGHTDEF: %i\n", handle );
406         }
407 }
408
409 /*
410 ================
411 WriteRenderLight
412 ================
413 */
414 void    idRenderWorldLocal::WriteRenderLight( qhandle_t handle, const renderLight_t *light ) {
415
416         // only the main renderWorld writes stuff to demos, not the wipes or
417         // menu renders
418         if ( this != session->rw ) {
419                 return;
420         }
421
422         session->writeDemo->WriteInt( DS_RENDER );
423         session->writeDemo->WriteInt( DC_UPDATE_LIGHTDEF );
424         session->writeDemo->WriteInt( handle );
425
426         session->writeDemo->WriteMat3( light->axis );
427         session->writeDemo->WriteVec3( light->origin );
428         session->writeDemo->WriteInt( light->suppressLightInViewID );
429         session->writeDemo->WriteInt( light->allowLightInViewID );
430         session->writeDemo->WriteBool( light->noShadows );
431         session->writeDemo->WriteBool( light->noSpecular );
432         session->writeDemo->WriteBool( light->pointLight );
433         session->writeDemo->WriteBool( light->parallel );
434         session->writeDemo->WriteVec3( light->lightRadius );
435         session->writeDemo->WriteVec3( light->lightCenter );
436         session->writeDemo->WriteVec3( light->target );
437         session->writeDemo->WriteVec3( light->right );
438         session->writeDemo->WriteVec3( light->up );
439         session->writeDemo->WriteVec3( light->start );
440         session->writeDemo->WriteVec3( light->end );
441         session->writeDemo->WriteInt( (int&)light->prelightModel );
442         session->writeDemo->WriteInt( light->lightId );
443         session->writeDemo->WriteInt( (int&)light->shader );
444         for ( int i = 0; i < MAX_ENTITY_SHADER_PARMS; i++)
445                 session->writeDemo->WriteFloat( light->shaderParms[i] );
446         session->writeDemo->WriteInt( (int&)light->referenceSound );
447
448         if ( light->prelightModel ) {
449                 session->writeDemo->WriteHashString( light->prelightModel->Name() );
450         }
451         if ( light->shader ) {
452                 session->writeDemo->WriteHashString( light->shader->GetName() );
453         }
454         if ( light->referenceSound ) {
455                 int     index = light->referenceSound->Index();
456                 session->writeDemo->WriteInt( index );
457         }
458
459         if ( r_showDemo.GetBool() ) {
460                 common->Printf( "write DC_UPDATE_LIGHTDEF: %i\n", handle );
461         }
462 }
463
464 /*
465 ================
466 ReadRenderLight
467 ================
468 */
469 void    idRenderWorldLocal::ReadRenderLight( ) {
470         renderLight_t   light;
471         int                             index;
472
473         session->readDemo->ReadInt( index );
474         if ( index < 0 ) {
475                 common->Error( "ReadRenderLight: index < 0 " );
476         }
477
478         session->readDemo->ReadMat3( light.axis );
479         session->readDemo->ReadVec3( light.origin );
480         session->readDemo->ReadInt( light.suppressLightInViewID );
481         session->readDemo->ReadInt( light.allowLightInViewID );
482         session->readDemo->ReadBool( light.noShadows );
483         session->readDemo->ReadBool( light.noSpecular );
484         session->readDemo->ReadBool( light.pointLight );
485         session->readDemo->ReadBool( light.parallel );
486         session->readDemo->ReadVec3( light.lightRadius );
487         session->readDemo->ReadVec3( light.lightCenter );
488         session->readDemo->ReadVec3( light.target );
489         session->readDemo->ReadVec3( light.right );
490         session->readDemo->ReadVec3( light.up );
491         session->readDemo->ReadVec3( light.start );
492         session->readDemo->ReadVec3( light.end );
493         session->readDemo->ReadInt( (int&)light.prelightModel );
494         session->readDemo->ReadInt( light.lightId );
495         session->readDemo->ReadInt( (int&)light.shader );
496         for ( int i = 0; i < MAX_ENTITY_SHADER_PARMS; i++)
497                 session->readDemo->ReadFloat( light.shaderParms[i] );
498         session->readDemo->ReadInt( (int&)light.referenceSound );
499         if ( light.prelightModel ) {
500                 light.prelightModel = renderModelManager->FindModel( session->readDemo->ReadHashString() );
501         }
502         if ( light.shader ) {
503                 light.shader = declManager->FindMaterial( session->readDemo->ReadHashString() );
504         }
505         if ( light.referenceSound ) {
506                 int     index;
507                 session->readDemo->ReadInt( index );
508                 light.referenceSound = session->sw->EmitterForIndex( index );
509         }
510
511         UpdateLightDef( index, &light );
512
513         if ( r_showDemo.GetBool() ) {
514                 common->Printf( "DC_UPDATE_LIGHTDEF: %i\n", index );
515         }
516 }
517
518 /*
519 ================
520 WriteRenderEntity
521 ================
522 */
523 void    idRenderWorldLocal::WriteRenderEntity( qhandle_t handle, const renderEntity_t *ent ) {
524
525         // only the main renderWorld writes stuff to demos, not the wipes or
526         // menu renders
527         if ( this != session->rw ) {
528                 return;
529         }
530
531         session->writeDemo->WriteInt( DS_RENDER );
532         session->writeDemo->WriteInt( DC_UPDATE_ENTITYDEF );
533         session->writeDemo->WriteInt( handle );
534         
535         session->writeDemo->WriteInt( (int&)ent->hModel );
536         session->writeDemo->WriteInt( ent->entityNum );
537         session->writeDemo->WriteInt( ent->bodyId );
538         session->writeDemo->WriteVec3( ent->bounds[0] );
539         session->writeDemo->WriteVec3( ent->bounds[1] );
540         session->writeDemo->WriteInt( (int&)ent->callback );
541         session->writeDemo->WriteInt( (int&)ent->callbackData );
542         session->writeDemo->WriteInt( ent->suppressSurfaceInViewID );
543         session->writeDemo->WriteInt( ent->suppressShadowInViewID );
544         session->writeDemo->WriteInt( ent->suppressShadowInLightID );
545         session->writeDemo->WriteInt( ent->allowSurfaceInViewID );
546         session->writeDemo->WriteVec3( ent->origin );
547         session->writeDemo->WriteMat3( ent->axis );
548         session->writeDemo->WriteInt( (int&)ent->customShader );
549         session->writeDemo->WriteInt( (int&)ent->referenceShader );
550         session->writeDemo->WriteInt( (int&)ent->customSkin );
551         session->writeDemo->WriteInt( (int&)ent->referenceSound );
552         for ( int i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ )
553                 session->writeDemo->WriteFloat( ent->shaderParms[i] );
554         for ( int i = 0; i < MAX_RENDERENTITY_GUI; i++ )
555                 session->writeDemo->WriteInt( (int&)ent->gui[i] );
556         session->writeDemo->WriteInt( (int&)ent->remoteRenderView );
557         session->writeDemo->WriteInt( ent->numJoints );
558         session->writeDemo->WriteInt( (int&)ent->joints );
559         session->writeDemo->WriteFloat( ent->modelDepthHack );
560         session->writeDemo->WriteBool( ent->noSelfShadow );
561         session->writeDemo->WriteBool( ent->noShadow );
562         session->writeDemo->WriteBool( ent->noDynamicInteractions );
563         session->writeDemo->WriteBool( ent->weaponDepthHack );
564         session->writeDemo->WriteInt( ent->forceUpdate );
565
566         if ( ent->customShader ) {
567                 session->writeDemo->WriteHashString( ent->customShader->GetName() );
568         }
569         if ( ent->customSkin ) {
570                 session->writeDemo->WriteHashString( ent->customSkin->GetName() );
571         }
572         if ( ent->hModel ) {
573                 session->writeDemo->WriteHashString( ent->hModel->Name() );
574         }
575         if ( ent->referenceShader ) {
576                 session->writeDemo->WriteHashString( ent->referenceShader->GetName() );
577         }
578         if ( ent->referenceSound ) {
579                 int     index = ent->referenceSound->Index();
580                 session->writeDemo->WriteInt( index );
581         }
582         if ( ent->numJoints ) {
583                 for ( int i = 0; i < ent->numJoints; i++) {
584                         float *data = ent->joints[i].ToFloatPtr();
585                         for ( int j = 0; j < 12; ++j)
586                                 session->writeDemo->WriteFloat( data[j] );
587                 }
588         }
589
590         /*
591         if ( ent->decals ) {
592                 ent->decals->WriteToDemoFile( session->readDemo );
593         }
594         if ( ent->overlay ) {
595                 ent->overlay->WriteToDemoFile( session->writeDemo );
596         }
597         */
598
599 #ifdef WRITE_GUIS
600         if ( ent->gui ) {
601                 ent->gui->WriteToDemoFile( session->writeDemo );
602         }
603         if ( ent->gui2 ) {
604                 ent->gui2->WriteToDemoFile( session->writeDemo );
605         }
606         if ( ent->gui3 ) {
607                 ent->gui3->WriteToDemoFile( session->writeDemo );
608         }
609 #endif
610
611         // RENDERDEMO_VERSION >= 2 ( Doom3 1.2 )
612         session->writeDemo->WriteInt( ent->timeGroup );
613         session->writeDemo->WriteInt( ent->xrayIndex );
614
615         if ( r_showDemo.GetBool() ) {
616                 common->Printf( "write DC_UPDATE_ENTITYDEF: %i = %s\n", handle, ent->hModel ? ent->hModel->Name() : "NULL" );
617         }
618 }
619
620 /*
621 ================
622 ReadRenderEntity
623 ================
624 */
625 void    idRenderWorldLocal::ReadRenderEntity() {
626         renderEntity_t          ent;
627         int                             index, i;
628
629         session->readDemo->ReadInt( index );
630         if ( index < 0 ) {
631                 common->Error( "ReadRenderEntity: index < 0" );
632         }
633
634         session->readDemo->ReadInt( (int&)ent.hModel );
635         session->readDemo->ReadInt( ent.entityNum );
636         session->readDemo->ReadInt( ent.bodyId );
637         session->readDemo->ReadVec3( ent.bounds[0] );
638         session->readDemo->ReadVec3( ent.bounds[1] );
639         session->readDemo->ReadInt( (int&)ent.callback );
640         session->readDemo->ReadInt( (int&)ent.callbackData );
641         session->readDemo->ReadInt( ent.suppressSurfaceInViewID );
642         session->readDemo->ReadInt( ent.suppressShadowInViewID );
643         session->readDemo->ReadInt( ent.suppressShadowInLightID );
644         session->readDemo->ReadInt( ent.allowSurfaceInViewID );
645         session->readDemo->ReadVec3( ent.origin );
646         session->readDemo->ReadMat3( ent.axis );
647         session->readDemo->ReadInt( (int&)ent.customShader );
648         session->readDemo->ReadInt( (int&)ent.referenceShader );
649         session->readDemo->ReadInt( (int&)ent.customSkin );
650         session->readDemo->ReadInt( (int&)ent.referenceSound );
651         for ( i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) {
652                 session->readDemo->ReadFloat( ent.shaderParms[i] );
653         }
654         for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
655                 session->readDemo->ReadInt( (int&)ent.gui[i] );
656         }
657         session->readDemo->ReadInt( (int&)ent.remoteRenderView );
658         session->readDemo->ReadInt( ent.numJoints );
659         session->readDemo->ReadInt( (int&)ent.joints );
660         session->readDemo->ReadFloat( ent.modelDepthHack );
661         session->readDemo->ReadBool( ent.noSelfShadow );
662         session->readDemo->ReadBool( ent.noShadow );
663         session->readDemo->ReadBool( ent.noDynamicInteractions );
664         session->readDemo->ReadBool( ent.weaponDepthHack );
665         session->readDemo->ReadInt( ent.forceUpdate );
666         ent.callback = NULL;
667         if ( ent.customShader ) {
668                 ent.customShader = declManager->FindMaterial( session->readDemo->ReadHashString() );
669         }
670         if ( ent.customSkin ) {
671                 ent.customSkin = declManager->FindSkin( session->readDemo->ReadHashString() );
672         }
673         if ( ent.hModel ) {
674                 ent.hModel = renderModelManager->FindModel( session->readDemo->ReadHashString() );
675         }
676         if ( ent.referenceShader ) {
677                 ent.referenceShader = declManager->FindMaterial( session->readDemo->ReadHashString() );
678         }
679         if ( ent.referenceSound ) {
680                 int     index;
681                 session->readDemo->ReadInt( index );
682                 ent.referenceSound = session->sw->EmitterForIndex( index );
683         }
684         if ( ent.numJoints ) {
685                 ent.joints = (idJointMat *)Mem_Alloc16( ent.numJoints * sizeof( ent.joints[0] ) ); 
686                 for ( int i = 0; i < ent.numJoints; i++) {
687                         float *data = ent.joints[i].ToFloatPtr();
688                         for ( int j = 0; j < 12; ++j)
689                                 session->readDemo->ReadFloat( data[j] );
690                 }
691         }
692
693         ent.callbackData = NULL;
694
695         /*
696         if ( ent.decals ) {
697                 ent.decals = idRenderModelDecal::Alloc();
698                 ent.decals->ReadFromDemoFile( session->readDemo );
699         }
700         if ( ent.overlay ) {
701                 ent.overlay = idRenderModelOverlay::Alloc();
702                 ent.overlay->ReadFromDemoFile( session->readDemo );
703         }
704         */
705
706         for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
707                 if ( ent.gui[ i ] ) {
708                         ent.gui[ i ] = uiManager->Alloc();
709 #ifdef WRITE_GUIS
710                         ent.gui[ i ]->ReadFromDemoFile( session->readDemo );
711 #endif
712                 }
713         }
714
715         // >= Doom3 v1.2 only
716         if ( session->renderdemoVersion >= 2 ) {
717                 session->readDemo->ReadInt( ent.timeGroup );
718                 session->readDemo->ReadInt( ent.xrayIndex );
719         } else {
720                 ent.timeGroup = 0;
721                 ent.xrayIndex = 0;
722         }
723
724         UpdateEntityDef( index, &ent );
725
726         if ( r_showDemo.GetBool() ) {
727                 common->Printf( "DC_UPDATE_ENTITYDEF: %i = %s\n", index, ent.hModel ? ent.hModel->Name() : "NULL" );
728         }
729 }