MStatus meshOpFty::doIt() // // Description: // Performs the operation on the selected mesh and components // { MStatus status; unsigned int i, j; // Get access to the mesh's function set // MFnMesh meshFn(fMesh); // The division count argument is used in many of the operations // to execute the operation multiple subsequent times. For example, // with a division count of 2 in subdivide face, the given faces will be // divide once and then the resulting inner faces will be divided again. // int divisionCount = 2; MFloatVector translation; if (fOperationType == kExtrudeEdges || fOperationType == kExtrudeFaces || fOperationType == kDuplicateFaces || fOperationType == kExtractFaces) { // The translation vector is used for the extrude, extract and // duplicate operations to move the result to a new position. For // example, if you extrude an edge on a mesh without a subsequent // translation, the extruded edge will be on at the position of the // orignal edge and the created faces will have no area. // // Here, we provide a translation that is in the same direction as the // average normal of the given components. // MFn::Type componentType = getExpectedComponentType(fOperationType); MIntArray adjacentVertexList; switch (componentType) { case MFn::kMeshEdgeComponent: for (i = 0; i < fComponentIDs.length(); ++i) { int2 vertices; meshFn.getEdgeVertices(fComponentIDs[i], vertices); adjacentVertexList.append(vertices[0]); adjacentVertexList.append(vertices[1]); } break; case MFn::kMeshPolygonComponent: for (i = 0; i < fComponentIDs.length(); ++i) { MIntArray vertices; meshFn.getPolygonVertices(fComponentIDs[i], vertices); for (j = 0; j < vertices.length(); ++j) adjacentVertexList.append(vertices[j]); } break; default: break; } MVector averageNormal(0, 0, 0); for (i = 0; i < adjacentVertexList.length(); ++i) { MVector vertexNormal; meshFn.getVertexNormal(adjacentVertexList[i], vertexNormal, MSpace::kWorld); averageNormal += vertexNormal; } if (averageNormal.length() < 0.001) averageNormal = MVector(0.0, 1.0, 0.0); else averageNormal.normalize(); translation = averageNormal; } // When doing an extrude operation, there is a choice of extrude the // faces/edges individually or together. If extrudeTogether is true and // multiple adjacent components are selected, they will be extruded as if // it were one more complex component. // // The following variable sets that option. // bool extrudeTogether = true; // Execute the requested operation // switch (fOperationType) { case kSubdivideEdges: { status = meshFn.subdivideEdges(fComponentIDs, divisionCount); CHECK_STATUS(status); break; } case kSubdivideFaces: { status = meshFn.subdivideFaces(fComponentIDs, divisionCount); CHECK_STATUS(status); break; } case kExtrudeEdges: { status = meshFn.extrudeEdges(fComponentIDs, divisionCount, &translation, extrudeTogether); CHECK_STATUS(status); break; } case kExtrudeFaces: { status = meshFn.extrudeFaces(fComponentIDs, divisionCount, &translation, extrudeTogether); CHECK_STATUS(status); break; } case kCollapseEdges: { status = meshFn.collapseEdges(fComponentIDs); CHECK_STATUS(status); break; } case kCollapseFaces: { status = meshFn.collapseFaces(fComponentIDs); CHECK_STATUS(status); break; } case kDuplicateFaces: { status = meshFn.duplicateFaces(fComponentIDs, &translation); CHECK_STATUS(status); break; } case kExtractFaces: { status = meshFn.extractFaces(fComponentIDs, &translation); CHECK_STATUS(status); break; } case kSplitLightning: { status = doLightningSplit(meshFn); CHECK_STATUS(status); break; } default: status = MS::kFailure; break; } return status; }
void Storage::fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center, osg::ref_ptr<osg::Vec3Array> positions, osg::ref_ptr<osg::Vec3Array> normals, osg::ref_ptr<osg::Vec4Array> colours) { // LOD level n means every 2^n-th vertex is kept size_t increment = 1 << lodLevel; osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); assert(origin.x() == (int) origin.x()); assert(origin.y() == (int) origin.y()); int startX = static_cast<int>(origin.x()); int startY = static_cast<int>(origin.y()); size_t numVerts = static_cast<size_t>(size*(ESM::Land::LAND_SIZE - 1) / increment + 1); positions->resize(numVerts*numVerts); normals->resize(numVerts*numVerts); colours->resize(numVerts*numVerts); osg::Vec3f normal; osg::Vec4f color; float vertY = 0; float vertX = 0; float vertY_ = 0; // of current cell corner for (int cellY = startY; cellY < startY + std::ceil(size); ++cellY) { float vertX_ = 0; // of current cell corner for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) { ESM::Land* land = getLand(cellX, cellY); if (land && !(land->mDataTypes&ESM::Land::DATA_VHGT)) land = NULL; int rowStart = 0; int colStart = 0; // Skip the first row / column unless we're at a chunk edge, // since this row / column is already contained in a previous cell if (colStart == 0 && vertY_ != 0) colStart += increment; if (rowStart == 0 && vertX_ != 0) rowStart += increment; vertY = vertY_; for (int col=colStart; col<ESM::Land::LAND_SIZE; col += increment) { vertX = vertX_; for (int row=rowStart; row<ESM::Land::LAND_SIZE; row += increment) { float height = -2048; if (land) height = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; (*positions)[static_cast<unsigned int>(vertX*numVerts + vertY)] = osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * 8192, (vertY / float(numVerts - 1) - 0.5f) * size * 8192, height); if (land && land->mDataTypes&ESM::Land::DATA_VNML) { normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; normal.normalize(); } else normal = osg::Vec3f(0,0,1); // Normals apparently don't connect seamlessly between cells if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) fixNormal(normal, cellX, cellY, col, row); // some corner normals appear to be complete garbage (z < 0) if ((row == 0 || row == ESM::Land::LAND_SIZE-1) && (col == 0 || col == ESM::Land::LAND_SIZE-1)) averageNormal(normal, cellX, cellY, col, row); assert(normal.z() > 0); (*normals)[static_cast<unsigned int>(vertX*numVerts + vertY)] = normal; if (land && land->mDataTypes&ESM::Land::DATA_VCLR) { color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; } else { color.r() = 1; color.g() = 1; color.b() = 1; } // Unlike normals, colors mostly connect seamlessly between cells, but not always... if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) fixColour(color, cellX, cellY, col, row); color.a() = 1; (*colours)[static_cast<unsigned int>(vertX*numVerts + vertY)] = color; ++vertX; } ++vertY; } vertX_ = vertX; } vertY_ = vertY; assert(vertX_ == numVerts); // Ensure we covered whole area } assert(vertY_ == numVerts); // Ensure we covered whole area }