/*! * \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); }
Lib3dsMesh* GLC_WorldTo3ds::create3dsMeshFromGLC_Mesh(GLC_Mesh* pMesh, const QString& meshName) { // Create empty 3ds mesh with the given name Lib3dsMesh* p3dsMesh= lib3ds_mesh_new(meshName.toLocal8Bit().data()); const int stride= 3; GLfloatVector vertice= pMesh->positionVector(); const uint pointsCount= vertice.count() / stride; // Add points to the 3DS mesh lib3ds_mesh_new_point_list(p3dsMesh, pointsCount); for (uint i= 0; i < pointsCount; ++i) { Lib3dsPoint point; point.pos[0]= vertice[i * 3]; point.pos[1]= vertice[i * 3 + 1]; point.pos[2]= vertice[i * 3 + 2]; p3dsMesh->pointL[i]= point; } // Add texel to the 3DS mesh GLfloatVector texelVector= pMesh->texelVector(); if(!texelVector.isEmpty()) { lib3ds_mesh_new_texel_list(p3dsMesh, pointsCount); for (uint i= 0; i < pointsCount; ++i) { p3dsMesh->texelL[i][0]= texelVector[i * 2]; p3dsMesh->texelL[i][1]= texelVector[i * 2 + 1]; } } // Add faces to the 3ds mesh const uint totalFaceCount= pMesh->faceCount(0); lib3ds_mesh_new_face_list(p3dsMesh, totalFaceCount); QSet<GLC_Material*> materialSet= pMesh->materialSet(); QSet<GLC_Material*>::iterator iMat= materialSet.begin(); uint currentFaceIndex= 0; while(iMat != materialSet.end()) { GLC_Material* pCurrentGLCMat= *iMat; Lib3dsMaterial* pMaterial= get3dsMaterialFromGLC_Material(pCurrentGLCMat); IndexList currentTriangleIndex= pMesh->getEquivalentTrianglesStripsFansIndex(0, pCurrentGLCMat->id()); const int faceCount= currentTriangleIndex.count() / 3; for (int i= 0; i < faceCount; ++i) { Lib3dsFace face; strcpy(face.material, pMaterial->name); face.points[0]= currentTriangleIndex.at(i * 3); face.points[1]= currentTriangleIndex.at(i * 3 + 1); face.points[2]= currentTriangleIndex.at(i * 3 + 2); p3dsMesh->faceL[currentFaceIndex++]= face; Q_ASSERT(currentFaceIndex <= totalFaceCount); } ++iMat; } return p3dsMesh; }
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); } }