doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Model_liquid.cpp
Go to the documentation of this file.
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 #define LIQUID_MAX_SKIP_FRAMES 5
36 #define LIQUID_MAX_TYPES 3
37 
38 /*
39 ====================
40 idRenderModelLiquid::idRenderModelLiquid
41 ====================
42 */
44  verts_x = 32;
45  verts_y = 32;
46  scale_x = 256.0f;
47  scale_y = 256.0f;
48  liquid_type = 0;
49  density = 0.97f;
50  drop_height = 4;
51  drop_radius = 4;
52  drop_delay = 1000;
54  update_tics = 33; // ~30 hz
55  time = 0;
56  seed = 0;
57 
58  random.SetSeed( 0 );
59 }
60 
61 /*
62 ====================
63 idRenderModelLiquid::GenerateSurface
64 ====================
65 */
67  srfTriangles_t *tri;
68  int i, base;
69  idDrawVert *vert;
70  modelSurface_t surf;
71  float inv_lerp;
72 
73  inv_lerp = 1.0f - lerp;
74  vert = verts.Ptr();
75  for( i = 0; i < verts.Num(); i++, vert++ ) {
76  vert->xyz.z = page1[ i ] * lerp + page2[ i ] * inv_lerp;
77  }
78 
82 
83  tri = R_AllocStaticTriSurf();
84 
85  // note that some of the data is references, and should not be freed
86  tri->deformedSurface = true;
87 
89  tri->indexes = deformInfo->indexes;
98 
100  R_AllocStaticTriSurfVerts( tri, tri->numVerts );
101  SIMDProcessor->Memcpy( tri->verts, verts.Ptr(), deformInfo->numSourceVerts * sizeof(tri->verts[0]) );
102 
103  // replicate the mirror seam vertexes
105  for ( i = 0 ; i < deformInfo->numMirroredVerts ; i++ ) {
106  tri->verts[base + i] = tri->verts[deformInfo->mirroredVerts[i]];
107  }
108 
109  R_BoundTriSurf( tri );
110 
111  // If a surface is going to be have a lighting interaction generated, it will also have to call
112  // R_DeriveTangents() to get normals, tangents, and face planes. If it only
113  // needs shadows generated, it will only have to generate face planes. If it only
114  // has ambient drawing, or is culled, no additional work will be necessary
115  if ( !r_useDeferredTangents.GetBool() ) {
116  // set face planes, vertex normals, tangents
117  R_DeriveTangents( tri );
118  }
119 
120  surf.geometry = tri;
121  surf.shader = shader;
122 
123  return surf;
124 }
125 
126 /*
127 ====================
128 idRenderModelLiquid::WaterDrop
129 ====================
130 */
131 void idRenderModelLiquid::WaterDrop( int x, int y, float *page ) {
132  int cx, cy;
133  int left,top,right,bottom;
134  int square;
135  int radsquare = drop_radius * drop_radius;
136  float invlength = 1.0f / ( float )radsquare;
137  float dist;
138 
139  if ( x < 0 ) {
140  x = 1 + drop_radius + random.RandomInt( verts_x - 2 * drop_radius - 1 );
141  }
142  if ( y < 0 ) {
143  y = 1 + drop_radius + random.RandomInt( verts_y - 2 * drop_radius - 1 );
144  }
145 
146  left=-drop_radius; right = drop_radius;
147  top=-drop_radius; bottom = drop_radius;
148 
149  // Perform edge clipping...
150  if ( x - drop_radius < 1 ) {
151  left -= (x-drop_radius-1);
152  }
153  if ( y - drop_radius < 1 ) {
154  top -= (y-drop_radius-1);
155  }
156  if ( x + drop_radius > verts_x - 1 ) {
157  right -= (x+drop_radius-verts_x+1);
158  }
159  if ( y + drop_radius > verts_y - 1 ) {
160  bottom-= (y+drop_radius-verts_y+1);
161  }
162 
163  for ( cy = top; cy < bottom; cy++ ) {
164  for ( cx = left; cx < right; cx++ ) {
165  square = cy*cy + cx*cx;
166  if ( square < radsquare ) {
167  dist = idMath::Sqrt( (float)square * invlength );
168  page[verts_x*(cy+y) + cx+x] += idMath::Cos16( dist * idMath::PI * 0.5f ) * drop_height;
169  }
170  }
171  }
172 }
173 
174 /*
175 ====================
176 idRenderModelLiquid::IntersectBounds
177 ====================
178 */
179 void idRenderModelLiquid::IntersectBounds( const idBounds &bounds, float displacement ) {
180  int cx, cy;
181  int left,top,right,bottom;
182  float up, down;
183  float *pos;
184 
185  left = ( int )( bounds[ 0 ].x / scale_x );
186  right = ( int )( bounds[ 1 ].x / scale_x );
187  top = ( int )( bounds[ 0 ].y / scale_y );
188  bottom = ( int )( bounds[ 1 ].y / scale_y );
189  down = bounds[ 0 ].z;
190  up = bounds[ 1 ].z;
191 
192  if ( ( right < 1 ) || ( left >= verts_x ) || ( bottom < 1 ) || ( top >= verts_x ) ) {
193  return;
194  }
195 
196  // Perform edge clipping...
197  if ( left < 1 ) {
198  left = 1;
199  }
200  if ( right >= verts_x ) {
201  right = verts_x - 1;
202  }
203  if ( top < 1 ) {
204  top = 1;
205  }
206  if ( bottom >= verts_y ) {
207  bottom = verts_y - 1;
208  }
209 
210  for ( cy = top; cy < bottom; cy++ ) {
211  for ( cx = left; cx < right; cx++ ) {
212  pos = &page1[ verts_x * cy + cx ];
213  if ( *pos > down ) {//&& ( *pos < up ) ) {
214  *pos = down;
215  }
216  }
217  }
218 }
219 
220 /*
221 ====================
222 idRenderModelLiquid::Update
223 ====================
224 */
226  int x, y;
227  float *p2;
228  float *p1;
229  float value;
230 
231  time += update_tics;
232 
233  idSwap( page1, page2 );
234 
235  if ( time > nextDropTime ) {
236  WaterDrop( -1, -1, page2 );
238  } else if ( time < nextDropTime - drop_delay ) {
240  }
241 
242  p1 = page1;
243  p2 = page2;
244 
245  switch( liquid_type ) {
246  case 0 :
247  for ( y = 1; y < verts_y - 1; y++ ) {
248  p2 += verts_x;
249  p1 += verts_x;
250  for ( x = 1; x < verts_x - 1; x++ ) {
251  value =
252  ( p2[ x + verts_x ] +
253  p2[ x - verts_x ] +
254  p2[ x + 1 ] +
255  p2[ x - 1 ] +
256  p2[ x - verts_x - 1 ] +
257  p2[ x - verts_x + 1 ] +
258  p2[ x + verts_x - 1 ] +
259  p2[ x + verts_x + 1 ] +
260  p2[ x ] ) * ( 2.0f / 9.0f ) -
261  p1[ x ];
262 
263  p1[ x ] = value * density;
264  }
265  }
266  break;
267 
268  case 1 :
269  for ( y = 1; y < verts_y - 1; y++ ) {
270  p2 += verts_x;
271  p1 += verts_x;
272  for ( x = 1; x < verts_x - 1; x++ ) {
273  value =
274  ( p2[ x + verts_x ] +
275  p2[ x - verts_x ] +
276  p2[ x + 1 ] +
277  p2[ x - 1 ] +
278  p2[ x - verts_x - 1 ] +
279  p2[ x - verts_x + 1 ] +
280  p2[ x + verts_x - 1 ] +
281  p2[ x + verts_x + 1 ] ) * 0.25f -
282  p1[ x ];
283 
284  p1[ x ] = value * density;
285  }
286  }
287  break;
288 
289  case 2 :
290  for ( y = 1; y < verts_y - 1; y++ ) {
291  p2 += verts_x;
292  p1 += verts_x;
293  for ( x = 1; x < verts_x - 1; x++ ) {
294  value =
295  ( p2[ x + verts_x ] +
296  p2[ x - verts_x ] +
297  p2[ x + 1 ] +
298  p2[ x - 1 ] +
299  p2[ x - verts_x - 1 ] +
300  p2[ x - verts_x + 1 ] +
301  p2[ x + verts_x - 1 ] +
302  p2[ x + verts_x + 1 ] +
303  p2[ x ] ) * ( 1.0f / 9.0f );
304 
305  p1[ x ] = value * density;
306  }
307  }
308  break;
309  }
310 }
311 
312 /*
313 ====================
314 idRenderModelLiquid::Reset
315 ====================
316 */
318  int i, x, y;
319 
320  if ( pages.Num() < 2 * verts_x * verts_y ) {
321  return;
322  }
323 
324  nextDropTime = 0;
325  time = 0;
326  random.SetSeed( seed );
327 
328  page1 = pages.Ptr();
329  page2 = page1 + verts_x * verts_y;
330 
331  for ( i = 0, y = 0; y < verts_y; y++ ) {
332  for ( x = 0; x < verts_x; x++, i++ ) {
333  page1[ i ] = 0.0f;
334  page2[ i ] = 0.0f;
335  verts[ i ].xyz.z = 0.0f;
336  }
337  }
338 }
339 
340 /*
341 ====================
342 idRenderModelLiquid::InitFromFile
343 ====================
344 */
345 void idRenderModelLiquid::InitFromFile( const char *fileName ) {
346  int i, x, y;
347  idToken token;
349  idList<int> tris;
350  float size_x, size_y;
351  float rate;
352 
353  name = fileName;
354 
355  if ( !parser.LoadFile( fileName ) ) {
357  return;
358  }
359 
360  size_x = scale_x * verts_x;
361  size_y = scale_y * verts_y;
362 
363  while( parser.ReadToken( &token ) ) {
364  if ( !token.Icmp( "seed" ) ) {
365  seed = parser.ParseInt();
366  } else if ( !token.Icmp( "size_x" ) ) {
367  size_x = parser.ParseFloat();
368  } else if ( !token.Icmp( "size_y" ) ) {
369  size_y = parser.ParseFloat();
370  } else if ( !token.Icmp( "verts_x" ) ) {
371  verts_x = parser.ParseFloat();
372  if ( verts_x < 2 ) {
373  parser.Warning( "Invalid # of verts. Using default model." );
375  return;
376  }
377  } else if ( !token.Icmp( "verts_y" ) ) {
378  verts_y = parser.ParseFloat();
379  if ( verts_y < 2 ) {
380  parser.Warning( "Invalid # of verts. Using default model." );
382  return;
383  }
384  } else if ( !token.Icmp( "liquid_type" ) ) {
385  liquid_type = parser.ParseInt() - 1;
386  if ( ( liquid_type < 0 ) || ( liquid_type >= LIQUID_MAX_TYPES ) ) {
387  parser.Warning( "Invalid liquid_type. Using default model." );
389  return;
390  }
391  } else if ( !token.Icmp( "density" ) ) {
392  density = parser.ParseFloat();
393  } else if ( !token.Icmp( "drop_height" ) ) {
394  drop_height = parser.ParseFloat();
395  } else if ( !token.Icmp( "drop_radius" ) ) {
396  drop_radius = parser.ParseInt();
397  } else if ( !token.Icmp( "drop_delay" ) ) {
398  drop_delay = SEC2MS( parser.ParseFloat() );
399  } else if ( !token.Icmp( "shader" ) ) {
400  parser.ReadToken( &token );
401  shader = declManager->FindMaterial( token );
402  } else if ( !token.Icmp( "seed" ) ) {
403  seed = parser.ParseInt();
404  } else if ( !token.Icmp( "update_rate" ) ) {
405  rate = parser.ParseFloat();
406  if ( ( rate <= 0.0f ) || ( rate > 60.0f ) ) {
407  parser.Warning( "Invalid update_rate. Must be between 0 and 60. Using default model." );
409  return;
410  }
411  update_tics = 1000 / rate;
412  } else {
413  parser.Warning( "Unknown parameter '%s'. Using default model.", token.c_str() );
415  return;
416  }
417  }
418 
419  scale_x = size_x / ( verts_x - 1 );
420  scale_y = size_y / ( verts_y - 1 );
421 
422  pages.SetNum( 2 * verts_x * verts_y );
423  page1 = pages.Ptr();
424  page2 = page1 + verts_x * verts_y;
425 
426  verts.SetNum( verts_x * verts_y );
427  for ( i = 0, y = 0; y < verts_y; y++ ) {
428  for ( x = 0; x < verts_x; x++, i++ ) {
429  page1[ i ] = 0.0f;
430  page2[ i ] = 0.0f;
431  verts[ i ].Clear();
432  verts[ i ].xyz.Set( x * scale_x, y * scale_y, 0.0f );
433  verts[ i ].st.Set( (float) x / (float)( verts_x - 1 ), (float) -y / (float)( verts_y - 1 ) );
434  }
435  }
436 
437  tris.SetNum( ( verts_x - 1 ) * ( verts_y - 1 ) * 6 );
438  for( i = 0, y = 0; y < verts_y - 1; y++ ) {
439  for( x = 1; x < verts_x; x++, i += 6 ) {
440  tris[ i + 0 ] = y * verts_x + x;
441  tris[ i + 1 ] = y * verts_x + x - 1;
442  tris[ i + 2 ] = ( y + 1 ) * verts_x + x - 1;
443 
444  tris[ i + 3 ] = ( y + 1 ) * verts_x + x - 1;
445  tris[ i + 4 ] = ( y + 1 ) * verts_x + x;
446  tris[ i + 5 ] = y * verts_x + x;
447  }
448  }
449 
450  // build the information that will be common to all animations of this mesh:
451  // sil edge connectivity and normal / tangent generation information
452  deformInfo = R_BuildDeformInfo( verts.Num(), verts.Ptr(), tris.Num(), tris.Ptr(), true );
453 
454  bounds.Clear();
455  bounds.AddPoint( idVec3( 0.0f, 0.0f, drop_height * -10.0f ) );
456  bounds.AddPoint( idVec3( ( verts_x - 1 ) * scale_x, ( verts_y - 1 ) * scale_y, drop_height * 10.0f ) );
457 
458  // set the timestamp for reloadmodels
460 
461  Reset();
462 }
463 
464 /*
465 ====================
466 idRenderModelLiquid::InstantiateDynamicModel
467 ====================
468 */
470  idRenderModelStatic *staticModel;
471  int frames;
472  int t;
473  float lerp;
474 
475  if ( cachedModel ) {
476  delete cachedModel;
477  cachedModel = NULL;
478  }
479 
480  if ( !deformInfo ) {
481  return NULL;
482  }
483 
484  if ( !view ) {
485  t = 0;
486  } else {
487  t = view->renderView.time;
488  }
489 
490  // update the liquid model
491  frames = ( t - time ) / update_tics;
492  if ( frames > LIQUID_MAX_SKIP_FRAMES ) {
493  // don't let time accumalate when skipping frames
494  time += update_tics * ( frames - LIQUID_MAX_SKIP_FRAMES );
495 
496  frames = LIQUID_MAX_SKIP_FRAMES;
497  }
498 
499  while( frames > 0 ) {
500  Update();
501  frames--;
502  }
503 
504  // create the surface
505  lerp = ( float )( t - time ) / ( float )update_tics;
506  modelSurface_t surf = GenerateSurface( lerp );
507 
508  staticModel = new idRenderModelStatic;
509  staticModel->AddSurface( surf );
510  staticModel->bounds = surf.geometry->bounds;
511 
512  return staticModel;
513 }
514 
515 /*
516 ====================
517 idRenderModelLiquid::IsDynamicModel
518 ====================
519 */
521  return DM_CONTINUOUS;
522 }
523 
524 /*
525 ====================
526 idRenderModelLiquid::Bounds
527 ====================
528 */
530  // FIXME: need to do this better
531  return bounds;
532 }
GLdouble GLdouble bottom
Definition: qgl.h:273
deformInfo_t * R_BuildDeformInfo(int numVerts, const idDrawVert *verts, int numIndexes, const int *indexes, bool useUnsmoothedTangents)
GLsizei const GLfloat * value
Definition: glext.h:3614
glIndex_t * silIndexes
Definition: Model.h:104
int numVerts
Definition: Model.h:98
virtual dynamicModel_t IsDynamicModel() const
#define LIQUID_MAX_TYPES
void SetNum(int newnum, bool resize=true)
Definition: List.h:289
virtual void Reset()
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
idVec3 xyz
Definition: DrawVert.h:42
static const float PI
Definition: Math.h:205
idList< idDrawVert > verts
Definition: Model_local.h:273
GLenum GLint GLint y
Definition: glext.h:2849
float z
Definition: Vector.h:320
case const int
Definition: Callbacks.cpp:52
int numDupVerts
Definition: Model.h:109
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
const idMaterial * shader
Definition: Model.h:146
glIndex_t * indexes
Definition: tr_local.h:1526
Definition: Vector.h:316
case const float
Definition: Callbacks.cpp:62
int numMirroredVerts
Definition: tr_local.h:1522
type * Ptr(void)
Definition: List.h:596
performanceCounters_t pc
Definition: tr_local.h:788
static float Sqrt(float x)
Definition: Math.h:302
silEdge_t * silEdges
Definition: Model.h:113
void Clear(void)
Definition: Bounds.h:201
Definition: Token.h:71
void R_DeriveTangents(srfTriangles_t *tri, bool allocFacePlanes=true)
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
srfTriangles_t * R_AllocStaticTriSurf(void)
Definition: tr_trisurf.cpp:523
glIndex_t * silIndexes
Definition: tr_local.h:1528
GLdouble right
Definition: qgl.h:273
GLenum GLint x
Definition: glext.h:2849
int i
Definition: process.py:33
void MakeDefaultModel()
Definition: Model.cpp:229
virtual idBounds Bounds(const struct renderEntity_s *ent) const
int Icmp(const char *text) const
Definition: Str.h:667
static float Cos16(float a)
Definition: Math.h:350
int * dupVerts
Definition: tr_local.h:1531
int numSilEdges
Definition: Model.h:112
int ReadToken(idToken *token)
Definition: Parser.cpp:2338
bool AddPoint(const idVec3 &v)
Definition: Bounds.h:226
int RandomInt(void)
Definition: Random.h:70
idCVar r_useDeferredTangents("r_useDeferredTangents","1", CVAR_RENDERER|CVAR_BOOL,"defer tangents calculations after deform")
int numMirroredVerts
Definition: Model.h:106
void SetSeed(int seed)
Definition: Random.h:62
int ParseInt(void)
Definition: Parser.cpp:2775
idBounds bounds
Definition: Model.h:87
renderView_t renderView
Definition: tr_local.h:370
bool deformedSurface
Definition: Model.h:95
#define NULL
Definition: Lib.h:88
srfTriangles_t * geometry
Definition: Model.h:147
virtual void InitFromFile(const char *fileName)
void WaterDrop(int x, int y, float *page)
void void Warning(const char *str,...) const id_attribute((format(printf
Definition: Parser.cpp:335
float ParseFloat(void)
Definition: Parser.cpp:2812
void R_BoundTriSurf(srfTriangles_t *tri)
Definition: tr_trisurf.cpp:704
int numSilEdges
Definition: tr_local.h:1533
ID_INLINE void idSwap(type &a, type &b)
Definition: List.h:77
int numSourceVerts
Definition: tr_local.h:1515
int * mirroredVerts
Definition: Model.h:107
GLdouble GLdouble GLdouble top
Definition: qgl.h:273
virtual void VPCALL Memcpy(void *dst, const void *src, const int count)=0
idDeclManager * declManager
#define SEC2MS(t)
Definition: Math.h:59
virtual idRenderModel * InstantiateDynamicModel(const struct renderEntity_s *ent, const struct viewDef_s *view, idRenderModel *cachedModel)
bool GetBool(void) const
Definition: CVarSystem.h:142
tuple f
Definition: idal.py:89
int numDupVerts
Definition: tr_local.h:1530
int Num(void) const
Definition: List.h:265
int LoadFile(const char *filename, bool OSPath=false)
Definition: Parser.cpp:3013
dynamicModel_t
Definition: Model.h:150
const GLcharARB * name
Definition: glext.h:3629
int numIndexes
Definition: tr_local.h:1525
void IntersectBounds(const idBounds &bounds, float displacement)
const idMaterial * shader
Definition: Model_local.h:260
const char * c_str(void) const
Definition: Str.h:487
glIndex_t * indexes
Definition: Model.h:102
idList< float > pages
Definition: Model_local.h:269
dominantTri_t * dominantTris
Definition: tr_local.h:1536
idRenderSystemLocal tr
#define LIQUID_MAX_SKIP_FRAMES
silEdge_t * silEdges
Definition: tr_local.h:1534
int * dupVerts
Definition: Model.h:110
int numIndexes
Definition: Model.h:101
int * mirroredVerts
Definition: tr_local.h:1523
modelSurface_t GenerateSurface(float lerp)
void R_AllocStaticTriSurfVerts(srfTriangles_t *tri, int numVerts)
Definition: tr_trisurf.cpp:555
struct deformInfo_s * deformInfo
Definition: Model_local.h:261
idDrawVert * verts
Definition: Model.h:99
int numOutputVerts
Definition: tr_local.h:1520
virtual void AddSurface(modelSurface_t surface)
Definition: Model.cpp:355
GLdouble GLdouble t
Definition: glext.h:2943
void Clear(void)
Definition: List.h:184
idSIMDProcessor * SIMDProcessor
Definition: Simd.cpp:43
dominantTri_t * dominantTris
Definition: Model.h:117