#include #if !defined(HFSLIM_HPP) #include "HFslim.hpp" #include "terra\terra.hpp" #endif const Scalar One_Over_Three = 1.0f/3.0f; extern FILE *analyzeFile; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ToDrawTriangle::GetSurfaceAreaAndCentroid() { // //--------------------- // 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; // //----------------------------------------------- // Generate all the information on the first pass //----------------------------------------------- // position_a = v[0]; position_b = v[1]; position_c = v[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) { center *= (One_Over_Three/area); } else { center *= One_Over_Three; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // HFSlim::HFSlim() { 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; nrOfIZs = 0; terrainGroup = new GroupElement(); Register_Object(terrainGroup); fullTerrainGroup = NULL; simpleTerrainGroup = NULL; borderPixelFun = 0.0f; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // HFSlim::~HFSlim() { if(fullTerrainGroup!=NULL) { Unregister_Object(fullTerrainGroup); delete fullTerrainGroup; fullTerrainGroup = NULL; } if(simpleTerrainGroup!=NULL) { Unregister_Object(simpleTerrainGroup); delete simpleTerrainGroup; simpleTerrainGroup = NULL; } Unregister_Object(terrainGroup); delete terrainGroup; terrainGroup = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Stuff::ExtentBox HFSlim::GetExtents() { Stuff::ExtentBox ebox; ebox.minX = GetX(0); ebox.minZ = GetZ(0); ebox.maxX = GetX(X-1); ebox.maxZ = GetZ(Z-1); int i, j; Scalar h; ebox.maxY = ebox.minY = GetHeight(0, 0); for (j=1;j h) { ebox.minY = h; } } return ebox; } //--------------------------------------------------------------------------- void HFSlim::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 HFSlim::FillFromImage(Image &image, int smooth) { X = image.GetWidth()+1; Z = image.GetHeight()+1; Verify(image.GetBpp()==8); field.SetLength(X*Z); unsigned char *ptr; ptr=(unsigned char *)image.Lock(); int i, j; for(i=0;i& tdtrilist, ExtentBox *uvFrame, 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 MLR_Terrain2 *erf_mesh = new MLR_Terrain2; erf_mesh->SetOffset(0.0f, 0.0f); erf_mesh->SetDepthData(maxAllDepth-diffLevel, maxAllDepth); erf_mesh->SetTileData(tX, tY); erf_mesh->SetGrid(xGridSize, zGridSize); erf_mesh->SetBorderPixel(borderPixelFun); #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, x, z, 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]->v[0].x, maxx=tdtrilist[0]->v[0].x, miny=tdtrilist[0]->v[0].y, maxy=tdtrilist[0]->v[0].y, minz=tdtrilist[0]->v[0].z, maxz=tdtrilist[0]->v[0].z; Point3D center0 = Point3D::Identity, center1 = Point3D::Identity, center2 = Point3D::Identity, center3 = Point3D::Identity; for(i=0;icenter; if(tdtrilist[i]->v[0].x < minx) { minX[0] = i; minX[1] = 0; minx = tdtrilist[i]->v[0].x; } else if(tdtrilist[i]->v[0].x > maxx) { maxX[0] = i; maxX[1] = 0; maxx = tdtrilist[i]->v[0].x; } if(tdtrilist[i]->v[0].y < miny) { minY[0] = i; minY[1] = 0; miny = tdtrilist[i]->v[0].y; } else if(tdtrilist[i]->v[0].y > maxy) { maxY[0] = i; maxY[1] = 0; maxy = tdtrilist[i]->v[0].y; } if(tdtrilist[i]->v[0].z < minz) { minZ[0] = i; minZ[1] = 0; minz = tdtrilist[i]->v[0].z; } else if(tdtrilist[i]->v[0].z > maxz) { maxZ[0] = i; maxZ[1] = 0; maxz = tdtrilist[i]->v[0].z; } x = (int)(tdtrilist[i]->v[0].x/dX); z = (int)(tdtrilist[i]->v[0].z/dZ); vert_id[x + X*z]++; if(vert_id[x + X*z]==1) { center0 += tdtrilist[i]->v[0]; point_count++; } if(tdtrilist[i]->v[2].x < minx) { minX[0] = i; minX[1] = 2; minx = tdtrilist[i]->v[2].x; } else if(tdtrilist[i]->v[2].x > maxx) { maxX[0] = i; maxX[1] = 2; maxx = tdtrilist[i]->v[2].x; } if(tdtrilist[i]->v[2].y < miny) { minY[0] = i; minY[1] = 2; miny = tdtrilist[i]->v[2].y; } else if(tdtrilist[i]->v[2].y > maxy) { maxY[0] = i; maxY[1] = 2; maxy = tdtrilist[i]->v[2].y; } if(tdtrilist[i]->v[2].z < minz) { minZ[0] = i; minZ[1] = 2; minz = tdtrilist[i]->v[2].z; } else if(tdtrilist[i]->v[2].z > maxz) { maxZ[0] = i; maxZ[1] = 2; maxz = tdtrilist[i]->v[2].z; } x = (int)(tdtrilist[i]->v[2].x/dX); z = (int)(tdtrilist[i]->v[2].z/dZ); vert_id[x + X*z]++; if(vert_id[x + X*z]==1) { center0 += tdtrilist[i]->v[1]; point_count++; } if(tdtrilist[i]->v[1].x < minx) { minX[0] = i; minX[1] = 0; minx = tdtrilist[i]->v[1].x; } else if(tdtrilist[i]->v[1].x > maxx) { maxX[0] = i; maxX[1] = 1; maxx = tdtrilist[i]->v[1].x; } if(tdtrilist[i]->v[1].y < miny) { minY[0] = i; minY[1] = 1; miny = tdtrilist[i]->v[1].y; } else if(tdtrilist[i]->v[1].y > maxy) { maxY[0] = i; maxY[1] = 1; maxy = tdtrilist[i]->v[1].y; } if(tdtrilist[i]->v[1].z < minz) { minZ[0] = i; minZ[1] = 1; minz = tdtrilist[i]->v[1].z; } else if(tdtrilist[i]->v[1].z > maxz) { maxZ[0] = i; maxZ[1] = 1; maxz = tdtrilist[i]->v[1].z; } x = (int)(tdtrilist[i]->v[1].x/dX); z = (int)(tdtrilist[i]->v[1].z/dZ); vert_id[x + X*z]++; if(vert_id[x + X*z]==1) { center0 += tdtrilist[i]->v[2]; point_count++; } } 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]]->v[maxX[1]], tdtrilist[minX[0]]->v[minX[1]]); d[0] = v3.GetLengthSquared(); v3.Subtract(tdtrilist[maxY[0]]->v[maxY[1]], tdtrilist[minY[0]]->v[minY[1]]); d[1] = v3.GetLengthSquared(); v3.Subtract(tdtrilist[maxZ[0]]->v[maxZ[1]], tdtrilist[minZ[0]]->v[minZ[1]]); d[2] = v3.GetLengthSquared(); if(d[0] > d[1]) { if(d[0]>d[2]) { center1 = tdtrilist[maxX[0]]->v[maxX[1]]; center1 += tdtrilist[minX[0]]->v[minX[1]]; center1 *= 0.5f; } else { center1 = tdtrilist[maxZ[0]]->v[maxZ[1]]; center1 += tdtrilist[minZ[0]]->v[minZ[1]]; center1 *= 0.5f; } } else { if(d[1]>d[2]) { center1 = tdtrilist[maxY[0]]->v[maxY[1]]; center1 += tdtrilist[minY[0]]->v[minY[1]]; center1 *= 0.5f; } else { center1 = tdtrilist[maxZ[0]]->v[maxZ[1]]; center1 += tdtrilist[minZ[0]]->v[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); int nrOfPoints = 0; Scalar radiusSquared, maxRadius0 = 0.0f, maxRadius1 = 0.0f, maxRadius2 = 0.0f, maxRadius3 = 0.0f; for(z=0;z 0 ) { Verify(nrOfPointsmaxRadius0 ? radiusSquared:maxRadius0; v3.Subtract(coords[nrOfPoints], center1); radiusSquared = v3.GetLengthSquared(); maxRadius1 = radiusSquared>maxRadius1 ? radiusSquared:maxRadius1; v3.Subtract(coords[nrOfPoints], center2); radiusSquared = v3.GetLengthSquared(); maxRadius2 = radiusSquared>maxRadius2 ? radiusSquared:maxRadius2; v3.Subtract(coords[nrOfPoints], center3); radiusSquared = v3.GetLengthSquared(); maxRadius3 = radiusSquared>maxRadius3 ? radiusSquared:maxRadius3; #ifndef TERRAIN2_TEST texCoords[nrOfPoints][0] = borderPixelFun + (1.0f-2*borderPixelFun)*((uvFrame->maxX - coords[nrOfPoints].x)/(uvFrame->maxX-uvFrame->minX)); texCoords[nrOfPoints][1] = borderPixelFun + (1.0f-2*borderPixelFun)*((uvFrame->maxZ - coords[nrOfPoints].z)/(uvFrame->maxZ-uvFrame->minZ)); #endif nrOfPoints++; } else vert_id[z*X+x] = -1; } 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[0].x/dX); z = (int)(tdtrilist[i]->v[0].z/dZ); j = x + X*z; Verify(vert_id[j]>=0); index[l++] = vert_id[j]; if(z==Z-1) k++; x = (int)(tdtrilist[i]->v[2].x/dX); z = (int)(tdtrilist[i]->v[2].z/dZ); j = x + X*z; Verify(vert_id[j]>=0); index[l++] = vert_id[j]; if(z==Z-1) k++; x = (int)(tdtrilist[i]->v[1].x/dX); z = (int)(tdtrilist[i]->v[1].z/dZ); j = x + X*z; Verify(vert_id[j]>=0); index[l++] = vert_id[j]; if(z==Z-1) k++; if(k>=2) { j = 0; } if( index[l-3]==index[l-2] || index[l-2]==index[l-1] || index[l-1]==index[l-3] ) { l-=3; continue; } Vector3D vCross; vCross.Cross( coords[index[l-1]], coords[index[l-2]], coords[index[l-3]] ); if(Small_Enough(vCross)) { l-=3; continue; } } erf_mesh->SetSubprimitiveLengths(NULL, l/3); erf_mesh->SetCoordData(coords, nrOfPoints); #ifdef TERRAIN2_TEST erf_mesh->SetCurrentDepth(maxAllDepth-diffLevel); #else erf_mesh->SetTexCoordData(texCoords, nrOfPoints); #endif erf_mesh->SetIndexData(index, l); erf_mesh->FindFacePlanes(); delete [] coords; delete [] texCoords; delete [] index; if(state) { erf_mesh->SetReferenceState(*state); } else { erf_mesh->SetReferenceState(state0); } erf_mesh->SetReferenceState(state1, 1); ShapeElement* Shape = new ShapeElement; Register_Object(Shape); MLRShape *shape = new MLRShape(1); Register_Object(shape); shape->Add(erf_mesh); erf_mesh->DetachReference(); Shape->SetMLRShape(shape); Shape->localOBB.localToParent = Stuff::LinearMatrix4D::Identity; Shape->localOBB.localToParent.BuildTranslation(center); Shape->localOBB.sphereRadius = maxRadius; // Shape->SetVolumeCullMode(); Shape->SetRootMode(); parent->AttachIndexedChild(listIndex, Shape); Shape->SetVolumeCullMode(); return true; } int primCounter, maxPrims; bool HFSlim::BinSort( ListElement *parent, int index, int levDiff, DynamicArrayOf& tdtrilist, int binSize, ExtentBox *uvFrame, 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, uvFrame, 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, uvFrame, 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); ListElement *group = new ListElement; Register_Object(group); group->SetSize(2); // //---------------------------------- // 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, uvFrame, state)) { worked |= 1; } if (BinSort( group, 1, levDiff, group_b, binSize, uvFrame, 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 HFSlim::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); tdtrilist.SetLength((X-1)*(Z-1)); DirectMap map(X,Z); int i, j; float maxY = 0; for(j=0;j maxY) { maxY = field[j*X + i]; } } Offset = -maxY*dY; MASK = new ImportMask; MASK->width=X; MASK->height=Z; GreedySubdivision mesh(&map); point_limit=1024; if(depth==0) point_limit = GetFullPolyCount()/4; else point_limit = depth; triangleCounter = 0; int count=1; while(mesh.pointCount() error_threshold) { mesh.greedyInsert(); } fprintf(stdout, "The mesh was greedy.\n"); mesh.overFaces(GetFacesCB, tdtrilist.GetData()); for(i=0;i(dY*mesh.eval( (int)(tdtrilist[i].v[0].x), (int)(tdtrilist[i].v[0].z) )); tdtrilist[i].v[1].y = Offset + static_cast(dY*mesh.eval( (int)(tdtrilist[i].v[1].x), (int)(tdtrilist[i].v[1].z) )); tdtrilist[i].v[2].y = Offset + static_cast(dY*mesh.eval( (int)(tdtrilist[i].v[2].x), (int)(tdtrilist[i].v[2].z) )); tdtrilist[i].v[0].x *= dX; tdtrilist[i].v[0].z *= dZ; tdtrilist[i].v[1].x *= dX; tdtrilist[i].v[1].z *= dZ; tdtrilist[i].v[2].x *= dX; tdtrilist[i].v[2].z *= dZ; tdtrilist[i].GetSurfaceAreaAndCentroid(); } OptPolyCount = triangleCounter; if(triangleCounter == 0 || mesh.pointCount() == 0) { return; } toSortTriangles.SetLength(triangleCounter); for(i=0,j=0;i &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 HFSlim::BuildTile( ElementRenderer::ListElement *list, int index, int depth, int maxdepth, DynamicArrayOf& onOffPoints, int maxNumOfTrianglesPerMesh, Scalar xGridOffset, Scalar zGridOffset, Scalar xGrid, Scalar zGrid, int tileX, int tileZ, const char *texRoot ) { char textureName[1024]; int numOfTriangles = toSortTriangles.GetLength(); DynamicArrayOf tempTrianglesPtr(numOfTriangles); DynamicArrayOf tempTriangles(numOfTriangles); int i, j, inCount, newCount = 0, extraTriangles = 0; int k, l, m; Scalar x0, z0, x1, z1; x0 = xGridOffset + tileX*xGrid; z0 = zGridOffset + tileZ*zGrid; x1 = x0 + xGrid; z1 = z0 + zGrid; MLRState state; /* 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); 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); for(i=0,j=0;iGetV0().x < x0) { clipIt[0] |= 1; } if(toSortTriangles[i]->GetV0().x > x1) { clipIt[0] |= 4; } if(toSortTriangles[i]->GetV0().z < z0) { clipIt[0] |= 8; } if(toSortTriangles[i]->GetV0().z > z1) { clipIt[0] |= 2; } orIt |= clipIt[0]; addIt &= clipIt[0]; if(toSortTriangles[i]->GetV1().x < x0) { clipIt[1] |= 1; } if(toSortTriangles[i]->GetV1().x > x1) { clipIt[1] |= 4; } if(toSortTriangles[i]->GetV1().z < z0) { clipIt[1] |= 8; } if(toSortTriangles[i]->GetV1().z > z1) { clipIt[1] |= 2; } orIt |= clipIt[1]; addIt &= clipIt[1]; if(toSortTriangles[i]->GetV2().x < x0) { clipIt[2] |= 1; } if(toSortTriangles[i]->GetV2().x > x1) { clipIt[2] |= 4; } if(toSortTriangles[i]->GetV2().z < z0) { clipIt[2] |= 8; } if(toSortTriangles[i]->GetV2().z > z1) { clipIt[2] |= 2; } orIt |= clipIt[2]; addIt &= clipIt[2]; if(orIt == 0) { onOffPoints[i] = 1; tempTrianglesPtr[newCount++] = toSortTriangles[i]; } else if(addIt==0) { if(orIt==1 || orIt==2 || orIt==4 || orIt==8) { Point3D triangle[3], clipPoints[6]; triangle[0].x = toSortTriangles[i]->GetV0().x; triangle[0].y = toSortTriangles[i]->GetV0().y; triangle[0].z = toSortTriangles[i]->GetV0().z; triangle[1].x = toSortTriangles[i]->GetV1().x; triangle[1].y = toSortTriangles[i]->GetV1().y; triangle[1].z = toSortTriangles[i]->GetV1().z; triangle[2].x = toSortTriangles[i]->GetV2().x; triangle[2].y = toSortTriangles[i]->GetV2().y; triangle[2].z = toSortTriangles[i]->GetV2().z; 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) ); 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) ); 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) ); 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) ); break; } break; } mask <<= 1; } } Verify(l>2); for(m=1;mGetV0().x; clipPoints[key][0].y = toSortTriangles[i]->GetV0().y; clipPoints[key][0].z = toSortTriangles[i]->GetV0().z; clipPoints[key][1].x = toSortTriangles[i]->GetV1().x; clipPoints[key][1].y = toSortTriangles[i]->GetV1().y; clipPoints[key][1].z = toSortTriangles[i]->GetV1().z; clipPoints[key][2].x = toSortTriangles[i]->GetV2().x; clipPoints[key][2].y = toSortTriangles[i]->GetV2().y; clipPoints[key][2].z = toSortTriangles[i]->GetV2().z; clipMeToo[key][0] = clipIt[0]; clipMeToo[key][1] = clipIt[1]; clipMeToo[key][2] = clipIt[2]; len[key] = 3; int next, mask = 1; for(m=0;m<4;++m) { if(orIt & mask) { for(k=0;k 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=1;m SMALL) { tempTrianglesPtr[newCount++] = &tempTriangles[extraTriangles]; extraTriangles++; } } } } } } // tempTriangles.SetLength(extraTriangles); tempTrianglesPtr.SetLength(newCount); if(newCount > 0) { AnalyzeThis( tempTrianglesPtr, x0, z0, x1, z1 ); int i = 1<<(maxdepth - depth); 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 = 0.0f; box.minZ = z0; box.maxZ = z1; if(!BinSort( list, index, maxdepth - depth, tempTrianglesPtr, maxNumOfTrianglesPerMesh, &box, &state ) ) { } else { brokenTriangles += newCount; } } else { } tempTrianglesPtr.SetLength(0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void HFSlim::DescentToUnderMountain( int depth, #ifdef GRID_TEST ElementRenderer::GridElement *group, #else ElementRenderer::ListElement *group, #endif DynamicArrayOf& onOffPoints, int maxNumOfTrianglesPerMesh, Scalar x0, Scalar z0, Scalar x1, Scalar z1, int tileX, int tileZ, const char *texRoot ) { if((depth & 0xff) ==0) { char textureName[1024]; int numOfTriangles = toSortTriangles.GetLength(); DynamicArrayOf tempTrianglesPtr(numOfTriangles); DynamicArrayOf tempTriangles(numOfTriangles); int i, j, inCount, newCount = 0, extraTriangles = 0; int k, l, m; MLRState state; /* 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); sprintf(textureName, "%s_%1d_%02x%02x", texRoot, (depth>>8)-depth&0xff, tileX, tileZ); MLRTexture *texture = MLRTexturePool::Instance->Add(textureName); state.SetTextureHandle(texture->GetTextureHandle()); state.SetTextureWrapMode(MLRState::TextureClamp); for(i=0,j=0;iGetV0().x < x0) { clipIt[0] |= 1; } if(toSortTriangles[i]->GetV0().x > x1) { clipIt[0] |= 4; } if(toSortTriangles[i]->GetV0().z < z0) { clipIt[0] |= 8; } if(toSortTriangles[i]->GetV0().z > z1) { clipIt[0] |= 2; } orIt |= clipIt[0]; addIt &= clipIt[0]; if(toSortTriangles[i]->GetV1().x < x0) { clipIt[1] |= 1; } if(toSortTriangles[i]->GetV1().x > x1) { clipIt[1] |= 4; } if(toSortTriangles[i]->GetV1().z < z0) { clipIt[1] |= 8; } if(toSortTriangles[i]->GetV1().z > z1) { clipIt[1] |= 2; } orIt |= clipIt[1]; addIt &= clipIt[1]; if(toSortTriangles[i]->GetV2().x < x0) { clipIt[2] |= 1; } if(toSortTriangles[i]->GetV2().x > x1) { clipIt[2] |= 4; } if(toSortTriangles[i]->GetV2().z < z0) { clipIt[2] |= 8; } if(toSortTriangles[i]->GetV2().z > z1) { clipIt[2] |= 2; } orIt |= clipIt[2]; addIt &= clipIt[2]; if(orIt == 0) { onOffPoints[i] = 1; tempTrianglesPtr[newCount++] = toSortTriangles[i]; } else if(addIt==0) { if(orIt==1 || orIt==2 || orIt==4 || orIt==8) { Point3D triangle[3], clipPoints[6]; triangle[0].x = toSortTriangles[i]->GetV0().x; triangle[0].y = toSortTriangles[i]->GetV0().y; triangle[0].z = toSortTriangles[i]->GetV0().z; triangle[1].x = toSortTriangles[i]->GetV1().x; triangle[1].y = toSortTriangles[i]->GetV1().y; triangle[1].z = toSortTriangles[i]->GetV1().z; triangle[2].x = toSortTriangles[i]->GetV2().x; triangle[2].y = toSortTriangles[i]->GetV2().y; triangle[2].z = toSortTriangles[i]->GetV2().z; 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) ); 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) ); 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) ); 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) ); break; } break; } mask <<= 1; } } Verify(l>2); for(m=1;mGetV0().x; clipPoints[key][0].y = toSortTriangles[i]->GetV0().y; clipPoints[key][0].z = toSortTriangles[i]->GetV0().z; clipPoints[key][1].x = toSortTriangles[i]->GetV1().x; clipPoints[key][1].y = toSortTriangles[i]->GetV1().y; clipPoints[key][1].z = toSortTriangles[i]->GetV1().z; clipPoints[key][2].x = toSortTriangles[i]->GetV2().x; clipPoints[key][2].y = toSortTriangles[i]->GetV2().y; clipPoints[key][2].z = toSortTriangles[i]->GetV2().z; clipMeToo[key][0] = clipIt[0]; clipMeToo[key][1] = clipIt[1]; clipMeToo[key][2] = clipIt[2]; len[key] = 3; int next, mask = 1; for(m=0;m<4;++m) { if(orIt & mask) { for(k=0;k 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=1;m 0) { #ifdef GRID_TEST group->SetSize(1, 1); #else group->SetSize(1); #endif Stuff::ExtentBox box; box.minX = x0; box.maxX = x1; box.minY = Offset; box.maxY = 0.0f; box.minZ = z0; box.maxZ = z1; if(!BinSort( group, 0, 0, tempTrianglesPtr, maxNumOfTrianglesPerMesh, &box, &state ) ) { #ifdef GRID_TEST group->SetSize(0, 0); #else group->SetSize(0); #endif } else { fprintf(analyzeFile, "%d\n", newCount); brokenTriangles += newCount; } } else { #ifdef GRID_TEST group->SetSize(0, 0); #else group->SetSize(0); #endif } tempTrianglesPtr.SetLength(0); } else { #ifdef GRID_TEST ElementRenderer::GridElement #else ElementRenderer::ListElement #endif *group00, *group01, *group10, *group11; #ifdef GRID_TEST group->SetSize(2, 2); group00 = new ElementRenderer::GridElement(2, 2); #else group->SetSize(4); group00 = new ElementRenderer::ListElement; #endif Register_Object(group00); #ifdef GRID_TEST group->AttachIndexedChild(0, 0, group00); #else group->AttachIndexedChild(0, group00); group00->NeedNewBounds(); group00->SetVolumeCullMode(); #endif #ifdef GRID_TEST group01 = new ElementRenderer::GridElement(2, 2); #else group01 = new ElementRenderer::ListElement; #endif Register_Object(group01); #ifdef GRID_TEST group->AttachIndexedChild(0, 1, group01); #else group->AttachIndexedChild(1, group01); group01->NeedNewBounds(); group01->SetVolumeCullMode(); #endif #ifdef GRID_TEST group10 = new ElementRenderer::GridElement(2, 2); #else group10 = new ElementRenderer::ListElement; #endif Register_Object(group10); #ifdef GRID_TEST group->AttachIndexedChild(1, 0, group10); #else group->AttachIndexedChild(2, group10); group10->NeedNewBounds(); group10->SetVolumeCullMode(); #endif #ifdef GRID_TEST group11 = new ElementRenderer::GridElement(2, 2); #else group11 = new ElementRenderer::ListElement; #endif Register_Object(group11); #ifdef GRID_TEST group->AttachIndexedChild(1, 1, group11); #else group->AttachIndexedChild(3, group11); group11->NeedNewBounds(); group11->SetVolumeCullMode(); #endif DescentToUnderMountain( depth-1, group00, onOffPoints, maxNumOfTrianglesPerMesh, x0, z0, x0 + (x1-x0)/2.0f, z0 + (z1-z0)/2.0f, 2*tileX, 2*tileZ, texRoot ); DescentToUnderMountain( depth-1, group01, onOffPoints, maxNumOfTrianglesPerMesh, x0 + (x1-x0)/2.0f, z0, x1, z0 + (z1-z0)/2.0f, 2*tileX+1, 2*tileZ, texRoot ); DescentToUnderMountain( depth-1, group10, onOffPoints, maxNumOfTrianglesPerMesh, x0, z0 + (z1-z0)/2.0f, x0 + (x1-x0)/2.0f, z1, 2*tileX, 2*tileZ+1, texRoot ); DescentToUnderMountain( depth-1, group11, onOffPoints, maxNumOfTrianglesPerMesh, x0 + (x1-x0)/2.0f, z0 + (z1-z0)/2.0f, x1, z1, 2*tileX+1, 2*tileZ+1, texRoot ); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool HFSlim::SetMegaTexture( int nrOfLevels, int bucketSize, const char *mega_base_name, DetailLevelInfo *dli ) { 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.SetAlphaMode(detailInfo.alphaMode); state1.SetPriority(MLRState::DefaultPriority + 1); MLRTexture *texture = MLRTexturePool::Instance->Add(detailInfo.name); state1.SetTextureHandle(texture->GetTextureHandle()); } DynamicArrayOf onOffTriangles; onOffTriangles.AssignValue(0, toSortTriangles.GetLength()); if(simpleTerrainGroup) { Unregister_Object(simpleTerrainGroup); delete simpleTerrainGroup; simpleTerrainGroup = NULL; } Stuff::ExtentBox allBox; allBox = GetExtents(); brokenTriangles = 0; #ifdef GRID_TEST int len = 1<SetName("OptimizedTerrain"); int i, j, level; xGridSize = (allBox.maxX-allBox.minX)/len; zGridSize = (allBox.maxZ-allBox.minZ)/len; for(j=0;jwidth*dli->height==0) { level = nrOfLevels; } else { Verify(dli->width == len); Verify(dli->height == len); switch(dli->array[(dli->height-j-1)*len+dli->width-i-1]) { case 0: level = nrOfLevels-2; break; case 1: level = nrOfLevels-1; break; case 2: level = nrOfLevels; break; default: level = nrOfLevels; } } tX = i; tY = j; BuildTile( simpleTerrainGroup, j*len+i, level, nrOfLevels, onOffTriangles, bucketSize, allBox.minX, allBox.minZ, (allBox.maxX-allBox.minX)/len, (allBox.maxZ-allBox.minZ)/len, i, j, mega_base_name ); } } simpleTerrainGroup->LockBounds(); simpleTerrainGroup->SetDimensions(0.0f, 0.0f, GetXinM(), GetZinM()); #else simpleTerrainGroup = new ListElement; Register_Object(simpleTerrainGroup); simpleTerrainGroup->SetName("OptimizedTerrain"); DescentToUnderMountain ( (nrOfLevels<<8) + nrOfLevels, simpleTerrainGroup, bucketSize, allBox.minZ, allBox.maxX, allBox.maxZ, 0, 0, ); simpleTerrainGroup->NeedNewBounds(); #endif fprintf(stdout, "\"broken\" triangles: %d\n", brokenTriangles); return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Scalar HFSlim::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; } void HFSlim::DisplayFull(bool bl) { ElementRenderer::Element *element; if(bl==true) { element=terrainGroup->FindElement(fullTerrainGroup->GetName()); if(element==NULL) terrainGroup->AttachChild(fullTerrainGroup); } else { element=terrainGroup->FindElement(fullTerrainGroup->GetName()); if(element!=NULL) terrainGroup->DetachChild(fullTerrainGroup); } } void HFSlim::DisplayOpt(bool bl) { ElementRenderer::Element *element; if(bl==true) { element=terrainGroup->FindElement(simpleTerrainGroup->GetName()); if(element==NULL) terrainGroup->AttachChild(simpleTerrainGroup); } else { element=terrainGroup->FindElement(simpleTerrainGroup->GetName()); if(element!=NULL) terrainGroup->DetachChild(simpleTerrainGroup); } } void ToDrawTriangle::SetPoint(int idx,float x,float y,float z) { Verify(idx>=0 && idx<3); v[idx].x=x; v[idx].y=y; v[idx].z=z; }