2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
28 #include "../idlib/precompiled.h"
37 int sizeofRenderEntity;
38 int sizeofRenderLight;
48 void idRenderWorldLocal::StartWritingDemo( idDemoFile *demo ) {
51 // FIXME: we should track the idDemoFile locally, instead of snooping into session for it
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 );
62 // clear the archive counter on all defs
63 for ( i = 0 ; i < lightDefs.Num() ; i++ ) {
65 lightDefs[i]->archived = false;
68 for ( i = 0 ; i < entityDefs.Num() ; i++ ) {
69 if ( entityDefs[i] ) {
70 entityDefs[i]->archived = false;
75 void idRenderWorldLocal::StopWritingDemo() {
84 bool idRenderWorldLocal::ProcessDemoCommand( idDemoFile *readDemo, renderView_t *renderView, int *demoTimeOffset ) {
94 if ( !readDemo->ReadInt( (int&)dc ) ) {
95 // a demoShot may not have an endFrame, but it is still valid
101 // read the initial data
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" );
114 if ( r_showDemo.GetBool() ) {
115 common->Printf( "DC_LOADMAP: %s\n", header.mapname );
117 InitFromMap( header.mapname );
119 newMap = true; // we will need to set demoTimeOffset
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
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] );
143 if ( !readDemo->ReadInt( (int&)renderView->globalMaterial ) ) {
147 if ( r_showDemo.GetBool() ) {
148 common->Printf( "DC_RENDERVIEW: %i\n", renderView->time );
151 // possibly change the time offset if this is from a new map
152 if ( newMap && demoTimeOffset ) {
153 *demoTimeOffset = renderView->time - eventLoop->Milliseconds();
157 case DC_UPDATE_ENTITYDEF:
160 case DC_DELETE_ENTITYDEF:
161 if ( !readDemo->ReadInt( h ) ) {
164 if ( r_showDemo.GetBool() ) {
165 common->Printf( "DC_DELETE_ENTITYDEF: %i\n", h );
169 case DC_UPDATE_LIGHTDEF:
172 case DC_DELETE_LIGHTDEF:
173 if ( !readDemo->ReadInt( h ) ) {
176 if ( r_showDemo.GetBool() ) {
177 common->Printf( "DC_DELETE_LIGHTDEF: %i\n", h );
182 case DC_CAPTURE_RENDER:
183 if ( r_showDemo.GetBool() ) {
184 common->Printf( "DC_CAPTURE_RENDER\n" );
186 renderSystem->CaptureRenderToImage( readDemo->ReadHashString() );
190 if ( r_showDemo.GetBool() ) {
191 common->Printf( "DC_CROP_RENDER\n" );
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 );
200 case DC_UNCROP_RENDER:
201 if ( r_showDemo.GetBool() ) {
202 common->Printf( "DC_UNCROP\n" );
204 renderSystem->UnCrop();
208 if ( r_showDemo.GetBool() ) {
209 common->Printf( "DC_GUI_MODEL\n" );
211 tr.demoGuiModel->ReadFromDemo( readDemo );
214 case DC_DEFINE_MODEL:
216 idRenderModel *model = renderModelManager->AllocModel();
217 model->ReadFromDemoFile( session->readDemo );
218 // add to model manager, so we can find it
219 renderModelManager->AddModel( model );
221 // save it in the list to free when clearing this map
222 localModels.Append( model );
224 if ( r_showDemo.GetBool() ) {
225 common->Printf( "DC_DEFINE_MODEL\n" );
229 case DC_SET_PORTAL_STATE:
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] );
245 common->Error( "Bad token in demo stream" );
256 void idRenderWorldLocal::WriteLoadMap() {
258 // only the main renderWorld writes stuff to demos, not the wipes or
260 if ( this != session->rw ) {
264 session->writeDemo->WriteInt( DS_RENDER );
265 session->writeDemo->WriteInt( DC_LOADMAP );
268 strncpy( header.mapname, mapName.c_str(), sizeof( header.mapname ) - 1 );
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] );
278 if ( r_showDemo.GetBool() ) {
279 common->Printf( "write DC_DELETE_LIGHTDEF: %s\n", mapName.c_str() );
289 void idRenderWorldLocal::WriteVisibleDefs( const viewDef_t *viewDef ) {
290 // only the main renderWorld writes stuff to demos, not the wipes or
292 if ( this != session->rw ) {
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;
300 if ( ent->archived ) {
306 WriteRenderEntity( ent->index, &ent->parms );
307 ent->archived = true;
310 for ( viewLight_t *viewLight = viewDef->viewLights ; viewLight ; viewLight = viewLight->next ) {
311 idRenderLightLocal *light = viewLight->lightDef;
313 if ( light->archived ) {
318 WriteRenderLight( light->index, &light->parms );
319 light->archived = true;
329 void idRenderWorldLocal::WriteRenderView( const renderView_t *renderView ) {
332 // only the main renderWorld writes stuff to demos, not the wipes or
334 if ( this != session->rw ) {
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 );
360 if ( r_showDemo.GetBool() ) {
361 common->Printf( "write DC_RENDERVIEW: %i\n", renderView->time );
370 void idRenderWorldLocal::WriteFreeEntity( qhandle_t handle ) {
372 // only the main renderWorld writes stuff to demos, not the wipes or
374 if ( this != session->rw ) {
378 session->writeDemo->WriteInt( DS_RENDER );
379 session->writeDemo->WriteInt( DC_DELETE_ENTITYDEF );
380 session->writeDemo->WriteInt( handle );
382 if ( r_showDemo.GetBool() ) {
383 common->Printf( "write DC_DELETE_ENTITYDEF: %i\n", handle );
392 void idRenderWorldLocal::WriteFreeLight( qhandle_t handle ) {
394 // only the main renderWorld writes stuff to demos, not the wipes or
396 if ( this != session->rw ) {
400 session->writeDemo->WriteInt( DS_RENDER );
401 session->writeDemo->WriteInt( DC_DELETE_LIGHTDEF );
402 session->writeDemo->WriteInt( handle );
404 if ( r_showDemo.GetBool() ) {
405 common->Printf( "write DC_DELETE_LIGHTDEF: %i\n", handle );
414 void idRenderWorldLocal::WriteRenderLight( qhandle_t handle, const renderLight_t *light ) {
416 // only the main renderWorld writes stuff to demos, not the wipes or
418 if ( this != session->rw ) {
422 session->writeDemo->WriteInt( DS_RENDER );
423 session->writeDemo->WriteInt( DC_UPDATE_LIGHTDEF );
424 session->writeDemo->WriteInt( handle );
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 );
448 if ( light->prelightModel ) {
449 session->writeDemo->WriteHashString( light->prelightModel->Name() );
451 if ( light->shader ) {
452 session->writeDemo->WriteHashString( light->shader->GetName() );
454 if ( light->referenceSound ) {
455 int index = light->referenceSound->Index();
456 session->writeDemo->WriteInt( index );
459 if ( r_showDemo.GetBool() ) {
460 common->Printf( "write DC_UPDATE_LIGHTDEF: %i\n", handle );
469 void idRenderWorldLocal::ReadRenderLight( ) {
473 session->readDemo->ReadInt( index );
475 common->Error( "ReadRenderLight: index < 0 " );
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() );
502 if ( light.shader ) {
503 light.shader = declManager->FindMaterial( session->readDemo->ReadHashString() );
505 if ( light.referenceSound ) {
507 session->readDemo->ReadInt( index );
508 light.referenceSound = session->sw->EmitterForIndex( index );
511 UpdateLightDef( index, &light );
513 if ( r_showDemo.GetBool() ) {
514 common->Printf( "DC_UPDATE_LIGHTDEF: %i\n", index );
523 void idRenderWorldLocal::WriteRenderEntity( qhandle_t handle, const renderEntity_t *ent ) {
525 // only the main renderWorld writes stuff to demos, not the wipes or
527 if ( this != session->rw ) {
531 session->writeDemo->WriteInt( DS_RENDER );
532 session->writeDemo->WriteInt( DC_UPDATE_ENTITYDEF );
533 session->writeDemo->WriteInt( handle );
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 );
566 if ( ent->customShader ) {
567 session->writeDemo->WriteHashString( ent->customShader->GetName() );
569 if ( ent->customSkin ) {
570 session->writeDemo->WriteHashString( ent->customSkin->GetName() );
573 session->writeDemo->WriteHashString( ent->hModel->Name() );
575 if ( ent->referenceShader ) {
576 session->writeDemo->WriteHashString( ent->referenceShader->GetName() );
578 if ( ent->referenceSound ) {
579 int index = ent->referenceSound->Index();
580 session->writeDemo->WriteInt( index );
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] );
592 ent->decals->WriteToDemoFile( session->readDemo );
594 if ( ent->overlay ) {
595 ent->overlay->WriteToDemoFile( session->writeDemo );
601 ent->gui->WriteToDemoFile( session->writeDemo );
604 ent->gui2->WriteToDemoFile( session->writeDemo );
607 ent->gui3->WriteToDemoFile( session->writeDemo );
611 // RENDERDEMO_VERSION >= 2 ( Doom3 1.2 )
612 session->writeDemo->WriteInt( ent->timeGroup );
613 session->writeDemo->WriteInt( ent->xrayIndex );
615 if ( r_showDemo.GetBool() ) {
616 common->Printf( "write DC_UPDATE_ENTITYDEF: %i = %s\n", handle, ent->hModel ? ent->hModel->Name() : "NULL" );
625 void idRenderWorldLocal::ReadRenderEntity() {
629 session->readDemo->ReadInt( index );
631 common->Error( "ReadRenderEntity: index < 0" );
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] );
654 for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
655 session->readDemo->ReadInt( (int&)ent.gui[i] );
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 );
667 if ( ent.customShader ) {
668 ent.customShader = declManager->FindMaterial( session->readDemo->ReadHashString() );
670 if ( ent.customSkin ) {
671 ent.customSkin = declManager->FindSkin( session->readDemo->ReadHashString() );
674 ent.hModel = renderModelManager->FindModel( session->readDemo->ReadHashString() );
676 if ( ent.referenceShader ) {
677 ent.referenceShader = declManager->FindMaterial( session->readDemo->ReadHashString() );
679 if ( ent.referenceSound ) {
681 session->readDemo->ReadInt( index );
682 ent.referenceSound = session->sw->EmitterForIndex( index );
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] );
693 ent.callbackData = NULL;
697 ent.decals = idRenderModelDecal::Alloc();
698 ent.decals->ReadFromDemoFile( session->readDemo );
701 ent.overlay = idRenderModelOverlay::Alloc();
702 ent.overlay->ReadFromDemoFile( session->readDemo );
706 for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
707 if ( ent.gui[ i ] ) {
708 ent.gui[ i ] = uiManager->Alloc();
710 ent.gui[ i ]->ReadFromDemoFile( session->readDemo );
715 // >= Doom3 v1.2 only
716 if ( session->renderdemoVersion >= 2 ) {
717 session->readDemo->ReadInt( ent.timeGroup );
718 session->readDemo->ReadInt( ent.xrayIndex );
724 UpdateEntityDef( index, &ent );
726 if ( r_showDemo.GetBool() ) {
727 common->Printf( "DC_UPDATE_ENTITYDEF: %i = %s\n", index, ent.hModel ? ent.hModel->Name() : "NULL" );