Model_liquid.cpp (13391B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition 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 BFG Edition 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 #pragma hdrstop 30 #include "../idlib/precompiled.h" 31 32 33 #include "tr_local.h" 34 #include "Model_local.h" 35 36 #define LIQUID_MAX_SKIP_FRAMES 5 37 #define LIQUID_MAX_TYPES 3 38 39 /* 40 ==================== 41 idRenderModelLiquid::idRenderModelLiquid 42 ==================== 43 */ 44 idRenderModelLiquid::idRenderModelLiquid() { 45 verts_x = 32; 46 verts_y = 32; 47 scale_x = 256.0f; 48 scale_y = 256.0f; 49 liquid_type = 0; 50 density = 0.97f; 51 drop_height = 4; 52 drop_radius = 4; 53 drop_delay = 1000; 54 shader = declManager->FindMaterial( NULL ); 55 update_tics = 33; // ~30 hz 56 time = 0; 57 seed = 0; 58 59 random.SetSeed( 0 ); 60 } 61 62 /* 63 ==================== 64 idRenderModelLiquid::GenerateSurface 65 ==================== 66 */ 67 modelSurface_t idRenderModelLiquid::GenerateSurface( float lerp ) { 68 srfTriangles_t *tri; 69 int i, base; 70 idDrawVert *vert; 71 modelSurface_t surf; 72 float inv_lerp; 73 74 inv_lerp = 1.0f - lerp; 75 vert = verts.Ptr(); 76 for( i = 0; i < verts.Num(); i++, vert++ ) { 77 vert->xyz.z = page1[ i ] * lerp + page2[ i ] * inv_lerp; 78 } 79 80 tr.pc.c_deformedSurfaces++; 81 tr.pc.c_deformedVerts += deformInfo->numOutputVerts; 82 tr.pc.c_deformedIndexes += deformInfo->numIndexes; 83 84 tri = R_AllocStaticTriSurf(); 85 86 // note that some of the data is references, and should not be freed 87 tri->referencedIndexes = true; 88 89 tri->numIndexes = deformInfo->numIndexes; 90 tri->indexes = deformInfo->indexes; 91 tri->silIndexes = deformInfo->silIndexes; 92 tri->numMirroredVerts = deformInfo->numMirroredVerts; 93 tri->mirroredVerts = deformInfo->mirroredVerts; 94 tri->numDupVerts = deformInfo->numDupVerts; 95 tri->dupVerts = deformInfo->dupVerts; 96 tri->numSilEdges = deformInfo->numSilEdges; 97 tri->silEdges = deformInfo->silEdges; 98 99 tri->numVerts = deformInfo->numOutputVerts; 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 104 base = deformInfo->numOutputVerts - deformInfo->numMirroredVerts; 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 surf.geometry = tri; 112 surf.shader = shader; 113 114 return surf; 115 } 116 117 /* 118 ==================== 119 idRenderModelLiquid::WaterDrop 120 ==================== 121 */ 122 void idRenderModelLiquid::WaterDrop( int x, int y, float *page ) { 123 int cx, cy; 124 int left,top,right,bottom; 125 int square; 126 int radsquare = drop_radius * drop_radius; 127 float invlength = 1.0f / ( float )radsquare; 128 float dist; 129 130 if ( x < 0 ) { 131 x = 1 + drop_radius + random.RandomInt( verts_x - 2 * drop_radius - 1 ); 132 } 133 if ( y < 0 ) { 134 y = 1 + drop_radius + random.RandomInt( verts_y - 2 * drop_radius - 1 ); 135 } 136 137 left=-drop_radius; right = drop_radius; 138 top=-drop_radius; bottom = drop_radius; 139 140 // Perform edge clipping... 141 if ( x - drop_radius < 1 ) { 142 left -= (x-drop_radius-1); 143 } 144 if ( y - drop_radius < 1 ) { 145 top -= (y-drop_radius-1); 146 } 147 if ( x + drop_radius > verts_x - 1 ) { 148 right -= (x+drop_radius-verts_x+1); 149 } 150 if ( y + drop_radius > verts_y - 1 ) { 151 bottom-= (y+drop_radius-verts_y+1); 152 } 153 154 for ( cy = top; cy < bottom; cy++ ) { 155 for ( cx = left; cx < right; cx++ ) { 156 square = cy*cy + cx*cx; 157 if ( square < radsquare ) { 158 dist = idMath::Sqrt( (float)square * invlength ); 159 page[verts_x*(cy+y) + cx+x] += idMath::Cos16( dist * idMath::PI * 0.5f ) * drop_height; 160 } 161 } 162 } 163 } 164 165 /* 166 ==================== 167 idRenderModelLiquid::IntersectBounds 168 ==================== 169 */ 170 void idRenderModelLiquid::IntersectBounds( const idBounds &bounds, float displacement ) { 171 int cx, cy; 172 int left,top,right,bottom; 173 float up, down; 174 float *pos; 175 176 left = ( int )( bounds[ 0 ].x / scale_x ); 177 right = ( int )( bounds[ 1 ].x / scale_x ); 178 top = ( int )( bounds[ 0 ].y / scale_y ); 179 bottom = ( int )( bounds[ 1 ].y / scale_y ); 180 down = bounds[ 0 ].z; 181 up = bounds[ 1 ].z; 182 183 if ( ( right < 1 ) || ( left >= verts_x ) || ( bottom < 1 ) || ( top >= verts_x ) ) { 184 return; 185 } 186 187 // Perform edge clipping... 188 if ( left < 1 ) { 189 left = 1; 190 } 191 if ( right >= verts_x ) { 192 right = verts_x - 1; 193 } 194 if ( top < 1 ) { 195 top = 1; 196 } 197 if ( bottom >= verts_y ) { 198 bottom = verts_y - 1; 199 } 200 201 for ( cy = top; cy < bottom; cy++ ) { 202 for ( cx = left; cx < right; cx++ ) { 203 pos = &page1[ verts_x * cy + cx ]; 204 if ( *pos > down ) {//&& ( *pos < up ) ) { 205 *pos = down; 206 } 207 } 208 } 209 } 210 211 /* 212 ==================== 213 idRenderModelLiquid::Update 214 ==================== 215 */ 216 void idRenderModelLiquid::Update() { 217 int x, y; 218 float *p2; 219 float *p1; 220 float value; 221 222 time += update_tics; 223 224 SwapValues( page1, page2 ); 225 226 if ( time > nextDropTime ) { 227 WaterDrop( -1, -1, page2 ); 228 nextDropTime = time + drop_delay; 229 } else if ( time < nextDropTime - drop_delay ) { 230 nextDropTime = time + drop_delay; 231 } 232 233 p1 = page1; 234 p2 = page2; 235 236 switch( liquid_type ) { 237 case 0 : 238 for ( y = 1; y < verts_y - 1; y++ ) { 239 p2 += verts_x; 240 p1 += verts_x; 241 for ( x = 1; x < verts_x - 1; x++ ) { 242 value = 243 ( p2[ x + verts_x ] + 244 p2[ x - verts_x ] + 245 p2[ x + 1 ] + 246 p2[ x - 1 ] + 247 p2[ x - verts_x - 1 ] + 248 p2[ x - verts_x + 1 ] + 249 p2[ x + verts_x - 1 ] + 250 p2[ x + verts_x + 1 ] + 251 p2[ x ] ) * ( 2.0f / 9.0f ) - 252 p1[ x ]; 253 254 p1[ x ] = value * density; 255 } 256 } 257 break; 258 259 case 1 : 260 for ( y = 1; y < verts_y - 1; y++ ) { 261 p2 += verts_x; 262 p1 += verts_x; 263 for ( x = 1; x < verts_x - 1; x++ ) { 264 value = 265 ( p2[ x + verts_x ] + 266 p2[ x - verts_x ] + 267 p2[ x + 1 ] + 268 p2[ x - 1 ] + 269 p2[ x - verts_x - 1 ] + 270 p2[ x - verts_x + 1 ] + 271 p2[ x + verts_x - 1 ] + 272 p2[ x + verts_x + 1 ] ) * 0.25f - 273 p1[ x ]; 274 275 p1[ x ] = value * density; 276 } 277 } 278 break; 279 280 case 2 : 281 for ( y = 1; y < verts_y - 1; y++ ) { 282 p2 += verts_x; 283 p1 += verts_x; 284 for ( x = 1; x < verts_x - 1; x++ ) { 285 value = 286 ( p2[ x + verts_x ] + 287 p2[ x - verts_x ] + 288 p2[ x + 1 ] + 289 p2[ x - 1 ] + 290 p2[ x - verts_x - 1 ] + 291 p2[ x - verts_x + 1 ] + 292 p2[ x + verts_x - 1 ] + 293 p2[ x + verts_x + 1 ] + 294 p2[ x ] ) * ( 1.0f / 9.0f ); 295 296 p1[ x ] = value * density; 297 } 298 } 299 break; 300 } 301 } 302 303 /* 304 ==================== 305 idRenderModelLiquid::Reset 306 ==================== 307 */ 308 void idRenderModelLiquid::Reset() { 309 int i, x, y; 310 311 if ( pages.Num() < 2 * verts_x * verts_y ) { 312 return; 313 } 314 315 nextDropTime = 0; 316 time = 0; 317 random.SetSeed( seed ); 318 319 page1 = pages.Ptr(); 320 page2 = page1 + verts_x * verts_y; 321 322 for ( i = 0, y = 0; y < verts_y; y++ ) { 323 for ( x = 0; x < verts_x; x++, i++ ) { 324 page1[ i ] = 0.0f; 325 page2[ i ] = 0.0f; 326 verts[ i ].xyz.z = 0.0f; 327 } 328 } 329 } 330 331 /* 332 ==================== 333 idRenderModelLiquid::InitFromFile 334 ==================== 335 */ 336 void idRenderModelLiquid::InitFromFile( const char *fileName ) { 337 int i, x, y; 338 idToken token; 339 idParser parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS ); 340 idList<int> tris; 341 float size_x, size_y; 342 float rate; 343 344 name = fileName; 345 346 if ( !parser.LoadFile( fileName ) ) { 347 MakeDefaultModel(); 348 return; 349 } 350 351 size_x = scale_x * verts_x; 352 size_y = scale_y * verts_y; 353 354 while( parser.ReadToken( &token ) ) { 355 if ( !token.Icmp( "seed" ) ) { 356 seed = parser.ParseInt(); 357 } else if ( !token.Icmp( "size_x" ) ) { 358 size_x = parser.ParseFloat(); 359 } else if ( !token.Icmp( "size_y" ) ) { 360 size_y = parser.ParseFloat(); 361 } else if ( !token.Icmp( "verts_x" ) ) { 362 verts_x = parser.ParseFloat(); 363 if ( verts_x < 2 ) { 364 parser.Warning( "Invalid # of verts. Using default model." ); 365 MakeDefaultModel(); 366 return; 367 } 368 } else if ( !token.Icmp( "verts_y" ) ) { 369 verts_y = parser.ParseFloat(); 370 if ( verts_y < 2 ) { 371 parser.Warning( "Invalid # of verts. Using default model." ); 372 MakeDefaultModel(); 373 return; 374 } 375 } else if ( !token.Icmp( "liquid_type" ) ) { 376 liquid_type = parser.ParseInt() - 1; 377 if ( ( liquid_type < 0 ) || ( liquid_type >= LIQUID_MAX_TYPES ) ) { 378 parser.Warning( "Invalid liquid_type. Using default model." ); 379 MakeDefaultModel(); 380 return; 381 } 382 } else if ( !token.Icmp( "density" ) ) { 383 density = parser.ParseFloat(); 384 } else if ( !token.Icmp( "drop_height" ) ) { 385 drop_height = parser.ParseFloat(); 386 } else if ( !token.Icmp( "drop_radius" ) ) { 387 drop_radius = parser.ParseInt(); 388 } else if ( !token.Icmp( "drop_delay" ) ) { 389 drop_delay = SEC2MS( parser.ParseFloat() ); 390 } else if ( !token.Icmp( "shader" ) ) { 391 parser.ReadToken( &token ); 392 shader = declManager->FindMaterial( token ); 393 } else if ( !token.Icmp( "update_rate" ) ) { 394 rate = parser.ParseFloat(); 395 if ( ( rate <= 0.0f ) || ( rate > 60.0f ) ) { 396 parser.Warning( "Invalid update_rate. Must be between 0 and 60. Using default model." ); 397 MakeDefaultModel(); 398 return; 399 } 400 update_tics = 1000 / rate; 401 } else { 402 parser.Warning( "Unknown parameter '%s'. Using default model.", token.c_str() ); 403 MakeDefaultModel(); 404 return; 405 } 406 } 407 408 scale_x = size_x / ( verts_x - 1 ); 409 scale_y = size_y / ( verts_y - 1 ); 410 411 pages.SetNum( 2 * verts_x * verts_y ); 412 page1 = pages.Ptr(); 413 page2 = page1 + verts_x * verts_y; 414 415 verts.SetNum( verts_x * verts_y ); 416 for ( i = 0, y = 0; y < verts_y; y++ ) { 417 for ( x = 0; x < verts_x; x++, i++ ) { 418 page1[ i ] = 0.0f; 419 page2[ i ] = 0.0f; 420 verts[ i ].Clear(); 421 verts[ i ].xyz.Set( x * scale_x, y * scale_y, 0.0f ); 422 verts[ i ].SetTexCoord( (float) x / (float)( verts_x - 1 ), (float) -y / (float)( verts_y - 1 ) ); 423 } 424 } 425 426 tris.SetNum( ( verts_x - 1 ) * ( verts_y - 1 ) * 6 ); 427 for( i = 0, y = 0; y < verts_y - 1; y++ ) { 428 for( x = 1; x < verts_x; x++, i += 6 ) { 429 tris[ i + 0 ] = y * verts_x + x; 430 tris[ i + 1 ] = y * verts_x + x - 1; 431 tris[ i + 2 ] = ( y + 1 ) * verts_x + x - 1; 432 433 tris[ i + 3 ] = ( y + 1 ) * verts_x + x - 1; 434 tris[ i + 4 ] = ( y + 1 ) * verts_x + x; 435 tris[ i + 5 ] = y * verts_x + x; 436 } 437 } 438 439 // build the information that will be common to all animations of this mesh: 440 // sil edge connectivity and normal / tangent generation information 441 deformInfo = R_BuildDeformInfo( verts.Num(), verts.Ptr(), tris.Num(), tris.Ptr(), true ); 442 443 bounds.Clear(); 444 bounds.AddPoint( idVec3( 0.0f, 0.0f, drop_height * -10.0f ) ); 445 bounds.AddPoint( idVec3( ( verts_x - 1 ) * scale_x, ( verts_y - 1 ) * scale_y, drop_height * 10.0f ) ); 446 447 // set the timestamp for reloadmodels 448 fileSystem->ReadFile( name, NULL, &timeStamp ); 449 450 Reset(); 451 } 452 453 /* 454 ==================== 455 idRenderModelLiquid::InstantiateDynamicModel 456 ==================== 457 */ 458 idRenderModel *idRenderModelLiquid::InstantiateDynamicModel( const struct renderEntity_s *ent, const viewDef_t *view, idRenderModel *cachedModel ) { 459 idRenderModelStatic *staticModel; 460 int frames; 461 int t; 462 float lerp; 463 464 if ( cachedModel ) { 465 delete cachedModel; 466 cachedModel = NULL; 467 } 468 469 if ( !deformInfo ) { 470 return NULL; 471 } 472 473 if ( !view ) { 474 t = 0; 475 } else { 476 t = view->renderView.time[0]; 477 } 478 479 // update the liquid model 480 frames = ( t - time ) / update_tics; 481 if ( frames > LIQUID_MAX_SKIP_FRAMES ) { 482 // don't let time accumalate when skipping frames 483 time += update_tics * ( frames - LIQUID_MAX_SKIP_FRAMES ); 484 485 frames = LIQUID_MAX_SKIP_FRAMES; 486 } 487 488 while( frames > 0 ) { 489 Update(); 490 frames--; 491 } 492 493 // create the surface 494 lerp = ( float )( t - time ) / ( float )update_tics; 495 modelSurface_t surf = GenerateSurface( lerp ); 496 497 staticModel = new (TAG_MODEL) idRenderModelStatic; 498 staticModel->AddSurface( surf ); 499 staticModel->bounds = surf.geometry->bounds; 500 501 return staticModel; 502 } 503 504 /* 505 ==================== 506 idRenderModelLiquid::IsDynamicModel 507 ==================== 508 */ 509 dynamicModel_t idRenderModelLiquid::IsDynamicModel() const { 510 return DM_CONTINUOUS; 511 } 512 513 /* 514 ==================== 515 idRenderModelLiquid::Bounds 516 ==================== 517 */ 518 idBounds idRenderModelLiquid::Bounds(const struct renderEntity_s *ent) const { 519 // FIXME: need to do this better 520 return bounds; 521 }