protot/src/modules/RenderUtils.cc

701 lines
19 KiB
C++
Raw Normal View History

2016-08-29 22:31:11 +02:00
#include <string.h> // strlen
#include <locale.h>
#include <iostream>
2018-02-13 12:05:07 +01:00
#include <fstream>
2016-08-29 22:31:11 +02:00
#include "RenderModule.h"
2016-08-29 22:31:11 +02:00
#include "RenderUtils.h"
2017-02-05 10:36:37 +01:00
#include "Globals.h"
2018-03-10 08:48:41 +01:00
#include "FileModificationObserver.h"
#include "imgui/imgui.h"
#include "imgui_dock.h"
using namespace SimpleMath;
using namespace SimpleMath::GL;
//
// Camera
//
void Camera::UpdateMatrices() {
mViewMatrix = LookAt(mEye, mPoi, mUp);
if (mIsOrthographic) {
float width = mWidth * 0.5f * (mFar - mNear * 0.5f) * 0.001f;
float height = width * mHeight / mWidth;
mProjectionMatrix = Ortho(-width * 0.5f, width * 0.5f, -height * 0.5f, height * 0.5f, mNear, mFar);
} else {
mProjectionMatrix = Perspective(mFov, mWidth / mHeight, mNear, mFar);
}
}
void Camera::DrawGui() {
ImGui::Text("Width %3.4f, Height %3.4f", mWidth, mHeight);
ImGui::InputFloat3("Eye", mEye.data(), -10.0f, 10.0f);
ImGui::SliderFloat3("EyeS", mEye.data(), -10.0f, 10.0f);
ImGui::InputFloat3("Poi", mPoi.data(), -10.0f, 10.0f);
ImGui::InputFloat3("Up", mUp.data(), -10.0f, 10.0f);
ImGui::Checkbox("Orthographic", &mIsOrthographic);
ImGui::SliderFloat("Fov", &mFov, 5, 160);
ImGui::SliderFloat("Near", &mNear, -10, 10);
ImGui::SliderFloat("Far", &mFar, -20, 50);
if (ImGui::Button("Reset")) {
*this = Camera();
}
}
2016-08-29 22:31:11 +02:00
//
// RenderProgram
//
2018-02-13 12:05:07 +01:00
RenderProgram::~RenderProgram() {
if (mProgramId != -1)
2018-02-13 12:05:07 +01:00
glDeleteProgram(mProgramId);
2016-08-29 22:31:11 +02:00
}
2018-03-10 21:22:35 +01:00
GLuint RenderProgram::CompileVertexShader() {
2018-02-13 12:05:07 +01:00
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
2016-08-29 22:31:11 +02:00
2018-02-13 12:05:07 +01:00
// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(mVertexShaderFilename.c_str(), std::ios::in);
if(VertexShaderStream.is_open()){
std::stringstream sstr;
sstr << VertexShaderStream.rdbuf();
VertexShaderCode = sstr.str();
VertexShaderStream.close();
}else{
gLog("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !", mVertexShaderFilename.c_str());
2018-02-13 12:05:07 +01:00
getchar();
2018-03-10 21:22:35 +01:00
return -1;
2016-08-29 22:31:11 +02:00
}
2018-02-13 12:05:07 +01:00
GLint Result = GL_FALSE;
int InfoLogLength;
2016-08-29 22:31:11 +02:00
2018-02-13 12:05:07 +01:00
// Compile Vertex Shader
gLog("Compiling shader : %s", mVertexShaderFilename.c_str());
2018-02-13 12:05:07 +01:00
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
2016-08-29 22:31:11 +02:00
2018-02-13 12:05:07 +01:00
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
gLog("%s", &VertexShaderErrorMessage[0]);
2018-03-10 21:22:35 +01:00
return -1;
}
2018-03-10 21:22:35 +01:00
return VertexShaderID;
}
GLuint RenderProgram::CompileFragmentShader() {
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
2018-03-10 21:22:35 +01:00
// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(mFragmentShaderFilename.c_str(), std::ios::in);
if(FragmentShaderStream.is_open()){
std::stringstream sstr;
sstr << FragmentShaderStream.rdbuf();
FragmentShaderCode = sstr.str();
FragmentShaderStream.close();
}
GLint Result = GL_FALSE;
int InfoLogLength;
2018-02-13 12:05:07 +01:00
// Compile Fragment Shader
gLog("Compiling shader : %s", mFragmentShaderFilename.c_str());
2018-02-13 12:05:07 +01:00
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);
2018-02-13 12:05:07 +01:00
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
gLog("%s", &FragmentShaderErrorMessage[0]);
2018-03-10 21:22:35 +01:00
return -1;
}
2018-03-10 21:22:35 +01:00
return FragmentShaderID;
}
2018-03-10 21:22:35 +01:00
GLuint RenderProgram::LinkProgram(GLuint vertex_shader, GLuint fragment_shader) {
2018-02-13 12:05:07 +01:00
// Link the program
gLog("Linking program");
2018-02-13 12:05:07 +01:00
GLuint ProgramID = glCreateProgram();
2018-03-10 21:22:35 +01:00
glAttachShader(ProgramID, vertex_shader);
glAttachShader(ProgramID, fragment_shader);
// Bind attribute locations
glBindAttribLocation(ProgramID, 0, "inCoord");
glBindAttribLocation(ProgramID, 1, "inNormal");
glBindAttribLocation(ProgramID, 2, "inUV");
glBindAttribLocation(ProgramID, 3, "inColor");
2018-02-13 12:05:07 +01:00
glLinkProgram(ProgramID);
2018-03-10 21:22:35 +01:00
GLint Result = GL_FALSE;
int InfoLogLength;
2018-02-13 12:05:07 +01:00
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> ProgramErrorMessage(InfoLogLength+1);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
gLog("%s", &ProgramErrorMessage[0]);
}
2018-03-10 21:22:35 +01:00
return ProgramID;
}
bool RenderProgram::Load() {
GLuint vertex_shader_id = CompileVertexShader();
if (vertex_shader_id == -1) {
return false;
}
GLuint fragment_shader_id = CompileFragmentShader();
if (fragment_shader_id == -1) {
glDeleteShader(vertex_shader_id);
return false;
}
mProgramId = LinkProgram(vertex_shader_id, fragment_shader_id);
if (mProgramId == -1) {
glDeleteShader(vertex_shader_id);
glDeleteShader(fragment_shader_id);
return false;
}
glDetachShader(mProgramId, vertex_shader_id);
glDetachShader(mProgramId, fragment_shader_id);
2018-03-10 21:22:35 +01:00
glDeleteShader(vertex_shader_id);
glDeleteShader(fragment_shader_id);
2018-02-13 12:05:07 +01:00
return true;
}
2018-02-16 21:22:34 +01:00
GLuint RenderProgram::GetUniformLocation(const std::string& name) {
if (mProgramId == -1) {
gLog("Cannot get uniform '%s' for program '%s' and '%s': shader not valid.",
name.c_str(),
mVertexShaderFilename.c_str(),
mFragmentShaderFilename.c_str()
);
assert(mProgramId != -1);
}
GLuint result = glGetUniformLocation(mProgramId, name.c_str());
if (result == -1) {
gLog ("Error loading uniform '%s' from shaders '%s' and '%s': uniform not found.",
name.c_str(),
mVertexShaderFilename.c_str(),
mFragmentShaderFilename.c_str()
);
assert(false);
} else {
gLog ("Uniform '%s': %d", name.c_str(), result);
}
return result;
}
2018-03-10 08:48:41 +01:00
void RenderProgram::RegisterFileModification() {
gFileModificationObserver->AddListener(mVertexShaderFilename, this);
gFileModificationObserver->AddListener(mFragmentShaderFilename, this);
}
bool RenderProgram::OnFileChanged(const std::string& filename) {
gLog("Renderprogram reload as file %s changed", filename.c_str());
2018-03-10 21:22:35 +01:00
GLuint vertex_shader_id = CompileVertexShader();
if (vertex_shader_id == -1) {
gLog ("Reload failed: error when compiling vertex shader");
return true;
}
GLuint fragment_shader_id = CompileFragmentShader();
if (fragment_shader_id == -1) {
glDeleteShader(vertex_shader_id);
gLog ("Reload failed: error when compiling fragment shader");
return false;
}
mProgramId = LinkProgram(vertex_shader_id, fragment_shader_id);
if (mProgramId == -1) {
glDeleteShader(vertex_shader_id);
glDeleteShader(fragment_shader_id);
gLog ("Reload failed: error when linking the program");
return false;
}
glDetachShader(mProgramId, vertex_shader_id);
glDetachShader(mProgramId, fragment_shader_id);
glDeleteShader(vertex_shader_id);
glDeleteShader(fragment_shader_id);
gLog ("Reload successful");
2018-03-10 08:48:41 +01:00
return true;
}
//
// RenderTarget
//
RenderTarget::~RenderTarget() {
Cleanup();
}
2018-02-13 14:27:16 +01:00
void RenderTarget::Initialize(int width, int height, int flags) {
2018-02-13 14:27:16 +01:00
Cleanup();
mFlags = flags;
2018-02-13 14:27:16 +01:00
Resize(width, height);
}
void RenderTarget::Bind() {
assert(glIsFramebuffer(mFrameBufferId));
glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferId);
2018-03-15 11:54:00 +01:00
GLenum shadow_map_draw_buffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, shadow_map_draw_buffers);
2018-02-13 14:27:16 +01:00
}
void RenderTarget::Cleanup() {
if (mFrameBufferId != -1) {
glDeleteFramebuffers(1, &mFrameBufferId);
mFrameBufferId = -1;
}
if (mColorTexture != -1) {
glDeleteTextures(1, &mColorTexture);
mColorTexture = -1;
}
2018-02-14 13:14:10 +01:00
if (mDepthTexture!= -1) {
glDeleteTextures(1, &mDepthTexture);
mDepthTexture = -1;
}
2018-02-13 14:27:16 +01:00
if (mDepthBuffer != -1) {
glDeleteRenderbuffers(1, &mDepthBuffer);
mDepthBuffer = -1;
}
if (mLinearizedDepthTexture != -1) {
glDeleteTextures(1, &mLinearizedDepthTexture);
mLinearizedDepthTexture = -1;
}
2018-02-28 21:11:51 +01:00
mWidth = -1;
mHeight = -1;
2018-02-13 14:27:16 +01:00
}
void RenderTarget::Resize(int width, int height) {
2018-02-28 21:11:51 +01:00
if (width == mWidth && height == mHeight)
2018-02-13 14:27:16 +01:00
return;
Cleanup();
gLog("Resizing RenderTarget to %d,%d", width, height);
2018-02-28 21:11:51 +01:00
2018-02-13 14:27:16 +01:00
mWidth = width;
mHeight = height;
glGenFramebuffers(1, &mFrameBufferId);
glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferId);
2018-02-13 14:27:16 +01:00
if (mFlags & EnableColor) {
glGenTextures(1, &mColorTexture);
glBindTexture(GL_TEXTURE_2D, mColorTexture);
2018-02-13 14:27:16 +01:00
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, mWidth, mHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mColorTexture, 0);
}
2018-02-14 13:14:10 +01:00
if (mFlags & EnableDepthTexture) {
assert((mFlags & EnableDepth) == false);
glGenTextures(1, &mDepthTexture);
glBindTexture(GL_TEXTURE_2D, mDepthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, mWidth, mHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
// Set parameters so that we can set a shadow2DSampler
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
float border_color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
2018-02-14 13:14:10 +01:00
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, mDepthTexture, 0);
if (mFlags & EnableLinearizedDepthTexture) {
glGenTextures(1, &mLinearizedDepthTexture);
glBindTexture(GL_TEXTURE_2D, mLinearizedDepthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, mWidth, mHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mLinearizedDepthTexture, 0);
}
2018-02-14 13:14:10 +01:00
} else if (mFlags & EnableDepth) {
assert((mFlags & EnableDepthTexture) == false);
glGenRenderbuffers(1, &mDepthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, mDepthBuffer);
2018-02-13 14:27:16 +01:00
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, mWidth, mHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthBuffer);
}
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (result != GL_FRAMEBUFFER_COMPLETE) {
switch (result) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: gLog("Error: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
break;
case GL_FRAMEBUFFER_UNDEFINED: gLog("Error: GL_FRAMEBUFFER_UNDEFINED");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: gLog("Error: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
break;
default: gLog("Error when creating Framebuffer: %d", result);
}
}
assert(result == GL_FRAMEBUFFER_COMPLETE);
}
void RenderTarget::RenderToLinearizedDepth(const float& near, const float& far, bool is_orthographic) {
assert(mFlags & EnableLinearizedDepthTexture);
assert(mLinearizedDepthTexture != -1);
2018-03-15 11:01:55 +01:00
assert(mVertexArray != nullptr);
assert(mQuadMesh != nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferId);
GLenum draw_attachment_1[] = { GL_COLOR_ATTACHMENT1 };
glDrawBuffers(1, draw_attachment_1);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mDepthTexture);
// render depth texture
glUseProgram(mLinearizeDepthProgram.mProgramId);
mLinearizeDepthProgram.SetFloat("uNear", near);
mLinearizeDepthProgram.SetFloat("uFar", far);
mLinearizeDepthProgram.SetFloat("uIsOrthographic", is_orthographic ? 1.0f : 0.0f);
mLinearizeDepthProgram.SetInt("uDepthTexture", 0);
2018-03-15 11:01:55 +01:00
mVertexArray->Bind();
mQuadMesh->Draw(GL_TRIANGLES);
if (mFlags & EnableColor) {
GLenum draw_attachment_0[] = { GL_COLOR_ATTACHMENT1 };
glDrawBuffers(1, draw_attachment_0);
2018-03-15 11:01:55 +01:00
glEnable(GL_DEPTH_TEST);
}
}
//
// Texture
//
Texture::~Texture() {
if (mTextureId != -1) {
glDeleteTextures(1, &mTextureId);
mTextureId = -1;
}
}
void Texture::MakeGrid(const int& size, const Vector3f &c1, const Vector3f &c2) {
mWidth = size;
mHeight = size;
unsigned char buffer[size * size * 3];
int size_half = size / 2;
for (int i = 0; i < size_half; ++i) {
for (int j = 0; j < size_half; ++j) {
buffer[(i * size * 3) + (j * 3) + 0] = static_cast<unsigned char>(c1[0] * 255.0f);
buffer[(i * size * 3) + (j * 3) + 1] = static_cast<unsigned char>(c1[1] * 255.0f);
buffer[(i * size * 3) + (j * 3) + 2] = static_cast<unsigned char>(c1[2] * 255.0f);
}
}
for (int i = size_half; i < size; ++i) {
for (int j = 0; j < size_half; ++j) {
buffer[(i * size * 3) + (j * 3) + 0] = static_cast<unsigned char>(c2[0] * 255.0f);
buffer[(i * size * 3) + (j * 3) + 1] = static_cast<unsigned char>(c2[1] * 255.0f);
buffer[(i * size * 3) + (j * 3) + 2] = static_cast<unsigned char>(c2[2] * 255.0f);
}
}
for (int i = size_half; i < size; ++i) {
for (int j = size_half; j < size; ++j) {
buffer[(i * size * 3) + (j * 3) + 0] = static_cast<unsigned char>(c1[0] * 255.0f);
buffer[(i * size * 3) + (j * 3) + 1] = static_cast<unsigned char>(c1[1] * 255.0f);
buffer[(i * size * 3) + (j * 3) + 2] = static_cast<unsigned char>(c1[2] * 255.0f);
}
}
for (int i = 0; i < size_half; ++i) {
for (int j = size_half; j < size; ++j) {
buffer[(i * size * 3) + (j * 3) + 0] = static_cast<unsigned char>(c2[0] * 255.0f);
buffer[(i * size * 3) + (j * 3) + 1] = static_cast<unsigned char>(c2[1] * 255.0f);
buffer[(i * size * 3) + (j * 3) + 2] = static_cast<unsigned char>(c2[2] * 255.0f);
}
}
glGenTextures(1, &mTextureId);
glBindTexture(GL_TEXTURE_2D, mTextureId);
glTexImage2D(GL_TEXTURE_2D,
0, // level
GL_RGB, // internal format
size, // width
size, // height
0, // border (must be 0)
GL_RGB, // format of pixel data
GL_UNSIGNED_BYTE, // type of pixel data
buffer // pixel data
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
bool Texture::Load(const char* filename, int num_components) {
// unsigned char* rgb = stbi_load(filename, &mWidth, &mHeight, num_components);
assert(false);
}
VertexArray::~VertexArray() {
if (mVertexArrayId != -1) {
Cleanup();
}
}
void VertexArray::Initialize(const int& size, GLenum usage) {
mNumVertices = size;
mNumUsedVertices = 0;
glGenVertexArrays (1, &mVertexArrayId);
glBindVertexArray(mVertexArrayId);
glGenBuffers(1, &mVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData) * mNumVertices, NULL, usage);
}
void VertexArray::Cleanup() {
glDeleteBuffers(1, &mVertexBuffer);
mVertexBuffer = -1;
glDeleteVertexArrays(1, &mVertexArrayId);
mVertexArrayId = -1;
mNumVertices = -1;
mNumUsedVertices = -1;
}
GLuint VertexArray::AllocateMesh(const int& size) {
if (mNumUsedVertices + size > mNumVertices) {
gLog("Cannot allocate mesh in VertexArray: not enough vertices available");
assert(false);
return -1;
}
GLuint offset = mNumUsedVertices;
mNumUsedVertices += size;
return offset;
}
void VertexArray::Bind() {
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
// Attribute 0: coords
glEnableVertexAttribArray(0);
glVertexAttribPointer(
0,
4,
GL_FLOAT,
GL_FALSE,
(sizeof(VertexData)),
(void*)0
);
// Attribute 1: normals
2018-03-11 17:30:56 +01:00
glEnableVertexAttribArray(1);
glVertexAttribPointer(
1,
3,
GL_FLOAT,
GL_FALSE,
(sizeof(VertexData)),
(void*)(sizeof(float) * 4)
);
// Attribute 2: texture coordinates
2018-03-11 17:30:56 +01:00
glEnableVertexAttribArray(2);
glVertexAttribPointer(
2,
2,
GL_FLOAT,
GL_FALSE,
(sizeof(VertexData)),
(void*)(sizeof(float) * 7)
);
// Attribute 1: color
glEnableVertexAttribArray(3);
glVertexAttribPointer(
3,
4,
GL_UNSIGNED_BYTE,
GL_TRUE,
(sizeof(VertexData)),
(void*)(sizeof(float) * 9)
);
}
bool VertexArray::IsBound() {
GLint bound_vertex_buffer = -1;
glGetIntegerv (GL_ARRAY_BUFFER_BINDING, &bound_vertex_buffer);
return bound_vertex_buffer == mVertexBuffer;
}
void VertexArrayMesh::Initialize(VertexArray &array, const int& size) {
mVertexArray = &array;
mIndexOffset = mVertexArray->AllocateMesh(size);
mOffsetPtr = (void*) (sizeof(VertexArray::VertexData) * mIndexOffset);
}
void VertexArrayMesh::SetData(
const VertexArray::VertexData* data,
const int& count
) {
// upload the data
mVertexCount = count;
glBindBuffer(GL_ARRAY_BUFFER, mVertexArray->mVertexBuffer);
glBufferSubData(
GL_ARRAY_BUFFER,
(GLintptr) mOffsetPtr,
sizeof(VertexArray::VertexData) * count,
data
);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void VertexArrayMesh::SetData(
const std::vector<Vector4f> &coords,
const std::vector<Vector3f> &normals,
const std::vector<Vector2f> &uvs,
const std::vector<Vector4f> &colors,
const std::vector<GLuint> &indices
) {
assert(mOffsetPtr != (void*) -1);
int vertex_count = coords.size();
assert(vertex_count > 0);
bool have_normals = normals.size() > 0;
bool have_uvs = uvs.size() > 0;
bool have_colors = colors.size() > 0;
assert(!have_normals || (normals.size() == vertex_count));
assert(!have_uvs || (uvs.size() == vertex_count));
assert(!have_colors || (colors.size() == vertex_count));
std::vector<VertexArray::VertexData> vertex_data(vertex_count, VertexArray::VertexData());
for (int i = 0, n = vertex_count; i < n; ++i) {
memcpy (vertex_data[i].mCoords, coords[i].data(), sizeof(float) * 4);
if (have_normals) {
memcpy (vertex_data[i].mNormals, normals[i].data(), sizeof(float) * 3);
} else {
memset (vertex_data[i].mNormals, 0, sizeof(float) * 3);
}
if (have_uvs) {
memcpy (vertex_data[i].mTexCoords, uvs[i].data(), sizeof(float) * 2);
} else {
memset (vertex_data[i].mTexCoords, 0, sizeof(float) * 2);
}
if (have_colors) {
for (int j = 0; j < 4; ++j) {
vertex_data[i].mColor[j] = GLubyte(colors[i][j] * 255.0f);
}
} else {
memset (vertex_data[i].mColor, 0, sizeof(float) * 4);
}
}
SetData(
vertex_data.data(),
vertex_count
);
}
void VertexArrayMesh::SetIndexData(const GLuint* indices, const int& count) {
assert(mIndexBuffer == -1);
// copy the indices and increase the indices by mIndexOffset
GLuint temp_buffer[count];
memcpy (temp_buffer, indices, sizeof(GLuint) * count);
for (int i = 0; i < count; ++i) {
temp_buffer[i] += mIndexOffset;
}
mIndexCount = count;
glGenBuffers(1, &mIndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(GLuint), temp_buffer, GL_STATIC_DRAW);
}
void VertexArrayMesh::Draw(GLenum mode) {
assert(mVertexArray->IsBound());
if (mIndexBuffer == -1) {
glDrawArrays(mode, mIndexOffset, mVertexCount);
} else {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
glDrawElements(mode, mIndexCount, GL_UNSIGNED_INT, (void*) 0);
}
}