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. * * @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() }
/** 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); }
void GFX::loadTexture(const char *filename, GLenum filter) { const char *extension = strrchr(filename, '.'); // determine the filetype iV_Image image; if (!extension || strcmp(extension, ".png") != 0) { debug(LOG_ERROR, "Bad image filename: %s", filename); return; } if (iV_loadImage_PNG(filename, &image)) { makeTexture(image.width, image.height, filter, iV_getPixelFormat(&image), image.bmp); iV_unloadImage(&image); } }
/*! * Load an image from file */ static bool dataImageLoad(const char *fileName, void **ppData) { iV_Image *psSprite = (iV_Image *)malloc(sizeof(iV_Image)); if (!psSprite) { return false; } if (!iV_loadImage_PNG(fileName, psSprite)) { debug( LOG_ERROR, "IMGPAGE load failed" ); return false; } *ppData = psSprite; return true; }
/** init_system_ColorCursor()-- Create a colored mouse cursor image */ SDL_Cursor *init_system_ColorCursor(CURSOR cur, const char *fileName) { iV_Image *psSprite = (iV_Image *)malloc(sizeof(iV_Image)); if (!psSprite) { debug(LOG_FATAL, "Could not allocate memory for cursor sprite. Exiting."); exit(-1); } if (!iV_loadImage_PNG(fileName, psSprite)) { debug(LOG_FATAL, "Could not load cursor sprite. Exiting."); exit(-1); } #if SDL_BYTEORDER == SDL_BIG_ENDIAN uint32_t rmask = 0xff000000; uint32_t gmask = 0x00ff0000; uint32_t bmask = 0x0000ff00; uint32_t amask = 0x000000ff; #else uint32_t rmask = 0x000000ff; uint32_t gmask = 0x0000ff00; uint32_t bmask = 0x00ff0000; uint32_t amask = 0xff000000; #endif SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(psSprite->bmp, psSprite->width, psSprite->height, psSprite->depth * 8, psSprite->width * 4, rmask, gmask, bmask, amask); SDL_Cursor *pointer = SDL_CreateColorCursor(surface, psSprite->width / 2, psSprite->height / 2); // We center the hotspot for all (FIXME ?) if (!pointer) { debug(LOG_FATAL, "Could not create cursor because %s", SDL_GetError()); exit(-1); } // free up image & surface data free(psSprite->bmp); free(psSprite); SDL_FreeSurface(surface); return pointer; }
void screen_SetBackDropFromFile(const char* filename) { // HACK : We should use a resource handler here! const char *extension = strrchr(filename, '.');// determine the filetype iV_Image image; if(!extension) { debug(LOG_ERROR, "Image without extension: \"%s\"!", filename); return; // filename without extension... don't bother } // Make sure the current texture page is reloaded after we are finished // Otherwise WZ will think it is still loaded and not load it again pie_SetTexturePage(TEXPAGE_EXTERN); if( strcmp(extension,".png") == 0 ) { if (iV_loadImage_PNG( filename, &image ) ) { if (~backDropTexture == 0) glGenTextures(1, &backDropTexture); glBindTexture(GL_TEXTURE_2D, backDropTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, iV_getPixelFormat(&image), GL_UNSIGNED_BYTE, image.bmp); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); iV_unloadImage(&image); } return; } else debug(LOG_ERROR, "Unknown extension \"%s\" for image \"%s\"!", extension, filename); }
bool texLoad(const char *fileName) { char fullPath[PATH_MAX], partialPath[PATH_MAX], *buffer; unsigned int i, j, k, size; int texPage; GLint glval; firstPage = _TEX_INDEX; ASSERT_OR_RETURN(false, _TEX_INDEX < iV_TEX_MAX, "Too many texture pages used"); ASSERT_OR_RETURN(false, MIPMAP_MAX == TILE_WIDTH && MIPMAP_MAX == TILE_HEIGHT, "Bad tile sizes"); // store the filename so we can later determine which tileset we are using if (tileset) free(tileset); tileset = strdup(fileName); // reset defaults mipmap_max = MIPMAP_MAX; mipmap_levels = MIPMAP_LEVELS; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glval); while (glval < mipmap_max * TILES_IN_PAGE_COLUMN) { mipmap_max /= 2; mipmap_levels--; debug(LOG_ERROR, "Max supported texture size %dx%d is too low - reducing texture detail to %dx%d.", (int)glval, (int)glval, mipmap_max, mipmap_max); ASSERT(mipmap_levels > 0, "Supported texture size %d is too low to load any mipmap levels!", (int)glval); if (mipmap_levels == 0) { exit(1); } } while (maxTextureSize < mipmap_max) { mipmap_max /= 2; mipmap_levels--; debug(LOG_TEXTURE, "Downgrading texture quality to %d due to user setting %d", mipmap_max, maxTextureSize); } /* Get and set radar colours */ sprintf(fullPath, "%s.radar", fileName); if (!loadFile(fullPath, &buffer, &size)) { debug(LOG_FATAL, "texLoad: Could not find radar colours at %s", fullPath); abort(); // cannot recover; we could possibly generate a random palette? } i = 0; // tile j = 0; // place in buffer do { unsigned int r, g, b; int cnt = 0; k = sscanf(buffer + j, "%2x%2x%2x%n", &r, &g, &b, &cnt); j += cnt; if (k >= 3) { radarColour(i, r, g, b); } i++; // next tile } while (k >= 3 && j + 6 < size); free(buffer); /* Now load the actual tiles */ i = mipmap_max; // i is used to keep track of the tile dimensions for (j = 0; j < mipmap_levels; j++) { int xOffset = 0, yOffset = 0; // offsets into the texture atlas int xSize = 1; int ySize = 1; const int xLimit = TILES_IN_PAGE_COLUMN * i; const int yLimit = TILES_IN_PAGE_ROW * i; // pad width and height into ^2 values while (xLimit > (xSize *= 2)) {} while (yLimit > (ySize *= 2)) {} // Generate the empty texture buffer in VRAM texPage = newPage(fileName, j, xSize, ySize, 0); sprintf(partialPath, "%s-%d", fileName, i); // Load until we cannot find anymore of them for (k = 0; k < MAX_TILES; k++) { iV_Image tile; sprintf(fullPath, "%s/tile-%02d.png", partialPath, k); if (PHYSFS_exists(fullPath)) // avoid dire warning { bool retval = iV_loadImage_PNG(fullPath, &tile); ASSERT_OR_RETURN(false, retval, "Could not load %s!", fullPath); } else { // no more textures in this set ASSERT_OR_RETURN(false, k > 0, "Could not find %s", fullPath); break; } // Insert into texture page glTexSubImage2D(GL_TEXTURE_2D, j, xOffset, yOffset, tile.width, tile.height, GL_RGBA, GL_UNSIGNED_BYTE, tile.bmp); free(tile.bmp); if (i == mipmap_max) // dealing with main texture page; so register coordinates { tileTexInfo[k].uOffset = (float)xOffset / (float)xSize; tileTexInfo[k].vOffset = (float)yOffset / (float)ySize; tileTexInfo[k].texPage = texPage; debug(LOG_TEXTURE, " texLoad: Registering k=%d i=%d u=%f v=%f xoff=%d yoff=%d xsize=%d ysize=%d tex=%d (%s)", k, i, tileTexInfo[k].uOffset, tileTexInfo[k].vOffset, xOffset, yOffset, xSize, ySize, texPage, fullPath); } xOffset += i; // i is width of tile if (xOffset + i > xLimit) { yOffset += i; // i is also height of tile xOffset = 0; } if (yOffset + i > yLimit) { /* Change to next texture page */ xOffset = 0; yOffset = 0; debug(LOG_TEXTURE, "texLoad: Extra page added at %d for %s, was page %d, opengl id %u", k, partialPath, texPage, (unsigned int)_TEX_PAGE[texPage].id); texPage = newPage(fileName, j, xSize, ySize, k); } } debug(LOG_TEXTURE, "texLoad: Found %d textures for %s mipmap level %d, added to page %d, opengl id %u", k, partialPath, i, texPage, (unsigned int)_TEX_PAGE[texPage].id); i /= 2; // halve the dimensions for the next series; OpenGL mipmaps start with largest at level zero } return 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; }