UltimateZoneBuilder/Source/Native/OpenGL/GLTexture.cpp
volte 7fbd07e586
New feature: classic lighting renderer for visual mode (#680)
Added classic rendering mode to closer emulate software renderer visuals in visual mode
2022-01-04 20:17:12 +01:00

300 lines
8.2 KiB
C++

/*
** BuilderNative Renderer
** Copyright (c) 2019 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
*/
#include "Precomp.h"
#include "GLTexture.h"
#include "GLRenderDevice.h"
#include <stdexcept>
GLTexture::GLTexture()
{
}
GLTexture::~GLTexture()
{
Finalize();
}
void GLTexture::Finalize()
{
if (Device)
Invalidate();
}
void GLTexture::Set2DImage(int width, int height, PixelFormat format)
{
// This really shouldn't be here. The calling code should send valid input and this should throw an error.
if (width < 1) width = 16;
if (height < 1) height = 16;
mCubeTexture = false;
mWidth = width;
mHeight = height;
mFormat = format;
}
void GLTexture::SetCubeImage(int size, PixelFormat format)
{
mCubeTexture = true;
mWidth = size;
mHeight = size;
mFormat = format;
}
bool GLTexture::SetPixels(GLRenderDevice* device, const void* data)
{
GLint texture = GetTexture(device);
if (!texture) return false;
GLint oldActiveTex = GL_TEXTURE0;
glGetIntegerv(GL_ACTIVE_TEXTURE, &oldActiveTex);
glActiveTexture(GL_TEXTURE0);
GLint oldBinding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding);
//
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, mTexture);
glTexImage2D(GL_TEXTURE_2D, 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), data);
if (data != nullptr)
glGenerateMipmap(GL_TEXTURE_2D);
//
glBindTexture(GL_TEXTURE_2D, oldBinding);
glActiveTexture(oldActiveTex);
return true;
}
bool GLTexture::SetCubePixels(GLRenderDevice* device, CubeMapFace face, const void* data)
{
static GLint cubeMapFaceToGL[] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
GLint texture = GetTexture(device);
if (!texture) return false;
GLint oldActiveTex = GL_TEXTURE0;
glGetIntegerv(GL_ACTIVE_TEXTURE, &oldActiveTex);
glActiveTexture(GL_TEXTURE0);
GLint oldBinding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &oldBinding);
//
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, mTexture);
glTexImage2D(cubeMapFaceToGL[(int)face], 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), data);
if (data != nullptr && face == CubeMapFace::NegativeZ)
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
//
glBindTexture(GL_TEXTURE_CUBE_MAP, oldBinding);
glActiveTexture(oldActiveTex);
return true;
}
void GLTexture::Invalidate()
{
if (mDepthRenderbuffer) glDeleteRenderbuffers(1, &mDepthRenderbuffer);
if (mFramebuffer) glDeleteFramebuffers(1, &mFramebuffer);
if (mTexture) glDeleteTextures(1, &mTexture);
if (mPBO) glDeleteBuffers(1, &mPBO);
mDepthRenderbuffer = 0;
mFramebuffer = 0;
mTexture = 0;
mPBO = 0;
if (Device) Device->mTextures.erase(ItTexture);
Device = nullptr;
}
GLuint GLTexture::GetTexture(GLRenderDevice* device)
{
if (mTexture == 0)
{
if (Device == nullptr)
{
Device = device;
ItTexture = Device->mTextures.insert(Device->mTextures.end(), this);
}
GLint oldActiveTex = GL_TEXTURE0;
glGetIntegerv(GL_ACTIVE_TEXTURE, &oldActiveTex);
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &mTexture);
if (!IsCubeTexture())
{
GLint oldBinding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, mTexture);
glTexImage2D(GL_TEXTURE_2D, 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), nullptr);
glBindTexture(GL_TEXTURE_2D, oldBinding);
}
else
{
GLint oldBinding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &oldBinding);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, mTexture);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), nullptr);
glBindTexture(GL_TEXTURE_CUBE_MAP, oldBinding);
}
glActiveTexture(oldActiveTex);
}
return mTexture;
}
GLuint GLTexture::GetFramebuffer(GLRenderDevice* device, bool usedepthbuffer)
{
if (!usedepthbuffer)
{
if (mFramebuffer == 0)
{
GLuint texture = GetTexture(device);
glGenFramebuffers(1, &mFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("glCheckFramebufferStatus did not return GL_FRAMEBUFFER_COMPLETE");
}
return mFramebuffer;
}
else
{
if (mDepthRenderbuffer == 0)
{
if (Device == nullptr)
{
Device = device;
ItTexture = Device->mTextures.insert(Device->mTextures.end(), this);
}
glGenRenderbuffers(1, &mDepthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mWidth, mHeight);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
if (mFramebuffer == 0)
{
GLuint texture = GetTexture(device);
glGenFramebuffers(1, &mFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepthRenderbuffer);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("glCheckFramebufferStatus did not return GL_FRAMEBUFFER_COMPLETE");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
return mFramebuffer;
}
}
GLuint GLTexture::GetPBO(GLRenderDevice* device)
{
if (mPBO == 0)
{
if (Device == nullptr)
{
Device = device;
ItTexture = Device->mTextures.insert(Device->mTextures.end(), this);
}
glGenBuffers(1, &mPBO);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO);
glBufferData(GL_PIXEL_UNPACK_BUFFER, mWidth*mHeight * 4, NULL, GL_STREAM_DRAW);
}
return mPBO;
}
GLint GLTexture::ToInternalFormat(PixelFormat format)
{
static GLint cvt[] =
{
GL_RGBA8,
GL_RGBA8,
GL_RG16F,
GL_RGBA16F,
GL_R32F,
GL_RG32F,
GL_RGB32F,
GL_RGBA32F,
GL_DEPTH32F_STENCIL8,
GL_DEPTH24_STENCIL8
};
return cvt[(int)format];
}
GLenum GLTexture::ToDataFormat(PixelFormat format)
{
static GLint cvt[] =
{
GL_RGBA,
GL_BGRA,
GL_RG,
GL_RGBA,
GL_RED,
GL_RG,
GL_RGB,
GL_RGBA,
GL_DEPTH_STENCIL,
GL_DEPTH_STENCIL
};
return cvt[(int)format];
}
GLenum GLTexture::ToDataType(PixelFormat format)
{
static GLint cvt[] =
{
GL_UNSIGNED_BYTE,
GL_UNSIGNED_BYTE,
GL_FLOAT,
GL_FLOAT,
GL_FLOAT,
GL_FLOAT,
GL_FLOAT,
GL_FLOAT,
GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
GL_UNSIGNED_INT_24_8
};
return cvt[(int)format];
}