#include "stdafx.h" #include "resource.h" #include "ProgDlg.h" #include "FinalBitmapWnd.h" #include #if !defined(MLR_TERRAIN_HEIGHTFIELD_HPP) #include "MLRHeightField.hpp" #include "terra\terra.hpp" #endif #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif const Scalar One_Over_Three = 1.0f/3.0f; #define USE_TRI_MESH 1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MLRHeightField::MLRHeightField() { X = (int)0.0f; Z = (int)0.0f; dX = 2.0f; dY = 0.15f; dZ = 2.0f; visHeight = 0; nrOfIZs = 0; #ifdef _DEBUG #undef new #endif terrainGroup = new GroupElement(); Register_Object(terrainGroup); #ifdef _DEBUG #define new DEBUG_NEW #endif fullTerrainGroup = NULL; simpleTerrainGroup = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MLRHeightField::~MLRHeightField() { 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 MLRHeightField::GetExtents() { Stuff::ExtentBox ebox; ebox.minX = 0.0f; ebox.minY = GetOffset(); ebox.minZ = 0.0f; ebox.maxX = dX*(X-1); ebox.maxZ = dZ*(Z-1); int i; ebox.maxY= field[0]*dY+GetOffset() > 16.0f ? field[0]*dY+GetOffset() : 16.0f; for (i=1;i (field[i]*dY+GetOffset()) ? ebox.maxY:(field[i]*dY+GetOffset()); } return ebox; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRHeightField::MakeTerrainFromField() { terrainGroup->SetNeverCullMode(); terrainGroup->SetName("Terrain"); #ifdef _DEBUG #undef new #endif fullTerrainGroup = new GroupElement(); Register_Object(fullTerrainGroup); fullTerrainGroup->SetName("FullTerrain"); DisplayFull(true); int side = 1 + (int)sqrt( (6*(X-1)*(Z-1)) / Limits::Max_Number_Vertices_Per_Mesh); meshX = X / side; meshZ = Z / side; UnitVector3D sun; sun = Vector3D(-1.0f, -1.0f, 0.0f); int i, j, mx, mz, k, l, count, test; test = side-1; terrain.SetLength(test*test); i = 0, j = 0, count = 0; MLR_I_DT_PMesh *mesh; if(field.GetLength() > 0) { Scalar maxFH = field[0]; for(i=1;i maxFH ? field[i] : maxFH; } Offset = -maxFH*dY; } CProgressDlg pdlg; pdlg.Create(); pdlg.ShowWindow(SW_SHOW); pdlg.SetWindowText("Create regular terrain"); pdlg.SetErrorText(0.0f); for(i=0;i h ? maxH : h; } points[mx*k+l] = Point3D( (j*meshX+l) * dX, h, (i*meshZ+k) * dZ ); texCoords[mx*k+l] = Vector2DScalar( // (Scalar)(j*side+l)/(Scalar)X, // (Scalar)(i*side+k)/(Scalar)Z // (Scalar)(l+j*mx)/(16.0f*(mx-1)), // (Scalar)(k+i*mz)/(16.0f*(mz-1)) // (Scalar)(l+j*mx)/(16.0f*(mx-0)), // (Scalar)(k+i*mz)/(16.0f*(mz-0)) (Scalar)(j*meshX+l)/(X-1), (Scalar)(i*meshZ+k)/(Z-1) ); texCoords[mx*k+l+mx*mz] = Vector2DScalar( (Scalar)(l)/(Scalar)(mx-1), (Scalar)(k)/(Scalar)(mz-1) ); } } mesh->SetCoordData(points, mx*mz); mesh->SetTexCoordData(texCoords, 2*mx*mz); delete [] points; delete [] texCoords; WORD *indices = new WORD [(mx-1)*(mz-1)*6]; for(k=0;kSetIndexData(indices, (mx-1)*(mz-1)*6); delete indices; unsigned char *lengths = new unsigned char [(mx-1)*(mz-1)*2]; for(k=0;k<(mx-1)*(mz-1)*2;k++) { lengths[k] = 3; } mesh->SetSubprimitiveLengths(lengths, (mx-1)*(mz-1)*2); mesh->FindFacePlanes(); delete lengths; mesh->SetReferenceState(state0); mesh->SetReferenceState(state1, 1); terrain[count]->Add(mesh); mesh->DetachReference(); #ifdef _DEBUG #undef new #endif ShapeElement* Shape = new ShapeElement; Register_Object(Shape); #ifdef _DEBUG #define new DEBUG_NEW #endif Shape->SetMLRShape(terrain[count]); fullTerrainGroup->AttachChild(Shape); Shape->localOBB.localToParent.BuildTranslation(Point3D( (((Scalar)j + 0.5f)*meshX) * dX, (maxH-minH)/2.0f + minH, (((Scalar)i + 0.5f)*meshZ) * dZ )); Shape->localOBB.sphereRadius = sqrt(3.0f)/2.0f * meshX * dX > meshZ * dZ ? (meshX * dX > (maxH-minH) ? meshX * dX : (maxH-minH)) : (meshZ * dZ > (maxH-minH) ? meshZ * dZ : (maxH-minH)) ; Shape->SetVolumeCullMode(); pdlg.SetPos(count*100/(test*test)); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRHeightField::Blur2D () { // 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<3;i++) { float logscale = float(log(scale)); for (y = 0; y < Z; y++) { float ryp = y+scale, rym = y-scale; int yp = (int) floor(ryp), ym = (int) ceil(rym); for (x = 0; x < X; x++) { float rxp = x+scale, rxm = x-scale; int xp = (int) floor(rxp), xm = (int) ceil(rxm); // x portion of second central difference float xsum = -2*field[y*X+x]; if ( xp >= 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; } int triangleCounter = 0; void GetFacesCB(Triangle &tri,void *cbp) { ToDrawTriangle *tdtrilist = (ToDrawTriangle *)cbp; tdtrilist[triangleCounter].SetPoint(0,(float)tri.point1()[0],0.0f,(float)tri.point1()[1]); tdtrilist[triangleCounter].SetPoint(1,(float)tri.point2()[0],0.0f,(float)tri.point2()[1]); tdtrilist[triangleCounter].SetPoint(2,(float)tri.point3()[0],0.0f,(float)tri.point3()[1]); triangleCounter++; } bool MLRHeightField::CreateMesh( ListElement *parent, int listIndex, DynamicArrayOf& 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; } #ifdef _DEBUG #undef new #endif #if USE_TRI_MESH MLR_I_DeT_TMesh *erf_mesh = new MLR_I_DeT_TMesh; #else // MLR_I_C_PMesh *erf_mesh = new MLR_I_C_PMesh; MLR_I_DeT_PMesh *erf_mesh = new MLR_I_DeT_PMesh; #endif Register_Object(erf_mesh); erf_mesh->SetDetailData(detailInfo.xOff, detailInfo.zOff, detailInfo.xFac, detailInfo.zFac); #ifdef _DEBUG #define new DEBUG_NEW #endif DynamicArrayOf 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.y += Offset; center3 *= 1.0f/polygon_count; center3.y += Offset; 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.y += Offset; center2.x = (maxx+minx)*0.5f; center2.y = (maxy+miny)*0.5f; center2.z = (maxz+minz)*0.5f; center2.y += Offset; Point3D *coords = new Point3D [point_count]; Register_Pointer(coords); Vector2DScalar *texCoords = new Vector2DScalar[point_count]; Register_Pointer(texCoords); 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; texCoords[nrOfPoints][0] = (coords[nrOfPoints].x - uvFrame->minX)/(uvFrame->maxX-uvFrame->minX); texCoords[nrOfPoints][1] = (coords[nrOfPoints].z - uvFrame->minZ)/(uvFrame->maxZ-uvFrame->minZ); 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(maxRadius0DrawGrid( tdtrilist.GetData(), polygon_count, col, center.x, center.z, maxRadius ); #if USE_TRI_MESH #else unsigned char *lengths = new unsigned char [polygon_count]; Register_Pointer(lengths); #endif unsigned short *index = new unsigned short [polygon_count*3]; Register_Pointer(index); int k, l; for(i=0,l=0;iv[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; } } #if USE_TRI_MESH erf_mesh->SetSubprimitiveLengths(NULL, l/3); #else erf_mesh->SetSubprimitiveLengths(lengths, l/3); Unregister_Pointer(lengths); delete lengths; #endif erf_mesh->SetCoordData(coords, nrOfPoints); erf_mesh->SetTexCoordData(texCoords, nrOfPoints); erf_mesh->SetIndexData(index, l); erf_mesh->FindFacePlanes(); Unregister_Pointer(coords); delete coords; Unregister_Pointer(texCoords); delete texCoords; Unregister_Pointer(index); delete index; if(state) { erf_mesh->SetReferenceState(*state); } else { erf_mesh->SetReferenceState(state0); } erf_mesh->SetReferenceState(state1, 1); #ifdef _DEBUG #undef new #endif ShapeElement* Shape = new ShapeElement; Register_Object(Shape); MLRShape *shape = new MLRShape(1); Register_Object(shape); #ifdef _DEBUG #define new DEBUG_NEW #endif shape->Add(erf_mesh); erf_mesh->DetachReference(); Shape->SetMLRShape(shape); 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 MLRHeightField::BinSort( ListElement *parent, int index, DynamicArrayOf& tdtrilist, int binSize, CProgressDlg *pdlg, ExtentBox *uvFrame, MLRState *state ) { int polygon_count = tdtrilist.GetLength(); if (polygon_count==0) { return false; } unsigned i; #ifdef _ARMOR unsigned j; for (i=0; iv[j].x >= 0.0f && tdtrilist[i]->v[j].x <= GetXinM()); Verify(tdtrilist[i]->v[j].y >= Offset && tdtrilist[i]->v[j].y <= -Offset); Verify(tdtrilist[i]->v[j].z >= 0.0f && tdtrilist[i]->v[j].z <= GetZinM()); } } #endif // //--------------------------------------------------------- // If the polygon mesh is already small enough, just return //--------------------------------------------------------- // if (polygon_count <= binSize) { if(pdlg) pdlg->SetPos(++primCounter*100/maxPrims); return CreateMesh(parent, index, 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)) { if(pdlg) pdlg->SetPos(++primCounter*100/maxPrims); return CreateMesh(parent, index, 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 //------------------------------------------------------------------------- // #ifdef _DEBUG #undef new #endif Check_Object(parent); ListElement *group = new ListElement; Register_Object(group); group->SetSize(2); parent->AttachIndexedChild(index, group); #ifdef _DEBUG #define new DEBUG_NEW #endif // //---------------------------------- // 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 //------------------------------------------------------------------- // if (BinSort( group, 0, group_a, binSize, pdlg, uvFrame, state)) { } if (BinSort( group, 1, group_b, binSize, pdlg, uvFrame, state)) { } // //----------------------------------------- // Now set the bounding sphere of the group //----------------------------------------- // Check_Object(group); #if 0 DynamicArrayOf vert_id(X*Z); memset(vert_id.GetData(), 0, vert_id.GetSize()); Point3D center = Point3D::Identity; int x, z, point_count; for(i=0;iv[0].x/dX); z = (int)(tdtrilist[i]->v[0].z/dZ); vert_id[x + X*z]++; if(vert_id[x + X*z]==1) { center += tdtrilist[i]->v[0]; point_count++; } 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) { center += tdtrilist[i]->v[1]; point_count++; } 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) { center += tdtrilist[i]->v[2]; point_count++; } } center *= 1.0f/point_count; center.y += Offset; int nrOfPoints = 0; Point3D p; Vector3D v3; Scalar radiusSquared, maxRadius = 0.0f; for(z=0;z 0 ) { Verify(nrOfPointsmaxRadius ? radiusSquared:maxRadius; nrOfPoints++; } else vert_id[z*X+x] = -1; } maxRadius = static_cast(sqrt(maxRadius)); group->localOBB.localToParent.BuildTranslation(center); group->localOBB.sphereRadius = maxRadius; #endif group->NeedNewBounds(); group->SetVolumeCullMode(); return false; } void MLRHeightField::OptimizeHField(int mode, int depth, int binSize) { if(X*Z == 0) { return; } #ifdef _DEBUG #undef new #endif simpleTerrainGroup = new ListElement; Register_Object(simpleTerrainGroup); simpleTerrainGroup->SetSize(1); simpleTerrainGroup->SetName("OptimizedTerrain"); #ifdef _DEBUG #define new DEBUG_NEW #endif DirectMap map(X,Z); DynamicArrayOf tdtrilist((X-1)*(Z-1)); int i, j; for(j=0;jwidth=X; MASK->height=Z; GreedySubdivision mesh(&map); point_limit=1024; CProgressDlg pdlg; pdlg.Create(); pdlg.ShowWindow(SW_SHOW); if(depth==0) point_limit = GetFullPolyCount()/4; else point_limit = depth; while(mesh.pointCount() error_threshold) { triangleCounter = 0; mesh.greedyInsert(); if(!(mesh.pointCount()%100)) pdlg.SetPos(mesh.pointCount()*100/point_limit); pdlg.SetErrorText(static_cast(mesh.maxError())); } 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 = static_cast(dY*mesh.eval( (int)(tdtrilist[i].v[1].x), (int)(tdtrilist[i].v[1].z) )); tdtrilist[i].v[2].y = 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(); } Wnd2D->DrawGrid(tdtrilist.GetData(), triangleCounter); Sleep(100); OptPolyCount = triangleCounter; { Point3D *points; RGBAColor *colors; int x, z, point_count, color_count; Scalar diff; MLRPrimitiveBase *primitive; for(i=0;iGetNum();j++) { primitive = terrain[i]->Find(j); Check_Object(primitive); if(primitive->IsDerivedFrom(MidLevelRenderer::MLR_I_C_PMesh::DefaultData)) { Cast_Object(MLR_I_C_PMesh*, primitive)->GetColorData(&colors, &color_count); } else if(primitive->IsDerivedFrom(MidLevelRenderer::MLR_I_C_DT_PMesh::DefaultData)) { Cast_Object(MLR_I_C_DT_PMesh*, primitive)->GetColorData(&colors, &color_count); } else if(primitive->IsDerivedFrom(MidLevelRenderer::MLR_I_C_DeT_PMesh::DefaultData)) { Cast_Object(MLR_I_C_DeT_PMesh*, primitive)->GetColorData(&colors, &color_count); } else { continue; } primitive->GetCoordData(&points, &point_count); Verify(point_count==color_count); for(j=0;j(points[j].x/dX); z = static_cast(points[j].z/dZ); diff = static_cast(mesh.eval(x, z) - field[z*X + x]); if(diff > 0.0f) { colors[j].red = 1.0f; colors[j].green = 1.0f - diff/32.0f; colors[j].blue = 1.0f - diff/32.0f; colors[j].alpha = 1.0f; } else { colors[j].red = 1.0f + diff/32.0f; colors[j].green = 1.0f + diff/32.0f; colors[j].blue = 1.0f; colors[j].alpha = 1.0f; } } } } } if(triangleCounter == 0 || mesh.pointCount() == 0) { return; } DynamicArrayOf toSortTriangles(triangleCounter); for(i=0,j=0;iNeedNewBounds(); nrOfIZs = 1; Sleep(1000); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void SuckVerticesFromElement( ElementRenderer::Element *group, Point3D *points, int& numOfPoints, LinearMatrix4D& matrix ) { Check_Object(group); LinearMatrix4D localMatrix; localMatrix.Multiply(matrix, group->GetLocalToParent()); if(group->IsDerivedFrom(ElementRenderer::GroupElement::DefaultData)) { Stuff::ChainIteratorOf *children; ElementRenderer::Element *curelt; children = Cast_Pointer(ElementRenderer::GroupElement*, group)->MakeIterator(); int j; while ((curelt = children->ReadAndNext()) != NULL) { if(curelt->IsDerivedFrom(ElementRenderer::ShapeElement::DefaultData) ) { MidLevelRenderer::MLRShape *Shape = Cast_Object(ElementRenderer::ShapeElement *,curelt)->GetMLRShape(); for(j=0;jGetNum();j++) { MLRPrimitiveBase *primitive = Shape->Find(j); Check_Object(primitive); Point3D *coords; int nrOfPoints; if(primitive->IsDerivedFrom(MLRIndexedPrimitiveBase::DefaultData)) { unsigned short *indices; int nrOfIndices; primitive->GetCoordData(&coords, &nrOfPoints); (Cast_Pointer(MLRIndexedPrimitiveBase*, primitive))->GetIndexData(&indices, &nrOfIndices); for(int i=0;iMultiply(coords[indices[i]], localMatrix); } } else { primitive->GetCoordData(&coords, &nrOfPoints); for(int i=0;iMultiply(coords[i], localMatrix); } } } } else if(curelt->IsDerivedFrom(ElementRenderer::GroupElement::DefaultData) ) { SuckVerticesFromElement( Cast_Object(ElementRenderer::GroupElement *, curelt), points, numOfPoints, localMatrix ); } } } else if(group->IsDerivedFrom(ElementRenderer::ListElement::DefaultData)) { ElementRenderer::Element *curelt; int i, j, end = Cast_Pointer(ElementRenderer::ListElement*, group)->GetActiveCount(); for(i=0;iGetIndexedElement(i); if(curelt->IsDerivedFrom(ElementRenderer::ShapeElement::DefaultData) ) { MidLevelRenderer::MLRShape *Shape = Cast_Object(ElementRenderer::ShapeElement *,curelt)->GetMLRShape(); for(j=0;jGetNum();j++) { MLRPrimitiveBase *primitive = Shape->Find(j); Check_Object(primitive); Point3D *coords; int nrOfPoints; if(primitive->IsDerivedFrom(MLRIndexedPrimitiveBase::DefaultData)) { unsigned short *indices; int nrOfIndices; primitive->GetCoordData(&coords, &nrOfPoints); (Cast_Pointer(MLRIndexedPrimitiveBase*, primitive))->GetIndexData(&indices, &nrOfIndices); for(int i=0;iMultiply(coords[indices[i]], localMatrix); } } else { primitive->GetCoordData(&coords, &nrOfPoints); for(int i=0;iMultiply(coords[i], localMatrix); } } } } else if(curelt->IsDerivedFrom(ElementRenderer::GroupElement::DefaultData) ) { SuckVerticesFromElement( Cast_Object(ElementRenderer::GroupElement *, curelt), points, numOfPoints, localMatrix ); } } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRHeightField::DescentToUnderMountain( int depth, ElementRenderer::ListElement *group, Point3D *points, unsigned char *onOffPoints, int numOfTriangles, int maxNumOfTrianglesPerMesh, Scalar x0, Scalar z0, Scalar x1, Scalar z1, int tileX, int tileZ, const char *texRoot ) { if((depth & 0xff) ==0) { char textureName[1024]; DynamicArrayOf tempPoints(3*numOfTriangles); DynamicArrayOf collapsedPoints(3*maxNumOfTrianglesPerMesh); DynamicArrayOf tempIndices(3*maxNumOfTrianglesPerMesh); DynamicArrayOf tempTexCoords(3*maxNumOfTrianglesPerMesh); DynamicArrayOf tempLength(3*maxNumOfTrianglesPerMesh); int i, j, k, l, m, inCount, newCount = 0; sprintf(textureName, "%s_%1d_%02x%02x", texRoot, (depth>>8)-depth&0xff, tileZ, tileX); MLRState state; state.SetBackFaceOn(); state.SetDitherOff(); state.SetTextureCorrectionOn(); state.SetZBufferCompareOn(); state.SetZBufferWriteOn(); state.SetFilterMode(MLRState::BiLinearFilterMode); state.SetFogMode(MLRState::DisableFogMode); state.SetFogData( 0, 0.0f, 1.0f, 100.0f ); MLRTexture *texture = MLRTexturePool::Instance->Add(textureName); state.SetTextureHandle(texture->GetTextureHandle()); state.SetTextureWrapMode(MLRState::TextureClamp); for(i=0,j=0;i x1) { clipIt[k] |= 4; } if(points[j+k].z < z0) { clipIt[k] |= 8; } if(points[j+k].z > z1) { clipIt[k] |= 2; } orIt |= clipIt[k]; addIt &= clipIt[k]; } if(orIt == 0) { onOffPoints[i] = 1; tempPoints[newCount++] = points[j]; tempPoints[newCount++] = points[j+1]; tempPoints[newCount++] = points[j+2]; } else if(addIt==0) { Point3D clipPoints[5]; if(orIt==1 || orIt==2 || orIt==4 || orIt==8) { l = 0; for(k=0;k<3;k++) { int next = k+1>2?0:k+1; if(clipIt[k]==0) { clipPoints[l++] = points[j+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( points[j+k], Vector3D( points[j+next].x - points[j+k].x, points[j+next].y - points[j+k].y, points[j+next].z - points[j+k].z ), (x0-points[j+k].x)/(points[j+next].x-points[j+k].x) ); break; case 1: clipPoints[l++].AddScaled( points[j+k], Vector3D( points[j+next].x - points[j+k].x, points[j+next].y - points[j+k].y, points[j+next].z - points[j+k].z ), (z1-points[j+k].z)/(points[j+next].z-points[j+k].z) ); break; case 2: clipPoints[l++].AddScaled( points[j+k], Vector3D( points[j+next].x - points[j+k].x, points[j+next].y - points[j+k].y, points[j+next].z - points[j+k].z ), (x1-points[j+k].x)/(points[j+next].x-points[j+k].x) ); break; case 3: clipPoints[l++].AddScaled( points[j+k], Vector3D( points[j+next].x - points[j+k].x, points[j+next].y - points[j+k].y, points[j+next].z - points[j+k].z ), (z0-points[j+k].z)/(points[j+next].z-points[j+k].z) ); break; } break; } mask <<= 1; } } Verify(l>2); for(m=1;m 0) { group->SetSize(1); #ifdef _DEBUG #undef new #endif DynamicArrayOf tdtrilist(newCount/3); DynamicArrayOf ptrTdtrilist(newCount/3); for(i=0,j=0;iSetSize(4); #ifdef _DEBUG #undef new #endif group00 = new ElementRenderer::ListElement; Register_Object(group00); group->AttachIndexedChild(0, group00); group00->NeedNewBounds(); group00->SetVolumeCullMode(); group01 = new ElementRenderer::ListElement; Register_Object(group01); group->AttachIndexedChild(1, group01); group01->NeedNewBounds(); group01->SetVolumeCullMode(); group10 = new ElementRenderer::ListElement; Register_Object(group10); group->AttachIndexedChild(2, group10); group10->NeedNewBounds(); group10->SetVolumeCullMode(); group11 = new ElementRenderer::ListElement; Register_Object(group11); group->AttachIndexedChild(3, group11); group11->NeedNewBounds(); group11->SetVolumeCullMode(); #ifdef _DEBUG #define new DEBUG_NEW #endif DescentToUnderMountain( depth-1, group00, points, onOffPoints, numOfTriangles, maxNumOfTrianglesPerMesh, x0, z0, x0 + (x1-x0)/2.0f, z0 + (z1-z0)/2.0f, 2*tileX, 2*tileZ, texRoot ); DescentToUnderMountain( depth-1, group01, points, onOffPoints, numOfTriangles, maxNumOfTrianglesPerMesh, x0 + (x1-x0)/2.0f, z0, x1, z0 + (z1-z0)/2.0f, 2*tileX+1, 2*tileZ, texRoot ); DescentToUnderMountain( depth-1, group10, points, onOffPoints, numOfTriangles, maxNumOfTrianglesPerMesh, x0, z0 + (z1-z0)/2.0f, x0 + (x1-x0)/2.0f, z1, 2*tileX, 2*tileZ+1, texRoot ); DescentToUnderMountain( depth-1, group11, points, onOffPoints, numOfTriangles, maxNumOfTrianglesPerMesh, x0 + (x1-x0)/2.0f, z0 + (z1-z0)/2.0f, x1, z1, 2*tileX+1, 2*tileZ+1, texRoot ); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool MLRHeightField::SetMegaTexture( int nrOfLevels, const char *mega_base_name ) { if(simpleTerrainGroup==NULL) { return false; } if(detailInfo.name) { state1.SetBackFaceOn(); state1.SetDitherOff(); state1.SetTextureCorrectionOn(); state1.SetZBufferCompareOn(); state1.SetZBufferWriteOff(); state1.SetAlphaMode(detailInfo.alphaMode); state1.SetPriority(MLRState::DefaultPriority + 1); state1.SetFilterMode(MLRState::BiLinearFilterMode); state1.SetFogMode(MLRState::DisableFogMode); state1.SetFogData( 0, 0.0f, 1.0f, 100.0f ); MLRTexture *texture = MLRTexturePool::Instance->Add(detailInfo.name); state1.SetTextureHandle(texture->GetTextureHandle()); } // analyzing the data // textures on the lowest level int totll = static_cast(pow(2, nrOfLevels-1)); // lets care about the regular grid bool simpleWasAttached = (NULL != (terrainGroup->FindElement(simpleTerrainGroup->GetName()))); if(simpleWasAttached == true) terrainGroup->DetachChild(simpleTerrainGroup); DynamicArrayOf allTheTriangles(3*OptPolyCount); LinearMatrix4D matrix; matrix = LinearMatrix4D::Identity; int nrOfTriangles, nrOfPoints = 0; SuckVerticesFromElement( simpleTerrainGroup, allTheTriangles.GetData(), nrOfPoints, matrix ); Verify(0==nrOfPoints%3); allTheTriangles.SetLength(nrOfPoints); nrOfTriangles = nrOfPoints/3; DynamicArrayOf onOffTriangles; onOffTriangles.AssignValue(0, nrOfTriangles); Unregister_Object(simpleTerrainGroup); delete simpleTerrainGroup; simpleTerrainGroup = NULL; #ifdef _DEBUG #undef new #endif simpleTerrainGroup = new ListElement; Register_Object(simpleTerrainGroup); simpleTerrainGroup->SetName("OptimizedTerrain"); #ifdef _DEBUG #define new DEBUG_NEW #endif Stuff::ExtentBox allBox; allBox = GetExtents(); DescentToUnderMountain ( (nrOfLevels<<8) + nrOfLevels, simpleTerrainGroup, allTheTriangles.GetData(), onOffTriangles.GetData(), nrOfTriangles, 256, allBox.minX, allBox.minZ, allBox.maxX, allBox.maxZ, 0, 0, mega_base_name ); simpleTerrainGroup->NeedNewBounds(); MLRTexturePool::Instance->LoadImages(); return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Scalar MLRHeightField::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; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Scalar MLRHeightField::GetHeight(Scalar _x, Scalar _z) { int x, z, x1, z1, key = 0; Scalar dy00, dy10, dy20, dy30, dy01, dy11, dy21, dy31; Scalar gp0, gp1, gp2, gp3; Scalar ret; x = (int) floor (_x / dX); if (x<0) x = 0; if (x>GetX()-1) { x = GetX() - 1; } z = (int) floor (_z / dZ); if (z<0) z = 0; if (z>GetZ()-1) { z = GetZ() - 1; } if (_x - x*dX > 0.5*dX) { x1 = x + 1; key |= 2; } else { x1 = x; key |= 1; } if (_z - z*dZ > 0.5*dZ) { z1 = z + 1; key |= 8; } else { z1 = z; key |= 4; } ret = GetHeight (x1, z1); gp0 = GetHeight (x, z); gp1 = GetHeight (x, z+1); gp2 = GetHeight (x+1, z+1); gp3 = GetHeight (x+1, z); dy00 = ( gp1 - gp0 ) * (_z - z*dZ) / dZ; dy01 = ( gp0 - gp1 ) * ((z+1)*dZ - _z) / dZ; dy10 = ( gp2 - gp1 ) * (_x - x*dX) / dX; dy11 = ( gp1 - gp2 ) * ((x+1)*dX - _x) / dX; dy20 = ( gp3 - gp2 ) * ((z+1)*dZ - _z) / dZ; dy21 = ( gp2 - gp3 ) * (_z - z*dZ) / dZ; dy30 = ( gp0 - gp3 ) * ((x+1)*dX - _x) / dX; dy31 = ( gp3 - gp0 ) * (_x - x*dX) / dX; switch (key) { case 5: ret += (dy00 + dy31); break; case 9: ret += (dy01 + dy10); break; case 6: ret += (dy21 + dy30); break; case 10: ret += (dy20 + dy11); break; } // ret += visHeight*dY; return ret; } bool MLRHeightField::SaveHeightFieldInformations(MString& file_name) { HeightFieldFileHeader hffh; hffh.signature = 'HTMP'; hffh.version = 1; hffh.minX = 0.0f; hffh.maxX = GetXinM(); hffh.minZ = 0.0f; hffh.maxZ = GetZinM(); hffh.vertexCountX = X; hffh.vertexCountZ = Z; hffh.totalSizeOfFile = sizeof(HeightFieldFileHeader) + X*Z*(sizeof(float) + sizeof(char)); FILE *hd; hd = fopen(file_name, "wb"); if(!hd) { return false; } fwrite(&hffh, sizeof(HeightFieldFileHeader), 1, hd); int i, j; Scalar height; for(i=0;iFindElement(fullTerrainGroup->GetName()); if(element==NULL) terrainGroup->AttachChild(fullTerrainGroup); } else { element=terrainGroup->FindElement(fullTerrainGroup->GetName()); if(element!=NULL) terrainGroup->DetachChild(fullTerrainGroup); } } void MLRHeightField::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; }