// Saves the given mesh to the given file. void SaveMesh(const utf8_ntri &file, const Mesh &mesh, uint4 flags) { const MeshImpl &meshImpl = static_cast<const MeshImpl&>(mesh); lean::raw_file meshFile(file, lean::file::readwrite, lean::file::overwrite); // Mesh ChunkInfo meshChunk; BeginChunk(meshFile, beScene::MeshDataChunk::Header, meshChunk); // Mesh name { const aiNode &rootNode = *meshImpl.GetScene()->mRootNode; if (rootNode.mName.length > 0) meshChunk.Size += WriteStringChunk(meshFile, beScene::MeshDataChunk::Name, rootNode.mName.data, static_cast<uint4>(rootNode.mName.length)); } // Mesh subsets { meshChunk.Size += SaveSubsets(meshFile, *meshImpl.GetScene(), flags); } EndChunk(meshFile, meshChunk); }
/************* * DESCRIPTION: read a material-chunk * INPUT: pointer to chunk * OUTPUT: - *************/ static void ParsePropMat(HANDLER_DATA *data, CHUNK *mainchunk) { CHUNK chunk; SURFACE *surf; float perc; COLOR color, diffuse; char buf[80]; surf = data->link->SurfaceAdd(data->rc); if (!surf) { data->err = ERR_MEM; return; } do { BeginChunk(data, &chunk); switch (chunk.id) { case ID_PROPNAME: ReadASCIIZ(data, buf); if (!data->link->SurfaceName(data->rc, surf,buf)) { data->err = ERR_MEM; return; } break; case ID_AMBIENT: ParseColor(data, &color); data->link->SurfaceAmbient(data->rc, surf,color.r,color.g,color.b); break; case ID_DIFFUSE: ParseColor(data, &diffuse); data->link->SurfaceDiffuse(data->rc, surf,diffuse.r,diffuse.g,diffuse.b); break; case ID_SPECULAR: ParseColor(data, &color); data->link->SurfaceSpecular(data->rc, surf,color.r,color.g,color.b); break; case ID_SHININESS: perc = ParsePercentage(data); data->link->SurfaceRefPhong(data->rc, surf,perc*100.f); break; case ID_TRANSPARENCY: perc = ParsePercentage(data); data->link->SurfaceTranspar(data->rc, surf,perc*diffuse.r,perc*diffuse.g,perc*diffuse.b); break; } EndChunk(data, &chunk); } while (INCHUNK); }
/************* * DESCRIPTION: parse a 3DS file * INPUT: pointer to chunk * OUTPUT: - *************/ static void Parse3DS(HANDLER_DATA *data, CHUNK *mainchunk) { CHUNK chunk; do { BeginChunk(data, &chunk); switch (chunk.id) { case ID_MESHBLOCK: ParseMData(data, &chunk); break; } EndChunk(data, &chunk); if(data->SetProgress) data->SetProgress(data->rc, (float)ftell(data->hFile)/(float)data->filesize); } while (INCHUNK); }
/************* * DESCRIPTION: parse main data * INPUT: pointer to chunk * OUTPUT: - *************/ static void ParseMData(HANDLER_DATA *data, CHUNK *mainchunk) { CHUNK chunk; do { BeginChunk(data, &chunk); switch (chunk.id) { case ID_PROPMATENTRY: ParsePropMat(data, &chunk); break; case ID_OBJECTDESC: ParseNamedObject(data, &chunk); break; } EndChunk(data, &chunk); } while (INCHUNK); }
/************* * DESCRIPTION: read a percent value * INPUT: - * OUTPUT: float (0..1) *************/ static float ParsePercentage(HANDLER_DATA *data) { CHUNK chunk; float percent = 0.f; BeginChunk(data, &chunk); switch (chunk.id) { case ID_PERCENT100: ReadFloat(data, &percent, 1); percent*= 0.01f; break; case ID_PERCENT1: ReadChunkBytes(data, &percent, 1); break; } EndChunk(data, &chunk); return percent; }
/************* * DESCRIPTION: read an object consisting of * triangles * INPUT: pointer to chunk * OUTPUT: - *************/ static void ParseTriObject(HANDLER_DATA *data, CHUNK *mainchunk) { CHUNK chunk; do { BeginChunk(data, &chunk); switch (chunk.id) { case ID_POINTS: ParsePoints(data); break; case ID_FACES: ParseFaces(data, &chunk); break; case ID_MAPPINGCOORS: ParseMapping(data); break; case ID_TRANSMATRIX: ReadFloat(data, &data->transm[0], 12); data->transmatrix.m[0] = data->transm[0]; data->transmatrix.m[1] = data->transm[1]; data->transmatrix.m[2] = data->transm[2]; data->transmatrix.m[4] = data->transm[3]; data->transmatrix.m[5] = data->transm[4]; data->transmatrix.m[6] = data->transm[5]; data->transmatrix.m[8] = data->transm[6]; data->transmatrix.m[9] = data->transm[7]; data->transmatrix.m[10] = data->transm[8]; data->transmatrix.m[12] = data->transm[9]; data->transmatrix.m[13] = data->transm[10]; data->transmatrix.m[14] = data->transm[11]; break; } EndChunk(data, &chunk); } while (INCHUNK); }
/************* * DESCRIPTION: read a color * INPUT: color pointer to color * OUTPUT: - *************/ static void ParseColor(HANDLER_DATA *data, COLOR *color) { CHUNK chunk; UBYTE c[3]; BeginChunk(data, &chunk); switch (chunk.id) { case ID_COLOR1: ReadFloat(data, &color->r, 1); ReadFloat(data, &color->g, 1); ReadFloat(data, &color->b, 1); break; case ID_COLOR255: ReadChunkBytes(data, &c, 3); color->r = c[0]/255.0f; color->g = c[1]/255.0f; color->b = c[2]/255.0f; break; } EndChunk(data, &chunk); }
/************* * DESCRIPTION: read a 3DS-file * INPUT: rc context * filename name of 3DS-file * link link structure * pos object position * ox, oy, oz object orientation * actor pointer to actor * replacesurf surface to replace object surface with * version version of file * OUTPUT: NULL if ok, else error string *************/ extern "C" char* SAVEDS objRead(rsiCONTEXT *rc_, char* filename, OBJLINK *link_, const VECTOR *pos, const VECTOR *ox, const VECTOR *oy, const VECTOR *oz, const VECTOR *scale, ACTOR *actor, SURFACE *replacesurf, ULONG *version, void (*SetProgress)(rsiCONTEXT*, float)) { CHUNK chunk; HANDLER_DATA data; data.link = link_; data.rc = rc_; data.pointcount = 0; data.points = NULL; data.mapping = NULL; data.VertNorms = NULL; data.face = NULL; data.facecount = 0; data.material = NULL; data.defaultsurface = NULL; data.replacesurface = NULL; data.smooth_angle = 0.5235987f; data.TriNorms = NULL; data.TriSmooth = NULL; data.TriList = NULL; data.cos_smooth_angle = (float)cos(data.smooth_angle); data.mainactor = NULL; data.SetProgress = SetProgress; data.size_done = 0; data.transmatrix.IdentityMatrix(); data.matrix.SetSOTMatrix(scale, ox, oy, oz, pos); data.alignmatrix.SetOMatrix(ox, oy, oz); data.err = OK; data.hFile = Open3DS(filename); if (!data.hFile) { Cleanup3DS(&data); return errors[ERR_OPEN]; } BeginChunk(&data, &chunk); data.filesize = chunk.end; // test if 3ds file if (chunk.id != ID_PRIMARY) { Cleanup3DS(&data); return errors[ERR_NO3DS]; } data.mainactor = actor; data.replacesurface = replacesurf; Parse3DS(&data, &chunk); EndChunk(&data, &chunk); if(data.SetProgress) data.SetProgress(data.rc, (float)ftell(data.hFile)/(float)data.filesize); Cleanup3DS(&data); return errors[data.err]; }
/************* * DESCRIPTION: - * INPUT: pointer to chunk * OUTPUT: - *************/ static void ParseNamedObject(HANDLER_DATA *data, CHUNK *mainchunk) { CHUNK chunk; TRIANGLE *triangle; TRILIST *ph1,*ph2; float angle; UWORD p1, p2, p3; UWORD *edges; int i, h; ReadASCIIZ(data, data->ObjName); do { BeginChunk(data, &chunk); switch (chunk.id) { case ID_TRIANGLE: ParseTriObject(data, &chunk); break; } EndChunk(data, &chunk); } while (INCHUNK); if (data->TriList && (data->link->type == LINK_RENDERER)) { // go through all vertices and calculate normals (only for renderer) for (i = 0; i < data->pointcount; i++) { data->VertNorms[i].x = data->VertNorms[i].y = data->VertNorms[i].z = 0.f; ph1 = data->TriList[i]; while (ph1) { for (ph2 = ph1->next; ph2 != NULL; ph2 = ph2->next) { if (!ph1->flag || !ph2->flag) { // test angle between two triangles angle = VecAngle(data->TriNorms[ph1->tri], data->TriNorms[ph2->tri]); // if (angle < 2*PI && angle > /*cos_*/smooth_angle) if (angle >0 && angle < /*cos_*/data->smooth_angle) { if (!ph1->flag) { VecAdd(&data->VertNorms[i], &data->TriNorms[ph1->tri], &data->VertNorms[i]); ph1->flag = TRUE; data->TriSmooth[ph1->tri] = TRUE; } if (!ph2->flag) { VecAdd(&data->VertNorms[i], &data->TriNorms[ph2->tri], &data->VertNorms[i]); ph2->flag = TRUE; data->TriSmooth[ph2->tri] = TRUE; } } } } ph2 = ph1; ph1 = ph1->next; delete ph2; } VecNormalize(&data->VertNorms[i]); } } if (data->face) { data->link->ObjectBegin(data->rc); data->defaultsurface = data->link->SurfaceAdd(data->rc); if (!data->defaultsurface) { data->err = ERR_MEM; return; } data->link->SurfaceName(data->rc, data->defaultsurface, "default"); data->link->SurfaceDiffuse(data->rc, data->defaultsurface, 0.9f, 0.9f, 0.9f); data->link->SurfaceAmbient(data->rc, data->defaultsurface, 0.1f, 0.1f, 0.1f); data->link->SurfaceRefPhong(data->rc, data->defaultsurface, 49.f); triangle = data->link->TriangleAdd(data->rc, data->facecount,data->defaultsurface,data->mainactor); if (!triangle) { data->err = ERR_MEM; return; } if (data->link->type == LINK_SCENARIO) { // modeler needs points,edges and faces seperate if (data->link->TriangleAddPoints(data->rc, data->pointcount,data->points) == -1) { data->err = ERR_MEM; return; } edges = new UWORD[data->facecount*6]; if (!edges) { data->err = ERR_MEM; return; } for (i = 0; i < data->facecount; i++) { h = i*6; edges[h++] = data->face[i].p1; edges[h++] = data->face[i].p2; edges[h++] = data->face[i].p2; edges[h++] = data->face[i].p3; edges[h++] = data->face[i].p3; edges[h++] = data->face[i].p1; } if (data->link->TriangleAddEdges(data->rc, data->facecount*3,edges) == -1) { delete edges; data->err = ERR_MEM; return; } delete edges; } for (i = 0; i < data->facecount; i++) { p1 = data->face[i].p1; p2 = data->face[i].p3; p3 = data->face[i].p2; if(data->replacesurface) data->link->TriangleSurface(data->rc, triangle, data->replacesurface); else { if(!data->material[i]) data->link->TriangleSurface(data->rc, triangle, data->defaultsurface); else data->link->TriangleSurface(data->rc, triangle, data->material[i]); } if (data->link->type == LINK_SCENARIO) { // modeler needs edges data->link->TriangleSetEdges(data->rc, triangle,i*3,i*3+1,i*3+2); } else { // raystorm renderer needs triangles and normals data->link->TrianglePoints(data->rc, triangle,&data->points[p1],&data->points[p2],&data->points[p3]); if (!VecZero(data->TriNorms[i])) { // generate smooth triangle when smooth flag is set if (data->TriSmooth[i]) { data->link->TriangleVNorm(data->rc, triangle, VecZero(data->VertNorms[p1]) ? &data->TriNorms[i] : &data->VertNorms[p1], VecZero(data->VertNorms[p2]) ? &data->TriNorms[i] : &data->VertNorms[p2], VecZero(data->VertNorms[p3]) ? &data->TriNorms[i] : &data->VertNorms[p3]); } } if(data->mapping) { data->link->TriangleUV(data->rc, triangle, &data->mapping[p1], &data->mapping[p2], &data->mapping[p3]); } } // next triangle triangle = data->link->TriangleGetNext(data->rc, triangle); } data->link->ObjectEnd(data->rc); } CleanupMesh(data); }
/************* * DESCRIPTION: read faces of object * INPUT: pointer to chunk * OUTPUT: - *************/ static void ParseFaces(HANDLER_DATA *data, CHUNK *mainchunk) { CHUNK chunk; UWORD i, matcount, index, p1, p2, p3; VECTOR e1, e2; SURFACE *s; TRILIST *hp; char buf[80]; ReadWord(data, (WORD *)&data->facecount, 1); // read number of faces if (data->facecount == 0) return; data->face = new FACE3DS[data->facecount]; if (!data->face) { data->err = ERR_MEM; return; } if (!data->replacesurface) { data->material = (SURFACE **)malloc(sizeof(SURFACE *)*data->facecount); if (!data->material) { data->err = ERR_MEM; return; } } ReadWord(data, (WORD *)data->face, 4*data->facecount); // read faces if (data->link->type == LINK_RENDERER) { // do it for renderer only data->VertNorms = new VECTOR[data->pointcount]; if (!data->VertNorms) { data->err = ERR_MEM; return; } data->TriNorms = new VECTOR[data->facecount]; if (!data->TriNorms) { data->err = ERR_MEM; return; } memset(data->VertNorms, 0, sizeof(VECTOR)*data->pointcount); // Init normals data->TriSmooth = new UBYTE[data->facecount]; if (!data->TriSmooth) { data->err = ERR_MEM; return; } for (i = 0; i < data->facecount; i++) { if (data->replacesurface) data->material[i] = data->replacesurface; else data->material[i] = NULL; data->TriSmooth[i] = FALSE; // get three points for the triangle p1 = data->face[i].p1; p2 = data->face[i].p3; p3 = data->face[i].p2; hp = new TRILIST; if (!hp) { data->err = ERR_MEM; return; } hp->next = data->TriList[p1]; hp->tri = i; hp->flag = FALSE; data->TriList[p1] = hp; hp = new TRILIST; if (!hp) { data->err = ERR_MEM; return; } hp->next = data->TriList[p2]; hp->tri = i; hp->flag = FALSE; data->TriList[p2] = hp; hp = new TRILIST; if (!hp) { data->err = ERR_MEM; return; } hp->next = data->TriList[p3]; hp->tri = i; hp->flag = FALSE; data->TriList[p3] = hp; // calculate normal of triangle VecSub(&data->points[p3], &data->points[p1], &e1); VecSub(&data->points[p2], &data->points[p1], &e2); VecNormCross(&e1, &e2, &data->TriNorms[i]); } } do { BeginChunk(data, &chunk); switch (chunk.id) { case ID_MSHMATGROUP: if (!data->replacesurface) { ReadASCIIZ(data, buf); s = data->link->SurfaceGetByName(data->rc, buf); ReadWord(data, (WORD*)&matcount, 1); for (i = 0; i < matcount; i++) { ReadWord(data, (WORD*)&index, 1); data->material[index] = s; } } break; case ID_SMOOTHGROUP: // no info about this group break; } EndChunk(data, &chunk); } while (INCHUNK); }