/*! * Find the bounding box of a mesh object. * * \param mesh The mesh object * \param min Returned bounding box * \param max Returned bounding box * * \ingroup mesh */ void lib3ds_mesh_bounding_box(Lib3dsMesh *mesh, Lib3dsVector min, Lib3dsVector max) { unsigned i,j; Lib3dsFloat v; if (!mesh->points) { lib3ds_vector_zero(min); lib3ds_vector_zero(max); return; } lib3ds_vector_copy(min, mesh->pointL[0].pos); lib3ds_vector_copy(max, mesh->pointL[0].pos); for (i=1; i<mesh->points; ++i) { for (j=0; j<3; ++j) { v=mesh->pointL[i].pos[j]; if (v<min[j]) { min[j]=v; } if (v>max[j]) { max[j]=v; } } }; }
Lib3dsSpotlightNode* lib3ds_node_new_spotlight(Lib3dsLight *light) { Lib3dsNode *node; Lib3dsSpotlightNode *n; assert(light); node = lib3ds_node_new(LIB3DS_NODE_SPOTLIGHT); strcpy(node->name, light->name); n = (Lib3dsSpotlightNode*)node; lib3ds_track_resize(&n->pos_track, 1); lib3ds_vector_copy(n->pos_track.keys[0].value, light->position); lib3ds_track_resize(&n->color_track, 1); lib3ds_vector_copy(n->color_track.keys[0].value, light->color); lib3ds_track_resize(&n->hotspot_track, 1); n->hotspot_track.keys[0].value[0] = light->hotspot; lib3ds_track_resize(&n->falloff_track, 1); n->falloff_track.keys[0].value[0] = light->falloff; lib3ds_track_resize(&n->roll_track, 1); n->roll_track.keys[0].value[0] = light->roll; return n; }
/*! * \ingroup file */ void lib3ds_file_bounding_box(Lib3dsFile *file, Lib3dsVector min, Lib3dsVector max) { Lib3dsBool init=LIB3DS_FALSE; { Lib3dsVector lmin, lmax; Lib3dsMesh *p=file->meshes; if (!init && p) { init = LIB3DS_TRUE; lib3ds_mesh_bounding_box(p, min, max); p = p->next; } while (p) { lib3ds_mesh_bounding_box(p, lmin, lmax); lib3ds_vector_min(min, lmin); lib3ds_vector_max(max, lmax); p=p->next; } } { Lib3dsCamera *p=file->cameras; if (!init && p) { init = LIB3DS_TRUE; lib3ds_vector_copy(min, p->position); lib3ds_vector_copy(max, p->position); } while (p) { lib3ds_vector_min(min, p->position); lib3ds_vector_max(max, p->position); lib3ds_vector_min(min, p->target); lib3ds_vector_max(max, p->target); p=p->next; } } { Lib3dsLight *p=file->lights; if (!init && p) { init = LIB3DS_TRUE; lib3ds_vector_copy(min, p->position); lib3ds_vector_copy(max, p->position); } while (p) { lib3ds_vector_min(min, p->position); lib3ds_vector_max(max, p->position); if (p->spot_light) { lib3ds_vector_min(min, p->spot); lib3ds_vector_max(max, p->spot); } p=p->next; } } }
static void rib_lights(FILE *o, Lib3dsFile *f, Lib3dsMatrix M) { Lib3dsLight *light; Lib3dsNode *l; Lib3dsNode *s; int i=1; for (light=f->lights; light; light=light->next) { l=lib3ds_file_node_by_name(f, light->name, LIB3DS_LIGHT_NODE); s=lib3ds_file_node_by_name(f, light->name, LIB3DS_SPOT_NODE); if (!l) { fprintf(stderr, "***ERROR*** Invalid light!\n"); exit(1); } if (s) { Lib3dsVector pos,spot; lib3ds_vector_copy(pos, l->data.light.pos); lib3ds_vector_copy(spot, s->data.spot.pos); fprintf(o, "LightSource " "\"lib3dslight\" " "%d " "\"string lighttype\" [\"spot\"] " "\"point from\" [%f %f %f] " "\"point to\" [%f %f %f]\n", i, pos[0], pos[1], pos[2], spot[0], spot[1], spot[2] ); } else { Lib3dsVector pos; lib3ds_vector_copy(pos, l->data.light.pos); fprintf(o, "LightSource " "\"pointlight\" " "%d " "\"from\" [%f %f %f]\n", i, pos[0], pos[1], pos[2] ); } fprintf(o, "Illuminate %d 1\n", i); ++i; } }
/*! * \ingroup tracks */ void lib3ds_lin3_track_eval(Lib3dsLin3Track *track, Lib3dsVector p, Lib3dsFloat t) { Lib3dsLin3Key *k; Lib3dsFloat nt; Lib3dsFloat u; if (!track->keyL) { lib3ds_vector_zero(p); return; } if (!track->keyL->next) { lib3ds_vector_copy(p, track->keyL->value); return; } for (k=track->keyL; k->next!=0; k=k->next) { if ((t>=(Lib3dsFloat)k->tcb.frame) && (t<(Lib3dsFloat)k->next->tcb.frame)) { break; } } if (!k->next) { if (track->flags&LIB3DS_REPEAT) { nt=(Lib3dsFloat)fmod(t, k->tcb.frame); for (k=track->keyL; k->next!=0; k=k->next) { if ((nt>=(Lib3dsFloat)k->tcb.frame) && (nt<(Lib3dsFloat)k->next->tcb.frame)) { break; } } ASSERT(k->next); } else { lib3ds_vector_copy(p, k->value); return; } } else { nt=t; } u=nt - (Lib3dsFloat)k->tcb.frame; u/=(Lib3dsFloat)(k->next->tcb.frame - k->tcb.frame); lib3ds_vector_cubic( p, k->value, k->dd, k->next->ds, k->next->value, u ); }
static void mesh_dump(Lib3dsMesh *mesh) { int i; float p[3]; assert(mesh); printf(" %s vertices=%ld faces=%ld\n", mesh->name, mesh->nvertices, mesh->nfaces); printf(" matrix:\n"); matrix_dump(mesh->matrix); printf(" vertices (x, y, z, u, v):\n"); for (i = 0; i < mesh->nvertices; ++i) { lib3ds_vector_copy(p, mesh->vertices[i]); printf(" %10.5f %10.5f %10.5f", p[0], p[1], p[2]); if (mesh->texcos) { printf("%10.5f %10.5f", mesh->texcos[i][0], mesh->texcos[i][1]); } printf("\n"); } printf(" facelist:\n"); for (i = 0; i < mesh->nfaces; ++i) { printf(" %4d %4d %4d flags:%X smoothing:%X material:\"%d\"\n", mesh->faces[i].index[0], mesh->faces[i].index[1], mesh->faces[i].index[2], mesh->faces[i].flags, mesh->faces[i].smoothing_group, mesh->faces[i].material ); } }
/*! * This function prints data associated with the specified mesh such as * vertex and point lists. * * \param mesh Points to a mesh that you wish to view the data for. * * \return None * * \warning WIN32: Should only be used in a console window not in a GUI. * * \ingroup mesh */ void lib3ds_mesh_dump(Lib3dsMesh *mesh) { unsigned i; Lib3dsVector p; ASSERT(mesh); printf(" %s vertices=%ld faces=%ld\n", mesh->name, (long int)mesh->points, (long int)mesh->faces ); printf(" matrix:\n"); lib3ds_matrix_dump(mesh->matrix); printf(" point list:\n"); for (i=0; i<mesh->points; ++i) { lib3ds_vector_copy(p, mesh->pointL[i].pos); printf (" %8f %8f %8f\n", p[0], p[1], p[2]); } printf(" facelist:\n"); for (i=0; i<mesh->faces; ++i) { printf (" %4d %4d %4d smoothing:%X flags:%X material:\"%s\"\n", mesh->faceL[i].points[0], mesh->faceL[i].points[1], mesh->faceL[i].points[2], (unsigned)mesh->faceL[i].smoothing, mesh->faceL[i].flags, mesh->faceL[i].material ); } }
Lib3dsOmnilightNode* lib3ds_node_new_omnilight(Lib3dsLight *light) { Lib3dsNode *node; Lib3dsOmnilightNode *n; assert(light); node = lib3ds_node_new(LIB3DS_NODE_OMNILIGHT); strcpy(node->name, light->name); n = (Lib3dsOmnilightNode*)node; lib3ds_track_resize(&n->pos_track, 1); lib3ds_vector_copy(n->pos_track.keys[0].value, light->position); lib3ds_track_resize(&n->color_track, 1); lib3ds_vector_copy(n->color_track.keys[0].value, light->color); return n; }
/*! * \ingroup tracks */ void lib3ds_lin3_key_setup(Lib3dsLin3Key *p, Lib3dsLin3Key *cp, Lib3dsLin3Key *c, Lib3dsLin3Key *cn, Lib3dsLin3Key *n) { Lib3dsVector np,nn; Lib3dsFloat ksm,ksp,kdm,kdp; int i; ASSERT(c); if (!cp) { cp=c; } if (!cn) { cn=c; } if (!p && !n) { lib3ds_vector_zero(c->ds); lib3ds_vector_zero(c->dd); return; } if (n && p) { lib3ds_tcb(&p->tcb, &cp->tcb, &c->tcb, &cn->tcb, &n->tcb, &ksm, &ksp, &kdm, &kdp); lib3ds_vector_sub(np, c->value, p->value); lib3ds_vector_sub(nn, n->value, c->value); for(i=0; i<3; ++i) { c->ds[i]=ksm*np[i] + ksp*nn[i]; c->dd[i]=kdm*np[i] + kdp*nn[i]; } } else { if (p) { lib3ds_vector_sub(np, c->value, p->value); lib3ds_vector_copy(c->ds, np); lib3ds_vector_copy(c->dd, np); } if (n) { lib3ds_vector_sub(nn, n->value, c->value); lib3ds_vector_copy(c->ds, nn); lib3ds_vector_copy(c->dd, nn); } } }
Lib3dsMeshInstanceNode* lib3ds_node_new_mesh_instance(Lib3dsMesh *mesh, const char *instance_name, float pos0[3], float scl0[3], float rot0[4]) { Lib3dsNode *node; Lib3dsMeshInstanceNode *n; int i; node = lib3ds_node_new(LIB3DS_NODE_MESH_INSTANCE); if (mesh) { strcpy(node->name, mesh->name); } else { strcpy(node->name, "$$$DUMMY"); } n = (Lib3dsMeshInstanceNode*)node; if (instance_name) { strcpy(n->instance_name, instance_name); } lib3ds_track_resize(&n->pos_track, 1); if (pos0) { lib3ds_vector_copy(n->pos_track.keys[0].value, pos0); } lib3ds_track_resize(&n->scl_track, 1); if (scl0) { lib3ds_vector_copy(n->scl_track.keys[0].value, scl0); } else { lib3ds_vector_make(n->scl_track.keys[0].value, 1, 1, 1); } lib3ds_track_resize(&n->rot_track, 1); if (rot0) { for (i = 0; i < 4; ++i) n->rot_track.keys[0].value[i] = rot0[i]; } else { for (i = 0; i < 4; ++i) n->rot_track.keys[0].value[i] = 0; } return n; }
Lib3dsTargetNode* lib3ds_node_new_spotligf_target(Lib3dsLight *light) { Lib3dsNode *node; Lib3dsTargetNode *n; assert(light); node = lib3ds_node_new(LIB3DS_NODE_SPOTLIGHT_TARGET); strcpy(node->name, light->name); n = (Lib3dsTargetNode*)node; lib3ds_track_resize(&n->pos_track, 1); lib3ds_vector_copy(n->pos_track.keys[0].value, light->target); return n; }
Lib3dsTargetNode* lib3ds_node_new_camera_target(Lib3dsCamera *camera) { Lib3dsNode *node; Lib3dsTargetNode *n; assert(camera); node = lib3ds_node_new(LIB3DS_NODE_CAMERA_TARGET); strcpy(node->name, camera->name); n = (Lib3dsTargetNode*)node; lib3ds_track_resize(&n->pos_track, 1); lib3ds_vector_copy(n->pos_track.keys[0].value, camera->target); return n; }
Lib3dsAmbientColorNode* lib3ds_node_new_ambient_color(float color0[3]) { Lib3dsNode *node; Lib3dsAmbientColorNode *n; node = lib3ds_node_new(LIB3DS_NODE_AMBIENT_COLOR); n = (Lib3dsAmbientColorNode*)node; lib3ds_track_resize(&n->color_track, 1); if (color0) { lib3ds_vector_copy(n->color_track.keys[0].value, color0); } else { lib3ds_vector_zero(n->color_track.keys[0].value); } return n; }
Lib3dsCameraNode* lib3ds_node_new_camera(Lib3dsCamera *camera) { Lib3dsNode *node; Lib3dsCameraNode *n; assert(camera); node = lib3ds_node_new(LIB3DS_NODE_CAMERA); strcpy(node->name, camera->name); n = (Lib3dsCameraNode*)node; lib3ds_track_resize(&n->pos_track, 1); lib3ds_vector_copy(n->pos_track.keys[0].value, camera->position); lib3ds_track_resize(&n->fov_track, 1); n->fov_track.keys[0].value[0] = camera->fov; lib3ds_track_resize(&n->roll_track, 1); n->roll_track.keys[0].value[0] = camera->roll; return n; }
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); }
/*! * \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); }
void dump_wzm_file(Lib3dsFile *f, FILE *ctl, bool swapYZ, bool invertUV, bool reverseWinding, unsigned int baseTexFlags, float scaleFactor) { Lib3dsMesh *m; Lib3dsMaterial *material; int meshIdx, j; fprintf(ctl, "WZM 1\n"); for (j = 0, material = f->materials; material; material = material->next, j++) { Lib3dsTextureMap *texture = &material->texture1_map; resToLower(texture->name); if (j > 0) { fprintf(stderr, "Texture %d %s: More than one texture currently not supported!\n", j, texture->name); continue; } fprintf(ctl, "TEXTURE %s\n", texture->name); } for (j = 0, m = f->meshes; m; m = m->next, j++); fprintf(ctl, "MESHES %d\n", j); for (meshIdx = 0, m = f->meshes; m; m = m->next, meshIdx++) { unsigned int i; fprintf(ctl, "MESH %d\n", meshIdx); fprintf(ctl, "TEAMCOLOURS 0\n"); fprintf(ctl, "VERTICES %d\n", m->points); fprintf(ctl, "FACES %d\n", m->faces); fprintf(ctl, "VERTEXARRAY\n"); for (i = 0; i < m->points; i++) { Lib3dsVector pos; lib3ds_vector_copy(pos, m->pointL[i].pos); if (swapYZ) { fprintf(ctl, "\t%f %f %f\n", pos[0] * scaleFactor, pos[2] * scaleFactor, pos[1] * scaleFactor); } else { fprintf(ctl, "\t%f %f %f\n", pos[0] * scaleFactor, pos[1] * scaleFactor, pos[2] * scaleFactor); } } fprintf(ctl, "TEXTUREARRAYS 1\n"); fprintf(ctl, "TEXTUREARRAY 0\n"); for (i = 0; i < m->points; i++) { if (invertUV) { fprintf(ctl, "\t%f %f\n", m->texelL[i][0], 1.0f - m->texelL[i][1]); } else { fprintf(ctl, "\t%f %f\n", m->texelL[i][0], m->texelL[i][1]); } } fprintf(ctl, "INDEXARRAY\n"); for (i = 0; i < m->faces; ++i) { Lib3dsFace *face = &m->faceL[i]; if (reverseWinding) { fprintf(ctl, "\t%d %d %d\n", (int)face->points[2], (int)face->points[1], (int)face->points[0]); } else { fprintf(ctl, "\t%d %d %d\n", (int)face->points[0], (int)face->points[1], (int)face->points[2]); } } fprintf(ctl, "FRAMES 0\n"); fprintf(ctl, "CONNECTORS 0\n"); } }
/*! * Calculates the vertex normals corresponding to the smoothing group * settings for each face of a mesh. * * \param mesh A pointer to the mesh to calculate the normals for. * \param normalL A pointer to a buffer to store the calculated * normals. The buffer must have the size: * 3*sizeof(Lib3dsVector)*mesh->faces. * * To allocate the normal buffer do for example the following: * \code * Lib3dsVector *normalL = malloc(3*sizeof(Lib3dsVector)*mesh->faces); * \endcode * * To access the normal of the i-th vertex of the j-th face do the * following: * \code * normalL[3*j+i] * \endcode * * \ingroup mesh */ void lib3ds_mesh_calculate_normals(Lib3dsMesh *mesh, Lib3dsVector *normalL) { Lib3dsFaces **fl; Lib3dsFaces *fa; unsigned i,j,k; if (!mesh->faces) { return; } fl=calloc(sizeof(Lib3dsFaces*),mesh->points); ASSERT(fl); fa=calloc(sizeof(Lib3dsFaces),3*mesh->faces); ASSERT(fa); k=0; for (i=0; i<mesh->faces; ++i) { Lib3dsFace *f=&mesh->faceL[i]; for (j=0; j<3; ++j) { Lib3dsFaces* l=&fa[k++]; ASSERT(f->points[j]<mesh->points); l->face=f; l->next=fl[f->points[j]]; fl[f->points[j]]=l; } } for (i=0; i<mesh->faces; ++i) { Lib3dsFace *f=&mesh->faceL[i]; for (j=0; j<3; ++j) { // FIXME: static array needs at least check!! Lib3dsVector n,N[128]; Lib3dsFaces *p; int k,l; int found; ASSERT(f->points[j]<mesh->points); if (f->smoothing) { lib3ds_vector_zero(n); k=0; for (p=fl[f->points[j]]; p; p=p->next) { found=0; for (l=0; l<k; ++l) { if( l >= 128 ) printf("array N overflow: i=%d, j=%d, k=%d\n", i,j,k); if (fabs(lib3ds_vector_dot(N[l], p->face->normal)-1.0)<1e-5) { found=1; break; } } if (!found) { if (f->smoothing & p->face->smoothing) { lib3ds_vector_add(n,n, p->face->normal); lib3ds_vector_copy(N[k], p->face->normal); ++k; } } } } else { lib3ds_vector_copy(n, f->normal); } lib3ds_vector_normalize(n); lib3ds_vector_copy(normalL[3*i+j], n); } } free(fa); free(fl); }
int main(int argc, char **argv) { Lib3dsFile *file = lib3ds_file_new(); file->frames = 360; { Lib3dsMaterial *mat = lib3ds_material_new("c_tex"); lib3ds_file_insert_material(file, mat, -1); strcpy(mat->texture1_map.name, "cube.tga"); mat->texture1_map.percent = 1.0; mat = lib3ds_material_new("c_red"); lib3ds_file_insert_material(file, mat, -1); mat->diffuse[0] = 1.0; mat->diffuse[1] = 0.0; mat->diffuse[2] = 0.0; mat = lib3ds_material_new("c_blue"); lib3ds_file_insert_material(file, mat, -1); mat->diffuse[0] = 0.0; mat->diffuse[1] = 0.0; mat->diffuse[2] = 1.0; } { int i, j; Lib3dsMesh *mesh = lib3ds_mesh_new("cube"); Lib3dsMeshInstanceNode *inst; lib3ds_file_insert_mesh(file, mesh, -1); lib3ds_mesh_resize_vertices(mesh, 8, 1, 0); for (i = 0; i < 8; ++i) { lib3ds_vector_copy(mesh->vertices[i], g_vertices[i]); mesh->texcos[i][0] = g_texcoords[i][0]; mesh->texcos[i][1] = g_texcoords[i][1]; } lib3ds_mesh_resize_faces(mesh, 12); for (i = 0; i < 12; ++i) { for (j = 0; j < 3; ++j) { mesh->faces[i].index[j] = g_indices[i][j]; } } for (i = 0; i < 8; ++i) { mesh->faces[i].material = 0; } for (i = 0; i < 2; ++i) { mesh->faces[8+i].material = 1; } for (i = 0; i < 2; ++i) { mesh->faces[10+i].material = 2; } inst = lib3ds_node_new_mesh_instance(mesh, "01", NULL, NULL, NULL); lib3ds_file_append_node(file, (Lib3dsNode*)inst, NULL); } { Lib3dsCamera *camera; Lib3dsCameraNode *n; Lib3dsTargetNode *t; int i; camera = lib3ds_camera_new("camera01"); lib3ds_file_insert_camera(file, camera, -1); lib3ds_vector_make(camera->position, 0.0, -100, 0.0); lib3ds_vector_make(camera->target, 0.0, 0.0, 0.0); n = lib3ds_node_new_camera(camera); t = lib3ds_node_new_camera_target(camera); lib3ds_file_append_node(file, (Lib3dsNode*)n, NULL); lib3ds_file_append_node(file, (Lib3dsNode*)t, NULL); lib3ds_track_resize(&n->pos_track, 37); for (i = 0; i <= 36; i++) { n->pos_track.keys[i].frame = 10 * i; lib3ds_vector_make(n->pos_track.keys[i].value, (float)(100.0 * cos(2 * M_PI * i / 36.0)), (float)(100.0 * sin(2 * M_PI * i / 36.0)), 50.0 ); } } if (!lib3ds_file_save(file, "cube.3ds")) { fprintf(stderr, "ERROR: Saving 3ds file failed!\n"); } lib3ds_file_free(file); }
static void dump_to_3ds(Lib3dsFile *f, FILE *fp) { Lib3dsMesh *m = lib3ds_mesh_new("Warzone Mesh"); Lib3dsMaterial *material = lib3ds_material_new("Warzone texture"); Lib3dsTextureMap *texture = &material->texture1_map; int i, num, x, y, levels; char s[200]; num = fscanf(fp, "PIE %d\n", &i); if (num != 1) { fprintf(stderr, "Bad PIE file %s\n", input); exit(1); } fprintf(stdout, "PIE version %d\n", i); num = fscanf(fp, "TYPE %d\n", &i); // ignore if (num != 1) { fprintf(stderr, "Bad TYPE directive in %s\n", input); exit(1); } num = fscanf(fp, "TEXTURE %d %s %d %d\n", &i, s, &x, &y); if (num != 4) { fprintf(stderr, "Bad TEXTURE directive in %s\n", input); exit(1); } strcpy(texture->name, s); num = fscanf(fp, "LEVELS %d\n", &levels); if (num != 1) { fprintf(stderr, "Bad LEVELS directive in %s\n", input); exit(1); } f->frames = levels; f->meshes = m; f->materials = material; for (i = 0; i < levels; i++) { int j, points, faces, faces3DS, faceCount, points3DS, pointCount; WZ_FACE *faceList; WZ_POSITION *posList; num = fscanf(fp, "LEVEL %d\n", &x); if (num != 1 || (i + 1) != x) { fprintf(stderr, "Bad LEVEL directive in %s, was %d should be %d\n", input, x, i + 1); exit(1); } num = fscanf(fp, "POINTS %d\n", &points); if (num != 1) { fprintf(stderr, "Bad POINTS directive in %s frame %d\n", input, i); exit(1); } posList = malloc(sizeof(WZ_POSITION) * points); for (j = 0; j < points; j++) { if (swapYZ) { num = fscanf(fp, "%d %d %d\n", &posList[j].x, &posList[j].z, &posList[j].y); } else { num = fscanf(fp, "%d %d %d\n", &posList[j].x, &posList[j].y, &posList[j].z); } if (num != 3) { fprintf(stderr, "Bad POINTS entry frame %d, number %d\n", i, j); exit(1); } } num = fscanf(fp, "POLYGONS %d", &faces); if (num != 1) { fprintf(stderr, "Bad POLYGONS directive in %s frame %d\n", input, i); exit(1); } faces3DS = faces; // for starters faceList = malloc(sizeof(WZ_FACE) * faces); points3DS = 0; for (j = 0; j < faces; ++j) { int k; unsigned int flags; num = fscanf(fp, "\n%x", &flags); if (num != 1) { fprintf(stderr, "Bad POLYGONS texture flag entry frame %d, number %d\n", i, j); exit(1); } if (!(flags & iV_IMD_TEX)) { fprintf(stderr, "Bad texture flag entry frame %d, number %d - no texture flag!\n", i, j); exit(1); } num = fscanf(fp, "%d", &faceList[j].vertices); if (num != 1) { fprintf(stderr, "Bad POLYGONS vertices entry frame %d, number %d\n", i, j); exit(1); } assert(faceList[j].vertices <= MAX_POLYGON_SIZE); // larger polygons not supported assert(faceList[j].vertices >= 3); // points and lines not supported if (faceList[j].vertices > 3) { // since they are triangle fans already, we get to do easy tessellation faces3DS += (faceList[j].vertices - 3); } points3DS += faceList[j].vertices; // Read in vertex indices and texture coordinates for (k = 0; k < faceList[j].vertices; k++) { num = fscanf(fp, "%d", &faceList[j].index[k]); if (num != 1) { fprintf(stderr, "Bad vertex position entry frame %d, number %d\n", i, j); exit(1); } } if (flags & iV_IMD_TEXANIM) { // read in and discard animation values for now int frames, rate, width, height; num = fscanf(fp, "%d %d %d %d", &frames, &rate, &width, &height); if (num != 4) { fprintf(stderr, "Bad texture animation entry frame %d, number %d\n", i, j); exit(1); } } for (k = 0; k < faceList[j].vertices; k++) { num = fscanf(fp, "%d %d", &faceList[j].texCoord[k][0], &faceList[j].texCoord[k][1]); if (num != 2) { fprintf(stderr, "Bad texture coordinate entry frame %d, number %d\n", i, j); exit(1); } } } // Calculate position list. Since positions hold texture coordinates in 3DS, unlike in Warzone, // we need to use some black magic to transfer them over here. lib3ds_mesh_new_point_list(m, points3DS); lib3ds_mesh_new_texel_list(m, points3DS); pointCount = 0; for (j = 0; j < faces; j++) { int k; for (k = 0; k < faceList[j].vertices; k++) { Lib3dsVector pos; pos[0] = posList[faceList[j].index[k]].x; pos[1] = posList[faceList[j].index[k]].y; pos[2] = posList[faceList[j].index[k]].z; lib3ds_vector_copy(m->pointL[pointCount].pos, pos); faceList[j].index[k] = pointCount; // use new position list if (invertUV) { m->texelL[pointCount][0] = ((float)faceList[j].texCoord[k][0] / 256.0f); m->texelL[pointCount][1] = 1.0f - ((float)faceList[j].texCoord[k][1] / 256.0f); } else { m->texelL[pointCount][0] = ((float)faceList[j].texCoord[k][0] / 256.0f); m->texelL[pointCount][1] = ((float)faceList[j].texCoord[k][1] / 256.0f); } pointCount++; } } lib3ds_mesh_new_face_list(m, faces3DS); faceCount = 0; // TODO reverse winding afterwards for (j = 0; j < faces; j++) { int k, key, previous; key = m->faceL[faceCount].points[0] = faceList[j].index[0]; m->faceL[faceCount].points[1] = faceList[j].index[1]; previous = m->faceL[faceCount].points[2] = faceList[j].index[2]; faceCount++; // Generate triangles from the Warzone triangle fans (PIEs, get it?) for (k = 3; k < faceList[j].vertices; k++) { m->faceL[faceCount].points[0] = key; m->faceL[faceCount].points[1] = previous; previous = m->faceL[faceCount].points[0] = faceList[j].index[k]; } // Since texture coordinates are properties of positions, not indices, // we do not need a similar expansion of these } free(faceList); free(posList); } if (!lib3ds_file_save(f, output)) { fprintf(stderr, "Cannot open \"%s\" for writing: %s", output, strerror(errno)); exit(1); } }
/*! * Render node recursively, first children, then parent. * Each node receives its own OpenGL display list. */ static void render_node(Lib3dsNode *node) { assert(file); { Lib3dsNode *p; for (p = node->childs; p != 0; p = p->next) { render_node(p); } } if (node->type == LIB3DS_NODE_MESH_INSTANCE) { int index; Lib3dsMesh *mesh; Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node; if (strcmp(node->name, "$$$DUMMY") == 0) { return; } 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) { return; } mesh = file->meshes[index]; if (!mesh->user_id) { assert(mesh); mesh->user_id = glGenLists(1); glNewList(mesh->user_id, GL_COMPILE); { int p; float (*normalL)[3] = (float(*)[3])malloc(3 * 3 * sizeof(float) * mesh->nfaces); Lib3dsMaterial *oldmat = (Lib3dsMaterial *) - 1; { float M[4][4]; lib3ds_matrix_copy(M, mesh->matrix); lib3ds_matrix_inv(M); glMultMatrixf(&M[0][0]); } lib3ds_mesh_calculate_vertex_normals(mesh, normalL); for (p = 0; p < mesh->nfaces; ++p) { Lib3dsMaterial *mat = 0; #ifdef USE_SDL Player_texture *pt = NULL; int tex_mode = 0; #endif if (mesh->faces[p].material > 0) { mat = file->materials[mesh->faces[p].material]; } if (mat != oldmat) { if (mat) { if (mat->two_sided) glDisable(GL_CULL_FACE); else glEnable(GL_CULL_FACE); glDisable(GL_CULL_FACE); /* Texturing added by Gernot < *****@*****.** > */ if (mat->texture1_map.name[0]) { /* texture map? */ Lib3dsTextureMap *tex = &mat->texture1_map; if (!tex->user_ptr) { /* no player texture yet? */ char texname[1024]; pt = (Player_texture*)malloc(sizeof(*pt)); tex->user_ptr = pt; //snprintf(texname, sizeof(texname), "%s/%s", datapath, tex->name); strcpy(texname, datapath); strcat(texname, "/"); strcat(texname, tex->name); #ifdef DEBUG printf("Loading texture map, name %s\n", texname); #endif /* DEBUG */ #ifdef USE_SDL #ifdef USE_SDL_IMG_load pt->bitmap = IMG_load(texname); #else pt->bitmap = IMG_Load(texname); #endif /* IMG_Load */ #else /* USE_SDL */ pt->bitmap = NULL; fputs("3dsplayer: Warning: No image loading support, skipping texture.\n", stderr); #endif /* USE_SDL */ if (pt->bitmap) { /* could image be loaded ? */ /* this OpenGL texupload code is incomplete format-wise! * to make it complete, examine SDL_surface->format and * tell us @lib3ds.sf.net about your improvements :-) */ int upload_format = GL_RED; /* safe choice, shows errors */ #ifdef USE_SDL int bytespp = pt->bitmap->format->BytesPerPixel; void *pixel = NULL; glGenTextures(1, &pt->tex_id); #ifdef DEBUG printf("Uploading texture to OpenGL, id %d, at %d bytepp\n", pt->tex_id, bytespp); #endif /* DEBUG */ if (pt->bitmap->format->palette) { pixel = convert_to_RGB_Surface(pt->bitmap); upload_format = GL_RGBA; } else { pixel = pt->bitmap->pixels; /* e.g. this could also be a color palette */ if (bytespp == 1) upload_format = GL_LUMINANCE; else if (bytespp == 3) upload_format = GL_RGB; else if (bytespp == 4) upload_format = GL_RGBA; } glBindTexture(GL_TEXTURE_2D, pt->tex_id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_XSIZE, TEX_YSIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, pt->bitmap->w, pt->bitmap->h, upload_format, GL_UNSIGNED_BYTE, pixel); pt->scale_x = (float)pt->bitmap->w / (float)TEX_XSIZE; pt->scale_y = (float)pt->bitmap->h / (float)TEX_YSIZE; #endif /* USE_SDL */ pt->valid = 1; } else { fprintf(stderr, "Load of texture %s did not succeed " "(format not supported !)\n", texname); pt->valid = 0; } } else { pt = (Player_texture *)tex->user_ptr; } tex_mode = pt->valid; } else { tex_mode = 0; } { float a[4], d[4], s[4]; int i; for (i=0; i<3; ++i) { a[i] = mat->ambient[i]; d[i] = mat->diffuse[i]; s[i] = mat->specular[i]; } a[3] = d[3] = s[3] = 1.0f; glMaterialfv(GL_FRONT, GL_AMBIENT, a); glMaterialfv(GL_FRONT, GL_DIFFUSE, d); glMaterialfv(GL_FRONT, GL_SPECULAR, s); } glMaterialf(GL_FRONT, GL_SHININESS, pow(2, 10.0*mat->shininess)); } else { static const float a[4] = {0.7, 0.7, 0.7, 1.0}; static const float d[4] = {0.7, 0.7, 0.7, 1.0}; static const float s[4] = {1.0, 1.0, 1.0, 1.0}; glMaterialfv(GL_FRONT, GL_AMBIENT, a); glMaterialfv(GL_FRONT, GL_DIFFUSE, d); glMaterialfv(GL_FRONT, GL_SPECULAR, s); glMaterialf(GL_FRONT, GL_SHININESS, pow(2, 10.0*0.5)); } oldmat = mat; } else if (mat != NULL && mat->texture1_map.name[0]) { Lib3dsTextureMap *tex = &mat->texture1_map; if (tex != NULL && tex->user_ptr != NULL) { pt = (Player_texture *)tex->user_ptr; tex_mode = pt->valid; } } { int i; #ifndef USE_GL10 if (tex_mode) { //printf("Binding texture %d\n", pt->tex_id); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, pt->tex_id); } #endif #if 0 { float v1[3], n[3], v2[3]; glBegin(GL_LINES); for (i = 0; i < 3; ++i) { lib3ds_vector_copy(v1, mesh->vertices[f->points[i]]); glVertex3fv(v1); lib3ds_vector_copy(n, normalL[3*p+i]); lib3ds_vector_scalar(n, 10.f); lib3ds_vector_add(v2, v1, n); glVertex3fv(v2); } glEnd(); } #endif glBegin(GL_TRIANGLES); for (i = 0; i < 3; ++i) { glNormal3fv(normalL[3*p+i]); if (tex_mode) { glTexCoord2f( mesh->texcos[mesh->faces[p].index[i]][1]*pt->scale_x, pt->scale_y - mesh->texcos[mesh->faces[p].index[i]][0]*pt->scale_y); } glVertex3fv(mesh->vertices[mesh->faces[p].index[i]]); } glEnd(); if (tex_mode) glDisable(GL_TEXTURE_2D); } } free(normalL); } glEndList(); } if (mesh->user_id) { glPushMatrix(); glMultMatrixf(&node->matrix[0][0]); glTranslatef(-n->pivot[0], -n->pivot[1], -n->pivot[2]); glCallList(mesh->user_id); /* glutSolidSphere(50.0, 20,20); */ glPopMatrix(); if (flush) glFlush(); } } }
/*! * Calculates the vertex normals corresponding to the smoothing group * settings for each face of a mesh. * * \param mesh A pointer to the mesh to calculate the normals for. * \param normals A pointer to a buffer to store the calculated * normals. The buffer must have the size: * 3*3*sizeof(float)*mesh->nfaces. * * To allocate the normal buffer do for example the following: * \code * Lib3dsVector *normals = malloc(3*3*sizeof(float)*mesh->nfaces); * \endcode * * To access the normal of the i-th vertex of the j-th face do the * following: * \code * normals[3*j+i] * \endcode */ void lib3ds_mesh_calculate_vertex_normals(Lib3dsMesh *mesh, float (*normals)[3]) { Lib3dsFaces **fl; Lib3dsFaces *fa; int i, j; if (!mesh->nfaces) { return; } fl = (Lib3dsFaces**)calloc(sizeof(Lib3dsFaces*), mesh->nvertices); fa = (Lib3dsFaces*)malloc(sizeof(Lib3dsFaces) * 3 * mesh->nfaces); for (i = 0; i < mesh->nfaces; ++i) { for (j = 0; j < 3; ++j) { Lib3dsFaces* l = &fa[3*i+j]; float p[3], q[3], n[3]; float len, weight; l->index = i; l->next = fl[mesh->faces[i].index[j]]; fl[mesh->faces[i].index[j]] = l; lib3ds_vector_sub(p, mesh->vertices[mesh->faces[i].index[j<2? j + 1 : 0]], mesh->vertices[mesh->faces[i].index[j]]); lib3ds_vector_sub(q, mesh->vertices[mesh->faces[i].index[j>0? j - 1 : 2]], mesh->vertices[mesh->faces[i].index[j]]); lib3ds_vector_cross(n, p, q); len = lib3ds_vector_length(n); if (len > 0) { weight = (float)atan2(len, lib3ds_vector_dot(p, q)); lib3ds_vector_scalar_mul(l->normal, n, weight / len); } else { lib3ds_vector_zero(l->normal); } } } for (i = 0; i < mesh->nfaces; ++i) { Lib3dsFace *f = &mesh->faces[i]; for (j = 0; j < 3; ++j) { float n[3]; Lib3dsFaces *p; Lib3dsFace *pf; assert(mesh->faces[i].index[j] < mesh->nvertices); if (f->smoothing_group) { unsigned smoothing_group = f->smoothing_group; lib3ds_vector_zero(n); for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) { pf = &mesh->faces[p->index]; if (pf->smoothing_group & f->smoothing_group) smoothing_group |= pf->smoothing_group; } for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) { pf = &mesh->faces[p->index]; if (smoothing_group & pf->smoothing_group) { lib3ds_vector_add(n, n, p->normal); } } } else { lib3ds_vector_copy(n, fa[3*i+j].normal); } lib3ds_vector_normalize(n); lib3ds_vector_copy(normals[3*i+j], n); } } free(fa); free(fl); }
MODEL *QWzmViewer::load3DS(QString input) { const bool swapYZ = true; const bool reverseWinding = true; const bool invertUV = true; const float scaleFactor = 1.0f; Lib3dsFile *f = lib3ds_file_load(input.toAscii().constData()); Lib3dsMaterial *material = f->materials; int meshes = 0; Lib3dsMesh *m; int meshIdx; MODEL *psModel; if (!f) { qWarning("Loading 3DS file %s failed", input.toAscii().constData()); return NULL; } for (meshes = 0, m = f->meshes; m; m = m->next, meshes++) ; // count the meshes psModel = createModel(meshes, 0); if (!psModel) { qFatal("Out of memory"); } // Grab texture name for (int j = 0; material; material = material->next, j++) { Lib3dsTextureMap *texture = &material->texture1_map; QString texName(texture->name); if (j > 0) { qWarning("Texture %d %s: More than one texture currently not supported!", j, texture->name); continue; } strcpy(psModel->texPath, texName.toLower().toAscii().constData()); } // Grab each mesh for (meshIdx = 0, m = f->meshes; m; m = m->next, meshIdx++) { MESH *psMesh = &psModel->mesh[meshIdx]; psMesh->vertices = m->points; psMesh->faces = m->faces; psMesh->vertexArray = (GLfloat*)malloc(sizeof(GLfloat) * psMesh->vertices * 3); psMesh->indexArray = (GLuint*)malloc(sizeof(GLuint) * psMesh->faces * 3); psMesh->textureArrays = 1; // only one supported from 3DS psMesh->textureArray[0] = (GLfloat*)malloc(sizeof(GLfloat) * psMesh->vertices * 2); for (unsigned int i = 0; i < m->points; i++) { Lib3dsVector pos; lib3ds_vector_copy(pos, m->pointL[i].pos); if (swapYZ) { psMesh->vertexArray[i * 3 + 0] = pos[0] * scaleFactor; psMesh->vertexArray[i * 3 + 1] = pos[2] * scaleFactor; psMesh->vertexArray[i * 3 + 2] = pos[1] * scaleFactor; } else { psMesh->vertexArray[i * 3 + 0] = pos[0] * scaleFactor; psMesh->vertexArray[i * 3 + 1] = pos[1] * scaleFactor; psMesh->vertexArray[i * 3 + 2] = pos[2] * scaleFactor; } } for (unsigned int i = 0; i < m->points; i++) { GLfloat *v = &psMesh->textureArray[0][i * 2]; v[0] = m->texelL[i][0]; if (invertUV) { v[1] = 1.0f - m->texelL[i][1]; } else { v[1] = m->texelL[i][1]; } } for (unsigned int i = 0; i < m->faces; ++i) { Lib3dsFace *face = &m->faceL[i]; GLuint *v = &psMesh->indexArray[i * 3]; if (reverseWinding) { v[0] = face->points[2]; v[1] = face->points[1]; v[2] = face->points[0]; } else { v[0] = face->points[0]; v[1] = face->points[1]; v[2] = face->points[2]; } } } lib3ds_file_free(f); return psModel; }
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); }
// TODO: Build own exporter class void objectExporter::on_buttonBox_accepted() { QString fileName = QFileDialog::getSaveFileName(gloParent, "Save 3ds Object", ".", "3D Object (*.3ds)", 0, 0); QList<trackHandler*> trackList = gloParent->getTrackList(); trackHandler* curTrack = trackList[ui->trackBox->currentIndex()]; trackMesh* mesh = curTrack->mMesh; QVector<float> *vertices = new QVector<float>(); QVector<unsigned int> *indices = new QVector<unsigned int>(); QVector<unsigned int> *borders = new QVector<unsigned int>(); Lib3dsFile *file = lib3ds_file_new(); file->frames = 360; { Lib3dsMaterial* mat = lib3ds_material_new("coaster"); lib3ds_file_insert_material(file, mat, -1); mat->diffuse[0] = curTrack->trackColors[0].red()/255.f; mat->diffuse[1] = curTrack->trackColors[0].green()/255.f; mat->diffuse[2] = curTrack->trackColors[0].blue()/255.f; } { for(int section = 0; section < curTrack->trackData->lSections.size(); ++section) { vertices->clear(); indices->clear(); borders->clear(); mesh->build3ds(section, vertices, indices, borders); float* fvertices = new float[vertices->size()]; for(int i = 0; i < vertices->size()/3; ++i) { fvertices[3*i+0] = vertices->at(3*i+0); fvertices[3*i+1] = -vertices->at(3*i+2); fvertices[3*i+2] = vertices->at(3*i+1); //exportScreen->doFastExport(); } for(int subIndex = 0; subIndex < borders->size()-2; subIndex+= 2) { int fromVIndex = borders->at(subIndex)/3; int toVIndex = borders->at(subIndex+2)/3; int fromIIndex = borders->at(subIndex+1)/3; int toIIndex = borders->at(subIndex+3)/3; int i, j; QString name = QString::number(section).append(QString("_").append(QString::number(subIndex/2))); Lib3dsMesh *mesh = lib3ds_mesh_new(name.toLocal8Bit().data()); Lib3dsMeshInstanceNode *inst; lib3ds_file_insert_mesh(file, mesh, -1); lib3ds_mesh_resize_vertices(mesh, toVIndex-fromVIndex, 1, 0); for (i = 0; i < toVIndex-fromVIndex; ++i) { lib3ds_vector_copy(mesh->vertices[i], &fvertices[(i+fromVIndex)*3]); mesh->texcos[i][0] = 0.f; mesh->texcos[i][1] = 0.f; } lib3ds_mesh_resize_faces(mesh, toIIndex-fromIIndex); for (i = 0; i < toIIndex-fromIIndex; ++i) { for (j = 0; j < 3; ++j) { mesh->faces[i].index[j] = indices->at(3*(i+fromIIndex)+j)-fromVIndex; mesh->faces[i].material = 0; } } inst = lib3ds_node_new_mesh_instance(mesh, name.toLocal8Bit().data(), NULL, NULL, NULL); lib3ds_file_append_node(file, (Lib3dsNode*)inst, NULL); } delete[] fvertices; } } { Lib3dsCamera *camera; Lib3dsCameraNode *n; Lib3dsTargetNode *t; int i; camera = lib3ds_camera_new("camera01"); lib3ds_file_insert_camera(file, camera, -1); lib3ds_vector_make(camera->position, 0.0, -100, 0.0); lib3ds_vector_make(camera->target, 0.0, 0.0, 0.0); n = lib3ds_node_new_camera(camera); t = lib3ds_node_new_camera_target(camera); lib3ds_file_append_node(file, (Lib3dsNode*)n, NULL); lib3ds_file_append_node(file, (Lib3dsNode*)t, NULL); lib3ds_track_resize(&n->pos_track, 37); for (i = 0; i <= 36; i++) { n->pos_track.keys[i].frame = 10 * i; lib3ds_vector_make(n->pos_track.keys[i].value, (float)(100.0 * cos(2 * F_PI * i / 36.0)), (float)(100.0 * sin(2 * F_PI * i / 36.0)), 50.0 ); } } if (!lib3ds_file_save(file, fileName.toLocal8Bit().data())) { qDebug("ERROR: Saving 3ds file failed!\n"); } lib3ds_file_free(file); delete indices; delete vertices; }