axmol/extensions/Effekseer/EffekseerRendererGL/EffekseerRenderer/GraphicsDevice.cpp

1639 lines
41 KiB
C++
Raw Normal View History

#include "GraphicsDevice.h"
#include "EffekseerRendererGL.Base.h"
#include "EffekseerRendererGL.GLExtension.h"
#ifdef __ANDROID__
#ifdef __ANDROID__DEBUG__
#include "android/log.h"
#define LOG(s) __android_log_print(ANDROID_LOG_DEBUG, "Tag", "%s", s)
#else
#define LOG(s) printf("%s", s)
#endif
#elif defined(_WIN32)
#include <windows.h>
#define LOG(s) OutputDebugStringA(s)
#else
#define LOG(s) printf("%s", s)
#endif
#undef min
namespace EffekseerRendererGL
{
namespace Backend
{
Effekseer::CustomVector<GLint> GetVertexAttribLocations(const VertexLayoutRef& vertexLayout, const ShaderRef& shader)
{
Effekseer::CustomVector<GLint> ret;
for (size_t i = 0; i < vertexLayout->GetElements().size(); i++)
{
const auto& element = vertexLayout->GetElements()[i];
ret.emplace_back(GLExt::glGetAttribLocation(shader->GetProgram(), element.Name.c_str()));
}
return ret;
}
void EnableLayouts(const VertexLayoutRef& vertexLayout, const Effekseer::CustomVector<GLint>& locations)
{
int32_t vertexSize = 0;
for (size_t i = 0; i < vertexLayout->GetElements().size(); i++)
{
const auto& element = vertexLayout->GetElements()[i];
vertexSize += Effekseer::Backend::GetVertexLayoutFormatSize(element.Format);
}
uint32_t offset = 0;
for (size_t i = 0; i < vertexLayout->GetElements().size(); i++)
{
const auto& element = vertexLayout->GetElements()[i];
const auto loc = locations[i];
GLenum type = {};
int32_t count = {};
GLboolean isNormalized = false;
if (element.Format == Effekseer::Backend::VertexLayoutFormat::R8G8B8A8_UINT)
{
count = 4;
type = GL_UNSIGNED_BYTE;
}
else if (element.Format == Effekseer::Backend::VertexLayoutFormat::R8G8B8A8_UNORM)
{
count = 4;
type = GL_UNSIGNED_BYTE;
isNormalized = GL_TRUE;
}
else if (element.Format == Effekseer::Backend::VertexLayoutFormat::R32_FLOAT)
{
count = 1;
type = GL_FLOAT;
}
else if (element.Format == Effekseer::Backend::VertexLayoutFormat::R32G32_FLOAT)
{
count = 2;
type = GL_FLOAT;
}
else if (element.Format == Effekseer::Backend::VertexLayoutFormat::R32G32B32_FLOAT)
{
count = 3;
type = GL_FLOAT;
}
else if (element.Format == Effekseer::Backend::VertexLayoutFormat::R32G32B32A32_FLOAT)
{
count = 4;
type = GL_FLOAT;
}
else
{
assert(0);
}
if (loc >= 0)
{
GLExt::glEnableVertexAttribArray(loc);
GLExt::glVertexAttribPointer(loc,
count,
type,
isNormalized,
vertexSize,
reinterpret_cast<GLvoid*>(static_cast<size_t>(offset)));
}
offset += Effekseer::Backend::GetVertexLayoutFormatSize(element.Format);
}
}
void DisableLayouts(const Effekseer::CustomVector<GLint>& locations)
{
for (size_t i = 0; i < locations.size(); i++)
{
auto loc = locations[i];
if (loc >= 0)
{
GLExt::glDisableVertexAttribArray(loc);
}
}
}
void StoreUniforms(const ShaderRef& shader, const UniformBufferRef& vertexUniform, const UniformBufferRef& fragmentUniform, bool transpose)
{
for (size_t i = 0; i < shader->GetLayout()->GetElements().size(); i++)
{
const auto& element = shader->GetLayout()->GetElements()[i];
const auto loc = shader->GetUniformLocations()[i];
if (loc < 0)
{
continue;
}
UniformBuffer* uniformBuffer = nullptr;
if (element.Stage == Effekseer::Backend::ShaderStageType::Vertex)
{
uniformBuffer = static_cast<UniformBuffer*>(vertexUniform.Get());
}
else if (element.Stage == Effekseer::Backend::ShaderStageType::Pixel)
{
uniformBuffer = static_cast<UniformBuffer*>(fragmentUniform.Get());
}
if (uniformBuffer != nullptr)
{
if (element.Type == Effekseer::Backend::UniformBufferLayoutElementType::Vector4)
{
const auto& buffer = uniformBuffer->GetBuffer();
assert(buffer.size() >= element.Offset + sizeof(float) * 4);
GLExt::glUniform4fv(loc, element.Count, reinterpret_cast<const GLfloat*>(buffer.data() + element.Offset));
}
else if (element.Type == Effekseer::Backend::UniformBufferLayoutElementType::Matrix44)
{
const auto& buffer = uniformBuffer->GetBuffer();
assert(buffer.size() >= element.Offset + sizeof(float) * 4 * 4);
GLExt::glUniformMatrix4fv(loc, element.Count, transpose ? GL_TRUE : GL_FALSE, reinterpret_cast<const GLfloat*>(buffer.data() + element.Offset));
}
else
{
// Unimplemented
assert(0);
}
}
else
{
// Invalid
assert(0);
}
}
}
void DeviceObject::OnLostDevice()
{
}
void DeviceObject::OnResetDevice()
{
}
VertexBuffer::VertexBuffer(GraphicsDevice* graphicsDevice)
: graphicsDevice_(graphicsDevice)
{
ES_SAFE_ADDREF(graphicsDevice_);
graphicsDevice_->Register(this);
}
VertexBuffer::~VertexBuffer()
{
graphicsDevice_->Unregister(this);
Deallocate();
ES_SAFE_RELEASE(graphicsDevice_);
}
bool VertexBuffer::Allocate(int32_t size, bool isDynamic)
{
resources_.resize(static_cast<size_t>(size));
GLExt::glGenBuffers(1, &buffer_);
int arrayBufferBinding = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &arrayBufferBinding);
GLExt::glBindBuffer(GL_ARRAY_BUFFER, buffer_);
GLExt::glBufferData(GL_ARRAY_BUFFER, static_cast<uint32_t>(resources_.size()), nullptr, isDynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
GLExt::glBindBuffer(GL_ARRAY_BUFFER, arrayBufferBinding);
return true;
}
void VertexBuffer::Deallocate()
{
if (buffer_ != 0)
{
GLExt::glDeleteBuffers(1, &buffer_);
buffer_ = 0;
}
}
void VertexBuffer::OnLostDevice()
{
Deallocate();
}
void VertexBuffer::OnResetDevice()
{
Allocate(size_, isDynamic_);
}
bool VertexBuffer::Init(int32_t size, bool isDynamic)
{
size_ = size;
isDynamic_ = isDynamic;
return Allocate(size_, isDynamic_);
}
void VertexBuffer::UpdateData(const void* src, int32_t size, int32_t offset)
{
if (size == 0 || src == nullptr)
{
return;
}
bool isSupportedBufferRange = GLExt::IsSupportedBufferRange();
#ifdef __ANDROID__
isSupportedBufferRange = false;
#endif
int arrayBufferBinding = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &arrayBufferBinding);
GLExt::glBindBuffer(GL_ARRAY_BUFFER, buffer_);
if (isSupportedBufferRange)
{
auto target = GLExt::glMapBufferRange(GL_ARRAY_BUFFER, offset, size, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
memcpy(target, src, size);
GLExt::glUnmapBuffer(GL_ARRAY_BUFFER);
}
else
{
memcpy(resources_.data() + offset, src, size);
GLExt::glBufferData(GL_ARRAY_BUFFER, static_cast<uint32_t>(resources_.size()), resources_.data(), isDynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
}
GLExt::glBindBuffer(GL_ARRAY_BUFFER, arrayBufferBinding);
}
IndexBuffer::IndexBuffer(GraphicsDevice* graphicsDevice)
: graphicsDevice_(graphicsDevice)
{
ES_SAFE_ADDREF(graphicsDevice_);
graphicsDevice_->Register(this);
}
IndexBuffer::~IndexBuffer()
{
graphicsDevice_->Unregister(this);
Deallocate();
ES_SAFE_RELEASE(graphicsDevice_);
}
bool IndexBuffer::Allocate(int32_t elementCount, int32_t stride)
{
resources_.resize(elementCount_ * stride_);
GLExt::glGenBuffers(1, &buffer_);
int elementArrayBufferBinding = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &elementArrayBufferBinding);
GLExt::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_);
GLExt::glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<uint32_t>(resources_.size()), nullptr, GL_STATIC_DRAW);
GLExt::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBufferBinding);
elementCount_ = elementCount;
strideType_ = stride == 4 ? Effekseer::Backend::IndexBufferStrideType::Stride4 : Effekseer::Backend::IndexBufferStrideType::Stride2;
return true;
}
void IndexBuffer::Deallocate()
{
if (buffer_ != 0)
{
GLExt::glDeleteBuffers(1, &buffer_);
buffer_ = 0;
}
}
void IndexBuffer::OnLostDevice()
{
Deallocate();
}
void IndexBuffer::OnResetDevice()
{
Allocate(elementCount_, stride_);
}
bool IndexBuffer::Init(int32_t elementCount, int32_t stride)
{
elementCount_ = elementCount;
stride_ = stride;
return Allocate(elementCount_, stride_);
}
void IndexBuffer::UpdateData(const void* src, int32_t size, int32_t offset)
{
if (size == 0 || src == nullptr)
{
return;
}
memcpy(resources_.data() + offset, src, size);
int elementArrayBufferBinding = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &elementArrayBufferBinding);
GLExt::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_);
GLExt::glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<uint32_t>(resources_.size()), resources_.data(), GL_STATIC_DRAW);
GLExt::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBufferBinding);
}
bool UniformBuffer::Init(int32_t size, const void* initialData)
{
buffer_.resize(size);
if (auto data = static_cast<const uint8_t*>(initialData))
{
buffer_.assign(data, data + size);
}
return true;
}
void UniformBuffer::UpdateData(const void* src, int32_t size, int32_t offset)
{
assert(buffer_.size() >= size + offset && offset >= 0);
buffer_.resize(size);
if (auto data = static_cast<const uint8_t*>(src))
{
memcpy(buffer_.data() + offset, src, size);
}
}
Texture::Texture(GraphicsDevice* graphicsDevice)
: graphicsDevice_(graphicsDevice)
{
ES_SAFE_ADDREF(graphicsDevice_);
}
Texture::~Texture()
{
if (onDisposed_)
{
onDisposed_();
}
else
{
if (buffer_ > 0)
{
glDeleteTextures(1, &buffer_);
buffer_ = 0;
}
if (renderbuffer_ > 0)
{
GLExt::glDeleteRenderbuffers(1, &renderbuffer_);
}
}
ES_SAFE_RELEASE(graphicsDevice_);
}
bool Texture::Init(const Effekseer::Backend::TextureParameter& param, const Effekseer::CustomVector<uint8_t>& initialData)
{
if (graphicsDevice_->GetDeviceType() == OpenGLDeviceType::OpenGL2 || graphicsDevice_->GetDeviceType() == OpenGLDeviceType::OpenGLES2)
{
if ((param.Format == Effekseer::Backend::TextureFormatType::B8G8R8A8_UNORM ||
param.Format == Effekseer::Backend::TextureFormatType::B8G8R8A8_UNORM_SRGB))
{
// not supported
return false;
}
}
bool woSampling = param.SampleCount <= 1;
// Compressed texture
auto isCompressed = param.Format == Effekseer::Backend::TextureFormatType::BC1 ||
param.Format == Effekseer::Backend::TextureFormatType::BC2 ||
param.Format == Effekseer::Backend::TextureFormatType::BC3 ||
param.Format == Effekseer::Backend::TextureFormatType::BC1_SRGB ||
param.Format == Effekseer::Backend::TextureFormatType::BC2_SRGB ||
param.Format == Effekseer::Backend::TextureFormatType::BC3_SRGB;
const size_t initialDataSize = initialData.size();
const void* initialDataPtr = initialData.size() > 0 ? initialData.data() : nullptr;
GLint bound = 0;
int boundTarget = GL_TEXTURE_BINDING_2D;
int target = GL_TEXTURE_2D;
if (woSampling)
{
if ((param.Usage & Effekseer::Backend::TextureUsageType::Array) != Effekseer::Backend::TextureUsageType::None)
{
boundTarget = GL_TEXTURE_BINDING_2D_ARRAY;
target = GL_TEXTURE_2D_ARRAY;
}
else if (param.Dimension == 3)
{
boundTarget = GL_TEXTURE_BINDING_3D;
target = GL_TEXTURE_3D;
}
glGetIntegerv(boundTarget, &bound);
glGenTextures(1, &buffer_);
glBindTexture(target, buffer_);
}
else
{
if (isCompressed)
{
return false;
}
glGetIntegerv(GL_RENDERBUFFER_BINDING, &bound);
GLExt::glGenRenderbuffers(1, &renderbuffer_);
GLExt::glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer_);
}
if (isCompressed)
{
GLenum format = GL_RGBA;
if (param.Format == Effekseer::Backend::TextureFormatType::BC1)
{
format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::BC2)
{
format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::BC3)
{
format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::BC1_SRGB)
{
format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::BC2_SRGB)
{
format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::BC3_SRGB)
{
format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
}
GLExt::glCompressedTexImage2D(target,
0,
format,
param.Size[0],
param.Size[1],
0,
static_cast<GLsizei>(initialDataSize),
initialDataPtr);
}
else
{
GLuint internalFormat = GL_RGBA;
GLenum format = GL_RGBA;
GLenum type = GL_UNSIGNED_BYTE;
if (param.Format == Effekseer::Backend::TextureFormatType::R8G8B8A8_UNORM)
{
internalFormat = GL_RGBA;
format = GL_RGBA;
type = GL_UNSIGNED_BYTE;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::B8G8R8A8_UNORM)
{
internalFormat = GL_RGBA;
format = GL_BGRA;
type = GL_UNSIGNED_BYTE;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::R8G8B8A8_UNORM_SRGB)
{
internalFormat = GL_SRGB8_ALPHA8;
format = GL_RGBA;
type = GL_UNSIGNED_BYTE;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::B8G8R8A8_UNORM_SRGB)
{
internalFormat = GL_SRGB8_ALPHA8;
format = GL_BGRA;
type = GL_UNSIGNED_BYTE;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::R8_UNORM)
{
internalFormat = GL_R8;
format = GL_RED;
type = GL_UNSIGNED_BYTE;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::R16_FLOAT)
{
internalFormat = GL_R16F;
format = GL_RED;
type = GL_HALF_FLOAT;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::R32_FLOAT)
{
internalFormat = GL_R16F;
format = GL_RED;
type = GL_FLOAT;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::R16G16_FLOAT)
{
internalFormat = GL_RG16F;
format = GL_RG;
type = GL_HALF_FLOAT;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::R16G16B16A16_FLOAT)
{
internalFormat = GL_RGBA16F;
format = GL_RGBA;
type = GL_HALF_FLOAT;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::R32G32B32A32_FLOAT)
{
internalFormat = GL_RGBA32F;
format = GL_RGBA;
type = GL_FLOAT;
}
else
{
// not supported
Effekseer::Log(Effekseer::LogType::Error, "The format is not supported.(" + std::to_string(static_cast<int>(param.Format)) + ")");
return false;
}
if (woSampling)
{
if ((param.Usage & Effekseer::Backend::TextureUsageType::Array) != Effekseer::Backend::TextureUsageType::None)
{
GLExt::glTexImage3D(target, 0, internalFormat, param.Size[0], param.Size[1], param.Size[2], 0, format, type, initialDataPtr);
}
else if (param.Dimension == 3)
{
GLExt::glTexImage3D(target, 0, internalFormat, param.Size[0], param.Size[1], param.Size[2], 0, format, type, initialDataPtr);
}
else
{
glTexImage2D(target,
0,
internalFormat,
param.Size[0],
param.Size[1],
0,
format,
type,
initialDataPtr);
}
}
else
{
GLExt::glRenderbufferStorageMultisample(GL_RENDERBUFFER, param.SampleCount, internalFormat, param.Size[0], param.Size[1]);
}
}
if (param.MipLevelCount != 1)
{
GLExt::glGenerateMipmap(target);
}
if (woSampling)
{
glBindTexture(target, bound);
}
else
{
GLExt::glBindRenderbuffer(GL_RENDERBUFFER, bound);
}
target_ = target;
param_ = param;
return true;
}
bool Texture::Init(const Effekseer::Backend::RenderTextureParameter& param)
{
Effekseer::Backend::TextureParameter paramInternal;
paramInternal.Size = {param.Size[0], param.Size[1], 1};
paramInternal.Format = param.Format;
paramInternal.MipLevelCount = 1;
paramInternal.SampleCount = param.SamplingCount;
paramInternal.Dimension = 2;
paramInternal.Usage = Effekseer::Backend::TextureUsageType::RenderTarget;
return Init(paramInternal, {});
}
bool Texture::Init(const Effekseer::Backend::DepthTextureParameter& param)
{
GLint internalFormat = 0;
GLenum format = 0;
if (param.Format == Effekseer::Backend::TextureFormatType::D24S8)
{
format = GL_DEPTH_STENCIL;
internalFormat = GL_DEPTH24_STENCIL8;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::D32S8)
{
format = GL_DEPTH_STENCIL;
internalFormat = GL_DEPTH32F_STENCIL8;
}
else if (param.Format == Effekseer::Backend::TextureFormatType::D32)
{
format = GL_DEPTH_COMPONENT;
internalFormat = GL_DEPTH_COMPONENT32;
}
else
{
return false;
}
bool initWithBuffer = param.SamplingCount <= 1;
GLint bound = 0;
if (initWithBuffer)
{
glGetIntegerv(GL_TEXTURE_BINDING_2D, &bound);
glGenTextures(1, &buffer_);
glBindTexture(GL_TEXTURE_2D, buffer_);
}
else
{
glGetIntegerv(GL_RENDERBUFFER_BINDING, &bound);
GLExt::glGenRenderbuffers(1, &renderbuffer_);
GLExt::glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer_);
}
if (initWithBuffer)
{
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, param.Size[0], param.Size[1], 0, format, GL_FLOAT, nullptr);
}
else
{
GLExt::glRenderbufferStorageMultisample(GL_RENDERBUFFER, param.SamplingCount, internalFormat, param.Size[0], param.Size[1]);
}
if (initWithBuffer)
{
glBindTexture(GL_TEXTURE_2D, bound);
}
else
{
GLExt::glBindRenderbuffer(GL_RENDERBUFFER, bound);
}
param_.Format = param.Format;
param_.Dimension = 2;
param_.Size = {param.Size[0], param.Size[1], 1};
param_.MipLevelCount = 1;
param_.SampleCount = param.SamplingCount;
param_.Usage = Effekseer::Backend::TextureUsageType::None;
return true;
}
bool Texture::Init(GLuint buffer, bool hasMipmap, const std::function<void()>& onDisposed)
{
if (buffer == 0)
return false;
buffer_ = buffer;
onDisposed_ = onDisposed;
// TODO : make correct
param_.Format = Effekseer::Backend::TextureFormatType::R8G8B8A8_UNORM;
param_.Dimension = 2;
param_.Size = {1, 1, 1};
param_.MipLevelCount = hasMipmap ? 2 : 1;
param_.SampleCount = 1;
param_.Usage = Effekseer::Backend::TextureUsageType::External;
return true;
}
bool VertexLayout::Init(const Effekseer::Backend::VertexLayoutElement* elements, int32_t elementCount)
{
elements_.resize(elementCount);
for (int32_t i = 0; i < elementCount; i++)
{
elements_[i] = elements[i];
}
return true;
}
Shader::Shader(GraphicsDevice* graphicsDevice)
: graphicsDevice_(graphicsDevice)
{
ES_SAFE_ADDREF(graphicsDevice_);
}
Shader::~Shader()
{
Reset();
ES_SAFE_RELEASE(graphicsDevice_);
}
bool Shader::Compile()
{
std::array<GLchar*, elementMax> vsCodePtr;
std::array<GLchar*, elementMax> psCodePtr;
std::array<GLint, elementMax> vsCodeLen;
std::array<GLint, elementMax> psCodeLen;
for (size_t i = 0; i < vsCodes_.size(); i++)
{
vsCodePtr[i] = const_cast<GLchar*>(vsCodes_[i].data());
vsCodeLen[i] = static_cast<GLint>(strlen(vsCodePtr[i]));
}
for (size_t i = 0; i < psCodes_.size(); i++)
{
psCodePtr[i] = const_cast<GLchar*>(psCodes_[i].data());
psCodeLen[i] = static_cast<GLint>(strlen(psCodePtr[i]));
}
GLint res_vs, res_fs, res_link = 0;
auto vert_shader = GLExt::glCreateShader(GL_VERTEX_SHADER);
GLExt::glShaderSource(vert_shader, vsCodes_.size(), const_cast<const GLchar**>(vsCodePtr.data()), vsCodeLen.data());
GLExt::glCompileShader(vert_shader);
GLExt::glGetShaderiv(vert_shader, GL_COMPILE_STATUS, &res_vs);
auto frag_shader = GLExt::glCreateShader(GL_FRAGMENT_SHADER);
GLExt::glShaderSource(frag_shader, psCodes_.size(), const_cast<const GLchar**>(psCodePtr.data()), psCodeLen.data());
GLExt::glCompileShader(frag_shader);
GLExt::glGetShaderiv(frag_shader, GL_COMPILE_STATUS, &res_fs);
// create shader program
auto program = GLExt::glCreateProgram();
GLExt::glAttachShader(program, vert_shader);
GLExt::glAttachShader(program, frag_shader);
// link shaders
GLExt::glLinkProgram(program);
GLExt::glGetProgramiv(program, GL_LINK_STATUS, &res_link);
#ifndef NDEBUG
if (res_link == GL_FALSE)
{
// output errors
char log[512];
int32_t log_size;
GLExt::glGetShaderInfoLog(vert_shader, sizeof(log), &log_size, log);
if (log_size > 0)
{
LOG(": Vertex Shader error.\n");
LOG(log);
}
GLExt::glGetShaderInfoLog(frag_shader, sizeof(log), &log_size, log);
if (log_size > 0)
{
LOG(": Fragment Shader error.\n");
LOG(log);
}
GLExt::glGetProgramInfoLog(program, sizeof(log), &log_size, log);
if (log_size > 0)
{
LOG(": Shader Link error.\n");
LOG(log);
}
}
#endif
// dispose shader objects
GLExt::glDeleteShader(frag_shader);
GLExt::glDeleteShader(vert_shader);
if (res_link == GL_FALSE)
{
GLExt::glDeleteProgram(program);
return false;
}
program_ = program;
if (GLExt::IsSupportedVertexArray())
{
GLExt::glGenVertexArrays(1, &vao_);
}
if (layout_ != nullptr)
{
textureLocations_.reserve(layout_->GetTextures().size());
for (size_t i = 0; i < layout_->GetTextures().size(); i++)
{
textureLocations_.emplace_back(GLExt::glGetUniformLocation(program_, layout_->GetTextures()[i].c_str()));
}
uniformLocations_.reserve(layout_->GetElements().size());
for (size_t i = 0; i < layout_->GetElements().size(); i++)
{
uniformLocations_.emplace_back(GLExt::glGetUniformLocation(program_, layout_->GetElements()[i].Name.c_str()));
}
}
return true;
}
void Shader::Reset()
{
if (program_ > 0)
{
GLExt::glDeleteProgram(program_);
}
if (vao_ > 0)
{
GLExt::glDeleteVertexArrays(1, &vao_);
}
textureLocations_.clear();
uniformLocations_.clear();
}
bool Shader::Init(const Effekseer::CustomVector<Effekseer::StringView<char>>& vsCodes, const Effekseer::CustomVector<Effekseer::StringView<char>>& psCodes, Effekseer::Backend::UniformLayoutRef& layout)
{
layout_ = layout;
if (vsCodes.size() > elementMax || psCodes.size() > elementMax)
{
Effekseer::Log(Effekseer::LogType::Error, "There are too many elements.");
return false;
}
vsCodes_.resize(vsCodes.size());
for (size_t i = 0; i < vsCodes_.size(); i++)
{
vsCodes_[i] = vsCodes[i].data();
}
psCodes_.resize(psCodes.size());
for (size_t i = 0; i < psCodes_.size(); i++)
{
psCodes_[i] = psCodes[i].data();
}
Reset();
return Compile();
}
void Shader::OnLostDevice()
{
Reset();
}
void Shader::OnResetDevice()
{
Compile();
}
bool PipelineState::Init(const Effekseer::Backend::PipelineStateParameter& param)
{
param_ = param;
attribLocations_ = GetVertexAttribLocations(param_.VertexLayoutPtr.DownCast<Backend::VertexLayout>(), param_.ShaderPtr.DownCast<Backend::Shader>());
return true;
}
RenderPass::RenderPass(GraphicsDevice* graphicsDevice)
: graphicsDevice_(graphicsDevice)
{
ES_SAFE_ADDREF(graphicsDevice_);
}
RenderPass::~RenderPass()
{
if (buffer_ > 0)
{
GLExt::glDeleteFramebuffers(1, &buffer_);
buffer_ = 0;
}
ES_SAFE_RELEASE(graphicsDevice_);
}
bool RenderPass::Init(Effekseer::FixedSizeVector<Effekseer::Backend::TextureRef, Effekseer::Backend::RenderTargetMax>& textures, Effekseer::Backend::TextureRef depthTexture)
{
for (int32_t i = 0; i < textures.size(); i++)
{
if (textures.at(i) == nullptr)
{
Effekseer::Log(Effekseer::LogType::Error, "RenderPass : textures " + std::to_string(i) + " must not be null.");
return false;
}
if ((textures.at(i)->GetParameter().Usage & Effekseer::Backend::TextureUsageType::RenderTarget) == Effekseer::Backend::TextureUsageType::None)
{
Effekseer::Log(Effekseer::LogType::Error, "RenderPass : textures " + std::to_string(i) + " must be Render.");
return false;
}
}
if (depthTexture != nullptr && !Effekseer::Backend::IsDepthTextureFormat(depthTexture->GetParameter().Format))
{
Effekseer::Log(Effekseer::LogType::Error, "RenderPass : depthTexture must be Depth.");
return false;
}
textures_ = textures;
depthTexture_ = depthTexture;
GLExt::glGenFramebuffers(1, &buffer_);
if (buffer_ == 0)
{
return false;
}
GLint backupFramebuffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &backupFramebuffer);
GLExt::glBindFramebuffer(GL_FRAMEBUFFER, buffer_);
for (int32_t i = 0; i < textures.size(); i++)
{
GLExt::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, static_cast<Texture*>(textures.at(i).Get())->GetBuffer(), 0);
}
if (depthTexture != nullptr)
{
GLExt::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, static_cast<Texture*>(depthTexture.Get())->GetBuffer(), 0);
}
textures_ = textures;
depthTexture_ = depthTexture;
const GLenum bufs[] = {
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3,
};
GLExt::glDrawBuffers(static_cast<GLsizei>(textures.size()), bufs);
GLExt::glBindFramebuffer(GL_FRAMEBUFFER, backupFramebuffer);
return true;
}
GraphicsDevice::GraphicsDevice(OpenGLDeviceType deviceType, bool isExtensionsEnabled)
: deviceType_(deviceType)
{
if (!GLExt::Initialize(deviceType, isExtensionsEnabled))
{
isValid_ = false;
}
if (deviceType == OpenGLDeviceType::OpenGL3 || deviceType == OpenGLDeviceType::OpenGLES3)
{
GLExt::glGenSamplers(Effekseer::TextureSlotMax, samplers_.data());
}
{
GLint v;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &v);
properties_[DevicePropertyType::MaxVaryingVectors] = v;
}
{
GLint v;
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &v);
properties_[DevicePropertyType::MaxVertexUniformVectors] = v;
}
{
GLint v;
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &v);
properties_[DevicePropertyType::MaxFragmentUniformVectors] = v;
}
{
GLint v;
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &v);
properties_[DevicePropertyType::MaxVertexTextureImageUnits] = v;
}
{
GLint v;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &v);
properties_[DevicePropertyType::MaxTextureImageUnits] = v;
}
GLExt::glGenFramebuffers(1, &frameBufferTemp_);
}
GraphicsDevice::~GraphicsDevice()
{
GLExt::glDeleteFramebuffers(1, &frameBufferTemp_);
if (isValid_)
{
if (deviceType_ == OpenGLDeviceType::OpenGL3 || deviceType_ == OpenGLDeviceType::OpenGLES3)
{
GLExt::glDeleteSamplers(Effekseer::TextureSlotMax, samplers_.data());
}
}
}
bool GraphicsDevice::GetIsValid() const
{
return isValid_;
}
int GraphicsDevice::GetProperty(DevicePropertyType type) const
{
return properties_.at(type);
}
void GraphicsDevice::LostDevice()
{
for (auto& o : objects_)
{
o->OnLostDevice();
}
}
void GraphicsDevice::ResetDevice()
{
for (auto& o : objects_)
{
o->OnResetDevice();
}
}
OpenGLDeviceType GraphicsDevice::GetDeviceType() const
{
return deviceType_;
}
void GraphicsDevice::Register(DeviceObject* deviceObject)
{
objects_.insert(deviceObject);
}
void GraphicsDevice::Unregister(DeviceObject* deviceObject)
{
objects_.erase(deviceObject);
}
Effekseer::Backend::VertexBufferRef GraphicsDevice::CreateVertexBuffer(int32_t size, const void* initialData, bool isDynamic)
{
auto ret = Effekseer::MakeRefPtr<VertexBuffer>(this);
if (!ret->Init(size, isDynamic))
{
return nullptr;
}
ret->UpdateData(initialData, size, 0);
return ret;
}
Effekseer::Backend::IndexBufferRef GraphicsDevice::CreateIndexBuffer(int32_t elementCount, const void* initialData, Effekseer::Backend::IndexBufferStrideType stride)
{
auto ret = Effekseer::MakeRefPtr<IndexBuffer>(this);
if (!ret->Init(elementCount, stride == Effekseer::Backend::IndexBufferStrideType::Stride4 ? 4 : 2))
{
return nullptr;
}
ret->UpdateData(initialData, elementCount * (stride == Effekseer::Backend::IndexBufferStrideType::Stride4 ? 4 : 2), 0);
return ret;
}
Effekseer::Backend::TextureRef GraphicsDevice::CreateTexture(const Effekseer::Backend::TextureParameter& param, const Effekseer::CustomVector<uint8_t>& initialData)
{
auto ret = Effekseer::MakeRefPtr<Texture>(this);
if (!ret->Init(param, initialData))
{
return nullptr;
}
return ret;
}
Effekseer::Backend::TextureRef GraphicsDevice::CreateRenderTexture(const Effekseer::Backend::RenderTextureParameter& param)
{
auto ret = Effekseer::MakeRefPtr<Texture>(this);
if (!ret->Init(param))
{
return nullptr;
}
return ret;
}
Effekseer::Backend::TextureRef GraphicsDevice::CreateDepthTexture(const Effekseer::Backend::DepthTextureParameter& param)
{
auto ret = Effekseer::MakeRefPtr<Texture>(this);
if (!ret->Init(param))
{
return nullptr;
}
return ret;
}
bool GraphicsDevice::CopyTexture(Effekseer::Backend::TextureRef& dst, Effekseer::Backend::TextureRef& src, const std::array<int, 3>& dstPos, const std::array<int, 3>& srcPos, const std::array<int, 3>& size, int32_t dstLayer, int32_t srcLayer)
{
auto dstgl = dst.DownCast<Texture>();
auto srcgl = src.DownCast<Texture>();
if (srcgl->GetTarget() != GL_TEXTURE_2D)
{
return false;
}
if (dstgl->GetTarget() != GL_TEXTURE_3D && dstgl->GetTarget() != GL_TEXTURE_2D_ARRAY) // use glCopyTexSubImage2D?
{
if (dstPos[2] != 0)
{
return false;
}
}
GLint backupFramebuffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &backupFramebuffer);
GLExt::glBindFramebuffer(GL_FRAMEBUFFER, frameBufferTemp_);
GLExt::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcgl->GetBuffer(), 0);
GLCheckError();
if (dstgl->GetTarget() == GL_TEXTURE_2D)
{
glBindTexture(dstgl->GetTarget(), dstgl->GetBuffer());
glCopyTexSubImage2D(dstgl->GetTarget(), 0, dstPos[0], dstPos[1], srcPos[0], srcPos[1], size[0], size[1]);
GLCheckError();
}
else
{
glBindTexture(dstgl->GetTarget(), dstgl->GetBuffer());
GLExt::glCopyTexSubImage3D(dstgl->GetTarget(), 0, dstPos[0], dstPos[1], dstPos[2] + dstLayer, srcPos[0], srcPos[1], size[0], size[1]);
GLCheckError();
}
GLExt::glBindFramebuffer(GL_FRAMEBUFFER, backupFramebuffer);
GLCheckError();
return true;
}
Effekseer::Backend::UniformBufferRef GraphicsDevice::CreateUniformBuffer(int32_t size, const void* initialData)
{
auto ret = Effekseer::MakeRefPtr<UniformBuffer>();
if (!ret->Init(size, initialData))
{
return nullptr;
}
return ret;
}
Effekseer::Backend::VertexLayoutRef GraphicsDevice::CreateVertexLayout(const Effekseer::Backend::VertexLayoutElement* elements, int32_t elementCount)
{
auto ret = Effekseer::MakeRefPtr<VertexLayout>();
if (!ret->Init(elements, elementCount))
{
return nullptr;
}
return ret;
}
Effekseer::Backend::RenderPassRef GraphicsDevice::CreateRenderPass(Effekseer::FixedSizeVector<Effekseer::Backend::TextureRef, Effekseer::Backend::RenderTargetMax>& textures, Effekseer::Backend::TextureRef& depthTexture)
{
auto ret = Effekseer::MakeRefPtr<RenderPass>(this);
if (!ret->Init(textures, depthTexture))
{
return nullptr;
}
return ret;
}
Effekseer::Backend::PipelineStateRef GraphicsDevice::CreatePipelineState(const Effekseer::Backend::PipelineStateParameter& param)
{
auto ret = Effekseer::MakeRefPtr<PipelineState>();
if (!ret->Init(param))
{
return nullptr;
}
return ret;
}
Effekseer::Backend::ShaderRef GraphicsDevice::CreateShaderFromKey(const char* key)
{
return nullptr;
}
Effekseer::Backend::ShaderRef GraphicsDevice::CreateShaderFromCodes(const Effekseer::CustomVector<Effekseer::StringView<char>>& vsCodes, const Effekseer::CustomVector<Effekseer::StringView<char>>& psCodes, Effekseer::Backend::UniformLayoutRef layout)
{
auto ret = Effekseer::MakeRefPtr<Shader>(this);
if (!ret->Init(vsCodes, psCodes, layout))
{
return nullptr;
}
return ret;
}
void GraphicsDevice::SetViewport(int32_t x, int32_t y, int32_t width, int32_t height)
{
glViewport(x, y, width, height);
GLCheckError();
}
void GraphicsDevice::Draw(const Effekseer::Backend::DrawParameter& drawParam)
{
if (drawParam.VertexBufferPtr == nullptr ||
drawParam.IndexBufferPtr == nullptr ||
drawParam.PipelineStatePtr == nullptr)
{
return;
}
auto pip = static_cast<PipelineState*>(drawParam.PipelineStatePtr.Get());
auto shader = static_cast<Shader*>(pip->GetParam().ShaderPtr.Get());
auto vertexLayout = static_cast<VertexLayout*>(pip->GetParam().VertexLayoutPtr.Get());
if (shader->GetLayout() == nullptr)
{
return;
}
GLint currentVAO = 0;
if (GLExt::IsSupportedVertexArray())
{
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &currentVAO);
GLExt::glBindVertexArray(shader->GetVAO());
}
GLExt::glBindBuffer(GL_ARRAY_BUFFER, static_cast<VertexBuffer*>(drawParam.VertexBufferPtr.Get())->GetBuffer());
GLExt::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, static_cast<IndexBuffer*>(drawParam.IndexBufferPtr.Get())->GetBuffer());
GLExt::glUseProgram(shader->GetProgram());
// textures
const auto textureCount = std::min(static_cast<int32_t>(shader->GetLayout()->GetTextures().size()), drawParam.TextureCount);
for (int32_t i = 0; i < textureCount; i++)
{
const auto textureSlot = shader->GetTextureLocations()[i];
if (textureSlot < 0)
{
continue;
}
GLExt::glUniform1i(textureSlot, i);
auto texture = static_cast<Texture*>(drawParam.TexturePtrs[i].Get());
if (texture != nullptr)
{
GLExt::glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(texture->GetTarget(), texture->GetBuffer());
GLCheckError();
static const GLint glfilterMin[] = {GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR};
static const GLint glfilterMin_NoneMipmap[] = {GL_NEAREST, GL_LINEAR};
static const GLint glfilterMag[] = {GL_NEAREST, GL_LINEAR};
static const GLint glwrap[] = {GL_REPEAT, GL_CLAMP_TO_EDGE};
GLint filterMin = 0;
GLint filterMag = 0;
GLint wrap = 0;
if (drawParam.TextureSamplingTypes[i] == Effekseer::Backend::TextureSamplingType::Linear)
{
if (texture->GetParameter().MipLevelCount != 1)
{
filterMin = glfilterMin[1];
}
else
{
filterMin = glfilterMin_NoneMipmap[1];
}
filterMag = glfilterMag[1];
}
else
{
if (texture->GetParameter().MipLevelCount != 1)
{
filterMin = glfilterMin[0];
}
else
{
filterMin = glfilterMin_NoneMipmap[0];
}
filterMag = glfilterMag[0];
}
if (drawParam.TextureWrapTypes[i] == Effekseer::Backend::TextureWrapType::Clamp)
{
wrap = glwrap[1];
}
else
{
wrap = glwrap[0];
}
if (deviceType_ == OpenGLDeviceType::OpenGL3 || deviceType_ == OpenGLDeviceType::OpenGLES3)
{
GLExt::glSamplerParameteri(samplers_[i], GL_TEXTURE_MAG_FILTER, filterMag);
GLExt::glSamplerParameteri(samplers_[i], GL_TEXTURE_MIN_FILTER, filterMin);
GLExt::glSamplerParameteri(samplers_[i], GL_TEXTURE_WRAP_S, wrap);
GLExt::glSamplerParameteri(samplers_[i], GL_TEXTURE_WRAP_T, wrap);
GLExt::glBindSampler(i, samplers_[i]);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterMag);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterMin);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
}
GLCheckError();
}
}
GLCheckError();
// uniformss
StoreUniforms(pip->GetParam().ShaderPtr.DownCast<Backend::Shader>(),
drawParam.VertexUniformBufferPtr.DownCast<Backend::UniformBuffer>(),
drawParam.PixelUniformBufferPtr.DownCast<Backend::UniformBuffer>(),
false);
GLCheckError();
// layouts
auto vl = pip->GetParam().VertexLayoutPtr;
EnableLayouts(vl.DownCast<Backend::VertexLayout>(), pip->GetAttribLocations());
GLCheckError();
// States
GLint frontFace = 0;
glGetIntegerv(GL_FRONT_FACE, &frontFace);
if (GL_CW == frontFace)
{
if (pip->GetParam().Culling == Effekseer::Backend::CullingType::Clockwise)
{
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
}
else if (pip->GetParam().Culling == Effekseer::Backend::CullingType::CounterClockwise)
{
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
}
else if (pip->GetParam().Culling == Effekseer::Backend::CullingType::DoubleSide)
{
glDisable(GL_CULL_FACE);
glCullFace(GL_FRONT_AND_BACK);
}
}
else
{
if (pip->GetParam().Culling == Effekseer::Backend::CullingType::Clockwise)
{
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
}
else if (pip->GetParam().Culling == Effekseer::Backend::CullingType::CounterClockwise)
{
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
}
else if (pip->GetParam().Culling == Effekseer::Backend::CullingType::DoubleSide)
{
glDisable(GL_CULL_FACE);
glCullFace(GL_FRONT_AND_BACK);
}
}
GLCheckError();
{
if (pip->GetParam().IsDepthTestEnabled || pip->GetParam().IsDepthWriteEnabled)
{
glEnable(GL_DEPTH_TEST);
}
else
{
glDisable(GL_DEPTH_TEST);
}
if (pip->GetParam().IsDepthTestEnabled)
{
std::array<GLenum, 8> depthFuncs;
depthFuncs[static_cast<int>(::Effekseer::Backend::DepthFuncType::Less)] = GL_LESS;
depthFuncs[static_cast<int>(::Effekseer::Backend::DepthFuncType::LessEqual)] = GL_LEQUAL;
depthFuncs[static_cast<int>(::Effekseer::Backend::DepthFuncType::NotEqual)] = GL_NOTEQUAL;
depthFuncs[static_cast<int>(::Effekseer::Backend::DepthFuncType::Equal)] = GL_EQUAL;
depthFuncs[static_cast<int>(::Effekseer::Backend::DepthFuncType::Greater)] = GL_GREATER;
depthFuncs[static_cast<int>(::Effekseer::Backend::DepthFuncType::GreaterEqual)] = GL_GEQUAL;
depthFuncs[static_cast<int>(::Effekseer::Backend::DepthFuncType::Never)] = GL_NEVER;
depthFuncs[static_cast<int>(::Effekseer::Backend::DepthFuncType::Always)] = GL_ALWAYS;
glDepthFunc(depthFuncs[static_cast<int>(pip->GetParam().DepthFunc)]);
}
else
{
glDepthFunc(GL_ALWAYS);
}
glDepthMask(pip->GetParam().IsDepthWriteEnabled);
}
{
if (pip->GetParam().IsBlendEnabled)
{
glEnable(GL_BLEND);
std::array<GLenum, 5> blendEq;
blendEq[static_cast<int>(::Effekseer::Backend::BlendEquationType::Add)] = GL_FUNC_ADD;
blendEq[static_cast<int>(::Effekseer::Backend::BlendEquationType::Sub)] = GL_FUNC_SUBTRACT;
blendEq[static_cast<int>(::Effekseer::Backend::BlendEquationType::ReverseSub)] = GL_FUNC_REVERSE_SUBTRACT;
blendEq[static_cast<int>(::Effekseer::Backend::BlendEquationType::Min)] = GL_MIN;
blendEq[static_cast<int>(::Effekseer::Backend::BlendEquationType::Max)] = GL_MAX;
std::array<GLenum, 10> blendFunc;
blendFunc[static_cast<int>(::Effekseer::Backend::BlendFuncType::Zero)] = GL_ZERO;
blendFunc[static_cast<int>(::Effekseer::Backend::BlendFuncType::One)] = GL_ONE;
blendFunc[static_cast<int>(::Effekseer::Backend::BlendFuncType::SrcColor)] = GL_SRC_COLOR;
blendFunc[static_cast<int>(::Effekseer::Backend::BlendFuncType::OneMinusSrcColor)] = GL_ONE_MINUS_SRC_COLOR;
blendFunc[static_cast<int>(::Effekseer::Backend::BlendFuncType::SrcAlpha)] = GL_SRC_ALPHA;
blendFunc[static_cast<int>(::Effekseer::Backend::BlendFuncType::OneMinusSrcAlpha)] = GL_ONE_MINUS_SRC_ALPHA;
blendFunc[static_cast<int>(::Effekseer::Backend::BlendFuncType::DstColor)] = GL_DST_COLOR;
blendFunc[static_cast<int>(::Effekseer::Backend::BlendFuncType::OneMinusDstColor)] = GL_ONE_MINUS_DST_COLOR;
blendFunc[static_cast<int>(::Effekseer::Backend::BlendFuncType::DstAlpha)] = GL_DST_ALPHA;
blendFunc[static_cast<int>(::Effekseer::Backend::BlendFuncType::OneMinusDstAlpha)] = GL_ONE_MINUS_DST_ALPHA;
GLExt::glBlendEquationSeparate(blendEq[static_cast<int>(pip->GetParam().BlendEquationRGB)], blendEq[static_cast<int>(pip->GetParam().BlendEquationAlpha)]);
GLExt::glBlendFuncSeparate(blendFunc[static_cast<int>(pip->GetParam().BlendSrcFunc)], blendFunc[static_cast<int>(pip->GetParam().BlendDstFunc)], blendFunc[static_cast<int>(pip->GetParam().BlendSrcFuncAlpha)], blendFunc[static_cast<int>(pip->GetParam().BlendDstFuncAlpha)]);
}
else
{
glDisable(GL_BLEND);
}
}
GLCheckError();
GLenum primitiveMode = {};
GLenum indexStrideType = {};
int32_t indexPerPrimitive = {};
if (pip->GetParam().Topology == Effekseer::Backend::TopologyType::Triangle)
{
primitiveMode = GL_TRIANGLES;
indexPerPrimitive = 3;
}
else if (pip->GetParam().Topology == Effekseer::Backend::TopologyType::Line)
{
primitiveMode = GL_LINES;
indexPerPrimitive = 2;
}
else if (pip->GetParam().Topology == Effekseer::Backend::TopologyType::Point)
{
primitiveMode = GL_POINTS;
indexPerPrimitive = 1;
}
int32_t indexStride = {};
if (drawParam.IndexBufferPtr->GetStrideType() == Effekseer::Backend::IndexBufferStrideType::Stride4)
{
indexStrideType = GL_UNSIGNED_INT;
indexStride = 4;
}
else if (drawParam.IndexBufferPtr->GetStrideType() == Effekseer::Backend::IndexBufferStrideType::Stride2)
{
indexStrideType = GL_UNSIGNED_SHORT;
indexStride = 2;
}
if (drawParam.InstanceCount > 1)
{
GLExt::glDrawElementsInstanced(primitiveMode, indexPerPrimitive * drawParam.PrimitiveCount, indexStrideType, (void*)(drawParam.IndexOffset * indexStride), drawParam.InstanceCount);
}
else
{
glDrawElements(primitiveMode, indexPerPrimitive * drawParam.PrimitiveCount, indexStrideType, (void*)(drawParam.IndexOffset * indexStride));
}
DisableLayouts(pip->GetAttribLocations());
if (GLExt::IsSupportedVertexArray())
{
GLExt::glBindVertexArray(currentVAO);
}
GLCheckError();
}
void GraphicsDevice::BeginRenderPass(Effekseer::Backend::RenderPassRef& renderPass, bool isColorCleared, bool isDepthCleared, Effekseer::Color clearColor)
{
const auto renderPassGL = static_cast<RenderPass*>(renderPass.Get());
if (renderPass != nullptr)
{
GLExt::glBindFramebuffer(GL_FRAMEBUFFER, static_cast<RenderPass*>(renderPass.Get())->GetBuffer());
}
else
{
GLExt::glBindFramebuffer(GL_FRAMEBUFFER, 0);
#if !defined(EMSCRIPTEN) && !defined(__EFFEKSEER_RENDERER_GLES2__) && !defined(__EFFEKSEER_RENDERER_GL2__) && !defined(__EFFEKSEER_RENDERER_GLES3__)
glDrawBuffer(GL_BACK);
#endif
}
if (renderPassGL != nullptr)
{
auto texture = renderPassGL->GetTextures().at(0);
glViewport(0, 0, texture->GetParameter().Size[0], texture->GetParameter().Size[1]);
}
GLCheckError();
GLbitfield flag = 0;
if (isColorCleared)
{
flag |= GL_COLOR_BUFFER_BIT;
glClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, clearColor.A / 255.0f);
GLCheckError();
}
if (isDepthCleared)
{
flag |= GL_DEPTH_BUFFER_BIT;
}
if (flag != 0)
{
glClear(flag);
}
GLCheckError();
}
void GraphicsDevice::EndRenderPass()
{
GLExt::glBindFramebuffer(GL_FRAMEBUFFER, 0);
GLCheckError();
}
bool GraphicsDevice::UpdateUniformBuffer(Effekseer::Backend::UniformBufferRef& buffer, int32_t size, int32_t offset, const void* data)
{
if (buffer == nullptr)
{
return false;
}
auto b = static_cast<UniformBuffer*>(buffer.Get());
b->UpdateData(data, size, offset);
return true;
}
Effekseer::Backend::TextureRef GraphicsDevice::CreateTexture(GLuint buffer, bool hasMipmap, const std::function<void()>& onDisposed)
{
auto ret = Effekseer::MakeRefPtr<Texture>(this);
if (!ret->Init(buffer, hasMipmap, onDisposed))
{
return nullptr;
}
return ret;
}
} // namespace Backend
} // namespace EffekseerRendererGL