Exemple #1
0
Submesh*
CmodLoader::loadSubmesh()
{
    VertexSpec* vertexSpec = loadVertexSpec();
    if (!vertexSpec)
    {
        return NULL;
    }

    VertexArray* vertexArray = loadVertexArray(*vertexSpec);
    if (!vertexArray)
    {
        delete vertexSpec;
        return NULL;
    }

    Submesh* submesh = new Submesh(vertexArray);

    bool done = false;
    while (!done && !error())
    {
        quint16 token = 0;
        *m_inputStream >> token;

        if (token == CmodEndMesh)
        {
            done = true;
        }
        else
        {
            unsigned int materialIndex = 0;
            PrimitiveBatch* primitives = loadPrimitiveBatch(token, vertexArray->count(), &materialIndex);
            if (primitives)
            {
                submesh->addPrimitiveBatch(primitives, materialIndex);
            }
        }
    }

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

    return submesh;
}
Exemple #2
0
/** Merge a list of submeshes to create a single submesh. All submeshes must share
  * the same vertex spec. There must be at least one submesh in the list to merge.
  *
  * \return the new submesh, or null if there was an error creating the submesh.
  */
Submesh*
Submesh::mergeSubmeshes(const std::vector<Submesh*>& submeshes)
{
    if (submeshes.empty())
    {
        return NULL;
    }

    const VertexSpec& vertexSpec = submeshes.front()->vertices()->vertexSpec();
    const unsigned int vertexStride = submeshes.front()->vertices()->stride();

    // Verify that the strides and vertex specs of all submeshes match
    unsigned int vertexCount = 0;
    for (vector<Submesh*>::const_iterator iter = submeshes.begin(); iter != submeshes.end(); ++iter)
    {
        Submesh* s = *iter;
        if (s->vertices()->vertexSpec() != vertexSpec || s->vertices()->stride() != vertexStride)
        {
            VESTA_WARNING("MergeSubmeshes attempted on incompatible submeshes.");
            return false;
        }

        vertexCount += s->vertices()->count();
    }

    // Create a new vertex array large enough to contain all of the submeshes
    unsigned int vertexDataSize = vertexCount * vertexStride;

    Submesh* submesh = NULL;
    char* vertexData = NULL;
    VertexArray* vertexArray = NULL;
    try
    {
        vertexData = new char[vertexDataSize];
        vertexArray = new VertexArray(vertexData, vertexCount, vertexSpec, vertexStride);
        submesh = new Submesh(vertexArray);
    }
    catch (bad_alloc&)
    {
        VESTA_WARNING("Out of memory during submesh merge.");
        if (vertexArray)
        {
            // Deleting the vertex array takes care of the vertexData too
            delete vertexArray;
        }
        else if (vertexData)
        {
            delete[] vertexData;
        }
        return NULL;
    }

    unsigned int vertexDataOffset = 0;

    // Copy vertices from the submeshes in the merge list to the new vertex array
    for (vector<Submesh*>::const_iterator iter = submeshes.begin(); iter != submeshes.end(); ++iter)
    {
        Submesh* s = *iter;
        unsigned int submeshVertexDataSize = vertexStride * s->vertices()->count();
        assert(vertexDataOffset + submeshVertexDataSize <= vertexDataSize);

        copy(reinterpret_cast<const char*>(s->vertices()->data()),
             reinterpret_cast<const char*>(s->vertices()->data()) + submeshVertexDataSize,
             vertexData + vertexDataOffset);
        vertexDataOffset += submeshVertexDataSize;
    }

    // Copy materials and primitive batches from submeshes in the merge list
    try
    {
        unsigned int vertexOffset = 0;
        for (vector<Submesh*>::const_iterator iter = submeshes.begin(); iter != submeshes.end() && submesh != NULL; ++iter)
        {
            Submesh* s = *iter;

            assert(s->materials().size() == s->primitiveBatches().size());
            for (unsigned int i = 0; i < s->primitiveBatchCount(); ++i)
            {
                const PrimitiveBatch* prims = s->primitiveBatches().at(i);
                PrimitiveBatch* newPrims = new PrimitiveBatch(*prims);
                if (vertexOffset != 0)
                {
                    if (!newPrims->offsetIndices(vertexOffset))
                    {
                        delete submesh;
                        submesh = NULL;
                        break;
                    }
                }

                submesh->addPrimitiveBatch(newPrims, s->materials().at(i));
            }

            vertexOffset += s->vertices()->count();
        }
    }
    catch (bad_alloc&)
    {
        VESTA_WARNING("Out of memory during submesh merge.");
        delete submesh;
        submesh = NULL;
    }

    return submesh;
}
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;
}