Click here to Skip to main content
15,897,291 members
Articles / Multimedia / OpenGL

Modified version of lib3ds reader of .3ds format

Rate me:
Please Sign up or sign in to vote.
4.78/5 (15 votes)
4 Oct 2012CPOL3 min read 42.9K   2.9K   23  
In this article I present version of lib3ds reader for C++ language
#include "Lib3ds_stage.h"

#include <QFile>
#include <math.h>

#define FLT_MAX 10000

Lib3ds_stage::Lib3ds_stage()
{
}

bool Lib3ds_stage::load3ds(QString filename)
{
    bool ok = false;

    ok = lib3ds_stage_open(filename);

    return ok;
}

bool Lib3ds_stage::lib3ds_stage_open(QString filename)
{
    bool ok = false;

    file = new QFile(filename);

    if(file->exists())
    {
        lib3ds_file_clear();

        ok = file->open(QIODevice::ReadOnly);

        if(ok)
        {
            ok = lib3ds_stage_read();

        }

        file->close();
    }

    delete file;

    return ok;
}

bool Lib3ds_stage::lib3ds_stage_read()
{
    Lib3dsChunk c;

    uint16_t chunk;

    if(!lib3ds_chunk_read_start(&c, 0))
    {
        return false;
    }
    switch (c.chunk)
    {
        case CHK_MDATA: // Flag Starting reading of mesh data
        {
            lib3ds_chunk_read_reset(&c);

            if(!mdata_read())
            {
                return false;
            }

            break;
        }

        case CHK_M3DMAGIC: // Flag starting of reading of the stage
        case CHK_MLIBMAGIC:
        case CHK_CMAGIC:
        {
            while ((chunk = lib3ds_chunk_read_next(&c)) != 0)
            {
                switch (chunk)
                {
                    case CHK_M3D_VERSION: // Flag of reading mesh version
                    {
                        mesh_version = lib3ds_io_read_dword();

                        break;
                    }

                    case CHK_MDATA: // Flag reading of mesh data
                    {
                        lib3ds_chunk_read_reset(&c);

                        if(!mdata_read())
                        {
                            return false;
                        }

                        break;
                    }

                    case CHK_KFDATA: // Flag reading of key frame animation
                    {
                        lib3ds_chunk_read_reset(&c);

                        if(!kfdata_read())
                        {
                            return false;
                        }

                        break;
                    }

                    default:
                        lib3ds_chunk_unknown(chunk);
                }
            }
            break;
        }

        default:

            lib3ds_chunk_unknown(c.chunk);

            return false;
    }

    lib3ds_chunk_read_end(&c);

    return true;

}

bool Lib3ds_stage::mdata_read()
{
    Lib3dsChunk c;
    uint16_t chunk;

    if(!lib3ds_chunk_read_start(&c, CHK_MDATA))
    {
        return false;
    }

    while ((chunk = lib3ds_chunk_read_next(&c)) != 0)
    {
        switch (chunk)
        {
            case CHK_MESH_VERSION: // Flag reading of mesh version
            {
                mesh_version = lib3ds_io_read_intd();

                break;
            }

            case CHK_MASTER_SCALE: // Flag of scale of the stage
            {
                master_scale = lib3ds_io_read_float();

                break;
            }

            case CHK_MAT_ENTRY: // Flag of reading of material
            {
                Lib3dsMaterial material = lib3ds_material_new();

                lib3ds_chunk_read_reset(&c);

                if(!lib3ds_material_read(&material))
                {
                    return false;
                }

                materials[material.name] = material;

                break;
            }

            case CHK_SHADOW_MAP_SIZE: // Flags of reading of the shadow
            case CHK_LO_SHADOW_BIAS:
            case CHK_HI_SHADOW_BIAS:
            case CHK_SHADOW_SAMPLES:
            case CHK_SHADOW_RANGE:
            case CHK_SHADOW_FILTER:
            case CHK_RAY_BIAS:
            {
                lib3ds_chunk_read_reset(&c);

                if(!lib3ds_shadow_read(&shadow))
                {
                    return false;
                }

                break;
            }

            case CHK_VIEWPORT_LAYOUT: // Flags of reading of the view
            case CHK_DEFAULT_VIEW:
            {
                lib3ds_chunk_read_reset(&c);

                if(lib3ds_viewport_read(&viewport))
                {
                    return false;
                }

                break;
            }

            case CHK_O_CONSTS: // Flag of Planes
            {
                int i;
                for (i = 0; i < 3; ++i)
                {
                    construction_plane[i] = lib3ds_io_read_float();
                }
                break;
            }

            case CHK_AMBIENT_LIGHT: // Flag of reading of the ambient light
            {
                lib3ds_chunk_read_reset(&c);

                if(!ambient_read())
                {
                    return false;
                }

                break;
            }

            case CHK_BIT_MAP: // Flags of reading of setting of the background
            case CHK_SOLID_BGND:
            case CHK_V_GRADIENT:
            case CHK_USE_BIT_MAP:
            case CHK_USE_SOLID_BGND:
            case CHK_USE_V_GRADIENT:
            {
                lib3ds_chunk_read_reset(&c);

                if(!lib3ds_background_read(&background))
                {
                    return false;
                }

                break;
            }

            case CHK_FOG: // Flags of reading of setting of the atmosphere setting
            case CHK_LAYER_FOG:
            case CHK_DISTANCE_CUE:
            case CHK_USE_FOG:
            case CHK_USE_LAYER_FOG:
            case CHK_USE_DISTANCE_CUE:
            {
                lib3ds_chunk_read_reset(&c);

                if(!lib3ds_atmosphere_read(&atmosphere))
                {
                    return false;
                }

                break;
            }



            case CHK_NAMED_OBJECT: // Flag of reading of object
            {
                lib3ds_chunk_read_reset(&c);

                if(!named_object_read())
                {
                    return false;
                }

                break;
            }

            default:
                lib3ds_chunk_unknown(chunk);
        }
    }

    lib3ds_chunk_read_end(&c);

    return true;
}

