diff options
Diffstat (limited to 'apps/openmb/renderer/Skybox.cpp')
| -rw-r--r-- | apps/openmb/renderer/Skybox.cpp | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/apps/openmb/renderer/Skybox.cpp b/apps/openmb/renderer/Skybox.cpp new file mode 100644 index 0000000..fea0021 --- /dev/null +++ b/apps/openmb/renderer/Skybox.cpp @@ -0,0 +1,155 @@ +#include "Skybox.hpp" + +#include "Shader.hpp" +#include <stb_image.h> + +#include <algorithm> +#include <filesystem> +#include <iostream> + +namespace Fs = std::filesystem; + +namespace renderer { +Skybox::Skybox () : mTexID( 0 ), mVAO( 0 ), mVBO( 0 ), mInitialized( false ) {} + +Skybox::~Skybox () { + if( mVBO ) + glDeleteBuffers( 1, &mVBO ); + if( mVAO ) + glDeleteVertexArrays( 1, &mVAO ); + if( mTexID ) + glDeleteTextures( 1, &mTexID ); +} + +static std::string toLower ( const std::string& s ) { + std::string out = s; + std::transform( out.begin(), out.end(), out.begin(), [] ( unsigned char c ) { return std::tolower( c ); } ); + return out; +} + +bool Skybox::loadFromDirectory ( const std::string& dirPath ) { + + std::vector<std::string> faceTokens = { "right", "left", "top", "bottom", "front", "back" }; + std::vector<std::string> faces( 6 ); + + if( !Fs::exists( dirPath ) || !Fs::is_directory( dirPath ) ) { + std::cerr << "Skybox directory does not exist: " << dirPath << std::endl; + return false; + } + + for( auto& entry : Fs::directory_iterator( dirPath ) ) { + if( !entry.is_regular_file() ) + continue; + auto name = entry.path().filename().string(); + std::string lname = toLower( name ); + for( size_t i = 0; i < faceTokens.size(); ++i ) { + if( lname.find( faceTokens[i] ) != std::string::npos ) { + faces[i] = entry.path().string(); + } + } + } + + for( size_t i = 0; i < faces.size(); ++i ) { + if( faces[i].empty() ) { + std::cerr << "Missing skybox face for token: " << faceTokens[i] << std::endl; + return false; + } + } + + return loadFaces( faces ); +} + +bool Skybox::loadFaces ( const std::vector<std::string>& faces ) { + glGenTextures( 1, &mTexID ); + glBindTexture( GL_TEXTURE_CUBE_MAP, mTexID ); + + stbi_set_flip_vertically_on_load( false ); + for( unsigned i = 0; i < faces.size(); ++i ) { + int w, h, ch; + unsigned char* data = stbi_load( faces[i].c_str(), &w, &h, &ch, 0 ); + if( !data ) { + std::cerr << "Failed to load skybox face: " << faces[i] << std::endl; + glBindTexture( GL_TEXTURE_CUBE_MAP, 0 ); + return false; + } + GLenum format = ( ch == 4 ) ? GL_RGBA : GL_RGB; + glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, w, h, 0, format, GL_UNSIGNED_BYTE, data ); + stbi_image_free( data ); + } + + glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); + + glBindTexture( GL_TEXTURE_CUBE_MAP, 0 ); + + initMesh(); + mInitialized = true; + return true; +} + +void Skybox::initMesh () { + + float skyboxVertices[] = { -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, + + -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, + + 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, + + -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, + + -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, + + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f }; + + glGenVertexArrays( 1, &mVAO ); + glGenBuffers( 1, &mVBO ); + glBindVertexArray( mVAO ); + glBindBuffer( GL_ARRAY_BUFFER, mVBO ); + glBufferData( GL_ARRAY_BUFFER, sizeof( skyboxVertices ), &skyboxVertices, GL_STATIC_DRAW ); + glEnableVertexAttribArray( 0 ); + glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof( float ), (void*)0 ); + glBindVertexArray( 0 ); +} + +void Skybox::draw ( const glm::mat4& view, const glm::mat4& proj ) { + if( !mInitialized ) + return; + + static Shader s; + static bool shaderLoaded = false; + if( !shaderLoaded ) { + s.fromFiles( "apps/openmb/resources/shaders/skybox.vert", "apps/openmb/resources/shaders/skybox.frag" ); + shaderLoaded = true; + } + + glDepthFunc( GL_LEQUAL ); + glDepthMask( GL_FALSE ); + + s.use(); + + glm::mat4 viewNoTrans = glm::mat4( glm::mat3( view ) ); + s.setMat4( "view", viewNoTrans ); + s.setMat4( "proj", proj ); + + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_CUBE_MAP, mTexID ); + s.setInt( "skybox", 0 ); + + glBindVertexArray( mVAO ); + glDrawArrays( GL_TRIANGLES, 0, 36 ); + glBindVertexArray( 0 ); + + glDepthMask( GL_TRUE ); + glDepthFunc( GL_LESS ); +} + +} // namespace renderer |