• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/cannonball/src/Level.cpp

Go to the documentation of this file.
00001 #include "main.h"
00002 
00003 #define MAX_BUFFER_LEN 256
00004 
00005 struct rvlHeader
00006 {
00007         char head[4];
00008         int version;
00009         int numGeometries;
00010         int numTextures;
00011         int numObjects;
00012         int numLights;
00013 };
00014 
00015 struct gemetryHeader
00016 {
00017         int vertexSize;
00018         int vertexCount;
00019         int indexCount;
00020         char name[32];
00021 };
00022 
00023 Level::Level(IPhysic& physic, IRender& render)
00024 : physic(physic),
00025   render(render)
00026 {
00027         numGeometries = 0;
00028         numTextures = 0;
00029         numBodies = 0;
00030         geometries = 0;
00031         textures = 0;
00032         bodies = 0;
00033         start.zero();
00034         end.zero();
00035         items.init(32);
00036         for(int i=0; i<4; itemGeometries[i] = 0, i++);
00037 }
00038 
00039 Level::~Level()
00040 {
00041 }
00042 
00043 bool Level::loadMeshData(FILE* file, MeshData& meshData, const char* name)
00044 {
00045         gemetryHeader header;
00046 
00047         // read file header
00048         if(fread(&header, sizeof(gemetryHeader), 1, file) != 1)
00049                 return false;
00050 
00051         // validate file format
00052         if(header.vertexSize != int(sizeof(Vertex)))
00053                 return false;
00054         if(header.vertexCount < 3)
00055                 return false;
00056         if((header.indexCount < 3) || ((header.indexCount % 3) != 0))
00057                 return false;
00058 
00059         if(name == 0 || strcmp(header.name, name) == 0){
00060                 // allocate memory for vertices and indices
00061                 void* memory = malloc(header.vertexSize*header.vertexCount + 2*header.indexCount);
00062                 Vertex* vertices = (Vertex*)memory;
00063                 ushort* indices = (ushort*)&vertices[header.vertexCount];
00064 
00065                 // read vertices data
00066                 if(fread(vertices, sizeof(Vertex), header.vertexCount, file) != header.vertexCount)
00067                         return fclose(file), false;
00068                 // read indices data
00069                 if(fread(indices, sizeof(ushort), header.indexCount, file) != header.indexCount)
00070                         return fclose(file), false;
00071 
00072                 // fill output structure
00073                 meshData.vertexSize = header.vertexSize;
00074                 meshData.vertexCount = header.vertexCount;
00075                 meshData.indexCount = header.indexCount;
00076                 meshData.vertices = vertices;
00077                 meshData.indices = indices;
00078         }else{
00079                 if(fseek(file, sizeof(Vertex)*header.vertexCount, SEEK_CUR) != 0)
00080                         return fclose(file), false;
00081                 if(fseek(file, sizeof(ushort)*header.indexCount, SEEK_CUR) != 0)
00082                         return fclose(file), false;
00083         }
00084 
00085         return true;
00086 }
00087 
00088 bool Level::loadUnknown(const wchar* filename, int& width, int& height, Pixel** outData)
00089 {
00090         bool ok = true;
00091         size_t filenameLength = wcslen(filename);
00092 
00093         if(wcscmp(&filename[filenameLength-4], TEXT(".bmp")) == 0)
00094                 ok = loadBMP(filename, width, height, outData);
00095         else if(wcscmp(&filename[filenameLength-4], TEXT(".tga")) == 0)
00096                 ok = loadTGA(filename, width, height, outData);
00097         else
00098                 return false;
00099 
00100         if(outData == 0 && width != height)
00101                 return false;
00102 
00103         return ok;
00104 }
00105 
00106 bool Level::loadTextureData(const wchar* colorFilename, const wchar* normalFilename, const wchar* heightFilename, TextureData& out)
00107 {
00108         Pixel* colorData = 0;
00109         Pixel* normalData = 0;
00110         Pixel* heightData = 0;
00111         int widthColor = 0, heightColor = 0;
00112         int widthDetail = 0, heightDetail = 0;
00113         bool ok = true;
00114 
00115         ok = loadUnknown(colorFilename, widthColor, heightColor, 0);
00116         if(ok) ok = loadUnknown(colorFilename, widthColor, heightColor, &colorData);
00117         ok = loadUnknown(normalFilename, widthDetail, heightDetail, 0);
00118         if(ok) ok = loadUnknown(normalFilename, widthDetail, heightDetail, &normalData);
00119         if(ok) ok = loadUnknown(heightFilename, widthDetail, heightDetail, &heightData);
00120 
00121         if(ok == false)
00122         {
00123                 SAVEFREE(colorData);
00124                 SAVEFREE(normalData);
00125                 SAVEFREE(heightData);
00126                 return false;
00127         }
00128 
00129         int mipmapsColor = 0;
00130         int mipmapsDetail = 0;
00131         int mipmapPixelsColor = 0;
00132         int mipmapPixelsDetail = 0;
00133         MipMap* colorMipmaps;
00134         MipMap* detailMipmaps;
00135 
00136         for(int w=widthColor; w>0; mipmapPixelsColor+=w*w, w/=2, mipmapsColor++);
00137         for(int w=widthDetail; w>0; mipmapPixelsDetail+=w*w, w/=2, mipmapsDetail++);
00138 
00139         void* mem = malloc(sizeof(MipMap)*(mipmapsColor+mipmapsDetail) + sizeof(Pixel)*(mipmapPixelsColor+mipmapPixelsDetail));
00140 
00141         colorMipmaps = (MipMap*)mem;
00142         detailMipmaps = &colorMipmaps[mipmapsColor];
00143         Pixel* colorPixels = (Pixel*)&detailMipmaps[mipmapsDetail];
00144         Pixel* detailPixels = &colorPixels[mipmapPixelsColor];
00145 
00146         for(int i=0, w=widthColor, curPixel=0; i<mipmapsColor; curPixel+=w*w, w/=2, i++)
00147         {
00148                 colorMipmaps[i].width = w;
00149                 colorMipmaps[i].height = w;
00150                 colorMipmaps[i].data = &colorPixels[curPixel];
00151         }
00152 
00153         for(int i=0, w=widthDetail, curPixel=0; i<mipmapsDetail; curPixel+=w*w, w/=2, i++)
00154         {
00155                 detailMipmaps[i].width = w;
00156                 detailMipmaps[i].height = w;
00157                 detailMipmaps[i].data = &detailPixels[curPixel];
00158         }
00159 
00160         // copy loaded data
00161         for(int y=0; y<colorMipmaps[0].height; y++)
00162         {
00163                 for(int x=0; x<colorMipmaps[0].width; x++)
00164                         colorMipmaps[0].data[y*widthColor+x] = colorData[y*widthColor+x];
00165         }
00166 
00167         // compute color mipmaps
00168         for(int i=0; i<mipmapsColor-1; i++)
00169         {
00170                 for(int y=0; y<colorMipmaps[i+1].height; y++)
00171                 {
00172                         for(int x=0; x<colorMipmaps[i+1].width; x++)
00173                         {
00174                                 int color[4];
00175                                 for(int c=0; c<4; color[c]  = colorMipmaps[i].data[((y+0)* colorMipmaps[i].width + x + 0)*2].canal[c], c++);
00176                                 for(int c=0; c<4; color[c] += colorMipmaps[i].data[((y+0)* colorMipmaps[i].width + x + 1)*2].canal[c], c++);
00177                                 for(int c=0; c<4; color[c] += colorMipmaps[i].data[((y+1)* colorMipmaps[i].width + x + 0)*2].canal[c], c++);
00178                                 for(int c=0; c<4; color[c] += colorMipmaps[i].data[((y+1)* colorMipmaps[i].width + x + 1)*2].canal[c], c++);
00179                                 for(int c=0; c<4; colorMipmaps[i+1].data[y * colorMipmaps[i+1].width + x].canal[c] = uchar(color[c]/4), c++);
00180                         }
00181                 }
00182         }
00183 
00184         // copy loaded height data
00185         for(int y=0; y<detailMipmaps[0].height; y++)
00186         {
00187                 for(int x=0; x<detailMipmaps[0].width; x++)
00188                 {
00189                         normalData[y*widthDetail+x].a = heightData[y*widthDetail+x].r;
00190                         detailMipmaps[0].data[y*widthDetail+x] = normalData[y*widthDetail+x];
00191                 }
00192         }
00193 
00194         // compute color mipmaps
00195         for(int i=0; i<mipmapsDetail-1; i++)
00196         {
00197                 for(int y=0; y<detailMipmaps[i].height/2; y++)
00198                 {
00199                         for(int x=0; x<detailMipmaps[i].width/2; x++)
00200                         {
00201                                 int normal[4];
00202                                 for(int c=0; c<4; normal[c]  = detailMipmaps[i].data[((y+0)* detailMipmaps[i].width + x + 0)*2].canal[c], c++);
00203                                 for(int c=0; c<4; normal[c] += detailMipmaps[i].data[((y+0)* detailMipmaps[i].width + x + 1)*2].canal[c], c++);
00204                                 for(int c=0; c<4; normal[c] += detailMipmaps[i].data[((y+1)* detailMipmaps[i].width + x + 0)*2].canal[c], c++);
00205                                 for(int c=0; c<4; normal[c] += detailMipmaps[i].data[((y+1)* detailMipmaps[i].width + x + 1)*2].canal[c], c++);
00206                                 for(int c=0; c<4; detailMipmaps[i+1].data[y * detailMipmaps[i+1].width + x].canal[c] = uchar(normal[c]/4), c++);
00207                         }
00208                 }
00209         }
00210 
00211         // free temporary data
00212         SAVEFREE(colorData);
00213         SAVEFREE(normalData);
00214         SAVEFREE(heightData);
00215 
00216         // fill output structure
00217         out.mipmapsColor = mipmapsColor;
00218         out.mipmapsDetail = mipmapsDetail;
00219         out.color = colorMipmaps;
00220         out.detail = detailMipmaps;
00221         return true;
00222 }
00223 
00224 bool Level::load(const wchar* filename, const wchar* textureDir)
00225 {
00226         unload();
00227 
00228         FILE* file;
00229         const char rvlHead[] = "RVL ";
00230         rvlHeader header;
00231         int i;
00232         int lenBuffer;
00233         wchar bufferColor[MAX_BUFFER_LEN+1];
00234         wchar bufferNormal[MAX_BUFFER_LEN+1];
00235         wchar bufferHeight[MAX_BUFFER_LEN+1];
00236         char charBuffer[32];
00237         MeshData* meshDatas;
00238 
00239         bufferColor[MAX_BUFFER_LEN] = bufferNormal[MAX_BUFFER_LEN] = bufferHeight[MAX_BUFFER_LEN] = 0;
00240 
00241         if(wcslen(textureDir) + 32 > MAX_BUFFER_LEN)
00242                 return false;
00243 
00244         // save open file
00245         if(_wfopen_s(&file, filename, TEXT("rb")) != 0)
00246                 return false;
00247 
00248         // read file header
00249         if(fread(&header, sizeof(rvlHeader), 1, file) != 1)
00250                 return fclose(file), false;
00251 
00252         // validate file format
00253         if(*(uint*)header.head != *(uint*)rvlHead)
00254                 return fclose(file), false;
00255         if(header.version != 1)
00256                 return fclose(file), false;
00257 
00258         numGeometries = header.numGeometries;
00259         numTextures = header.numTextures;
00260         numBodies = header.numObjects;
00261         numLights = header.numLights;
00262 
00263         // reserve memory
00264         void* memory = malloc((sizeof(pIGeometry)+sizeof(MeshData))*numGeometries + sizeof(pITexture)*numTextures + sizeof(pIBody)*numBodies);
00265         geometries = (pIGeometry*)memory;
00266         textures = (pITexture*)&geometries[numGeometries];
00267         bodies = (pIBody*)&textures[numTextures];
00268         meshDatas = (MeshData*)&bodies[numBodies];
00269 
00270         // load geometry objects
00271         for(i=0; i<numGeometries; i++){
00272 
00273                 if(loadMeshData(file, meshDatas[i]) == false){
00274                         printf("%s", "Geometry mesh data could not be loaded.");
00275                         break;
00276                 }
00277 
00278                 pIGeometry geom = render.createGeometry(meshDatas[i]);
00279 
00280                 if(geom == 0){
00281                         printf("%s", "Geometry could not be created.");
00282                         break;
00283                 }
00284 
00285                 geometries[i] = geom;
00286         }
00287 
00288         if(i != numGeometries){
00289                 for(int a=0; a<i; meshDatas[a].free(), a++);
00290                 return free(memory), fclose(file), false;
00291         }
00292 
00293         // load texture objects
00294         lenBuffer = wcslen(textureDir);
00295         for(int l=0; l<lenBuffer; bufferColor[l] = textureDir[l], l++);
00296         for(int l=0; l<lenBuffer; bufferNormal[l] = textureDir[l], l++);
00297         for(int l=0; l<lenBuffer; bufferHeight[l] = textureDir[l], l++);
00298 
00299         for(i=0; i<numTextures; i++){
00300                 int len;
00301                 TextureData textureData;
00302 
00303                 memset(&charBuffer, 0, sizeof(char)*32);
00304                 if(fread(&charBuffer, sizeof(char), 32, file) != 32){
00305                         printf("%s", "Color texture name could not be read from the file.");
00306                         break;
00307                 }
00308                 len = strlen(charBuffer);
00309                 MultiByteToWideChar(CP_ACP, 0, charBuffer, len, &bufferColor[lenBuffer], len);
00310                 bufferColor[lenBuffer+len] = 0;
00311 
00312                 memset(&charBuffer, 0, sizeof(char)*32);
00313                 if(fread(&charBuffer, sizeof(char), 32, file) != 32){
00314                         printf("%s", "Normal texture name could not be read from the file.");
00315                         break;
00316                 }
00317                 len = strlen(charBuffer);
00318                 MultiByteToWideChar(CP_ACP, 0, charBuffer, len, &bufferNormal[lenBuffer], len);
00319                 bufferNormal[lenBuffer+len] = 0;
00320 
00321                 memset(&charBuffer, 0, sizeof(char)*32);
00322                 if(fread(&charBuffer, sizeof(char), 32, file) != 32){
00323                         printf("%s", "Height texture name could not be read from the file.");
00324                         break;
00325                 }
00326                 len = strlen(charBuffer);
00327                 MultiByteToWideChar(CP_ACP, 0, charBuffer, len, &bufferHeight[lenBuffer], len);
00328                 bufferHeight[lenBuffer+len] = 0;
00329 
00330                 if(loadTextureData(bufferColor, bufferNormal, bufferHeight, textureData) == false){
00331                         printf("%s", "Texture data could not be loaded.");
00332                         break;
00333                 }
00334 
00335                 pITexture tex = render.createTexture(textureData);
00336 
00337                 if(tex == 0){
00338                         printf("Texture '%s' could not be loaded.", &bufferColor[lenBuffer]);
00339                         break;
00340                 }
00341 
00342                 textures[i] = tex;
00343         }
00344 
00345         if(i != numTextures){
00346                 for(int a=0; a<numGeometries; meshDatas[a].free(), a++);
00347                 return free(memory), fclose(file), false;
00348         }
00349 
00350         // load render objects
00351         for(i=0; i<numBodies; i++){
00352                 pIBody body = 0;
00353                 LevelObjectBody objData;
00354 
00355                 if(fread(&objData, sizeof(LevelObjectBody), 1, file) != 1){
00356                         printf("%s", "Object data could not be loaded.");
00357                         break;
00358                 }
00359 
00360                 float boundingRadius = float3(objData.width/2, objData.height/2, objData.depth/2).length();
00361 
00362                 switch(objData.geom){
00363                         case bodyDummy:
00364                                 body = physic.createDummy(
00365                                         objData.position,
00366                                         objData.rotation);
00367                                 break;
00368                         case bodySphere:
00369                                 body = physic.createSphere(
00370                                         objData.position,
00371                                         objData.rotation,
00372                                         boundingRadius,
00373                                         objData.density,
00374                                         ushort(objData.group),
00375                                         objData.material,
00376                                         objData.type == typeDynamic);
00377                                 break;
00378                         case bodyBox:
00379                                 body = physic.createBox(
00380                                         objData.position,
00381                                         objData.rotation,
00382                                         objData.width,
00383                                         objData.height,
00384                                         objData.depth,
00385                                         objData.density,
00386                                         ushort(objData.group),
00387                                         objData.material,
00388                                         objData.type == typeDynamic);
00389                                 break;
00390                         case bodyMesh:
00391                                 body = physic.createMesh(
00392                                         objData.position,
00393                                         objData.rotation,
00394                                         meshDatas[objData.geometryID].vertices[0].position.v,
00395                                         meshDatas[objData.geometryID].vertexSize,
00396                                         meshDatas[objData.geometryID].vertexCount,
00397                                         meshDatas[objData.geometryID].indices,
00398                                         meshDatas[objData.geometryID].indexCount,
00399                                         objData.density,
00400                                         ushort(objData.group),
00401                                         objData.material,
00402                                         objData.type == typeDynamic);
00403                                 break;
00404                         default:
00405                                 break;
00406                 }
00407 
00408                 if(body == 0){
00409                         printf("%s", "Object could not be loaded.");
00410                         break;
00411                 }
00412 
00413                 body->setRadius(boundingRadius);
00414 
00415                 bodies[i] = body;
00416 
00417                 // add draw call
00418                 if(objData.textureID >= 0)
00419                         render.createDrawCall(textures[objData.textureID], geometries[objData.geometryID], bodies[i]);
00420                 else
00421                         render.createColorDrawCall(geometries[objData.geometryID], bodies[i]);
00422         }
00423 
00424         if(i != numBodies){
00425                 for(int a=0; a<numGeometries; meshDatas[a].free(), a++);
00426                 return free(memory), fclose(file), false;
00427         }
00428 
00429         for(i=0; i<numLights; i++){
00430                 LightData lightData;
00431 
00432                 if(fread(&lightData, sizeof(LightData), 1, file) != 1){
00433                         printf("%s", "Light data could not be loaded.");
00434                         break;
00435                 }
00436 
00437                 render.setLight(i, lightData);
00438         }
00439 
00440         // done reading from file
00441         fclose(file);
00442         for(int a=0; a<numGeometries; meshDatas[a].free(), a++);
00443         //free(memory);
00444 
00445         if(i != numLights)
00446                 return false;
00447 
00448         int numberOfItems = 0;
00449         LevelItem levelItem;
00450         float3 position;
00451         int type;
00452         int item;
00453         float value;
00454         int filenameLen = wcslen(filename);
00455         if(filenameLen + 4 > MAX_BUFFER_LEN)
00456                 return false;
00457         wcscpy_s(bufferColor, MAX_BUFFER_LEN, filename);
00458         bufferColor[filenameLen++] = TEXT('.');
00459         bufferColor[filenameLen++] = TEXT('d');
00460         bufferColor[filenameLen++] = TEXT('e');
00461         bufferColor[filenameLen++] = TEXT('f');
00462         bufferColor[filenameLen] = 0;
00463 
00464         // save open file
00465         if(_wfopen_s(&file, bufferColor, TEXT("rb")) != 0)
00466                 return false;
00467 
00468         // read number of items
00469         if(fread(&numberOfItems, sizeof(int), 1, file) != 1)
00470                 return fclose(file), false;
00471 
00472         itemBodies.init(numberOfItems);
00473         itemInstances.init(numberOfItems);
00474 
00475         for(int i=0; i<numberOfItems; i++){
00476                 // read data
00477                 if(fread(&position, sizeof(float3), 1, file) != 1)
00478                         return fclose(file), false;
00479                 if(fread(&type, sizeof(int), 1, file) != 1)
00480                         return fclose(file), false;
00481                 if(fread(&item, sizeof(int), 1, file) != 1)
00482                         return fclose(file), false;
00483                 if(fread(&value, sizeof(float), 1, file) != 1)
00484                         return fclose(file), false;
00485                 // set item
00486                 switch(type){
00487                         case 0: // start
00488                                 start = position;
00489                                 break;
00490                         case 1: // end
00491                                 end = position;
00492                                 break;
00493                         case 2: // item
00494                                 levelItem.position = position;
00495                                 levelItem.item = item;
00496                                 levelItem.value = int(value);
00497                                 items.add(levelItem);
00498                                 if(itemGeometries[item]){
00499                                         pIBody body = physic.createDummy(position, float3(0.f,0.f,0.f));
00500                                         itemBodies.add(body);
00501                                         pInstance instance = render.createColorDrawCall(itemGeometries[item], body);
00502                                         itemInstances.add(instance);
00503                                 }
00504                                 break;
00505                         default:
00506                                 break;
00507                 }
00508         }
00509 
00510         fclose(file);
00511 
00512         return true;
00513 }
00514 
00515 bool Level::loadGeometry(const wchar* filename, const char* name, pIGeometry& geometry)
00516 {
00517         FILE* file;
00518         const char rvlHead[] = "RVL ";
00519         rvlHeader header;
00520         int i;
00521         MeshData meshData;
00522 
00523         // save open file
00524         if(_wfopen_s(&file, filename, TEXT("rb")) != 0)
00525                 return false;
00526 
00527         // read file header
00528         if(fread(&header, sizeof(rvlHeader), 1, file) != 1)
00529                 return fclose(file), false;
00530 
00531         // validate file format
00532         if(*(uint*)header.head != *(uint*)rvlHead)
00533                 return fclose(file), false;
00534         if(header.version != 1)
00535                 return fclose(file), false;
00536 
00537         numGeometries = header.numGeometries;
00538 
00539         // load geometry objects
00540         for(i=0; i<numGeometries; i++){
00541                 if(loadMeshData(file, meshData, name) == false)
00542                         continue;
00543 
00544                 geometry = render.createGeometry(meshData);
00545                 meshData.free();
00546 
00547                 if(geometry == 0)
00548                         printf("%s", "Geometry could not be created.");
00549                 break;
00550         }
00551 
00552         fclose(file);
00553 
00554         if(geometry == 0)
00555                 return false;
00556 
00557         return true;
00558 }
00559 
00560 bool Level::loadGeometry(const wchar* filename, const char* name, pIGeometry& geometry, MeshData& meshData)
00561 {
00562         FILE* file;
00563         const char rvlHead[] = "RVL ";
00564         rvlHeader header;
00565         int i;
00566         //MeshData meshData;
00567 
00568         // save open file
00569         if(_wfopen_s(&file, filename, TEXT("rb")) != 0)
00570                 return false;
00571 
00572         // read file header
00573         if(fread(&header, sizeof(rvlHeader), 1, file) != 1)
00574                 return fclose(file), false;
00575 
00576         // validate file format
00577         if(*(uint*)header.head != *(uint*)rvlHead)
00578                 return fclose(file), false;
00579         if(header.version != 1)
00580                 return fclose(file), false;
00581 
00582         numGeometries = header.numGeometries;
00583 
00584         // load geometry objects
00585         for(i=0; i<numGeometries; i++){
00586                 if(loadMeshData(file, meshData, name) == false)
00587                         continue;
00588 
00589                 geometry = render.createGeometry(meshData);
00590                 //meshData.free();
00591 
00592                 if(geometry == 0)
00593                         printf("%s", "Geometry could not be created.");
00594                 break;
00595         }
00596 
00597         fclose(file);
00598 
00599         if(geometry == 0)
00600                 return false;
00601 
00602         return true;
00603 }
00604 
00605 void Level::unload(void)
00606 {
00607         render.clear();
00608         if(bodies){
00609                 for(int i=0; i<numBodies; i++)
00610                         physic.freeBody(bodies[i]);
00611         }
00612         if(textures){
00613                 for(int i=0; i<numTextures; i++)
00614                         render.freeTexture(textures[i]);
00615         }
00616         if(geometries){
00617                 for(int i=0; i<numGeometries; i++)
00618                         render.freeGeometry(geometries[i]);
00619                 free(geometries);
00620         }
00621         for(uint i=0; i<itemBodies.size(); i++)
00622                 physic.freeBody(itemBodies.getRef(i));
00623         numGeometries = 0;
00624         numTextures = 0;
00625         numBodies = 0;
00626         geometries = 0;
00627         textures = 0;
00628         bodies = 0;
00629         start.zero();
00630         end.zero();
00631         items.clear();
00632         itemBodies.uninit();
00633         itemInstances.uninit();
00634 }

Generated on Fri Jun 18 2010 17:48:39 for Cannonball by  doxygen 1.7.0