#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;
}
}
}