/*! * \internal * * The objects created as children of \p parent will \em not be rotated or * translated correctly. Instead the required transformations are stored and * provided to the user, see \ref Loader3ds::getTransformationNodes */ bool Loader3dsInternal::loadNode(dcollide::World* world, dcollide::Proxy* parent, Lib3dsNode* node, Lib3dsMatrix* parentTranslateRotateMatrix) { if (!parent || !node) { return false; } if (node->type != LIB3DS_OBJECT_NODE) { return false; } Lib3dsObjectData* data = &node->data.object; Lib3dsMatrix translateRotateMatrix; lib3ds_matrix_copy(translateRotateMatrix, *parentTranslateRotateMatrix); lib3ds_matrix_translate(translateRotateMatrix, data->pos); lib3ds_matrix_rotate(translateRotateMatrix, data->rot); dcollide::Shape* shape = createShape(node, &translateRotateMatrix); dcollide::Proxy* object = world->createProxy(shape); mData->mProxy2TextureInformation.insert(std::make_pair(object, loadTextureInformation(node))); dcollide::Vector3 scale(data->scl[0], data->scl[1], data->scl[2]); dcollide::Vector3 translation(data->pos[0], data->pos[1], data->pos[2]); Lib3dsMatrix lib3dsRotationMatrix; lib3ds_matrix_identity(lib3dsRotationMatrix); lib3ds_matrix_rotate(lib3dsRotationMatrix, data->rot); dcollide::Matrix rotation(&lib3dsRotationMatrix[0][0]); Loader3ds::TransformationNode transformation; transformation.translation = translation; transformation.rotation = rotation; mData->mProxy2Transformation.insert(std::make_pair(object, transformation)); for (Lib3dsNode* n = node->childs; n; n = n->next) { if (!loadNode(world, object, n, &translateRotateMatrix)) { std::cerr << "Failed loading node " << n->name << std::endl; // TODO: delete object->getProxy() ? delete object; return false; } } parent->addChild(object); return 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]); }
/*! * 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, 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; }