]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/Model_prt.cpp
Use the same OpenAL headers on all platforms.
[icculus/iodoom3.git] / neo / renderer / Model_prt.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
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "tr_local.h"
33 #include "Model_local.h"
34
35 static const char *parametricParticle_SnapshotName = "_ParametricParticle_Snapshot_";
36
37 /*
38 ====================
39 idRenderModelPrt::idRenderModelPrt
40 ====================
41 */
42 idRenderModelPrt::idRenderModelPrt() {
43         particleSystem = NULL;
44 }
45
46 /*
47 ====================
48 idRenderModelPrt::InitFromFile
49 ====================
50 */
51 void idRenderModelPrt::InitFromFile( const char *fileName ) {
52         name = fileName;
53         particleSystem = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, fileName ) );
54 }
55
56 /*
57 =================
58 idRenderModelPrt::TouchData
59 =================
60 */
61 void idRenderModelPrt::TouchData( void ) {
62         // Ensure our particle system is added to the list of referenced decls
63         particleSystem = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, name ) );
64 }
65
66 /*
67 ====================
68 idRenderModelPrt::InstantiateDynamicModel
69 ====================
70 */
71 idRenderModel *idRenderModelPrt::InstantiateDynamicModel( const struct renderEntity_s *renderEntity, const struct viewDef_s *viewDef, idRenderModel *cachedModel ) {
72         idRenderModelStatic     *staticModel;
73
74         if ( cachedModel && !r_useCachedDynamicModels.GetBool() ) {
75                 delete cachedModel;
76                 cachedModel = NULL;
77         }
78
79         // this may be triggered by a model trace or other non-view related source, to which we should look like an empty model
80         if ( renderEntity == NULL || viewDef == NULL ) {
81                 delete cachedModel;
82                 return NULL;
83         }
84
85         if ( r_skipParticles.GetBool() ) {
86                 delete cachedModel;
87                 return NULL;
88         }
89
90         /*
91         // if the entire system has faded out
92         if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] && viewDef->renderView.time * 0.001f >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] ) {
93                 delete cachedModel;
94                 return NULL;
95         }
96         */
97
98         if ( cachedModel != NULL ) {
99
100                 assert( dynamic_cast<idRenderModelStatic *>(cachedModel) != NULL );
101                 assert( idStr::Icmp( cachedModel->Name(), parametricParticle_SnapshotName ) == 0 );
102
103                 staticModel = static_cast<idRenderModelStatic *>(cachedModel);
104
105         } else {
106
107                 staticModel = new idRenderModelStatic;
108                 staticModel->InitEmpty( parametricParticle_SnapshotName );
109         }
110
111         particleGen_t g;
112
113         g.renderEnt = renderEntity;
114         g.renderView = &viewDef->renderView;
115         g.origin.Zero();
116         g.axis.Identity();
117
118         for ( int stageNum = 0; stageNum < particleSystem->stages.Num(); stageNum++ ) {
119                 idParticleStage *stage = particleSystem->stages[stageNum];
120
121                 if ( !stage->material ) {
122                         continue;
123                 }
124                 if ( !stage->cycleMsec ) {
125                         continue;
126                 }
127                 if ( stage->hidden ) {          // just for gui particle editor use
128                         staticModel->DeleteSurfaceWithId( stageNum );
129                         continue;
130                 }
131
132                 idRandom steppingRandom, steppingRandom2;
133
134                 int stageAge = g.renderView->time + renderEntity->shaderParms[SHADERPARM_TIMEOFFSET] * 1000 - stage->timeOffset * 1000;
135                 int     stageCycle = stageAge / stage->cycleMsec;
136                 int     inCycleTime = stageAge - stageCycle * stage->cycleMsec;
137
138                 // some particles will be in this cycle, some will be in the previous cycle
139                 steppingRandom.SetSeed( (( stageCycle << 10 ) & idRandom::MAX_RAND) ^ (int)( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND )  );
140                 steppingRandom2.SetSeed( (( (stageCycle-1) << 10 ) & idRandom::MAX_RAND) ^ (int)( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND )  );
141
142                 int     count = stage->totalParticles * stage->NumQuadsPerParticle();
143
144                 int surfaceNum;
145                 modelSurface_t *surf;
146
147                 if ( staticModel->FindSurfaceWithId( stageNum, surfaceNum ) ) {
148                         surf = &staticModel->surfaces[surfaceNum];
149                         R_FreeStaticTriSurfVertexCaches( surf->geometry );
150                 } else {
151                         surf = &staticModel->surfaces.Alloc();
152                         surf->id = stageNum;
153                         surf->shader = stage->material;
154                         surf->geometry = R_AllocStaticTriSurf();
155                         R_AllocStaticTriSurfVerts( surf->geometry, 4 * count );
156                         R_AllocStaticTriSurfIndexes( surf->geometry, 6 * count );
157                         R_AllocStaticTriSurfPlanes( surf->geometry, 6 * count );
158                 }
159
160                 int numVerts = 0;
161                 idDrawVert *verts = surf->geometry->verts;
162
163                 for ( int index = 0; index < stage->totalParticles; index++ ) {
164                         g.index = index;
165
166                         // bump the random
167                         steppingRandom.RandomInt();
168                         steppingRandom2.RandomInt();
169
170                         // calculate local age for this index 
171                         int     bunchOffset = stage->particleLife * 1000 * stage->spawnBunching * index / stage->totalParticles;
172
173                         int particleAge = stageAge - bunchOffset;
174                         int     particleCycle = particleAge / stage->cycleMsec;
175                         if ( particleCycle < 0 ) {
176                                 // before the particleSystem spawned
177                                 continue;
178                         }
179                         if ( stage->cycles && particleCycle >= stage->cycles ) {
180                                 // cycled systems will only run cycle times
181                                 continue;
182                         }
183
184                         if ( particleCycle == stageCycle ) {
185                                 g.random = steppingRandom;
186                         } else {
187                                 g.random = steppingRandom2;
188                         }
189
190                         int     inCycleTime = particleAge - particleCycle * stage->cycleMsec;
191
192                         if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] && 
193                                 g.renderView->time - inCycleTime >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME]*1000 ) {
194                                 // don't fire any more particles
195                                 continue;
196                         }
197
198                         // supress particles before or after the age clamp
199                         g.frac = (float)inCycleTime / ( stage->particleLife * 1000 );
200                         if ( g.frac < 0.0f ) {
201                                 // yet to be spawned
202                                 continue;
203                         }
204                         if ( g.frac > 1.0f ) {
205                                 // this particle is in the deadTime band
206                                 continue;
207                         }
208
209                         // this is needed so aimed particles can calculate origins at different times
210                         g.originalRandom = g.random;
211
212                         g.age = g.frac * stage->particleLife;
213
214                         // if the particle doesn't get drawn because it is faded out or beyond a kill region, don't increment the verts
215                         numVerts += stage->CreateParticle( &g, verts + numVerts );
216                 }
217
218                 // numVerts must be a multiple of 4
219                 assert( ( numVerts & 3 ) == 0 && numVerts <= 4 * count );
220
221                 // build the indexes
222                 int     numIndexes = 0;
223                 glIndex_t *indexes = surf->geometry->indexes;
224                 for ( int i = 0; i < numVerts; i += 4 ) {
225                         indexes[numIndexes+0] = i;
226                         indexes[numIndexes+1] = i+2;
227                         indexes[numIndexes+2] = i+3;
228                         indexes[numIndexes+3] = i;
229                         indexes[numIndexes+4] = i+3;
230                         indexes[numIndexes+5] = i+1;
231                         numIndexes += 6;
232                 }
233
234                 surf->geometry->tangentsCalculated = false;
235                 surf->geometry->facePlanesCalculated = false;
236                 surf->geometry->numVerts = numVerts;
237                 surf->geometry->numIndexes = numIndexes;
238                 surf->geometry->bounds = stage->bounds;         // just always draw the particles
239         }
240
241         return staticModel;
242 }
243
244 /*
245 ====================
246 idRenderModelPrt::IsDynamicModel
247 ====================
248 */
249 dynamicModel_t idRenderModelPrt::IsDynamicModel() const {
250         return DM_CONTINUOUS;
251 }
252
253 /*
254 ====================
255 idRenderModelPrt::Bounds
256 ====================
257 */
258 idBounds idRenderModelPrt::Bounds( const struct renderEntity_s *ent ) const {
259         return particleSystem->bounds;
260 }
261
262 /*
263 ====================
264 idRenderModelPrt::DepthHack
265 ====================
266 */
267 float idRenderModelPrt::DepthHack() const {
268         return particleSystem->depthHack;
269 }
270
271 /*
272 ====================
273 idRenderModelPrt::Memory
274 ====================
275 */
276 int idRenderModelPrt::Memory() const {
277         int total = 0;
278
279         total += idRenderModelStatic::Memory();
280
281         if ( particleSystem ) {
282                 total += sizeof( *particleSystem );
283
284                 for ( int i = 0; i < particleSystem->stages.Num(); i++ ) {
285                         total += sizeof( particleSystem->stages[i] );
286                 }
287         }
288
289         return total;
290 }