445 lines
11 KiB
C++
Raw Permalink Normal View History

2025-01-22 16:18:30 +01:00
#include "TextureImpl.h"
#include "ogl.h"
#include <Kore/Graphics1/Image.h>
#include <Kore/Graphics3/Graphics.h>
#include <Kore/Log.h>
using namespace Kore;
#ifndef GL_TEXTURE_3D
#define GL_TEXTURE_3D 0x806F
#endif
namespace {
int convertFormat(Graphics3::Image::Format format) {
switch (format) {
case Graphics3::Image::RGBA32:
case Graphics3::Image::RGBA64:
case Graphics3::Image::RGBA128:
default:
// #ifdef GL_BGRA
// return GL_BGRA;
// #else
return GL_RGBA;
// #endif
case Graphics3::Image::RGB24:
return GL_RGB;
case Graphics3::Image::Grey8:
#ifdef KINC_OPENGL_ES
return GL_LUMINANCE;
#else
return GL_RED;
#endif
}
}
int convertInternalFormat(Graphics3::Image::Format format) {
switch (format) {
case Graphics3::Image::RGBA128:
return GL_RGBA;
case Graphics3::Image::RGBA32:
case Graphics3::Image::RGBA64:
default:
// #ifdef GL_BGRA
// return GL_BGRA;
// #else
return GL_RGBA;
// #endif
case Graphics3::Image::RGB24:
return GL_RGB;
case Graphics3::Image::Grey8:
#ifdef KINC_OPENGL_ES
return GL_LUMINANCE;
#else
return GL_RED;
#endif
}
}
int convertType(Graphics3::Image::Format format) {
switch (format) {
case Graphics3::Image::RGBA128:
case Graphics3::Image::RGBA64:
return GL_FLOAT;
case Graphics3::Image::RGBA32:
default:
return GL_UNSIGNED_BYTE;
}
}
#if 0
int astcFormat(u8 blockX, u8 blockY) {
switch (blockX) {
case 4:
switch (blockY) {
case 4:
return COMPRESSED_RGBA_ASTC_4x4_KHR;
}
case 5:
switch (blockY) {
case 4:
return COMPRESSED_RGBA_ASTC_5x4_KHR;
case 5:
return COMPRESSED_RGBA_ASTC_5x5_KHR;
}
case 6:
switch (blockY) {
case 5:
return COMPRESSED_RGBA_ASTC_6x5_KHR;
case 6:
return COMPRESSED_RGBA_ASTC_6x6_KHR;
}
case 8:
switch (blockY) {
case 5:
return COMPRESSED_RGBA_ASTC_8x5_KHR;
case 6:
return COMPRESSED_RGBA_ASTC_8x6_KHR;
case 8:
return COMPRESSED_RGBA_ASTC_8x8_KHR;
}
case 10:
switch (blockY) {
case 5:
return COMPRESSED_RGBA_ASTC_10x5_KHR;
case 6:
return COMPRESSED_RGBA_ASTC_10x6_KHR;
case 8:
return COMPRESSED_RGBA_ASTC_10x8_KHR;
case 10:
return COMPRESSED_RGBA_ASTC_10x10_KHR;
}
case 12:
switch (blockY) {
case 10:
return COMPRESSED_RGBA_ASTC_12x10_KHR;
case 12:
return COMPRESSED_RGBA_ASTC_12x12_KHR;
}
}
return 0;
}
#endif
int pow(int pow) {
int ret = 1;
for (int i = 0; i < pow; ++i)
ret *= 2;
return ret;
}
int getPower2(int i) {
for (int power = 0;; ++power)
if (pow(power) >= i)
return pow(power);
}
void convertImageToPow2(Graphics3::Image::Format format, u8 *from, int fw, int fh, u8 *to, int tw, int th) {
switch (format) {
case Graphics3::Image::RGBA32:
for (int y = 0; y < th; ++y) {
for (int x = 0; x < tw; ++x) {
to[tw * 4 * y + x * 4 + 0] = 0;
to[tw * 4 * y + x * 4 + 1] = 0;
to[tw * 4 * y + x * 4 + 2] = 0;
to[tw * 4 * y + x * 4 + 3] = 0;
}
}
for (int y = 0; y < fh; ++y) {
for (int x = 0; x < fw; ++x) {
to[tw * 4 * y + x * 4 + 0] = from[y * fw * 4 + x * 4 + 0];
to[tw * 4 * y + x * 4 + 1] = from[y * fw * 4 + x * 4 + 1];
to[tw * 4 * y + x * 4 + 2] = from[y * fw * 4 + x * 4 + 2];
to[tw * 4 * y + x * 4 + 3] = from[y * fw * 4 + x * 4 + 3];
}
}
break;
case Graphics3::Image::Grey8:
for (int y = 0; y < th; ++y) {
for (int x = 0; x < tw; ++x) {
to[tw * y + x] = 0;
}
}
for (int y = 0; y < fh; ++y) {
for (int x = 0; x < fw; ++x) {
to[tw * y + x] = from[y * fw + x];
}
}
break;
}
}
}
void Graphics3::Texture::init(const char *format, bool readable) {
bool toPow2;
if (Graphics3::nonPow2TexturesSupported()) {
texWidth = width;
texHeight = height;
toPow2 = false;
}
else {
texWidth = getPower2(width);
texHeight = getPower2(height);
toPow2 = !(texWidth == width && texHeight == height);
}
u8 *conversionBuffer = nullptr;
if (compressed) {
#if defined(KINC_IOS)
texWidth = Kore::max(texWidth, texHeight);
texHeight = Kore::max(texWidth, texHeight);
if (texWidth < 8)
texWidth = 8;
if (texHeight < 8)
texHeight = 8;
#elif defined(KINC_ANDROID)
texWidth = width;
texHeight = height;
#endif
}
else if (toPow2) {
conversionBuffer = new u8[texWidth * texHeight * sizeOf(this->format)];
convertImageToPow2(this->format, (u8 *)data, width, height, conversionBuffer, texWidth, texHeight);
}
#ifdef KINC_ANDROID
external_oes = false;
#endif
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glCheckErrors();
glGenTextures(1, &texture);
glCheckErrors();
glBindTexture(GL_TEXTURE_2D, texture);
glCheckErrors();
int convertedType = convertType(this->format);
bool isHdr = convertedType == GL_FLOAT;
if (compressed) {
#ifdef KINC_IOS
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, texWidth, texHeight, 0, texWidth * texHeight / 2, data);
// #elif defined(KINC_ANDROID)
// u8 blockX = internalFormat >> 8;
// u8 blockY = internalFormat & 0xff;
// glCompressedTexImage2D(GL_TEXTURE_2D, 0, astcFormat(blockX, blockY), texWidth, texHeight, 0, dataSize, data);
#endif
}
else {
if (isHdr) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, convertedType, hdrData);
}
else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, convertedType, toPow2 ? conversionBuffer : data);
}
glCheckErrors();
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glCheckErrors();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glCheckErrors();
if (toPow2) {
delete[] conversionBuffer;
conversionBuffer = nullptr;
}
if (!readable) {
if (isHdr) {
delete[] hdrData;
hdrData = nullptr;
}
else {
delete[] data;
data = nullptr;
}
}
if (readable && compressed) {
log(Kore::Warning, "Compressed images can not be readable.");
}
}
Graphics3::Texture::Texture(int width, int height, Image::Format format, bool readable) : Image(width, height, format, readable) {
#ifdef KINC_IOS
texWidth = width;
texHeight = height;
#else
if (Graphics3::nonPow2TexturesSupported()) {
texWidth = width;
texHeight = height;
}
else {
texWidth = getPower2(width);
texHeight = getPower2(height);
}
#endif
// conversionBuffer = new u8[texWidth * texHeight * 4];
#ifdef KINC_ANDROID
external_oes = false;
#endif
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glCheckErrors();
glGenTextures(1, &texture);
glCheckErrors();
glBindTexture(GL_TEXTURE_2D, texture);
glCheckErrors();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glCheckErrors();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glCheckErrors();
if (convertType(format) == GL_FLOAT) {
glTexImage2D(GL_TEXTURE_2D, 0, convertInternalFormat(format), texWidth, texHeight, 0, convertFormat(format), GL_FLOAT, nullptr);
}
else {
glTexImage2D(GL_TEXTURE_2D, 0, convertInternalFormat(format), texWidth, texHeight, 0, convertFormat(format), GL_UNSIGNED_BYTE, data);
}
glCheckErrors();
/*if (!readable) {
delete[] data;
data = nullptr;
}*/
}
Graphics3::Texture::Texture(int width, int height, int depth, Graphics3::Image::Format format, bool readable) : Image(width, height, depth, format, readable) {
#ifndef OPENGLES
glGenTextures(1, &texture);
glCheckErrors();
glBindTexture(GL_TEXTURE_3D, texture);
glCheckErrors();
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glCheckErrors();
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glCheckErrors();
glTexImage3D(GL_TEXTURE_3D, 0, convertFormat(format), width, height, depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glCheckErrors();
#endif
}
#ifdef KINC_ANDROID
Texture::Texture(unsigned texid) : Image(1023, 684, Image::RGBA32, false) {
texture = texid;
external_oes = true;
texWidth = 1023;
texHeight = 684;
}
#endif
TextureImpl::~TextureImpl() {
glDeleteTextures(1, &texture);
glFlush();
}
void Graphics3::Texture::_set(TextureUnit unit) {
GLenum target = depth > 1 ? GL_TEXTURE_3D : GL_TEXTURE_2D;
glActiveTexture(GL_TEXTURE0 + unit.unit);
glCheckErrors();
#ifdef KINC_ANDROID
if (external_oes) {
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
glCheckErrors();
}
else {
glBindTexture(target, texture);
glCheckErrors();
}
#else
glBindTexture(target, texture);
glCheckErrors();
#endif
}
int Graphics3::Texture::stride() {
return width * sizeOf(format);
}
u8 *Graphics3::Texture::lock() {
return (u8 *)data;
}
/*void Texture::unlock() {
if (conversionBuffer != nullptr) {
convertImageToPow2(format, (u8*)data, width, height, conversionBuffer, texWidth, texHeight);
glBindTexture(GL_TEXTURE_2D, texture);
#ifndef GL_LUMINANCE
#define GL_LUMINANCE GL_RED
#endif
glTexImage2D(GL_TEXTURE_2D, 0, (format == Image::RGBA32) ? GL_RGBA : GL_LUMINANCE, texWidth, texHeight, 0, (format == Image::RGBA32) ? GL_RGBA :
GL_LUMINANCE, GL_UNSIGNED_BYTE, conversionBuffer);
}
}*/
void Graphics3::Texture::unlock() {
// if (conversionBuffer != nullptr) {
// convertImageToPow2(format, (u8*)data, width, height, conversionBuffer, texWidth, texHeight);
glBindTexture(GL_TEXTURE_2D, texture);
glCheckErrors();
// glTexImage2D(GL_TEXTURE_2D, 0, (format == Image::RGBA32) ? GL_RGBA : GL_LUMINANCE, texWidth, texHeight, 0, (format == Image::RGBA32) ? GL_RGBA :
// GL_LUMINANCE, GL_UNSIGNED_BYTE, conversionBuffer);
if (convertType(format) == GL_FLOAT) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texWidth, texHeight, convertFormat(format), GL_FLOAT, hdrData);
glCheckErrors();
}
else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texWidth, texHeight, convertFormat(format), GL_UNSIGNED_BYTE, data);
glCheckErrors();
}
// }
}
void Graphics3::Texture::clear(int x, int y, int z, int width, int height, int depth, uint color) {
#ifdef GL_VERSION_4_4
static float clearColor[4];
clearColor[0] = ((color & 0x00ff0000) >> 16) / 255.0f;
clearColor[1] = ((color & 0x0000ff00) >> 8) / 255.0f;
clearColor[2] = (color & 0x000000ff) / 255.0f;
clearColor[3] = ((color & 0xff000000) >> 24) / 255.0f;
GLenum target = depth > 1 ? GL_TEXTURE_3D : GL_TEXTURE_2D;
glBindTexture(target, texture);
glClearTexSubImage(texture, 0, x, y, z, width, height, depth, convertFormat(format), convertType(format), clearColor);
#endif
}
#ifdef KINC_IOS
void Texture::upload(u8 *data) {
glBindTexture(GL_TEXTURE_2D, texture);
glCheckErrors();
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texWidth, texHeight, convertFormat(format), GL_UNSIGNED_BYTE, data);
glCheckErrors();
}
#endif
void Graphics3::Texture::generateMipmaps(int levels) {
GLenum target = depth > 1 ? GL_TEXTURE_3D : GL_TEXTURE_2D;
glBindTexture(target, texture);
glCheckErrors();
glGenerateMipmap(target);
glCheckErrors();
}
void Graphics3::Texture::setMipmap(Texture *mipmap, int level) {
int convertedType = convertType(mipmap->format);
bool isHdr = convertedType == GL_FLOAT;
GLenum target = depth > 1 ? GL_TEXTURE_3D : GL_TEXTURE_2D;
glBindTexture(target, texture);
glCheckErrors();
if (isHdr) {
glTexImage2D(target, level, convertInternalFormat(mipmap->format), mipmap->texWidth, mipmap->texHeight, 0, convertFormat(mipmap->format), convertedType,
mipmap->hdrData);
glCheckErrors();
}
else {
glTexImage2D(target, level, convertInternalFormat(mipmap->format), mipmap->texWidth, mipmap->texHeight, 0, convertFormat(mipmap->format), convertedType,
mipmap->data);
glCheckErrors();
}
}