bool Lib3ds_stage::named_object_read()
{
    Lib3dsChunk c;

    QString name;

    uint16_t chunk;

    Lib3dsMesh *mesh = NULL;

    Lib3dsCamera *camera = NULL;

    Lib3dsLight *light = NULL;

    uint32_t object_flags;

    if(!lib3ds_chunk_read_start(&c, CHK_NAMED_OBJECT))
    {
        return false;
    }

    if(!lib3ds_io_read_string(name, 64))
    {
        return false;
    }

    lib3ds_chunk_read_tell(&c);

    object_flags = 0;

    while ((chunk = lib3ds_chunk_read_next(&c)) != 0)
    {
        switch (chunk)
        {
            case CHK_N_TRI_OBJECT: // Names mesh
            {
                Lib3dsMesh temp_mesh = lib3ds_mesh_new(name);

                meshes[temp_mesh.name] = temp_mesh;

                mesh = &(meshes[temp_mesh.name]);

                lib3ds_chunk_read_reset(&c);

                if(!lib3ds_mesh_read(mesh))
                {
                    return false;
                }

                break;
            }

            case CHK_N_CAMERA: // Names camera
            {
                Lib3dsCamera temp_camera = lib3ds_camera_new(name);

                cameras[temp_camera.name] = temp_camera;

                camera = &(cameras[temp_camera.name]);

                lib3ds_chunk_read_reset(&c);

                if(!lib3ds_camera_read(camera))
                {
                    return false;
                }

                break;
            }

            case CHK_N_DIRECT_LIGHT: // Names light source
            {
                Lib3dsLight temp_light = lib3ds_light_new(name);

                lights[temp_light.name] = temp_light;

                light = &(lights[temp_light.name]);

                lib3ds_chunk_read_reset(&c);

                if(lib3ds_light_read(light))
                {
                    return false;
                }

                break;
            }

            case CHK_OBJ_HIDDEN:
                object_flags |= LIB3DS_OBJECT_HIDDEN;
                break;

            case CHK_OBJ_DOESNT_CAST:
                object_flags |= LIB3DS_OBJECT_DOESNT_CAST;
                break;

            case CHK_OBJ_VIS_LOFTER:
                object_flags |= LIB3DS_OBJECT_VIS_LOFTER;
                break;

            case CHK_OBJ_MATTE:
                object_flags |= LIB3DS_OBJECT_MATTE;
                break;

            case CHK_OBJ_DONT_RCVSHADOW:
                object_flags |= LIB3DS_OBJECT_DONT_RCVSHADOW;
                break;

            case CHK_OBJ_FAST:
                object_flags |= LIB3DS_OBJECT_FAST;
                break;

            case CHK_OBJ_FROZEN:
                object_flags |= LIB3DS_OBJECT_FROZEN;
                break;

            default:
                lib3ds_chunk_unknown(chunk);
        }
    }

    if (mesh)
        mesh->setting.object_flags = object_flags;
    if (camera)
        camera->setting.object_flags = object_flags;
    if (light)
        light->setting.object_flags = object_flags;

    lib3ds_chunk_read_end(&c);

    return true;
}

/*!
 * Evaluate all of the nodes in this Lib3dsFile object.
 *
 * \param file The Lib3dsFile object to be evaluated.
 * \param t time value, between 0. and file->frames
 *
 * \see lib3ds_node_eval
 */
