2019-12-22 23:13:09 +00:00
|
|
|
/*
|
|
|
|
** 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.
|
|
|
|
*/
|
2019-08-09 04:18:08 +00:00
|
|
|
|
2019-08-10 00:32:08 +00:00
|
|
|
#include "Precomp.h"
|
2019-12-23 19:09:38 +00:00
|
|
|
#include "GLTexture.h"
|
|
|
|
#include "GLRenderDevice.h"
|
2019-08-17 01:08:34 +00:00
|
|
|
#include <stdexcept>
|
2019-08-09 04:18:08 +00:00
|
|
|
|
2019-12-23 19:09:38 +00:00
|
|
|
GLTexture::GLTexture()
|
2019-08-09 04:18:08 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-23 19:09:38 +00:00
|
|
|
GLTexture::~GLTexture()
|
2019-12-26 00:09:31 +00:00
|
|
|
{
|
|
|
|
Finalize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLTexture::Finalize()
|
2019-08-14 11:51:05 +00:00
|
|
|
{
|
2019-12-22 22:44:58 +00:00
|
|
|
if (Device)
|
|
|
|
Invalidate();
|
2019-08-14 11:51:05 +00:00
|
|
|
}
|
|
|
|
|
2020-01-15 22:28:17 +00:00
|
|
|
void GLTexture::Set2DImage(int width, int height, PixelFormat format)
|
2019-08-09 21:15:48 +00:00
|
|
|
{
|
2020-01-15 22:28:17 +00:00
|
|
|
// 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;
|
2019-08-09 21:15:48 +00:00
|
|
|
mCubeTexture = false;
|
|
|
|
mWidth = width;
|
|
|
|
mHeight = height;
|
2020-01-15 22:28:17 +00:00
|
|
|
mFormat = format;
|
2019-08-09 21:15:48 +00:00
|
|
|
}
|
|
|
|
|
2020-01-15 22:28:17 +00:00
|
|
|
void GLTexture::SetCubeImage(int size, PixelFormat format)
|
2019-08-09 21:15:48 +00:00
|
|
|
{
|
|
|
|
mCubeTexture = true;
|
|
|
|
mWidth = size;
|
|
|
|
mHeight = size;
|
2020-01-15 22:28:17 +00:00
|
|
|
mFormat = format;
|
2019-08-09 21:15:48 +00:00
|
|
|
}
|
|
|
|
|
2019-12-25 17:08:43 +00:00
|
|
|
bool GLTexture::SetPixels(GLRenderDevice* device, const void* data)
|
2019-08-09 21:15:48 +00:00
|
|
|
{
|
2019-12-25 17:08:43 +00:00
|
|
|
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);
|
2020-01-15 22:28:17 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), data);
|
2022-01-04 19:17:12 +00:00
|
|
|
if (data != nullptr)
|
2019-12-25 17:08:43 +00:00
|
|
|
glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, oldBinding);
|
|
|
|
glActiveTexture(oldActiveTex);
|
|
|
|
|
|
|
|
return true;
|
2019-08-09 21:15:48 +00:00
|
|
|
}
|
|
|
|
|
2019-12-25 17:08:43 +00:00
|
|
|
bool GLTexture::SetCubePixels(GLRenderDevice* device, CubeMapFace face, const void* data)
|
2019-08-09 21:15:48 +00:00
|
|
|
{
|
2019-12-25 17:08:43 +00:00
|
|
|
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);
|
2020-01-15 22:28:17 +00:00
|
|
|
glTexImage2D(cubeMapFaceToGL[(int)face], 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), data);
|
2019-12-25 17:08:43 +00:00
|
|
|
if (data != nullptr && face == CubeMapFace::NegativeZ)
|
|
|
|
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_CUBE_MAP, oldBinding);
|
|
|
|
glActiveTexture(oldActiveTex);
|
|
|
|
|
|
|
|
return true;
|
2019-08-09 21:15:48 +00:00
|
|
|
}
|
|
|
|
|
2019-12-23 19:09:38 +00:00
|
|
|
void GLTexture::Invalidate()
|
2019-08-15 00:52:21 +00:00
|
|
|
{
|
|
|
|
if (mDepthRenderbuffer) glDeleteRenderbuffers(1, &mDepthRenderbuffer);
|
|
|
|
if (mFramebuffer) glDeleteFramebuffers(1, &mFramebuffer);
|
|
|
|
if (mTexture) glDeleteTextures(1, &mTexture);
|
2019-12-16 04:54:44 +00:00
|
|
|
if (mPBO) glDeleteBuffers(1, &mPBO);
|
2019-08-15 00:57:09 +00:00
|
|
|
mDepthRenderbuffer = 0;
|
2019-08-15 00:52:21 +00:00
|
|
|
mFramebuffer = 0;
|
|
|
|
mTexture = 0;
|
2019-12-16 04:54:44 +00:00
|
|
|
mPBO = 0;
|
2019-12-25 23:37:47 +00:00
|
|
|
if (Device) Device->mTextures.erase(ItTexture);
|
2019-12-22 22:44:58 +00:00
|
|
|
Device = nullptr;
|
2019-08-15 00:52:21 +00:00
|
|
|
}
|
|
|
|
|
2019-12-23 19:09:38 +00:00
|
|
|
GLuint GLTexture::GetTexture(GLRenderDevice* device)
|
2019-08-14 11:51:05 +00:00
|
|
|
{
|
|
|
|
if (mTexture == 0)
|
|
|
|
{
|
2019-12-25 23:46:05 +00:00
|
|
|
if (Device == nullptr)
|
|
|
|
{
|
|
|
|
Device = device;
|
|
|
|
ItTexture = Device->mTextures.insert(Device->mTextures.end(), this);
|
|
|
|
}
|
2019-12-22 22:44:58 +00:00
|
|
|
|
2019-08-16 02:10:03 +00:00
|
|
|
GLint oldActiveTex = GL_TEXTURE0;
|
|
|
|
glGetIntegerv(GL_ACTIVE_TEXTURE, &oldActiveTex);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
|
2019-08-16 09:24:22 +00:00
|
|
|
glGenTextures(1, &mTexture);
|
|
|
|
|
2019-08-14 11:51:05 +00:00
|
|
|
if (!IsCubeTexture())
|
|
|
|
{
|
|
|
|
GLint oldBinding = 0;
|
|
|
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding);
|
|
|
|
|
2019-12-16 04:54:44 +00:00
|
|
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
2019-08-14 11:51:05 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, mTexture);
|
2020-01-15 22:28:17 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), nullptr);
|
2019-12-25 11:39:55 +00:00
|
|
|
|
2019-08-14 11:51:05 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, oldBinding);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GLint oldBinding = 0;
|
|
|
|
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &oldBinding);
|
|
|
|
|
2019-12-16 04:54:44 +00:00
|
|
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
2019-08-14 11:51:05 +00:00
|
|
|
glBindTexture(GL_TEXTURE_CUBE_MAP, mTexture);
|
2020-01-15 22:28:17 +00:00
|
|
|
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);
|
2019-12-25 11:39:55 +00:00
|
|
|
|
2019-08-14 11:51:05 +00:00
|
|
|
glBindTexture(GL_TEXTURE_CUBE_MAP, oldBinding);
|
|
|
|
}
|
2019-08-16 02:10:03 +00:00
|
|
|
|
|
|
|
glActiveTexture(oldActiveTex);
|
2019-08-14 11:51:05 +00:00
|
|
|
}
|
|
|
|
return mTexture;
|
|
|
|
}
|
|
|
|
|
2019-12-23 19:09:38 +00:00
|
|
|
GLuint GLTexture::GetFramebuffer(GLRenderDevice* device, bool usedepthbuffer)
|
2019-08-15 00:52:21 +00:00
|
|
|
{
|
|
|
|
if (!usedepthbuffer)
|
|
|
|
{
|
|
|
|
if (mFramebuffer == 0)
|
|
|
|
{
|
2019-12-25 23:37:47 +00:00
|
|
|
GLuint texture = GetTexture(device);
|
2019-08-15 00:52:21 +00:00
|
|
|
glGenFramebuffers(1, &mFramebuffer);
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
|
2019-08-17 01:08:34 +00:00
|
|
|
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");
|
2019-08-15 00:52:21 +00:00
|
|
|
}
|
|
|
|
return mFramebuffer;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-15 16:48:38 +00:00
|
|
|
if (mDepthRenderbuffer == 0)
|
2019-08-15 00:52:21 +00:00
|
|
|
{
|
2019-12-25 23:46:05 +00:00
|
|
|
if (Device == nullptr)
|
|
|
|
{
|
|
|
|
Device = device;
|
|
|
|
ItTexture = Device->mTextures.insert(Device->mTextures.end(), this);
|
|
|
|
}
|
2019-12-22 22:44:58 +00:00
|
|
|
|
2019-12-15 16:48:38 +00:00
|
|
|
glGenRenderbuffers(1, &mDepthRenderbuffer);
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbuffer);
|
|
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mWidth, mHeight);
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
|
|
}
|
2019-08-15 00:52:21 +00:00
|
|
|
|
2019-12-15 16:48:38 +00:00
|
|
|
if (mFramebuffer == 0)
|
|
|
|
{
|
2019-12-25 23:37:47 +00:00
|
|
|
GLuint texture = GetTexture(device);
|
2019-08-15 00:52:21 +00:00
|
|
|
glGenFramebuffers(1, &mFramebuffer);
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
|
2019-08-17 01:08:34 +00:00
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
|
2019-08-15 00:57:09 +00:00
|
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepthRenderbuffer);
|
2019-08-17 01:08:34 +00:00
|
|
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
|
|
|
throw std::runtime_error("glCheckFramebufferStatus did not return GL_FRAMEBUFFER_COMPLETE");
|
2019-12-15 16:48:38 +00:00
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
2019-08-15 00:52:21 +00:00
|
|
|
}
|
2019-12-15 16:48:38 +00:00
|
|
|
return mFramebuffer;
|
2019-08-15 00:52:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-23 19:09:38 +00:00
|
|
|
GLuint GLTexture::GetPBO(GLRenderDevice* device)
|
2019-12-16 04:54:44 +00:00
|
|
|
{
|
|
|
|
if (mPBO == 0)
|
|
|
|
{
|
2019-12-25 23:46:05 +00:00
|
|
|
if (Device == nullptr)
|
|
|
|
{
|
|
|
|
Device = device;
|
|
|
|
ItTexture = Device->mTextures.insert(Device->mTextures.end(), this);
|
|
|
|
}
|
2019-12-22 22:44:58 +00:00
|
|
|
|
2019-12-16 04:54:44 +00:00
|
|
|
glGenBuffers(1, &mPBO);
|
|
|
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO);
|
|
|
|
glBufferData(GL_PIXEL_UNPACK_BUFFER, mWidth*mHeight * 4, NULL, GL_STREAM_DRAW);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mPBO;
|
|
|
|
}
|
2020-01-15 22:28:17 +00:00
|
|
|
|
|
|
|
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];
|
|
|
|
}
|