#include #if !defined(HFSLIMMZL_HPP) #include "HFslimMZL.hpp" #include "terra\terra.hpp" #endif const Scalar One_Over_Three = 1.0f/3.0f; bool doWater = false; Scalar waterLevel; bool doBSP = false; extern FILE *analyzeFile; DynamicArrayOf uniquePoints; int usedUniquePoints; PointStruct *TriangleStruct::points = NULL; DynamicArrayOf triangleIndices; int usedTriangleIndices; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int FindPoint(Point3D& point) { for(int i=0;i 1.0f ? 1.0f : l1; l1 = l1 < -1.0f ? -1.0f : l1; return static_cast (acos(l1)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void PointStruct::Add (TriangleStruct *ts, int pos) { Verify(Close_Enough(p.x, ts->GetPoint(pos).x) && Close_Enough(p.z, ts->GetPoint(pos).z)); myTri[connectedTo].tri = ts; myTri[connectedTo].pos = pos; myTri[connectedTo].angle = GetAngle(ts->GetPoint((pos-1+3)%3), ts->GetPoint(pos), ts->GetPoint((pos+1)%3)); Verify(myTri[connectedTo].angle<=Pi); if(++connectedTo==myTri.GetLength()) { myTri.SetLength(myTri.GetLength()+12); } Check_Object(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void PointStruct::CalculateAngles() { Check_Object(this); for(int i=0;iGetPoint((myTri[i].pos-1+3)%3), myTri[i].tri->GetPoint(myTri[i].pos), myTri[i].tri->GetPoint((myTri[i].pos+1)%3) ); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool PointStruct::CheckAngles(Scalar xMax, Scalar zMax) { Check_Object(this); if(connectedTo==0) { return true; } float angle = 0.0f; for(int j=0;jv[0] < usedUniquePoints); Verify(myTri[i].tri->v[1] < usedUniquePoints); Verify(myTri[i].tri->v[2] < usedUniquePoints); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void TriangleStruct::GetSurfaceAreaAndCentroid() { Verify(points!=NULL); // //--------------------- // Set up the variables //--------------------- // Point3D position_a = Point3D::Identity, position_b, position_c = Point3D::Identity; Vector3D leg_1, leg_2 = Vector3D::Identity; // //----------------------------------- // Spin through, testing the vertices //----------------------------------- // area = 0.0f; center = Point3D::Identity; plane.normal.x = 0.0f; plane.normal.y = 0.0f; plane.normal.z = 1.0f; plane.offset = 0.0f; if(v[0]==v[1] || v[0]==v[2] || v[1]==v[2]) { return; } // //----------------------------------------------- // Generate all the information on the first pass //----------------------------------------------- // position_a = GetPoint(0); position_b = GetPoint(1); position_c = GetPoint(2); leg_1.Subtract(position_b, position_a); leg_2.Subtract(position_c, position_a); // //----------------------------------------------------------------- // Compute the cross-product of the two legs to get the area of the // triangle //----------------------------------------------------------------- // Vector3D vcp; vcp.Cross(leg_1, leg_2); // //------------------------------------------------------------------- // Add the three triangle points together and multiply by the area of // the triangle to give a weighted sum for the polygon centroid //------------------------------------------------------------------- // Point3D centroid; centroid.Add(position_a, position_b); centroid += position_c; Scalar wedge_area = vcp.GetLength() * 0.5f; if (area <= SMALL) { if (wedge_area > SMALL) { area += wedge_area; centroid *= wedge_area; } center = centroid; } else { if (wedge_area > SMALL) { area += wedge_area; centroid *= wedge_area; center += centroid; } } if(area > SMALL) { plane.BuildPlane( GetPoint(0), GetPoint(1), GetPoint(2) ); center *= (One_Over_Three/area); } else { center *= One_Over_Three; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /* bool ToDrawTriangle::IntersectTriangle(ToDrawTriangle *tri) { Scalar x, dx, dz, dx1, dz1; int i, i1, j, j1; for(i=0;i<3;i++) { i1 = i<2 ? i+1 : 0; dx1 = v[i1].x - v[i].x; dz1 = v[i1].z - v[i].z; for(j=0;j<3;j++) { j1 = j<2 ? j+1 : 0; dx = tri->v[j1].x - tri->v[j].x; dz = tri->v[j1].z - tri->v[j].z; if(dx<=SMALL && dx1<=SMALL) { continue; } if(dz<=SMALL && dz1<=SMALL) { continue; } if( Close_Enough(dz*dx1, dz1*dx) ) { continue; } x = (dx*dx1*v[i].z - tri->v[j].z*dx*dx1 - dz1*dx*v[i].x + dz*dx1*tri->v[j].x) / (dz*dx1 - dz1*dx); if(v[i].x < v[i1].x) { if(tri->v[j].x < tri->v[j1].x) { if(x>v[i].x && xtri->v[j].x && xv[j1].x) { return true; } } else { if(x>v[i].x && xtri->v[j1].x && xv[j].x) { return true; } } } else { if(tri->v[j].x < tri->v[j1].x) { if(x>v[i1].x && xtri->v[j].x && xv[j1].x) { return true; } } else { if(x>v[i1].x && xtri->v[j1].x && xv[j].x) { return true; } } } } } return false; } */ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // HFSlimMZL::HFSlimMZL() { X = (int)0.0f; Z = (int)0.0f; dX = 2.0f; dY = 0.15f; dZ = 2.0f; xOffset = 0.0f; zOffset = 0.0f; Offset = 0.0f; visHeight = 0; simpleTerrainGroup.SetLength(0); borderPixelFun = 0.0f; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // HFSlimMZL::~HFSlimMZL() { for(int i=0;i h) { ebox.minY = h; } } return ebox; } //--------------------------------------------------------------------------- void HFSlimMZL::Blur2D (int smooth) { // Precondition for stability: 0 < scale < exp(0.25) // Good choice for iterative blurring is scale = exp(0.125) float scale = static_cast(exp(0.125)); float** temp = new float*[Z]; int x, y; for (y = 0; y < Z; y++) temp[y] = new float[X]; for(int i=0;i= X-1 ) // use boundary value xsum += field[y*X+X-1]; else // linearly interpolate xsum += field[y*X+xp]+(rxp-xp)*(field[y*X+xp+1]-field[y*X+xp]); if ( xm <= 0 ) // use boundary value xsum += field[y*X+0]; else // linearly interpolate xsum += field[y*X+xm]+(rxm-xm)*(field[y*X+xm]-field[y*X+xm-1]); // y portion of second central difference float ysum = -2*field[y*X+x]; if ( yp >= Z-1 ) // use boundary value ysum += field[(Z-1)*X+x]; else // linearly interpolate ysum += field[yp*X+x]+(ryp-yp)*(field[(yp+1)*X+x]-field[yp*X+x]); if ( ym <= 0 ) // use boundary value ysum += field[0*X+x]; else // linearly interpolate ysum += field[ym*X+x]+(rym-ym)*(field[ym*X+x]-field[(ym-1)*X+x]); temp[y][x] = field[y*X+x]+logscale*(xsum+ysum); } } for (y = 0; y < Z; y++) for (x = 0; x < X; x++) field[y*X+x] = temp[y][x]; } for (y = 0; y < Z; y++) delete[] temp[y]; delete[] temp; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void HFSlimMZL::FillFromImage(Image &image, int smooth) { X = image.GetWidth()+1; Z = image.GetHeight()+1; Verify(((X-1)%256 == 0) && ((Z-1)%256 == 0)); xDim = image.GetWidth()/256; zDim = image.GetHeight()/256; Verify(image.GetBpp()==8); field.SetLength(X*Z); unsigned char *ptr; ptr=(unsigned char *)image.Lock(); int i, j; for(i=0;iOrg(); Vec2 to = edge->Dest(); int x1 = (int)from[0] & ~31; int z1 = (int)from[1] & ~31; int x2 = (int)to[0] & ~31; int z2 = (int)to[1] & ~31; int color = 0xffffff; if(x1!=x2) { if(abs(x1-x2) > 32) { color &= 0xff00ff; } else { if(x1 32) { color &= 0xffff00; } else { if(z1& tdtrilist, frameArray *frame, MLRState *state ) { int polygon_count = tdtrilist.GetLength(); if(polygon_count==0 || polygon_count*3 >= Limits::Max_Number_Vertices_Per_Mesh) { return false; } #ifndef TERRAIN2_TEST MLR_I_DeT_TMesh *erf_mesh = new MLR_I_DeT_TMesh; #else gos_PushCurrentHeap(MidLevelRenderer::Heap); MLR_Terrain2 *erf_mesh = new MLR_Terrain2; gos_PopCurrentHeap(); erf_mesh->SetDepthData(maxAllDepth-diffLevel, maxAllDepth); erf_mesh->SetTileData(tX, tY); #ifdef BORDERPIXEL erf_mesh->SetBorderPixel(borderPixelFun); #endif // erf_mesh->SetOffset(xOffset, zOffset); // erf_mesh->SetGrid(xGridSize, zGridSize); for(int ii=0;ii<8;ii++) { erf_mesh->SetFrame(ii, (*frame)[ii][0], (*frame)[ii][1], (*frame)[ii][2], (*frame)[ii][3]); } #endif Register_Object(erf_mesh); erf_mesh->SetDetailData( detailInfo.xOff, detailInfo.zOff, detailInfo.xFac*(1< vert_id(X*Z); memset(vert_id.GetData(), 0, vert_id.GetSize()); int i, j, k, l, point_count = 0; int minX[2]={0,0}, maxX[2]={0,0}, minY[2]={0,0}, maxY[2]={0,0}, minZ[2]={0,0}, maxZ[2]={0,0}; Scalar minx=tdtrilist[0]->GetPoint(0).x, maxx=tdtrilist[0]->GetPoint(0).x, miny=tdtrilist[0]->GetPoint(0).y, maxy=tdtrilist[0]->GetPoint(0).y, minz=tdtrilist[0]->GetPoint(0).z, maxz=tdtrilist[0]->GetPoint(0).z; Point3D center0 = Point3D::Identity, center1 = Point3D::Identity, center2 = Point3D::Identity, center3 = Point3D::Identity; int *uPoints = new int [3*polygon_count]; point_count = 0; for(i=0;icenter; for(k=0;k<3;k++) { for(l=0;lv[k]) { break; } } if(l==point_count) { uPoints[point_count++] = tdtrilist[i]->v[k]; center0 += tdtrilist[i]->GetPoint(k); } if(tdtrilist[i]->GetPoint(k).x < minx) { minX[0] = i; minX[1] = k; minx = tdtrilist[i]->GetPoint(k).x; } else if(tdtrilist[i]->GetPoint(k).x > maxx) { maxX[0] = i; maxX[1] = k; maxx = tdtrilist[i]->GetPoint(k).x; } if(tdtrilist[i]->GetPoint(k).y < miny) { minY[0] = i; minY[1] = k; miny = tdtrilist[i]->GetPoint(k).y; } else if(tdtrilist[i]->GetPoint(k).y > maxy) { maxY[0] = i; maxY[1] = k; maxy = tdtrilist[i]->GetPoint(k).y; } if(tdtrilist[i]->GetPoint(k).z < minz) { minZ[0] = i; minZ[1] = k; minz = tdtrilist[i]->GetPoint(k).z; } else if(tdtrilist[i]->GetPoint(k).z > maxz) { maxZ[0] = i; maxZ[1] = k; maxz = tdtrilist[i]->GetPoint(k).z; } } } center0 *= 1.0f/point_count; center0.x = GetX(center0.x); center0.y += Offset; center0.z = GetZ(center0.z); center3 *= 1.0f/polygon_count; center3.x = GetX(center3.x); center3.y += Offset; center3.z = GetZ(center3.z); Vector3D v3; Scalar d[3]; v3.Subtract(tdtrilist[maxX[0]]->GetPoint(maxX[1]), tdtrilist[minX[0]]->GetPoint(minX[1])); d[0] = v3.GetLengthSquared(); v3.Subtract(tdtrilist[maxY[0]]->GetPoint(maxY[1]), tdtrilist[minY[0]]->GetPoint(minY[1])); d[1] = v3.GetLengthSquared(); v3.Subtract(tdtrilist[maxZ[0]]->GetPoint(maxZ[1]), tdtrilist[minZ[0]]->GetPoint(minZ[1])); d[2] = v3.GetLengthSquared(); if(d[0] > d[1]) { if(d[0]>d[2]) { center1 = tdtrilist[maxX[0]]->GetPoint(maxX[1]); center1 += tdtrilist[minX[0]]->GetPoint(minX[1]); center1 *= 0.5f; } else { center1 = tdtrilist[maxZ[0]]->GetPoint(maxZ[1]); center1 += tdtrilist[minZ[0]]->GetPoint(minZ[1]); center1 *= 0.5f; } } else { if(d[1]>d[2]) { center1 = tdtrilist[maxY[0]]->GetPoint(maxY[1]); center1 += tdtrilist[minY[0]]->GetPoint(minY[1]); center1 *= 0.5f; } else { center1 = tdtrilist[maxZ[0]]->GetPoint(maxZ[1]); center1 += tdtrilist[minZ[0]]->GetPoint(minZ[1]); center1 *= 0.5f; } } center1.x = GetX(center1.x); center1.y += Offset; center1.z = GetZ(center1.z); center2.x = GetX((maxx+minx)*0.5f); center2.y = (maxy+miny)*0.5f; center2.z = GetZ((maxz+minz)*0.5f); center2.y += Offset; Point3D *coords = new Point3D [point_count]; Vector2DScalar *texCoords = new Vector2DScalar[point_count]; UnitVector3D sun; sun = Vector3D(-1.0f, -1.0f, 0.0f); Scalar radiusSquared, maxRadius0 = 0.0f, maxRadius1 = 0.0f, maxRadius2 = 0.0f, maxRadius3 = 0.0f; for(i=0;i=(*frame)[maxAllDepth][0]); Verify(coords[i].z<=(*frame)[maxAllDepth][3] && coords[i].z>=(*frame)[maxAllDepth][1]); v3.Subtract(coords[i], center0); radiusSquared = v3.GetLengthSquared(); maxRadius0 = radiusSquared>maxRadius0 ? radiusSquared:maxRadius0; v3.Subtract(coords[i], center1); radiusSquared = v3.GetLengthSquared(); maxRadius1 = radiusSquared>maxRadius1 ? radiusSquared:maxRadius1; v3.Subtract(coords[i], center2); radiusSquared = v3.GetLengthSquared(); maxRadius2 = radiusSquared>maxRadius2 ? radiusSquared:maxRadius2; v3.Subtract(coords[i], center3); radiusSquared = v3.GetLengthSquared(); maxRadius3 = radiusSquared>maxRadius3 ? radiusSquared:maxRadius3; #ifndef TERRAIN2_TEST texCoords[i][0] = borderPixelFun + (1.0f-2*borderPixelFun)*(((*frame)[maxAllDepth][2] - coords[i].x)/((*frame)[maxAllDepth][2]-uvFrame->minX)); texCoords[i][1] = borderPixelFun + (1.0f-2*borderPixelFun)*(((*frame)[maxAllDepth][3] - coords[i].z)/((*frame)[maxAllDepth][3]-uvFrame->minZ)); #endif } maxRadius0 = static_cast(sqrt(maxRadius0)); maxRadius1 = static_cast(sqrt(maxRadius1)); maxRadius2 = static_cast(sqrt(maxRadius2)); maxRadius3 = static_cast(sqrt(maxRadius3)); Point3D center; Scalar maxRadius; if(maxRadius0v[k]) { break; } } Verify(jSetSubprimitiveLengths(NULL, l/3); erf_mesh->SetCoordData(coords, point_count); #ifdef TERRAIN2_TEST erf_mesh->SetCurrentDepth(maxAllDepth-diffLevel); #else erf_mesh->SetTexCoordData(texCoords, point_count); #endif erf_mesh->SetIndexData(index, l); gos_PopCurrentHeap(); // delete [] uPoints; // delete [] coords; // delete [] texCoords; // delete [] index; erf_mesh->FindFacePlanes(); if(state) { erf_mesh->SetReferenceState(*state); } else { erf_mesh->SetReferenceState(state0); } erf_mesh->SetReferenceState(state1, 1); gos_PushCurrentHeap(ElementRenderer::Heap); ShapeElement* Shape = new ShapeElement; Register_Object(Shape); gos_PopCurrentHeap(); gos_PushCurrentHeap(MidLevelRenderer::Heap); MLRShape *shape = new MLRShape(1); Register_Object(shape); gos_PopCurrentHeap(); shape->Add(erf_mesh); erf_mesh->DetachReference(); Shape->SetMLRShape(shape); Shape->m_localOBB.localToParent = LinearMatrix4D::Identity; Shape->m_localOBB.localToParent.BuildTranslation(center); Shape->m_localOBB.sphereRadius = maxRadius; parent->AttachIndexedChild(listIndex, Shape); Shape->SetVolumeCullMode(); return true; } int primCounter, maxPrims; bool HFSlimMZL::BinSort( ListElement *parent, int index, int levDiff, DynamicArrayOf& tdtrilist, int binSize, frameArray *frame, MLRState *state ) { int polygon_count = tdtrilist.GetLength(); if (polygon_count==0) { return false; } // //--------------------------------------------------------- // If the polygon mesh is already small enough, just return //--------------------------------------------------------- // if (polygon_count <= binSize) { return CreateMesh(parent, index, levDiff, tdtrilist, frame, state); } DynamicArrayOf centroids(polygon_count); unsigned i; for (i=0; icenter; } // //------------------------------------------------------------------------ // Calculate the dividing plane, and if none can be found, don't do nothin //------------------------------------------------------------------------ // Plane plane; if (!plane.ComputeBestDividingPlane(centroids)) { return CreateMesh(parent, index, levDiff, tdtrilist, frame, state); } // //------------------------------------------------------------------------- // The mesh is too big, so we have to cut it up. Make a group proxy to // hold the new mesh collection //------------------------------------------------------------------------- // Check_Object(parent); gos_PushCurrentHeap(ElementRenderer::Heap); ListElement *group = new ListElement; Register_Object(group); group->SetSize(2); gos_PopCurrentHeap(); // //---------------------------------- // Set the position of the group //---------------------------------- // LinearMatrix4D m; m = parent->GetLocalToParent(); parent->SetLocalToParent(LinearMatrix4D::Identity); group->SetLocalToParent(m); #if 0 const char *name; if ((name=parent->GetName())!=NULL) { parent->SetName(NULL); group->SetName(name); } #endif DynamicArrayOf group_a(polygon_count), group_b(polygon_count); unsigned count_a = 0, count_b = 0; // //------------------------------------------------------------------ // Sort each of the centroids against the plane into one of two bins //------------------------------------------------------------------ // for (i=0; i0); group_a.SetLength(count_a); // bin_a->AddPolygons(process, group_a); Verify(count_b>0); group_b.SetLength(count_b); // bin_b->AddPolygons(process, group_b); // //------------------------------------------------------------------- // Now that the mesh has been split up, Bin_Sort each smaller mesh and // destroy this mesh //------------------------------------------------------------------- // int worked = 0; if (BinSort( group, 0, levDiff, group_a, binSize, frame, state)) { worked |= 1; } if (BinSort( group, 1, levDiff, group_b, binSize, frame, state)) { worked |= 2; } if(worked != 3) { if(worked == 0) return false; ListElement *smallgroup = new ListElement; Register_Object(smallgroup); group->SetSize(1); Element *element; if(worked==1) { element = group->GetIndexedElement(0); element->DetachFromParent(); } else { element = group->GetIndexedElement(1); element->DetachFromParent(); } delete group; smallgroup->AttachIndexedChild(0, element); Check_Object(smallgroup); parent->AttachIndexedChild(index, smallgroup); } else { Check_Object(group); parent->AttachIndexedChild(index, group); } // //----------------------------------------- // Now set the bounding sphere of the group //----------------------------------------- // group->NeedNewBounds(); group->SetVolumeCullMode(); return true; } void HFSlimMZL::OptimizeHField(int depth, int binSize) { if(X*Z == 0) { return; } fprintf(stdout, "Going to optimize the terrain: MaxNr.Of Points: %d BinSize: %d\n", depth, binSize); DirectMap map(X,Z); int i, j; float maxY = 0; for(j=0;jwidth=X; MASK->height=Z; GreedySubdivision mesh(&map); point_limit=1024; point_limit = depth; int count=1; while(mesh.pointCount() error_threshold) { mesh.greedyInsert(); } fprintf(stdout, "The mesh was greedy.\n"); usedUniquePoints = 0; usedTriangleIndices = 0; uniquePoints.SetLength(2*mesh.pointCount()); TriangleStruct::points = uniquePoints.GetData(); triangleIndices.SetLength(8*mesh.pointCount()); mesh.overFaces(GetFacesCB, NULL); for(i=0;i(dY*mesh.eval( (int)(uniquePoints[i].p.x), (int)(uniquePoints[i].p.z) )); uniquePoints[i].p.x *= dX; uniquePoints[i].p.z *= dZ; } for(i=0;i Stuff::SMALL) ) { STOP(("Found a triangle with a face normal not pointing up, consider revising map !")); } } fprintf(stdout, "optimized to %d triangles.\n", usedTriangleIndices); } int brokenTriangles; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /* void AnalyzeThis( DynamicArrayOf &tempTrianglesPtr, Scalar x0, Scalar z0, Scalar x1, Scalar z1 ) { int i, j, k, l, len = tempTrianglesPtr.GetLength(); int divide = 2; Scalar x0n, z0n, x1n, z1n; fprintf(analyzeFile, "%d ", len); int in, out; for(i=0;iGetV0().x >= x0n && tempTrianglesPtr[k]->GetV0().x <= x1n && tempTrianglesPtr[k]->GetV0().z >= z0n && tempTrianglesPtr[k]->GetV0().z < z1n ) { l++; } if( tempTrianglesPtr[k]->GetV1().x >= x0n && tempTrianglesPtr[k]->GetV1().x <= x1n && tempTrianglesPtr[k]->GetV1().z >= z0n && tempTrianglesPtr[k]->GetV1().z <= z1n ) { l++; } if( tempTrianglesPtr[k]->GetV2().x >= x0n && tempTrianglesPtr[k]->GetV2().x <= x1n && tempTrianglesPtr[k]->GetV2().z >= z0n && tempTrianglesPtr[k]->GetV2().z <= z1n ) { l++; } if(l==3) { in++; } else if(l>0) { if( tempTrianglesPtr[k]->center.x >= x0n && tempTrianglesPtr[k]->center.x <= x1n && tempTrianglesPtr[k]->center.z >= z0n && tempTrianglesPtr[k]->center.z <= z1n ) { out++; } } } fprintf(analyzeFile, "%d %d ", in, out); } } fprintf(analyzeFile, "\n"); } */ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void HFSlimMZL::CreateTile( ElementRenderer::ListElement *list, DynamicArrayOf& tempTrianglesPtr, int index, int depth, int maxdepth, int maxNumOfTrianglesPerMesh, Scalar xGridOffset, Scalar zGridOffset, Scalar xGrid, Scalar zGrid, int tileX, int tileZ, const char *texRoot ) { char textureName[1024]; Scalar x0, z0, x1, z1; x0 = xGridOffset + tileX*xGrid; z0 = zGridOffset + tileZ*zGrid; x1 = x0 + xGrid; z1 = z0 + zGrid; MLRState state; gos_PushCurrentHeap(ElementRenderer::Heap); ElementRenderer::GroupElement *group = new GroupElement; Register_Object(group); list->AttachIndexedChild(index, group); group->NeedNewBounds(); group->SetVolumeCullMode(); ElementRenderer::ListElement *subList = new ListElement; Register_Object(subList); subList->SetSize(1); group->AttachChild(subList); subList->NeedNewBounds(); subList->SetVolumeCullMode(); gos_PopCurrentHeap(); /* state.SetBackFaceOn(); state.SetDitherOff(); state.SetTextureCorrectionOn(); state.SetZBufferCompareOn(); state.SetZBufferWriteOn(); state.SetFilterMode(MLRState::BiLinearFilterMode); state.SetFogMode(MLRState::OverrideFogMode); state.SetFogData( 0xff9090f0, 0.0f, 700.0f, 1000.0f ); */ state.SetPriority(MLRState::DefaultPriority); #if 0 sprintf(textureName, "%s_%1d_%02x%02x", texRoot, depth, (1<Add(textureName); texture->SetHint(gosHint_AGPMemory | gosHint_DontShrink); state.SetTextureHandle(texture->GetTextureHandle()); state.SetTextureWrapMode(MLRState::TextureClamp); /* AnalyzeThis( tempTrianglesPtr, x0, z0, x1, z1 ); */ int i = 1<<(maxdepth - depth); Scalar frame[8][4]; 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; 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; } /* x0 = xGridOffset + (tileX/i)*(i*xGrid); z0 = zGridOffset + (tileZ/i)*(i*zGrid); x1 = x0 + i*xGrid; z1 = z0 + i*zGrid; Stuff::ExtentBox box; box.minX = x0; box.maxX = x1; box.minY = Offset; box.maxY = Offset+256.0f; box.minZ = z0; box.maxZ = z1; */ if(!BinSort( subList, 0, maxdepth - depth, tempTrianglesPtr, maxNumOfTrianglesPerMesh, &frame, &state ) ) { PAUSE(("Unstable triangle mesh created!")); } group->Sync(); group->LockBounds(); group->SetNeverCullMode(); subList->LockBounds(); subList->SetNeverCullMode(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void HFSlimMZL::BuildTile( DynamicArrayOf& tempTrianglesPtr, int index, int depth, int maxdepth, int numOfTriangles, DynamicArrayOf& onOffPoints, int maxNumOfTrianglesPerMesh, Scalar xGridOffset, Scalar zGridOffset, Scalar xGrid, Scalar zGrid, int tileX, int tileZ ) { int orgUsedTriangleIndices = usedTriangleIndices; int i, j, inCount, newCount = 0, extraTriangles = 0, refused = 0; int k, l, m; Scalar x0, z0, x1, z1; x0 = xGridOffset + tileX*xGrid; z0 = zGridOffset + tileZ*zGrid; x1 = x0 + xGrid; z1 = z0 + zGrid; for(i=0,j=0;i x1) { clipIt[k] |= 4; } if(triangleIndices[i].GetPoint(k).z < z0) { clipIt[k] |= 8; } if(triangleIndices[i].GetPoint(k).z > z1) { clipIt[k] |= 2; } orIt |= clipIt[k]; addIt &= clipIt[k]; } if(orIt == 0) { onOffPoints[i] = 1; tempTrianglesPtr[newCount++] = &triangleIndices[i]; uniquePoints[triangleIndices[i].v[0]].Add(&triangleIndices[i], 0); uniquePoints[triangleIndices[i].v[1]].Add(&triangleIndices[i], 1); uniquePoints[triangleIndices[i].v[2]].Add(&triangleIndices[i], 2); } else if(addIt==0) { if(orIt==1 || orIt==2 || orIt==4 || orIt==8) { Point3D triangle[3], clipPoints[6]; int index[6]; float angles[6]; for(k=0;k<3;k++) { triangle[k] = triangleIndices[i].GetPoint(k); } l = 0; for(k=0;k<3;k++) { int next = k+1>2?0:k+1; if(clipIt[k]==0) { clipPoints[l++] = triangle[k]; if(clipIt[next]==0) { continue; } } else { if(clipIt[next]!=0) { continue; } } // //----------------------------------------------------- // Find the boundary conditions that match our clipping // plane //----------------------------------------------------- // int mask = 1; for (m=0; m<4; m++) { if((clipIt[k] | clipIt[next]) & mask) { switch(m) { case 0: clipPoints[l].AddScaled( triangle[k], Vector3D( triangle[next].x - triangle[k].x, triangle[next].y - triangle[k].y, triangle[next].z - triangle[k].z ), (x0-triangle[k].x)/(triangle[next].x-triangle[k].x) ); clipPoints[l++].x = x0; break; case 1: clipPoints[l].AddScaled( triangle[k], Vector3D( triangle[next].x - triangle[k].x, triangle[next].y - triangle[k].y, triangle[next].z - triangle[k].z ), (z1-triangle[k].z)/(triangle[next].z-triangle[k].z) ); clipPoints[l++].z = z1; break; case 2: clipPoints[l].AddScaled( triangle[k], Vector3D( triangle[next].x - triangle[k].x, triangle[next].y - triangle[k].y, triangle[next].z - triangle[k].z ), (x1-triangle[k].x)/(triangle[next].x-triangle[k].x) ); clipPoints[l++].x = x1; break; case 3: clipPoints[l].AddScaled( triangle[k], Vector3D( triangle[next].x - triangle[k].x, triangle[next].y - triangle[k].y, triangle[next].z - triangle[k].z ), (z0-triangle[k].z)/(triangle[next].z-triangle[k].z) ); clipPoints[l++].z = z0; break; } break; } mask <<= 1; } } Verify(l>2); for(m=0;m a) { a = angles[m]; ba = m; } } for(m=1;m x1) { clipMeToo[key][k] |= 4; } if(clipPoints[key][k].z < z0) { clipMeToo[key][k] |= 8; } if(clipPoints[key][k].z > z1) { clipMeToo[key][k] |= 2; } } len[!key] = 0; } mask <<= 1; } for(m=0;m a) { a = angles[m]; ba = m; } } for(m=1;mGetPoint(0).x >= x0); Verify(tempTrianglesPtr[i]->GetPoint(0).x <= x1); Verify(tempTrianglesPtr[i]->GetPoint(0).z >= z0); Verify(tempTrianglesPtr[i]->GetPoint(0).z <= z1); Verify(tempTrianglesPtr[i]->GetPoint(1).x >= x0); Verify(tempTrianglesPtr[i]->GetPoint(1).x <= x1); Verify(tempTrianglesPtr[i]->GetPoint(1).z >= z0); Verify(tempTrianglesPtr[i]->GetPoint(1).z <= z1); Verify(tempTrianglesPtr[i]->GetPoint(2).x >= x0); Verify(tempTrianglesPtr[i]->GetPoint(2).x <= x1); Verify(tempTrianglesPtr[i]->GetPoint(2).z >= z0); Verify(tempTrianglesPtr[i]->GetPoint(2).z <= z1); } } #endif brokenTriangles += newCount; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool HFSlimMZL::SetMegaTexture( int nrOfLevels, int bucketSize, const char *theName ) { static char megaBaseName[1024]; if(detailInfo.name) { /* state1.SetBackFaceOn(); state1.SetDitherOff(); state1.SetTextureCorrectionOn(); state1.SetZBufferCompareOn(); state1.SetZBufferWriteOff(); state1.SetFilterMode(MLRState::BiLinearFilterMode); state1.SetFogMode(MLRState::DisableFogMode); state1.SetFogData( 0xff000000, 0.0f, 90.0f, 100.0f ); */ state1.SetTextureWrapMode(MLRState::TextureWrap); state1.SetAlphaMode(detailInfo.alphaMode); state1.SetPriority(MLRState::DefaultPriority + 1); MLRTexture *texture = MLRTexturePool::Instance->Add(detailInfo.name); state1.SetTextureHandle(texture->GetTextureHandle()); } DynamicArrayOf onOffTriangles; onOffTriangles.AssignValue(0, triangleIndices.GetLength()); int i, j, k, l, level; simpleTerrainGroup.SetLength(xDim*zDim); Stuff::ExtentBox allBox; allBox = GetExtents(); int len = 1< *tempTrianglesPtr; tempTrianglesPtr = new DynamicArrayOf [zDim*xDim*len*len]; for(l=0;l(fmod(uniquePoints[i].p.x, dX)))) { point.x = static_cast(dX*floor(uniquePoints[i].p.x*one_over_dX + 0.5)); redo = true; } if(!Small_Enough(static_cast(fmod(uniquePoints[i].p.z, dZ)))) { point.z = static_cast(dZ*floor(uniquePoints[i].p.z*one_over_dZ + 0.5)); redo = true; } if(redo==true) { point.y = GetHeight((int)(point.x/dX), (int)(point.z/dZ)); int pi = FindPoint(point); uniquePoints[i].p = point; if(pi<0 || i==pi) { for(j=0;jv[0]].CalculateAngles(); uniquePoints[uniquePoints[i].myTri[j].tri->v[1]].CalculateAngles(); uniquePoints[uniquePoints[i].myTri[j].tri->v[2]].CalculateAngles(); } uniquePoints[i].CalculateAngles(); } else { int from, to; if(iv[k] == from) { uniquePoints[to].myTri[j].tri->v[k] = to; } } } for(k=0;kv[0]].CalculateAngles(); uniquePoints[uniquePoints[i].myTri[k].tri->v[1]].CalculateAngles(); uniquePoints[uniquePoints[i].myTri[k].tri->v[2]].CalculateAngles(); } uniquePoints[to].CalculateAngles(); uniquePoints[from].connectedTo = 0; } } } tJunction = 0; for(i=0;i Stuff::SMALL && triangleIndices[i].plane.normal.y < Stuff::SMALL) { int pmin, pmid, pmax; bool xCase = false, zCase = false; if( Close_Enough(triangleIndices[i].GetPoint(0).x, triangleIndices[i].GetPoint(1).x) && Close_Enough(triangleIndices[i].GetPoint(0).x, triangleIndices[i].GetPoint(2).x) ) { if(triangleIndices[i].GetPoint(0).z < triangleIndices[i].GetPoint(1).z) { if(triangleIndices[i].GetPoint(0).z < triangleIndices[i].GetPoint(2).z) { pmin = triangleIndices[i].v[0]; if(triangleIndices[i].GetPoint(1).z < triangleIndices[i].GetPoint(2).z) { pmid = triangleIndices[i].v[1]; pmax = triangleIndices[i].v[2]; } else { pmid = triangleIndices[i].v[2]; pmax = triangleIndices[i].v[1]; } } else { pmin = triangleIndices[i].v[2]; pmid = triangleIndices[i].v[0]; pmax = triangleIndices[i].v[1]; } } else { if(triangleIndices[i].GetPoint(1).z < triangleIndices[i].GetPoint(2).z) { pmin = triangleIndices[i].v[1]; if(triangleIndices[i].GetPoint(0).z < triangleIndices[i].GetPoint(2).z) { pmid = triangleIndices[i].v[0]; pmax = triangleIndices[i].v[2]; } else { pmid = triangleIndices[i].v[2]; pmax = triangleIndices[i].v[0]; } } else { pmin = triangleIndices[i].v[2]; pmid = triangleIndices[i].v[1]; pmax = triangleIndices[i].v[0]; } } xCase = true; } if( Close_Enough(triangleIndices[i].GetPoint(0).z, triangleIndices[i].GetPoint(1).z) && Close_Enough(triangleIndices[i].GetPoint(0).z, triangleIndices[i].GetPoint(2).z) ) { if(triangleIndices[i].GetPoint(0).x < triangleIndices[i].GetPoint(1).x) { if(triangleIndices[i].GetPoint(0).x < triangleIndices[i].GetPoint(2).x) { pmin = triangleIndices[i].v[0]; if(triangleIndices[i].GetPoint(1).x < triangleIndices[i].GetPoint(2).x) { pmid = triangleIndices[i].v[1]; pmax = triangleIndices[i].v[2]; } else { pmid = triangleIndices[i].v[2]; pmax = triangleIndices[i].v[1]; } } else { pmin = triangleIndices[i].v[2]; pmid = triangleIndices[i].v[0]; pmax = triangleIndices[i].v[1]; } } else { if(triangleIndices[i].GetPoint(1).x < triangleIndices[i].GetPoint(2).x) { pmin = triangleIndices[i].v[1]; if(triangleIndices[i].GetPoint(0).x < triangleIndices[i].GetPoint(2).x) { pmid = triangleIndices[i].v[0]; pmax = triangleIndices[i].v[2]; } else { pmid = triangleIndices[i].v[2]; pmax = triangleIndices[i].v[0]; } } else { pmin = triangleIndices[i].v[2]; pmid = triangleIndices[i].v[1]; pmax = triangleIndices[i].v[0]; } } zCase = true; } Verify(!(zCase && xCase)); Verify(uniquePoints[pmin].p.x <= uniquePoints[pmid].p.x && uniquePoints[pmid].p.x <= uniquePoints[pmax].p.x); Verify(uniquePoints[pmin].p.z <= uniquePoints[pmid].p.z && uniquePoints[pmid].p.z <= uniquePoints[pmax].p.z); int pfaraway = -1; int pminDI = -1, pminVI = -1; for(j=0;jarea < Stuff::SMALL) { continue; } if(&triangleIndices[i]==uniquePoints[pmin].myTri[j].tri) { if(pminVI>=0) { STOP(("What, the hell, happend ?")); } pminVI = j; continue; } for(k=0;k<3;k++) { if(uniquePoints[pmin].myTri[j].tri->v[k]==pmax) { break; } } if(k<3) { for(k=0;k<3;k++) { if(uniquePoints[pmin].myTri[j].tri->v[k]!=pmax && uniquePoints[pmin].myTri[j].tri->v[k]!=pmin) { pfaraway = uniquePoints[pmin].myTri[j].tri->v[k]; break; } } Verify(pfaraway>=0); if(pminDI<0) { pminDI = j; } else { STOP(("Now we are in real trouble !")); } } } int pmaxDI = -1, pmaxVI = -1; for(j=0;jarea < Stuff::SMALL) { continue; } if(&triangleIndices[i]==uniquePoints[pmax].myTri[j].tri) { if(pmaxVI>=0) { STOP(("What, the hell, happend ?")); } pmaxVI = j; continue; } for(k=0;k<3;k++) { if(uniquePoints[pmax].myTri[j].tri->v[k]==pmin) { break; } } if(k<3) { for(k=0;k<3;k++) { if(uniquePoints[pmax].myTri[j].tri->v[k]!=pmax && uniquePoints[pmax].myTri[j].tri->v[k]!=pmin) { Verify(pfaraway == uniquePoints[pmax].myTri[j].tri->v[k]); break; } } if(pmaxDI<0) { pmaxDI = j; } else { STOP(("Now we are in real trouble !")); } } } if(pminDI>=0 && pmaxDI>=0) { for(k=0;k<3;k++) { if(uniquePoints[pmin].myTri[pminDI].tri->v[k]==pmax) { uniquePoints[pmin].myTri[pminDI].tri->v[k] = pmid; uniquePoints[pmid].Add(uniquePoints[pmin].myTri[pminDI].tri, k); uniquePoints[pmin].myTri[pminDI].tri->GetSurfaceAreaAndCentroid(); break; } } uniquePoints[pmin].connectedTo--; for(j=pminVI;jv[k]==pmin) { uniquePoints[pmax].myTri[pmaxVI].tri->v[k] = pfaraway; uniquePoints[pfaraway].Add(uniquePoints[pmax].myTri[pmaxVI].tri, k); uniquePoints[pmax].myTri[pmaxVI].tri->GetSurfaceAreaAndCentroid(); break; } } uniquePoints[pmax].connectedTo--; for(j=pmaxDI;j tileTrianglesPtr; for(l=0;lSetName("OptimizedTerrain"); gos_PopCurrentHeap(); for(j=0;jarea < SMALL) { continue; } else if(tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i][m]->plane.normal.y < Stuff::SMALL) { continue; } tileTrianglesPtr[usable++] = tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i][m]; } tileTrianglesPtr.SetLength(usable); tX = i; tY = j; CreateTile( simpleTerrainGroup[l*xDim+k], tileTrianglesPtr, j*len+i, level, nrOfLevels, bucketSize, xOffset, zOffset, xGridSize, zGridSize, i, j, megaBaseName ); } } simpleTerrainGroup[l*xDim+k]->LockBounds(); } } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Scalar HFSlimMZL::GetHeight(int x, int z) { if (x<0) x = 0; if (x>GetX()-1) { x = GetX() - 1; } if (z<0) z = 0; if (z>GetZ()-1) { z = GetZ() - 1; } return field[z*X + x]*dY + Offset; }