- Main Page
- Classes
- Files

- File List
- File Members

# flTexture.c

Go to the documentation of this file.

    00001 #include "flGlobal.h"
    00002 #if FL_TEXTURE != 0
    00003 #include <string.h>
    00004 #include <stdio.h>
    00005 #include <pspgu.h>
    00006 #include <pspkernel.h>
    00007
    00008 #if FL_INCLUDE_ALL_C == 0
    00009 #include "flTexture.h"
    00010 #include "flMemory.h"
    00011 #include "flColor.h"
    00012 #include "flMath.h"
    00013 #include "flString.h"
    00014
    00015 #if FL_DEBUG != 0
    00016 #include "flDebug.h"
    00017 #endif
    00018
    00019 #if FL_GRAPHICS != 0
    00020 #include "flGraphics.h"
    00021 #endif
    00022
    00023 #if FL_TEXTURE_PCX != 0
    00024 #include "flTexturePCX.h"
    00025 #endif
    00026 #if FL_TEXTURE_TGA != 0
    00027 #include "flTextureTGA.h"
    00028 #endif
    00029 #if FL_TEXTURE_BMP != 0
    00030 #include "flTextureBMP.h"
    00031 #endif
    00032 #if FL_TEXTURE_WAL != 0
    00033 #include "flTextureWAL.h"
    00034 #endif
    00035 #if FL_TEXTURE_FTF != 0
    00036 #include "flTextureFTF.h"
    00037 #endif
    00038 #if FL_TEXTURE_RAW != 0
    00039 #include "flTextureRAW.h"
    00040 #endif
    00041 #endif
    00042
    00043
    00044
    00045
    00046 // Texture tree prototypes
    00047 typedef struct {
    00048      char     texNodePath[244];
    00049      Texture* texNodeData;
    00050      void*    texNodeNext[2];
    00051 } texTreeNode;
    00052
    00053 bool         texTreeAdd(char* inPath, Texture* inTex);
    00054 Texture*     texTreeFindTexByPath(char* inPath);
    00055 texTreeNode* texTreeFindNodeByTexR(Texture* inTex, texTreeNode* inNode);
    00056 char*        texTreeFindPathByTex(Texture* inTex);
    00057 texTreeNode* texTreeFindNodeByTex(Texture* inTex);
    00058 void         texTreeAddR(texTreeNode* inNode);
    00059 void         texTreeDelR(texTreeNode* inNode);
    00060 bool         texTreeDelNodeByTex(Texture* inTex);
    00061
    00062 texTreeNode* texTree = NULL;
    00063
    00064
    00065
    00066
    00067 #if FL_TEXTURE_ERRORTEX != 0
    00068 #if FL_TEXTURE_ERRORTEX_COMPILE != 0
    00069 #include "flTexError.c"
    00070 #endif
    00071 Texture* texError = NULL;
    00072 #endif
    00073
    00074 void* texBound = NULL;
    00075 void* palBound = NULL;
    00076
    00077 Palette* palGrayscaleT8Ptr = NULL;
    00078 Palette* palGrayscaleT4Ptr = NULL;
    00079 Palette* palDefaultColorT4Ptr = NULL;
    00080
    00081 static int getNextPower2(int inNum) {
    00082      int tempOut = inNum;
    00083      int tempBits;
    00084      for(tempBits = 0; tempOut != 0; tempBits++)
    00085           tempOut >>= 1;
    00086      tempOut = 1 << tempBits;
    00087      if(tempOut == (inNum << 1))
    00088           tempOut = inNum;
    00089      return tempOut;
    00090 }
    00091
    00092 static inline int getPaletteSize(int inEntries) {
    00093      while(inEntries & 7)
    00094           inEntries++;
    00095      return inEntries;
    00096 }
    00097
    00098 #if FL_GRAPHICS != 0
    00099 inline u8 texBPP(Texture* inTex) {
    00100      switch(inTex->texPixelFormat) {
    00101           case GU_PSM_8888:
    00102           case GU_PSM_T32:
    00103                return 32;
    00104           case GU_PSM_4444:
    00105           case GU_PSM_5650:
    00106           case GU_PSM_5551:
    00107           case GU_PSM_T16:
    00108                return 16;
    00109           case GU_PSM_DXT3:
    00110           case GU_PSM_DXT5:
    00111           case GU_PSM_T8:
    00112                return 8;
    00113           case GU_PSM_DXT1:
    00114           case GU_PSM_T4:
    00115                return 4;
    00116      }
    00117      return 0;
    00118 }
    00119 #endif
    00120
    00121 inline u8 texPalettized(Texture* inTex) {
    00122      return (inTex->texPixelFormat & 4);
    00123 }
    00124
    00125 inline u8 palBPP(Palette* inPal) {
    00126      #if FL_GRAPHICS != 0
    00127      if(inPal->palPixelFormat > GU_PSM_8888) {
    00128           #if FL_DEBUG_WARNING != 0
    00129           debugWarning("Warning, erroneous palette BPP %u.", (unsigned int)inPal->palPixelFormat);
    00130           #endif
    00131           return 0;
    00132      }
    00133      return graphicsPixelFormatBPP(inPal->palPixelFormat);
    00134      #else
    00135      switch(inPal->palPixelFormat) {
    00136           case GU_PSM_8888:
    00137                return 32;
    00138           case GU_PSM_4444:
    00139           case GU_PSM_5650:
    00140           case GU_PSM_5551:
    00141                return 16;
    00142           case GU_PSM_T32:
    00143           case GU_PSM_T16:
    00144           case GU_PSM_DXT3:
    00145           case GU_PSM_DXT5:
    00146           case GU_PSM_T8:
    00147           case GU_PSM_DXT1:
    00148           case GU_PSM_T4:
    00149           #if FL_DEBUG_WARNING != 0
    00150           debugWarning("Warning, erroneous palette BPP %u.", (unsigned int)inPath->palPixelFormat);
    00151           #endif
    00152           return 0;
    00153      }
    00154      return 0;
    00155      #endif
    00156 }
    00157
    00158 inline void palBind(Palette* inPalette) {
    00159      if(palBound && (inPalette == palBound))
    00160           return;
    00161
    00162      sceGuClutMode(inPalette->palPixelFormat, 0, 0xFF, 0);
    00163      sceGuClutLoad((inPalette->palEntries >> 3), inPalette->palData);
    00164
    00165      palBound = inPalette->palData;
    00166 }
    00167
    00168 void texInit() {
    00169      #if FL_TEXTURE_ERRORTEX != 0
    00170      #if FL_TEXTURE_ERRORTEX_COMPILE != 0
    00171      texError = &texErrorStruct;
    00172      #else
    00173      texError = texLoad(FL_TEXTURE_ERRORTEX_PATH);
    00174      #endif
    00175      #endif
    00176 }
    00177
    00178 Texture* texLoad(char* inPath) {
    00179      if(!inPath || (inPath[0] == 0)) {
    00180           #if FL_DEBUG_WARNING != 0
    00181           debugWarning("Invalid texture file path \"%s\".", inPath);
    00182           #endif
    00183           return NULL;
    00184      }
    00185
    00186      inPath = filePathValidate(inPath);
    00187
    00188      Texture* tempOut = texTreeFindTexByPath(inPath);
    00189      if(tempOut) {
    00190           tempOut->texUseCount++;
    00191           return tempOut;
    00192      }
    00193
    00194      char* tempExt = fileExtension(inPath);
    00195      if(!tempExt || !tempExt[0]) {
    00196           #if FL_DEBUG_WARNING != 0
    00197           debugWarning("Cannot determine file extension for texture \"%s\".", inPath);
    00198           #endif
    00199           return NULL;
    00200      }
    00201      strLCase((u8*)tempExt);
    00202
    00203      if((strcmp(tempExt, "pcx") == 0) || (strcmp(tempExt, "pcc") == 0)){
    00204           #if FL_TEXTURE_PCX != 0
    00205           tempOut = texLoadPCX(inPath);
    00206           #else
    00207           #if FL_DEBUG_ERROR != 0
    00208           debugError("PCX textures not supported in this build.");
    00209           #endif
    00210           #endif
    00211      } else if((strcmp(tempExt, "tga") == 0) || (strcmp(tempExt, "tpic") == 0)) {
    00212           #if FL_TEXTURE_TGA != 0
    00213           tempOut = texLoadTGA(inPath);
    00214           #else
    00215           #if FL_DEBUG_ERROR != 0
    00216           debugError("TGA textures not supported in this build.");
    00217           #endif
    00218           #endif
    00219      } else if((strcmp(tempExt, "bmp") == 0) || (strcmp(tempExt, "dib") == 0)){
    00220           #if FL_TEXTURE_BMP != 0
    00221           tempOut = texLoadBMP(inPath);
    00222           #else
    00223           #if FL_DEBUG_ERROR != 0
    00224           debugError("BMP textures not supported in this build.");
    00225           #endif
    00226           #endif
    00227      } else if(strcmp(tempExt, "wal") == 0) {
    00228           #if FL_TEXTURE_WAL != 0
    00229           tempOut = texLoadWAL(inPath);
    00230           #else
    00231           #if FL_DEBUG_ERROR != 0
    00232           debugError("WAL textures not supported in this build.");
    00233           #endif
    00234           #endif
    00235      } else if(strcmp(tempExt, "ftf") == 0) {
    00236           #if FL_TEXTURE_FTF != 0
    00237           tempOut = texLoadFTF(inPath);
    00238           #else
    00239           #if FL_DEBUG_ERROR != 0
    00240           debugError("FTF textures not supported in this build.");
    00241           #endif
    00242           #endif
    00243      } else {
    00244           #if FL_DEBUG_WARNING != 0
    00245           debugWarning("Texture format \"%s\" not supported.", tempExt);
    00246           #endif
    00247      }
    00248
    00249      memFree(tempExt);
    00250
    00251      if(!tempOut)
    00252           return NULL;
    00253
    00254      #if FL_TEXTURE_AUTOMIPMAP != 0
    00255      #if FL_TEXTURE_AUTOMIPMAP_PALETTED == 0
    00256      if(!texPalettized(tempOut)) {
    00257      #endif
    00258      texMipMap(tempOut, FL_TEXTURE_AUTOMIPMAP);
    00259      #if FL_TEXTURE_AUTOMIPMAP_PALETTED == 0
    00260      }
    00261      #endif
    00262      #endif
    00263
    00264      #if FL_TEXTURE_AUTOSWIZZLE != 0
    00265      texSwizzle(tempOut);
    00266      #endif
    00267
    00268      #if ((FL_TEXTURE_AUTOMIPMAP == 0) && (FL_TEXTURE_AUTOSWIZZLE == 0))
    00269      if(memIsCachedPointer(tempOut->texData)) {
    00270           if(texDataSize(tempOut) >= 16384)
    00271                sceKernelDcacheWritebackInvalidateAll();
    00272           else
    00273                sceKernelDcacheWritebackInvalidateRange(tempOut->texData, texDataSize(tempOut));
    00274      }
    00275      #endif
    00276
    00277      texTreeAdd(inPath, tempOut);
    00278
    00279      return tempOut;
    00280 }
    00281
    00282 bool texSave(Texture* inTex, char* inPath) {
    00283      if(!inTex) {
    00284           #if FL_DEBUG_WARNING != 0
    00285           debugWarning("Trying to save a NULL texture.");
    00286           #endif
    00287           return false;
    00288      }
    00289      if(!inPath || (inPath[0] == 0)) {
    00290           #if FL_DEBUG_WARNING != 0
    00291           debugWarning("Invalid texture save file path \"%s\".", inPath);
    00292           #endif
    00293           return false;
    00294      }
    00295
    00296      inPath = filePathValidate(inPath);
    00297
    00298      char* tempExt = fileExtension(inPath);
    00299      if(!tempExt || !tempExt[0]) {
    00300           #if FL_DEBUG_WARNING != 0
    00301           debugWarning("Cannot determine file extension for texture \"%s\".", inPath);
    00302           #endif
    00303           return false;
    00304      }
    00305      strLCase((u8*)tempExt);
    00306
    00307      if((strcmp(tempExt, "pcx") == 0) || (strcmp(tempExt, "pcc") == 0)){
    00308           #if FL_TEXTURE_PCX != 0
    00309           return texSavePCX(inTex, inPath);
    00310           #else
    00311           #if FL_DEBUG_ERROR != 0
    00312           debugError("PCX textures not supported in this build.");
    00313           #endif
    00314           return false;
    00315           #endif
    00316      } else if((strcmp(tempExt, "tga") == 0) || (strcmp(tempExt, "tpic") == 0)) {
    00317           #if FL_TEXTURE_TGA != 0
    00318           return texSaveTGA(inTex, inPath);
    00319           #else
    00320           #if FL_DEBUG_ERROR != 0
    00321           debugError("TGA textures not supported in this build.");
    00322           #endif
    00323           return false;
    00324           #endif
    00325      } else if((strcmp(tempExt, "bmp") == 0) || (strcmp(tempExt, "dib") == 0)){
    00326           #if FL_TEXTURE_BMP != 0
    00327           return texSaveBMP(inTex, inPath);
    00328           #else
    00329           #if FL_DEBUG_ERROR != 0
    00330           debugError("BMP textures not supported in this build.");
    00331           #endif
    00332           return false;
    00333           #endif
    00334      } else if(strcmp(tempExt, "wal") == 0) {
    00335           #if FL_TEXTURE_WAL != 0
    00336           return texSaveWAL(inTex, inPath);
    00337           #else
    00338           #if FL_DEBUG_ERROR != 0
    00339           debugError("WAL textures not supported in this build.");
    00340           #endif
    00341           return false;
    00342           #endif
    00343      } else if(strcmp(tempExt, "ftf") == 0) {
    00344           #if FL_TEXTURE_FTF != 0
    00345           return texSaveFTF(inTex, inPath);
    00346           #else
    00347           #if FL_DEBUG_ERROR != 0
    00348           debugError("FTF textures not supported in this build.");
    00349           #endif
    00350           return false;
    00351           #endif
    00352      } else if(strcmp(tempExt, "raw") == 0) {
    00353           #if FL_TEXTURE_FTF != 0
    00354           return texSaveRAW(inTex, inPath);
    00355           #else
    00356           #if FL_DEBUG_ERROR != 0
    00357           debugError("RAW textures not supported in this build.");
    00358           #endif
    00359           return false;
    00360           #endif
    00361      }
    00362
    00363      #if FL_DEBUG_WARNING != 0
    00364      debugWarning("Texture format \"%s\"not supported.", tempExt);
    00365      #endif
    00366
    00367      memFree(tempExt);
    00368
    00369      return false;
    00370 }
    00371
    00372 char* texPath(Texture* inTex) {
    00373      return texTreeFindPathByTex(inTex);
    00374 }
    00375
    00376 Texture* texCreate(u32 inWidth, u32 inHeight, u8 inPixelFormat) {
    00377      Texture* tempOut = (Texture*)memAlloc(sizeof(Texture));
    00378      if(!tempOut) {
    00379           #if FL_DEBUG_ERROR != 0
    00380           debugError("Couldn't create texture struct.\nOut of memory.");
    00381           #endif
    00382           return NULL;
    00383      }
    00384      tempOut->texWidth = inWidth;
    00385      tempOut->texHeight = inHeight;
    00386      tempOut->texPixelFormat = inPixelFormat;
    00387      tempOut->texDataWidth = getNextPower2(inWidth);
    00388      tempOut->texDataHeight = getNextPower2(inHeight);
    00389      tempOut->texStride = tempOut->texDataWidth;
    00390      tempOut->texUseCount = 1;
    00391      tempOut->texSwizzled = false;
    00392      tempOut->texMipMaps = 0;
    00393      #if FL_TEXTURE_PRESERVENONALPHA != 0
    00394      tempOut->texAlpha = true;
    00395      #endif
    00396
    00397      #if FL_TEXTURE_UNCACHED != 0
    00398      tempOut->texData = (char*)memAllocUncached(texDataSize(tempOut));
    00399      #else
    00400      tempOut->texData = (char*)memAlign(16, texDataSize(tempOut));
    00401      #endif
    00402
    00403      if(!tempOut->texData) {
    00404           #if FL_DEBUG_ERROR != 0
    00405           debugError("Couldn't create texture(%ux%u:%i).\nOut of memory.", (unsigned int)tempOut->texDataWidth, (unsigned int)tempOut->texDataHeight, texBPP(tempOut));
    00406           #endif
    00407           memFree(tempOut);
    00408           return NULL;
    00409      }
    00410      #if (FL_TEXTURE_UNCACHED != 0) && (FL_MEMORY == 0)
    00411      tempOut->texData = (char*)((unsigned int)tempOut->texData | 0x40000000);
    00412      sceKernelDcacheWritebackAll();
    00413      #endif
    00414      tempOut->texPalette = NULL;
    00415      memClear(tempOut->texMipData, 8);
    00416
    00417      if(tempOut->texDataWidth != inWidth) {
    00418           u32 j;
    00419           for(j = 0; j < inHeight; j++)
    00420                memClear(&tempOut->texData[(((j * tempOut->texDataWidth) + inWidth) * texBPP(tempOut)) >> 3], ((tempOut->texDataWidth - inWidth) * texBPP(tempOut)) >> 3);
    00421      }
    00422      if(tempOut->texDataHeight != inHeight)
    00423           memClear(&tempOut->texData[((inHeight * tempOut->texDataWidth) * texBPP(tempOut)) >> 3], ((tempOut->texDataWidth * (tempOut->texDataHeight - inHeight) * texBPP(tempOut)) >> 3));
    00424
    00425      return tempOut;
    00426 }
    00427
    00428 Texture* texCreateBlank(u32 inWidth, u32 inHeight, u8 inPixelFormat) {
    00429      Texture* tempOut = texCreate(inWidth, inHeight, inPixelFormat);
    00430      if(!tempOut)
    00431           return NULL;
    00432
    00433      memClear(tempOut->texData, ((tempOut->texDataHeight * tempOut->texDataWidth * texBPP(tempOut)) >> 3));
    00434
    00435      return tempOut;
    00436 }
    00437
    00438 #if FL_GRAPHICS != 0
    00439 bool texSwizzle(Texture* inTex) {
    00440      if(inTex->texSwizzled) {
    00441           #if FL_DEBUG_WARNING != 0
    00442           debugWarning("Trying to swizzle a swizzled texture.");
    00443           #endif
    00444           return false;
    00445      }
    00446
    00447      if(!graphicsSwizzleData((u8*)inTex->texData, inTex->texDataWidth, inTex->texHeight, inTex->texPixelFormat)) {
    00448           #if FL_DEBUG_WARNING != 0
    00449           debugWarning("Error swizzling texture.");
    00450           #endif
    00451           return false;
    00452      }
    00453
    00454      if(inTex->texMipMaps) {
    00455           u8 i;
    00456           for(i = 0; i < inTex->texMipMaps; i++) {
    00457                if(!inTex->texMipData[i] || !(inTex->texDataWidth >> (i + 1)) || (((inTex->texDataWidth * texBPP(inTex)) >> (i + 4)) & 15) || ((inTex->texDataHeight >> (i + 1)) & 7))
    00458                     break;
    00459                if(!graphicsSwizzleData((u8*)inTex->texMipData[i], (inTex->texDataWidth >> (i + 1)), (inTex->texDataHeight >> (i + 1)), inTex->texPixelFormat)) {
    00460                     #if FL_DEBUG_WARNING != 0
    00461                     debugWarning("Error swizzling texture mipmap %i.", i);
    00462                     #endif
    00463                     break;
    00464                }
    00465           }
    00466      }
    00467
    00468      inTex->texSwizzled = true;
    00469      return true;
    00470 }
    00471
    00472 bool texUnswizzle(Texture* inTex) {
    00473      if(!inTex->texSwizzled) {
    00474           #if FL_DEBUG_WARNING != 0
    00475           debugWarning("Trying to unswizzle an unswizzled texture.");
    00476           #endif
    00477           return false;
    00478      }
    00479
    00480      if(!graphicsUnswizzleData((u8*)inTex->texData, inTex->texDataWidth, inTex->texHeight, inTex->texPixelFormat)) {
    00481           #if FL_DEBUG_WARNING != 0
    00482           debugWarning("Error unswizzling texture.");
    00483           #endif
    00484           return false;
    00485      }
    00486
    00487      if(inTex->texMipMaps) {
    00488           u8 i;
    00489           for(i = 1; i <= inTex->texMipMaps; i++) {
    00490                if(!inTex->texMipData[i] || !(inTex->texDataWidth >> (i + 1)) || (((inTex->texDataWidth * texBPP(inTex)) >> (i + 4)) & 15) || ((inTex->texDataHeight >> (i + 1)) & 7))
    00491                     break;
    00492                if(!graphicsUnswizzleData((u8*)inTex->texMipData[i - 1], (inTex->texDataWidth >> i), (inTex->texDataHeight >> i), inTex->texPixelFormat)) {
    00493                     #if FL_DEBUG_WARNING != 0
    00494                     debugWarning("Error unswizzling texture mipmap %i.", i);
    00495                     #endif
    00496                     return false;
    00497                }
    00498           }
    00499      }
    00500
    00501      inTex->texSwizzled = false;
    00502      return true;
    00503 }
    00504 #endif
    00505
    00506 void texBind(Texture* inTex) {
    00507      if((!inTex) || (!inTex->texData)) {
    00508           #if FL_DEBUG_WARNING != 0
    00509           debugWarning("Trying to bind a NULL texture or a texture with NULL data.");
    00510           #endif
    00511           #if FL_TEXTURE_ERRORTEX != 0
    00512           inTex = texError;
    00513           #else
    00514           return;
    00515           #endif
    00516      } else if(texPalettized(inTex) && (inTex->texPalette == NULL)) {
    00517           #if FL_DEBUG_WARNING != 0
    00518           debugWarning("Trying to bind a palettized texture without a palette.");
    00519           #endif
    00520           #if FL_TEXTURE_ERRORTEX != 0
    00521           inTex = texError;
    00522           #else
    00523           return;
    00524           #endif
    00525      }
    00526
    00527      if(texPalettized(inTex))
    00528           palBind(inTex->texPalette);
    00529
    00530      if(texBound && (texBound == inTex->texData))
    00531           return;
    00532
    00533      sceGuTexMode(inTex->texPixelFormat, inTex->texMipMaps, 0, inTex->texSwizzled);
    00534      sceGuTexImage(0, inTex->texDataWidth, inTex->texDataHeight, inTex->texStride, (void*)inTex->texData);
    00535      if(inTex->texMipMaps) {
    00536           u8 i;
    00537           for(i = 1; i <= inTex->texMipMaps; i++)
    00538                sceGuTexImage(i, (inTex->texDataWidth >> i), (inTex->texDataHeight >> i), (inTex->texStride >> i), (void*)inTex->texMipData[i - 1]);
    00539      }
    00540
    00541      sceGuTexWrap(GU_REPEAT, GU_REPEAT);
    00542
    00543      texBound = inTex->texData;
    00544 }
    00545
    00546 void texFree(void* inTex) {
    00547      Texture* tempTex = (Texture*)inTex;
    00548
    00549      tempTex->texUseCount--;
    00550      if(tempTex->texUseCount)
    00551           return;
    00552
    00553      #if FL_MEMORY
    00554      if(tempTex) {
    00555           if(tempTex->texData == texBound)
    00556                texBound = NULL;
    00557           memFree(tempTex->texData);
    00558           if(tempTex->texMipMaps) {
    00559                u8 i;
    00560                for(i = 1; i <= tempTex->texMipMaps; i++)
    00561                     memFree(tempTex->texMipData[i - 1]);
    00562           }
    00563           if(tempTex->texPalette && !tempTex->texPalette->palGlobal)
    00564                palFree(tempTex->texPalette);
    00565           memFree(tempTex);
    00566      }
    00567      #else
    00568      if(tempTex) {
    00569           if(tempTex->texData) {
    00570                free(tempTex->texData);
    00571                if(tempTex->texData == texBound)
    00572                     texBound = NULL;
    00573           }
    00574           if(tempTex->texMipMaps) {
    00575                u8 i;
    00576                for(i = 1; i <= tempTex->texMipMaps; i++) {
    00577                     if(inTex->texMipData[i - 1])
    00578                          memFree(tempTex->texMipData[i - 1]);
    00579                }
    00580           }
    00581           if(tempTex->texPalette && !tempTex->texPalette->palGlobal)
    00582                palFree(tempTex->texPalette);
    00583           free(tempTex);
    00584      }
    00585      #endif
    00586
    00587      texTreeDelNodeByTex(tempTex);
    00588 }
    00589
    00590 int texMipMap(Texture* inTex, u8 inLevel) {
    00591      if(!inLevel)
    00592           return 0;
    00593      if(!inTex) {
    00594           #if FL_DEBUG_WARNING != 0
    00595           debugWarning("Trying to mipmap NULL texture.");
    00596           #endif
    00597           return -1;
    00598      }
    00599
    00600      inLevel = min(inLevel, 8);
    00601      while(!(inTex->texDataWidth >> inLevel) || !(inTex->texDataHeight >> inLevel))
    00602           inLevel--;
    00603
    00604      while(inTex->texMipMaps < inLevel) {
    00605           if(!texMipMapAdd(inTex))
    00606                break;
    00607      }
    00608      return inTex->texMipMaps;
    00609 }
    00610
    00611 bool texMipMapAdd(Texture* inTex) {
    00612      if(!inTex) {
    00613           #if FL_DEBUG_WARNING != 0
    00614           debugWarning("Trying to mipmap NULL texture.");
    00615           #endif
    00616           return false;
    00617      }
    00618      if(inTex->texMipMaps >= 8) {
    00619           #if FL_DEBUG_WARNING != 0
    00620           debugWarning("Trying to mipmap a fully mipmapped texture.");
    00621           #endif
    00622           return false;
    00623      }
    00624      #if FL_COLOR == 0
    00625      if(texPalettized(inTex) {
    00626           #if FL_DEBUG_DEVWARNING != 0
    00627           debugDevWarning("Mipmapping of paletted textures requires FL_COLOR.");
    00628           #endif
    00629           return false;
    00630      }
    00631      #endif
    00632
    00633      bool tempSwizzle = false;
    00634      if(inTex->texSwizzled) {
    00635           #if FL_DEBUG_DEVWARNING != 0
    00636           debugDevWarning("Mip-mapping swizzled textures requires them to be unswizzled, mip-mapped, then swizzled again.");
    00637           #endif
    00638           tempSwizzle = true;
    00639           texUnswizzle(inTex);
    00640      }
    00641
    00642
    00643      u8 tempLevel = (inTex->texMipMaps + 1);
    00644      u32 tempWidth = inTex->texDataWidth >> tempLevel;
    00645      u32 tempHeight = inTex->texDataHeight >> tempLevel;
    00646      if(!tempWidth || !tempHeight) {
    00647           #if FL_DEBUG_WARNING != 0
    00648           debugWarning("Trying to create mipmap smaller than a pixel.");
    00649           #endif
    00650           return false;
    00651      }
    00652      u32 tempDataSize = ((inTex->texDataWidth * inTex->texDataHeight * texBPP(inTex)) >> (3 + (tempLevel << 1)));
    00653
    00654      u8* tempMipMap = NULL;
    00655      u8* tempLastMip;
    00656      if(tempLevel == 1)
    00657           tempLastMip = (u8*)inTex->texData;
    00658      else
    00659           tempLastMip = (u8*)inTex->texMipData[tempLevel - 2];
    00660
    00661      bool tempVMem = false;
    00662      #if FL_MEMORY_VMEM != 0
    00663      tempVMem = vmemPointer(inTex->texData);
    00664      if(tempVMem)
    00665           tempMipMap = vmemAlloc(tempDataSize);
    00666      tempVMem = (tempMipMap != NULL);
    00667      #endif
    00668      if(!tempVMem)
    00669           tempMipMap = memAlign(16, tempDataSize);
    00670      if(!tempMipMap) {
    00671           #if FL_DEBUG_WARNING != 0
    00672           debugWarning("Couldn't allocate mip-map, probably out of memory.");
    00673           #endif
    00674           return false;
    00675      }
    00676
    00677      int i, j;
    00678      if(inTex->texPixelFormat == GU_PSM_8888) {
    00679           u32* tempMipMap32 = (u32*)tempMipMap;
    00680           u32* tempLastMip32 = (u32*)tempLastMip;
    00681           u32 tempMerge32[4];
    00682           for(j = 0; j < (inTex->texDataHeight >> tempLevel); j++) {
    00683                for(i = 0; i < tempWidth; i++) {
    00684                     tempMerge32[0] = tempLastMip32[(((j << 1) + 0) * (tempWidth << 1)) + ((i << 1) + 0)];
    00685                     tempMerge32[1] = tempLastMip32[(((j << 1) + 0) * (tempWidth << 1)) + ((i << 1) + 1)];
    00686                     tempMerge32[2] = tempLastMip32[(((j << 1) + 1) * (tempWidth << 1)) + ((i << 1) + 0)];
    00687                     tempMerge32[3] = tempLastMip32[(((j << 1) + 1) * (tempWidth << 1)) + ((i << 1) + 1)];
    00688                     tempMipMap32[(j * tempWidth) + i] = color8888_Merge4(tempMerge32[0], tempMerge32[1], tempMerge32[2], tempMerge32[3]);
    00689                }
    00690           }
    00691      } else if(inTex->texPixelFormat < GU_PSM_8888) {
    00692           u16* tempMipMap16 = (u16*)tempMipMap;
    00693           u16* tempLastMip16 = (u16*)tempLastMip;
    00694           u16 tempMerge16[4];
    00695           for(j = 0; j < (inTex->texDataHeight >> tempLevel); j++) {
    00696                for(i = 0; i < tempWidth; i++) {
    00697                     tempMerge16[0] = tempLastMip16[(((j << 1) + 0) * (tempWidth << 1)) + ((i << 1) + 0)];
    00698                     tempMerge16[1] = tempLastMip16[(((j << 1) + 0) * (tempWidth << 1)) + ((i << 1) + 1)];
    00699                     tempMerge16[2] = tempLastMip16[(((j << 1) + 1) * (tempWidth << 1)) + ((i << 1) + 0)];
    00700                     tempMerge16[3] = tempLastMip16[(((j << 1) + 1) * (tempWidth << 1)) + ((i << 1) + 1)];
    00701                     if(inTex->texPixelFormat == GU_PSM_4444)
    00702                          tempMipMap16[(j * tempWidth) + i] = color4444_Merge4(tempMerge16[0], tempMerge16[1], tempMerge16[2], tempMerge16[3]);
    00703                     else if(inTex->texPixelFormat == GU_PSM_5551)
    00704                          tempMipMap16[(j * tempWidth) + i] = color5551_Merge4(tempMerge16[0], tempMerge16[1], tempMerge16[2], tempMerge16[3]);
    00705                     else if(inTex->texPixelFormat == GU_PSM_5650)
    00706                          tempMipMap16[(j * tempWidth) + i] = color5650_Merge4(tempMerge16[0], tempMerge16[1], tempMerge16[2], tempMerge16[3]);
    00707                }
    00708           }
    00709      #if FL_COLOR != 0
    00710      } else if(inTex->texPixelFormat == GU_PSM_T8) { // TODO - Fix mipmapping of clut
    00711           int k, l;
    00712           tempLastMip = (u8*)inTex->texData;
    00713           if(inTex->texPalette->palPixelFormat == GU_PSM_8888) {
    00714                u32* tempPalEntries32 = (u32*)inTex->texPalette->palData;
    00715                u32 tempMerge32[(1 << tempLevel) * (1 << tempLevel)];
    00716                for(j = 0; j < (inTex->texDataHeight >> tempLevel); j++) {
    00717                     for(i = 0; i < tempWidth; i++) {
    00718                          for(k = 0; k < (1 << tempLevel); k++) {
    00719                               for(l = 0; l < (1 << tempLevel); l++) {
    00720                                    tempMerge32[(k * (1 << tempLevel)) + l] = tempPalEntries32[tempLastMip[(((j << tempLevel) + k) * inTex->texWidth) + ((i << tempLevel) + l)]];
    00721                               }
    00722                          }
    00723                          tempMipMap[(j * tempWidth) + i] = palClosestColor(inTex->texPalette, colorMergeN8888(tempMerge32, ((1 << tempLevel) * (1 << tempLevel))));
    00724                     }
    00725                }
    00726           } else {
    00727                u16* tempPalEntries16 = (u16*)inTex->texPalette->palData;
    00728                u16 tempMerge16[(1 << tempLevel) * (1 << tempLevel)];
    00729                for(j = 0; j < (inTex->texDataHeight >> tempLevel); j++) {
    00730                     for(i = 0; i < tempWidth; i++) {
    00731                          for(k = 0; k < (1 << tempLevel); k++) {
    00732                               for(l = 0; l < (1 << tempLevel); l++) {
    00733                                    tempMerge16[(k * (1 << tempLevel)) + l] = tempPalEntries16[tempLastMip[(((j << tempLevel) + k) * inTex->texWidth) + ((i << tempLevel) + l)]];
    00734                               }
    00735                          }
    00736                          if(inTex->texPalette->palPixelFormat == GU_PSM_4444)
    00737                               tempMipMap[(j * tempWidth) + i] = palClosestColor(inTex->texPalette, colorMergeN4444(tempMerge16, ((1 << tempLevel) * (1 << tempLevel))));
    00738                          else if(inTex->texPalette->palPixelFormat == GU_PSM_5551)
    00739                               tempMipMap[(j * tempWidth) + i] = palClosestColor(inTex->texPalette, colorMergeN5551(tempMerge16, ((1 << tempLevel) * (1 << tempLevel))));
    00740                          else if(inTex->texPalette->palPixelFormat == GU_PSM_5650)
    00741                               tempMipMap[(j * tempWidth) + i] = palClosestColor(inTex->texPalette, colorMergeN5650(tempMerge16, ((1 << tempLevel) * (1 << tempLevel))));
    00742                     }
    00743                }
    00744           }
    00745      } else if(inTex->texPixelFormat == GU_PSM_T4) {
    00746           memClear(tempMipMap, tempDataSize);
    00747           if(inTex->texPalette->palPixelFormat == GU_PSM_8888) {
    00748                u32* tempPalEntries32 = (u32*)inTex->texPalette->palData;
    00749                u32 tempMerge32[4];
    00750                for(j = 0; j < (inTex->texDataHeight >> tempLevel); j++) {
    00751                     for(i = 0; i < tempWidth; i++) {
    00752                          tempMerge32[0] = tempPalEntries32[tempLastMip[(((j << 1) + 0) * tempWidth) + i] & 0x0F];
    00753                          tempMerge32[1] = tempPalEntries32[(tempLastMip[(((j << 1) + 0) * tempWidth) + i] & 0xF0) >> 4];
    00754                          tempMerge32[2] = tempPalEntries32[tempLastMip[(((j << 1) + 1) * tempWidth) + i] & 0x0F];
    00755                          tempMerge32[3] = tempPalEntries32[(tempLastMip[(((j << 1) + 1) * tempWidth) + i] & 0xF0) >> 4];
    00756                          if(i & 1) {
    00757                               tempMipMap[(j * tempWidth) + i] += (palClosestColor(inTex->texPalette, color8888_Merge4(tempMerge32[0], tempMerge32[1], tempMerge32[2], tempMerge32[3])) << 4);
    00758                          } else {
    00759                               tempMipMap[(j * tempWidth) + i] = palClosestColor(inTex->texPalette, color8888_Merge4(tempMerge32[0], tempMerge32[1], tempMerge32[2], tempMerge32[3]));
    00760                          }
    00761                     }
    00762                }
    00763           } else {
    00764                u16* tempPalEntries16 = (u16*)inTex->texPalette->palData;
    00765                u16 tempMerge16[4];
    00766                for(j = 0; j < (inTex->texDataHeight >> tempLevel); j++) {
    00767                     for(i = 0; i < tempWidth; i++) {
    00768                          tempMerge16[0] = tempPalEntries16[tempLastMip[(((j << 1) + 0) * tempWidth) + i] & 0x0F];
    00769                          tempMerge16[1] = tempPalEntries16[(tempLastMip[(((j << 1) + 0) * tempWidth) + i] & 0xF0) >> 4];
    00770                          tempMerge16[2] = tempPalEntries16[tempLastMip[(((j << 1) + 1) * tempWidth) + i] & 0x0F];
    00771                          tempMerge16[3] = tempPalEntries16[(tempLastMip[(((j << 1) + 1) * tempWidth) + i] & 0xF0) >> 4];
    00772                          if(inTex->texPalette->palPixelFormat == GU_PSM_4444)
    00773                               tempMipMap[(j * tempWidth) + i] = palClosestColor(inTex->texPalette, color4444_Merge4(tempMerge16[0], tempMerge16[1], tempMerge16[2], tempMerge16[3]));
    00774                          else if(inTex->texPalette->palPixelFormat == GU_PSM_5551)
    00775                               tempMipMap[(j * tempWidth) + i] = palClosestColor(inTex->texPalette, color5551_Merge4(tempMerge16[0], tempMerge16[1], tempMerge16[2], tempMerge16[3]));
    00776                          else if(inTex->texPalette->palPixelFormat == GU_PSM_5650)
    00777                               tempMipMap[(j * tempWidth) + i] = palClosestColor(inTex->texPalette, color5650_Merge4(tempMerge16[0], tempMerge16[1], tempMerge16[2], tempMerge16[3]));
    00778                     }
    00779                }
    00780           }
    00781      #endif
    00782      } else {
    00783           #if FL_DEBUG_WARNING != 0
    00784           debugWarning("Can't mipmap textures with palettes of over 8 bits, or DXT compressed.");
    00785           #endif
    00786           return false;
    00787      }
    00788
    00789      inTex->texMipMaps = tempLevel;
    00790      inTex->texMipData[tempLevel - 1] = (char*)tempMipMap;
    00791
    00792      if(tempSwizzle)
    00793           texSwizzle(inTex);
    00794
    00795      if(memIsCachedPtr(tempMipMap)) {
    00796           if(tempDataSize > 16384)
    00797                sceKernelDcacheWritebackAll();
    00798           else
    00799                sceKernelDcacheWritebackRange(tempMipMap, tempDataSize);
    00800      }
    00801
    00802      return true;
    00803 }
    00804
    00805 Palette* palCreate(u32 inEntries, u8 inFormat, bool inGlobal) {
    00806      if(inFormat > GU_PSM_8888) {
    00807           #if FL_DEBUG_ERROR != 0
    00808           debugError("Trying to create a palette with incorrect format.\nDXT and palettized palettes are not supported.");
    00809           #endif
    00810           return NULL;
    00811      }
    00812      if(inEntries > 256) {
    00813           #if FL_DEBUG_ERROR != 0
    00814           debugError("Trying to create a palette with %u entries (Max: 256).", (unsigned int)inEntries);
    00815           #endif
    00816           return NULL;
    00817      }
    00818      #if FL_DEBUG_DEVWARNING != 0
    00819      if(!inEntries)
    00820           debugDevWarning("Creating palette with 0 entries.");
    00821      #endif
    00822      Palette* tempOut = (Palette*)memAlloc(sizeof(Palette));
    00823      if(!tempOut) {
    00824           #if FL_DEBUG_ERROR != 0
    00825           debugError("Couldn't create palette structure.\nOut of memory.");
    00826           #endif
    00827           return NULL;
    00828      }
    00829      tempOut->palEntries = getPaletteSize(inEntries);
    00830      tempOut->palPixelFormat = inFormat;
    00831      tempOut->palGlobal = inGlobal;
    00832      #if FL_MEMORY != 0
    00833      #if FL_TEXTURE_UNCACHED != 0
    00834      tempOut->palData = (char*)memAllocUncached((tempOut->palEntries * palBPP(tempOut)) >> 3);
    00835      #else
    00836      tempOut->palData = (char*)memAlign(16, ((tempOut->palEntries * palBPP(tempOut)) >> 3));
    00837      #endif
    00838      #else
    00839      tempOut->palData = (char*)memalign(16, ((tempOut->palEntries * palBPP(tempOut)) >> 3));
    00840      #endif
    00841      if(!tempOut->palData) {
    00842           #if FL_DEBUG_ERROR != 0
    00843           debugError("Couldn't create palette data.\nOut of memory");
    00844           #endif
    00845           memFree(tempOut);
    00846           return NULL;
    00847      }
    00848      #if (FL_TEXTURE_UNCACHED != 0) && (FL_MEMORY == 0)
    00849      tempOut->palData = (char*)((unsigned int)tempOut->palData | 0x40000000);
    00850      sceKernelDcacheWritebackAll();
    00851      #endif
    00852      if(tempOut->palEntries > inEntries)
    00853           memClear(&tempOut->palData[(inEntries * palBPP(tempOut)) >> 3], (((tempOut->palEntries - inEntries) * palBPP(tempOut)) >> 3));
    00854      #if FL_TEXTURE_UNCACHED == 0
    00855      sceKernelDcacheWritebackAll();
    00856      #endif
    00857      return tempOut;
    00858 }
    00859
    00860 void palFree(Palette* inPalette) {
    00861      #if FL_MEMORY != 0
    00862      memFree(inPalette->palData);
    00863      memFree(inPalette);
    00864      #else
    00865      if(!inPalette)
    00866           return;
    00867      if(inPalette->palData)
    00868           free(inPalette->palData);
    00869      free(inPalette);
    00870      #endif
    00871      if(inPalette == palBound)
    00872           palBound = NULL;
    00873 }
    00874
    00875 s32 palClosestColor(Palette* inPal, u32 inColor) {
    00876      if(!inPal) {
    00877           #if FL_DEBUG_WARNING != 0
    00878           debugWarning("Trying to find closest entry in NULL palette.");
    00879           #endif
    00880           return -1;
    00881      }
    00882      if(inPal->palPixelFormat > GU_PSM_8888) {
    00883           #if FL_DEBUG_WARNING != 0
    00884           debugWarning("Trying to find closest entry in invalid palette.");
    00885           #endif
    00886           return -2;
    00887      }
    00888      if(!inPal->palEntries) {
    00889           #if FL_DEBUG_WARNING != 0
    00890           debugWarning("Trying to find closest entry in palette with 0 entries.");
    00891           #endif
    00892           return -3;
    00893      }
    00894      u8 tempByPP = 4;
    00895      if(inPal->palPixelFormat != GU_PSM_8888) {
    00896           inColor &= 0x0000FFFF;
    00897           tempByPP = 2;
    00898      }
    00899      int i, tempCmp;
    00900      int tempClosest = 0;
    00901      int tempDiff = (1 << 30);
    00902      u32* tempColor32 = (u32*)inPal->palData;
    00903      u16* tempColor16 = (u16*)inPal->palData;
    00904      if(inPal->palPixelFormat == GU_PSM_8888) {
    00905           for(i = 0; i < inPal->palEntries; i++) {
    00906                if(tempColor32[i] == inColor) {
    00907                     return i;
    00908                } else {
    00909                     tempCmp = color8888_Cmp(inColor, tempColor32[i]);
    00910                     if(tempCmp < tempDiff) {
    00911                          tempClosest = i;
    00912                          tempDiff = tempCmp;
    00913                     }
    00914                }
    00915           }
    00916      } else if(inPal->palPixelFormat == GU_PSM_4444) {
    00917           for(i = 0; i < inPal->palEntries; i++) {
    00918                if(tempColor16[i] == inColor) {
    00919                     return i;
    00920                } else {
    00921                     tempCmp = color4444_Cmp(inColor, tempColor16[i]);
    00922                     if(tempCmp < tempDiff) {
    00923                          tempClosest = i;
    00924                          tempDiff = tempCmp;
    00925                     }
    00926                }
    00927           }
    00928      } else if(inPal->palPixelFormat == GU_PSM_5551) {
    00929           for(i = 0; i < inPal->palEntries; i++) {
    00930                if(tempColor16[i] == inColor) {
    00931                     return i;
    00932                } else {
    00933                     tempCmp = color5551_Cmp(inColor, tempColor16[i]);
    00934                     if(tempCmp < tempDiff) {
    00935                          tempClosest = i;
    00936                          tempDiff = tempCmp;
    00937                     }
    00938                }
    00939           }
    00940      } else if(inPal->palPixelFormat == GU_PSM_5650) {
    00941           for(i = 0; i < inPal->palEntries; i++) {
    00942                if(tempColor16[i] == inColor) {
    00943                     return i;
    00944                } else {
    00945                     tempCmp = color5650_Cmp(inColor, tempColor16[i]);
    00946                     if(tempCmp < tempDiff) {
    00947                          tempClosest = i;
    00948                          tempDiff = tempCmp;
    00949                     }
    00950                }
    00951           }
    00952      }
    00953      return tempClosest;
    00954 }
    00955
    00956 Palette* palCreateGrayscaleT8() {
    00957      Palette* tempOut = palCreate(256, GU_PSM_8888, false);
    00958      u8* tempData = (u8*)tempOut->palData;
    00959      int i;
    00960      for(i = 0; i < 256; i++) {
    00961           tempData[i << 2] = i;
    00962           tempData[(i << 2) + 1] = i;
    00963           tempData[(i << 2) + 2] = i;
    00964           tempData[(i << 2) + 3] = 0xFF;
    00965      }
    00966      #if FL_TEXTURE_UNCACHED == 0
    00967      sceKernelDcacheWritebackInvalidateAll();
    00968      #endif
    00969      return tempOut;
    00970 }
    00971
    00972 Palette* palCreateGrayscaleT4() {
    00973      Palette* tempOut = palCreate(16, GU_PSM_8888, false);
    00974      u8* tempData = (u8*)tempOut->palData;
    00975      int i;
    00976      for(i = 0; i < 16; i++) {
    00977           tempData[i << 2] = ((i * 0xFF) / 15);
    00978           tempData[(i << 2) + 1] = ((i * 0xFF) / 15);
    00979           tempData[(i << 2) + 2] = ((i * 0xFF) / 15);
    00980           tempData[(i << 2) + 3] = 0xFF;
    00981      }
    00982      #if FL_TEXTURE_UNCACHED == 0
    00983      sceKernelDcacheWritebackInvalidateAll();
    00984      #endif
    00985      return tempOut;
    00986 }
    00987
    00988 Palette* palCreateMonoT4(u32 inForeColor, u32 inBackColor) {
    00989      Palette* tempOut = palCreate(16, GU_PSM_8888, false);
    00990      u8* tempData = (u8*)tempOut->palData;
    00991      int i;
    00992      for(i = 0; i < 16; i++) {
    00993           tempData[i << 2] = (((i * (inForeColor & 0x000000FF)) + ((15 - i) * (inBackColor & 0x000000FF))) / 15);
    00994           tempData[(i << 2) + 1] = (((i * ((inForeColor & 0x0000FF00) >> 8)) + ((15 - i) * ((inBackColor & 0x0000FF00) >> 8))) / 15);
    00995           tempData[(i << 2) + 2] = (((i * ((inForeColor & 0x00FF0000) >> 16)) + ((15 - i) * ((inBackColor & 0x00FF0000) >> 16))) / 15);
    00996           tempData[(i << 2) + 3] = (((i * ((inForeColor & 0xFF000000) >> 24)) + ((15 - i) * ((inBackColor & 0xFF000000) >> 24))) / 15);
    00997      }
    00998      #if FL_TEXTURE_UNCACHED == 0
    00999      sceKernelDcacheWritebackInvalidateAll();
    01000      #endif
    01001      return tempOut;
    01002 }
    01003
    01004 Palette* palCreateDefaultColorT4() {
    01005      Palette* tempOut = palCreate(16, GU_PSM_8888, false);
    01006      u32* tempPalData = (u32*)tempOut->palData;
    01007      tempPalData[0]  = 0xFF000000; // Black
    01008      tempPalData[1]  = 0xFF7F7F7F; // Med. Gray
    01009      tempPalData[2]  = 0xFFCFCFCF; // Lig. Gray
    01010      tempPalData[3]  = 0xFFFFFFFF; // White
    01011      tempPalData[4]  = 0xFF00007F; // Dark Red
    01012      tempPalData[5]  = 0xFF0000FF; // Red
    01013      tempPalData[6]  = 0xFF007F7F; // Dark Yellow
    01014      tempPalData[7]  = 0xFF00FFFF; // Yellow
    01015      tempPalData[8]  = 0xFF007F00; // Dark Green
    01016      tempPalData[9]  = 0xFF00FF00; // Green
    01017      tempPalData[10] = 0xFF7F7F00; // Dark Turqoise
    01018      tempPalData[11] = 0xFFFFFF00; // Turqoise
    01019      tempPalData[12] = 0xFF7F0000; // Dark Blue
    01020      tempPalData[13] = 0xFFFF0000; // Blue
    01021      tempPalData[14] = 0xFF7F007F; // Dark Purple
    01022      tempPalData[15] = 0xFFFF00FF; // Purple
    01023      #if FL_TEXTURE_UNCACHED == 0
    01024      sceKernelDcacheWritebackInvalidateAll();
    01025      #endif
    01026      return tempOut;
    01027 }
    01028
    01029 Palette* palGrayscaleT8() {
    01030      if(!palGrayscaleT8Ptr) {
    01031           palGrayscaleT8Ptr = palCreateGrayscaleT8();
    01032           palGrayscaleT8Ptr->palGlobal = true;
    01033      }
    01034      return palGrayscaleT8Ptr;
    01035 }
    01036
    01037 Palette* palGrayscaleT4() {
    01038      if(!palGrayscaleT4Ptr) {
    01039           palGrayscaleT4Ptr = palCreateGrayscaleT4();
    01040           palGrayscaleT4Ptr->palGlobal = true;
    01041      }
    01042      return palGrayscaleT4Ptr;
    01043 }
    01044
    01045 Palette* palDefaultColorT4() {
    01046      if(!palDefaultColorT4Ptr) {
    01047           palDefaultColorT4Ptr = palCreateDefaultColorT4();
    01048           palDefaultColorT4Ptr->palGlobal = true;
    01049      }
    01050      return palDefaultColorT4Ptr;
    01051 }
    01052
    01053 #if FL_GRAPHICS != 0
    01054 Texture* texScreenshot() {
    01055      Texture* tempOut = texCreate(SCREEN_WIDTH, SCREEN_HEIGHT, GU_PSM_8888);
    01056      if(!tempOut) {
    01057           #if FL_DEBUG_ERROR != 0
    01058           debugError("Error creating screenshot.\nMost likely out of memory.");
    01059           #endif
    01060           return NULL;
    01061      }
    01062      u32 j;
    01063      #if FL_MEMORY != 0
    01064      char* tempDispBuffer = (char*)vmemAbsolutePtr(graphicsDispBuffer);
    01065      #else
    01066      char* tempDispBuffer = (char*)((unsigned int)graphicsDispBuffer | 0x04000000);
    01067      #endif
    01068      for(j = 0; j < SCREEN_HEIGHT; j++)
    01069           memCopy(&tempOut->texData[(j * tempOut->texDataWidth) << 2], &tempDispBuffer[(j * SCREEN_STRIDE) << 2], (SCREEN_WIDTH << 2));
    01070      #if FL_TEXTURE_UNCACHED == 0
    01071      sceKernelDcacheWritebackInvalidateAll();
    01072      #endif
    01073      #if FL_TEXTURE_PRESERVENONALPHA != 0
    01074      tempOut->texAlpha = false;
    01075      #endif
    01076      return tempOut;
    01077 }
    01078 #endif
    01079
    01080 #if FL_MEMORY_VMEM != 0
    01081 bool texMoveVMem(Texture* inTex) {
    01082      int tempSize = texDataSize(inTex);
    01083      void* tempVPtr = vmemAlloc(tempSize);
    01084      if(!tempVPtr) {
    01085           #if DEBUG_WARNING != 0
    01086           debugWarning("Couldn't move texture to vram\nProbably out of video memory.");
    01087           #endif
    01088           return false;
    01089      }
    01090      #if FL_GRAPHICS != 0
    01091      if(!graphicsFrame)
    01092           sceGuStart(GU_DIRECT, graphicsDisplayList);
    01093      sceGuCopyImage(inTex->texPixelFormat, 0, 0, inTex->texDataWidth, inTex->texDataHeight, inTex->texDataWidth, inTex->texData, 0, 0, inTex->texDataWidth, tempVPtr);
    01094      #else
    01095      memCopy(tempVPtr, inTex->texData, tempSize);
    01096      #endif
    01097      memFree(inTex->texData);
    01098      inTex->texData = tempVPtr;
    01099
    01100      //if(texPalettized(inTex))
    01101      //     palMoveVMem(inTex->texPalette);
    01102
    01103      u8 i;
    01104      if(inTex->texMipMaps) {
    01105           for(i = 1; i <= inTex->texMipMaps; i++) {
    01106                tempSize >>= 2;
    01107                tempVPtr = vmemAlloc(tempSize);
    01108                if(!tempVPtr) {
    01109                     #if FL_DEBUG_WARNING
    01110                     debugWarning("Couldn't copy all mip-maps to vram.");
    01111                     #endif
    01112                     return true;
    01113                }
    01114                #if FL_GRAPHICS != 0
    01115                sceGuCopyImage(inTex->texPixelFormat, 0, 0, (inTex->texDataWidth >> i), (inTex->texDataHeight >> i), (inTex->texDataWidth >> i), inTex->texMipData[i - 1], 0, 0, (inTex->texDataWidth >> i), tempVPtr);
    01116                #else
    01117                memCopy(tempVPtr, inTex->texMipData[i - 1], tempSize);
    01118                #endif
    01119                memFree(inTex->texMipData[i - 1]);
    01120                inTex->texMipData[i - 1] = tempVPtr;
    01121           }
    01122      }
    01123
    01124      #if FL_GRAPHICS != 0
    01125      if(!graphicsFrame)
    01126           sceGuFinish();
    01127      #endif
    01128
    01129      return true;
    01130 }
    01131
    01132 bool palMoveVMem(Palette* inPal) {
    01133      if(!inPal) {
    01134           #if DEBUG_WARNING != 0
    01135           debugWarning("Can't move NULL palette to vmem.");
    01136           #endif
    01137           return false;
    01138      }
    01139
    01140      void* tempVPtr = vmemAlloc((inPal->palEntries * palBPP(inPal)) >> 3);
    01141      if(!tempVPtr) {
    01142           #if DEBUG_WARNING != 0
    01143           debugWarning("Couldn't move palette to vram\nProbably out of video memory.");
    01144           #endif
    01145           return false;
    01146      }
    01147      #if FL_GRAPHICS != 0
    01148      if(!graphicsFrame)
    01149           sceGuStart(GU_DIRECT, graphicsDisplayList);
    01150      sceGuCopyImage(inPal->palPixelFormat, 0, 0, 8, (inPal->palEntries >> 3), 8, inPal->palData, 0, 0, 8, tempVPtr);
    01151      if(!graphicsFrame)
    01152           sceGuFinish();
    01153      #else
    01154      memCopy(tempVPtr, inPal->palData, ((inPal->palEntries * palBPP(inPal)) >> 3));
    01155      #endif
    01156
    01157      memFree(inPal->palData);
    01158
    01159      inPal->palData = tempVPtr;
    01160      return true;
    01161 }
    01162 #endif
    01163
    01164 u32 texPixel(Texture* inTex, int inX, int inY) {
    01165      while(inX < 0)
    01166           inX += inTex->texWidth;
    01167      while(inX > inTex->texWidth)
    01168           inX -= inTex->texWidth;
    01169      while(inY < 0)
    01170           inY += inTex->texHeight;
    01171      while(inY > inTex->texHeight)
    01172           inY -= inTex->texHeight;
    01173      u32 tempOut = 0;
    01174      if(texBPP(inTex) >= 8)
    01175          memCopy(&tempOut, &inTex->texData[(((inY * inTex->texDataWidth) + inX) * texBPP(inTex)) >> 3], (texBPP(inTex) >> 3));
    01176      else
    01177          tempOut= ((inTex->texData[(((inY * inTex->texDataWidth) + inX) * texBPP(inTex)) >> 3] & (0x0F << (inX & 1))) >> (inX & 1));
    01178      return tempOut;
    01179 }
    01180
    01181 /*void texAddMagMap(Texture* inTex) {
    01182      if(!inTex || !inTex->texData) {
    01183           #if FL_DEBUG_WARNING != 0
    01184           debugWarning("Trying to magnify a NULL texture or a texture with NULL data.");
    01185           #endif
    01186           return;
    01187      }
    01188      if(((inTex->texDataWidth << 1) > 512) || ((inTex->texDataHeight << 1) > 512)) {
    01189           #if FL_DEBUG_WARNING != 0
    01190           debugWarning("Trying to magnify a texture of dimensions (%ux%u:%u), this would overstep the 512x512 boundry.", (unsigned int)inTex->texWidth, (unsigned int)inTex->texHeight, (unsigned int)texBPP(inTex));
    01191           #endif
    01192           return;
    01193      }
    01194
    01195      u32 tempDataSize = (texDataSize(inTex) << 2);
    01196      u8* tempData = memAlloc(tempDataSize);
    01197
    01198      // TODO
    01199 }*/
    01200
    01201
    01202
    01203
    01204
    01205
    01206 // Texture tree functions.
    01207
    01208 bool texTreeAdd(char* inPath, Texture* inTex) {
    01209      if(!inPath || !inTex || !inPath[0])
    01210           return false;
    01211      texTreeNode* tempNodeAdd = (texTreeNode*)memAlloc(sizeof(texTreeNode));
    01212      if(!tempNodeAdd) {
    01213           #if FL_DEBUG_WARNING != 0
    01214           debugWarning("Unable to add texture to tree.\nProbably out of memory.");
    01215           #endif
    01216           return false;
    01217      }
    01218
    01219      strcpy(tempNodeAdd->texNodePath, inPath);
    01220      tempNodeAdd->texNodeData = inTex;
    01221      tempNodeAdd->texNodeNext[0] = NULL;
    01222      tempNodeAdd->texNodeNext[1] = NULL;
    01223
    01224      if(!texTree) {
    01225           texTree = tempNodeAdd;
    01226           return true;
    01227      }
    01228
    01229      texTreeNode* tempNode = texTree;
    01230      int tempCmp = 0;
    01231      while(flRunning) {
    01232           tempCmp = strcmp(inPath, tempNode->texNodePath);
    01233           if(!tempCmp) {
    01234                #if FL_DEBUG_WARNING != 0
    01235                debugWarning("Trying to add texture to tree, but texture is already in the tree.");
    01236                #endif
    01237                return false;
    01238           }
    01239           tempCmp = (tempCmp > 0 ? 1 : 0);
    01240           if(!tempNode->texNodeNext[tempCmp]) {
    01241                tempNode->texNodeNext[tempCmp] = tempNodeAdd;
    01242                return true;
    01243           }
    01244           tempNode = tempNode->texNodeNext[tempCmp];
    01245      }
    01246
    01247      return false;
    01248 }
    01249
    01250 Texture* texTreeFindTexByPath(char* inPath) {
    01251      if(!inPath || !inPath[0] || !texTree)
    01252           return NULL;
    01253      texTreeNode* tempNode = texTree;
    01254      int tempCmp = 0;
    01255      while(flRunning) {
    01256           tempCmp = strcmp(inPath, tempNode->texNodePath);
    01257           if(!tempCmp)
    01258                return tempNode->texNodeData;
    01259           tempCmp = (tempCmp > 0 ? 1 : 0);
    01260           if(!tempNode->texNodeNext[tempCmp])
    01261                return NULL;
    01262           tempNode = tempNode->texNodeNext[tempCmp];
    01263      }
    01264      return NULL;
    01265 }
    01266
    01267 texTreeNode* texTreeFindNodeByTexR(Texture* inTex, texTreeNode* inNode) {
    01268      if(!inNode)
    01269           return NULL;
    01270      if(inTex == inNode->texNodeData)
    01271           return inNode;
    01272      texTreeNode* tempOut = NULL;
    01273      if(inNode->texNodeNext[0]) {
    01274           tempOut = texTreeFindNodeByTexR(inTex, inNode->texNodeNext[0]);
    01275           if(tempOut)
    01276                return tempOut;
    01277      }
    01278      if(inNode->texNodeNext[1])
    01279           tempOut = texTreeFindNodeByTexR(inTex, inNode->texNodeNext[1]);
    01280      return tempOut;
    01281 }
    01282
    01283 char* texTreeFindPathByTex(Texture* inTex) {
    01284      if(!texTree || !inTex)
    01285           return NULL;
    01286      return texTreeFindNodeByTexR(inTex, texTree)->texNodePath;
    01287 }
    01288
    01289 texTreeNode* texTreeFindNodeByTex(Texture* inTex) {
    01290      if(!texTree || !inTex)
    01291           return NULL;
    01292      return texTreeFindNodeByTexR(inTex, texTree);
    01293 }
    01294
    01295 void texTreeAddR(texTreeNode* inNode) {
    01296      texTreeAdd(inNode->texNodePath, inNode->texNodeData);
    01297      if(inNode->texNodeNext[0])
    01298           texTreeAddR(inNode->texNodeNext[0]);
    01299      if(inNode->texNodeNext[1])
    01300           texTreeAddR(inNode->texNodeNext[1]);
    01301 }
    01302
    01303 void texTreeDelR(texTreeNode* inNode) {
    01304      if(inNode->texNodeNext[0])
    01305           texTreeDelR(inNode->texNodeNext[0]);
    01306      if(inNode->texNodeNext[1])
    01307           texTreeDelR(inNode->texNodeNext[1]);
    01308      free(inNode);
    01309 }
    01310
    01311 bool texTreeDelNodeByTex(Texture* inTex) {
    01312      if(!texTree || !inTex)
    01313           return false;
    01314      texTreeNode* tempNodeDel = texTreeFindNodeByTex(inTex);
    01315      if(!tempNodeDel) {
    01316           #if FL_DEBUG_WARNING != 0
    01317           debugWarning("Trying to delete non-existant texture node from tree.");
    01318           #endif
    01319           return false;
    01320      }
    01321      if(tempNodeDel->texNodeNext[0])
    01322           texTreeAddR(tempNodeDel->texNodeNext[0]);
    01323      if(tempNodeDel->texNodeNext[1])
    01324           texTreeAddR(tempNodeDel->texNodeNext[1]);
    01325      texTreeDelR(tempNodeDel);
    01326
    01327      return true;
    01328 }
    01329
    01330 #endif