#include "Skybox.hpp" #include "Shader.hpp" #include #include #include #include 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 faceTokens = { "right", "left", "top", "bottom", "front", "back" }; std::vector 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& 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