Files
minecraft-pe-0.6.1/src/client/renderer/Textures.cpp
2026-03-13 16:26:19 +01:00

362 lines
11 KiB
C++
Executable File

#include "Textures.h"
#include "TextureData.h"
#include "ptexture/DynamicTexture.h"
#include "../Options.h"
#include "../../platform/time.h"
#include "../../AppPlatform.h"
#include "../../util/StringUtils.h"
/*static*/ int Textures::textureChanges = 0;
/*static*/ bool Textures::MIPMAP = false;
/*static*/ const TextureId Textures::InvalidId = -1;
Textures::Textures( Options* options_, AppPlatform* platform_ )
: clamp(false),
blur(false),
options(options_),
platform(platform_),
lastBoundTexture(Textures::InvalidId)
{
}
Textures::~Textures()
{
clear();
for (unsigned int i = 0; i < dynamicTextures.size(); ++i)
delete dynamicTextures[i];
}
void Textures::clear()
{
for (TextureMap::iterator it = idMap.begin(); it != idMap.end(); ++it) {
if (it->second != Textures::InvalidId)
glDeleteTextures(1, &it->second);
}
for (TextureImageMap::iterator it = loadedImages.begin(); it != loadedImages.end(); ++it) {
if (!(it->second).memoryHandledExternally)
delete[] (it->second).data;
}
idMap.clear();
loadedImages.clear();
lastBoundTexture = Textures::InvalidId;
}
TextureId Textures::loadAndBindTexture( const std::string& resourceName )
{
//static Stopwatch t;
//t.start();
TextureId id = loadTexture(resourceName);
//t.stop();
if (id != Textures::InvalidId)
bind(id);
//t.printEvery(1000);
return id;
}
TextureId Textures::loadTexture( const std::string& resourceName, bool inTextureFolder /* = true */ )
{
TextureMap::iterator it = idMap.find(resourceName);
if (it != idMap.end())
return it->second;
bool isUrl = Util::startsWith(resourceName, "http://") || Util::startsWith(resourceName, "https://");
TextureData texdata = platform->loadTexture(resourceName, isUrl ? false : inTextureFolder);
if (texdata.data)
return assignTexture(resourceName, texdata);
else if (texdata.identifier != InvalidId) {
//LOGI("Adding id: %d for %s\n", texdata.identifier, resourceName.c_str());
idMap.insert(std::make_pair(resourceName, texdata.identifier));
}
else {
idMap.insert(std::make_pair(resourceName, Textures::InvalidId));
//loadedImages.insert(std::make_pair(InvalidId, texdata));
}
return Textures::InvalidId;
}
TextureId Textures::assignTexture( const std::string& resourceName, const TextureData& img )
{
TextureId id;
glGenTextures(1, &id);
bind(id);
if (MIPMAP) {
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
if (blur) {
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
if (clamp) {
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else {
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
switch (img.format)
{
case TEXF_COMPRESSED_PVRTC_4444:
case TEXF_COMPRESSED_PVRTC_565:
case TEXF_COMPRESSED_PVRTC_5551:
{
#if defined(__APPLE__)
int fmt = img.transparent? GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
glCompressedTexImage2D(GL_TEXTURE_2D, 0, fmt, img.w, img.h, 0, img.numBytes, img.data);
#endif
break;
}
default:
const GLint mode = img.transparent? GL_RGBA : GL_RGB;
if (img.format == TEXF_UNCOMPRESSED_565) {
glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_SHORT_5_6_5, img.data);
}
else if (img.format == TEXF_UNCOMPRESSED_4444) {
glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_SHORT_4_4_4_4, img.data);
}
else if (img.format == TEXF_UNCOMPRESSED_5551) {
glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_SHORT_5_5_5_1, img.data);
}
else {
glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_BYTE, img.data);
}
break;
}
//LOGI("Adding id: %d to map\n", id);
idMap.insert(std::make_pair(resourceName, id));
loadedImages.insert(std::make_pair(id, img));
return id;
}
const TextureData* Textures::getTemporaryTextureData( TextureId id )
{
TextureImageMap::iterator it = loadedImages.find(id);
if (it == loadedImages.end())
return NULL;
return &it->second;
}
void Textures::tick(bool uploadToGraphicsCard)
{
for (unsigned int i = 0; i < dynamicTextures.size(); ++i ) {
DynamicTexture* tex = dynamicTextures[i];
tex->tick();
if (uploadToGraphicsCard) {
tex->bindTexture(this);
for (int xx = 0; xx < tex->replicate; xx++)
for (int yy = 0; yy < tex->replicate; yy++) {
glTexSubImage2D2(GL_TEXTURE_2D, 0, tex->tex % 16 * 16 + xx * 16,
tex->tex / 16 * 16 + yy * 16, 16, 16,
GL_RGBA, GL_UNSIGNED_BYTE, tex->pixels);
}
}
}
}
void Textures::addDynamicTexture( DynamicTexture* dynamicTexture )
{
dynamicTextures.push_back(dynamicTexture);
dynamicTexture->tick();
}
void Textures::reloadAll()
{
//TexturePack skin = skins.selected;
//for (int id : loadedImages.keySet()) {
// BufferedImage image = loadedImages.get(id);
// loadTexture(image, id);
//}
////for (HttpTexture httpTexture : httpTextures.values()) {
//// httpTexture.isLoaded = false;
////}
//for (std::string name : idMap.keySet()) {
// try {
// BufferedImage image;
// if (name.startsWith("##")) {
// image = makeStrip(readImage(skin.getResource(name.substring(2))));
// } else if (name.startsWith("%clamp%")) {
// clamp = true;
// image = readImage(skin.getResource(name.substring(7)));
// } else if (name.startsWith("%blur%")) {
// blur = true;
// image = readImage(skin.getResource(name.substring(6)));
// } else {
// image = readImage(skin.getResource(name));
// }
// int id = idMap.get(name);
// loadTexture(image, id);
// blur = false;
// clamp = false;
// } catch (IOException e) {
// e.printStackTrace();
// }
//}
}
int Textures::smoothBlend( int c0, int c1 )
{
int a0 = (int) (((c0 & 0xff000000) >> 24)) & 0xff;
int a1 = (int) (((c1 & 0xff000000) >> 24)) & 0xff;
return ((a0 + a1) >> 1 << 24) + (((c0 & 0x00fefefe) + (c1 & 0x00fefefe)) >> 1);
}
int Textures::crispBlend( int c0, int c1 )
{
int a0 = (int) (((c0 & 0xff000000) >> 24)) & 0xff;
int a1 = (int) (((c1 & 0xff000000) >> 24)) & 0xff;
int a = 255;
if (a0 + a1 == 0) {
a0 = 1;
a1 = 1;
a = 0;
}
int r0 = ((c0 >> 16) & 0xff) * a0;
int g0 = ((c0 >> 8) & 0xff) * a0;
int b0 = ((c0) & 0xff) * a0;
int r1 = ((c1 >> 16) & 0xff) * a1;
int g1 = ((c1 >> 8) & 0xff) * a1;
int b1 = ((c1) & 0xff) * a1;
int r = (r0 + r1) / (a0 + a1);
int g = (g0 + g1) / (a0 + a1);
int b = (b0 + b1) / (a0 + a1);
return (a << 24) | (r << 16) | (g << 8) | b;
}
///*public*/ int loadHttpTexture(std::string url, std::string backup) {
// HttpTexture texture = httpTextures.get(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 == NULL) return -1;
// return loadTexture(backup);
// }
// return texture.id;
//}
//HttpTexture addHttpTexture(std::string url, HttpTextureProcessor processor) {
// HttpTexture texture = httpTextures.get(url);
// if (texture == NULL) {
// httpTextures.put(url, /*new*/ HttpTexture(url, processor));
// } else {
// texture.count++;
// }
// return texture;
//}
//void removeHttpTexture(std::string url) {
// HttpTexture texture = httpTextures.get(url);
// if (texture != NULL) {
// texture.count--;
// if (texture.count == 0) {
// if (texture.id >= 0) releaseTexture(texture.id);
// httpTextures.remove(url);
// }
// }
//}
//void tick() {
// for (int i = 0; i < dynamicTextures.size(); i++) {
// DynamicTexture dynamicTexture = dynamicTextures.get(i);
// dynamicTexture.anaglyph3d = options.anaglyph3d;
// dynamicTexture.tick();
//
// pixels.clear();
// pixels.put(dynamicTexture.pixels);
// pixels.position(0).limit(dynamicTexture.pixels.length);
//
// dynamicTexture.bindTexture(this);
//
// for (int xx = 0; xx < dynamicTexture.replicate; xx++)
// for (int yy = 0; yy < dynamicTexture.replicate; yy++) {
//
// glTexSubImage2D2(GL_TEXTURE_2D, 0, dynamicTexture.tex % 16 * 16 + xx * 16, dynamicTexture.tex / 16 * 16 + yy * 16, 16, 16, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// if (MIPMAP) {
// for (int level = 1; level <= 4; level++) {
// int os = 16 >> (level - 1);
// int s = 16 >> level;
//
// for (int x = 0; x < s; x++)
// for (int y = 0; y < s; y++) {
// int c0 = pixels.getInt(((x * 2 + 0) + (y * 2 + 0) * os) * 4);
// int c1 = pixels.getInt(((x * 2 + 1) + (y * 2 + 0) * os) * 4);
// int c2 = pixels.getInt(((x * 2 + 1) + (y * 2 + 1) * os) * 4);
// int c3 = pixels.getInt(((x * 2 + 0) + (y * 2 + 1) * os) * 4);
// int col = smoothBlend(smoothBlend(c0, c1), smoothBlend(c2, c3));
// pixels.putInt((x + y * s) * 4, col);
// }
// glTexSubImage2D2(GL_TEXTURE_2D, level, dynamicTexture.tex % 16 * s, dynamicTexture.tex / 16 * s, s, s, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// }
// }
// }
// }
//
// for (int i = 0; i < dynamicTextures.size(); i++) {
// DynamicTexture dynamicTexture = dynamicTextures.get(i);
//
// if (dynamicTexture.copyTo > 0) {
// pixels.clear();
// pixels.put(dynamicTexture.pixels);
// pixels.position(0).limit(dynamicTexture.pixels.length);
// glBindTexture2(GL_TEXTURE_2D, dynamicTexture.copyTo);
// glTexSubImage2D2(GL_TEXTURE_2D, 0, 0, 0, 16, 16, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// if (MIPMAP) {
// for (int level = 1; level <= 4; level++) {
// int os = 16 >> (level - 1);
// int s = 16 >> level;
//
// for (int x = 0; x < s; x++)
// for (int y = 0; y < s; y++) {
// int c0 = pixels.getInt(((x * 2 + 0) + (y * 2 + 0) * os) * 4);
// int c1 = pixels.getInt(((x * 2 + 1) + (y * 2 + 0) * os) * 4);
// int c2 = pixels.getInt(((x * 2 + 1) + (y * 2 + 1) * os) * 4);
// int c3 = pixels.getInt(((x * 2 + 0) + (y * 2 + 1) * os) * 4);
// int col = smoothBlend(smoothBlend(c0, c1), smoothBlend(c2, c3));
// pixels.putInt((x + y * s) * 4, col);
// }
// glTexSubImage2D2(GL_TEXTURE_2D, level, 0, 0, s, s, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// }
// }
// }
// }
//}
// void releaseTexture(int id) {
// loadedImages.erase(id);
// glDeleteTextures(1, (const GLuint*)&id);
// }