/*! * Load shape level polygons * \param ppFileData Pointer to the data (usualy read from a file) * \param s Pointer to shape level * \return false on error (memory allocation failure/bad file format), true otherwise * \pre ppFileData loaded * \pre s allocated * \pre s->npolys set * \post s->polys allocated (iFSDPoly * s->npolys) * \post s->pindex allocated for each poly */ static bool _imd_load_polys( const char **ppFileData, iIMDShape *s ) { const char *pFileData = *ppFileData; int i, j, cnt; iIMDPoly *poly; s->numFrames = 0; s->animInterval = 0; s->polys = (iIMDPoly*)malloc(sizeof(iIMDPoly) * s->npolys); if (s->polys == NULL) { fprintf(stderr, "(_load_polys) Out of memory (polys)\n"); return false; } for (i = 0, poly = s->polys; i < s->npolys; i++, poly++) { Uint32 flags, npnts; if (sscanf(pFileData, "%x %d%n", &flags, &npnts, &cnt) != 2) { fprintf(stderr, "(_load_polys) [poly %d] error loading flags and npoints", i); } pFileData += cnt; poly->flags = flags; poly->npnts = npnts; poly->pindex = (VERTEXID*)malloc(sizeof(VERTEXID) * poly->npnts); if (poly->pindex == NULL) { fprintf(stderr, "(_load_polys) [poly %d] memory alloc fail (poly indices)", i); return false; } for (j = 0; j < poly->npnts; j++) { int newID; if (sscanf(pFileData, "%d%n", &newID, &cnt) != 1) { fprintf(stderr, "failed poly %d. point %d", i, j); return false; } pFileData += cnt; poly->pindex[j] = vertexTable[newID]; } // calc poly normal if (poly->npnts > 2) { Vector3f p0, p1, p2; //assumes points already set p0.x = s->points[poly->pindex[0]].x; p0.y = s->points[poly->pindex[0]].y; p0.z = s->points[poly->pindex[0]].z; p1.x = s->points[poly->pindex[1]].x; p1.y = s->points[poly->pindex[1]].y; p1.z = s->points[poly->pindex[1]].z; p2.x = s->points[poly->pindex[poly->npnts-1]].x; p2.y = s->points[poly->pindex[poly->npnts-1]].y; p2.z = s->points[poly->pindex[poly->npnts-1]].z; pie_SurfaceNormal3fv(&p0, &p1, &p2, &poly->normal); } else { Vector3f_Set(&poly->normal, 0.0f, 0.0f, 0.0f); } if (poly->flags & iV_IMD_TEXANIM) { unsigned int nFrames, pbRate, tWidth, tHeight; poly->pTexAnim = (iTexAnim*)malloc(sizeof(iTexAnim)); if (poly->pTexAnim == NULL) { fprintf(stderr, "(_load_polys) [poly %d] memory alloc fail (iTexAnim struct)", i); return false; } // even the psx needs to skip the data if (sscanf(pFileData, "%d %d %d %d%n", &nFrames, &pbRate, &tWidth, &tHeight, &cnt) != 4) { fprintf(stderr, "(_load_polys) [poly %d] error reading texanim data", i); return false; } pFileData += cnt; //ASSERT( tWidth > 0, "_imd_load_polys: texture width = %i", tWidth ); //ASSERT( tHeight > 0, "_imd_load_polys: texture height = %i", tHeight ); /* Assumes same number of frames per poly */ s->numFrames = nFrames; poly->pTexAnim->nFrames = nFrames; poly->pTexAnim->playbackRate =pbRate; /* Uses Max metric playback rate */ s->animInterval = pbRate; poly->pTexAnim->textureWidth = tWidth; poly->pTexAnim->textureHeight = tHeight; } else { poly->pTexAnim = NULL; } // PC texture coord routine if (poly->flags & iV_IMD_TEX) { poly->texCoord = (Vector2f*)malloc(sizeof(Vector2f) * poly->npnts); if (poly->texCoord == NULL) { fprintf(stderr, "(_load_polys) [poly %d] memory alloc fail (vertex struct)", i); return false; } for (j = 0; j < poly->npnts; j++) { float VertexU, VertexV; if (sscanf(pFileData, "%f %f%n", &VertexU, &VertexV, &cnt) != 2) { fprintf(stderr, "(_load_polys) [poly %d] error reading tex outline", i); return false; } pFileData += cnt; poly->texCoord[j].x = VertexU; poly->texCoord[j].y = VertexV; } } else { poly->texCoord = NULL; } } *ppFileData = pFileData; return true; }
/*! * Load shape level polygons * \param ppFileData Pointer to the data (usualy read from a file) * \param s Pointer to shape level * \return false on error (memory allocation failure/bad file format), true otherwise * \pre ppFileData loaded * \pre s allocated * \pre s->npolys set * \post s->polys allocated (iFSDPoly * s->npolys) * \post s->pindex allocated for each poly */ static bool _imd_load_polys(const QString &filename, const char **ppFileData, iIMDShape *s, int pieVersion) { const char *pFileData = *ppFileData; unsigned int i, j; iIMDPoly *poly; s->numFrames = 0; s->animInterval = 0; s->polys = (iIMDPoly *)malloc(sizeof(iIMDPoly) * s->npolys); if (s->polys == nullptr) { debug(LOG_ERROR, "(_load_polys) Out of memory (polys)"); return false; } for (i = 0, poly = s->polys; i < s->npolys; i++, poly++) { unsigned int flags, npnts; int cnt; if (sscanf(pFileData, "%x %u%n", &flags, &npnts, &cnt) != 2) { debug(LOG_ERROR, "(_load_polys) [poly %u] error loading flags and npoints", i); } pFileData += cnt; poly->flags = flags; ASSERT_OR_RETURN(false, npnts == 3, "Invalid polygon size (%d)", npnts); if (sscanf(pFileData, "%d %d %d%n", &poly->pindex[0], &poly->pindex[1], &poly->pindex[2], &cnt) != 3) { debug(LOG_ERROR, "failed reading triangle, point %d", i); return false; } pFileData += cnt; // calc poly normal { Vector3f p0, p1, p2; //assumes points already set p0.x = s->points[poly->pindex[0]].x; p0.y = s->points[poly->pindex[0]].y; p0.z = s->points[poly->pindex[0]].z; p1.x = s->points[poly->pindex[1]].x; p1.y = s->points[poly->pindex[1]].y; p1.z = s->points[poly->pindex[1]].z; p2.x = s->points[poly->pindex[2]].x; p2.y = s->points[poly->pindex[2]].y; p2.z = s->points[poly->pindex[2]].z; poly->normal = pie_SurfaceNormal3fv(p0, p1, p2); } // texture coord routine if (poly->flags & iV_IMD_TEX) { int nFrames, framesPerLine, frame, pbRate; float tWidth, tHeight; if (poly->flags & iV_IMD_TEXANIM) { if (sscanf(pFileData, "%d %d %f %f%n", &nFrames, &pbRate, &tWidth, &tHeight, &cnt) != 4) { debug(LOG_ERROR, "(_load_polys) [poly %u] error reading texanim data", i); return false; } pFileData += cnt; ASSERT(tWidth > 0.0001f, "%s: texture width = %f", filename.toUtf8().constData(), tWidth); ASSERT(tHeight > 0.f, "%s: texture height = %f (width=%f)", filename.toUtf8().constData(), tHeight, tWidth); ASSERT(nFrames > 1, "%s: animation frames = %d", filename.toUtf8().constData(), nFrames); ASSERT(pbRate > 0, "%s: animation interval = %d ms", filename.toUtf8().constData(), pbRate); /* Must have same number of frames and same playback rate for all polygons */ if (s->numFrames == 0) { s->numFrames = nFrames; s->animInterval = pbRate; } else { ASSERT(s->numFrames == nFrames, "%s: varying number of frames within one PIE level: %d != %d", filename.toUtf8().constData(), nFrames, s->numFrames); ASSERT(s->animInterval == pbRate, "%s: varying animation intervals within one PIE level: %d != %d", filename.toUtf8().constData(), pbRate, s->animInterval); } poly->texAnim.x = tWidth; poly->texAnim.y = tHeight; if (pieVersion != PIE_FLOAT_VER) { poly->texAnim.x /= OLD_TEXTURE_SIZE_FIX; poly->texAnim.y /= OLD_TEXTURE_SIZE_FIX; } framesPerLine = 1 / poly->texAnim.x; } else { nFrames = 1; framesPerLine = 1; pbRate = 1; tWidth = 0.f; tHeight = 0.f; poly->texAnim.x = 0; poly->texAnim.y = 0; } poly->texCoord = (Vector2f *)malloc(sizeof(*poly->texCoord) * nFrames * 3); ASSERT_OR_RETURN(false, poly->texCoord, "Out of memory allocating texture coordinates"); for (j = 0; j < 3; j++) { float VertexU, VertexV; if (sscanf(pFileData, "%f %f%n", &VertexU, &VertexV, &cnt) != 2) { debug(LOG_ERROR, "(_load_polys) [poly %u] error reading tex outline", i); return false; } pFileData += cnt; if (pieVersion != PIE_FLOAT_VER) { VertexU /= OLD_TEXTURE_SIZE_FIX; VertexV /= OLD_TEXTURE_SIZE_FIX; } for (frame = 0; frame < nFrames; frame++) { const float uFrame = (frame % framesPerLine) * poly->texAnim.x; const float vFrame = (frame / framesPerLine) * poly->texAnim.y; Vector2f *c = &poly->texCoord[frame * 3 + j]; c->x = VertexU + uFrame; c->y = VertexV + vFrame; } } } else { ASSERT_OR_RETURN(false, !(poly->flags & iV_IMD_TEXANIM), "Polygons with texture animation must have textures!"); poly->texCoord = nullptr; } } *ppFileData = pFileData; return true; }
static void normalsOnTile(unsigned int tileX, unsigned int tileY, unsigned int quadrant, unsigned int *numNormals, Vector3f normals[]) { /* Get a pointer to our tile */ /* And to the ones to the east, south and southeast of it */ MAPTILE *psTile = mapTile(tileX,tileY), *tileRight = mapTile(tileX+1,tileY), *tileDownRight = mapTile(tileX+1,tileY+1), *tileDown = mapTile(tileX,tileY+1); unsigned int rMod = 0, drMod = 0, dMod = 0, nMod = 0; switch(quadrant) { case 0: case 2: /* Is it flipped? In this case one triangle */ if(TRI_FLIPPED(psTile)) { if(quadrant==0) { Vector3f corner1 = { world_coord(tileX + 1), world_coord(tileY), tileRight->height - rMod }, corner2 = { world_coord(tileX + 1), world_coord(tileY + 1), tileDownRight->height - drMod }, corner3 = { world_coord(tileX), world_coord(tileY + 1), tileDown->height - dMod }; normals[(*numNormals)++] = pie_SurfaceNormal3fv( corner1, corner2, corner3); } else { Vector3f corner1 = { world_coord(tileX), world_coord(tileY), psTile->height - nMod }, corner2 = { world_coord(tileX + 1), world_coord(tileY), tileRight->height - rMod }, corner3 = { world_coord(tileX), world_coord(tileY + 1), tileDown->height - dMod }; normals[(*numNormals)++] = pie_SurfaceNormal3fv( corner1, corner2, corner3); } } else { /* Otherwise, it's not flipped and so two triangles*/ { // MSVC hack Vector3f corner1 = { world_coord(tileX), world_coord(tileY), psTile->height - nMod }, corner2 = { world_coord(tileX + 1), world_coord(tileY), tileRight->height - rMod }, corner3 = { world_coord(tileX + 1), world_coord(tileY + 1), tileDownRight->height - drMod }; normals[(*numNormals)++] = pie_SurfaceNormal3fv( corner1, corner2, corner3); } { // MSVC hack Vector3f corner1 = { world_coord(tileX), world_coord(tileY), psTile->height - nMod }, corner2 = { world_coord(tileX + 1), world_coord(tileY + 1), tileDownRight->height - drMod }, corner3 = { world_coord(tileX), world_coord(tileY + 1), tileDown->height - dMod }; normals[(*numNormals)++] = pie_SurfaceNormal3fv( corner1, corner2, corner3); } } break; case 1: case 3: /* Is it flipped? In this case two triangles */ if(TRI_FLIPPED(psTile)) { { // MSVC hack Vector3f corner1 = { world_coord(tileX), world_coord(tileY), psTile->height - nMod }, corner2 = { world_coord(tileX + 1), world_coord(tileY), tileRight->height - rMod }, corner3 = { world_coord(tileX), world_coord(tileY + 1), tileDown->height - dMod }; normals[(*numNormals)++] = pie_SurfaceNormal3fv( corner1, corner2, corner3); } { // MSVC hack Vector3f corner1 = { world_coord(tileX + 1), world_coord(tileY), tileRight->height - rMod }, corner2 = { world_coord(tileX + 1), world_coord(tileY + 1), tileDownRight->height - drMod }, corner3 = { world_coord(tileX), world_coord(tileY + 1), tileDown->height - dMod }; normals[(*numNormals)++] = pie_SurfaceNormal3fv( corner1, corner2, corner3); } } else { if(quadrant==1) { Vector3f corner1 = { world_coord(tileX), world_coord(tileY), psTile->height - nMod }, corner2 = { world_coord(tileX + 1), world_coord(tileY + 1), tileDownRight->height - drMod }, corner3 = { world_coord(tileX), world_coord(tileY + 1), tileDown->height - dMod }; normals[(*numNormals)++] = pie_SurfaceNormal3fv( corner1, corner2, corner3); } else { Vector3f corner1 = { world_coord(tileX), world_coord(tileY), psTile->height - nMod }, corner2 = { world_coord(tileX + 1), world_coord(tileY), tileRight->height - rMod }, corner3 = { world_coord(tileX + 1), world_coord(tileY + 1), tileDownRight->height - drMod }; normals[(*numNormals)++] = pie_SurfaceNormal3fv( corner1, corner2, corner3); } } break; default: ASSERT( false,"Invalid quadrant in lighting code" ); } // end switch }