diff options
Diffstat (limited to 'Minecraft.Client/Textures.cpp')
| -rw-r--r-- | Minecraft.Client/Textures.cpp | 1404 |
1 files changed, 1404 insertions, 0 deletions
diff --git a/Minecraft.Client/Textures.cpp b/Minecraft.Client/Textures.cpp new file mode 100644 index 00000000..ce7a9bfc --- /dev/null +++ b/Minecraft.Client/Textures.cpp @@ -0,0 +1,1404 @@ +#include "stdafx.h" +#include "Textures.h" +#include "TexturePackRepository.h" +#include "HttpTexture.h" +#include "MemTexture.h" +#include "..\Minecraft.World\InputStream.h" +#include "..\Minecraft.World\IntBuffer.h" +#include "..\Minecraft.World\ByteBuffer.h" +#include "TexturePack.h" +#include "Options.h" +#include "..\Minecraft.Client\MemTextureProcessor.h" +#include "MobSkinMemTextureProcessor.h" +#include "PreStitchedTextureMap.h" +#include "StitchedTexture.h" +#include "Texture.h" +#include "..\Minecraft.World\net.minecraft.world.h" +#include "..\Minecraft.World\net.minecraft.world.level.h" +#include "..\Minecraft.World\StringHelpers.h" + +bool Textures::MIPMAP = true; +C4JRender::eTextureFormat Textures::TEXTURE_FORMAT = C4JRender::TEXTURE_FORMAT_RxGyBzAw; + +int Textures::preLoadedIdx[TN_COUNT]; +wchar_t *Textures::preLoaded[TN_COUNT] = +{ + L"%blur%misc/pumpkinblur", +// L"%blur%/misc/vignette", // Not currently used + L"%clamp%misc/shadow", +// L"/achievement/bg", // Not currently used + L"art/kz", + L"environment/clouds", + L"environment/rain", + L"environment/snow", + L"gui/gui", + L"gui/icons", + L"item/arrows", + L"item/boat", + L"item/cart", + L"item/sign", + L"misc/mapbg", + L"misc/mapicons", + L"misc/water", + L"misc/footprint", + L"mob/saddle", + L"mob/sheep_fur", + L"mob/spider_eyes", + L"particles", + L"mob/chicken", + L"mob/cow", + L"mob/pig", + L"mob/sheep", + L"mob/squid", + L"mob/wolf", + L"mob/wolf_tame", + L"mob/wolf_angry", + L"mob/creeper", + L"mob/ghast", + L"mob/ghast_fire", + L"mob/zombie", + L"mob/pigzombie", + L"mob/skeleton", + L"mob/slime", + L"mob/spider", + L"mob/char", + L"mob/char1", + L"mob/char2", + L"mob/char3", + L"mob/char4", + L"mob/char5", + L"mob/char6", + L"mob/char7", + L"terrain/moon", + L"terrain/sun", + L"armor/power", + + // 1.8.2 + L"mob/cavespider", + L"mob/enderman", + L"mob/silverfish", + L"mob/enderman_eyes", + L"misc/explosion", + L"item/xporb", + L"item/chest", + L"item/largechest", + + // 1.3.2 + L"item/enderchest", + + // 1.0.1 + L"mob/redcow", + L"mob/snowman", + L"mob/enderdragon/ender", + L"mob/fire", + L"mob/lava", + L"mob/villager/villager", + L"mob/villager/farmer", + L"mob/villager/librarian", + L"mob/villager/priest", + L"mob/villager/smith", + L"mob/villager/butcher", + L"mob/enderdragon/crystal", + L"mob/enderdragon/shuffle", + L"mob/enderdragon/beam", + L"mob/enderdragon/ender_eyes", + L"%blur%misc/glint", + L"item/book", + L"misc/tunnel", + L"misc/particlefield", + L"terrain/moon_phases", + + // 1.2.3 + L"mob/ozelot", + L"mob/cat_black", + L"mob/cat_red", + L"mob/cat_siamese", + L"mob/villager_golem", + L"mob/skeleton_wither", + + // TU 14 + L"mob/wolf_collar", + L"mob/zombie_villager", + +#ifdef _LARGE_WORLDS + L"misc/additionalmapicons", +#endif + + L"font/Default", + L"font/alternate", + + // skin packs +/* L"/SP1", + L"/SP2", + L"/SP3", + L"/SPF", + + // themes + L"/ThSt", + L"/ThIr", + L"/ThGo", + L"/ThDi", + + // gamerpics + L"/GPAn", + L"/GPCo", + L"/GPEn", + L"/GPFo", + L"/GPTo", + L"/GPBA", + L"/GPFa", + L"/GPME", + L"/GPMF", + L"/GPMM", + L"/GPSE", + + // avatar items + + L"/AH_0006", + L"/AH_0003", + L"/AH_0007", + L"/AH_0005", + L"/AH_0004", + L"/AH_0001", + L"/AH_0002", + L"/AT_0001", + L"/AT_0002", + L"/AT_0003", + L"/AT_0004", + L"/AT_0005", + L"/AT_0006", + L"/AT_0007", + L"/AT_0008", + L"/AT_0009", + L"/AT_0010", + L"/AT_0011", + L"/AT_0012", + L"/AP_0001", + L"/AP_0002", + L"/AP_0003", + L"/AP_0004", + L"/AP_0005", + L"/AP_0006", + L"/AP_0007", + L"/AP_0009", + L"/AP_0010", + L"/AP_0011", + L"/AP_0012", + L"/AP_0013", + L"/AP_0014", + L"/AP_0015", + L"/AP_0016", + L"/AP_0017", + L"/AP_0018", + L"/AA_0001", + L"/AT_0013", + L"/AT_0014", + L"/AT_0015", + L"/AT_0016", + L"/AT_0017", + L"/AT_0018", + L"/AP_0019", + L"/AP_0020", + L"/AP_0021", + L"/AP_0022", + L"/AP_0023", + L"/AH_0008", + L"/AH_0009",*/ + + L"gui/items", + L"terrain", +}; + +Textures::Textures(TexturePackRepository *skins, Options *options) +{ +// pixels = MemoryTracker::createIntBuffer(2048 * 2048); // 4J removed - now just creating this buffer when we need it + missingNo = new BufferedImage(16, 16, BufferedImage::TYPE_INT_ARGB); + + this->skins = skins; + this->options = options; + + /* 4J - TODO, maybe... + Graphics g = missingNo.getGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, 64, 64); + g.setColor(Color.BLACK); + int y = 10; + int i = 0; + while (y < 64) { + String text = (i++ % 2 == 0) ? "missing" : "texture"; + g.drawString(text, 1, y); + y += g.getFont().getSize(); + if (i % 2 == 0) y += 5; + } + + g.dispose(); + */ + + // 4J Stu - Changed these to our PreStitchedTextureMap from TextureMap + terrain = new PreStitchedTextureMap(Icon::TYPE_TERRAIN, L"terrain", L"textures/blocks/", missingNo, true); + items = new PreStitchedTextureMap(Icon::TYPE_ITEM, L"items", L"textures/items/", missingNo, true); + + // 4J - added - preload a set of commonly used textures that can then be referenced directly be an enumerated type rather by string + loadIndexedTextures(); +} + +void Textures::loadIndexedTextures() +{ + // 4J - added - preload a set of commonly used textures that can then be referenced directly be an enumerated type rather by string + for( int i = 0; i < TN_COUNT - 2; i++ ) + { + preLoadedIdx[i] = loadTexture((TEXTURE_NAME)i, wstring(preLoaded[i]) + L".png"); + } +} + +intArray Textures::loadTexturePixels(TEXTURE_NAME texId, const wstring& resourceName) +{ + TexturePack *skin = skins->getSelected(); + + { + intArray id = pixelsMap[resourceName]; + // 4J - if resourceName isn't in the map, it should add an element and as that will use the default constructor, its + // internal data pointer will be NULL + if (id.data != NULL) return id; + } + + // 4J - removed try/catch +// try { + intArray res; + //wstring in = skin->getResource(resourceName); + if (false)// 4J - removed - was ( in == NULL) + { + res = loadTexturePixels(missingNo); + } + else + { + BufferedImage *bufImage = readImage(texId, resourceName); //in); + res = loadTexturePixels(bufImage); + delete bufImage; + } + + pixelsMap[resourceName] = res; + return res; +/* +} + catch (IOException e) { + e.printStackTrace(); + int[] res = loadTexturePixels(missingNo); + pixelsMap.put(resourceName, res); + return res; + } + */ +} + +intArray Textures::loadTexturePixels(BufferedImage *img) +{ + int w = img->getWidth(); + int h = img->getHeight(); + intArray pixels(w*h); + return loadTexturePixels(img, pixels); +} + +intArray Textures::loadTexturePixels(BufferedImage *img, intArray pixels) +{ + int w = img->getWidth(); + int h = img->getHeight(); + img->getRGB(0, 0, w, h, pixels, 0, w); + return pixels; +} + +int Textures::loadTexture(int idx) +{ + if( idx == -1 ) + { + return 0; + } + else + { + if ( idx == TN_TERRAIN ) + { + terrain->getStitchedTexture()->bind(0); + return terrain->getStitchedTexture()->getGlId(); + } + if ( idx == TN_GUI_ITEMS) + { + items->getStitchedTexture()->bind(0); + return items->getStitchedTexture()->getGlId(); + } + return preLoadedIdx[idx]; + } +} + +// 4J added - textures default to standard 32-bit RGBA format, but where we can, use an 8-bit format. There's 3 different varieties of these currently +// in the renderer that map the single 8-bit channel to RGBA differently. +void Textures::setTextureFormat(const wstring& resourceName) +{ + // 4J Stu - These texture formats are not currently in the render header +#ifdef _XBOX + if(resourceName == L"/environment/clouds.png") + { + TEXTURE_FORMAT = C4JRender::TEXTURE_FORMAT_R1G1B1Ax; + } + else if(resourceName == L"%blur%/misc/pumpkinblur.png") + { + TEXTURE_FORMAT = C4JRender::TEXTURE_FORMAT_R0G0B0Ax; + } + else if(resourceName == L"%clamp%/misc/shadow.png") + { + TEXTURE_FORMAT = C4JRender::TEXTURE_FORMAT_R0G0B0Ax; + } + else if(resourceName == L"/environment/snow.png") + { + TEXTURE_FORMAT = C4JRender::TEXTURE_FORMAT_RxGxBxAx; + } + else if(resourceName == L"/1_2_2/misc/explosion.png") + { + TEXTURE_FORMAT = C4JRender::TEXTURE_FORMAT_RxGxBxAx; + } + else +#endif + { + TEXTURE_FORMAT = C4JRender::TEXTURE_FORMAT_RxGyBzAw; + } +} + +void Textures::bindTexture(const wstring &resourceName) +{ + bind(loadTexture(TN_COUNT,resourceName)); +} + +// 4J Added +void Textures::bindTexture(int resourceId) +{ + bind(loadTexture(resourceId)); +} + +void Textures::bind(int id) +{ + //if (id != lastBoundId) + { + if(id < 0) return; + glBindTexture(GL_TEXTURE_2D, id); + // lastBoundId = id; + } +} + +void Textures::clearLastBoundId() +{ + lastBoundId = -1; +} + +int Textures::loadTexture(TEXTURE_NAME texId, const wstring& resourceName) +{ +// char buf[256]; +// wcstombs(buf, resourceName.c_str(), 256); +// printf("Textures::loadTexture name - %s\n",buf); + + //if (resourceName.compare(L"/terrain.png") == 0) + //{ + // terrain->getStitchedTexture()->bind(0); + // return terrain->getStitchedTexture()->getGlId(); + //} + //if (resourceName.compare(L"/gui/items.png") == 0) + //{ + // items->getStitchedTexture()->bind(0); + // return items->getStitchedTexture()->getGlId(); + //} + + // If the texture is not present in the idMap, load it, otherwise return its id + + { + bool inMap = ( idMap.find(resourceName) != idMap.end() ); + int id = idMap[resourceName]; + if (inMap) return id; + } + + wstring pathName = resourceName; + + // 4J - added special cases to avoid mipmapping on clouds & shadows + if( (resourceName == L"environment/clouds.png") || + (resourceName == L"%clamp%misc/shadow.png") || + (resourceName == L"%blur%misc/pumpkinblur.png") || + (resourceName == L"%clamp%misc/shadow.png") || + (resourceName == L"gui/icons.png" ) || + (resourceName == L"gui/gui.png" ) || + (resourceName == L"misc/footprint.png") ) + { + MIPMAP = false; + } + setTextureFormat(resourceName); + + // 4J - removed try/catch +// try { + int id = MemoryTracker::genTextures(); + + + wstring prefix = L"%blur%"; + bool blur = resourceName.substr(0, prefix.size()).compare(prefix) == 0; //resourceName.startsWith("%blur%"); + if (blur) pathName = resourceName.substr(6); + + prefix = L"%clamp%"; + bool clamp = resourceName.substr(0, prefix.size()).compare(prefix) == 0; //resourceName.startsWith("%clamp%"); + if (clamp) pathName = resourceName.substr(7); + + //wstring in = skins->getSelected()->getResource(pathName); + if (false ) // 4J - removed was ( in == NULL) + { + loadTexture(missingNo, id, blur, clamp); + } + else + { + // 4J Stu - Get resource above just returns the name for texture packs + BufferedImage *bufImage = readImage(texId, pathName); //in); + loadTexture(bufImage, id, blur, clamp); + delete bufImage; + } + + idMap[resourceName] = id; + MIPMAP = true; // 4J added + TEXTURE_FORMAT = C4JRender::TEXTURE_FORMAT_RxGyBzAw; + return id; + /* + } catch (IOException e) { + e.printStackTrace(); + MemoryTracker.genTextures(ib); + int id = ib.get(0); + loadTexture(missingNo, id); + idMap.put(resourceName, id); + return id; + } + */ +} + +int Textures::getTexture(BufferedImage *img, C4JRender::eTextureFormat format, bool mipmap) +{ + int id = MemoryTracker::genTextures(); + TEXTURE_FORMAT = format; + MIPMAP = mipmap; + loadTexture(img, id); + TEXTURE_FORMAT = C4JRender::TEXTURE_FORMAT_RxGyBzAw; + MIPMAP = true; + loadedImages[id] = img; + return id; +} + +void Textures::loadTexture(BufferedImage *img, int id) +{ +// printf("Textures::loadTexture BufferedImage %d\n",id); + + loadTexture(img, id, false, false); +} + +void Textures::loadTexture(BufferedImage *img, int id, bool blur, bool clamp) +{ +// printf("Textures::loadTexture BufferedImage with blur and clamp %d\n",id); + int iMipLevels=1; + MemSect(33); + glBindTexture(GL_TEXTURE_2D, id); + + if (MIPMAP) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + /* + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); + */ + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + if (blur) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + if (clamp) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + + int w = img->getWidth(); + int h = img->getHeight(); + + intArray rawPixels(w*h); + img->getRGB(0, 0, w, h, rawPixels, 0, w); + + if (options != NULL && options->anaglyph3d) + { + rawPixels = anaglyph(rawPixels); + } + + byteArray newPixels(w * h * 4); + for (unsigned int i = 0; i < rawPixels.length; i++) + { + int a = (rawPixels[i] >> 24) & 0xff; + int r = (rawPixels[i] >> 16) & 0xff; + int g = (rawPixels[i] >> 8) & 0xff; + int b = (rawPixels[i]) & 0xff; + +#ifdef _XBOX + newPixels[i * 4 + 0] = (byte) a; + newPixels[i * 4 + 1] = (byte) r; + newPixels[i * 4 + 2] = (byte) g; + newPixels[i * 4 + 3] = (byte) b; +#else + newPixels[i * 4 + 0] = (byte) r; + newPixels[i * 4 + 1] = (byte) g; + newPixels[i * 4 + 2] = (byte) b; + newPixels[i * 4 + 3] = (byte) a; +#endif + } + // 4J - now creating a buffer of the size we require dynamically + ByteBuffer *pixels = MemoryTracker::createByteBuffer(w * h * 4); + pixels->clear(); + pixels->put(newPixels); + pixels->position(0)->limit(newPixels.length); + + delete[] rawPixels.data; + delete[] newPixels.data; + + if (MIPMAP) + { + // 4J-PB - In the new XDK, the CreateTexture will fail if the number of mipmaps is higher than the width & height passed in will allow! + int iWidthMips=1; + int iHeightMips=1; + while((8<<iWidthMips)<w) iWidthMips++; + while((8<<iHeightMips)<h) iHeightMips++; + + iMipLevels=(iWidthMips<iHeightMips)?iWidthMips:iHeightMips; + //RenderManager.TextureSetTextureLevels(5); // 4J added + if(iMipLevels>5)iMipLevels = 5; + RenderManager.TextureSetTextureLevels(iMipLevels); // 4J added + } + RenderManager.TextureData(w,h,pixels->getBuffer(),0,TEXTURE_FORMAT); + //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixels); + + if (MIPMAP) + { + for (int level = 1; level < iMipLevels; level++) + { + int ow = w >> (level - 1); + // int oh = h >> (level - 1); + + int ww = w >> level; + int hh = h >> level; + + // 4J - added tempData so we aren't overwriting source data + unsigned int *tempData = new unsigned int[ww * hh]; + // 4J - added - have we loaded mipmap data for this level? Use that rather than generating if possible + if( img->getData( level ) ) + { + memcpy( tempData, img->getData( level ), ww * hh * 4); +#ifndef _XBOX + // Swap ARGB to RGBA + for( int i = 0; i < ww * hh ; i++ ) + { + tempData[i] = ( tempData[i] >> 24 ) | (tempData[i] << 8 ); + } +#endif + } + else + { + for (int x = 0; x < ww; x++) + for (int y = 0; y < hh; y++) + { + int c0 = pixels->getInt(((x * 2 + 0) + (y * 2 + 0) * ow) * 4); + int c1 = pixels->getInt(((x * 2 + 1) + (y * 2 + 0) * ow) * 4); + int c2 = pixels->getInt(((x * 2 + 1) + (y * 2 + 1) * ow) * 4); + int c3 = pixels->getInt(((x * 2 + 0) + (y * 2 + 1) * ow) * 4); +#ifndef _XBOX + // 4J - convert our RGBA texels to ARGB that crispBlend is expecting + c0 = ( ( c0 >> 8 ) & 0x00ffffff ) | ( c0 << 24 ); + c1 = ( ( c1 >> 8 ) & 0x00ffffff ) | ( c1 << 24 ); + c2 = ( ( c2 >> 8 ) & 0x00ffffff ) | ( c2 << 24 ); + c3 = ( ( c3 >> 8 ) & 0x00ffffff ) | ( c3 << 24 ); +#endif + int col = Texture::crispBlend(Texture::crispBlend(c0, c1), Texture::crispBlend(c2, c3)); +#ifndef _XBOX + // 4J - and back from ARGB -> RGBA + col = ( col << 8 ) | (( col >> 24 ) & 0xff); +#endif + tempData[x + y * ww] = col; + } + } + for (int x = 0; x < ww; x++ ) + for (int y = 0; y < hh; y++) + { + pixels->putInt((x + y * ww) * 4, tempData[x + y * ww]); + } + delete [] tempData; + RenderManager.TextureData(ww,hh,pixels->getBuffer(),level,TEXTURE_FORMAT); + } + } + + /* + * if (MIPMAP) { GLU.gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, w, h, + * GL_RGBA, GL_UNSIGNED_BYTE, pixels); } else { } + */ + delete pixels; // 4J - now creating this dynamically + MemSect(0); +} + +intArray Textures::anaglyph(intArray rawPixels) +{ + intArray result(rawPixels.length); + for (unsigned int i = 0; i < rawPixels.length; i++) + { + int a = (rawPixels[i] >> 24) & 0xff; + int r = (rawPixels[i] >> 16) & 0xff; + int g = (rawPixels[i] >> 8) & 0xff; + int b = (rawPixels[i]) & 0xff; + + int rr = (r * 30 + g * 59 + b * 11) / 100; + int gg = (r * 30 + g * 70) / (100); + int bb = (r * 30 + b * 70) / (100); + + + result[i] = a << 24 | rr << 16 | gg << 8 | bb; + } + + delete[] rawPixels.data; + + return result; +} + +void Textures::replaceTexture(intArray rawPixels, int w, int h, int id) +{ + bind(id); + + // Removed in Java +#if 0 + if (MIPMAP) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + /* + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); + */ + } + else +#endif + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + if (options != NULL && options->anaglyph3d) + { + rawPixels = anaglyph(rawPixels); + } + + byteArray newPixels(w * h * 4); + for (unsigned int i = 0; i < rawPixels.length; i++) + { + int a = (rawPixels[i] >> 24) & 0xff; + int r = (rawPixels[i] >> 16) & 0xff; + int g = (rawPixels[i] >> 8) & 0xff; + int b = (rawPixels[i]) & 0xff; + + if (options != NULL && options->anaglyph3d) + { + int rr = (r * 30 + g * 59 + b * 11) / 100; + int gg = (r * 30 + g * 70) / (100); + int bb = (r * 30 + b * 70) / (100); + + r = rr; + g = gg; + b = bb; + } + + newPixels[i * 4 + 0] = (byte) r; + newPixels[i * 4 + 1] = (byte) g; + newPixels[i * 4 + 2] = (byte) b; + newPixels[i * 4 + 3] = (byte) a; + } + ByteBuffer *pixels = MemoryTracker::createByteBuffer(w * h * 4); // 4J - now creating dynamically + pixels->put(newPixels); + pixels->position(0)->limit(newPixels.length); + delete [] newPixels.data; + + // New + // glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixels); +#ifdef _XBOX + RenderManager.TextureDataUpdate(pixels->getBuffer(),0); +#else + RenderManager.TextureDataUpdate(0, 0,w,h,pixels->getBuffer(),0); +#endif + // Old + //glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + delete pixels; +} + +// 4J - added. This is a more minimal version of replaceTexture that assumes the texture bytes are already in order, and so doesn't do any of the extra copying round +// that the original java version does +void Textures::replaceTextureDirect(intArray rawPixels, int w, int h, int id) +{ + glBindTexture(GL_TEXTURE_2D, id); + + // Remove in Java +#if 0 + if (MIPMAP) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + /* + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); + */ + } + else +#endif + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + +#ifdef _XBOX + RenderManager.TextureDataUpdate(rawPixels.data, 0); +#else + RenderManager.TextureDataUpdate(0, 0, w, h, rawPixels.data, 0); +#endif +} + +// 4J - added. This is a more minimal version of replaceTexture that assumes the texture bytes are already in order, and so doesn't do any of the extra copying round +// that the original java version does +void Textures::replaceTextureDirect(shortArray rawPixels, int w, int h, int id) +{ + glBindTexture(GL_TEXTURE_2D, id); + + // Remove in Java +#if 0 + if (MIPMAP) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + /* + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); + */ + } + else +#endif + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + +#ifdef _XBOX + RenderManager.TextureDataUpdate(rawPixels.data, 0); +#else + RenderManager.TextureDataUpdate(0, 0, w, h, rawPixels.data, 0); +#endif +} + +void Textures::releaseTexture(int id) +{ + loadedImages.erase(id); + glDeleteTextures(id); +} + +int Textures::loadHttpTexture(const wstring& url, const wstring& backup) +{ + HttpTexture *texture = httpTextures[url]; + if (texture != NULL) + { + if (texture->loadedImage != NULL && !texture->isLoaded) + { + if (texture->id < 0) + { + texture->id = getTexture(texture->loadedImage); + } + else + { + loadTexture(texture->loadedImage, texture->id); + } + texture->isLoaded = true; + } + } + if (texture == NULL || texture->id < 0) + { + if (backup.empty() ) return -1; + return loadTexture(TN_COUNT, backup); + } + return texture->id; +} + +int Textures::loadHttpTexture(const wstring& url, int backup) +{ + HttpTexture *texture = httpTextures[url]; + if (texture != NULL) + { + if (texture->loadedImage != NULL && !texture->isLoaded) + { + if (texture->id < 0) + { + texture->id = getTexture(texture->loadedImage); + } + else + { + loadTexture(texture->loadedImage, texture->id); + } + texture->isLoaded = true; + } + } + if (texture == NULL || texture->id < 0) + { + return loadTexture(backup); + } + return texture->id; +} + +bool Textures::hasHttpTexture(const wstring &url) +{ + return httpTextures.find(url) != httpTextures.end(); +} + +HttpTexture *Textures::addHttpTexture(const wstring& url, HttpTextureProcessor *processor) +{ + HttpTexture *texture = httpTextures[url]; + if (texture == NULL) + { + httpTextures[url] = new HttpTexture(url, processor); + } + else + { + texture->count++; + } + return texture; +} + +void Textures::removeHttpTexture(const wstring& url) +{ + HttpTexture *texture = httpTextures[url]; + if (texture != NULL) + { + texture->count--; + if (texture->count == 0) + { + if (texture->id >= 0) releaseTexture(texture->id); + httpTextures.erase(url); + } + } +} + +// 4J-PB - adding for texture in memory (from global title storage) +int Textures::loadMemTexture(const wstring& url, const wstring& backup) +{ + MemTexture *texture = NULL; + AUTO_VAR(it, memTextures.find(url) ); + if (it != memTextures.end()) + { + texture = (*it).second; + } + if(texture == NULL && app.IsFileInMemoryTextures(url)) + { + // If we haven't loaded it yet, but we have the data for it then add it + texture = addMemTexture(url, new MobSkinMemTextureProcessor() ); + } + if(texture != NULL) + { + if (texture->loadedImage != NULL && !texture->isLoaded) + { + // 4J - Disable mipmapping in general for skins & capes. Have seen problems with edge-on polys for some eg mumbo jumbo + if( ( url.substr(0,7) == L"dlcskin" ) || + ( url.substr(0,7) == L"dlccape" ) ) + { + MIPMAP = false; + } + + if (texture->id < 0) + { + texture->id = getTexture(texture->loadedImage, C4JRender::TEXTURE_FORMAT_RxGyBzAw, MIPMAP); + } + else + { + loadTexture(texture->loadedImage, texture->id); + } + texture->isLoaded = true; + MIPMAP = true; + } + } + if (texture == NULL || texture->id < 0) + { + if (backup.empty() ) return -1; + return loadTexture(TN_COUNT,backup); + } + return texture->id; +} + +int Textures::loadMemTexture(const wstring& url, int backup) +{ + MemTexture *texture = NULL; + AUTO_VAR(it, memTextures.find(url) ); + if (it != memTextures.end()) + { + texture = (*it).second; + } + if(texture == NULL && app.IsFileInMemoryTextures(url)) + { + // If we haven't loaded it yet, but we have the data for it then add it + texture = addMemTexture(url, new MobSkinMemTextureProcessor() ); + } + if(texture != NULL) + { + texture->ticksSinceLastUse = 0; + if (texture->loadedImage != NULL && !texture->isLoaded) + { + // 4J - Disable mipmapping in general for skins & capes. Have seen problems with edge-on polys for some eg mumbo jumbo + if( ( url.substr(0,7) == L"dlcskin" ) || + ( url.substr(0,7) == L"dlccape" ) ) + { + MIPMAP = false; + } + if (texture->id < 0) + { + texture->id = getTexture(texture->loadedImage, C4JRender::TEXTURE_FORMAT_RxGyBzAw, MIPMAP); + } + else + { + loadTexture(texture->loadedImage, texture->id); + } + texture->isLoaded = true; + MIPMAP = true; + } + } + if (texture == NULL || texture->id < 0) + { + return loadTexture(backup); + } + return texture->id; +} + +MemTexture *Textures::addMemTexture(const wstring& name,MemTextureProcessor *processor) +{ + MemTexture *texture = NULL; + AUTO_VAR(it, memTextures.find(name) ); + if (it != memTextures.end()) + { + texture = (*it).second; + } + if(texture == NULL) + { + // can we find it in the app mem files? + PBYTE pbData=NULL; + DWORD dwBytes=0; + app.GetMemFileDetails(name,&pbData,&dwBytes); + + if(dwBytes!=0) + { + texture = new MemTexture(name, pbData, dwBytes, processor); + memTextures[name] = texture; + } + else + { + // 4J Stu - Make an entry for this anyway and we can populate it later + memTextures[name] = NULL; + } + } + else + { + texture->count++; + } + + delete processor; + + return texture; +} + +// MemTexture *Textures::getMemTexture(const wstring& url, MemTextureProcessor *processor) +// { +// MemTexture *texture = memTextures[url]; +// if (texture != NULL) +// { +// texture->count++; +// } +// return texture; +// } + +void Textures::removeMemTexture(const wstring& url) +{ + MemTexture *texture = NULL; + AUTO_VAR(it, memTextures.find(url) ); + if (it != memTextures.end()) + { + texture = (*it).second; + + // If it's NULL then we should just remove the entry + if( texture == NULL ) memTextures.erase(url); + } + if(texture != NULL) + { + texture->count--; + if (texture->count == 0) + { + if (texture->id >= 0) releaseTexture(texture->id); + memTextures.erase(url); + delete texture; + } + } +} + +void Textures::tick(bool updateTextures, bool tickDynamics) // 4J added updateTextures parameter & tickDynamics +{ + MemSect(22); + if(tickDynamics) + { + // 4J - added - if we aren't updating the final renderer textures, just tick each of the dynamic textures instead. This is used so that in frames were we have multiple + // ticks due to framerate compensation, that we don't lock the renderer textures twice needlessly and force the CPU to sync with the GPU. + if( !updateTextures ) + { + MemSect(0); + return; + } + + // 4J - added - tell renderer that we're about to do a block of dynamic texture updates, so we can unlock the resources after they are done rather than a series of locks/unlocks + //RenderManager.TextureDynamicUpdateStart(); + terrain->cycleAnimationFrames(); + items->cycleAnimationFrames(); + //RenderManager.TextureDynamicUpdateEnd(); // 4J added - see comment above + } + + // 4J - go over all the memory textures once per frame, and free any that haven't been used for a while. Ones that are being used will + // have their ticksSinceLastUse reset in Textures::loadMemTexture. + for( AUTO_VAR(it, memTextures.begin() ); it != memTextures.end(); ) + { + MemTexture *tex = it->second; + + if( tex && ( ++tex->ticksSinceLastUse > MemTexture::UNUSED_TICKS_TO_FREE ) ) + { + if (tex->id >= 0) releaseTexture(tex->id); + delete tex; + it = memTextures.erase(it); + } + else + { + it++; + } + + } + MemSect(0); +} + +void Textures::reloadAll() +{ + TexturePack *skin = skins->getSelected(); + + for( int i = 0; i < TN_COUNT - 2; i++ ) + { + releaseTexture(preLoadedIdx[i]); + } + + idMap.clear(); + loadedImages.clear(); + + loadIndexedTextures(); + + pixelsMap.clear(); + // 4J Stu - These are not used any more + //WaterColor::init(loadTexturePixels(L"misc/watercolor.png")); + //GrassColor::init(loadTexturePixels(L"misc/grasscolor.png")); + //FoliageColor::init(loadTexturePixels(L"misc/foliagecolor.png")); + + stitch(); + + skins->clearInvalidTexturePacks(); + +#if 0 + AUTO_VAR(itEndLI, loadedImages.end() ); + for(unordered_map<int, BufferedImage *>::iterator it = loadedImages.begin(); it != itEndLI; it++ ) + { + BufferedImage *image = it->second; + loadTexture(image, it->first); + } + + AUTO_VAR(itEndHT, httpTextures.end()); + for(unordered_map<wstring, HttpTexture *>::iterator it = httpTextures.begin(); it != itEndHT; it++ ) + { + it->second->isLoaded = false; + } + + AUTO_VAR(itEndMT, memTextures.end()); + for(unordered_map<wstring, MemTexture *>::iterator it = memTextures.begin(); it != itEndMT; it++ ) + { + it->second->isLoaded = false; + } + + + AUTO_VAR(itEndIM, idMap.end()); + for( unordered_map<wstring, int>::iterator it = idMap.begin(); it != itEndIM; it++ ) + { + wstring name = it->first; + + int id = idMap[name]; + BufferedImage *image; + + wstring prefix = L"%blur%"; + bool blur = name.substr(0, prefix.size()).compare(prefix) == 0; //name.startsWith("%blur%"); + if (blur) name = name.substr(6); + + prefix = L"%clamp%"; + bool clamp = name.substr(0, prefix.size()).compare(prefix) == 0; //name.startsWith("%clamp%"); + if (clamp) name = name.substr(7); + + image = readImage(skin->getResource(name)); + + loadTexture(image, id, blur, clamp); + delete image; + } + AUTO_VAR(itEndPM, pixelsMap.end()); + for( unordered_map<wstring, intArray>::iterator it = pixelsMap.begin(); it != itEndPM; it++ ) + { + wstring name = it->first; + BufferedImage *image = readImage(skin->getResource(name)); + + loadTexturePixels(image, pixelsMap[name]); + delete image; + } +#endif + + // Recalculate fonts + //Minecraft::GetInstance()->font->loadCharacterWidths(); + //Minecraft::GetInstance()->altFont->loadCharacterWidths(); +} + +void Textures::stitch() +{ + terrain->stitch(); + items->stitch(); +} + +Icon *Textures::getMissingIcon(int type) +{ + switch (type) + { + case Icon::TYPE_ITEM: + default: + return items->getMissingIcon(); + case Icon::TYPE_TERRAIN: + return terrain->getMissingIcon(); + } +} + +BufferedImage *Textures::readImage(TEXTURE_NAME texId, const wstring& name) // 4J was InputStream *in +{ + BufferedImage *img=NULL; + MemSect(32); + // is this image one of the Title Update ones? + bool isTu = IsTUImage(texId, name); + wstring drive = L""; + + if(!skins->isUsingDefaultSkin() && skins->getSelected()->hasFile(L"res/" + name,false)) + { + drive = skins->getSelected()->getPath(isTu); + img = skins->getSelected()->getImageResource(name, false, isTu, drive); //new BufferedImage(name,false,isTu,drive); + } + else + { + const char *pchName=wstringtofilename(name); +#ifdef __PS3__ + if(app.GetBootedFromDiscPatch() && app.IsFileInPatchList(pchName)) + { + char *pchUsrDir = app.GetBDUsrDirPath(pchName); + wstring wstr (pchUsrDir, pchUsrDir+strlen(pchUsrDir)); + + if(isTu) + { + drive= wstr + L"\\Common\\res\\TitleUpdate\\"; + + } + else + { + drive= wstr + L"\\Common\\"; + } + } + else +#endif + { + drive = skins->getDefault()->getPath(isTu); + } + + const char *pchDrive=wstringtofilename(drive); + + if(IsOriginalImage(texId, name) || isTu) + { + img = skins->getDefault()->getImageResource(name,false,isTu,drive); //new BufferedImage(name,false,isTu,drive); + } + else + { + img = skins->getDefault()->getImageResource(L"1_2_2/" + name, false, isTu, drive); //new BufferedImage(L"/1_2_2" + name,false,isTu,drive); + } + } + + MemSect(0); + return img; +} + +// Match the preload images from their enum to avoid a ton of string comparisons +TEXTURE_NAME TUImages[] = +{ + TN_POWERED_CREEPER, + TN_MOB_ENDERMAN_EYES, + TN_MISC_EXPLOSION, + TN_MOB_ZOMBIE, + TN_MISC_FOOTSTEP, + TN_MOB_RED_COW, + TN_MOB_SNOWMAN, + TN_MOB_ENDERDRAGON, + TN_MOB_VILLAGER_VILLAGER, + TN_MOB_VILLAGER_FARMER, + TN_MOB_VILLAGER_LIBRARIAN, + TN_MOB_VILLAGER_PRIEST, + TN_MOB_VILLAGER_SMITH, + TN_MOB_VILLAGER_BUTCHER, + TN_MOB_ENDERDRAGON_ENDEREYES, + TN__BLUR__MISC_GLINT, + TN_ITEM_BOOK, + TN_MISC_PARTICLEFIELD, + + // TU9 + TN_MISC_TUNNEL, + TN_MOB_ENDERDRAGON_BEAM, + TN_GUI_ITEMS, + TN_TERRAIN, + TN_MISC_MAPICONS, + + // TU12 + TN_MOB_WITHER_SKELETON, + + // TU14 + TN_TILE_ENDER_CHEST, + TN_ART_KZ, + TN_MOB_WOLF_TAME, + TN_MOB_WOLF_COLLAR, + TN_PARTICLES, + TN_MOB_ZOMBIE_VILLAGER, + +#ifdef _LARGE_WORLDS + TN_MISC_ADDITIONALMAPICONS, +#endif + + // TU17 + TN_DEFAULT_FONT, + // TN_ALT_FONT, // Not in TU yet + + TN_COUNT // Why is this here? +}; + +// This is for any TU textures that aren't part of our enum indexed preload set +wchar_t *TUImagePaths[] = +{ + L"font/Default", + L"font/Mojangles_7", + L"font/Mojangles_11", + + // TU12 + L"armor/cloth_1.png", + L"armor/cloth_1_b.png", + L"armor/cloth_2.png", + L"armor/cloth_2_b.png", + + NULL +}; + +bool Textures::IsTUImage(TEXTURE_NAME texId, const wstring& name) +{ + int i = 0; + if(texId < TN_COUNT) + { + while(TUImages[i] < TN_COUNT) + { + if(texId == TUImages[i]) + { + return true; + } + i++; + } + } + i = 0; + while(TUImagePaths[i]) + { + if(name.compare(TUImagePaths[i])==0) + { + return true; + } + i++; + } + return false; +} + +TEXTURE_NAME OriginalImages[] = +{ + TN_MOB_CHAR, + TN_MOB_CHAR1, + TN_MOB_CHAR2, + TN_MOB_CHAR3, + TN_MOB_CHAR4, + TN_MOB_CHAR5, + TN_MOB_CHAR6, + TN_MOB_CHAR7, + + TN_MISC_MAPBG, + + TN_COUNT +}; + +wchar_t *OriginalImagesPaths[] = +{ + L"misc/watercolor.png", + + NULL +}; + +bool Textures::IsOriginalImage(TEXTURE_NAME texId, const wstring& name) +{ + int i = 0; + if(texId < TN_COUNT) + { + while(OriginalImages[i] < TN_COUNT) + { + if(texId == OriginalImages[i]) + { + return true; + } + i++; + } + } + i = 0; + while(OriginalImagesPaths[i]) + { + if(name.compare(OriginalImagesPaths[i])==0) + { + return true; + } + i++; + } + return false; +} + |
