Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

ATerrain.cpp

Go to the documentation of this file.
00001 /*
00002 CS Senior Project 2003
00003 Team : Leftfield
00004 Project : ModernWarfare
00005 Members :
00006 - Russ Christensen              <rchriste@cs.utah.edu>
00007 - Todd Smith                    <tcsmith@cs.utah.edu>
00008 - Usit Duongsaa                 <duongsaa@cs.utah.edu>
00009 
00010 Copyright 2003 Russ Christensen, Usit Duongsaa, and Todd Smith. All rights reserved.
00011 
00012 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
00013 
00014 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
00015 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
00016 THIS SOFTWARE IS PROVIDED BY RUSS CHRISTENSEN, USIT DUONGSAA, AND TODD SMITH ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RUSS, USIT, TODD OR OTHER CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00017 */
00018 
00023 #include "AEngine.h"
00024 #include "AState.h"
00025 #include "AUtil.h"
00026 #include "ATGAImage.h"
00027 
00028 //------------------------------------------------------------------------------------
00030 void createZMap(TerrainEntry &e, UBYTE *pImg)
00031 {
00032         for( int j=0; j<TERR_ROWS; j++ )                        // get height from channel R
00033                 for( int i=0; i<TERR_COLS; i++ )
00034                         e.zMap[j][i] = e.sizeZ * pImg[ (j*TERR_COLS+i)*3 ] / 255.0f + e.offsetZ;
00035 
00036 
00037         // blur Z
00038         FLOAT sum[TERR_ROWS][TERR_COLS];
00039         int   count[TERR_ROWS][TERR_COLS];
00040 
00041 #define ADD( x, y, value )   if( x>=0 && y>=0 && x<TERR_COLS && y<TERR_ROWS ) { sum[y][x]+=value; count[y][x]++; }
00042 
00043         for( int blurCount=0; blurCount<2; blurCount++ )
00044         {
00045                 ZeroMemory( sum, sizeof(sum) );
00046                 ZeroMemory( count, sizeof(count) );
00047                 for( int j=0; j<TERR_ROWS; j++ )
00048                         for( int i=0; i<TERR_COLS; i++ )
00049                         {
00050                                 FLOAT value = e.zMap[j][i];
00051                                 ADD( i-1, j-1, value )
00052                                 ADD( i  , j-1, value )
00053                                 ADD( i+1, j-1, value )
00054                                 ADD( i-1, j  , value )
00055                                 ADD( i+1, j  , value )
00056                                 ADD( i-1, j+1, value )
00057                                 ADD( i  , j+1, value )
00058                                 ADD( i+1, j+1, value )
00059                         }
00060 
00061                 for( int j=0; j<TERR_ROWS; j++ )
00062                         for( int i=0; i<TERR_COLS; i++ )
00063                                 e.zMap[j][i] = sum[j][i] / count[j][i];
00064         }
00065 }
00066 //------------------------------------------------------------------------------------
00068 void createNMap(TerrainEntry &e)
00069 {
00070         // 2x distance between 2 adjacent tiles
00071         FLOAT deltaX = 2.0f/TERR_COLS * e.sizeX;
00072         FLOAT deltaY = 2.0f/TERR_ROWS * e.sizeY;                
00073 
00074         for( int j=0; j<TERR_ROWS; j++ )
00075                 for( int i=0; i<TERR_COLS; i++ )
00076                 {
00077                         if( i==0 || i==TERR_COLS-1 || j==0 || j==TERR_ROWS-1 )          // if border case, normal points up
00078                         {
00079                                 e.NMap[j][i] = Vec3D( 0.0f, 0.0f, 1.0f );
00080                         }
00081                         else
00082                         {
00083                                 FLOAT dzdx = e.zMap[j-1][i+1] + e.zMap[j  ][i+1] + e.zMap[j+1][i+1]
00084                                                    - e.zMap[j-1][i-1] - e.zMap[j  ][i-1] - e.zMap[j+1][i-1];
00085                                 FLOAT dzdy = e.zMap[j+1][i-1] + e.zMap[j+1][i  ] + e.zMap[j+1][i+1]
00086                                                    - e.zMap[j-1][i-1] - e.zMap[j-1][i  ] - e.zMap[j-1][i+1];
00087                                 
00088                            dzdx *= 1.0f / 3.0f / deltaX;
00089                            dzdy *= 1.0f / 3.0f / deltaY;
00090                            FLOAT denom = 1.0f / sqrtf( dzdx*dzdx + dzdy*dzdy + 1.0f );          // normalize it
00091                            e.NMap[j][i] = Vec3D( dzdx*denom, dzdy*denom, denom );
00092                         }
00093                 }
00094 }
00095 //------------------------------------------------------------------------------------
00096 void createBMap(TerrainEntry &e, UBYTE *pImg)
00097 {
00098         for( int j=0; j<TERR_ROWS; j++ )                        // get blend factor from channel G
00099                 for( int i=0; i<TERR_COLS; i++ )
00100                         e.BMap[j][i] = pImg[ (j*TERR_COLS+i)*3 +1] / 255.0f;
00101 }
00102 //------------------------------------------------------------------------------------
00104 void createVIB(TerrainEntry &e)
00105 {
00106         int vbByteSize = TERR_ROWS * TERR_COLS * sizeof(ColoredTerrainVertex);
00107         int ibByteSize = ((TERR_ROWS-1)*2*TERR_COLS + (TERR_ROWS-2)*2) * sizeof(USHORT);
00108         ColoredTerrainVertex *pVertex;
00109         USHORT                           *pIndex;
00110 
00111         AS.pDevice->CreateVertexBuffer( vbByteSize, D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &e.vb );
00112         AS.pDevice->CreateIndexBuffer(  ibByteSize, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &e.ib );
00113         if( FAILED( e.vb->Lock(0,0, (BYTE**)&pVertex, 0) )) throw Error("Can't Lock terrVB");
00114         if( FAILED( e.ib->Lock(0,0, (BYTE**)&pIndex,  0) )) throw Error("Can't Lock terrIB");
00115 
00116         int writeIndex = 0;
00117         for( int j=0; j<TERR_ROWS; j++ )
00118                 for( int i=0; i<TERR_COLS; i++ )
00119                 {
00120                         pVertex[writeIndex].pos = Vec3D( e.sizeX * (i*1.0f/TERR_COLS -0.5f),
00121                                                                                          e.sizeY * (j*1.0f/TERR_ROWS -0.5f),
00122                                                                                          e.zMap[j][i] );
00123                         pVertex[writeIndex].normal = e.NMap[j][i];
00124                         pVertex[writeIndex].blendFactor = e.BMap[j][i];                 
00125                         writeIndex++;
00126                 }
00127 
00128         writeIndex = 0;
00129         for( int j=0; j<TERR_ROWS-1; j++ )                              // fill indices
00130         {
00131                 for( int i=0; i<TERR_COLS; i++ )                                                // create tri strips
00132                 {
00133                         pIndex[writeIndex++] = j*TERR_COLS +i;
00134                         pIndex[writeIndex++] = (j+1)*TERR_COLS +i;
00135                 }
00136                 if( j<TERR_ROWS-2 )                                                                     // join strips
00137                 {
00138                         pIndex[writeIndex++] = (j+2)*TERR_COLS -1;
00139                         pIndex[writeIndex++] = (j+1)*TERR_COLS;
00140                 }
00141         }
00142 
00143     e.vb->Unlock();
00144         e.ib->Unlock();
00145 }
00146 //------------------------------------------------------------------------------------
00147 ATerrain terrain_create( string filename, FLOAT sizeX, FLOAT sizeY, FLOAT sizeZ, FLOAT offsetZ )
00148 {
00149         CImage img;
00150         img.LoadTga(filename);
00151         assert(img.GetWidth()==TERR_COLS && img.GetHeight()==TERR_ROWS);
00152         UBYTE *imgData  = img.GetImageData();
00153 
00154         TerrainEntry e;
00155         e.doRender = false;
00156         e.texLow    = (DWORD) -1;
00157         e.texHigh   = (DWORD) -1;
00158         e.texNormal = (DWORD) -1;
00159         e.sizeX = sizeX;
00160         e.sizeY = sizeY;
00161         e.sizeZ = sizeZ;
00162         e.offsetZ = offsetZ;
00163 
00164         createZMap(e,imgData);
00165         createNMap(e);
00166         createBMap(e,imgData);
00167         createVIB(e);
00168 
00169         AS.res_terrains.push_back(e);
00170 
00171         // create V&P shaders
00172         if(AS.vshader_terrain==0)
00173         {
00174                 AS.vshader_terrain = util_loadVertexShader( "shaders\\terrain.vso", dwColoredTerrainVertexDecl );
00175                 AS.pshader_terrain = util_loadPixelShader(  "shaders\\terrain.pso" );   
00176         }
00177         
00178         return (ATerrain)AS.res_terrains.size()-1;
00179 }
00180 //------------------------------------------------------------------------------------
00181 void terrain_render( ATerrain terrain, ATexture texLow, ATexture texHigh, ATexture texNormal )
00182 {
00183         assert(terrain>=0 && terrain<(int)AS.res_terrains.size());
00184         AS.res_terrains[terrain].doRender = true;
00185         AS.res_terrains[terrain].texLow    = texLow;
00186         AS.res_terrains[terrain].texHigh   = texHigh;
00187         AS.res_terrains[terrain].texNormal = texNormal;
00188 }
00189 //------------------------------------------------------------------------------------
00190 void terrain_flush()
00191 {
00192         for( UINT i=0; i<AS.res_terrains.size(); i++ )
00193                 AS.res_terrains[i].doRender = false;
00194 }
00195 //------------------------------------------------------------------------------------
00196 void terrain_processRenderRequest()
00197 {       
00198         UINT i;
00199         for( i=0; i<AS.res_terrains.size(); i++ )               // find the one that needs rendering, if any
00200                 if( AS.res_terrains[i].doRender ) break;
00201         if( i>=AS.res_terrains.size() ) return;
00202         TerrainEntry &e = AS.res_terrains[i];   
00203 
00204         device_setVertexShader( AS.vshader_terrain );
00205         device_setPixelShader(  AS.pshader_terrain );
00206 
00207         device_setTexture( 0, AS.res_textures[e.texLow] );
00208         device_setTexture( 1, AS.res_textures[e.texHigh] );
00209         device_setTexture( 2, AS.res_textures[e.texNormal] );
00210 
00211         device_setStreamSource( 0, e.vb, sizeof(ColoredTerrainVertex) );
00212         device_setIndexSource( e.ib );
00213 
00214         // rendering flags
00215         device_setRenderState( D3DRS_ZENABLE,  TRUE );
00216         device_setRenderState( D3DRS_ZWRITEENABLE,  TRUE );
00217         for( DWORD stage=0; stage<4; stage++ )
00218         {
00219                 device_setTextureStageState( stage, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
00220                 device_setTextureStageState( stage, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
00221                 device_setTextureStageState( stage, D3DTSS_MIPFILTER, D3DTEXF_LINEAR );
00222         }       
00223         device_setRenderState( D3DRS_CULLMODE, D3DCULL_CW );
00224         device_setRenderStateBlendMode( BlendModes::NONE );
00225         device_setRenderState( D3DRS_SPECULARENABLE, TRUE );
00226 
00227         // set projXview matrix
00228         Matx mat;       
00229         D3DXMatrixTranspose( &mat, &AS.camera_world2projMatrix);
00230         AS.pDevice->SetVertexShaderConstant( 0, &mat, 4 );
00231 
00232         // set UV const
00233         FLOAT uvScale[4] = { 10.0f/e.sizeX, 10.0f/e.sizeY, 0.0f, 0.0f };
00234         FLOAT uvShift[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
00235         FLOAT nScale[4]  = { 25.0f/e.sizeX, 25.0f/e.sizeY, 0.0f, 0.0f };
00236         AS.pDevice->SetVertexShaderConstant( 4, &uvScale, 1 );
00237         AS.pDevice->SetVertexShaderConstant( 5, &uvShift, 1 );
00238         AS.pDevice->SetVertexShaderConstant( 8, &nScale, 1 );
00239 
00240         // set ATM const
00241         FLOAT lightVec[4] = { 0.5882f, 0.1961f, 0.7843f, 0.0f };  //lightVec = c6
00242         FLOAT lightAmbient[4] = { 0.24f, 0.24f, 0.2f };
00243         AS.pDevice->SetVertexShaderConstant( 6, &lightVec, 1 );
00244         AS.pDevice->SetVertexShaderConstant( 7, &lightAmbient, 1 );
00245         
00246         FLOAT normalVec[4] = { 0.3882f, 0.1961f, 0.1843f, 0.0f };  // PS c0
00247         FLOAT atmColor[4]  = { 0.6f, 0.8f, 1.0f, 0.0f };
00248         FLOAT zScale[4]    = { 0.0025f };
00249         AS.pDevice->SetPixelShaderConstant( 0, &normalVec, 1 );         // PS c1 = atm color
00250         AS.pDevice->SetPixelShaderConstant( 1, &atmColor, 1 );
00251         AS.pDevice->SetVertexShaderConstant( 9, &zScale, 1 );
00252         
00253         // render strip
00254         int numVertex = TERR_ROWS * TERR_COLS;
00255         int primCount = (TERR_ROWS-1)*2*TERR_COLS + (TERR_ROWS-2)*2 - 2;
00256         AS.pDevice->DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP, 0, numVertex, 0, primCount );
00257 }
00258 //------------------------------------------------------------------------------------
00259 FLOAT triArea( Vec2D &p0, Vec2D &p1, Vec2D &p2 )
00260 {
00261         Vec2D side1 = p0 - p2;
00262         Vec2D side2 = p1 - p2;
00263         FLOAT area = D3DXVec2CCW( &side1, &side2) / 2.0f;               // size of the cross product/2
00264         if( area>0 ) return  area;
00265                 else     return -area;
00266 }
00267 //------------------------------------------------------------------------------------
00268 FLOAT terrain_getHeight( ATerrain terrain, FLOAT x, FLOAT y )
00269 {
00270         // idea : return the weighted average height of the closest 4 pts
00271         // weight = area of triangle formed
00272         assert(terrain>=0 && terrain<(int)AS.res_terrains.size());
00273         TerrainEntry &t = AS.res_terrains[terrain];
00274 
00275         FLOAT gridSizeX = t.sizeX / (TERR_COLS);
00276         FLOAT gridSizeY = t.sizeY / (TERR_ROWS);
00277         int i = (int)( (x+t.sizeX/2) / gridSizeX );
00278         int j = (int)( (y+t.sizeY/2) / gridSizeY );
00279         if( !(i>=0 && j>=0 && i<TERR_COLS-1 && j<TERR_ROWS-1) )
00280         {
00281                 sys_console() << "Warning : terrain_getHeight out of terrain area" << endl;
00282                 return 0;
00283         }
00284 
00285         Vec2D pMid(x,y);
00286         Vec2D p0( t.sizeX*(    i*1.0f/TERR_COLS -0.5f), t.sizeY*(    j*1.0f/TERR_ROWS -0.5f) );
00287         Vec2D p1( t.sizeX*((i+1)*1.0f/TERR_COLS -0.5f), t.sizeY*(    j*1.0f/TERR_ROWS -0.5f) );
00288         Vec2D p2( t.sizeX*((i+1)*1.0f/TERR_COLS -0.5f), t.sizeY*((j+1)*1.0f/TERR_ROWS -0.5f) );
00289         Vec2D p3( t.sizeX*(    i*1.0f/TERR_COLS -0.5f), t.sizeY*((j+1)*1.0f/TERR_ROWS -0.5f) );
00290 
00291         FLOAT tri0 = triArea( p0, p1, pMid );
00292         FLOAT tri1 = triArea( p1, p2, pMid );
00293         FLOAT tri2 = triArea( p2, p3, pMid );
00294         FLOAT tri3 = triArea( p3, p0, pMid );
00295 
00296         FLOAT weight0 = tri1*tri2,              weight1=tri2*tri3,
00297                   weight2 = tri3*tri0,          weight3=tri0*tri1;
00298         FLOAT sum = t.zMap[j][i]    *weight0 + t.zMap[j][i+1]*weight1
00299                       + t.zMap[j+1][i+1]*weight2 + t.zMap[j+1][i]*weight3;
00300         FLOAT height = sum/(weight0+weight1+weight2+weight3);   
00301         //return ((int)(height*10))/10.0f;
00302         return height;
00303 }
00304 //------------------------------------------------------------------------------------

Generated on Wed Apr 23 05:50:14 2003 for Modern Warfare by doxygen1.3-rc2