示例#1
0
MeshGeometry*
CmodLoader::loadMesh()
{
    char headerData[16];
    if (m_inputStream->readRawData(headerData, sizeof(headerData)) != sizeof(headerData))
    {
        setError("Error reading header");
        return NULL;
    }

    QString header = QString::fromLatin1(headerData, sizeof(headerData));
    if (header == "#celmodel__ascii")
    {
        setError("ASCII cmod files are not supported");
        return NULL;
    }
    else if (header != "#celmodel_binary")
    {
        setError("Wrong header; file is not a cmod mesh file");
        return NULL;
    }

    MeshGeometry* mesh = new MeshGeometry();

    // Add the default material
    Material* defaultMaterial = new Material();
    defaultMaterial->setDiffuse(Spectrum::Flat(0.8f));
    defaultMaterial->setBrdf(Material::Lambert);
    mesh->addMaterial(defaultMaterial);

    bool done = false;
    unsigned int meshCount = 0;

    while (!done && !error())
    {
        CmodToken token = readCmodToken();
        if (m_inputStream->atEnd())
        {
            done = true;
        }
        else if (token == CmodMaterial)
        {
            if (meshCount > 0)
            {
                setError("Materials must be appear before any meshes");
            }

            Material* material = loadMaterial();
            if (material)
            {
                mesh->addMaterial(material);
            }
        }
        else if (token == CmodMesh)
        {
            Submesh* submesh = loadSubmesh();
            if (submesh)
            {
                mesh->addSubmesh(submesh);
            }
        }
        else
        {
            setError("Unrecognized block in cmod (not a mesh or material)");
        }
    }

    if (error())
    {
        delete mesh;
        mesh = NULL;
    }

    return mesh;
}
static MeshGeometry*
Convert3DSMesh(Lib3dsFile* meshfile, TextureMapLoader* textureLoader)
{
    MeshGeometry* meshGeometry = new MeshGeometry();

    for (int materialIndex = 0; materialIndex < meshfile->nmaterials; ++materialIndex)
    {
        Lib3dsMaterial* material = meshfile->materials[materialIndex];
        Material* vmaterial = new Material();

        // Convert a 3ds material to VESTA material
        vmaterial->setOpacity(1.0f - material->transparency);
        vmaterial->setDiffuse(Spectrum(material->diffuse));

        if (material->shininess != 0.0f)
        {
            vmaterial->setSpecular(Spectrum(material->specular));
            vmaterial->setPhongExponent(std::pow(2.0f, 1.0f + 10.0f * material->shininess));
        }

        if (material->self_illum_flag)
        {
            vmaterial->setEmission(vmaterial->diffuse() * material->self_illum);
        }

        const string baseTextureName(material->texture1_map.name);
        if (!baseTextureName.empty())
        {
            TextureProperties texProperties;
            if ((material->texture1_map.flags & LIB3DS_TEXTURE_NO_TILE) != 0)
            {
                texProperties.addressS = TextureProperties::Clamp;
                texProperties.addressT = TextureProperties::Clamp;
            }

            if (textureLoader)
            {
                TextureMap* baseTexture = textureLoader->loadTexture(baseTextureName, texProperties);
                vmaterial->setBaseTexture(baseTexture);
            }
        }

        meshGeometry->addMaterial(vmaterial);
    }

    for (int meshIndex = 0; meshIndex < meshfile->nmeshes; ++meshIndex)
    {
        Lib3dsMesh* mesh = meshfile->meshes[meshIndex];
        if (mesh->nfaces > 0)
        {
            bool hasTextureCoords = mesh->texcos != 0;

            // Generate normals for the mesh
            float* normals = new float[mesh->nfaces * 9];
            lib3ds_mesh_calculate_vertex_normals(mesh, (float(*)[3]) normals);

            VertexPool vertexPool;

            for (int faceIndex = 0; faceIndex < mesh->nfaces; ++faceIndex)
            {
                for (int i = 0; i < 3; i++)
                {
                    int vertexIndex = mesh->faces[faceIndex].index[i];
                    vertexPool.addVec3(mesh->vertices[vertexIndex]);
                    vertexPool.addVec3(&normals[(faceIndex * 3 + i) * 3]);

                    if (hasTextureCoords)
                    {
                        // Invert the v texture coordinate, since 3ds uses a texture
                        // coordinate system that is flipped with respect to OpenGL's
                        vertexPool.addVec2(mesh->texcos[vertexIndex][0], 1.0f - mesh->texcos[vertexIndex][1]);
                    }
                }
            }

            delete[] normals;

            const VertexSpec* vertexSpec = hasTextureCoords ? &VertexSpec::PositionNormalTex : &VertexSpec::PositionNormal;
            VertexArray* vertexArray = vertexPool.createVertexArray(mesh->nfaces * 3, *vertexSpec);
            PrimitiveBatch* batch = new PrimitiveBatch(PrimitiveBatch::Triangles, mesh->nfaces);

            // Get the material for the primitive batch
            // TODO: This assumes that a single material is applied to the whole mesh; however,
            // materials can be assigned per-face (but rarely are in most 3ds files.)
            unsigned int materialIndex = Submesh::DefaultMaterialIndex;
            if (mesh->nfaces > 0)
            {
                // Use the material of the first face
                materialIndex = mesh->faces[0].material;
            }

            Submesh* submesh = new Submesh(vertexArray);
            submesh->addPrimitiveBatch(batch, materialIndex);

            meshGeometry->addSubmesh(submesh);
        }
    }

    return meshGeometry;
}