aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Textures.cpp
diff options
context:
space:
mode:
authordaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
committerdaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
commitb691c43c44ff180d10e7d4a9afc83b98551ff586 (patch)
tree3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.Client/Textures.cpp
parentdef8cb415354ac390b7e89052a50605285f1aca9 (diff)
Initial commit
Diffstat (limited to 'Minecraft.Client/Textures.cpp')
-rw-r--r--Minecraft.Client/Textures.cpp1404
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;
+}
+