/* Load a team colour mask texturepage into memory */ static bool dataTexPageTCMaskLoad(const char *fileName, void **ppData) { char texpage[PATH_MAX] = {'\0'}; // This hackery is needed, because fileName will include the directory name, whilst the LastResourceFilename will not, and we need a short name to identify the texpage sstrcpy(texpage, GetLastResourceFilename()); // Check if a corresponding texpage exists, exit if no pie_MakeTexPageName(texpage); ASSERT_OR_RETURN(false, resPresent(DT_TEXPAGE, texpage), "Corresponding texpage %s doesn't exists!", texpage); pie_MakeTexPageTCMaskName(texpage); if (!dataImageLoad(fileName, ppData)) { return false; } // see if this texture page has already been loaded if (resPresent(DT_TCMASK, texpage)) { // replace the old texture page with the new one debug(LOG_TEXTURE, "replacing %s with new tcmask %s", texpage, fileName); pie_ReplaceTexPage((iV_Image *)*ppData, texpage, getTextureSize(), false); } else { debug(LOG_TEXTURE, "adding page %s with tcmask %s", texpage, fileName); SetLastResourceFilename(texpage); pie_AddTexPage((iV_Image *)*ppData, texpage, 0, getTextureSize(), false); } return true; }
/** Retrieve the texture number for a given texture resource. * * @note We keep textures in a separate data structure _TEX_PAGE apart from the * normal resource system. * * @param filename The filename of the texture page to search for. * * @return a non-negative index number for the texture, negative if no texture * with the given filename could be found */ int iV_GetTexture(const char *filename) { unsigned int i = 0; iV_Image sSprite; char path[PATH_MAX]; /* Have we already loaded this one then? */ sstrcpy(path, filename); pie_MakeTexPageName(path); for (i = 0; i < iV_TEX_MAX; i++) { if (strncmp(path, _TEX_PAGE[i].name, iV_TEXNAME_MAX) == 0) { return i; } } // Try to load it sstrcpy(path, "texpages/"); sstrcat(path, filename); if (!iV_loadImage_PNG(path, &sSprite)) { debug(LOG_ERROR, "Failed to load %s", path); return -1; } sstrcpy(path, filename); pie_MakeTexPageName(path); return pie_AddTexPage(&sSprite, path, 0, -1, true); // FIXME, -1, use getTextureSize() }
/* Load a texturepage into memory */ static bool dataTexPageLoad(const char *fileName, void **ppData) { char texpage[PATH_MAX] = {'\0'}; // This hackery is needed, because fileName will include the directory name, whilst the LastResourceFilename will not, and we need a short name to identify the texpage sstrcpy(texpage, GetLastResourceFilename()); pie_MakeTexPageName(texpage); if (!dataImageLoad(fileName, ppData)) { return false; } // see if this texture page has already been loaded if (resPresent(DT_TEXPAGE, texpage)) { // replace the old texture page with the new one debug(LOG_TEXTURE, "replacing %s with new texture %s", texpage, fileName); (void) pie_ReplaceTexPage(*ppData, texpage, getTextureSize(), true); } else { debug(LOG_TEXTURE, "adding page %s with texture %s", texpage, fileName); SetLastResourceFilename(texpage); (void) pie_AddTexPage(*ppData, texpage, 0, getTextureSize(), true); } return true; }
bool replaceTexture(const QString &oldfile, const QString &newfile) { char tmpname[iV_TEXNAME_MAX]; // Load new one to replace it iV_Image image; if (!iV_loadImage_PNG(QString("texpages/" + newfile).toUtf8().constData(), &image)) { debug(LOG_ERROR, "Failed to load image: %s", newfile.toUtf8().constData()); return false; } sstrcpy(tmpname, oldfile.toUtf8().constData()); pie_MakeTexPageName(tmpname); // Have we already loaded this one? for (int i = 0; i < _TEX_PAGE.size(); i++) { if (strcmp(tmpname, _TEX_PAGE[i].name) == 0) { GL_DEBUG("Replacing texture"); debug(LOG_TEXTURE, "Replacing texture %s with %s from index %d (tex id %u)", _TEX_PAGE[i].name, newfile.toUtf8().constData(), i, _TEX_PAGE[i].id); sstrcpy(tmpname, newfile.toUtf8().constData()); pie_MakeTexPageName(tmpname); pie_AddTexPage(&image, tmpname, true, i); iV_unloadImage(&image); return true; } } iV_unloadImage(&image); debug(LOG_ERROR, "Nothing to replace!"); return false; }
/** Retrieve the texture number for a given texture resource. * * @note We keep textures in a separate data structure _TEX_PAGE apart from the * normal resource system. * * @param filename The filename of the texture page to search for. * @param compression If we need to load it, should we use texture compression? * * @return a non-negative index number for the texture, negative if no texture * with the given filename could be found */ int iV_GetTexture(const char *filename, bool compression) { iV_Image sSprite; char path[PATH_MAX]; /* Have we already loaded this one then? */ sstrcpy(path, filename); pie_MakeTexPageName(path); for (int i = 0; i < _TEX_PAGE.size(); i++) { if (strncmp(path, _TEX_PAGE[i].name, iV_TEXNAME_MAX) == 0) { return i; } } // Try to load it sstrcpy(path, "texpages/"); sstrcat(path, filename); if (!iV_loadImage_PNG(path, &sSprite)) { debug(LOG_ERROR, "Failed to load %s", path); return -1; } sstrcpy(path, filename); pie_MakeTexPageName(path); return pie_AddTexPage(&sSprite, path, compression); }
/************************************************************************** WRF files may specify overrides for the textures on a map. This is done through an ugly hack involving cutting the texture name down to just "page-NN", where NN is the page number, and replaceing the texture page with the same name if another file with this prefix is loaded. **************************************************************************/ int pie_ReplaceTexPage(iV_Image *s, const char *texPage, int maxTextureSize, bool useMipmaping) { int i = iV_GetTexture(texPage); ASSERT(i >= 0, "pie_ReplaceTexPage: Cannot find any %s to replace!", texPage); if (i < 0) { return -1; } glDeleteTextures(1, &_TEX_PAGE[i].id); debug(LOG_TEXTURE, "Reloading texture %s from index %d", texPage, i); _TEX_PAGE[i].name[0] = '\0'; pie_AddTexPage(s, texPage, i, maxTextureSize, useMipmaping); return i; }
static unsigned short LoadTextureFile(const char *FileName) { iV_Image *pSprite; unsigned int i; ASSERT_OR_RETURN( 0, resPresent("IMGPAGE", FileName), "Texture file \"%s\" not preloaded.", FileName); pSprite = (iV_Image*)resGetData("IMGPAGE", FileName); debug(LOG_TEXTURE, "Load texture from resource cache: %s (%d, %d)", FileName, pSprite->width, pSprite->height); /* Have we already uploaded this one? */ for (i = 0; i < _TEX_INDEX; ++i) { if (strcasecmp(FileName, _TEX_PAGE[i].name) == 0) { debug(LOG_TEXTURE, "LoadTextureFile: already uploaded"); return _TEX_PAGE[i].id; } } debug(LOG_TEXTURE, "LoadTextureFile: had to upload texture!"); return pie_AddTexPage(pSprite, FileName, 0, 0, true); }
IMAGEFILE *iV_LoadImageFile(const char *fileName) { // Find the directory of images. std::string imageDir = fileName; if (imageDir.find_last_of('.') != std::string::npos) { imageDir.erase(imageDir.find_last_of('.')); } imageDir += '/'; // Load the image list file. char *pFileData; unsigned pFileSize; if (!loadFile(fileName, &pFileData, &pFileSize)) { debug(LOG_ERROR, "iV_LoadImageFile: failed to open %s", fileName); return NULL; } char *ptr = pFileData; // count lines, which is identical to number of images int numImages = 0; while (ptr < pFileData + pFileSize && *ptr != '\0') { numImages += *ptr == '\n'; ++ptr; } IMAGEFILE *imageFile = new IMAGEFILE; imageFile->imageDefs.resize(numImages); imageFile->imageNames.resize(numImages); ImageMerge pageLayout; pageLayout.images.resize(numImages); ptr = pFileData; numImages = 0; while (ptr < pFileData + pFileSize) { int temp, retval; ImageDef *ImageDef = &imageFile->imageDefs[numImages]; char tmpName[256]; retval = sscanf(ptr, "%d,%d,%255[^\r\n\",]%n", &ImageDef->XOffset, &ImageDef->YOffset, tmpName, &temp); if (retval != 3) { debug(LOG_ERROR, "Bad line in \"%s\".", fileName); return NULL; } imageFile->imageNames[numImages].first = tmpName; imageFile->imageNames[numImages].second = numImages; std::string spriteName = imageDir + tmpName; ImageMergeRectangle *imageRect = &pageLayout.images[numImages]; imageRect->index = numImages; imageRect->data = new iV_Image; if (!iV_loadImage_PNG(spriteName.c_str(), imageRect->data)) { debug(LOG_ERROR, "Failed to find image \"%s\" listed in \"%s\".", spriteName.c_str(), fileName); return NULL; } imageRect->siz = Vector2i(imageRect->data->width, imageRect->data->height); numImages++; ptr += temp; while (ptr < pFileData + pFileSize && *ptr++ != '\n') {} // skip rest of line images.insert(tmpName, ImageDef); } free(pFileData); std::sort(imageFile->imageNames.begin(), imageFile->imageNames.end()); pageLayout.arrange(); // Arrange all the images onto texture pages (attempt to do so with as few pages as possible). imageFile->pages.resize(pageLayout.pages.size()); std::vector<iV_Image> ivImages(pageLayout.pages.size()); for (unsigned p = 0; p < pageLayout.pages.size(); ++p) { int size = pageLayout.pages[p]; ivImages[p].depth = 4; ivImages[p].width = size; ivImages[p].height = size; ivImages[p].bmp = (unsigned char *)malloc(size*size*4); // MUST be malloc, since this is free()d later by pie_AddTexPage(). memset(ivImages[p].bmp, 0x00, size*size*4); imageFile->pages[p].size = size; // Must set imageFile->pages[p].id later, after filling out ivImages[p].bmp. } for (std::vector<ImageMergeRectangle>::const_iterator r = pageLayout.images.begin(); r != pageLayout.images.end(); ++r) { imageFile->imageDefs[r->index].TPageID = r->page; imageFile->imageDefs[r->index].Tu = r->loc.x; imageFile->imageDefs[r->index].Tv = r->loc.y; imageFile->imageDefs[r->index].Width = r->siz.x; imageFile->imageDefs[r->index].Height = r->siz.y; // Copy image data onto texture page. iV_Image *srcImage = r->data; int srcDepth = srcImage->depth; int srcStride = srcImage->width*srcDepth; // Not sure whether to pad in the case that srcDepth ≠ 4, however this apparently cannot happen. unsigned char *srcBytes = srcImage->bmp + 0*srcDepth + 0*srcStride; iV_Image *dstImage = &ivImages[r->page]; int dstDepth = dstImage->depth; int dstStride = dstImage->width*dstDepth; unsigned char *dstBytes = dstImage->bmp + r->loc.x*dstDepth + r->loc.y*dstStride; Vector2i size = r->siz; unsigned char rgba[4] = {0x00, 0x00, 0x00, 0xFF}; for (int y = 0; y < size.y; ++y) for (int x = 0; x < size.x; ++x) { memcpy(rgba, srcBytes + x*srcDepth + y*srcStride, srcDepth); memcpy(dstBytes + x*dstDepth + y*dstStride, rgba, dstDepth); } // Finished reading the image data and copying it to the texture page, delete it. free(r->data->bmp); delete r->data; } // Debug usage only. Dump all images to disk (do mkdir images/, first). Doesn't dump the alpha channel, since the .ppm format doesn't support that. /*for (unsigned p = 0; p < pageLayout.pages.size(); ++p) { char fName[100]; sprintf(fName, "%s-%d", fileName, p); printf("Dump %s\n", fName); FILE *f = fopen(fName, "wb"); iV_Image *image = &ivImages[p]; fprintf(f, "P6\n%d %d\n255\n", image->width, image->height); for (int x = 0; x < image->width*image->height; ++x) if (fwrite(image->bmp + x*4, 3, 1, f) == 0) abort(); fclose(f); }*/ // Upload texture pages and free image data. for (unsigned p = 0; p < pageLayout.pages.size(); ++p) { char arbitraryName[256]; ssprintf(arbitraryName, "%s-%03u", fileName, p); // Now we can set imageFile->pages[p].id. This free()s the ivImages[p].bmp array! imageFile->pages[p].id = pie_AddTexPage(&ivImages[p], arbitraryName, 0, 0, true); } // duplicate some data, since we want another access point to these data structures now, FIXME for (unsigned i = 0; i < imageFile->imageDefs.size(); i++) { imageFile->imageDefs[i].textureId = imageFile->pages[imageFile->imageDefs[i].TPageID].id; imageFile->imageDefs[i].invTextureSize = 1.f / imageFile->pages[imageFile->imageDefs[i].TPageID].size; } files.append(imageFile); return imageFile; }