cmodfix.cpp

来自「celestia源代码」· C++ 代码 · 共 1,525 行 · 第 1/3 页

CPP
1,525
字号
    for (f = 0; f < nFaces; f++)    {        Face& face = faces[f];        for (uint32 j = 0; j < 3; j++)        {            vertexTangents[f * 3 + j] =                averageFaceVectors(faces, f,                                   &vertexFaces[face.vi[j]][1],                                   vertexFaces[face.vi[j]][0],                                   0.0f);        }    }    // Create the new vertex description    Mesh::VertexDescription newDesc(desc);    augmentVertexDescription(newDesc, Mesh::Tangent, Mesh::Float3);    // We need to convert the copy the old vertex attributes to the new    // mesh.  In order to do this, we need the old offset of each attribute    // in the new vertex description.  The fromOffsets array will contain    // this mapping.    uint32 tangentOffset = 0;    uint32 fromOffsets[16];    for (i = 0; i < newDesc.nAttributes; i++)    {        fromOffsets[i] = ~0;        if (newDesc.attributes[i].semantic == Mesh::Tangent)        {            tangentOffset = newDesc.attributes[i].offset;        }        else        {            for (uint32 j = 0; j < desc.nAttributes; j++)            {                if (desc.attributes[j].semantic == newDesc.attributes[i].semantic)                {                    assert(desc.attributes[j].format == newDesc.attributes[i].format);                    fromOffsets[i] = desc.attributes[j].offset;                    break;                }            }        }    }    // Copy the old vertex data along with the generated tangents to the    // new vertex data buffer.    void* newVertexData = new char[newDesc.stride * nFaces * 3];    for (f = 0; f < nFaces; f++)    {        Face& face = faces[f];        for (uint32 j = 0; j < 3; j++)        {            char* newVertex = reinterpret_cast<char*>(newVertexData) +                (f * 3 + j) * newDesc.stride;            copyVertex(newVertex, newDesc,                       vertexData, desc,                       face.i[j],                       fromOffsets);            memcpy(newVertex + tangentOffset, &vertexTangents[f * 3 + j],                   Mesh::getVertexAttributeSize(Mesh::Float3));        }    }    // Create the Celestia mesh    Mesh* newMesh = new Mesh();    newMesh->setVertexDescription(newDesc);    newMesh->setVertices(nFaces * 3, newVertexData);    // Create a trivial index list    uint32* indices = new uint32[nFaces * 3];    for (i = 0; i < nFaces * 3; i++)        indices[i] = i;    // TODO: This assumes that the mesh uses only one material.  Tangent    // generation should really be done one primitive group at a time.    uint32 materialIndex = mesh.getGroup(0)->materialIndex;    newMesh->addGroup(Mesh::TriList, materialIndex, nFaces * 3, indices);    // Clean up    delete[] faceCounts;    for (i = 0; i < nVertices; i++)    {        if (vertexFaces[i] != NULL)            delete[] vertexFaces[i];    }    delete[] vertexFaces;    return newMesh;}voidaddGroupWithOffset(Mesh& mesh,                   const Mesh::PrimitiveGroup& group,                   uint32 offset){    if (group.nIndices == 0)        return;    uint32* newIndices = new uint32[group.nIndices];    for (uint32 i = 0; i < group.nIndices; i++)        newIndices[i] = group.indices[i] + offset;    mesh.addGroup(group.prim, group.materialIndex,                  group.nIndices, newIndices);}// Merge all meshes that share the same vertex descriptionModel*mergeModelMeshes(const Model& model){    vector<Mesh*> meshes;    for (uint32 i = 0; model.getMesh(i) != NULL; i++)    {        meshes.push_back(model.getMesh(i));    }    // Sort the meshes by vertex description    sort(meshes.begin(), meshes.end(), MeshVertexDescComparator());    Model* newModel = new Model();    // Copy materials into the new model    for (i = 0; model.getMaterial(i) != NULL; i++)    {        newModel->addMaterial(model.getMaterial(i));    }    uint32 meshIndex = 0;    while (meshIndex < meshes.size())    {        const Mesh::VertexDescription& desc =            meshes[meshIndex]->getVertexDescription();                // Count the number of matching meshes        uint32 nMatchingMeshes;        for (nMatchingMeshes = 1;             meshIndex + nMatchingMeshes < meshes.size();             nMatchingMeshes++)        {            if (!(meshes[meshIndex + nMatchingMeshes]->getVertexDescription() == desc))            {                break;            }        }        // Count the number of vertices in all matching meshes        uint32 totalVertices = 0;        uint32 j;        for (j = meshIndex; j < meshIndex + nMatchingMeshes; j++)        {            totalVertices += meshes[j]->getVertexCount();        }        char* vertexData = new char[totalVertices * desc.stride];        // Create the new empty mesh        Mesh* mergedMesh = new Mesh();        mergedMesh->setVertexDescription(desc);        mergedMesh->setVertices(totalVertices, vertexData);                // Copy the vertex data and reindex and add primitive groups        uint32 vertexCount = 0;        for (j = meshIndex; j < meshIndex + nMatchingMeshes; j++)        {            const Mesh* mesh = meshes[j];            memcpy(vertexData + vertexCount * desc.stride,                   mesh->getVertexData(),                   mesh->getVertexCount() * desc.stride);            for (uint32 k = 0; mesh->getGroup(k) != NULL; k++)            {                addGroupWithOffset(*mergedMesh, *mesh->getGroup(k),                                   vertexCount);            }            vertexCount += mesh->getVertexCount();        }        assert(vertexCount == totalVertices);        newModel->addMesh(mergedMesh);        meshIndex += nMatchingMeshes;    }    return newModel;}#ifdef TRISTRIPboolconvertToStrips(Mesh& mesh){    vector<Mesh::PrimitiveGroup*> groups;    // NvTriStrip library can only handle 16-bit indices    if (mesh.getVertexCount() >= 0x10000)    {        return true;    }    // Verify that the mesh contains just tri strips    uint32 i;    for (i = 0; mesh.getGroup(i) != NULL; i++)    {        if (mesh.getGroup(i)->prim != Mesh::TriList)            return true;    }    // Convert the existing groups to triangle strips    for (i = 0; mesh.getGroup(i) != NULL; i++)    {        const Mesh::PrimitiveGroup* group = mesh.getGroup(i);        // Convert the vertex indices to shorts for the TriStrip library        unsigned short* indices = new unsigned short[group->nIndices];        uint32 j;        for (j = 0; j < group->nIndices; j++)        {            indices[j] = (unsigned short) group->indices[j];        }        PrimitiveGroup* strips = NULL;        unsigned short nGroups;        bool r = GenerateStrips(indices,                                group->nIndices,                                &strips,                                &nGroups,                                false);        if (!r || strips == NULL)        {            cerr << "Generate tri strips failed\n";            return false;        }        // Call the tristrip library to convert the lists to strips.  Then,        // convert from the NvTriStrip's primitive group structure to the        // CMOD one and add it to the collection that will be added once        // the mesh's original primitive groups are cleared.        for (j = 0; j < nGroups; j++)        {            Mesh::PrimitiveGroupType prim = Mesh::InvalidPrimitiveGroupType;            switch (strips[j].type)            {            case PT_LIST:                prim = Mesh::TriList;                break;            case PT_STRIP:                prim = Mesh::TriStrip;                break;            case PT_FAN:                prim = Mesh::TriFan;                break;            }            if (prim != Mesh::InvalidPrimitiveGroupType &&                strips[j].numIndices != 0)            {                Mesh::PrimitiveGroup* newGroup = new Mesh::PrimitiveGroup();                newGroup->prim = prim;                newGroup->materialIndex = group->materialIndex;                newGroup->nIndices = strips[j].numIndices;                newGroup->indices = new uint32[newGroup->nIndices];                for (uint32 k = 0; k < newGroup->nIndices; k++)                    newGroup->indices[k] = strips[j].indices[k];                                groups.push_back(newGroup);            }        }        delete[] strips;    }    mesh.clearGroups();    // Add the stripified groups to the mesh    for (vector<Mesh::PrimitiveGroup*>::const_iterator iter = groups.begin();         iter != groups.end(); iter++)    {        mesh.addGroup(*iter);    }    return true;}#endifbool parseCommandLine(int argc, char* argv[]){    int i = 1;    int fileCount = 0;    while (i < argc)    {        if (argv[i][0] == '-')        {            if (!strcmp(argv[i], "-b") || !strcmp(argv[i], "--binary"))            {                outputBinary = true;            }            else if (!strcmp(argv[i], "-a") || !strcmp(argv[i], "--ascii"))            {                outputBinary = false;            }            else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--uniquify"))            {                uniquify = true;            }            else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--normals"))            {                genNormals = true;            }            else if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tangents"))            {                genTangents = true;            }            else if (!strcmp(argv[i], "-w") || !strcmp(argv[i], "--weld"))            {                weldVertices = true;            }            else if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "--merge"))            {                mergeMeshes = true;            }            else if (!strcmp(argv[i], "-o") || !strcmp(argv[i], "--optimize"))            {                stripify = true;            }            else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--smooth"))            {                if (i == argc - 1)                {                    return false;                }                else                {                    if (sscanf(argv[i + 1], " %f", &smoothAngle) != 1)                        return false;                    i++;                }            }            else            {                return false;            }            i++;        }        else        {            if (fileCount == 0)            {                // input filename first                inputFilename = string(argv[i]);                fileCount++;            }            else if (fileCount == 1)            {                // output filename second                outputFilename = string(argv[i]);                fileCount++;            }            else            {                // more than two filenames on the command line is an error                return false;            }            i++;        }    }    return true;}int main(int argc, char* argv[]){    if (!parseCommandLine(argc, argv))    {        usage();        return 1;    }    Model* model = NULL;    if (!inputFilename.empty())    {        ifstream in(inputFilename.c_str(), ios::in | ios::binary);        if (!in.good())        {            cerr << "Error opening " << inputFilename << "\n";            return 1;        }        model = LoadModel(in);    }    else    {        model = LoadModel(cin);    }        if (model == NULL)        return 1;        if (genNormals || genTangents)    {        Model* newModel = new Model();        uint32 i;        // Copy materials        for (i = 0; model->getMaterial(i) != NULL; i++)        {            newModel->addMaterial(model->getMaterial(i));        }        // Generate normals and/or tangents for each model in the mesh        for (i = 0; model->getMesh(i) != NULL; i++)        {            Mesh* mesh = model->getMesh(i);            Mesh* newMesh = NULL;            if (genNormals)            {                newMesh = generateNormals(*mesh,                                          degToRad(smoothAngle),                                          weldVertices);                if (newMesh == NULL)                {                    cerr << "Error generating normals!\n";                    return 1;                }                // TODO: clean up old mesh                mesh = newMesh;            }            if (genTangents)            {                newMesh = generateTangents(*mesh, weldVertices);                if (newMesh == NULL)                {                    cerr << "Error generating tangents!\n";                    return 1;                }                // TODO: clean up old mesh                mesh = newMesh;            }            newModel->addMesh(mesh);        }        // delete model;        model = newModel;    }    if (mergeMeshes)    {        model = mergeModelMeshes(*model);    }    if (uniquify)    {        for (uint32 i = 0; model->getMesh(i) != NULL; i++)        {            Mesh* mesh = model->getMesh(i);            uniquifyVertices(*mesh);        }    }#ifdef TRISTRIP    if (stripify)    {        SetCacheSize(vertexCacheSize);        for (uint32 i = 0; model->getMesh(i) != NULL; i++)        {            Mesh* mesh = model->getMesh(i);            convertToStrips(*mesh);        }    }#endif    if (outputFilename.empty())    {        if (outputBinary)            SaveModelBinary(model, cout);        else            SaveModelAscii(model, cout);    }    else    {        ofstream out(outputFilename.c_str(),                     ios::out | (outputBinary ? ios::binary : 0));        if (!out.good())        {            cerr << "Error opening output file " << outputFilename << "\n";            return 1;        }        if (outputBinary)            SaveModelBinary(model, out);        else            SaveModelAscii(model, out);    }    return 0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?