diff --git a/main.cpp b/main.cpp index cf3e21f..264bee9 100644 --- a/main.cpp +++ b/main.cpp @@ -231,10 +231,6 @@ int main (int argc, char* argv[]) // TODO: FIGURE OUT THE REQUIRED INPUT MODE, AS SOME WALLPAPERS USE THINGS LIKE MOUSE POSITION // glfwSetInputMode (window, GLFW_STICKY_KEYS, GL_TRUE); - // set the scene clear color - auto sceneInformation = project->getWallpaper ()->as (); - FloatColor clearColor = sceneInformation->getClearColor (); - // enable depth text glEnable (GL_DEPTH_TEST); glDepthFunc (GL_LESS); @@ -252,10 +248,8 @@ int main (int argc, char* argv[]) g_Time = (float) glfwGetTime (); // get the start time of the frame startTime = clock (); - // render the scene wallpaper->render (); - // do buffer swapping glfwSwapBuffers (window); // poll for events (like closing the window) diff --git a/src/WallpaperEngine/Assets/CTexture.cpp b/src/WallpaperEngine/Assets/CTexture.cpp index 1c16042..05d60c3 100644 --- a/src/WallpaperEngine/Assets/CTexture.cpp +++ b/src/WallpaperEngine/Assets/CTexture.cpp @@ -22,6 +22,7 @@ CTexture::CTexture (void* fileData) this->m_header->height = this->m_header->mipmaps [0]->height; this->m_header->textureWidth = this->m_header->mipmaps [0]->width; this->m_header->textureHeight = this->m_header->mipmaps [0]->height; + // TODO: MAYBE IT'S BETTER TO CREATE A TEXTURE OF THE GIVEN SIZE AND COPY OVER WHAT WE READ FROM THE FILE? } else { @@ -86,7 +87,7 @@ CTexture::CTexture (void* fileData) } // TODO: USE THIS ONE - uint32_t blockSize = (internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16; + // uint32_t blockSize = (internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16; auto cur = this->m_header->mipmaps.begin (); auto end = this->m_header->mipmaps.end (); @@ -146,8 +147,6 @@ CTexture::CTexture (void* fileData) FreeImage_CloseMemory (memory); } } - - // TODO: IMPLEMENT SUPPORT FOR NORMAL IMAGES } CTexture::~CTexture () diff --git a/src/WallpaperEngine/Render/CScene.cpp b/src/WallpaperEngine/Render/CScene.cpp index c2a18e3..7d85be1 100644 --- a/src/WallpaperEngine/Render/CScene.cpp +++ b/src/WallpaperEngine/Render/CScene.cpp @@ -51,19 +51,23 @@ void CScene::render () auto cur = this->m_objects.begin (); auto end = this->m_objects.end (); - // do not use any framebuffer for now - glBindFramebuffer (GL_FRAMEBUFFER, 0); - // ensure we render over the whole screen - glViewport (0, 0, projection->getWidth (), projection->getHeight ()); - // clear screen FloatColor clearColor = this->getScene ()->getClearColor (); glClearColor (clearColor.r, clearColor.g, clearColor.b, clearColor.a); - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // use the scene's framebuffer by default + glBindFramebuffer (GL_FRAMEBUFFER, this->getWallpaperFramebuffer()); + // ensure we render over the whole screen + glViewport (0, 0, projection->getWidth (), projection->getHeight ()); for (; cur != end; cur ++) (*cur)->render (); + + // ensure we render over the whole screen + glViewport (0, 0, projection->getWidth (), projection->getHeight ()); + + CWallpaper::render (); } Core::CScene* CScene::getScene () diff --git a/src/WallpaperEngine/Render/CWallpaper.cpp b/src/WallpaperEngine/Render/CWallpaper.cpp index 7e6a2fb..649d6b3 100644 --- a/src/WallpaperEngine/Render/CWallpaper.cpp +++ b/src/WallpaperEngine/Render/CWallpaper.cpp @@ -1,7 +1,9 @@ #include "CWallpaper.h" +#include "CScene.h" #include #include +#include using namespace WallpaperEngine::Render; @@ -11,6 +13,34 @@ CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CCont m_type (std::move(type)) { this->setupFramebuffers (); + this->setupShaders (); + + GLfloat texCoords [] = { + 0.0f, 0.0f, + 1.0f, 0.0f, + 0.0f, 1.0f, + 0.0f, 1.0f, + 1.0f, 0.0f, + 1.0f, 1.0f + }; + + // inverted positions so the final texture is rendered properly + GLfloat position [] = { + -1.0f, 1.0f, 0.0f, + 1.0, 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 0.0f + }; + + glGenBuffers (1, &this->m_texCoordBuffer); + glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer); + glBufferData (GL_ARRAY_BUFFER, sizeof (texCoords), texCoords, GL_STATIC_DRAW); + + glGenBuffers (1, &this->m_positionBuffer); + glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer); + glBufferData (GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW); } CWallpaper::~CWallpaper () @@ -27,6 +57,161 @@ WallpaperEngine::Core::CWallpaper* CWallpaper::getWallpaperData () return this->m_wallpaperData; } +GLuint CWallpaper::getWallpaperFramebuffer () const +{ + return this->m_sceneFramebuffer; +} + +GLuint CWallpaper::getWallpaperTexture () const +{ + return this->m_sceneTexture; +} + +void CWallpaper::setupShaders () +{ + // reserve shaders in OpenGL + GLuint vertexShaderID = glCreateShader (GL_VERTEX_SHADER); + + // give shader's source code to OpenGL to be compiled + const char* sourcePointer = "#version 120\n" + "attribute vec3 a_Position;\n" + "attribute vec2 a_TexCoord;\n" + "varying vec2 v_TexCoord;\n" + "void main () {\n" + "gl_Position = vec4 (a_Position, 1.0);\n" + "v_TexCoord = a_TexCoord;\n" + "}"; + + glShaderSource (vertexShaderID, 1, &sourcePointer, nullptr); + glCompileShader (vertexShaderID); + + GLint result = GL_FALSE; + int infoLogLength = 0; + + // ensure the vertex shader was correctly compiled + glGetShaderiv (vertexShaderID, GL_COMPILE_STATUS, &result); + glGetShaderiv (vertexShaderID, GL_INFO_LOG_LENGTH, &infoLogLength); + + if (infoLogLength > 0) + { + char* logBuffer = new char [infoLogLength + 1]; + // ensure logBuffer ends with a \0 + memset (logBuffer, 0, infoLogLength + 1); + // get information about the error + glGetShaderInfoLog (vertexShaderID, infoLogLength, nullptr, logBuffer); + // throw an exception about the issue + std::string message = logBuffer; + // free the buffer + delete[] logBuffer; + // throw an exception + throw std::runtime_error (message); + } + + // reserve shaders in OpenGL + GLuint fragmentShaderID = glCreateShader (GL_FRAGMENT_SHADER); + + // give shader's source code to OpenGL to be compiled + sourcePointer = "#version 120\n" + "uniform sampler2D g_Texture0;\n" + "varying vec2 v_TexCoord;\n" + "void main () {\n" + "gl_FragColor = texture2D (g_Texture0, v_TexCoord);\n" + "}"; + + glShaderSource (fragmentShaderID, 1, &sourcePointer, nullptr); + glCompileShader (fragmentShaderID); + + result = GL_FALSE; + infoLogLength = 0; + + // ensure the vertex shader was correctly compiled + glGetShaderiv (fragmentShaderID, GL_COMPILE_STATUS, &result); + glGetShaderiv (fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength); + + if (infoLogLength > 0) + { + char* logBuffer = new char [infoLogLength + 1]; + // ensure logBuffer ends with a \0 + memset (logBuffer, 0, infoLogLength + 1); + // get information about the error + glGetShaderInfoLog (fragmentShaderID, infoLogLength, nullptr, logBuffer); + // throw an exception about the issue + std::string message = logBuffer; + // free the buffer + delete[] logBuffer; + // throw an exception + throw std::runtime_error (message); + } + + // create the final program + this->m_shader = glCreateProgram (); + // link the shaders together + glAttachShader (this->m_shader, vertexShaderID); + glAttachShader (this->m_shader, fragmentShaderID); + glLinkProgram (this->m_shader); + // check that the shader was properly linked + result = GL_FALSE; + infoLogLength = 0; + + glGetProgramiv (this->m_shader, GL_LINK_STATUS, &result); + glGetProgramiv (this->m_shader, GL_INFO_LOG_LENGTH, &infoLogLength); + + if (infoLogLength > 0) + { + char* logBuffer = new char [infoLogLength + 1]; + // ensure logBuffer ends with a \0 + memset (logBuffer, 0, infoLogLength + 1); + // get information about the error + glGetProgramInfoLog (this->m_shader, infoLogLength, nullptr, logBuffer); + // throw an exception about the issue + std::string message = logBuffer; + // free the buffer + delete[] logBuffer; + // throw an exception + throw std::runtime_error (message); + } + + // after being liked shaders can be dettached and deleted + glDetachShader (this->m_shader, vertexShaderID); + glDetachShader (this->m_shader, fragmentShaderID); + + glDeleteShader (vertexShaderID); + glDeleteShader (fragmentShaderID); + + // get textures + this->g_Texture0 = glGetUniformLocation (this->m_shader, "g_Texture0"); + this->a_Position = glGetAttribLocation (this->m_shader, "a_Position"); + this->a_TexCoord = glGetAttribLocation (this->m_shader, "a_TexCoord"); +} + +void CWallpaper::render () +{ + // write to default's framebuffer + glBindFramebuffer (GL_FRAMEBUFFER, GL_NONE); + + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDisable (GL_BLEND); + glDisable (GL_DEPTH_TEST); + // do not use any shader + glUseProgram (this->m_shader); + // activate scene texture + glActiveTexture (GL_TEXTURE0); + glBindTexture (GL_TEXTURE_2D, this->getWallpaperTexture ()); + // set uniforms and attribs + glEnableVertexAttribArray (this->a_TexCoord); + glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer); + glVertexAttribPointer (this->a_TexCoord, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + glEnableVertexAttribArray (this->a_Position); + glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer); + glVertexAttribPointer (this->a_Position, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glUniform1i (this->g_Texture0, 0); + // write the framebuffer as is to the screen + glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer); + glDrawArrays (GL_TRIANGLES, 0, 6); +} + void CWallpaper::pinpongFramebuffer (GLuint* drawTo, GLuint* inputTexture) { // get current main framebuffer and texture so we can swap them @@ -47,7 +232,7 @@ void CWallpaper::pinpongFramebuffer (GLuint* drawTo, GLuint* inputTexture) this->m_subTexture = currentMainTexture; } -void CWallpaper::setupFramebuffers () +void CWallpaper::createFramebuffer (GLuint* framebuffer, GLuint* depthbuffer, GLuint* texture) { int windowWidth = 1920; int windowHeight = 1080; @@ -62,12 +247,12 @@ void CWallpaper::setupFramebuffers () GLenum drawBuffers [1] = {GL_COLOR_ATTACHMENT0}; // create the main framebuffer - glGenFramebuffers (1, &this->m_mainFramebuffer); - glBindFramebuffer (GL_FRAMEBUFFER, this->m_mainFramebuffer); + glGenFramebuffers (1, framebuffer); + glBindFramebuffer (GL_FRAMEBUFFER, *framebuffer); // create the main texture - glGenTextures (1, &this->m_mainTexture); + glGenTextures (1, texture); // bind the new texture to set settings on it - glBindTexture (GL_TEXTURE_2D, this->m_mainTexture); + glBindTexture (GL_TEXTURE_2D, *texture); // give OpenGL an empty image glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, windowWidth, windowHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); @@ -78,46 +263,24 @@ void CWallpaper::setupFramebuffers () glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // create the depth render buffer for the main framebuffer - glGenRenderbuffers (1, &this->m_mainDepthBuffer); - glBindRenderbuffer (GL_RENDERBUFFER, this->m_mainDepthBuffer); + glGenRenderbuffers (1, depthbuffer); + glBindRenderbuffer (GL_RENDERBUFFER, *depthbuffer); glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, windowWidth, windowHeight); - glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, this->m_mainDepthBuffer); + glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *depthbuffer); // set the texture as the colour attachmend #0 - glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->m_mainTexture, 0); + glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture, 0); // finally set the list of draw buffers glDrawBuffers (1, drawBuffers); // ensure first framebuffer is okay if (glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) throw std::runtime_error ("Framebuffers are not properly set"); +} - // create the sub framebuffer - glGenFramebuffers (1, &this->m_subFramebuffer); - glBindFramebuffer (GL_FRAMEBUFFER, this->m_subFramebuffer); - // create the sub texture - glGenTextures (1, &this->m_subTexture); - // bind the new texture to set settings on it - glBindTexture (GL_TEXTURE_2D, this->m_subTexture); - // give OpenGL an empty image - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, windowWidth, windowHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - - // set filtering parameters, otherwise the texture is not rendered - 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); - - // create the depth render buffer for the main framebuffer - glGenRenderbuffers (1, &this->m_subDepthBuffer); - glBindRenderbuffer (GL_RENDERBUFFER, this->m_subDepthBuffer); - glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, windowWidth, windowHeight); - glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, this->m_subDepthBuffer); - // set the texture as the colour attachmend #0 - glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->m_subTexture, 0); - // finally set the list of draw buffers - glDrawBuffers (1, drawBuffers); - - // ensure second framebuffer is okay - if (glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - throw std::runtime_error ("Framebuffers are not properly set"); +void CWallpaper::setupFramebuffers () +{ + this->createFramebuffer (&this->m_mainFramebuffer, &this->m_mainDepthBuffer, &this->m_mainTexture); + this->createFramebuffer (&this->m_subFramebuffer, &this->m_subDepthBuffer, &this->m_subTexture); + // create framebuffer for the scene + this->createFramebuffer (&this->m_sceneFramebuffer, &this->m_sceneDepthBuffer, &this->m_sceneTexture); } \ No newline at end of file diff --git a/src/WallpaperEngine/Render/CWallpaper.h b/src/WallpaperEngine/Render/CWallpaper.h index 784d30a..a3729b0 100644 --- a/src/WallpaperEngine/Render/CWallpaper.h +++ b/src/WallpaperEngine/Render/CWallpaper.h @@ -32,7 +32,7 @@ namespace WallpaperEngine::Render /** * Performs a render pass of the wallpaper */ - virtual void render () = 0; + virtual void render (); /** * @return The container to resolve files for this wallpaper @@ -47,7 +47,18 @@ namespace WallpaperEngine::Render */ void pinpongFramebuffer (GLuint* drawTo, GLuint* inputTexture); + /** + * @return The scene's framebuffer + */ + GLuint getWallpaperFramebuffer () const; + /** + * @return The scene's texture + */ + GLuint getWallpaperTexture () const; + protected: + void createFramebuffer (GLuint* framebuffer, GLuint* depthbuffer, GLuint* texture); + CContainer* m_container; Core::CWallpaper* m_wallpaperData; @@ -81,9 +92,34 @@ namespace WallpaperEngine::Render GLuint m_subTexture; /** - * Setups OpenGL's framebuffers for ping-pong + * The framebuffer used for the scene output + */ + GLuint m_sceneFramebuffer; + /** + * The depthbuffer used for the scene output + */ + GLuint m_sceneDepthBuffer; + /** + * The texture used for the scene output + */ + GLuint m_sceneTexture; + GLuint m_texCoordBuffer; + GLuint m_positionBuffer; + GLuint m_shader; + // shader variables + GLint g_Texture0; + GLint g_ModelViewProjectionMatrix; + GLint a_Position; + GLint a_TexCoord; + + /** + * Setups OpenGL's framebuffers for ping-pong and scene rendering */ void setupFramebuffers (); + /** + * Setups OpenGL's shaders for this wallpaper backbuffer + */ + void setupShaders (); private: /** diff --git a/src/WallpaperEngine/Render/Objects/CImage.cpp b/src/WallpaperEngine/Render/Objects/CImage.cpp index 5c2a1f1..dbb1d2a 100644 --- a/src/WallpaperEngine/Render/Objects/CImage.cpp +++ b/src/WallpaperEngine/Render/Objects/CImage.cpp @@ -140,10 +140,8 @@ void CImage::render () if (this->getImage ()->isVisible () == false) return; - GLuint drawTo = 0; + GLuint drawTo = this->getScene()->getWallpaperFramebuffer(); GLuint inputTexture = this->m_texture->getTextureID (); - // get the orthogonal projection - auto projection = this->getScene ()->getScene ()->getOrthogonalProjection (); // pinpong current buffer this->getScene ()->pinpongFramebuffer (&drawTo, nullptr); @@ -166,7 +164,7 @@ void CImage::render () this->getScene ()->pinpongFramebuffer (nullptr, &inputTexture); // render the main material - this->m_material->render (0, inputTexture); + this->m_material->render (this->getScene()->getWallpaperFramebuffer(), inputTexture); /* glBindFramebuffer (GL_FRAMEBUFFER, 0); // set the viewport, for now use the scene width/height but we might want to use image's size TODO: INVESTIGATE THAT diff --git a/src/WallpaperEngine/Render/Objects/Effects/CPass.cpp b/src/WallpaperEngine/Render/Objects/Effects/CPass.cpp index 3308cbe..1478cd6 100644 --- a/src/WallpaperEngine/Render/Objects/Effects/CPass.cpp +++ b/src/WallpaperEngine/Render/Objects/Effects/CPass.cpp @@ -51,7 +51,7 @@ CPass::CPass (CMaterial* material, Core::Objects::Images::Materials::CPass* pass void CPass::render (GLuint drawTo, GLuint input) { // clear whatever buffer we're drawing to if we're not drawing to screen - if (drawTo > 0) + if (drawTo != this->m_material->getImage()->getScene()->getWallpaperFramebuffer()) glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // set texture blending @@ -95,7 +95,7 @@ void CPass::render (GLuint drawTo, GLuint input) // this should not be required once we do some prediction on rendering things // but for now should be enough this->a_TexCoord = (input == this->m_material->getImage ()->getTexture ()->getTextureID ()) ? *this->m_material->getImage ()->getTexCoordBuffer () : *this->m_material->getImage ()->getPassTexCoordBuffer (); - this->a_Position = (drawTo > 0) ? *this->m_material->getImage ()->getPassVertexBuffer () : *this->m_material->getImage ()->getVertexBuffer (); + this->a_Position = (drawTo != this->m_material->getImage()->getScene()->getWallpaperFramebuffer()) ? *this->m_material->getImage ()->getPassVertexBuffer () : *this->m_material->getImage ()->getVertexBuffer (); // use the shader we have registered glUseProgram (this->m_programID); @@ -173,7 +173,7 @@ void CPass::render (GLuint drawTo, GLuint input) } // start actual rendering now - glBindBuffer (GL_ARRAY_BUFFER, (drawTo > 0) ? *this->m_material->getImage ()->getPassVertexBuffer () : *this->m_material->getImage ()->getVertexBuffer ()); + glBindBuffer (GL_ARRAY_BUFFER, (drawTo != this->m_material->getImage()->getScene()->getWallpaperFramebuffer()) ? *this->m_material->getImage ()->getPassVertexBuffer () : *this->m_material->getImage ()->getVertexBuffer ()); glDrawArrays (GL_TRIANGLES, 0, 6); // disable vertex attribs array @@ -270,10 +270,6 @@ void CPass::setupShaders () // support three textures for now this->g_Texture0Rotation = glGetUniformLocation (this->m_programID, "g_Texture0Rotation"); this->g_Texture0Translation = glGetUniformLocation (this->m_programID, "g_Texture0Translation"); - - // bind a_TexCoord and a_Position - this->a_TexCoord = glGetAttribLocation (this->m_programID, "a_TexCoord"); - this->a_Position = glGetAttribLocation (this->m_programID, "a_Position"); } void CPass::setupAttributes () @@ -413,8 +409,9 @@ void CPass::setupShaderVariables () CShaderVariable* var = vertexVar == nullptr ? pixelVar : vertexVar; // ensure the shader's and the constant are of the same type - if ((*cur).second->getType () != var->getType ()) - throw std::runtime_error ("Constant and pixel/vertex variable are not of the same type"); + // TODO: CHECK THIS, THERE'S SOME BACKGROUNDS WHERE THIS HAPPENS :/ + /*if ((*cur).second->getType () != var->getType ()) + throw std::runtime_error ("Constant and pixel/vertex variable are not of the same type");*/ // now determine the constant's type and register the correct uniform for it if ((*cur).second->is ())