/*! * Apply a rotation about an arbitrary axis to a matrix. * * \ingroup matrix */ void lib3ds_matrix_rotate(Lib3dsMatrix m, Lib3dsQuat q) { Lib3dsFloat s,xs,ys,zs,wx,wy,wz,xx,xy,xz,yy,yz,zz,l; Lib3dsMatrix R; l=q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]; if (fabs(l)<LIB3DS_EPSILON) { s=1.0f; } else { s=2.0f/l; } xs = q[0] * s; ys = q[1] * s; zs = q[2] * s; wx = q[3] * xs; wy = q[3] * ys; wz = q[3] * zs; xx = q[0] * xs; xy = q[0] * ys; xz = q[0] * zs; yy = q[1] * ys; yz = q[1] * zs; zz = q[2] * zs; R[0][0]=1.0f - (yy +zz); R[1][0]=xy - wz; R[2][0]=xz + wy; R[0][1]=xy + wz; R[1][1]=1.0f - (xx +zz); R[2][1]=yz - wx; R[0][2]=xz - wy; R[1][2]=yz + wx; R[2][2]=1.0f - (xx + yy); R[3][0]=R[3][1]=R[3][2]=R[0][3]=R[1][3]=R[2][3]=0.0f; R[3][3]=1.0f; lib3ds_matrix_mult(m,R); }
static void point_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) { Lib3dsChunk c; int i; c.chunk = CHK_POINT_ARRAY; c.size = 8 + 12 * mesh->nvertices; lib3ds_chunk_write(&c, io); lib3ds_io_write_word(io, (uint16_t) mesh->nvertices); if (lib3ds_matrix_det(mesh->matrix) >= 0.0f) { for (i = 0; i < mesh->nvertices; ++i) { lib3ds_io_write_vector(io, mesh->vertices[i]); } } else { /* Flip X coordinate of vertices if mesh matrix has negative determinant */ float inv_matrix[4][4], M[4][4]; float tmp[3]; lib3ds_matrix_copy(inv_matrix, mesh->matrix); lib3ds_matrix_inv(inv_matrix); lib3ds_matrix_copy(M, mesh->matrix); lib3ds_matrix_scale(M, -1.0f, 1.0f, 1.0f); lib3ds_matrix_mult(M, M, inv_matrix); for (i = 0; i < mesh->nvertices; ++i) { lib3ds_vector_transform(tmp, M, mesh->vertices[i]); lib3ds_io_write_vector(io, tmp); } } }
/*! * Compute a camera matrix based on position, target and roll. * * Generates a translate/rotate matrix that maps world coordinates * to camera coordinates. Resulting matrix does not include perspective * transform. * * \param matrix Destination matrix. * \param pos Camera position * \param tgt Camera target * \param roll Roll angle * * \ingroup matrix */ void lib3ds_matrix_camera(Lib3dsMatrix matrix, Lib3dsVector pos, Lib3dsVector tgt, Lib3dsFloat roll) { Lib3dsMatrix M; Lib3dsVector x, y, z; lib3ds_vector_sub(y, tgt, pos); lib3ds_vector_normalize(y); if (y[0] != 0. || y[1] != 0) { z[0] = 0; z[1] = 0; z[2] = 1.0; } else { /* Special case: looking straight up or down z axis */ z[0] = -1.0; z[1] = 0; z[2] = 0; } lib3ds_vector_cross(x, y, z); lib3ds_vector_cross(z, x, y); lib3ds_vector_normalize(x); lib3ds_vector_normalize(z); lib3ds_matrix_identity(M); M[0][0] = x[0]; M[1][0] = x[1]; M[2][0] = x[2]; M[0][1] = y[0]; M[1][1] = y[1]; M[2][1] = y[2]; M[0][2] = z[0]; M[1][2] = z[1]; M[2][2] = z[2]; lib3ds_matrix_identity(matrix); lib3ds_matrix_rotate_y(matrix, roll); lib3ds_matrix_mult(matrix, M); lib3ds_matrix_translate_xyz(matrix, -pos[0],-pos[1],-pos[2]); }
static Lib3dsBool point_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) { Lib3dsChunk c; unsigned i; if (!mesh->points || !mesh->pointL) { return(LIB3DS_TRUE); } ASSERT(mesh->points<0x10000); c.chunk=LIB3DS_POINT_ARRAY; c.size=8+12*mesh->points; lib3ds_chunk_write(&c, io); lib3ds_io_write_word(io, (Lib3dsWord)mesh->points); if (lib3ds_matrix_det(mesh->matrix) >= 0.0f) { for (i=0; i<mesh->points; ++i) { lib3ds_io_write_vector(io, mesh->pointL[i].pos); } } else { /* Flip X coordinate of vertices if mesh matrix has negative determinant */ Lib3dsMatrix inv_matrix, M; Lib3dsVector tmp; lib3ds_matrix_copy(inv_matrix, mesh->matrix); lib3ds_matrix_inv(inv_matrix); lib3ds_matrix_copy(M, mesh->matrix); lib3ds_matrix_scale_xyz(M, -1.0f, 1.0f, 1.0f); lib3ds_matrix_mult(M, inv_matrix); for (i=0; i<mesh->points; ++i) { lib3ds_vector_transform(tmp, M, mesh->pointL[i].pos); lib3ds_io_write_vector(io, tmp); } } return(LIB3DS_TRUE); }
/*! * Compute a camera matrix based on position, target and roll. * * Generates a translate/rotate matrix that maps world coordinates * to camera coordinates. Resulting matrix does not include perspective * transform. * * \param matrix Destination matrix. * \param pos Camera position * \param tgt Camera target * \param roll Roll angle */ void lib3ds_matrix_camera(float matrix[4][4], float pos[3], float tgt[3], float roll) { float M[4][4]; float x[3], y[3], z[3]; lib3ds_vector_sub(y, tgt, pos); lib3ds_vector_normalize(y); if (y[0] != 0. || y[1] != 0) { z[0] = 0; z[1] = 0; z[2] = 1.0; } else { /* Special case: looking straight up or down z axis */ z[0] = -1.0; z[1] = 0; z[2] = 0; } lib3ds_vector_cross(x, y, z); lib3ds_vector_cross(z, x, y); lib3ds_vector_normalize(x); lib3ds_vector_normalize(z); lib3ds_matrix_identity(M); M[0][0] = x[0]; M[1][0] = x[1]; M[2][0] = x[2]; M[0][1] = y[0]; M[1][1] = y[1]; M[2][1] = y[2]; M[0][2] = z[0]; M[1][2] = z[1]; M[2][2] = z[2]; lib3ds_matrix_identity(matrix); lib3ds_matrix_rotate(matrix, roll, 0, 1, 0); lib3ds_matrix_mult(matrix, matrix, M); lib3ds_matrix_translate(matrix, -pos[0], -pos[1], -pos[2]); }
void lib3ds_mesh_read(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) { Lib3dsChunk c; uint16_t chunk; lib3ds_chunk_read_start(&c, CHK_N_TRI_OBJECT, io); while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) { switch (chunk) { case CHK_MESH_MATRIX: { int i, j; lib3ds_matrix_identity(mesh->matrix); for (i = 0; i < 4; i++) { for (j = 0; j < 3; j++) { mesh->matrix[i][j] = lib3ds_io_read_float(io); } } break; } case CHK_MESH_COLOR: { mesh->color = lib3ds_io_read_byte(io); break; } case CHK_POINT_ARRAY: { int i; uint16_t nvertices = lib3ds_io_read_word(io); lib3ds_mesh_resize_vertices(mesh, nvertices, mesh->texcos != NULL, mesh->vflags != NULL); for (i = 0; i < mesh->nvertices; ++i) { lib3ds_io_read_vector(io, mesh->vertices[i]); } break; } case CHK_POINT_FLAG_ARRAY: { int i; uint16_t nflags = lib3ds_io_read_word(io); uint16_t nvertices = (mesh->nvertices >= nflags)? mesh->nvertices : nflags; lib3ds_mesh_resize_vertices(mesh, nvertices, mesh->texcos != NULL, 1); for (i = 0; i < nflags; ++i) { mesh->vflags[i] = lib3ds_io_read_word(io); } break; } case CHK_FACE_ARRAY: { lib3ds_chunk_read_reset(&c, io); face_array_read(file, mesh, io); break; } case CHK_MESH_TEXTURE_INFO: { int i, j; //FIXME: mesh->map_type = lib3ds_io_read_word(io); for (i = 0; i < 2; ++i) { mesh->map_tile[i] = lib3ds_io_read_float(io); } for (i = 0; i < 3; ++i) { mesh->map_pos[i] = lib3ds_io_read_float(io); } mesh->map_scale = lib3ds_io_read_float(io); lib3ds_matrix_identity(mesh->map_matrix); for (i = 0; i < 4; i++) { for (j = 0; j < 3; j++) { mesh->map_matrix[i][j] = lib3ds_io_read_float(io); } } for (i = 0; i < 2; ++i) { mesh->map_planar_size[i] = lib3ds_io_read_float(io); } mesh->map_cylinder_height = lib3ds_io_read_float(io); break; } case CHK_TEX_VERTS: { int i; uint16_t ntexcos = lib3ds_io_read_word(io); uint16_t nvertices = (mesh->nvertices >= ntexcos)? mesh->nvertices : ntexcos;; if (!mesh->texcos) { lib3ds_mesh_resize_vertices(mesh, nvertices, 1, mesh->vflags != NULL); } for (i = 0; i < ntexcos; ++i) { mesh->texcos[i][0] = lib3ds_io_read_float(io); mesh->texcos[i][1] = lib3ds_io_read_float(io); } break; } default: lib3ds_chunk_unknown(chunk, io); } } if (lib3ds_matrix_det(mesh->matrix) < 0.0) { /* Flip X coordinate of vertices if mesh matrix has negative determinant */ float inv_matrix[4][4], M[4][4]; float tmp[3]; int i; lib3ds_matrix_copy(inv_matrix, mesh->matrix); lib3ds_matrix_inv(inv_matrix); lib3ds_matrix_copy(M, mesh->matrix); lib3ds_matrix_scale(M, -1.0f, 1.0f, 1.0f); lib3ds_matrix_mult(M, M, inv_matrix); for (i = 0; i < mesh->nvertices; ++i) { lib3ds_vector_transform(tmp, M, mesh->vertices[i]); lib3ds_vector_copy(mesh->vertices[i], tmp); } } lib3ds_chunk_read_end(&c, io); }
/*! * \ingroup mesh */ Lib3dsBool lib3ds_mesh_read(Lib3dsMesh *mesh, Lib3dsIo *io) { Lib3dsChunk c; Lib3dsWord chunk; if (!lib3ds_chunk_read_start(&c, LIB3DS_N_TRI_OBJECT, io)) { return(LIB3DS_FALSE); } while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) { switch (chunk) { case LIB3DS_MESH_MATRIX: { int i,j; lib3ds_matrix_identity(mesh->matrix); for (i=0; i<4; i++) { for (j=0; j<3; j++) { mesh->matrix[i][j]=lib3ds_io_read_float(io); } } } break; case LIB3DS_MESH_COLOR: { mesh->color=lib3ds_io_read_byte(io); } break; case LIB3DS_POINT_ARRAY: { unsigned i,j; unsigned points; lib3ds_mesh_free_point_list(mesh); points=lib3ds_io_read_word(io); if (points) { if (!lib3ds_mesh_new_point_list(mesh, points)) { LIB3DS_ERROR_LOG; return(LIB3DS_FALSE); } for (i=0; i<mesh->points; ++i) { for (j=0; j<3; ++j) { mesh->pointL[i].pos[j]=lib3ds_io_read_float(io); } } ASSERT((!mesh->flags) || (mesh->points==mesh->flags)); ASSERT((!mesh->texels) || (mesh->points==mesh->texels)); } } break; case LIB3DS_POINT_FLAG_ARRAY: { unsigned i; unsigned flags; lib3ds_mesh_free_flag_list(mesh); flags=lib3ds_io_read_word(io); if (flags) { if (!lib3ds_mesh_new_flag_list(mesh, flags)) { LIB3DS_ERROR_LOG; return(LIB3DS_FALSE); } for (i=0; i<mesh->flags; ++i) { mesh->flagL[i]=lib3ds_io_read_word(io); } ASSERT((!mesh->points) || (mesh->flags==mesh->points)); ASSERT((!mesh->texels) || (mesh->flags==mesh->texels)); } } break; case LIB3DS_FACE_ARRAY: { lib3ds_chunk_read_reset(&c, io); if (!face_array_read(mesh, io)) { return(LIB3DS_FALSE); } } break; case LIB3DS_MESH_TEXTURE_INFO: { int i,j; for (i=0; i<2; ++i) { mesh->map_data.tile[i]=lib3ds_io_read_float(io); } for (i=0; i<3; ++i) { mesh->map_data.pos[i]=lib3ds_io_read_float(io); } mesh->map_data.scale=lib3ds_io_read_float(io); lib3ds_matrix_identity(mesh->map_data.matrix); for (i=0; i<4; i++) { for (j=0; j<3; j++) { mesh->map_data.matrix[i][j]=lib3ds_io_read_float(io); } } for (i=0; i<2; ++i) { mesh->map_data.planar_size[i]=lib3ds_io_read_float(io); } mesh->map_data.cylinder_height=lib3ds_io_read_float(io); } break; case LIB3DS_TEX_VERTS: { unsigned i; unsigned texels; lib3ds_mesh_free_texel_list(mesh); texels=lib3ds_io_read_word(io); if (texels) { if (!lib3ds_mesh_new_texel_list(mesh, texels)) { LIB3DS_ERROR_LOG; return(LIB3DS_FALSE); } for (i=0; i<mesh->texels; ++i) { mesh->texelL[i][0]=lib3ds_io_read_float(io); mesh->texelL[i][1]=lib3ds_io_read_float(io); } ASSERT((!mesh->points) || (mesh->texels==mesh->points)); ASSERT((!mesh->flags) || (mesh->texels==mesh->flags)); } } break; default: lib3ds_chunk_unknown(chunk); } } { unsigned j; for (j=0; j<mesh->faces; ++j) { ASSERT(mesh->faceL[j].points[0]<mesh->points); ASSERT(mesh->faceL[j].points[1]<mesh->points); ASSERT(mesh->faceL[j].points[2]<mesh->points); lib3ds_vector_normal( mesh->faceL[j].normal, mesh->pointL[mesh->faceL[j].points[0]].pos, mesh->pointL[mesh->faceL[j].points[1]].pos, mesh->pointL[mesh->faceL[j].points[2]].pos ); } } if (lib3ds_matrix_det(mesh->matrix) < 0.0) { /* Flip X coordinate of vertices if mesh matrix has negative determinant */ Lib3dsMatrix inv_matrix, M; Lib3dsVector tmp; unsigned i; lib3ds_matrix_copy(inv_matrix, mesh->matrix); lib3ds_matrix_inv(inv_matrix); lib3ds_matrix_copy(M, mesh->matrix); lib3ds_matrix_scale_xyz(M, -1.0f, 1.0f, 1.0f); lib3ds_matrix_mult(M, inv_matrix); for (i=0; i<mesh->points; ++i) { lib3ds_vector_transform(tmp, M, mesh->pointL[i].pos); lib3ds_vector_copy(mesh->pointL[i].pos, tmp); } } lib3ds_chunk_read_end(&c, io); return(LIB3DS_TRUE); }
/*! * Evaluate an animation node. * * Recursively sets node and its children to their appropriate values * for this point in the animation. * * \param node Node to be evaluated. * \param t time value, between 0. and file->frames * * \ingroup node */ void lib3ds_node_eval(Lib3dsNode *node, Lib3dsFloat t) { ASSERT(node); switch (node->type) { case LIB3DS_UNKNOWN_NODE: { ASSERT(LIB3DS_FALSE); } break; case LIB3DS_AMBIENT_NODE: { Lib3dsAmbientData *n=&node->data.ambient; if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); } else { lib3ds_matrix_identity(node->matrix); } lib3ds_lin3_track_eval(&n->col_track, n->col, t); } break; case LIB3DS_OBJECT_NODE: { Lib3dsMatrix M; Lib3dsObjectData *n=&node->data.object; lib3ds_lin3_track_eval(&n->pos_track, n->pos, t); lib3ds_quat_track_eval(&n->rot_track, n->rot, t); if (n->scl_track.keyL) { lib3ds_lin3_track_eval(&n->scl_track, n->scl, t); } else { n->scl[0] = n->scl[1] = n->scl[2] = 1.0f; } lib3ds_bool_track_eval(&n->hide_track, &n->hide, t); lib3ds_morph_track_eval(&n->morph_track, n->morph, t); lib3ds_matrix_identity(M); lib3ds_matrix_translate(M, n->pos); lib3ds_matrix_rotate(M, n->rot); lib3ds_matrix_scale(M, n->scl); if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); lib3ds_matrix_mult(node->matrix, M); } else { lib3ds_matrix_copy(node->matrix, M); } } break; case LIB3DS_CAMERA_NODE: { Lib3dsCameraData *n=&node->data.camera; lib3ds_lin3_track_eval(&n->pos_track, n->pos, t); lib3ds_lin1_track_eval(&n->fov_track, &n->fov, t); lib3ds_lin1_track_eval(&n->roll_track, &n->roll, t); if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); } else { lib3ds_matrix_identity(node->matrix); } lib3ds_matrix_translate(node->matrix, n->pos); } break; case LIB3DS_TARGET_NODE: { Lib3dsTargetData *n=&node->data.target; lib3ds_lin3_track_eval(&n->pos_track, n->pos, t); if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); } else { lib3ds_matrix_identity(node->matrix); } lib3ds_matrix_translate(node->matrix, n->pos); } break; case LIB3DS_LIGHT_NODE: { Lib3dsLightData *n=&node->data.light; lib3ds_lin3_track_eval(&n->pos_track, n->pos, t); lib3ds_lin3_track_eval(&n->col_track, n->col, t); lib3ds_lin1_track_eval(&n->hotspot_track, &n->hotspot, t); lib3ds_lin1_track_eval(&n->falloff_track, &n->falloff, t); lib3ds_lin1_track_eval(&n->roll_track, &n->roll, t); if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); } else { lib3ds_matrix_identity(node->matrix); } lib3ds_matrix_translate(node->matrix, n->pos); } break; case LIB3DS_SPOT_NODE: { Lib3dsSpotData *n=&node->data.spot; lib3ds_lin3_track_eval(&n->pos_track, n->pos, t); if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); } else { lib3ds_matrix_identity(node->matrix); } lib3ds_matrix_translate(node->matrix, n->pos); } break; } { Lib3dsNode *p; for (p=node->childs; p!=0; p=p->next) { lib3ds_node_eval(p, t); } } }
/*! * Evaluate an animation node. * * Recursively sets node and its children to their appropriate values * for this point in the animation. * * \param node Node to be evaluated. * \param t time value, between 0. and file->frames */ void lib3ds_node_eval(Lib3dsNode *node, float t) { assert(node); switch (node->type) { case LIB3DS_NODE_AMBIENT_COLOR: { Lib3dsAmbientColorNode *n = (Lib3dsAmbientColorNode*)node; if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); } else { lib3ds_matrix_identity(node->matrix); } lib3ds_track_eval_vector(&n->color_track, n->color, t); break; } case LIB3DS_NODE_MESH_INSTANCE: { float M[4][4]; Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node; lib3ds_track_eval_vector(&n->pos_track, n->pos, t); lib3ds_track_eval_quat(&n->rot_track, n->rot, t); if (n->scl_track.nkeys) { lib3ds_track_eval_vector(&n->scl_track, n->scl, t); } else { n->scl[0] = n->scl[1] = n->scl[2] = 1.0f; } lib3ds_track_eval_bool(&n->hide_track, &n->hide, t); lib3ds_matrix_identity(M); lib3ds_matrix_translate(M, n->pos[0], n->pos[1], n->pos[2]); lib3ds_matrix_rotate_quat(M, n->rot); lib3ds_matrix_scale(M, n->scl[0], n->scl[1], n->scl[2]); if (node->parent) { lib3ds_matrix_mult(node->matrix, node->parent->matrix, M); } else { lib3ds_matrix_copy(node->matrix, M); } break; } case LIB3DS_NODE_CAMERA: { Lib3dsCameraNode *n = (Lib3dsCameraNode*)node; lib3ds_track_eval_vector(&n->pos_track, n->pos, t); lib3ds_track_eval_float(&n->fov_track, &n->fov, t); lib3ds_track_eval_float(&n->roll_track, &n->roll, t); if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); } else { lib3ds_matrix_identity(node->matrix); } lib3ds_matrix_translate(node->matrix, n->pos[0], n->pos[1], n->pos[2]); break; } case LIB3DS_NODE_CAMERA_TARGET: { Lib3dsTargetNode *n = (Lib3dsTargetNode*)node; lib3ds_track_eval_vector(&n->pos_track, n->pos, t); if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); } else { lib3ds_matrix_identity(node->matrix); } lib3ds_matrix_translate(node->matrix, n->pos[0], n->pos[1], n->pos[2]); break; } case LIB3DS_NODE_OMNILIGHT: { Lib3dsOmnilightNode *n = (Lib3dsOmnilightNode*)node; lib3ds_track_eval_vector(&n->pos_track, n->pos, t); lib3ds_track_eval_vector(&n->color_track, n->color, t); if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); } else { lib3ds_matrix_identity(node->matrix); } lib3ds_matrix_translate(node->matrix, n->pos[0], n->pos[1], n->pos[2]); break; } case LIB3DS_NODE_SPOTLIGHT: { Lib3dsSpotlightNode *n = (Lib3dsSpotlightNode*)node; lib3ds_track_eval_vector(&n->pos_track, n->pos, t); lib3ds_track_eval_vector(&n->color_track, n->color, t); lib3ds_track_eval_float(&n->hotspot_track, &n->hotspot, t); lib3ds_track_eval_float(&n->falloff_track, &n->falloff, t); lib3ds_track_eval_float(&n->roll_track, &n->roll, t); if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); } else { lib3ds_matrix_identity(node->matrix); } lib3ds_matrix_translate(node->matrix, n->pos[0], n->pos[1], n->pos[2]); break; } case LIB3DS_NODE_SPOTLIGHT_TARGET: { Lib3dsTargetNode *n = (Lib3dsTargetNode*)node; lib3ds_track_eval_vector(&n->pos_track, n->pos, t); if (node->parent) { lib3ds_matrix_copy(node->matrix, node->parent->matrix); } else { lib3ds_matrix_identity(node->matrix); } lib3ds_matrix_translate(node->matrix, n->pos[0], n->pos[1], n->pos[2]); break; } } { Lib3dsNode *p; for (p = node->childs; p != 0; p = p->next) { lib3ds_node_eval(p, t); } } }
static void file_bounding_box_of_nodes_impl(Lib3dsNode *node, Lib3dsFile *file, Lib3dsBool include_meshes, Lib3dsBool include_cameras, Lib3dsBool include_lights, Lib3dsVector bmin, Lib3dsVector bmax) { switch (node->type) { case LIB3DS_OBJECT_NODE: if (include_meshes) { Lib3dsMesh *mesh; mesh = lib3ds_file_mesh_by_name(file, node->data.object.instance); if (!mesh) mesh = lib3ds_file_mesh_by_name(file, node->name); if (mesh) { Lib3dsMatrix inv_matrix, M; Lib3dsVector v; unsigned i; lib3ds_matrix_copy(inv_matrix, mesh->matrix); lib3ds_matrix_inv(inv_matrix); lib3ds_matrix_copy(M, node->matrix); lib3ds_matrix_translate_xyz(M, -node->data.object.pivot[0], -node->data.object.pivot[1], -node->data.object.pivot[2]); lib3ds_matrix_mult(M, inv_matrix); for (i=0; i<mesh->points; ++i) { lib3ds_vector_transform(v, M, mesh->pointL[i].pos); lib3ds_vector_min(bmin, v); lib3ds_vector_max(bmax, v); } } } break; /* case LIB3DS_CAMERA_NODE: case LIB3DS_TARGET_NODE: if (include_cameras) { Lib3dsVector z,v; lib3ds_vector_zero(z); lib3ds_vector_transform(v, node->matrix, z); lib3ds_vector_min(bmin, v); lib3ds_vector_max(bmax, v); } break; case LIB3DS_LIGHT_NODE: case LIB3DS_SPOT_NODE: if (include_lights) { Lib3dsVector z,v; lib3ds_vector_zero(z); lib3ds_vector_transform(v, node->matrix, z); lib3ds_vector_min(bmin, v); lib3ds_vector_max(bmax, v); } break; */ } { Lib3dsNode *p=node->childs; while (p) { file_bounding_box_of_nodes_impl(p, file, include_meshes, include_cameras, include_lights, bmin, bmax); p=p->next; } } }
static void file_bounding_box_of_nodes_impl(Lib3dsNode *node, Lib3dsFile *file, int include_meshes, int include_cameras, int include_lights, float bmin[3], float bmax[3], float matrix[4][4]) { switch (node->type) { case LIB3DS_NODE_MESH_INSTANCE: if (include_meshes) { int index; Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node; index = lib3ds_file_mesh_by_name(file, n->instance_name); if (index < 0) index = lib3ds_file_mesh_by_name(file, node->name); if (index >= 0) { Lib3dsMesh *mesh; float inv_matrix[4][4], M[4][4]; float v[3]; int i; mesh = file->meshes[index]; lib3ds_matrix_copy(inv_matrix, mesh->matrix); lib3ds_matrix_inv(inv_matrix); lib3ds_matrix_mult(M, matrix, node->matrix); lib3ds_matrix_translate(M, -n->pivot[0], -n->pivot[1], -n->pivot[2]); lib3ds_matrix_mult(M, M, inv_matrix); for (i = 0; i < mesh->nvertices; ++i) { lib3ds_vector_transform(v, M, mesh->vertices[i]); 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->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->matrix); lib3ds_vector_zero(z); lib3ds_vector_transform(v, M, z); lib3ds_vector_min(bmin, v); lib3ds_vector_max(bmax, v); } break; } { Lib3dsNode *p = node->childs; while (p) { file_bounding_box_of_nodes_impl(p, file, include_meshes, include_cameras, include_lights, bmin, bmax, matrix); p = p->next; } } }
void write_mesh(FILE *o, Lib3dsFile *f, Lib3dsMeshInstanceNode *node) { float (*orig_vertices)[3]; int export_texcos; int export_normals; int i, j; Lib3dsMesh *mesh; mesh = lib3ds_file_mesh_for_node(f, (Lib3dsNode*)node); if (!mesh || !mesh->vertices) return; fprintf(o, "# object %s\n", node->base.name); fprintf(o, "g %s\n", node->instance_name[0]? node->instance_name : node->base.name); orig_vertices = (float(*)[3])malloc(sizeof(float) * 3 * mesh->nvertices); memcpy(orig_vertices, mesh->vertices, sizeof(float) * 3 * mesh->nvertices); { float inv_matrix[4][4], M[4][4]; float tmp[3]; int i; lib3ds_matrix_copy(M, node->base.matrix); lib3ds_matrix_translate(M, -node->pivot[0], -node->pivot[1], -node->pivot[2]); lib3ds_matrix_copy(inv_matrix, mesh->matrix); lib3ds_matrix_inv(inv_matrix); lib3ds_matrix_mult(M, M, inv_matrix); for (i = 0; i < mesh->nvertices; ++i) { lib3ds_vector_transform(tmp, M, mesh->vertices[i]); lib3ds_vector_copy(mesh->vertices[i], tmp); } } export_texcos = (mesh->texcos != 0); export_normals = (mesh->faces != 0); for (i = 0; i < mesh->nvertices; ++i) { fprintf(o, "v %f %f %f\n", mesh->vertices[i][0], mesh->vertices[i][1], mesh->vertices[i][2]); } fprintf(o, "# %d vertices\n", mesh->nvertices); if (export_texcos) { for (i = 0; i < mesh->nvertices; ++i) { fprintf(o, "vt %f %f\n", mesh->texcos[i][0], mesh->texcos[i][1]); } fprintf(o, "# %d texture vertices\n", mesh->nvertices); } if (export_normals) { float (*normals)[3] = (float(*)[3])malloc(sizeof(float) * 9 * mesh->nfaces); lib3ds_mesh_calculate_vertex_normals(mesh, normals); for (i = 0; i < 3 * mesh->nfaces; ++i) { fprintf(o, "vn %f %f %f\n", normals[i][0], normals[i][1], normals[i][2]); } free(normals); fprintf(o, "# %d normals\n", 3 * mesh->nfaces); } { int mat_index = -1; for (i = 0; i < mesh->nfaces; ++i) { if (mat_index != mesh->faces[i].material) { mat_index = mesh->faces[i].material; if (mat_index != -1) { fprintf(o, "usemtl %s\n", f->materials[mat_index]->name); } } fprintf(o, "f "); for (j = 0; j < 3; ++j) { fprintf(o, "%d", mesh->faces[i].index[j] + max_vertices + 1); if (export_texcos) { fprintf(o, "/%d", mesh->faces[i].index[j] + max_texcos + 1); } else if (export_normals) { fprintf(o, "/"); } if (export_normals) { fprintf(o, "/%d", 3 * i + j + max_normals + 1); } if (j < 3) { fprintf(o, " "); } } fprintf(o, "\n"); } } max_vertices += mesh->nvertices; if (export_texcos) max_texcos += mesh->nvertices; if (export_normals) max_normals += 3 * mesh->nfaces; memcpy(mesh->vertices, orig_vertices, sizeof(float) * 3 * mesh->nvertices); free(orig_vertices); }
std::vector<CL_Lib3dsMesh> CL_Lib3dsFile::export_meshes(Lib3dsNode *node) { if (node == 0) { lib3ds_file_eval(file, 0.0f); node = file->nodes; } std::vector<CL_Lib3dsMesh> meshes; for (; node; node = node->next) { if (node->type == LIB3DS_NODE_MESH_INSTANCE) { Lib3dsMeshInstanceNode *instance_node = (Lib3dsMeshInstanceNode *) node; Lib3dsMesh *mesh = lib3ds_file_mesh_for_node(file, (Lib3dsNode*)node); if (mesh && mesh->vertices) { float inv_matrix[4][4], M[4][4]; lib3ds_matrix_copy(M, instance_node->base.matrix); lib3ds_matrix_translate(M, -instance_node->pivot[0], -instance_node->pivot[1], -instance_node->pivot[2]); lib3ds_matrix_copy(inv_matrix, mesh->matrix); lib3ds_matrix_inv(inv_matrix); lib3ds_matrix_mult(M, M, inv_matrix); std::vector<CL_Vec3f> positions; for (int i = 0; i < mesh->nvertices; ++i) { float position[3]; lib3ds_vector_transform(position, M, mesh->vertices[i]); positions.push_back(CL_Vec3f(position[0], position[1], position[2])); } std::vector<CL_Vec2f> texcoords; if (mesh->texcos) { for (int i = 0; i < mesh->nvertices; ++i) { float tx = mesh->texcos[i][0]; float ty = mesh->texcos[i][1]; texcoords.push_back(CL_Vec2f(tx, ty)); } } std::vector<CL_Vec3f> normals; if (mesh->faces && mesh->nfaces > 0) { float (*normals_array)[3] = (float(*)[3])malloc(sizeof(float) * 9 * mesh->nfaces); lib3ds_mesh_calculate_vertex_normals(mesh, normals_array); for (int i = 0; i < 3 * mesh->nfaces; ++i) { normals.push_back(CL_Vec3f(normals_array[i][0], normals_array[i][1], normals_array[i][2])); } free(normals_array); } CL_Lib3dsMesh mesh_object; for (int i = 0; i < mesh->nfaces; ++i) { int material_index = mesh->faces[i].material; mesh_object.face_materials.push_back(material_index); for (int j = 0; j < 3; ++j) { int vertex_index = mesh->faces[i].index[j]; mesh_object.positions.push_back(positions[vertex_index]); if (!texcoords.empty()) mesh_object.texcooords.push_back(texcoords[vertex_index]); if (!normals.empty()) mesh_object.normals.push_back(normals[i*3+j]); } } meshes.push_back(mesh_object); } if (node->childs) { std::vector<CL_Lib3dsMesh> child_meshes = export_meshes(node->childs); meshes.insert(meshes.end(), child_meshes.begin(), child_meshes.end()); } } } return meshes; }