//===========================================================================// // Copyright (C) Microsoft Corporation. All rights reserved. // //===========================================================================// #include "MLRHeaders.hpp" #if defined(TRACE_ENABLED) && defined(MLR_TRACE) BitTrace *MLR_Terrain2_Clip; #endif extern DWORD gEnableLightMaps; //############################################################################# //## MLRTerrain with no color no lighting w/ detail texture, uv's from xyz ### //############################################################################# DynamicArrayOf *MLR_Terrain2::detailTexCoords; MLR_Terrain2::ClassData* MLR_Terrain2::DefaultData = NULL; extern DynamicArrayOf *lightMapUVs; extern DynamicArrayOf *lightMapSqFalloffs; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLR_Terrain2::InitializeClass() { Verify(!DefaultData); Verify(gos_GetCurrentHeap() == StaticHeap); DefaultData = new ClassData( MLR_Terrain2ClassID, "MidLevelRenderer::MLR_Terrain2", MLR_I_DeT_TMesh::DefaultData, (MLRPrimitiveBase::Factory)&Make ); Register_Object(DefaultData); detailTexCoords = new DynamicArrayOf (Limits::Max_Number_Vertices_Per_Mesh); Register_Object(detailTexCoords); #if defined(TRACE_ENABLED) && defined(MLR_TRACE) MLR_Terrain2_Clip = new BitTrace("MLR_Terrain2_Clip"); Register_Object(MLR_Terrain2_Clip); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLR_Terrain2::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; Unregister_Object(detailTexCoords); delete detailTexCoords; #if defined(TRACE_ENABLED) && defined(MLR_TRACE) Unregister_Object(MLR_Terrain2_Clip); delete MLR_Terrain2_Clip; #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MLR_Terrain2::MLR_Terrain2( ClassData *class_data, MemoryStream *stream, int version ): MLR_I_DeT_TMesh(class_data, stream, version) { Check_Pointer(this); Check_Pointer(stream); Verify(gos_GetCurrentHeap() == Heap); *stream >> tileX >> tileZ; *stream >> maxDepth >> maxAllDepth; if(version>4) { Scalar *fptr = &frame[0][0]; for(int i=0;i<32;i++) { *stream >> *fptr++; } } else { Scalar xOffset, zOffset, xGrid, zGrid; *stream >> xOffset >> zOffset; *stream >> xGrid >> zGrid; frame[0][0] = xOffset; frame[0][1] = zOffset; frame[0][2] = xOffset + 8*xGrid; frame[0][3] = zOffset + 8*zGrid; frame[1][0] = xOffset + 4*(tileX/4)*xGrid; frame[1][1] = zOffset + 4*(tileZ/4)*zGrid; frame[1][2] = frame[1][0] + 4*xGrid; frame[1][3] = frame[1][1] + 4*zGrid; int i; for(i=2;i<8;i++) { frame[i][0] = xOffset + tileX*xGrid; frame[i][1] = zOffset + tileZ*zGrid; frame[i][2] = frame[i][0] + xGrid; frame[i][3] = frame[i][1] + zGrid; } } *stream >> borderPixelFun; unsigned char textureFlags, mask = 1; *stream >> textureFlags; for(int i=0;i<8;i++) { if(textureFlags | mask) { textures[i] = 1; } else { textures[i] = 0; } mask <<= 1; } Check_Object(MLRTexturePool::Instance); MLRTexture *orgTexture = (*MLRTexturePool::Instance)[referenceState.GetTextureHandle()]; Check_Object(orgTexture); const char *texName = orgTexture->GetTextureName(); char texRoot[1024], name[1024]; int len; if((len = strlen(texName)) > 0) { Verify(len>8); int i, d = texName[len-6] - '0'; strncpy(texRoot, texName, len-7); texRoot[len-7] = '\0'; textures[d] = referenceState.GetTextureHandle(); MLRTexture *texture; unsigned char mask = 1; for(i=0;i<8;i++) { if(textureFlags & mask) { sprintf(name, "%s_%1d_%02x%02x", texRoot, i, (7-tileX)/(1<<(maxAllDepth-i)), (7-tileZ)/(1<<(maxAllDepth-i))); texture = (*MLRTexturePool::Instance)(name, 0); if (!texture) { texture = MLRTexturePool::Instance->Add(name, 0); } Check_Object(texture); texture->SetHint(orgTexture->GetHint()); textures[i] = texture->GetTextureHandle(); } else { textures[i] = 0; } mask <<= 1; } i++; for(;i<8;i++) { textures[i] = 0; } } else { for(int i=0;i<8;i++) { textures[i] = 0; } } Verify(textures[0]!=0); currentDepth = -1; SetCurrentDepth(1); referenceState.SetLightingMode(MLRState::LightMapLightingMode); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MLR_Terrain2::MLR_Terrain2(ClassData *class_data): MLR_I_DeT_TMesh(class_data) { Check_Pointer(this); Verify(gos_GetCurrentHeap() == Heap); tileX = 0; tileZ = 0; maxDepth = 0; maxAllDepth = 0; borderPixelFun = 0.0f; Scalar *fptr = &frame[0][0]; int i; for(i=0;i<32;i++) { *fptr++ = 0.0f; } for(i=0;i<8;i++) { textures[i] = 0; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MLR_Terrain2::~MLR_Terrain2() { Check_Object(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MLR_Terrain2* MLR_Terrain2::Make( MemoryStream *stream, int version ) { Check_Object(stream); gos_PushCurrentHeap(Heap); MLR_Terrain2 *terrain = new MLR_Terrain2(DefaultData, stream, version); gos_PopCurrentHeap(); return terrain; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLR_Terrain2::Save(MemoryStream *stream) { Check_Object(this); Check_Object(stream); texCoords.SetLength(0); MLR_I_DeT_TMesh::Save(stream); CalculateUVs(); *stream << tileX << tileZ; *stream << maxDepth << maxAllDepth; Scalar *fptr = &frame[0][0]; for(int i=0;i<32;i++) { *stream << *fptr++; } *stream << borderPixelFun; unsigned char textureFlags = 0; // HACK /* Check_Object(MLRTexturePool::Instance); MLRTexture *orgTexture = (*MLRTexturePool::Instance)[referenceState.GetTextureHandle()]; const char *texName = orgTexture->GetTextureName(); char texRoot[1024], name[1024]; int len; if((len = strlen(texName)) > 0) { Verify(len>8); int i, d = texName[len-6] - '0'; Verify(d==maxDepth); strncpy(texRoot, texName, len-7); texRoot[len-7] = '\0'; textures[d] = referenceState.GetTextureHandle(); MLRTexture *texture; unsigned char mask = 1; for(i=0;i(tileX/(1<<(maxAllDepth-i)))); Verify((1<(tileZ/(1<<(maxAllDepth-i)))); // SPEW(("micgaert", "%s", name)); texture = (*MLRTexturePool::Instance)(name, 0); if (texture) { textureFlags |= mask; textures[i] = texture->GetTextureHandle(); } mask <<= 1; } } Verify(textures[0]!=0); */ textureFlags = 3; // HACK *stream << textureFlags; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLR_Terrain2::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLR_Terrain2::SetCurrentDepth(unsigned char d) { if(d == currentDepth) { return; } else { Verify(d <= maxAllDepth); unsigned char dt; dt = d0 && textures[dt]==0) { dt--; } currentDepth = dt; } CalculateUVs(); referenceState.SetTextureHandle(textures[currentDepth]); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLR_Terrain2::SetLevelTexture(int lev, int handle) { Check_Object(this); Verify(lev>=0 && lev<8); textures[lev] = handle; if(lev==currentDepth) { referenceState.SetTextureHandle(textures[currentDepth]); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLR_Terrain2::CalculateUVs() { if(texCoords.GetLength() != coords.GetLength()) { gos_PushCurrentHeap(Heap); texCoords.SetLength(coords.GetLength()); gos_PopCurrentHeap(); } Scalar maxX = frame[currentDepth][2]; Scalar maxZ = frame[currentDepth][3]; Scalar OneOverX = 1.0f/(frame[currentDepth][2] - frame[currentDepth][0]); Scalar OneOverZ = 1.0f/(frame[currentDepth][3] - frame[currentDepth][1]); for(int i=0;i=0.0 && texCoords[i][0]<=1.0); Verify(texCoords[i][1]>=0.0 && texCoords[i][1]<=1.0); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #define I_SAY_YES_TO_DETAIL_TEXTURES #define I_SAY_YES_TO_TERRAIN2 #undef I_SAY_YES_TO_DUAL_TEXTURES #undef I_SAY_YES_TO_COLOR #undef I_SAY_YES_TO_TERRAIN #undef I_SAY_YES_TO_LIGHTING #define CLASSNAME MLR_Terrain2 #if defined(TRACE_ENABLED) && defined(MLR_TRACE) #define SET_MLR_TMESH_CLIP() MLR_Terrain2_Clip->Set() #define CLEAR_MLR_TMESH_CLIP() MLR_Terrain2_Clip->Clear() #else #define SET_MLR_TMESH_CLIP() #define CLEAR_MLR_TMESH_CLIP() #endif //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // This include contains follwing functions: // void MLR_Terrain2::TransformNoClip(Matrix4D*, GOSVertexPool*); // int MLR_Terrain2::Clip(MLRClippingState, GOSVertexPool*); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #include #undef I_SAY_YES_TO_DETAIL_TEXTURES #undef I_SAY_YES_TO_TERRAIN2 #undef CLASSNAME extern RGBAColor errorColor; extern bool CheckForBigTriangles(DynamicArrayOf *lightMapUVs, int stride); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLR_Terrain2::LightMapLighting(MLRLight *light) { if(!gEnableLightMaps) { return; } int i, j, k, len = numOfTriangles; LinearMatrix4D matrix = LinearMatrix4D::Identity; Point3D lightPosInShape, hitPoint; UnitVector3D up, left, forward; bool lm; Scalar falloff = 1.0f, distance; MLRLightMap *lightMap = light->GetLightMap(); if( (!lightMap) || (!gEnableLightMaps) ) { return; } int tooBig = 0; Scalar bigUV = MLRState::GetMaxUV(); switch(light->GetLightType()) { case MLRLight::PointLight: { Check_Object(lightMap); lightMap->AddState(referenceState.GetPriority()+1); light->GetInShapePosition(lightPosInShape); Scalar n, f; Cast_Object(MLRPointLight*, light)->GetFalloffDistance(n, f); Scalar One_Over_Falloff = 1.0f/(3.0f*f); for(i=0,j=0,k=0;i= -0.5f && (*lightMapUVs)[k][0] <= 0.5f && (*lightMapUVs)[k][1] >= -0.5f && (*lightMapUVs)[k][1] <= 0.5f ) { lm = true; } if( (*lightMapUVs)[k][0] < -bigUV || (*lightMapUVs)[k][0] > bigUV || (*lightMapUVs)[k][1] < -bigUV || (*lightMapUVs)[k][1] > bigUV ) { tooBig++; } } if(tooBig==0 && (lm == true || CheckForBigTriangles(lightMapUVs, 3) == true)) { lightMap->SetPolygonMarker(0); lightMap->AddUShort(3); #if 0 Vector3D vec(coords[index[j]]); SPEW(("micgaert", "\nvertex1 = %f,%f,%f", vec.x, vec.y, vec.z)); vec = coords[index[j+1]]; SPEW(("micgaert", "vertex2 = %f,%f,%f", vec.x, vec.y, vec.z)); vec = coords[index[j+2]]; SPEW(("micgaert", "vertex3 = %f,%f,%f", vec.x, vec.y, vec.z)); vec = facePlanes[i].normal; SPEW(("micgaert", "normal = %f,%f,%f", vec.x, vec.y, vec.z)); SPEW(("micgaert", "forward = %f,%f,%f", forward.x, forward.y, forward.z)); SPEW(("micgaert", "distance = %f", f)); SPEW(("micgaert", "light = %f,%f,%f", lightPosInShape.x, lightPosInShape.y, lightPosInShape.z)); SPEW(("micgaert", "projection = %f,%f,%f", hitPoint.x, hitPoint.y, hitPoint.z)); #endif Scalar sq_falloff = falloff*falloff*light->GetIntensity(); RGBAColor color; light->GetColor(color); color.red *= sq_falloff; color.green *= sq_falloff; color.blue *= sq_falloff; color.alpha = 1.0f; lightMap->AddColor(color); for(k=0;k<3;k++) { lightMap->AddCoord(coords[index[k+j]]); } for(k=0;k<3;k++) { lightMap->AddUVs((*lightMapUVs)[k][0]+0.5f, (*lightMapUVs)[k][1]+0.5f); // DEBUG_STREAM << k << " " << lightMapUVs[k][0] << " " << lightMapUVs[k][0] << "\n"; } } } } break; case MLRLight::SpotLight: { int behindCount = 0, falloffCount = 0; Check_Object(lightMap); lightMap->AddState(referenceState.GetPriority()+1); light->GetInShapePosition(matrix); lightPosInShape = matrix; Scalar tanSpeadAngle = Cast_Object(MLRSpotLight*, light)->GetTanSpreadAngle(); #ifndef TOP_DOWN_ONLY matrix.GetLocalLeftInWorld(&left); matrix.GetLocalUpInWorld(&up); matrix.GetLocalForwardInWorld(&forward); #else forward = UnitVector3D(0.0f, -1.0f, 0.0); up = UnitVector3D(1.0f, 0.0f, 0.0); left = UnitVector3D(0.0f, 0.0f, 1.0); #endif Verify(Small_Enough(up*left)); for(i=0,j=0,k=0;icoords[index[j+1]].x) { minX = coords[index[j+1]].x; } if(minX>coords[index[j+2]].x) { minX = coords[index[j+2]].x; } if(minZ>coords[index[j+1]].z) { minZ = coords[index[j+1]].z; } if(minX>coords[index[j+2]].z) { minZ = coords[index[j+2]].z; } if(maxX minX && lightPosInShape.x < maxX && lightPosInShape.z > minZ && lightPosInShape.z < maxZ) { SPEW(("micgaert", "On Target !!")); } #endif tooBig = 0; for(k=0;k<3;k++) { Vector3D vec; Scalar oneOver; vec.Subtract(coords[index[k+j]], lightPosInShape); #ifndef TOP_DOWN_ONLY distance = (vec*forward); #else distance = -vec.y; #endif #if SPEW_AWAY SPEW(("micgaert", "vertex%d = %f,%f,%f", k, coords[index[k+j]].x, coords[index[k+j]].y, coords[index[k+j]].z)); SPEW(("micgaert", "distance = %f", distance)); #endif if(distance > SMALL) { if(Cast_Object(MLRInfiniteLightWithFalloff*, light)->GetFalloff(distance, falloff) == false) { falloffCount++; } (*lightMapSqFalloffs)[k] = falloff*falloff*light->GetIntensity(); oneOver #if 0 = 1.0f/(2.0f*distance*tanSpeadAngle); #else = OneOverApproximate(2.0f*distance*tanSpeadAngle); #endif } else { behindCount++; oneOver = 1.0f/50.0f; (*lightMapSqFalloffs)[k] = 0.0f; #if SPEW_AWAY SPEW(("micgaert", "Behind")); #endif } #ifndef TOP_DOWN_ONLY (*lightMapUVs)[k][0] = (left*vec) * oneOver; (*lightMapUVs)[k][1] = -(up*vec) * oneOver; #else (*lightMapUVs)[k][0] = vec.x * oneOver; (*lightMapUVs)[k][1] = -vec.z * oneOver; #endif #if SPEW_AWAY SPEW(("micgaert", "uv%d = %f,%f", k, (*lightMapUVs)[k][0], (*lightMapUVs)[k][1])); #endif if( (*lightMapUVs)[k][0] >= -0.5f && (*lightMapUVs)[k][0] <= 0.5f && (*lightMapUVs)[k][1] >= -0.5f && (*lightMapUVs)[k][1] <= 0.5f ) { lm = true; } if( (*lightMapUVs)[k][0] < -bigUV || (*lightMapUVs)[k][0] > bigUV || (*lightMapUVs)[k][1] < -bigUV || (*lightMapUVs)[k][1] > bigUV ) { tooBig++; } } #if 1 if( tooBig == 0 && behindCount < 3 && falloffCount < 3 && ((lm == true) || CheckForBigTriangles(lightMapUVs, 3) == true) ) { lightMap->SetPolygonMarker(1); lightMap->AddUShort(3); for(k=0;k<3;k++) { lightMap->AddCoord(coords[index[k+j]]); } for(k=0;k<3;k++) { lightMap->AddColor((*lightMapSqFalloffs)[k], (*lightMapSqFalloffs)[k], (*lightMapSqFalloffs)[k], 1.0f); } for(k=0;k<3;k++) { lightMap->AddUVs((*lightMapUVs)[k][0]+0.5f, (*lightMapUVs)[k][1]+0.5f); // DEBUG_STREAM << k << " " << lightMapUVs[k][0] << " " << lightMapUVs[k][0] << "\n"; } #if SPEW_AWAY SPEW(("micgaert", "See the Light !")); #endif } #if SPEW_AWAY Vector3D vec = facePlanes[i].normal; SPEW(("micgaert", "normal = %f,%f,%f", vec.x, vec.y, vec.z)); SPEW(("micgaert", "forward = %f,%f,%f", forward.x, forward.y, forward.z)); SPEW(("micgaert", "left = %f,%f,%f", left.x, left.y, left.z)); SPEW(("micgaert", "up = %f,%f,%f", up.x, up.y, up.z)); SPEW(("micgaert", "light = %f,%f,%f\n", lightPosInShape.x, lightPosInShape.y, lightPosInShape.z)); #endif #else if(tooBig != 0) { lightMap->SetPolygonMarker(1); lightMap->AddUShort(3); for(k=0;k<3;k++) { lightMap->AddCoord(coords[index[k+j]]); } for(k=0;k<3;k++) { lightMap->AddColor(RGBAColor(0.0f, 0.0f, 0.5f, 1.0f)); } for(k=0;k<3;k++) { lightMap->AddUVs(0.5f, 0.5f); // DEBUG_STREAM << k << " " << lightMapUVs[k][0] << " " << lightMapUVs[k][0] << "\n"; } } else if(behindCount != 0) { lightMap->SetPolygonMarker(1); lightMap->AddUShort(3); for(k=0;k<3;k++) { lightMap->AddCoord(coords[index[k+j]]); } for(k=0;k<3;k++) { lightMap->AddColor(RGBAColor(0.5f, 0.0f, 0.0f, 1.0f)); } for(k=0;k<3;k++) { lightMap->AddUVs(0.5f, 0.5f); // DEBUG_STREAM << k << " " << lightMapUVs[k][0] << " " << lightMapUVs[k][0] << "\n"; } } else if(behindCount == 0 && (lm == true || CheckForBigTriangles(&lightMapUVs, 3) == true) ) { lightMap->SetPolygonMarker(1); lightMap->AddUShort(3); for(k=0;k<3;k++) { lightMap->AddCoord(coords[index[k+j]]); } for(k=0;k<3;k++) { lightMap->AddColor(lightMapSqFalloffs[k], lightMapSqFalloffs[k], lightMapSqFalloffs[k], 1.0f); } for(k=0;k<3;k++) { lightMap->AddUVs(lightMapUVs[k][0]+0.5f, lightMapUVs[k][1]+0.5f); // DEBUG_STREAM << k << " " << lightMapUVs[k][0] << " " << lightMapUVs[k][0] << "\n"; } } else if(CheckForBigTriangles(&lightMapUVs, 3) == false) { lightMap->SetPolygonMarker(1); lightMap->AddUShort(3); for(k=0;k<3;k++) { lightMap->AddCoord(coords[index[k+j]]); } for(k=0;k<3;k++) { lightMap->AddColor(errorColor); } for(k=0;k<3;k++) { lightMap->AddUVs(0.5f, 0.5f); // DEBUG_STREAM << k << " " << lightMapUVs[k][0] << " " << lightMapUVs[k][0] << "\n"; } } #endif } } break; default: STOP(("MLR_I_PMesh::LightMapLighting: What you want me to do ?")); break; } }