00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00023 #include "AEngine.h"
00024 #include "AState.h"
00025 #include "AUtil.h"
00026 #include "ATGAImage.h"
00027
00028
00030
00031 {
00032 for( int j=0; j<TERR_ROWS; j++ )
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
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
00069 {
00070
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 )
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 );
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++ )
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
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++ )
00130 {
00131 for( int i=0; i<TERR_COLS; i++ )
00132 {
00133 pIndex[writeIndex++] = j*TERR_COLS +i;
00134 pIndex[writeIndex++] = (j+1)*TERR_COLS +i;
00135 }
00136 if( j<TERR_ROWS-2 )
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
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++ )
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
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
00228 Matx mat;
00229 D3DXMatrixTranspose( &mat, &AS.camera_world2projMatrix);
00230 AS.pDevice->SetVertexShaderConstant( 0, &mat, 4 );
00231
00232
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
00241 FLOAT lightVec[4] = { 0.5882f, 0.1961f, 0.7843f, 0.0f };
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 };
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 );
00250 AS.pDevice->SetPixelShaderConstant( 1, &atmColor, 1 );
00251 AS.pDevice->SetVertexShaderConstant( 9, &zScale, 1 );
00252
00253
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;
00264 if( area>0 ) return area;
00265 else return -area;
00266 }
00267
00268 FLOAT terrain_getHeight( ATerrain terrain, FLOAT x, FLOAT y )
00269 {
00270
00271
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
00302 return height;
00303 }
00304