#include "OpenGLGraphics.h"
#include "limonAPI/Graphics/GraphicsProgram.h"
#include "Material.h"
#include "Graphics/Texture.h"
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#endif
#ifdef TRACY_ENABLE
#include "tracy/TracyOpenGL.hpp"
#endif
void createGraphicsBackend(OptionsUtil::Options* options, std::shared_ptr<GraphicsInterface>* backend) {
*backend = std::make_shared<OpenGLGraphics>(options);
}
GLuint OpenGLGraphics::createShader(GLenum eShaderType, const std::string &strShaderContent, const std::string& shaderName) {
GLuint shader = glCreateShader(eShaderType);
const char *shaderCodePtr = strShaderContent.c_str();
glShaderSource(shader, 1, &shaderCodePtr, nullptr);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetShaderInfoLog(shader, infoLogLength, nullptr, strInfoLog);
const char *strShaderType = nullptr;
switch (eShaderType) {
case GL_VERTEX_SHADER:
strShaderType = "vertex";
break;
case GL_GEOMETRY_SHADER:
strShaderType = "geometry";
break;
case GL_FRAGMENT_SHADER:
strShaderType = "fragment";
break;
default: break;
}
std::cerr << "File: " << shaderName << "\n"
<< strShaderType << " type shader could not be compiled:\n"
<< strInfoLog << "\n--- Shader Code ---\n"
<< GraphicsInterface::formatShaderCode(strShaderContent) << std::endl;
delete[] strInfoLog;
glDeleteShader(shader);
shader = 0;
}
checkErrors("createShader");
return shader;
}
GLuint OpenGLGraphics::createProgram(const std::vector<GLuint> &shaderList) {
GLuint program = glCreateProgram();
for (size_t iLoop = 0; iLoop < shaderList.size(); iLoop++) {
glAttachShader(program, shaderList[iLoop]);
}
glLinkProgram(program);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetProgramInfoLog(program, infoLogLength, nullptr, strInfoLog);
std::cerr << "Linking failed: \n" << strInfoLog << std::endl;
delete[] strInfoLog;
} else {
}
for (size_t iLoop = 0; iLoop < shaderList.size(); iLoop++) {
glDetachShader(program, shaderList[iLoop]);
}
checkErrors("createProgram");
return program;
}
uint32_t OpenGLGraphics::createGraphicsProgram(const std::string &vertexShaderContent, const std::string &vertexShaderName, const std::string &geometryShaderContent, const std::string &geometryShaderName, const std::string &fragmentShaderContent, const std::string &fragmentShaderName) {
GLuint program;
std::vector<GLuint> shaderList;
checkErrors("before create shaders");
shaderList.push_back(createShader(GL_VERTEX_SHADER, vertexShaderContent, vertexShaderName));
if(!geometryShaderContent.empty()){
shaderList.push_back(createShader(GL_GEOMETRY_SHADER, geometryShaderContent, geometryShaderName));
}
shaderList.push_back(createShader(GL_FRAGMENT_SHADER, fragmentShaderContent, fragmentShaderName));
program = createProgram(shaderList);
std::for_each(shaderList.begin(), shaderList.end(), glDeleteShader);
attachGeneralUBOs(program);
checkErrors("createGraphicsProgram");
return program;
}
void OpenGLGraphics::initializeProgramAsset(const uint32_t programId,
std::unordered_map<std::string, std::shared_ptr<Uniform>> &uniformMap, std::unordered_map<std::string, uint32_t> &attributesMap,
std::unordered_map<std::string, std::pair<Uniform::VariableTypes, FrameBufferAttachPoints>> &outputMap) {
fillUniformAndOutputMaps(programId, uniformMap, attributesMap, outputMap);
checkErrors("initializeProgramAsset");
}
void OpenGLGraphics::destroyProgram(uint32_t programID) {
glDeleteProgram(programID);
checkErrors("destroyProgram");
}
void OpenGLGraphics::fillUniformAndOutputMaps(const GLuint program,
std::unordered_map<std::string, std::shared_ptr<Uniform>> &uniformMap,
std::unordered_map<std::string, uint32_t> &attributesMap,
std::unordered_map<std::string, std::pair<Uniform::VariableTypes, FrameBufferAttachPoints>> &outputMap) {
GLint i;
GLint count;
GLint size;
GLenum type;
GLint maxLength;
glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
GLchar* name = new GLchar[maxLength];
GLsizei length;
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count);
uint32_t uniformLocation;
for (i = 0; i < count; i++) {
glGetActiveUniform(program, (GLuint)i, maxLength, &length, &size, &type, name);
uniformLocation = glGetUniformLocation(program, name);
uniformMap[name] = std::make_shared<Uniform>(uniformLocation, name, getVariableType(type), size);
}
delete[] name;
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
name = new GLchar[maxLength];
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &count);
uint32_t attributeLocation;
for (i = 0; i < count; i++) {
glGetActiveAttrib(program, (GLuint)i, maxLength, &length, &size, &type, name);
attributeLocation = glGetAttribLocation(program, name);
attributesMap[name] = attributeLocation;
}
delete[] name;
if (isProgramInterfaceQuerySupported) {
glGetProgramInterfaceiv(program, GL_PROGRAM_OUTPUT, GL_MAX_NAME_LENGTH, &maxLength);
name = new GLchar[maxLength];
glGetProgramInterfaceiv(program, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES, &count);
bool depthAdded = false;
for(i = 0; i < count; i++) {
glGetProgramResourceName(program, GL_PROGRAM_OUTPUT, i, maxLength, &size, name);
const GLenum properties[2] = {GL_TYPE, GL_LOCATION};
GLint queryResults[2];
Uniform::VariableTypes variableType;
glGetProgramResourceiv(program, GL_PROGRAM_OUTPUT, i, 2, properties, 2, nullptr, queryResults);
variableType = getSamplerVariableType(queryResults);
FrameBufferAttachPoints attachPoint;
switch (queryResults[1]) {
case 0: attachPoint=FrameBufferAttachPoints::COLOR0; break;
case 1: attachPoint=FrameBufferAttachPoints::COLOR1; break;
case 2: attachPoint=FrameBufferAttachPoints::COLOR2; break;
case 3: attachPoint=FrameBufferAttachPoints::COLOR3; break;
case 4: attachPoint=FrameBufferAttachPoints::COLOR4; break;
case 5: attachPoint=FrameBufferAttachPoints::COLOR5; break;
case 6: attachPoint=FrameBufferAttachPoints::COLOR6; break;
default: attachPoint=FrameBufferAttachPoints::NONE;
}
if(strcmp(name, "gl_FragDepth") == 0) {
depthAdded = true;
outputMap["Depth"] = std::make_pair(variableType, FrameBufferAttachPoints::DEPTH);
} else {
outputMap[name] = std::make_pair(variableType, attachPoint);
}
}
if(!depthAdded) {
* FIXME this is causing a lot of headache. We need a better way to detect if a program writes to depth or not.
*/
outputMap["Depth"] =std::make_pair(Uniform::VariableTypes::TEXTURE_2D, FrameBufferAttachPoints::DEPTH);
}
delete[] name;
}
checkErrors("fillUniformAndOutputMaps");
}
Uniform::VariableTypes OpenGLGraphics::getVariableType(const GLenum typeEnum) const {
switch (typeEnum) {
case GL_SAMPLER_CUBE:
case GL_SAMPLER_CUBE_SHADOW:
return Uniform::VariableTypes::CUBEMAP;
case GL_SAMPLER_CUBE_MAP_ARRAY_ARB:
case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
return Uniform::VariableTypes::CUBEMAP_ARRAY;
case GL_SAMPLER_2D:
case GL_SAMPLER_2D_SHADOW:
return Uniform::VariableTypes::TEXTURE_2D;
case GL_SAMPLER_2D_ARRAY:
case GL_SAMPLER_2D_ARRAY_SHADOW:
return Uniform::VariableTypes::TEXTURE_2D_ARRAY;
case GL_BOOL: return Uniform::VariableTypes::BOOL;
case GL_INT: return Uniform::VariableTypes::INT;
case GL_FLOAT: return Uniform::VariableTypes::FLOAT;
case GL_FLOAT_VEC2: return Uniform::VariableTypes::FLOAT_VEC2;
case GL_FLOAT_VEC3: return Uniform::VariableTypes::FLOAT_VEC3;
case GL_FLOAT_VEC4: return Uniform::VariableTypes::FLOAT_VEC4;
case GL_FLOAT_MAT4: return Uniform::VariableTypes::FLOAT_MAT4;
default: return Uniform::VariableTypes::UNDEFINED;
}
}
Uniform::VariableTypes OpenGLGraphics::getSamplerVariableType(const GLint *queryResults) const {
Uniform::VariableTypes variableType;
switch (queryResults[0]) {
case GL_SAMPLER_CUBE:
case GL_SAMPLER_CUBE_SHADOW:
variableType = Uniform::VariableTypes::CUBEMAP;
break;
case GL_SAMPLER_CUBE_MAP_ARRAY_ARB:
case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
variableType = Uniform::VariableTypes::CUBEMAP_ARRAY;
break;
case GL_SAMPLER_2D:
case GL_SAMPLER_2D_SHADOW:
variableType = Uniform::VariableTypes::TEXTURE_2D;
break;
case GL_SAMPLER_2D_ARRAY:
case GL_SAMPLER_2D_ARRAY_SHADOW:
variableType = Uniform::VariableTypes::TEXTURE_2D_ARRAY;
break;
case GL_INT:
case GL_FLOAT:
case GL_FLOAT_VEC2:
case GL_FLOAT_VEC3:
case GL_FLOAT_VEC4:
variableType = Uniform::VariableTypes::TEXTURE_2D;
break;
default:
variableType = Uniform::VariableTypes::UNDEFINED;
}
return variableType;
}
void OpenGLGraphics::attachModelTexture(const uint32_t program) {
GLint allModelsAttachPoint = glGetUniformLocation(program, "allModelTransformsTexture");
this->setUniform(program, allModelsAttachPoint, GraphicsInterface::MODEL_BONE_TRANSFORM_TEXTURE_UNIT_START);
checkErrors("attachModelTexture");
}
void OpenGLGraphics::attachRigTexture(const uint32_t program) {
GLint allBonesAttachPoint = glGetUniformLocation(program, "allBoneTransformsTexture");
this->setUniform(program, allBonesAttachPoint, GraphicsInterface::MODEL_BONE_TRANSFORM_TEXTURE_UNIT_START + 1);
checkErrors("attachRigTexture");
}
void OpenGLGraphics::attachModelIndicesUBO(const uint32_t programID) {
GLuint allModelIndexesAttachPoint = 8;
int uniformIndex = glGetUniformBlockIndex(programID, "ModelIndexBlock");
if (uniformIndex >= 0) {
glBindBuffer(GL_UNIFORM_BUFFER, allModelIndexesUBOLocation);
glUniformBlockBinding(programID, uniformIndex, allModelIndexesAttachPoint);
glBindBufferRange(GL_UNIFORM_BUFFER, allModelIndexesAttachPoint, allModelIndexesUBOLocation, 0,
sizeof(glm::uvec4) * modelIndexBatchCapacity);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
checkErrors("attachModelIndicesUBO");
}
void OpenGLGraphics::attachMaterialUBO(const uint32_t program){
GLuint allMaterialsAttachPoint = 9;
int uniformIndex = glGetUniformBlockIndex(program, "MaterialInformationBlock");
if (uniformIndex >= 0) {
glBindBuffer(GL_UNIFORM_BUFFER, allMaterialsUBOLocation);
glUniformBlockBinding(program, uniformIndex, allMaterialsAttachPoint);
glBindBufferBase(GL_UNIFORM_BUFFER, allMaterialsAttachPoint, allMaterialsUBOLocation);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
checkErrors("attachMaterialUBO");
}
void OpenGLGraphics::attachGeneralUBOs(const GLuint program){
int uniformIndex = glGetUniformBlockIndex(program, "LightSourceBlock");
if (uniformIndex >= 0) {
glUniformBlockBinding(program, uniformIndex, GraphicsInterface::LIGHT_BLOCK_BINDING);
}
int uniformIndex2 = glGetUniformBlockIndex(program, "PlayerTransformBlock");
if (uniformIndex2 >= 0) {
glUniformBlockBinding(program, uniformIndex2, GraphicsInterface::PLAYER_BLOCK_BINDING);
}
}
OpenGLGraphics::OpenGLGraphics(OptionsUtil::Options *options): GraphicsInterface(options), options(options) {}
OpenGLGraphics::ContextInformation OpenGLGraphics::getContextInformation() {
GraphicsInterface::ContextInformation contextInformation;
contextInformation.SDL_GL_ACCELERATED_VISUAL = 1;
contextInformation.SDL_GL_CONTEXT_MAJOR_VERSION = 3;
contextInformation.SDL_GL_CONTEXT_MINOR_VERSION = 3;
contextInformation.SDL_GL_CONTEXT_PROFILE_MASK = 1;
contextInformation.SDL_GL_CONTEXT_FLAGS = 1;
return contextInformation;
}
std::string OpenGLGraphics::getShaderHeader() const {
return "#version 330\n"
"#extension GL_ARB_texture_cube_map_array : enable\n"
"#define NR_MODEL_INDEX_BATCH " + std::to_string(modelIndexBatchCapacity) + "\n"
"#define MODEL_TRANSFORM_TEXTURE_WIDTH " + std::to_string(MODEL_TRANSFORM_TEXTURE_WIDTH);
}
bool OpenGLGraphics::createGraphicsBackend() {
this->screenHeight = options->getScreenHeight();
this->screenWidth = options->getScreenWidth();
GLenum rev;
error = GL_NO_ERROR;
glewExperimental = GL_TRUE;
rev = glewInit();
if (GLEW_OK != rev) {
std::cout << "GLEW init Error: " << glewGetErrorString(rev) << std::endl;
exit(1);
} else {
std::cout << "GLEW Init: Success!" << std::endl;
}
checkErrors("after Context creation");
#ifdef __APPLE__
CGLContextObj cglContext = CGLGetCurrentContext();
if (cglContext == nullptr) {
std::cerr << "No current CGL context, can't pin the GL surface size" << std::endl;
} else {
GLint surfaceDimensions[2] = { (GLint)this->screenWidth, (GLint)this->screenHeight };
CGLError cglError = CGLSetParameter(cglContext, kCGLCPSurfaceBackingSize, surfaceDimensions);
if (cglError == kCGLNoError) {
cglError = CGLEnable(cglContext, kCGLCESurfaceBackingSize);
}
if (cglError != kCGLNoError) {
std::cerr << "Couldn't pin the GL surface size: " << CGLErrorString(cglError) << std::endl;
} else {
options->setDrawableWidth((int)this->screenWidth);
options->setDrawableHeight((int)this->screenHeight);
std::cout << "GL surface pinned to " << this->screenWidth << "x" << this->screenHeight
<< " pixels, the window server will scale it to the view" << std::endl;
}
}
#endif
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureImageUnits);
std::cout << "Maximum number of texture image units is " << maxTextureImageUnits << std::endl;
state = new OpenglState(maxTextureImageUnits, frameStats);
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
glDepthRange(0.0f, 1.0f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
std::cout << "Rendererer: " << glGetString(GL_RENDERER) << std::endl
<< "GL version: " << glGetString(GL_VERSION) << std::endl;
std::cout << "Supported GLSL version is "<< (char *) glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
GLint n, i;
glGetIntegerv(GL_NUM_EXTENSIONS, &n);
std::cout << "found " << n << " extensions." << std::endl;
bool isCubeMapArraySupported = false;
char extensionNameBuffer[100];
int foundExtensionCount = 0;
for (i = 0; i < n; i++) {
sprintf(extensionNameBuffer, "%s", glGetStringi(GL_EXTENSIONS, i));
if(std::strcmp(extensionNameBuffer, "GL_ARB_texture_cube_map_array") == 0) {
isCubeMapArraySupported = true;
++foundExtensionCount;
}
if(std::strcmp(extensionNameBuffer, "GL_ARB_program_interface_query") == 0) {
isProgramInterfaceQuerySupported = true;
++foundExtensionCount;
}
if(std::strcmp(extensionNameBuffer, "GL_ARB_framebuffer_no_attachments") == 0) {
isFrameBufferParameterSupported = true;
++foundExtensionCount;
}
if(std::strcmp(extensionNameBuffer, "GL_ARB_debug_output") == 0) {
isDebugOutputSupported = true;
++foundExtensionCount;
}
if (foundExtensionCount == 4) {
break;
}
}
if(!isCubeMapArraySupported) {
std::cerr << "Cubemap array support is mandatory, exiting.. " << std::endl;
exit(-1);
}
if(!isProgramInterfaceQuerySupported) {
std::cerr << "Program Interface Query support is missing, auto discovery of shaders will not work... " << std::endl;
}
std::cout << "Cubemap array support is present. " << std::endl;
GLint uniformBufferAlignSize = 0;
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniformBufferAlignSize);
* When you are using the buffer to keep multiple items, but bind single item, that item has to be aligned to this value
* If actually put all of them in an array and use the array for binding, it will be aligned to the definition you have (std140 aligns to 16)
* Don't need this after the material changes, but keeping it here incase I need it again.
*
if(uniformBufferAlignSize > materialUniformSize) {
materialUniformSize = uniformBufferAlignSize;
} else {
//it is possible that they are not aligning, align
if(materialUniformSize % uniformBufferAlignSize == 0 ) {
//aligned
} else {
//MU size 18, alignment 16 -> we need 32
materialUniformSize = ((materialUniformSize / uniformBufferAlignSize)+1) * uniformBufferAlignSize;
}
}
*/
std::cout << "Uniform alignment size is " << uniformBufferAlignSize << std::endl;
GLint maxVertexUniformBlockCount = 0;
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &maxVertexUniformBlockCount);
std::cout << "Uniform maxVertexUniformBlockCount size is " << maxVertexUniformBlockCount << std::endl;
GLint maxTextureSize = 0;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
std::cout << "Uniform maxTextureSize size is " << maxTextureSize << std::endl;
if (maxTextureSize < MODEL_TRANSFORM_TEXTURE_WIDTH || maxTextureSize < MODEL_TRANSFORM_TEXTURE_HEIGHT || maxTextureSize < 4 * NR_BONE || maxTextureSize < NR_MAX_RIGS) {
std::cerr << "Model or bone transform texture is larger than the supported texture size. This will cause errors, black screens or crashing." << std::endl;
}
GLint maxUniformBlockSize = 0;
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
modelIndexBatchCapacity = std::min((uint32_t)NR_MAX_MODEL_INDEX_BATCH, (uint32_t)(maxUniformBlockSize / sizeof(glm::uvec4)));
std::cout << "Uniform maxUniformBlockSize is " << maxUniformBlockSize << ", model index batch capacity is " << modelIndexBatchCapacity << std::endl;
glGenBuffers(1, &allMaterialsUBOLocation);
glBindBuffer(GL_UNIFORM_BUFFER, allMaterialsUBOLocation);
glBufferData(GL_UNIFORM_BUFFER, materialUniformSize * NR_MAX_MATERIALS, nullptr, GL_STATIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glGenBuffers(1, &allModelIndexesUBOLocation);
glBindBuffer(GL_UNIFORM_BUFFER, allModelIndexesUBOLocation);
glBufferData(GL_UNIFORM_BUFFER, sizeof(glm::uvec4) * modelIndexBatchCapacity, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
frustumPlanes.resize(6);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
checkErrors("Constructor");
return true;
}
GLuint OpenGLGraphics::generateBuffer(const GLuint number) {
GLuint bufferID;
glGenBuffers(number, &bufferID);
bufferObjects.push_back(bufferID);
checkErrors("generateBuffer");
return bufferID;
}
bool OpenGLGraphics::deleteBuffer(const GLuint number, const GLuint bufferID) {
if (glIsBuffer(bufferID)) {
glDeleteBuffers(number, &bufferID);
checkErrors("deleteBuffer");
return true;
}
checkErrors("deleteBuffer");
return false;
}
bool OpenGLGraphics::freeBuffer(const GLuint bufferID) {
for (unsigned int i = 0; i < bufferObjects.size(); ++i) {
if (bufferObjects[i] == bufferID) {
deleteBuffer(1, bufferObjects[i]);
bufferObjects[i] = bufferObjects[bufferObjects.size() - 1];
bufferObjects.pop_back();
checkErrors("freeBuffer");
return true;
}
}
checkErrors("freeBuffer");
return false;
}
GLuint OpenGLGraphics::generateVAO(const GLuint number) {
GLuint bufferID;
glGenVertexArrays(number, &bufferID);
vertexArrays.push_back(bufferID);
checkErrors("generateVAO");
return bufferID;
}
bool OpenGLGraphics::deleteVAO(const GLuint number, const GLuint bufferID) {
if (glIsBuffer(bufferID)) {
glDeleteVertexArrays(number, &bufferID);
checkErrors("deleteVAO");
return true;
}
checkErrors("deleteVAO");
return false;
}
bool OpenGLGraphics::freeVAO(const GLuint bufferID) {
for (unsigned int i = 0; i < vertexArrays.size(); ++i) {
if (vertexArrays[i] == bufferID) {
deleteBuffer(1, vertexArrays[i]);
vertexArrays[i] = vertexArrays[vertexArrays.size() - 1];
vertexArrays.pop_back();
checkErrors("freeVAO");
return true;
}
}
checkErrors("freeVAO");
return false;
}
void OpenGLGraphics::bufferVertexData(const std::vector<glm::vec3> &vertices,
const std::vector<glm::u16vec3> &faces,
uint32_t &vao, uint32_t &vbo, const uint32_t attachPointer,
uint32_t &ebo) {
uint32_t temp;
glGenVertexArrays(1, &temp);
glBindVertexArray(temp);
vao = temp;
ebo = generateBuffer(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, faces.size() * sizeof(glm::u16vec3), faces.data(), GL_STATIC_DRAW);
vbo = generateBuffer(1);
bufferObjects.push_back(vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(attachPointer, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(attachPointer);
glBindVertexArray(0);
checkErrors("bufferVertexData");
}
void OpenGLGraphics::bufferNormalData(const std::vector<glm::vec3> &normals,
uint32_t &vao, uint32_t &vbo, const uint32_t attachPointer) {
glBindVertexArray(vao);
vbo = generateBuffer(1);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(attachPointer, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(attachPointer);
glBindVertexArray(0);
checkErrors("bufferNormalData");
}
void OpenGLGraphics::bufferExtraVertexData(const std::vector<glm::vec4> &extraData,
uint32_t &vao, uint32_t &vbo, const uint32_t attachPointer) {
bufferExtraVertexData(4, GL_FLOAT, extraData.size() * sizeof(glm::vec4), extraData.data(), vao, vbo, attachPointer);
checkErrors("bufferVertexDataVec4");
}
void OpenGLGraphics::bufferExtraVertexData(const std::vector<glm::lowp_uvec4> &extraData,
uint32_t &vao, uint32_t &vbo, const uint32_t attachPointer) {
bufferExtraVertexData(4, GL_UNSIGNED_INT, extraData.size() * sizeof(glm::lowp_uvec4), extraData.data(), vao, vbo,
attachPointer);
checkErrors("bufferVertexDataIVec4");
}
void OpenGLGraphics::bufferExtraVertexData(uint32_t elementPerVertexCount, GLenum elementType, uint32_t dataSize,
const void *extraData, uint32_t &vao, uint32_t &vbo,
const uint32_t attachPointer) {
glBindVertexArray(vao);
vbo = generateBuffer(1);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, dataSize, extraData, GL_STATIC_DRAW);
switch (elementType) {
case GL_UNSIGNED_INT:
case GL_INT:
glVertexAttribIPointer(attachPointer, elementPerVertexCount, elementType, 0, 0);
break;
default:
glVertexAttribPointer(attachPointer, elementPerVertexCount, elementType, GL_FALSE, 0, 0);
}
glEnableVertexAttribArray(attachPointer);
glBindVertexArray(0);
checkErrors("bufferExtraVertexDataInternal");
}
void OpenGLGraphics::bufferVertexTextureCoordinates(const std::vector<glm::vec2> &textureCoordinates,
uint32_t &vao, uint32_t &vbo, const uint32_t attachPointer) {
glBindVertexArray(vao);
vbo = generateBuffer(1);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, textureCoordinates.size() * sizeof(glm::vec2), textureCoordinates.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(attachPointer, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(attachPointer);
glBindVertexArray(0);
checkErrors("bufferVertexTextureCoordinates");
}
void
OpenGLGraphics::updateVertexData(const std::vector<glm::vec3> &vertices, const std::vector<glm::u16vec3> &faces,
uint32_t &vbo, uint32_t &ebo) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, faces.size() * sizeof(glm::u16vec3), faces.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);
checkErrors("updateVertexData");
}
void OpenGLGraphics::updateNormalData(const std::vector<glm::vec3> &normals, uint32_t &vbo) {
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
checkErrors("updateNormalData");
}
void OpenGLGraphics::updateExtraVertexData(const std::vector<glm::vec4> &extraData, uint32_t &vbo) {
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, extraData.size() * sizeof(glm::vec4), extraData.data(), GL_STATIC_DRAW);
checkErrors("updateExtraVertexDataV4");
}
void OpenGLGraphics::updateExtraVertexData(const std::vector<glm::lowp_uvec4> &extraData, uint32_t &vbo) {
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, extraData.size() * sizeof(glm::lowp_uvec4), extraData.data(), GL_STATIC_DRAW);
checkErrors("updateExtraVertexDataIV4");
}
void OpenGLGraphics::updateVertexTextureCoordinates(const std::vector<glm::vec2> &textureCoordinates, uint32_t &vbo) {
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, textureCoordinates.size() * sizeof(glm::vec2), textureCoordinates.data(),
GL_STATIC_DRAW);
checkErrors("updateVertexTextureCoordinates");
}
void
OpenGLGraphics::switchRenderStage(uint32_t width, uint32_t height, uint32_t frameBufferID, bool blendEnabled, bool depthTestEnabled, bool depthWriteEnabled, bool scissorEnabled,
bool clearColor, bool clearDepth, CullModes cullMode, std::map<uint32_t, std::shared_ptr<Texture>> &inputs, const std::string &name) {
popDebugGroup();
pushDebugGroup(name);
glViewport(0, 0, width, height);
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
if(depthTestEnabled) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
if(depthWriteEnabled) {
glDepthMask(GL_TRUE);
} else {
glDepthMask(GL_FALSE);
}
if(scissorEnabled) {
glEnable(GL_SCISSOR_TEST);
} else {
glDisable(GL_SCISSOR_TEST);
}
if(clearColor && clearDepth) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} else if(clearColor) {
glClear(GL_COLOR_BUFFER_BIT);
} else if(clearDepth) {
glClear(GL_DEPTH_BUFFER_BIT);
}
for (auto inputIt = inputs.begin(); inputIt != inputs.end(); ++inputIt) {
switch (inputIt->second->getType()) {
case OpenGLGraphics::TextureTypes::T2D: state->attachTexture(inputIt->second->getTextureID(), inputIt->first); break;
case OpenGLGraphics::TextureTypes::T2D_ARRAY: state->attach2DTextureArray(inputIt->second->getTextureID(), inputIt->first); break;
case OpenGLGraphics::TextureTypes::TCUBE_MAP: state->attachCubemap(inputIt->second->getTextureID(), inputIt->first); break;
case OpenGLGraphics::TextureTypes::TCUBE_MAP_ARRAY: state->attachCubemapArray(inputIt->second->getTextureID(), inputIt->first); break;
}
}
switch (cullMode) {
case OpenGLGraphics::CullModes::FRONT: glEnable(GL_CULL_FACE);glCullFace(GL_FRONT); break;
case OpenGLGraphics::CullModes::BACK: glEnable(GL_CULL_FACE);glCullFace(GL_BACK); break;
case OpenGLGraphics::CullModes::NONE: glDisable(GL_CULL_FACE); break;
case OpenGLGraphics::CullModes::NO_CHANGE: break;
}
if(blendEnabled) {
glEnable(GL_BLEND);
} else {
glDisable(GL_BLEND);
}
checkErrors("switchRenderStage");
}
void
OpenGLGraphics::switchRenderStage(uint32_t width, uint32_t height, uint32_t frameBufferID, bool blendEnabled, bool depthTestEnabled, bool depthWriteEnabled, bool scissorEnabled,
bool clearColor, bool clearDepth, CullModes cullMode, const std::map<uint32_t, std::shared_ptr<Texture>> &inputs,
const std::map<std::shared_ptr<Texture>,
std::pair<FrameBufferAttachPoints, int>> &attachmentLayerMap, const std::string &name) {
popDebugGroup();
pushDebugGroup(name);
for (auto attachmentLayerIt = attachmentLayerMap.begin(); attachmentLayerIt != attachmentLayerMap.end(); ++attachmentLayerIt) {
attachDrawTextureToFrameBuffer(frameBufferID, attachmentLayerIt->first->getType(),
attachmentLayerIt->first->getTextureID(), attachmentLayerIt->second.first,
attachmentLayerIt->second.second, false);
}
glViewport(0, 0, width, height);
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
if(clearColor && clearDepth) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} else if(clearColor) {
glClear(GL_COLOR_BUFFER_BIT);
} else if(clearDepth) {
glClear(GL_DEPTH_BUFFER_BIT);
}
if(depthTestEnabled) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
if(depthWriteEnabled) {
glDepthMask(GL_TRUE);
} else {
glDepthMask(GL_FALSE);
}
if(scissorEnabled) {
glEnable(GL_SCISSOR_TEST);
} else {
glDisable(GL_SCISSOR_TEST);
}
for (auto inputIt = inputs.begin(); inputIt != inputs.end(); ++inputIt) {
switch (inputIt->second->getType()) {
case OpenGLGraphics::TextureTypes::T2D: state->attachTexture(inputIt->second->getTextureID(), inputIt->first); break;
case OpenGLGraphics::TextureTypes::T2D_ARRAY: state->attach2DTextureArray(inputIt->second->getTextureID(), inputIt->first); break;
case OpenGLGraphics::TextureTypes::TCUBE_MAP: state->attachCubemap(inputIt->second->getTextureID(), inputIt->first); break;
case OpenGLGraphics::TextureTypes::TCUBE_MAP_ARRAY: state->attachCubemapArray(inputIt->second->getTextureID(), inputIt->first); break;
}
}
switch (cullMode) {
case OpenGLGraphics::CullModes::FRONT: glEnable(GL_CULL_FACE);glCullFace(GL_FRONT); break;
case OpenGLGraphics::CullModes::BACK: glEnable(GL_CULL_FACE);glCullFace(GL_BACK); break;
case OpenGLGraphics::CullModes::NONE: glDisable(GL_CULL_FACE); break;
case OpenGLGraphics::CullModes::NO_CHANGE: break;
}
if(blendEnabled) {
glEnable(GL_BLEND);
} else {
glDisable(GL_BLEND);
}
checkErrors("switchRenderStageLayer");
}
void OpenGLGraphics::render(const uint32_t program, const uint32_t vao, const uint32_t ebo, const uint32_t elementCount, const uint16_t *startIndex) {
if (program == 0) {
std::cerr << "No program render requested." << std::endl;
return;
}
state->setProgram(program);
glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
frameStats.triangleCount += elementCount / 3;
++frameStats.drawCallCount;
glDrawElements(GL_TRIANGLES, elementCount, GL_UNSIGNED_SHORT, startIndex);
glBindVertexArray(0);
checkErrors("render");
}
void OpenGLGraphics::renderInstanced(uint32_t program, uint32_t VAO, uint32_t EBO, uint32_t elementCount,
uint32_t instanceCount) {
if (program == 0) {
std::cerr << "No program render requested." << std::endl;
return;
}
state->setProgram(program);
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
frameStats.triangleCount += (elementCount / 3) * instanceCount;
frameStats.instanceCount += instanceCount;
++frameStats.drawCallCount;
glDrawElementsInstanced(GL_TRIANGLES, elementCount, GL_UNSIGNED_SHORT, nullptr, instanceCount);
glBindVertexArray(0);
checkErrors("renderInstanced");
}
void OpenGLGraphics::renderInstanced(uint32_t program, uint32_t VAO, uint32_t EBO, uint32_t elementCount, uint32_t startOffset,
uint32_t instanceCount) {
if (program == 0) {
std::cerr << "No program render requested." << std::endl;
return;
}
state->setProgram(program);
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
frameStats.triangleCount += (elementCount / 3) * instanceCount;
frameStats.instanceCount += instanceCount;
++frameStats.drawCallCount;
glDrawElementsInstanced(GL_TRIANGLES, elementCount, GL_UNSIGNED_SHORT, (void*)(startOffset*sizeof(GLushort)), instanceCount);
glBindVertexArray(0);
checkErrors("renderInstancedOffset");
}
bool OpenGLGraphics::setUniform(const uint32_t programID, const uint32_t uniformID, const glm::mat4 &matrix) {
if (!glIsProgram(programID)) {
std::cerr << "invalid program for setting uniform." << std::endl;
return false;
} else {
state->setProgram(programID);
glUniformMatrix4fv(uniformID, 1, GL_FALSE, glm::value_ptr(matrix));
frameStats.uniformSetCount++;
checkErrors("setUniformMatrix");
return true;
}
}
bool
OpenGLGraphics::setUniformArray(const uint32_t programID, const uint32_t uniformID, const std::vector<glm::mat4> &matrixArray) {
if (!glIsProgram(programID)) {
std::cerr << "invalid program for setting uniform." << std::endl;
return false;
} else {
state->setProgram(programID);
int elementCount = matrixArray.size();
glUniformMatrix4fv(uniformID, elementCount, GL_FALSE, glm::value_ptr(matrixArray.at(0)));
frameStats.uniformSetCount++;
checkErrors("setUniformMatrixArray");
return true;
}
}
bool OpenGLGraphics::setUniform(const uint32_t programID, const uint32_t uniformID, const glm::vec3 &vector) {
if (!glIsProgram(programID)) {
std::cerr << "invalid program for setting uniform." << std::endl;
return false;
} else {
state->setProgram(programID);
glUniform3fv(uniformID, 1, glm::value_ptr(vector));
frameStats.uniformSetCount++;
checkErrors("setUniformVector");
return true;
}
}
bool OpenGLGraphics::setUniform(const uint32_t programID, const uint32_t uniformID, const std::vector<glm::vec3> &vectorArray) {
if (!glIsProgram(programID)) {
std::cerr << "invalid program for setting uniform." << std::endl;
return false;
} else {
state->setProgram(programID);
glUniform3fv(uniformID, vectorArray.size(), glm::value_ptr(*vectorArray.data()));
frameStats.uniformSetCount++;
checkErrors("setUniformVector");
return true;
}
}
bool OpenGLGraphics::setUniform(const uint32_t programID, const uint32_t uniformID, const float value) {
if (!glIsProgram(programID)) {
std::cerr << "invalid program for setting uniform." << std::endl;
return false;
} else {
state->setProgram(programID);
glUniform1f(uniformID, value);
frameStats.uniformSetCount++;
checkErrors("setUniformFloat");
return true;
}
}
bool OpenGLGraphics::setUniform(const uint32_t programID, const uint32_t uniformID, const int value) {
if (!glIsProgram(programID)) {
std::cerr << "invalid program for setting uniform." << std::endl;
return false;
} else {
state->setProgram(programID);
glUniform1i(uniformID, value);
frameStats.uniformSetCount++;
checkErrors("setUniformInt");
return true;
}
}
OpenGLGraphics::~OpenGLGraphics() {
for (unsigned int i = 0; i < bufferObjects.size(); ++i) {
deleteBuffer(1, bufferObjects[i]);
}
deleteBuffer(1, allMaterialsUBOLocation);
deleteBuffer(1, allModelIndexesUBOLocation);
glDeleteFramebuffers(1, &combineFrameBuffer);
}
void OpenGLGraphics::reshape() {
this->screenHeight = options->getScreenHeight();
this->screenWidth = options->getScreenWidth();
glViewport(0, 0, options->getScreenWidth(), options->getScreenHeight());
aspect = float(options->getScreenHeight()) / float(options->getScreenWidth());
orthogonalProjectionMatrix = glm::ortho(0.0f, (float) options->getScreenWidth(), 0.0f, (float) options->getScreenHeight());
checkErrors("reshape");
}
void OpenGLGraphics::setWrapMode(uint32_t textureID, TextureTypes textureType, TextureWrapModes wrapModeS,
TextureWrapModes wrapModeT, TextureWrapModes wrapModeR) {
GLenum glTextureType = 0;
switch (textureType) {
case TextureTypes::T2D: {
glTextureType = GL_TEXTURE_2D;
}
break;
case TextureTypes::T2D_ARRAY: {
glTextureType = GL_TEXTURE_2D_ARRAY;
}
break;
case TextureTypes::TCUBE_MAP: {
glTextureType = GL_TEXTURE_CUBE_MAP;
}
break;
case TextureTypes::TCUBE_MAP_ARRAY: {
glTextureType = GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
}
break;
}
glBindTexture(glTextureType, textureID);
switch(wrapModeS) {
case TextureWrapModes::NONE: std::cerr << "Wrap mode S not set, this is unexpected" << std::endl; break;
case TextureWrapModes::BORDER: glTexParameteri(glTextureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); break;
case TextureWrapModes::REPEAT: glTexParameteri(glTextureType, GL_TEXTURE_WRAP_S, GL_REPEAT); break;
case TextureWrapModes::EDGE: glTexParameteri(glTextureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); break;
}
switch(wrapModeT) {
case TextureWrapModes::NONE: std::cerr << "Wrap mode T not set, this is unexpected" << std::endl; break;
case TextureWrapModes::BORDER: glTexParameteri(glTextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); break;
case TextureWrapModes::REPEAT: glTexParameteri(glTextureType, GL_TEXTURE_WRAP_T, GL_REPEAT); break;
case TextureWrapModes::EDGE: glTexParameteri(glTextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); break;
}
switch(wrapModeR) {
case TextureWrapModes::NONE: break;
case TextureWrapModes::BORDER: glTexParameteri(glTextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); break;
case TextureWrapModes::REPEAT: glTexParameteri(glTextureType, GL_TEXTURE_WRAP_T, GL_REPEAT); break;
case TextureWrapModes::EDGE: glTexParameteri(glTextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); break;
}
checkErrors("setWrapMode");
}
void OpenGLGraphics::setFilterMode(uint32_t textureID, TextureTypes textureType, FilterModes filterMode) {
GLenum glTextureType = 0;
switch (textureType) {
case TextureTypes::T2D: {
glTextureType = GL_TEXTURE_2D;
}
break;
case TextureTypes::T2D_ARRAY: {
glTextureType = GL_TEXTURE_2D_ARRAY;
}
break;
case TextureTypes::TCUBE_MAP: {
glTextureType = GL_TEXTURE_CUBE_MAP;
}
break;
case TextureTypes::TCUBE_MAP_ARRAY: {
glTextureType = GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
}
break;
}
glBindTexture(glTextureType, textureID);
switch (filterMode) {
case FilterModes::NEAREST:
glTexParameteri(glTextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(glTextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case FilterModes::LINEAR:
glTexParameteri(glTextureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(glTextureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
case FilterModes::TRILINEAR:
glTexParameteri(glTextureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(glTextureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
default:
std::cerr << "Unknown filter mode set, this should never happen. " << std::endl;
}
checkErrors("setFilterMode");
}
void OpenGLGraphics::setTextureBorder(uint32_t textureID, TextureTypes textureType, bool isBorderColorSet,
const std::vector<float> &borderColors) {
GLenum glTextureType;
switch (textureType) {
case TextureTypes::T2D: {
glTextureType = GL_TEXTURE_2D;
}
break;
case TextureTypes::T2D_ARRAY: {
glTextureType = GL_TEXTURE_2D_ARRAY;
}
break;
case TextureTypes::TCUBE_MAP: {
glTextureType = GL_TEXTURE_CUBE_MAP;
}
break;
case TextureTypes::TCUBE_MAP_ARRAY: {
glTextureType = GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
}
break;
default:
std::cerr << "Unknown texture type set, this should never happen. " << std::endl;
exit(-1);
}
glBindTexture(glTextureType, textureID);
if(isBorderColorSet) {
glTexParameteri(glTextureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(glTextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
if(borderColors.size() < 4) {
std::cerr << "Border color don't have 4 elements, this should never happen!" << std::endl;
std::exit(-1);
}
GLfloat borderColor[] = {borderColors[0], borderColors[1], borderColors[2], borderColors[3]};
glTexParameterfv(glTextureType, GL_TEXTURE_BORDER_COLOR, borderColor);
} else {
glTexParameteri(glTextureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(glTextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
checkErrors("setTextureBorder");
}
uint32_t OpenGLGraphics::createFrameBuffer(uint32_t width, uint32_t height) {
GLuint newFrameBufferLocation;
glGenFramebuffers(1, &newFrameBufferLocation);
glBindFramebuffer(GL_FRAMEBUFFER, newFrameBufferLocation);
if(getFrameBufferParameterSupported()) {
glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, width);
glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, height);
}
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
checkErrors("createFrameBuffer");
return newFrameBufferLocation;
}
void OpenGLGraphics::deleteFrameBuffer(uint32_t frameBufferID) {
glDeleteFramebuffers(1, &frameBufferID);
checkErrors("deleteFrameBuffer");
}
void OpenGLGraphics::attachDrawTextureToFrameBuffer(uint32_t frameBufferID, TextureTypes textureType, uint32_t textureID,
FrameBufferAttachPoints attachPoint, int32_t layer, bool clear) {
int32_t maxDrawBuffers;
glGetIntegerv( GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
GLenum glAttachment = 0;
uint32_t index = 0;
switch(attachPoint) {
case FrameBufferAttachPoints::NONE: glAttachment = GL_NONE; break;
case FrameBufferAttachPoints::COLOR0: glAttachment = GL_COLOR_ATTACHMENT0; break;
case FrameBufferAttachPoints::COLOR1: glAttachment = GL_COLOR_ATTACHMENT1; index = 1;break;
case FrameBufferAttachPoints::COLOR2: glAttachment = GL_COLOR_ATTACHMENT2; index = 2;break;
case FrameBufferAttachPoints::COLOR3: glAttachment = GL_COLOR_ATTACHMENT3; index = 3;break;
case FrameBufferAttachPoints::COLOR4: glAttachment = GL_COLOR_ATTACHMENT4; index = 4;break;
case FrameBufferAttachPoints::COLOR5: glAttachment = GL_COLOR_ATTACHMENT5; index = 5;break;
case FrameBufferAttachPoints::COLOR6: glAttachment = GL_COLOR_ATTACHMENT6; index = 6;break;
case FrameBufferAttachPoints::DEPTH: glAttachment = GL_DEPTH_ATTACHMENT; break;
}
if(attachPoint != OpenGLGraphics::FrameBufferAttachPoints::DEPTH) {
if (index >= (uint32_t)maxDrawBuffers) {
std::cerr << "Trying to attach to a color attachment index (" << index << ") that is higher than supported (" << maxDrawBuffers << ")" << std::endl;
} else {
std::vector<GLenum> drawBufferAttachments(maxDrawBuffers);
for (int i = 0; i < maxDrawBuffers; ++i) {
if (i == (int)index) {
drawBufferAttachments[i] = glAttachment;
if(clear) {
unsigned int tempAttachmentBuffer[1] = {glAttachment};
glDrawBuffers(1, tempAttachmentBuffer);
}
} else {
GLint currentAttachment;
glGetIntegerv(GL_DRAW_BUFFER0 + i, ¤tAttachment);
drawBufferAttachments[i] = currentAttachment;
}
}
glDrawBuffers(maxDrawBuffers, drawBufferAttachments.data());
}
}
switch (textureType) {
case TextureTypes::T2D: {
glFramebufferTexture2D(GL_FRAMEBUFFER, glAttachment, GL_TEXTURE_2D, textureID, 0);
}
break;
case TextureTypes::T2D_ARRAY: {
if(layer == -1 ) {
glFramebufferTexture(GL_FRAMEBUFFER, glAttachment, textureID, 0);
} else {
glFramebufferTextureLayer(GL_FRAMEBUFFER, glAttachment, textureID, 0, layer);
}
}
break;
case TextureTypes::TCUBE_MAP: {
glFramebufferTexture(GL_FRAMEBUFFER, glAttachment, textureID, 0);
}
break;
case TextureTypes::TCUBE_MAP_ARRAY: {
glFramebufferTexture(GL_FRAMEBUFFER, glAttachment, textureID, 0);
}
break;
}
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "frame buffer texture to attach is not complete" << std::endl;
}
if(clear) {
if(attachPoint == OpenGLGraphics::FrameBufferAttachPoints::DEPTH) {
glClear(GL_DEPTH_BUFFER_BIT);
} else {
glClear(GL_COLOR_BUFFER_BIT);
}
}
checkErrors("attachDrawTextureToFrameBuffer");
}
uint32_t OpenGLGraphics::createTexture(int height, int width, TextureTypes type, InternalFormatTypes internalFormat, FormatTypes format, DataTypes dataType, uint32_t textureLayers) {
GLuint texture;
glGenTextures(1, &texture);
state->activateTextureUnit(0);
GLint glInternalDataFormat = 0;
switch (internalFormat) {
case InternalFormatTypes::RED: glInternalDataFormat = GL_R8; break;
case InternalFormatTypes::RG8: glInternalDataFormat = GL_RG8; break;
case InternalFormatTypes::R32F: glInternalDataFormat = GL_R32F; break;
case InternalFormatTypes::RGB: glInternalDataFormat = GL_RGB; break;
case InternalFormatTypes::RGBA: glInternalDataFormat = GL_RGBA; break;
case InternalFormatTypes::RGB16F: glInternalDataFormat = GL_RGB16F; break;
case InternalFormatTypes::RGBA16F: glInternalDataFormat = GL_RGBA16F; break;
case InternalFormatTypes::RGB32F: glInternalDataFormat = GL_RGB32F; break;
case InternalFormatTypes::RGBA32F: glInternalDataFormat = GL_RGBA32F; break;
case InternalFormatTypes::DEPTH: glInternalDataFormat = GL_DEPTH_COMPONENT; break;
case InternalFormatTypes::COMPRESSED_RGB: glInternalDataFormat = GL_COMPRESSED_RGB; break;
case InternalFormatTypes::COMPRESSED_RGBA: glInternalDataFormat = GL_COMPRESSED_RGBA; break;
}
GLenum glFormat = 0;
switch (format) {
case FormatTypes::RED: glFormat = GL_RED; break;
case FormatTypes::RG: glFormat = GL_RG; break;
case FormatTypes::RGB: glFormat = GL_RGB; break;
case FormatTypes::RGBA: glFormat = GL_RGBA; break;
case FormatTypes::DEPTH: glFormat = GL_DEPTH_COMPONENT; break;
}
GLenum glDataType = 0;
switch (dataType) {
case DataTypes::FLOAT: glDataType = GL_FLOAT; break;
case DataTypes::HALF_FLOAT: glDataType = GL_HALF_FLOAT; break;
case DataTypes::UNSIGNED_BYTE: glDataType = GL_UNSIGNED_BYTE; break;
case DataTypes::UNSIGNED_SHORT: glDataType = GL_UNSIGNED_SHORT; break;
case DataTypes::UNSIGNED_INT: glDataType = GL_UNSIGNED_INT; break;
}
GLenum glTextureType = 0;
switch (type) {
case TextureTypes::T2D: {
glTextureType = GL_TEXTURE_2D;
glBindTexture(glTextureType, texture);
glTexImage2D(GL_TEXTURE_2D, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, nullptr);
}
break;
case TextureTypes::T2D_ARRAY: {
glTextureType = GL_TEXTURE_2D_ARRAY;
glBindTexture(glTextureType, texture);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, glInternalDataFormat, width,height, textureLayers, 0, glFormat, glDataType, nullptr);
}
break;
case TextureTypes::TCUBE_MAP: {
glTextureType = GL_TEXTURE_CUBE_MAP;
glBindTexture(glTextureType, texture);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, nullptr);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, nullptr);
}
break;
case TextureTypes::TCUBE_MAP_ARRAY: {
glTextureType = GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
glBindTexture(glTextureType, texture);
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY_ARB, 0, glInternalDataFormat, width,height, textureLayers * 6, 0,glFormat, glDataType, nullptr);
if(height != width) {
std::cerr << "Cubemaps require square textures, this will fail!" << std::endl;
}
}
break;
}
glTexParameteri(glTextureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(glTextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
std::string temp;
OptionsUtil::Options::Option<std::string> textureFilteringOption = options->getOption<std::string>(HASH("render_textureFiltering"));
temp = textureFilteringOption.getOrDefault("Nearest");
if (temp == "Nearest") {
glTexParameteri(glTextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(glTextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
} else if(temp == "Bilinear") {
glTexParameteri(glTextureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(glTextureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else if(temp == "Trilinear") {
glTexParameteri(glTextureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(glTextureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
if (format == FormatTypes::DEPTH) {
if (type == TextureTypes::T2D_ARRAY || type == TextureTypes::TCUBE_MAP_ARRAY) {
glTexParameteri(glTextureType, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(glTextureType, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
}
}
glBindTexture(glTextureType, 0);
checkErrors("Texture Constructor");
return texture;
}
void
OpenGLGraphics::loadTextureData(uint32_t textureID, int height, int width, TextureTypes type, InternalFormatTypes internalFormat, FormatTypes format, DataTypes dataType, uint32_t depth,
void *data, void *data2, void *data3, void *data4, void *data5, void *data6) {
state->activateTextureUnit(0);
GLint glInternalDataFormat = 0;
switch (internalFormat) {
case InternalFormatTypes::RED: glInternalDataFormat = GL_R8; break;
case InternalFormatTypes::RG8: glInternalDataFormat = GL_RG8; break;
case InternalFormatTypes::R32F: glInternalDataFormat = GL_R32F; break;
case InternalFormatTypes::RGB: glInternalDataFormat = GL_RGB; break;
case InternalFormatTypes::RGBA: glInternalDataFormat = GL_RGBA; break;
case InternalFormatTypes::RGB16F: glInternalDataFormat = GL_RGB16F; break;
case InternalFormatTypes::RGBA16F: glInternalDataFormat = GL_RGBA16F; break;
case InternalFormatTypes::RGB32F: glInternalDataFormat = GL_RGB32F; break;
case InternalFormatTypes::RGBA32F: glInternalDataFormat = GL_RGBA32F; break;
case InternalFormatTypes::DEPTH: glInternalDataFormat = GL_DEPTH_COMPONENT; break;
case InternalFormatTypes::COMPRESSED_RGB: glInternalDataFormat = GL_COMPRESSED_RGB; break;
case InternalFormatTypes::COMPRESSED_RGBA: glInternalDataFormat = GL_COMPRESSED_RGBA; break;
}
GLenum glFormat = 0;
switch (format) {
case FormatTypes::RED: glFormat = GL_RED; break;
case FormatTypes::RG: glFormat = GL_RG; break;
case FormatTypes::RGB: glFormat = GL_RGB; break;
case FormatTypes::RGBA: glFormat = GL_RGBA; break;
case FormatTypes::DEPTH: glFormat = GL_DEPTH_COMPONENT; break;
}
GLenum glDataType = 0;
switch (dataType) {
case DataTypes::FLOAT: glDataType = GL_FLOAT; break;
case DataTypes::UNSIGNED_BYTE: glDataType = GL_UNSIGNED_BYTE; break;
case DataTypes::UNSIGNED_SHORT: glDataType = GL_UNSIGNED_SHORT; break;
case DataTypes::UNSIGNED_INT: glDataType = GL_UNSIGNED_INT; break;
case DataTypes::HALF_FLOAT: glDataType = GL_HALF_FLOAT; break;
}
GLenum glTextureType = 0;
switch (type) {
case TextureTypes::T2D: {
glTextureType = GL_TEXTURE_2D;
glBindTexture(glTextureType, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, data);
}
break;
case TextureTypes::T2D_ARRAY: {
glTextureType = GL_TEXTURE_2D_ARRAY;
glBindTexture(glTextureType, textureID);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, glInternalDataFormat, width,height, depth, 0, glFormat, glDataType, data);
std::cerr << "This method of loading texture data is not tested." << std::endl;
}
break;
case TextureTypes::TCUBE_MAP: {
glTextureType = GL_TEXTURE_CUBE_MAP;
glBindTexture(glTextureType, textureID);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, data);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, data2);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, data3);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, data4);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, data5);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, glInternalDataFormat, width, height, 0, glFormat, glDataType, data6);
}
break;
case TextureTypes::TCUBE_MAP_ARRAY: {
glTextureType = GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
glBindTexture(glTextureType, textureID);
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY_ARB, 0, glInternalDataFormat, width,height, depth * 6, 0,glFormat, glDataType, data);
std::cerr << "This method of loading texture data is not tested." << std::endl;
}
break;
}
if (dataType != DataTypes::FLOAT && internalFormat != InternalFormatTypes::DEPTH) {
glGenerateMipmap(glTextureType);
} else {
glTexParameteri(glTextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(glTextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (format == FormatTypes::DEPTH) {
if (type == TextureTypes::T2D_ARRAY || type == TextureTypes::TCUBE_MAP_ARRAY) {
glTexParameteri(glTextureType, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(glTextureType, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
}
}
}
glBindTexture(glTextureType, 0);
checkErrors("loadTextureData");
}
void OpenGLGraphics::updateTextureRegion(uint32_t textureID, int x, int y, int width, int height, FormatTypes format, DataTypes dataType, const void *data) {
state->activateTextureUnit(0);
GLenum glFormat = 0;
switch (format) {
case FormatTypes::RED: glFormat = GL_RED; break;
case FormatTypes::RG: glFormat = GL_RG; break;
case FormatTypes::RGB: glFormat = GL_RGB; break;
case FormatTypes::RGBA: glFormat = GL_RGBA; break;
case FormatTypes::DEPTH: glFormat = GL_DEPTH_COMPONENT; break;
}
GLenum glDataType = 0;
switch (dataType) {
case DataTypes::FLOAT: glDataType = GL_FLOAT; break;
case DataTypes::HALF_FLOAT: glDataType = GL_HALF_FLOAT; break;
case DataTypes::UNSIGNED_BYTE: glDataType = GL_UNSIGNED_BYTE; break;
case DataTypes::UNSIGNED_SHORT: glDataType = GL_UNSIGNED_SHORT; break;
case DataTypes::UNSIGNED_INT: glDataType = GL_UNSIGNED_INT; break;
}
glBindTexture(GL_TEXTURE_2D, textureID);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, glFormat, glDataType, data);
glBindTexture(GL_TEXTURE_2D, 0);
checkErrors("updateTextureRegion");
}
void OpenGLGraphics::attachTexture(unsigned int textureID, unsigned int attachPoint) {
std::unordered_map<uint32_t, FrameResources::TextureCopies>::iterator frameBufferedTexture = frameResources.textures.find(textureID);
if (frameBufferedTexture != frameResources.textures.end()) {
frameResources.textureUnits[attachPoint] = textureID;
textureID = frameBufferedTexture->second.copies[frameResources.index];
} else {
frameResources.textureUnits.erase(attachPoint);
}
state->attachTexture(textureID, attachPoint);
checkErrors("attachTexture");
}
void OpenGLGraphics::attach2DArrayTexture(unsigned int textureID, unsigned int attachPoint) {
state->attach2DTextureArray(textureID, attachPoint);
checkErrors("attachTexture");
}
void OpenGLGraphics::attachCubeMap(unsigned int cubeMapID, unsigned int attachPoint) {
state->attachCubemap(cubeMapID, attachPoint);
checkErrors("attachCubeMap");
}
void OpenGLGraphics::attachCubeMapArrayTexture(unsigned int cubeMapID, unsigned int attachPoint) {
state->attachCubemapArray(cubeMapID, attachPoint);
checkErrors("attachCubeMap");
}
bool OpenGLGraphics::deleteTexture(GLuint textureID) {
bool result = state->deleteTexture(textureID);
checkErrors("deleteTexture");
return result;
}
bool OpenGLGraphics::getUniformLocation(const uint32_t programID, const std::string &uniformName, uint32_t &location) {
GLint rawLocation = glGetUniformLocation(programID, uniformName.c_str());
if (!checkErrors("getUniformLocation")) {
if (rawLocation >= 0) {
location = rawLocation;
return true;
} else {
std::cerr << "No error found, but uniform[" << uniformName << "] can not be located " << std::endl;
}
}
return false;
}
void OpenGLGraphics::createDebugVAOVBO(uint32_t &vao, uint32_t &vbo, uint32_t bufferSize) {
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
vbo = generateBuffer(1);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, bufferSize * sizeof(Line), nullptr, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 28, nullptr);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 28, (void*)12);
glVertexAttribIPointer(2, 1, GL_INT, 28, (void*)24);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
checkErrors("createDebugVAOVBO");
}
* This method draws lines, but is refreshes whole buffer. In a better world, these values should be
* loaded with other values, and rendered without the heavy load. but for now, it is faster then the older version.
*
* PLEASE NOTE, IF LINE SIZE IS BIGGER THEN ASSIGNED, UNDEFINED BEHAVIOUR
*
* @param program - glsl program used to render
* @param vao - vao
* @param vbo - vbo that the lines will be buffered. It should be
* @param lines - line vector
*/
void OpenGLGraphics::drawLines(GraphicsProgram &program, uint32_t vao, uint32_t vbo, const std::vector<Line> &lines) {
state->setProgram(program.getID());
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, lines.size() * sizeof(Line), lines.data());
frameStats.lineCount += lines.size();
++frameStats.drawCallCount;
glDrawArrays(GL_LINES, 0, lines.size()*2);
glBindVertexArray(0);
checkErrors("drawLines");
}
uint32_t OpenGLGraphics::createUniformBuffer() {
FrameResources::UniformBufferCopies uniformBuffer;
glGenBuffers(FrameResources::COPY_COUNT, uniformBuffer.copies);
for (uint32_t copyIndex = 0; copyIndex < FrameResources::COPY_COUNT; ++copyIndex) {
glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer.copies[copyIndex]);
uniformBuffer.copySizes[copyIndex] = 0;
}
glBindBuffer(GL_UNIFORM_BUFFER, 0);
frameResources.uniformBuffers[uniformBuffer.copies[0]] = uniformBuffer;
checkErrors("createUniformBuffer");
return uniformBuffer.copies[0];
}
void OpenGLGraphics::deleteUniformBuffer(uint32_t bufferID) {
std::unordered_map<uint32_t, FrameResources::UniformBufferCopies>::iterator uniformBuffer = frameResources.uniformBuffers.find(bufferID);
if (uniformBuffer == frameResources.uniformBuffers.end()) {
std::cerr << "Uniform buffer " << bufferID << " was not created by createUniformBuffer, not deleting." << std::endl;
return;
}
for (std::unordered_map<uint32_t, uint32_t>::iterator binding = frameResources.uniformBindings.begin(); binding != frameResources.uniformBindings.end();) {
if (binding->second == bufferID) {
binding = frameResources.uniformBindings.erase(binding);
} else {
++binding;
}
}
glDeleteBuffers(FrameResources::COPY_COUNT, uniformBuffer->second.copies);
frameResources.uniformBuffers.erase(uniformBuffer);
checkErrors("deleteUniformBuffer");
}
void OpenGLGraphics::writeUniformBuffer(uint32_t bufferID, const UniformBlockData &data) {
std::unordered_map<uint32_t, FrameResources::UniformBufferCopies>::iterator uniformBuffer = frameResources.uniformBuffers.find(bufferID);
if (uniformBuffer == frameResources.uniformBuffers.end()) {
std::cerr << "Uniform buffer " << bufferID << " was not created by createUniformBuffer, not writing." << std::endl;
return;
}
Std140Layout::layout(data, frameResources.blockBytes);
size_t ©Size = uniformBuffer->second.copySizes[frameResources.index];
glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer->second.copies[frameResources.index]);
if (copySize != frameResources.blockBytes.size()) {
glBufferData(GL_UNIFORM_BUFFER, frameResources.blockBytes.size(), frameResources.blockBytes.data(), GL_DYNAMIC_DRAW);
copySize = frameResources.blockBytes.size();
} else {
void* mappedBuffer = glMapBufferRange(GL_UNIFORM_BUFFER, 0, frameResources.blockBytes.size(), GL_MAP_WRITE_BIT);
if (mappedBuffer == nullptr) {
std::cerr << "Uniform buffer " << bufferID << " could not be mapped, not writing." << std::endl;
} else {
memcpy(mappedBuffer, frameResources.blockBytes.data(), frameResources.blockBytes.size());
glUnmapBuffer(GL_UNIFORM_BUFFER);
}
}
glBindBuffer(GL_UNIFORM_BUFFER, 0);
checkErrors("writeUniformBuffer");
}
void OpenGLGraphics::bindUniformBuffer(uint32_t bufferID, uint32_t bindingPoint) {
std::unordered_map<uint32_t, FrameResources::UniformBufferCopies>::iterator uniformBuffer = frameResources.uniformBuffers.find(bufferID);
if (uniformBuffer == frameResources.uniformBuffers.end()) {
std::cerr << "Uniform buffer " << bufferID << " was not created by createUniformBuffer, not binding." << std::endl;
return;
}
frameResources.uniformBindings[bindingPoint] = bufferID;
glBindBufferBase(GL_UNIFORM_BUFFER, bindingPoint, uniformBuffer->second.copies[frameResources.index]);
checkErrors("bindUniformBuffer");
}
uint32_t OpenGLGraphics::createFrameBufferedTexture(int height, int width, InternalFormatTypes internalFormat, FormatTypes format, DataTypes dataType) {
FrameResources::TextureCopies texture;
for (uint32_t copyIndex = 0; copyIndex < FrameResources::COPY_COUNT; ++copyIndex) {
texture.copies[copyIndex] = createTexture(height, width, TextureTypes::T2D, internalFormat, format, dataType, 0);
setFilterMode(texture.copies[copyIndex], TextureTypes::T2D, FilterModes::NEAREST);
}
frameResources.textures[texture.copies[0]] = texture;
return texture.copies[0];
}
void OpenGLGraphics::writeFrameBufferedTexture(uint32_t textureID, int x, int y, int width, int height, FormatTypes format, DataTypes dataType, const void *data) {
std::unordered_map<uint32_t, FrameResources::TextureCopies>::iterator texture = frameResources.textures.find(textureID);
if (texture == frameResources.textures.end()) {
std::cerr << "Texture " << textureID << " was not created by createFrameBufferedTexture, not writing." << std::endl;
return;
}
updateTextureRegion(texture->second.copies[frameResources.index], x, y, width, height, format, dataType, data);
}
void OpenGLGraphics::deleteFrameBufferedTexture(uint32_t textureID) {
std::unordered_map<uint32_t, FrameResources::TextureCopies>::iterator texture = frameResources.textures.find(textureID);
if (texture == frameResources.textures.end()) {
std::cerr << "Texture " << textureID << " was not created by createFrameBufferedTexture, not deleting." << std::endl;
return;
}
for (std::unordered_map<uint32_t, uint32_t>::iterator unit = frameResources.textureUnits.begin(); unit != frameResources.textureUnits.end();) {
if (unit->second == textureID) {
unit = frameResources.textureUnits.erase(unit);
} else {
++unit;
}
}
for (uint32_t copyIndex = 0; copyIndex < FrameResources::COPY_COUNT; ++copyIndex) {
deleteTexture(texture->second.copies[copyIndex]);
}
frameResources.textures.erase(texture);
}
void OpenGLGraphics::swapFrameResources() {
frameResources.index = (frameResources.index + 1) % FrameResources::COPY_COUNT;
for (const std::pair<const uint32_t, uint32_t> &binding : frameResources.uniformBindings) {
glBindBufferBase(GL_UNIFORM_BUFFER, binding.first, frameResources.uniformBuffers[binding.second].copies[frameResources.index]);
}
for (const std::pair<const uint32_t, uint32_t> &unit : frameResources.textureUnits) {
state->attachTexture(frameResources.textures[unit.second].copies[frameResources.index], unit.first);
}
checkErrors("swapFrameResources");
}
void OpenGLGraphics::setMaterial(const Material& material) {
* this buffer has 2 objects, model has mat4 and then the material below:
*
layout (std140) uniform MaterialInformationBlock {
vec3 ambient;
float shininess;
vec3 diffuse;
int isMap;
};
*/
float shininess = material.getSpecularExponent();
uint32_t maps = material.getMaps();
if (material.getMaterialIndex() >= NR_MAX_MATERIALS) {
std::cerr << "Material " << material.getName() << " has index " << material.getMaterialIndex()
<< ", which does not fit in the " << NR_MAX_MATERIALS << " slot material buffer. Not uploading." << std::endl;
return;
}
glBindBuffer(GL_UNIFORM_BUFFER, allMaterialsUBOLocation);
glBufferSubData(GL_UNIFORM_BUFFER, material.getMaterialIndex() * materialUniformSize,
sizeof(glm::vec3), glm::value_ptr(material.getAmbientColor()));
glBufferSubData(GL_UNIFORM_BUFFER, material.getMaterialIndex() * materialUniformSize + sizeof(glm::vec3),
sizeof(GLfloat), &shininess);
glBufferSubData(GL_UNIFORM_BUFFER, material.getMaterialIndex() * materialUniformSize + sizeof(glm::vec3) + sizeof(GLfloat),
sizeof(glm::vec3), glm::value_ptr(material.getDiffuseColor()));
glBufferSubData(GL_UNIFORM_BUFFER, material.getMaterialIndex() * materialUniformSize + 2 *sizeof(glm::vec3) + sizeof(GLfloat),
sizeof(GLint), &maps);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
checkErrors("setMaterial");
}
void OpenGLGraphics::setModelIndexesUBO(const std::vector<glm::uvec4> &modelIndicesList) {
* POSSIBLE FIXME
* std140 layout requires arrays to be padded to 16 bytes. std430 is not supported for uniform buffers.
* we can upload the array as is and calculate the vector component in shader, but since we are GPU bound I am
* choosing to pad it in CPU instead.
*/
if (modelIndicesList.size() > modelIndexBatchCapacity) {
std::cerr << "Model index batch of " << modelIndicesList.size() << " does not fit in the "
<< modelIndexBatchCapacity << " slot index buffer. Not uploading." << std::endl;
return;
}
glBindBuffer(GL_UNIFORM_BUFFER, allModelIndexesUBOLocation);
glBufferData(GL_UNIFORM_BUFFER, sizeof(glm::uvec4) * modelIndexBatchCapacity, nullptr, GL_DYNAMIC_DRAW);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::uvec4) * modelIndicesList.size(), modelIndicesList.data());
glBindBuffer(GL_UNIFORM_BUFFER, 0);
checkErrors("setModelIndexesUBO");
}
void OpenGLGraphics::backupCurrentState() {
this->state->backupState();
}
void OpenGLGraphics::restoreLastState() {
this->state->restoreState();
}
bool OpenGLGraphics::getFallbackContextInformation(GraphicsInterface::ContextInformation& fallbackContext) {
return false;
}
bool OpenGLGraphics::verifyContext() {
GLint major = 0, minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
if (major == 0) {
const char* versionStr = (const char*)glGetString(GL_VERSION);
if (versionStr) {
sscanf(versionStr, "%d.%d", &major, &minor);
}
}
std::cout << "Created OpenGL context version: " << major << "." << minor << std::endl;
if (major > 3 || (major == 3 && minor >= 3)) {
return true;
}
std::cerr << "OpenGL context version is too low. Required: 3.3, Got: " << major << "." << minor << std::endl;
return false;
}
void OpenGLGraphics::initGpuContext() {
#ifdef TRACY_ENABLE
TracyGpuContext;
#endif
}
void OpenGLGraphics::beginGpuProfileZone(const char* name [[gnu::unused]], bool active [[gnu::unused]]) {
#if defined(TRACY_ENABLE) && !defined(__APPLE__)
if (!active) {
gpuZoneStack.push_back(nullptr);
return;
}
gpuZoneStack.push_back(new tracy::GpuCtxScope(TracyLine,
TracyFile, strlen(TracyFile),
TracyFunction, strlen(TracyFunction),
name, strlen(name),
active));
#endif
}
void OpenGLGraphics::endGpuProfileZone() {
#if defined(TRACY_ENABLE) && !defined(__APPLE__)
if (gpuZoneStack.empty()) {
std::cerr << "GPU profile zone ended without a matching begin." << std::endl;
return;
}
delete gpuZoneStack.back();
gpuZoneStack.pop_back();
#endif
}
void OpenGLGraphics::collectGpuProfilingData() {
#ifdef TRACY_ENABLE
#ifndef __APPLE__
if (!gpuZoneStack.empty()) {
std::cerr << gpuZoneStack.size() << " GPU profile zones still open at frame end, a begin has no matching end." << std::endl;
}
#endif
TracyGpuCollect;
#endif
}