diff --git a/CMakeLists.txt b/CMakeLists.txt index 434419d..8808fca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,8 +19,9 @@ find_package(SDL REQUIRED) find_package(SDL_mixer REQUIRED) find_package(LZ4 REQUIRED) find_package(FFmpeg REQUIRED) +find_package(FreeImage REQUIRED) -include_directories(${X11_INCLUDE_DIR} ${XRANDR_INCLUDE_DIR} ${GLEW_INCLUDE_DIR} ${glfw3_INCLUDE_DIR} ${LZ4_INCLUDE_DIR} ${SDL_INCLUDE_DIRS} ${SDL_MIXER_INCLUDE_DIRS} ${FFMPEG_INCLUDE_DIR} src include) +include_directories(${X11_INCLUDE_DIR} ${XRANDR_INCLUDE_DIR} ${GLEW_INCLUDE_DIR} ${glfw3_INCLUDE_DIR} ${LZ4_INCLUDE_DIR} ${SDL_INCLUDE_DIRS} ${SDL_MIXER_INCLUDE_DIRS} ${FFMPEG_INCLUDE_DIR} ${FREEIMAGE_INCLUDE_DIR} src include) add_executable( wallengine @@ -169,4 +170,4 @@ add_executable( src/WallpaperEngine/Core/Objects/Images/Materials/CPass.h ) -target_link_libraries(wallengine ${X11_LIBRARIES} ${XRANDR_LIBRARIES} ${X11_Xxf86vm_LIB} ${OPENGL_LIBRARIES} ${GLEW_LIBRARIES} ${GLFW3_LIBRARY} ${GLUT_LIBRARIES} ${ZLIB_LIBRARIES} ${LZ4_LIBRARY} ${SDL_LIBRARY} ${SDL_MIXER_LIBRARIES} ${FFMPEG_LIBRARIES}) \ No newline at end of file +target_link_libraries(wallengine ${X11_LIBRARIES} ${XRANDR_LIBRARIES} ${X11_Xxf86vm_LIB} ${OPENGL_LIBRARIES} ${GLEW_LIBRARIES} ${GLFW3_LIBRARY} ${GLUT_LIBRARIES} ${ZLIB_LIBRARIES} ${LZ4_LIBRARY} ${SDL_LIBRARY} ${SDL_MIXER_LIBRARIES} ${FFMPEG_LIBRARIES} ${FREEIMAGE_LIBRARIES}) \ No newline at end of file diff --git a/CMakeModules/FindFreeImage.cmake b/CMakeModules/FindFreeImage.cmake new file mode 100644 index 0000000..9e4d5f7 --- /dev/null +++ b/CMakeModules/FindFreeImage.cmake @@ -0,0 +1,83 @@ +# Find the FreeImage library. +# +# This module defines +# FREEIMAGE_FOUND - True if FREEIMAGE was found. +# FREEIMAGE_INCLUDE_DIRS - Include directories for FREEIMAGE headers. +# FREEIMAGE_LIBRARIES - Libraries for FREEIMAGE. +# +# To specify an additional directory to search, set FREEIMAGE_ROOT. +# +# Copyright (c) 2010, Ewen Cheslack-Postava +# Based on FindSQLite3.cmake by: +# Copyright (c) 2006, Jaroslaw Staniek, +# Extended by Siddhartha Chaudhuri, 2008. +# +# Redistribution and use is allowed according to the terms of the BSD license. +# + +SET(FREEIMAGE_FOUND FALSE) +SET(FREEIMAGE_INCLUDE_DIRS) +SET(FREEIMAGE_LIBRARIES) + +SET(SEARCH_PATHS + $ENV{ProgramFiles}/freeimage/include + $ENV{SystemDrive}/freeimage/include + $ENV{ProgramFiles}/freeimage + $ENV{SystemDrive}/freeimage + ) +IF(FREEIMAGE_ROOT) + SET(SEARCH_PATHS + ${FREEIMAGE_ROOT} + ${FREEIMAGE_ROOT}/include + ${SEARCH_PATHS} + ) +ENDIF() + +FIND_PATH(FREEIMAGE_INCLUDE_DIRS + NAMES FreeImage.h + PATHS ${SEARCH_PATHS} + NO_DEFAULT_PATH) +IF(NOT FREEIMAGE_INCLUDE_DIRS) # now look in system locations + FIND_PATH(FREEIMAGE_INCLUDE_DIRS NAMES FreeImage.h) +ENDIF(NOT FREEIMAGE_INCLUDE_DIRS) + +SET(FREEIMAGE_LIBRARY_DIRS) +IF(FREEIMAGE_ROOT) + SET(FREEIMAGE_LIBRARY_DIRS ${FREEIMAGE_ROOT}) + IF(EXISTS "${FREEIMAGE_ROOT}/lib") + SET(FREEIMAGE_LIBRARY_DIRS ${FREEIMAGE_LIBRARY_DIRS} ${FREEIMAGE_ROOT}/lib) + ENDIF() + IF(EXISTS "${FREEIMAGE_ROOT}/lib/static") + SET(FREEIMAGE_LIBRARY_DIRS ${FREEIMAGE_LIBRARY_DIRS} ${FREEIMAGE_ROOT}/lib/static) + ENDIF() +ENDIF() + +# FREEIMAGE +# Without system dirs +FIND_LIBRARY(FREEIMAGE_LIBRARY + NAMES freeimage + PATHS ${FREEIMAGE_LIBRARY_DIRS} + NO_DEFAULT_PATH + ) +IF(NOT FREEIMAGE_LIBRARY) # now look in system locations + FIND_LIBRARY(FREEIMAGE_LIBRARY NAMES freeimage) +ENDIF(NOT FREEIMAGE_LIBRARY) + +SET(FREEIMAGE_LIBRARIES) +IF(FREEIMAGE_LIBRARY) + SET(FREEIMAGE_LIBRARIES ${FREEIMAGE_LIBRARY}) +ENDIF() + +IF(FREEIMAGE_INCLUDE_DIRS AND FREEIMAGE_LIBRARIES) + SET(FREEIMAGE_FOUND TRUE) + IF(NOT FREEIMAGE_FIND_QUIETLY) + MESSAGE(STATUS "Found FreeImage: headers at ${FREEIMAGE_INCLUDE_DIRS}, libraries at ${FREEIMAGE_LIBRARY_DIRS} :: ${FREEIMAGE_LIBRARIES}") + ENDIF(NOT FREEIMAGE_FIND_QUIETLY) +ELSE(FREEIMAGE_INCLUDE_DIRS AND FREEIMAGE_LIBRARIES) + SET(FREEIMAGE_FOUND FALSE) + IF(FREEIMAGE_FIND_REQUIRED) + MESSAGE(STATUS "FreeImage not found") + ENDIF(FREEIMAGE_FIND_REQUIRED) +ENDIF(FREEIMAGE_INCLUDE_DIRS AND FREEIMAGE_LIBRARIES) + +MARK_AS_ADVANCED(FREEIMAGE_INCLUDE_DIRS FREEIMAGE_LIBRARIES) diff --git a/README.md b/README.md index bda029c..772e916 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Wallpaper Engine is a software designed by [Kristjan Skutta](https://store.steam - Xrandr - GLW3 - GLM +- FreeImage # 5. How to use ## 5.1. Pre-requirements diff --git a/main.cpp b/main.cpp index d4b1c66..cf3e21f 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -136,38 +137,14 @@ int main (int argc, char* argv[]) return 1; } + // initialize freeimage + FreeImage_Initialise (TRUE); + // set some window hints (opengl version to be used) glfwWindowHint (GLFW_SAMPLES, 4); glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 1); - // create the window! - // TODO: DO WE NEED TO PASS MONITOR HERE OR ANYTHING? - // TODO: FIGURE OUT HOW TO PUT THIS WINDOW IN THE BACKGROUND - GLFWwindow* window = glfwCreateWindow (1920, 1080, "WallpaperEngine", NULL, NULL); - - if (window == nullptr) - { - fprintf (stderr, "Failed to open a GLFW window"); - glfwTerminate (); - return 2; - } - - glfwMakeContextCurrent (window); - - int windowWidth = 1920; - int windowHeight = 1080; - - // get the real framebuffer size - glfwGetFramebufferSize (window, &windowWidth, &windowHeight); - - if (glewInit () != GLEW_OK) - { - fprintf (stderr, "Failed to initialize GLEW"); - glfwTerminate (); - return 3; - } - std::string project_path = path + "project.json"; auto containers = new WallpaperEngine::Assets::CCombinedContainer (); @@ -192,6 +169,34 @@ int main (int argc, char* argv[]) auto project = WallpaperEngine::Core::CProject::fromFile ("project.json", containers); WallpaperEngine::Render::CWallpaper* wallpaper; + auto projection = project->getWallpaper ()->as ()->getOrthogonalProjection (); + // create the window! + // TODO: DO WE NEED TO PASS MONITOR HERE OR ANYTHING? + // TODO: FIGURE OUT HOW TO PUT THIS WINDOW IN THE BACKGROUND + GLFWwindow* window = glfwCreateWindow (projection->getWidth (), projection->getHeight (), "WallpaperEngine", NULL, NULL); + + if (window == nullptr) + { + fprintf (stderr, "Failed to open a GLFW window"); + glfwTerminate (); + return 2; + } + + glfwMakeContextCurrent (window); + + int windowWidth = projection->getWidth (); + int windowHeight = projection->getHeight (); + + // get the real framebuffer size + glfwGetFramebufferSize (window, &windowWidth, &windowHeight); + + if (glewInit () != GLEW_OK) + { + fprintf (stderr, "Failed to initialize GLEW"); + glfwTerminate (); + return 3; + } + if (project->getType () == "scene") { WallpaperEngine::Core::CScene* scene = project->getWallpaper ()->as (); @@ -248,15 +253,6 @@ int main (int argc, char* argv[]) // get the start time of the frame startTime = clock (); - // do not use any framebuffer for now - glBindFramebuffer (GL_FRAMEBUFFER, 0); - // ensure we render over the whole screen - glViewport (0, 0, 1920, 1080); - - glClearColor (clearColor.r, clearColor.g, clearColor.b, clearColor.a); - // clear window - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // render the scene wallpaper->render (); @@ -276,6 +272,8 @@ int main (int argc, char* argv[]) glfwTerminate (); // terminate SDL SDL_Quit (); + // terminate free image + FreeImage_DeInitialise (); return 0; } \ No newline at end of file diff --git a/src/WallpaperEngine/Assets/CTexture.cpp b/src/WallpaperEngine/Assets/CTexture.cpp index f832e6e..1c16042 100644 --- a/src/WallpaperEngine/Assets/CTexture.cpp +++ b/src/WallpaperEngine/Assets/CTexture.cpp @@ -11,8 +11,40 @@ CTexture::CTexture (void* fileData) // ensure the header is parsed this->parseHeader (static_cast (fileData)); + GLint internalFormat; + if (this->m_header->freeImageFormat != FREE_IMAGE_FORMAT::FIF_UNKNOWN) - throw std::runtime_error ("Normal images are not supported yet"); + { + internalFormat = GL_RGBA8; + // set some extra information too as it's used for image sizing + // this ensures that a_TexCoord uses the full image instead of just part of it + this->m_header->width = this->m_header->mipmaps [0]->width; + 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; + } + else + { + // detect the image format and hand it to openGL to be used + switch (this->m_header->format) + { + case TextureFormat::DXT5: + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case TextureFormat::DXT3: + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case TextureFormat::DXT1: + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case TextureFormat::ARGB8888: + internalFormat = GL_RGBA8; + break; + default: + delete this->m_header; + throw std::runtime_error ("Cannot determine the texture format"); + } + } // set the texture resolution // TODO: SUPPORT SPRITES @@ -21,28 +53,6 @@ CTexture::CTexture (void* fileData) this->m_header->textureWidth, this->m_header->textureHeight }; - GLint formatGL; - - // detect the image format and hand it to openGL to be used - switch (this->m_header->format) - { - case TextureFormat::DXT5: - formatGL = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - break; - case TextureFormat::DXT3: - formatGL = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - break; - case TextureFormat::DXT1: - formatGL = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - break; - case TextureFormat::ARGB8888: - formatGL = GL_RGBA8; - break; - default: - delete this->m_header; - throw std::runtime_error ("Cannot determine the texture format"); - } - // reserve a texture glGenTextures (1, &this->m_textureID); @@ -76,32 +86,64 @@ CTexture::CTexture (void* fileData) } // TODO: USE THIS ONE - uint32_t blockSize = (formatGL == 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 (); for (int32_t level = 0; cur != end; cur ++, level ++) { - switch (formatGL) + FIBITMAP* bitmap = nullptr; + FIBITMAP* converted = nullptr; + FIMEMORY* memory = nullptr; + void* dataptr = (*cur)->uncompressedData; + uint32_t width = (*cur)->width; + uint32_t height = (*cur)->height; + GLenum textureFormat = GL_RGBA; + + if (this->m_header->freeImageFormat != FREE_IMAGE_FORMAT::FIF_UNKNOWN) + { + memory = FreeImage_OpenMemory (reinterpret_cast ((*cur)->uncompressedData), (*cur)->uncompressedSize); + + // load the image and setup pointers so they can be used + bitmap = FreeImage_LoadFromMemory (this->m_header->freeImageFormat, memory); + // flip the image vertically + FreeImage_FlipVertical (bitmap); + // convert to a 32bits bytearray + converted = FreeImage_ConvertTo32Bits (bitmap); + + dataptr = FreeImage_GetBits (converted); + width = FreeImage_GetWidth (converted); + height = FreeImage_GetHeight (converted); + textureFormat = GL_BGRA; + } + + switch (internalFormat) { case GL_RGBA8: - glTexImage2D (GL_TEXTURE_2D, level, formatGL, - (*cur)->width, (*cur)->height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, - (*cur)->uncompressedData + glTexImage2D (GL_TEXTURE_2D, level, internalFormat, + width, height, 0, + textureFormat, GL_UNSIGNED_BYTE, + dataptr ); break; case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: glCompressedTexImage2D ( - GL_TEXTURE_2D, level, formatGL, - (*cur)->width, (*cur)->height, 0, - (*cur)->uncompressedSize, (*cur)->uncompressedData + GL_TEXTURE_2D, level, internalFormat, + (*cur)->width, (*cur)->height, 0, + (*cur)->uncompressedSize, dataptr ); break; + } + // freeimage buffer won't be used anymore, so free memory + if (this->m_header->freeImageFormat != FREE_IMAGE_FORMAT::FIF_UNKNOWN) + { + FreeImage_Unload (bitmap); + FreeImage_Unload (converted); + FreeImage_CloseMemory (memory); } } diff --git a/src/WallpaperEngine/Assets/CTexture.h b/src/WallpaperEngine/Assets/CTexture.h index c77da1c..a9171ca 100644 --- a/src/WallpaperEngine/Assets/CTexture.h +++ b/src/WallpaperEngine/Assets/CTexture.h @@ -7,6 +7,8 @@ #include #include +#include + namespace WallpaperEngine::Assets { class CTexture @@ -30,50 +32,6 @@ namespace WallpaperEngine::Assets R8 = 9, }; - // extracted from the free image library - enum FREE_IMAGE_FORMAT : int - { - FIF_UNKNOWN = -1, - FIF_BMP = 0, - FIF_ICO = 1, - FIF_JPEG = 2, - FIF_JNG = 3, - FIF_KOALA = 4, - FIF_LBM = 5, - FIF_IFF = FIF_LBM, - FIF_MNG = 6, - FIF_PBM = 7, - FIF_PBMRAW = 8, - FIF_PCD = 9, - FIF_PCX = 10, - FIF_PGM = 11, - FIF_PGMRAW = 12, - FIF_PNG = 13, - FIF_PPM = 14, - FIF_PPMRAW = 15, - FIF_RAS = 16, - FIF_TARGA = 17, - FIF_TIFF = 18, - FIF_WBMP = 19, - FIF_PSD = 20, - FIF_CUT = 21, - FIF_XBM = 22, - FIF_XPM = 23, - FIF_DDS = 24, - FIF_GIF = 25, - FIF_HDR = 26, - FIF_FAXG3 = 27, - FIF_SGI = 28, - FIF_EXR = 29, - FIF_J2K = 30, - FIF_JP2 = 31, - FIF_PFM = 32, - FIF_PICT = 33, - FIF_RAW = 34, - FIF_WEBP = 35, - FIF_JXR = 36 - }; - class TextureMipmap { public: diff --git a/src/WallpaperEngine/Render/CScene.cpp b/src/WallpaperEngine/Render/CScene.cpp index cc1e14b..c2a18e3 100644 --- a/src/WallpaperEngine/Render/CScene.cpp +++ b/src/WallpaperEngine/Render/CScene.cpp @@ -47,9 +47,21 @@ CCamera* CScene::getCamera () const void CScene::render () { + auto projection = this->getScene ()->getOrthogonalProjection (); 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); + for (; cur != end; cur ++) (*cur)->render (); } diff --git a/src/WallpaperEngine/Render/CWallpaper.cpp b/src/WallpaperEngine/Render/CWallpaper.cpp index e80c9c2..7e6a2fb 100644 --- a/src/WallpaperEngine/Render/CWallpaper.cpp +++ b/src/WallpaperEngine/Render/CWallpaper.cpp @@ -49,7 +49,17 @@ void CWallpaper::pinpongFramebuffer (GLuint* drawTo, GLuint* inputTexture) void CWallpaper::setupFramebuffers () { - // TODO: ENSURE THE WINDOW WIDTH AND HEIGHT IS CORRECT AND UPDATE THEM WHEN THE SCREEN CHANGES + int windowWidth = 1920; + int windowHeight = 1080; + + if (this->getWallpaperData ()->is ()) + { + auto projection = this->getWallpaperData ()->as ()->getOrthogonalProjection (); + + windowWidth = projection->getWidth (); + windowHeight = projection->getHeight (); + } + GLenum drawBuffers [1] = {GL_COLOR_ATTACHMENT0}; // create the main framebuffer glGenFramebuffers (1, &this->m_mainFramebuffer); @@ -59,7 +69,7 @@ void CWallpaper::setupFramebuffers () // bind the new texture to set settings on it glBindTexture (GL_TEXTURE_2D, this->m_mainTexture); // give OpenGL an empty image - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + 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); @@ -70,7 +80,7 @@ void CWallpaper::setupFramebuffers () // create the depth render buffer for the main framebuffer glGenRenderbuffers (1, &this->m_mainDepthBuffer); glBindRenderbuffer (GL_RENDERBUFFER, this->m_mainDepthBuffer); - glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1920, 1080); + glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, windowWidth, windowHeight); glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, this->m_mainDepthBuffer); // set the texture as the colour attachmend #0 glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->m_mainTexture, 0); @@ -89,7 +99,7 @@ void CWallpaper::setupFramebuffers () // 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, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + 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); @@ -100,7 +110,7 @@ void CWallpaper::setupFramebuffers () // 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, 1920, 1080); + 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);