void Lib3ds_stage::lib3ds_stage_eval(float t)
{

    QList<Lib3dsNode>::iterator i = nodes.begin();

    while (i != nodes.end())
    {
        lib3ds_node_eval(&(*i), t);

        ++i;
    }

}

bool Lib3ds_stage::ambient_read()
{
    Lib3dsChunk c;

    uint16_t chunk;

    bool have_lin = false;

    if(!lib3ds_chunk_read_start(&c, CHK_AMBIENT_LIGHT))
    {
        return false;
    }

    while ((chunk = lib3ds_chunk_read_next(&c)) != 0)
    {
        switch (chunk)
        {
            case CHK_LIN_COLOR_F:
            {
                int i;
                for (i = 0; i < 3; ++i)
                {
                    ambient[i] = lib3ds_io_read_float();
                }
                have_lin = true;
                break;
            }

            case CHK_COLOR_F:
            {
                /* gamma corrected color chunk
                   replaced in 3ds R3 by LIN_COLOR_24 */
                if (!have_lin)
                {
                    int i;
                    for (i = 0; i < 3; ++i)
                    {
                        ambient[i] = lib3ds_io_read_float();
                    }
                }
                break;
            }

            default:
                lib3ds_chunk_unknown(chunk);
        }
    }

    lib3ds_chunk_read_end(&c);

    return true;
}

bool compare_node_id(const Lib3dsNode &a, const Lib3dsNode &b)
{
    return a.setting.node_id < b.setting.node_id;
}

void Lib3ds_stage::reorderingnodes(Lib3dsNode *node)
{
    QList<Lib3dsNode>::iterator p = node->children.begin();

    while(p != node->children.end())
    {
        (*p).setting.parent = node;

        reorderingnodes(&(*p));

        ++p;
    }


}

bool Lib3ds_stage::kfdata_read()
{
    Lib3dsChunk c;
    uint16_t chunk;

    QList<Lib3dsNode> localnodes;

    if(!lib3ds_chunk_read_start(&c, CHK_KFDATA))
    {
        return false;
    }

    while ((chunk = lib3ds_chunk_read_next(&c)) != 0)
    {
        switch (chunk)
        {
            case CHK_KFHDR: // Flag of key frame head
            {
                keyf_revision = lib3ds_io_read_word();

                if(!lib3ds_io_read_string(name, 12 + 1))
                {
                    return false;
                }

                frames = lib3ds_io_read_intd();

                break;
            }

            case CHK_KFSEG: // Flag of reading of sements data
            {
                segment_from = lib3ds_io_read_intd();

                segment_to = lib3ds_io_read_intd();

                break;
            }

            case CHK_KFCURTIME: // Flag setting of number of current frame
            {
                current_frame = lib3ds_io_read_intd();

                break;
            }

            case CHK_VIEWPORT_LAYOUT: // Flags od reading of viewport data
            case CHK_DEFAULT_VIEW:
            {
                lib3ds_chunk_read_reset(&c);

                lib3ds_viewport_read(&viewport_keyf);

                break;
            }

            case CHK_AMBIENT_NODE_TAG: // Flags of node type
            case CHK_OBJECT_NODE_TAG:
            case CHK_CAMERA_NODE_TAG:
            case CHK_TARGET_NODE_TAG:
            case CHK_LIGHT_NODE_TAG:
            case CHK_SPOTLIGHT_NODE_TAG:
            case CHK_L_TARGET_NODE_TAG:
            {
                Lib3dsNodeType type;
                Lib3dsNode *node;

                switch (chunk)
                {
                    case CHK_AMBIENT_NODE_TAG:
                        type = LIB3DS_NODE_AMBIENT_COLOR;
                        break;
                    case CHK_OBJECT_NODE_TAG:
                        type = LIB3DS_NODE_MESH_INSTANCE;
                        break;
                    case CHK_CAMERA_NODE_TAG:
                        type = LIB3DS_NODE_CAMERA;
                        break;
                    case CHK_TARGET_NODE_TAG:
                        type = LIB3DS_NODE_CAMERA_TARGET;
                        break;
                    case CHK_LIGHT_NODE_TAG:
                        type = LIB3DS_NODE_OMNILIGHT;
                        break;
                    case CHK_SPOTLIGHT_NODE_TAG:
                        type = LIB3DS_NODE_SPOTLIGHT;
                        break;
                    case CHK_L_TARGET_NODE_TAG:
                        type = LIB3DS_NODE_SPOTLIGHT_TARGET;
                        break;
                }

                Lib3dsNode temp_node = lib3ds_node_new(type);

                localnodes.append(temp_node);

                node = &localnodes[localnodes.length()-1];

                lib3ds_chunk_read_reset(&c);

                if(!lib3ds_node_read(node))
                {
                    return false;
                }

                break;
            }

            default:
                lib3ds_chunk_unknown(chunk);
        }
    }

    {
        QList<Lib3dsNode>::iterator p;

        qSort(localnodes.begin(), localnodes.end(), compare_node_id);

        p = localnodes.end();

        while (p != localnodes.begin())
        {
            --p;

            if((*p).setting.user_id != 65535)
            {
                localnodes[(*p).setting.user_id].children.append((*p));
            }

        }


        p = localnodes.begin();

        while (p != localnodes.end())
        {
            if((*p).setting.user_id == 65535)
            {
                nodes.append((*p));
            }

            ++p;
        }

        p = nodes.begin();

        while(p != nodes.end())
        {
            reorderingnodes(&(*p));

            ++p;
        }

    }

    lib3ds_chunk_read_end(&c);

    return true;

}

