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
|
|
|
|
2016-10-21 22:07:23 +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"
|
2016-11-06 22:30:09 +01:00
|
|
|
|
2018-02-19 14:33:29 +01:00
|
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
|
|
|
|
|
|
#include "stb/stb_image.h"
|
|
|
|
|
2016-11-06 22:30:09 +01:00
|
|
|
using namespace SimpleMath;
|
2016-08-29 22:31:11 +02:00
|
|
|
|
2018-02-13 12:44:34 +01:00
|
|
|
//
|
|
|
|
// RenderProgram
|
|
|
|
//
|
|
|
|
|
2018-02-13 12:05:07 +01:00
|
|
|
RenderProgram::~RenderProgram() {
|
2018-02-27 23:31:13 +01:00
|
|
|
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{
|
2018-02-16 11:35:09 +01:00
|
|
|
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
|
2018-02-16 11:35:09 +01:00
|
|
|
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]);
|
2018-02-16 11:35:09 +01:00
|
|
|
gLog("%s", &VertexShaderErrorMessage[0]);
|
2018-03-10 21:22:35 +01:00
|
|
|
|
|
|
|
return -1;
|
2017-02-18 17:38:21 +01:00
|
|
|
}
|
|
|
|
|
2018-03-10 21:22:35 +01:00
|
|
|
return VertexShaderID;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLuint RenderProgram::CompileFragmentShader() {
|
|
|
|
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
|
2017-02-18 17:38:21 +01:00
|
|
|
|
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;
|
2017-02-18 17:38:21 +01:00
|
|
|
|
2018-02-13 12:05:07 +01:00
|
|
|
// Compile Fragment Shader
|
2018-02-16 11:35:09 +01:00
|
|
|
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);
|
2017-02-26 14:26:12 +01:00
|
|
|
|
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]);
|
2018-02-16 11:35:09 +01:00
|
|
|
gLog("%s", &FragmentShaderErrorMessage[0]);
|
2018-03-10 21:22:35 +01:00
|
|
|
|
|
|
|
return -1;
|
2017-02-26 14:26:12 +01:00
|
|
|
}
|
|
|
|
|
2018-03-10 21:22:35 +01:00
|
|
|
return FragmentShaderID;
|
|
|
|
}
|
2017-02-26 14:26:12 +01:00
|
|
|
|
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
|
2018-02-16 11:35:09 +01:00
|
|
|
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);
|
2018-02-13 12:05:07 +01:00
|
|
|
glLinkProgram(ProgramID);
|
2017-02-18 17:38:21 +01:00
|
|
|
|
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]);
|
2018-02-16 11:35:09 +01:00
|
|
|
gLog("%s", &ProgramErrorMessage[0]);
|
2017-02-26 14:26:12 +01:00
|
|
|
}
|
2016-11-28 22:19:09 +01:00
|
|
|
|
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);
|
2016-11-28 22:19:09 +01:00
|
|
|
|
2018-03-10 21:22:35 +01:00
|
|
|
glDeleteShader(vertex_shader_id);
|
|
|
|
glDeleteShader(fragment_shader_id);
|
2016-11-28 22:19:09 +01:00
|
|
|
|
2018-02-13 12:05:07 +01:00
|
|
|
return true;
|
2016-11-28 22:19:09 +01:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-02-13 12:44:34 +01:00
|
|
|
//
|
|
|
|
// RenderTarget
|
|
|
|
//
|
|
|
|
RenderTarget::RenderTarget(int width, int height, int flags) {
|
2018-02-13 14:27:16 +01:00
|
|
|
mFlags = flags;
|
|
|
|
|
|
|
|
Cleanup();
|
|
|
|
Resize(width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
RenderTarget::~RenderTarget() {
|
|
|
|
Cleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2018-02-17 23:49:56 +01:00
|
|
|
|
|
|
|
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();
|
|
|
|
|
2018-02-28 21:11:51 +01:00
|
|
|
gLog("Resizing RenderTarget");
|
|
|
|
|
2018-02-13 14:27:16 +01:00
|
|
|
mWidth = width;
|
|
|
|
mHeight = height;
|
|
|
|
|
2018-02-13 12:44:34 +01:00
|
|
|
glGenFramebuffers(1, &mFrameBufferId);
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferId);
|
|
|
|
|
2018-02-13 14:27:16 +01:00
|
|
|
if (mFlags & EnableColor) {
|
2018-02-13 12:44:34 +01:00
|
|
|
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);
|
2018-02-13 12:44:34 +01:00
|
|
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
|
|
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mDepthTexture, 0);
|
2018-02-17 23:49:56 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2018-02-14 13:14:10 +01:00
|
|
|
} else if (mFlags & EnableDepth) {
|
|
|
|
assert((mFlags & EnableDepthTexture) == false);
|
2018-02-13 12:44:34 +01:00
|
|
|
glGenRenderbuffers(1, &mDepthBuffer);
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, mDepthBuffer);
|
2018-02-13 14:27:16 +01:00
|
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, mWidth, mHeight);
|
2018-02-13 12:44:34 +01:00
|
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-17 23:49:56 +01:00
|
|
|
void RenderTarget::RenderToLinearizedDepth(bool render_to_depth) {
|
|
|
|
if (render_to_depth) {
|
|
|
|
assert(mFlags & EnableLinearizedDepthTexture);
|
|
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mLinearizedDepthTexture, 0);
|
|
|
|
} else {
|
|
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture, 0);
|
|
|
|
}
|
|
|
|
}
|
2018-02-19 14:33:29 +01:00
|
|
|
|
|
|
|
//
|
|
|
|
// 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);
|
|
|
|
}
|
2018-02-27 23:15:07 +01:00
|
|
|
|
2018-02-28 12:39:12 +01:00
|
|
|
VertexArray::~VertexArray() {
|
|
|
|
if (mVertexArrayId != -1) {
|
|
|
|
Cleanup();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-27 23:15:07 +01:00
|
|
|
void VertexArray::Initialize(const int& size, GLenum usage) {
|
2018-02-28 12:39:12 +01:00
|
|
|
mNumVertices = size;
|
|
|
|
mNumUsedVertices = 0;
|
2018-02-27 23:15:07 +01:00
|
|
|
|
|
|
|
glGenVertexArrays (1, &mVertexArrayId);
|
|
|
|
glBindVertexArray(mVertexArrayId);
|
|
|
|
|
|
|
|
glGenBuffers(1, &mVertexBuffer);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
|
2018-02-28 12:39:12 +01:00
|
|
|
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;
|
2018-02-27 23:15:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
GLuint VertexArray::AllocateMesh(const int& size) {
|
2018-02-28 12:39:12 +01:00
|
|
|
if (mNumUsedVertices + size > mNumVertices) {
|
2018-02-27 23:15:07 +01:00
|
|
|
gLog("Cannot allocate mesh in VertexArray: not enough vertices available");
|
|
|
|
assert(false);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-02-28 12:39:12 +01:00
|
|
|
GLuint offset = mNumUsedVertices;
|
|
|
|
mNumUsedVertices += size;
|
2018-02-27 23:15:07 +01:00
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2018-02-28 12:39:12 +01:00
|
|
|
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: color
|
|
|
|
glEnableVertexAttribArray(1);
|
|
|
|
glVertexAttribPointer(
|
|
|
|
1,
|
|
|
|
4,
|
|
|
|
GL_UNSIGNED_BYTE,
|
|
|
|
GL_FALSE,
|
|
|
|
(sizeof(VertexData)),
|
|
|
|
(void*)(sizeof(float) * 9)
|
|
|
|
);
|
|
|
|
// Attribute 2: normals
|
|
|
|
glEnableVertexAttribArray(2);
|
|
|
|
glVertexAttribPointer(
|
|
|
|
2,
|
|
|
|
3,
|
|
|
|
GL_FLOAT,
|
|
|
|
GL_FALSE,
|
|
|
|
(sizeof(VertexData)),
|
|
|
|
(void*)(sizeof(float) * 4)
|
|
|
|
);
|
|
|
|
// Attribute 3: texture coordinates
|
|
|
|
glEnableVertexAttribArray(3);
|
|
|
|
glVertexAttribPointer(
|
|
|
|
3,
|
|
|
|
2,
|
|
|
|
GL_FLOAT,
|
|
|
|
GL_FALSE,
|
|
|
|
(sizeof(VertexData)),
|
|
|
|
(void*)(sizeof(float) * 7)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VertexArray::IsBound() {
|
|
|
|
GLint bound_vertex_buffer = -1;
|
|
|
|
glGetIntegerv (GL_ARRAY_BUFFER_BINDING, &bound_vertex_buffer);
|
|
|
|
return bound_vertex_buffer == mVertexBuffer;
|
|
|
|
}
|
|
|
|
|
2018-02-27 23:15:07 +01:00
|
|
|
void VertexArrayMesh::Initialize(VertexArray &array, const int& size) {
|
2018-02-28 12:39:12 +01:00
|
|
|
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) {
|
|
|
|
memcpy (vertex_data[i].mColor, colors[i].data(), sizeof(float) * 4);
|
|
|
|
} else {
|
|
|
|
memset (vertex_data[i].mColor, 0, sizeof(float) * 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SetData(
|
|
|
|
vertex_data.data(),
|
|
|
|
vertex_count
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-02-28 21:36:44 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-02-28 12:39:12 +01:00
|
|
|
void VertexArrayMesh::Draw(GLenum mode) {
|
|
|
|
assert(mVertexArray->IsBound());
|
2018-02-28 21:36:44 +01:00
|
|
|
|
|
|
|
if (mIndexBuffer == -1) {
|
|
|
|
glDrawArrays(mode, mIndexOffset, mVertexCount);
|
|
|
|
} else {
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
|
|
|
|
glDrawElements(mode, mIndexCount, GL_UNSIGNED_INT, (void*) 0);
|
|
|
|
}
|
|
|
|
|
2018-02-27 23:15:07 +01:00
|
|
|
}
|