123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "tr_local.h"
- #include "Model_local.h"
- #define LIQUID_MAX_SKIP_FRAMES 5
- #define LIQUID_MAX_TYPES 3
- /*
- ====================
- idRenderModelLiquid::idRenderModelLiquid
- ====================
- */
- idRenderModelLiquid::idRenderModelLiquid() {
- verts_x = 32;
- verts_y = 32;
- scale_x = 256.0f;
- scale_y = 256.0f;
- liquid_type = 0;
- density = 0.97f;
- drop_height = 4;
- drop_radius = 4;
- drop_delay = 1000;
- shader = declManager->FindMaterial( NULL );
- update_tics = 33; // ~30 hz
- time = 0;
- seed = 0;
- random.SetSeed( 0 );
- }
- /*
- ====================
- idRenderModelLiquid::GenerateSurface
- ====================
- */
- modelSurface_t idRenderModelLiquid::GenerateSurface( float lerp ) {
- srfTriangles_t *tri;
- int i, base;
- idDrawVert *vert;
- modelSurface_t surf;
- float inv_lerp;
- inv_lerp = 1.0f - lerp;
- vert = verts.Ptr();
- for( i = 0; i < verts.Num(); i++, vert++ ) {
- vert->xyz.z = page1[ i ] * lerp + page2[ i ] * inv_lerp;
- }
- tr.pc.c_deformedSurfaces++;
- tr.pc.c_deformedVerts += deformInfo->numOutputVerts;
- tr.pc.c_deformedIndexes += deformInfo->numIndexes;
- tri = R_AllocStaticTriSurf();
- // note that some of the data is references, and should not be freed
- tri->referencedIndexes = true;
- tri->numIndexes = deformInfo->numIndexes;
- tri->indexes = deformInfo->indexes;
- tri->silIndexes = deformInfo->silIndexes;
- tri->numMirroredVerts = deformInfo->numMirroredVerts;
- tri->mirroredVerts = deformInfo->mirroredVerts;
- tri->numDupVerts = deformInfo->numDupVerts;
- tri->dupVerts = deformInfo->dupVerts;
- tri->numSilEdges = deformInfo->numSilEdges;
- tri->silEdges = deformInfo->silEdges;
- tri->numVerts = deformInfo->numOutputVerts;
- R_AllocStaticTriSurfVerts( tri, tri->numVerts );
- SIMDProcessor->Memcpy( tri->verts, verts.Ptr(), deformInfo->numSourceVerts * sizeof(tri->verts[0]) );
- // replicate the mirror seam vertexes
- base = deformInfo->numOutputVerts - deformInfo->numMirroredVerts;
- for ( i = 0 ; i < deformInfo->numMirroredVerts ; i++ ) {
- tri->verts[base + i] = tri->verts[deformInfo->mirroredVerts[i]];
- }
- R_BoundTriSurf( tri );
- surf.geometry = tri;
- surf.shader = shader;
- return surf;
- }
- /*
- ====================
- idRenderModelLiquid::WaterDrop
- ====================
- */
- void idRenderModelLiquid::WaterDrop( int x, int y, float *page ) {
- int cx, cy;
- int left,top,right,bottom;
- int square;
- int radsquare = drop_radius * drop_radius;
- float invlength = 1.0f / ( float )radsquare;
- float dist;
- if ( x < 0 ) {
- x = 1 + drop_radius + random.RandomInt( verts_x - 2 * drop_radius - 1 );
- }
- if ( y < 0 ) {
- y = 1 + drop_radius + random.RandomInt( verts_y - 2 * drop_radius - 1 );
- }
- left=-drop_radius; right = drop_radius;
- top=-drop_radius; bottom = drop_radius;
- // Perform edge clipping...
- if ( x - drop_radius < 1 ) {
- left -= (x-drop_radius-1);
- }
- if ( y - drop_radius < 1 ) {
- top -= (y-drop_radius-1);
- }
- if ( x + drop_radius > verts_x - 1 ) {
- right -= (x+drop_radius-verts_x+1);
- }
- if ( y + drop_radius > verts_y - 1 ) {
- bottom-= (y+drop_radius-verts_y+1);
- }
- for ( cy = top; cy < bottom; cy++ ) {
- for ( cx = left; cx < right; cx++ ) {
- square = cy*cy + cx*cx;
- if ( square < radsquare ) {
- dist = idMath::Sqrt( (float)square * invlength );
- page[verts_x*(cy+y) + cx+x] += idMath::Cos16( dist * idMath::PI * 0.5f ) * drop_height;
- }
- }
- }
- }
- /*
- ====================
- idRenderModelLiquid::IntersectBounds
- ====================
- */
- void idRenderModelLiquid::IntersectBounds( const idBounds &bounds, float displacement ) {
- int cx, cy;
- int left,top,right,bottom;
- float up, down;
- float *pos;
- left = ( int )( bounds[ 0 ].x / scale_x );
- right = ( int )( bounds[ 1 ].x / scale_x );
- top = ( int )( bounds[ 0 ].y / scale_y );
- bottom = ( int )( bounds[ 1 ].y / scale_y );
- down = bounds[ 0 ].z;
- up = bounds[ 1 ].z;
- if ( ( right < 1 ) || ( left >= verts_x ) || ( bottom < 1 ) || ( top >= verts_x ) ) {
- return;
- }
- // Perform edge clipping...
- if ( left < 1 ) {
- left = 1;
- }
- if ( right >= verts_x ) {
- right = verts_x - 1;
- }
- if ( top < 1 ) {
- top = 1;
- }
- if ( bottom >= verts_y ) {
- bottom = verts_y - 1;
- }
- for ( cy = top; cy < bottom; cy++ ) {
- for ( cx = left; cx < right; cx++ ) {
- pos = &page1[ verts_x * cy + cx ];
- if ( *pos > down ) {//&& ( *pos < up ) ) {
- *pos = down;
- }
- }
- }
- }
- /*
- ====================
- idRenderModelLiquid::Update
- ====================
- */
- void idRenderModelLiquid::Update() {
- int x, y;
- float *p2;
- float *p1;
- float value;
- time += update_tics;
- SwapValues( page1, page2 );
- if ( time > nextDropTime ) {
- WaterDrop( -1, -1, page2 );
- nextDropTime = time + drop_delay;
- } else if ( time < nextDropTime - drop_delay ) {
- nextDropTime = time + drop_delay;
- }
- p1 = page1;
- p2 = page2;
- switch( liquid_type ) {
- case 0 :
- for ( y = 1; y < verts_y - 1; y++ ) {
- p2 += verts_x;
- p1 += verts_x;
- for ( x = 1; x < verts_x - 1; x++ ) {
- value =
- ( p2[ x + verts_x ] +
- p2[ x - verts_x ] +
- p2[ x + 1 ] +
- p2[ x - 1 ] +
- p2[ x - verts_x - 1 ] +
- p2[ x - verts_x + 1 ] +
- p2[ x + verts_x - 1 ] +
- p2[ x + verts_x + 1 ] +
- p2[ x ] ) * ( 2.0f / 9.0f ) -
- p1[ x ];
- p1[ x ] = value * density;
- }
- }
- break;
- case 1 :
- for ( y = 1; y < verts_y - 1; y++ ) {
- p2 += verts_x;
- p1 += verts_x;
- for ( x = 1; x < verts_x - 1; x++ ) {
- value =
- ( p2[ x + verts_x ] +
- p2[ x - verts_x ] +
- p2[ x + 1 ] +
- p2[ x - 1 ] +
- p2[ x - verts_x - 1 ] +
- p2[ x - verts_x + 1 ] +
- p2[ x + verts_x - 1 ] +
- p2[ x + verts_x + 1 ] ) * 0.25f -
- p1[ x ];
- p1[ x ] = value * density;
- }
- }
- break;
- case 2 :
- for ( y = 1; y < verts_y - 1; y++ ) {
- p2 += verts_x;
- p1 += verts_x;
- for ( x = 1; x < verts_x - 1; x++ ) {
- value =
- ( p2[ x + verts_x ] +
- p2[ x - verts_x ] +
- p2[ x + 1 ] +
- p2[ x - 1 ] +
- p2[ x - verts_x - 1 ] +
- p2[ x - verts_x + 1 ] +
- p2[ x + verts_x - 1 ] +
- p2[ x + verts_x + 1 ] +
- p2[ x ] ) * ( 1.0f / 9.0f );
- p1[ x ] = value * density;
- }
- }
- break;
- }
- }
- /*
- ====================
- idRenderModelLiquid::Reset
- ====================
- */
- void idRenderModelLiquid::Reset() {
- int i, x, y;
- if ( pages.Num() < 2 * verts_x * verts_y ) {
- return;
- }
- nextDropTime = 0;
- time = 0;
- random.SetSeed( seed );
- page1 = pages.Ptr();
- page2 = page1 + verts_x * verts_y;
- for ( i = 0, y = 0; y < verts_y; y++ ) {
- for ( x = 0; x < verts_x; x++, i++ ) {
- page1[ i ] = 0.0f;
- page2[ i ] = 0.0f;
- verts[ i ].xyz.z = 0.0f;
- }
- }
- }
- /*
- ====================
- idRenderModelLiquid::InitFromFile
- ====================
- */
- void idRenderModelLiquid::InitFromFile( const char *fileName ) {
- int i, x, y;
- idToken token;
- idParser parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS );
- idList<int> tris;
- float size_x, size_y;
- float rate;
- name = fileName;
- if ( !parser.LoadFile( fileName ) ) {
- MakeDefaultModel();
- return;
- }
- size_x = scale_x * verts_x;
- size_y = scale_y * verts_y;
- while( parser.ReadToken( &token ) ) {
- if ( !token.Icmp( "seed" ) ) {
- seed = parser.ParseInt();
- } else if ( !token.Icmp( "size_x" ) ) {
- size_x = parser.ParseFloat();
- } else if ( !token.Icmp( "size_y" ) ) {
- size_y = parser.ParseFloat();
- } else if ( !token.Icmp( "verts_x" ) ) {
- verts_x = parser.ParseFloat();
- if ( verts_x < 2 ) {
- parser.Warning( "Invalid # of verts. Using default model." );
- MakeDefaultModel();
- return;
- }
- } else if ( !token.Icmp( "verts_y" ) ) {
- verts_y = parser.ParseFloat();
- if ( verts_y < 2 ) {
- parser.Warning( "Invalid # of verts. Using default model." );
- MakeDefaultModel();
- return;
- }
- } else if ( !token.Icmp( "liquid_type" ) ) {
- liquid_type = parser.ParseInt() - 1;
- if ( ( liquid_type < 0 ) || ( liquid_type >= LIQUID_MAX_TYPES ) ) {
- parser.Warning( "Invalid liquid_type. Using default model." );
- MakeDefaultModel();
- return;
- }
- } else if ( !token.Icmp( "density" ) ) {
- density = parser.ParseFloat();
- } else if ( !token.Icmp( "drop_height" ) ) {
- drop_height = parser.ParseFloat();
- } else if ( !token.Icmp( "drop_radius" ) ) {
- drop_radius = parser.ParseInt();
- } else if ( !token.Icmp( "drop_delay" ) ) {
- drop_delay = SEC2MS( parser.ParseFloat() );
- } else if ( !token.Icmp( "shader" ) ) {
- parser.ReadToken( &token );
- shader = declManager->FindMaterial( token );
- } else if ( !token.Icmp( "update_rate" ) ) {
- rate = parser.ParseFloat();
- if ( ( rate <= 0.0f ) || ( rate > 60.0f ) ) {
- parser.Warning( "Invalid update_rate. Must be between 0 and 60. Using default model." );
- MakeDefaultModel();
- return;
- }
- update_tics = 1000 / rate;
- } else {
- parser.Warning( "Unknown parameter '%s'. Using default model.", token.c_str() );
- MakeDefaultModel();
- return;
- }
- }
- scale_x = size_x / ( verts_x - 1 );
- scale_y = size_y / ( verts_y - 1 );
- pages.SetNum( 2 * verts_x * verts_y );
- page1 = pages.Ptr();
- page2 = page1 + verts_x * verts_y;
- verts.SetNum( verts_x * verts_y );
- for ( i = 0, y = 0; y < verts_y; y++ ) {
- for ( x = 0; x < verts_x; x++, i++ ) {
- page1[ i ] = 0.0f;
- page2[ i ] = 0.0f;
- verts[ i ].Clear();
- verts[ i ].xyz.Set( x * scale_x, y * scale_y, 0.0f );
- verts[ i ].SetTexCoord( (float) x / (float)( verts_x - 1 ), (float) -y / (float)( verts_y - 1 ) );
- }
- }
- tris.SetNum( ( verts_x - 1 ) * ( verts_y - 1 ) * 6 );
- for( i = 0, y = 0; y < verts_y - 1; y++ ) {
- for( x = 1; x < verts_x; x++, i += 6 ) {
- tris[ i + 0 ] = y * verts_x + x;
- tris[ i + 1 ] = y * verts_x + x - 1;
- tris[ i + 2 ] = ( y + 1 ) * verts_x + x - 1;
- tris[ i + 3 ] = ( y + 1 ) * verts_x + x - 1;
- tris[ i + 4 ] = ( y + 1 ) * verts_x + x;
- tris[ i + 5 ] = y * verts_x + x;
- }
- }
- // build the information that will be common to all animations of this mesh:
- // sil edge connectivity and normal / tangent generation information
- deformInfo = R_BuildDeformInfo( verts.Num(), verts.Ptr(), tris.Num(), tris.Ptr(), true );
- bounds.Clear();
- bounds.AddPoint( idVec3( 0.0f, 0.0f, drop_height * -10.0f ) );
- bounds.AddPoint( idVec3( ( verts_x - 1 ) * scale_x, ( verts_y - 1 ) * scale_y, drop_height * 10.0f ) );
- // set the timestamp for reloadmodels
- fileSystem->ReadFile( name, NULL, &timeStamp );
- Reset();
- }
- /*
- ====================
- idRenderModelLiquid::InstantiateDynamicModel
- ====================
- */
- idRenderModel *idRenderModelLiquid::InstantiateDynamicModel( const struct renderEntity_s *ent, const viewDef_t *view, idRenderModel *cachedModel ) {
- idRenderModelStatic *staticModel;
- int frames;
- int t;
- float lerp;
- if ( cachedModel ) {
- delete cachedModel;
- cachedModel = NULL;
- }
- if ( !deformInfo ) {
- return NULL;
- }
- if ( !view ) {
- t = 0;
- } else {
- t = view->renderView.time[0];
- }
- // update the liquid model
- frames = ( t - time ) / update_tics;
- if ( frames > LIQUID_MAX_SKIP_FRAMES ) {
- // don't let time accumalate when skipping frames
- time += update_tics * ( frames - LIQUID_MAX_SKIP_FRAMES );
- frames = LIQUID_MAX_SKIP_FRAMES;
- }
-
- while( frames > 0 ) {
- Update();
- frames--;
- }
- // create the surface
- lerp = ( float )( t - time ) / ( float )update_tics;
- modelSurface_t surf = GenerateSurface( lerp );
- staticModel = new (TAG_MODEL) idRenderModelStatic;
- staticModel->AddSurface( surf );
- staticModel->bounds = surf.geometry->bounds;
- return staticModel;
- }
- /*
- ====================
- idRenderModelLiquid::IsDynamicModel
- ====================
- */
- dynamicModel_t idRenderModelLiquid::IsDynamicModel() const {
- return DM_CONTINUOUS;
- }
- /*
- ====================
- idRenderModelLiquid::Bounds
- ====================
- */
- idBounds idRenderModelLiquid::Bounds(const struct renderEntity_s *ent) const {
- // FIXME: need to do this better
- return bounds;
- }
|