void Lib3ds_stage::lib3ds_stage_bounding_box_of_nodes(int include_meshes,
                                  int include_cameras,int include_lights,
                                  float bmin[3], float bmax[3], float matrix[4][4])
{

    float M[4][4];

    if (matrix)
    {
        lib3ds_matrix_copy(M, matrix);
    }
    else
    {
        lib3ds_matrix_identity(M);
    }

    bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
    bmax[0] = bmax[1] = bmax[2] = -FLT_MAX;

    QList<Lib3dsNode>::iterator p = nodes.begin();

    while(p!=nodes.end())
    {
      file_bounding_box_of_nodes_impl(&(*p), include_meshes, include_cameras, include_lights, bmin, bmax, M);

      ++p;
    }

}

void Lib3ds_stage::file_bounding_box_of_nodes_impl(Lib3dsNode *node, int include_meshes, int include_cameras,
                                                   int include_lights, float bmin[3],
                                                   float bmax[3], float matrix[4][4])
{
    switch (node->setting.type)
    {
        case LIB3DS_NODE_MESH_INSTANCE:
            if (include_meshes)
            {
                int index = -1;

                QString name;

                if(meshes.contains(node->MeshInstanceNode.instance_name))
                {
                    index = 0;

                    name = node->MeshInstanceNode.instance_name;
                }
                else
                {
                    if(meshes.contains(node->name))
                    {
                        index = 0;

                        name = node->name;
                    }
                }

                if (index == 0)
                {
                    Lib3dsMesh *mesh;
                    float inv_matrix[4][4], M[4][4];
                    float v[3];
                    int i;

                    mesh = &meshes[name];
                    lib3ds_matrix_copy(inv_matrix, mesh->setting.matrix);
                    lib3ds_matrix_inv(inv_matrix);
                    lib3ds_matrix_mult(M, matrix, node->setting.matrix);
                    lib3ds_matrix_translate(M, -node->MeshInstanceNode.pivot[0], -node->MeshInstanceNode.pivot[1], -node->MeshInstanceNode.pivot[2]);
                    lib3ds_matrix_mult(M, M, inv_matrix);

                    for (i = 0; i < mesh->vertices.size(); ++i)
                    {
                        float a[3];

                        a[0] = mesh->vertices[i].x();

                        a[1] = mesh->vertices[i].y();

                        a[2] = mesh->vertices[i].z();

                        lib3ds_vector_transform(v, M, a);
                        lib3ds_vector_min(bmin, v);
                        lib3ds_vector_max(bmax, v);
                    }
                }
            }
            break;

        case LIB3DS_NODE_CAMERA:
        case LIB3DS_NODE_CAMERA_TARGET:
            if (include_cameras) {
                float z[3], v[3];
                float M[4][4];
                lib3ds_matrix_mult(M, matrix, node->setting.matrix);
                lib3ds_vector_zero(z);
                lib3ds_vector_transform(v, M, z);
                lib3ds_vector_min(bmin, v);
                lib3ds_vector_max(bmax, v);
            }
            break;

        case LIB3DS_NODE_OMNILIGHT:
        case LIB3DS_NODE_SPOTLIGHT:
        case LIB3DS_NODE_SPOTLIGHT_TARGET:
            if (include_lights) {
                float z[3], v[3];
                float M[4][4];
                lib3ds_matrix_mult(M, matrix, node->setting.matrix);
                lib3ds_vector_zero(z);
                lib3ds_vector_transform(v, M, z);
                lib3ds_vector_min(bmin, v);
                lib3ds_vector_max(bmax, v);
            }
            break;

    default:

            break;
    }
    {
        QList<Lib3dsNode>::iterator p = node->children.begin();

        while(p!=node->children.end())
        {
            file_bounding_box_of_nodes_impl(&(*p), include_meshes, include_cameras, include_lights, bmin, bmax, matrix);

            ++p;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions