A minimal steps for others to reproduce the problem
- Go to that GitHub link and download the file render-to-texture.zip (there is a text “Sorry” but the Download button is on top right). I don’t know how to upload more than 100 files on GitHub, that’s why it’s a .zip file.
- Extract the .zip file somewhere, and open the main folder “render-to-texture” with VSCode, there is a “CMakeLists.txt” in it.
- Select a Kit (GCC 12.2.0 x86_64-w64-mingw32 or Visual Studio Build Tools 2017 Release - amd64).
- Select the launch target “test_render_to_texture”.
- Compile and run run the project named “test_render_to_texture”.
If you cannot compile the project (or want to switch to other compiler), then close VSCode and delete the folder named “build” and try again the previous steps.
Very important note to avoid being stuck
Very white quad probably means that there is an error in the GLSL code. If the GLSL compilation seems weird, like the result is always white even if you are sure it should have other color like green-yellow-red then there’s probably an error in the GLSL code but you didn’t see the error message, it’s shown in the terminal. Colorizing that error will require a lot of codes, that’s why it’s not colorized. This is a minimal project.
The reason of this thread
There is another project named “tutorial14_render_to_texture” (Tutorial 14 : Render To Texture) and I learned from it. When I compare it line by line with my project (test_render_to_texture) then it seems ok, but mine doesn’t work,
the reason the 2 projects are very different is mine is very close to my real project, and when it’s fixed, the real project will be instantly fixed. I was stuck for a very long time with my real project, that’s why I make this thread. Please help.
The problem and goal
When you run the project named “test_render_to_texture” then everything is just blue, the quad doesn’t show, that quad can be white (error) or black or something else but it should be a quad with triangle as a rendered texture as a goal result, the reason I make addition +0.15 to the texture color is to avoid confusion on the quad with the scene background.
There are 3 important settings on top of “test_render_to_texture.cpp”, you can change these values between 0 and 1 for each line.
SimpleFragmentShader.fragmentshader
#version 330 core
uniform sampler2D map;
layout (location = 0) in vec3 inNormal;
layout (location = 1) in vec2 inUV;
out vec3 outFragColor;
void main() {
#if 0
outFragColor = vec3(inUV.x, inUV.y, 0);
#else
vec4 c = texture(map, inUV);
outFragColor = 0.15 + 0.85 * vec3(c);
#endif
}
A few functions in test_render_to_texture.cpp
GLuint Shader::gl_useProgram(const PVMStruct &PVM) {
GLuint programID = gl_getProgramID();
glUseProgram(programID);
GLuint projection_id = glGetUniformLocation(programID, "ubo_projection");
GLuint view_id = glGetUniformLocation(programID, "ubo_view");
GLuint model_id = glGetUniformLocation(programID, "ubo_model");
if (projection_id != -1) { glUniformMatrix4fv(projection_id, 1, GL_FALSE, &PVM.projection[0][0]); }
if (view_id != -1) { glUniformMatrix4fv(view_id , 1, GL_FALSE, &PVM.view[0][0]); }
if (model_id != -1) { glUniformMatrix4fv(model_id , 1, GL_FALSE, &PVM.model[0][0]); }
return programID;
}
void Shader::gl_beginAttributes_pos() {
EMC_VERIFY(_gl.numAttribs == 0);
_gl.numAttribs = 1;
for (int i = 0; i < _gl.numAttribs; i++) {
glEnableVertexAttribArray(i);
int stride = (3) * sizeof(GLfloat);
switch (i) {
case 0:
// position
glVertexAttribPointer(
i, // index
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
stride, // stride
(void*)0 // array buffer offset
);
break;
}
}
}
void Shader::gl_beginAttributes_pos_nor_uv() {
EMC_VERIFY(_gl.numAttribs == 0);
_gl.numAttribs = 3;
for (int attrib = 0; attrib < _gl.numAttribs; attrib++) {
glEnableVertexAttribArray(attrib);
int stride = (3 + 3 + 2) * sizeof(GLfloat);
switch (attrib) {
case 0:
// position
glVertexAttribPointer(
attrib, // index
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
stride, // stride
(void*)0 // array buffer offset
);
break;
case 1:
// normal
glVertexAttribPointer(
attrib, // index
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
stride, // stride
(void*)(3 * sizeof(GLfloat)) // array buffer offset
);
break;
case 2:
// texCoord
glVertexAttribPointer(
attrib, // index
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
stride, // stride
(void*)((3 + 3) * sizeof(GLfloat)) // array buffer offset
);
break;
}
}
}
void Shader::gl_endAttributes() {
EMC_VERIFY(_gl.numAttribs != 0);
for (int i = 0; i < _gl.numAttribs; i++) {
glDisableVertexAttribArray(i);
}
_gl.numAttribs = 0;
}
Highlight important things in “test_render_to_texture/test_render_to_texture.cpp”
AppBase *appBase = new AppBase();
RenderToTexture rtt;
rtt.init(appBase, false, 1024, 1024);
rtt.makeData();
GLuint rtt_texID = glGetUniformLocation(rtt._shader->_gl.programID, "renderedTexture");
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Create and compile our GLSL program from the shaders
Shader *shader = new Shader(
appBase,
engineDataDir(_PROJECT_NAME) + "/shaders/SimpleVertexShader.vertexshader",
engineDataDir(_PROJECT_NAME) + "/shaders/SimpleFragmentShader.fragmentshader"
);
// A quad
static const GLfloat g_vertex_buffer_data[] = {
// Position Normal UV
-0.9f,-0.9f,0.0f, 0.0f,0.0f,1.0f, 0.0f,0.0f,
0.9f,-0.9f,0.0f, 0.0f,0.0f,1.0f, 1.0f,0.0f,
-0.9f, 0.9f,0.0f, 0.0f,0.0f,1.0f, 0.0f,1.0f,
0.9f,-0.9f,0.0f, 0.0f,0.0f,1.0f, 1.0f,0.0f,
0.9f, 0.9f,0.0f, 0.0f,0.0f,1.0f, 1.0f,1.0f,
-0.9f, 0.9f,0.0f, 0.0f,0.0f,1.0f, 0.0f,1.0f,
};
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
70% of “test_render_to_texture.cpp”
#define DEBUG_RENDER_TO_TEXTURE 1 // It should be 1.
#define DEBUG_RTT_ON_DEFAULT_FRAME_BUFFER 0 // It should be 0.
#define DEBUG_RENDER_SCENE 1 // It should be 1.
...
struct PVMStruct {
glm::mat4 projection;
glm::mat4 view;
glm::mat4 model;
};
class_memoryBlock (Shader) {
friend class LightData;
public: // TODO: private not public
AppBase *_appBase = nullptr;
#ifdef USE_OPENGL
struct {
GLuint programID = -1;
int numAttribs = 0;
} _gl;
#endif
public:
Shader(AppBase *appBase, const string &vertexFilePath, const string &fragmentFilePath);
~Shader();
AppBase *getAppBase() { return _appBase; }; // Needed by the glTF importer for example.
#ifdef USE_OPENGL
GLuint gl_getProgramID() { EMC_VERIFY(_gl.programID != -1); return _gl.programID; } // Must be public and not placed in _gl because used by glTF import function outside class.
GLuint gl_useProgram(const PVMStruct &PVM);
void gl_beginAttributes_pos();
void gl_beginAttributes_pos_col();
void gl_beginAttributes_pos_nor_uv();
void gl_endAttributes();
#endif
};
Shader::Shader(AppBase *appBase, const string &vertexFilePath, const string &fragmentFilePath) {
_appBase = appBase;
//Context *ctx = appBase->getPrimaryContext_s(); [EDIT]
//ctx->makeCurrent(); [EDIT]
if (g_renderingApi == RENDERINGAPI_OPENGL) {
#ifdef USE_OPENGL
// Referenced from [Basic OpenGL > "common/shader.cpp"](https://www.opengl-tutorial.org/beginners-tutorials/)
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertexFilePath.c_str(), std::ios::in);
if (VertexShaderStream.is_open()) {
std::stringstream sstr;
sstr << VertexShaderStream.rdbuf();
VertexShaderCode = sstr.str();
VertexShaderStream.close();
}
else {
throw "Impossible to open the 'vertexFilePath'. Are you in the right directory ? Don't forget to read the FAQ !";
return;
}
// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragmentFilePath.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;
// Compile Vertex Shader
printf("Compiling shader : %s\n", vertexFilePath.c_str());
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
// 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);
GLchar *str = &VertexShaderErrorMessage[0];
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, str);
if (strcasecmp(str, "") != 0) {
//pushConsoleTextColor(ConsoleTextColor_Red); [EDIT]
printf("%s\n", str);
//popConsoleTextColor(); [EDIT]
}
}
// Compile Fragment Shader
printf("Compiling shader : %s\n", fragmentFilePath.c_str());
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);
// 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);
GLchar *str = &FragmentShaderErrorMessage[0];
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, str);
if (strcasecmp(str, "") != 0) {
//pushConsoleTextColor(ConsoleTextColor_Red); [EDIT]
printf("%s\n", str);
//popConsoleTextColor(); [EDIT]
}
}
// Link the program
printf("Linking program\n");
_gl.programID = glCreateProgram();
glAttachShader(_gl.programID, VertexShaderID);
glAttachShader(_gl.programID, FragmentShaderID);
glLinkProgram(_gl.programID);
// Check the program
glGetProgramiv(_gl.programID, GL_LINK_STATUS, &Result);
glGetProgramiv(_gl.programID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
std::vector<char> ProgramErrorMessage(InfoLogLength+1);
GLchar *str = &ProgramErrorMessage[0];
glGetProgramInfoLog(_gl.programID, InfoLogLength, NULL, str);
if (strcasecmp(str, "") != 0) {
//pushConsoleTextColor(ConsoleTextColor_Red); [EDIT]
printf("%s\n", str);
//popConsoleTextColor(); [EDIT]
}
}
glDetachShader(_gl.programID, VertexShaderID);
glDetachShader(_gl.programID, FragmentShaderID);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
#endif
}
else if (g_renderingApi == RENDERINGAPI_VULKAN) {
#ifdef USE_VULKAN
// TODO
#endif
}
else if (g_renderingApi == RENDERINGAPI_DIRECTX12) {
#ifdef USE_DIRECTX
// TODO
#endif
}
}
Shader::~Shader() {
if (g_renderingApi == RENDERINGAPI_OPENGL) {
#ifdef USE_OPENGL
glDeleteProgram(_gl.programID); _gl.programID = -1;
#endif
}
else if (g_renderingApi == RENDERINGAPI_VULKAN) {
#ifdef USE_VULKAN
// TODO
#endif
}
else if (g_renderingApi == RENDERINGAPI_DIRECTX12) {
#ifdef USE_DIRECTX
// TODO
#endif
}
}
GLuint Shader::gl_useProgram(const PVMStruct &PVM) {
GLuint programID = gl_getProgramID();
glUseProgram(programID);
GLuint projection_id = glGetUniformLocation(programID, "ubo_projection");
GLuint view_id = glGetUniformLocation(programID, "ubo_view");
GLuint model_id = glGetUniformLocation(programID, "ubo_model");
if (projection_id != -1) { glUniformMatrix4fv(projection_id, 1, GL_FALSE, &PVM.projection[0][0]); }
if (view_id != -1) { glUniformMatrix4fv(view_id , 1, GL_FALSE, &PVM.view[0][0]); }
if (model_id != -1) { glUniformMatrix4fv(model_id , 1, GL_FALSE, &PVM.model[0][0]); }
return programID;
}
void Shader::gl_beginAttributes_pos() {
EMC_VERIFY(_gl.numAttribs == 0);
_gl.numAttribs = 1;
for (int i = 0; i < _gl.numAttribs; i++) {
glEnableVertexAttribArray(i);
int stride = (3) * sizeof(GLfloat);
switch (i) {
case 0:
// position
glVertexAttribPointer(
i, // index
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
stride, // stride
(void*)0 // array buffer offset
);
break;
}
}
}
void Shader::gl_beginAttributes_pos_nor_uv() {
EMC_VERIFY(_gl.numAttribs == 0);
_gl.numAttribs = 3;
for (int attrib = 0; attrib < _gl.numAttribs; attrib++) {
glEnableVertexAttribArray(attrib);
int stride = (3 + 3 + 2) * sizeof(GLfloat);
switch (attrib) {
case 0:
// position
glVertexAttribPointer(
attrib, // index
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
stride, // stride
(void*)0 // array buffer offset
);
break;
case 1:
// normal
glVertexAttribPointer(
attrib, // index
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
stride, // stride
(void*)(3 * sizeof(GLfloat)) // array buffer offset
);
break;
case 2:
// texCoord
glVertexAttribPointer(
attrib, // index
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
stride, // stride
(void*)((3 + 3) * sizeof(GLfloat)) // array buffer offset
);
break;
}
}
}
void Shader::gl_endAttributes() {
EMC_VERIFY(_gl.numAttribs != 0);
for (int i = 0; i < _gl.numAttribs; i++) {
glDisableVertexAttribArray(i);
}
_gl.numAttribs = 0;
}
//****************************************************************************************************
// Render To Texture
//****************************************************************************************************
struct RenderToTexture {
friend class ModelData;
//private: // Make private ????????????????????
AppBase *_appBase = nullptr;
bool _isShadowMap = false;
int _width = 0;
int _height = 0;
int _maxWidth = 0;
int _maxHeight = 0;
Shader *_shader = nullptr;
struct {
GLuint frameBuffer = (GLuint)-1;
GLuint renderedTexture = (GLuint)-1;
GLuint depthRenderBuffer = (GLuint)-1;
} _gl;
GLuint _draft_vertexBuffer = -1;
public:
void init(AppBase *appBase, bool isShadowMap, int width, int height);
void makeData();
void draw(bool drawOnDefaultFrameBuffer);
void destroy();
};
void RenderToTexture::init(AppBase *appBase, bool isShadowMap, int width, int height) {
_appBase = appBase;
_isShadowMap = isShadowMap;
_width = width;
_height = height;
_maxWidth = width;
_maxHeight = height;
if (g_renderingApi == RENDERINGAPI_OPENGL) {
#ifdef USE_OPENGL
// Referenced from:
// - [Basic OpenGL > "tutorial14_render_to_texture"](https://www.opengl-tutorial.org/beginners-tutorials/)
// - [Basic OpenGL > "tutorial16_shadowmaps" ](https://www.opengl-tutorial.org/beginners-tutorials/)
//appBase->getPrimaryContext_s()->makeCurrent(); // TODO: Fix this ????????????????????
// The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer.
EMC_VERIFY(_gl.frameBuffer == -1);
glGenFramebuffers(1, &_gl.frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, _gl.frameBuffer);
// The texture we're going to render to
EMC_VERIFY(_gl.renderedTexture == -1);
glGenTextures(1, &_gl.renderedTexture);
glBindTexture(GL_TEXTURE_2D, _gl.renderedTexture);
if (_isShadowMap == false) {
// Give an empty image to OpenGL (the last "0")
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, _maxWidth, _maxHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0);
// Poor filtering
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);
// The depth buffer
EMC_VERIFY(_gl.depthRenderBuffer == -1);
glGenRenderbuffers(1, &_gl.depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _gl.depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, _maxWidth, _maxHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _gl.depthRenderBuffer);
// Set "renderedTexture" as our colour attachement #0
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _gl.renderedTexture, 0);
// Set the list of draw buffers.
GLenum drawBuffers[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, drawBuffers); // "1" is the size of DrawBuffers
} else {
// Depth texture. Slower than a depth buffer, but you can sample it later in your shader
glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, _maxWidth, _maxHeight, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0);
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_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, _gl.renderedTexture, 0);
// No color output in the bound framebuffer, only depth.
glDrawBuffer(GL_NONE);
}
// Always check that our framebuffer is ok
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
EMC_ERROR("Failed.");
return;
}
// Shader
if (_isShadowMap == false) {
_shader = EMC_NEW Shader(
appBase,
engineDataDir(_PROJECT_NAME) + "/shaders/render-to-texture.vert",
engineDataDir(_PROJECT_NAME) + "/shaders/render-to-texture.frag"
);
}
else {
_shader = EMC_NEW Shader(
appBase,
engineDataDir(_PROJECT_NAME) + "/shaders/shadow-map-depth.vert",
engineDataDir(_PROJECT_NAME) + "/shaders/shadow-map-depth.frag"
);
}
#endif
}
else if (g_renderingApi == RENDERINGAPI_VULKAN) {
#ifdef USE_VULKAN
// TODO
#endif
}
else if (g_renderingApi == RENDERINGAPI_DIRECTX12) {
#ifdef USE_DIRECTX
// TODO
#endif
}
}
void RenderToTexture::makeData() {
if (g_renderingApi == RENDERINGAPI_OPENGL) {
#ifdef USE_OPENGL
GLfloat TMP_vertexBufferData[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
glGenBuffers(1, &_draft_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _draft_vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(TMP_vertexBufferData), TMP_vertexBufferData, GL_STATIC_DRAW);
#endif
}
}
void RenderToTexture::destroy() {
// TODO: Destroy shader.
if (g_renderingApi == RENDERINGAPI_OPENGL) {
#ifdef USE_OPENGL
glDeleteFramebuffers(1, &_gl.frameBuffer); _gl.frameBuffer = -1;
if (_isShadowMap == false) {
// TODO: Delete a few things.
}
else {
// TODO: Delete a few things.
}
#endif
}
else if (g_renderingApi == RENDERINGAPI_VULKAN) {
#ifdef USE_VULKAN
// TODO
#endif
}
else if (g_renderingApi == RENDERINGAPI_DIRECTX12) {
#ifdef USE_DIRECTX
// TODO
#endif
}
}
//****************************************************************************************************
// main()
//****************************************************************************************************
int main(void) {
// Initialise GLFW
if( !glfwInit() )
{
fprintf( stderr, "Failed to initialize GLFW\n" );
getchar();
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Open a window and create its OpenGL context
int windowWidth = 1024;
int windowHeight = 768;
window = glfwCreateWindow( windowWidth, windowHeight, "Render To Texture", NULL, NULL);
if( window == NULL ){
fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
getchar();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
getchar();
glfwTerminate();
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
//--------------------------------------------------
AppBase *appBase = new AppBase();
RenderToTexture rtt;
rtt.init(appBase, false, 1024, 1024);
rtt.makeData();
GLuint rtt_texID = glGetUniformLocation(rtt._shader->_gl.programID, "renderedTexture");
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Create and compile our GLSL program from the shaders
Shader *shader = new Shader(
appBase,
engineDataDir(_PROJECT_NAME) + "/shaders/SimpleVertexShader.vertexshader",
engineDataDir(_PROJECT_NAME) + "/shaders/SimpleFragmentShader.fragmentshader"
);
static const GLfloat g_vertex_buffer_data[] = {
-0.9f,-0.9f,0.0f, 0.0f,0.0f,1.0f, 0.0f,0.0f,
0.9f,-0.9f,0.0f, 0.0f,0.0f,1.0f, 1.0f,0.0f,
-0.9f, 0.9f,0.0f, 0.0f,0.0f,1.0f, 0.0f,1.0f,
0.9f,-0.9f,0.0f, 0.0f,0.0f,1.0f, 1.0f,0.0f,
0.9f, 0.9f,0.0f, 0.0f,0.0f,1.0f, 1.0f,1.0f,
-0.9f, 0.9f,0.0f, 0.0f,0.0f,1.0f, 0.0f,1.0f,
};
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
do {
// Render to texture
if (DEBUG_RENDER_TO_TEXTURE) {
glBindFramebuffer(GL_FRAMEBUFFER, (DEBUG_RTT_ON_DEFAULT_FRAME_BUFFER == 0) ? rtt._gl.frameBuffer : 0);
glViewport(0, 0, rtt._width, rtt._height);
if (rtt._isShadowMap == false) {
// .
}
else {
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
PVMStruct PVM;
PVM.projection = glm::mat4(1);
PVM.view = glm::mat4(1);
PVM.model = glm::mat4(1);
rtt._shader->gl_useProgram(PVM);
rtt._shader->gl_beginAttributes_pos();
glBindBuffer(GL_ARRAY_BUFFER, rtt._draft_vertexBuffer);
GLsizei numVertices = 3 * (1);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
rtt._shader->gl_endAttributes();
}
// Render the scene
if (DEBUG_RENDER_SCENE) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, windowWidth, windowHeight);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
PVMStruct PVM;
PVM.projection = glm::mat4(1.0f);
PVM.view = glm::mat4(1.0f);
PVM.model = glm::mat4(1.0f);
shader->gl_useProgram(PVM);
// The rendered texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, rtt._gl.renderedTexture);
glUniform1i(rtt_texID, 0);
// Draw
shader->gl_beginAttributes_pos_nor_uv();
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
int numVertices = 3 * (2);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
shader->gl_endAttributes();
}
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0 );
// Cleanup VBO
glDeleteBuffers(1, &vertexbuffer);
glDeleteVertexArrays(1, &VertexArrayID);
delete shader; shader = nullptr;
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}