diff --git a/SQCSim2021/SQCSim2021.vcxproj b/SQCSim2021/SQCSim2021.vcxproj index 4530bf3..c79a090 100644 --- a/SQCSim2021/SQCSim2021.vcxproj +++ b/SQCSim2021/SQCSim2021.vcxproj @@ -32,6 +32,7 @@ + @@ -48,6 +49,7 @@ + diff --git a/SQCSim2021/SQCSim2021.vcxproj.filters b/SQCSim2021/SQCSim2021.vcxproj.filters index 88259e2..353069b 100644 --- a/SQCSim2021/SQCSim2021.vcxproj.filters +++ b/SQCSim2021/SQCSim2021.vcxproj.filters @@ -62,6 +62,9 @@ Fichiers d%27en-tête + + Fichiers d%27en-tête + @@ -103,5 +106,8 @@ Fichiers sources + + Fichiers sources + \ No newline at end of file diff --git a/SQCSim2021/audio.cpp b/SQCSim2021/audio.cpp index bf4db7b..d2c428c 100644 --- a/SQCSim2021/audio.cpp +++ b/SQCSim2021/audio.cpp @@ -1,7 +1,5 @@ #include "audio.h" -irrklang::vec3df Audio::convertVector(Vector3f& vec) const { return irrklang::vec3df(vec.x, vec.y, vec.z); }; - Audio::Audio() { m_engine = irrklang::createIrrKlangDevice(); m_engine->setDopplerEffectParameters(1); @@ -20,25 +18,25 @@ Audio::Audio(const char * music) { } Audio::~Audio() { - m_music->drop(); - m_engine->drop(); + if (m_music) m_music->drop(); + if (m_engine) m_engine->drop(); } -void Audio::Update3DAudio(Vector3f& pos, Vector3f& dir, Vector3f& speed) { - m_engine->setListenerPosition(convertVector(pos), - convertVector(dir), - convertVector(speed)); +void Audio::Update3DAudio(Vector3f pos, Vector3f dir, Vector3f vel) { + m_engine->setListenerPosition(irrklang::vec3df(pos.x, pos.y, pos.z), + irrklang::vec3df(dir.x, dir.y, dir.z), + irrklang::vec3df(vel.x, vel.y, vel.z)); } -void Audio::Create3DAudioObj(irrklang::ISound* sound, const char* name, Vector3f& pos, Vector3f& speed, float volume = 1) { - sound = m_engine->play3D(name, convertVector(pos), true, false, true, irrklang::ESM_NO_STREAMING, true); - sound->setVelocity(convertVector(speed)); +void Audio::Create3DAudioObj(irrklang::ISound* sound, const char* name, Vector3f& pos, Vector3f& vel, float volume = 1) { + sound = m_engine->play3D(name, irrklang::vec3df(pos.x, pos.y, pos.z), true, false, true, irrklang::ESM_NO_STREAMING, true); + sound->setVelocity(irrklang::vec3df(vel.x, vel.y, vel.z)); sound->setVolume(volume); } -void Audio::Render3DAudioObj(irrklang::ISound* sound, Vector3f& pos, Vector3f& speed, float volume = 1) { - sound->setPosition(convertVector(pos)); - sound->setVelocity(convertVector(speed)); +void Audio::Render3DAudioObj(irrklang::ISound* sound, Vector3f& pos, Vector3f& vel, float volume = 1) { + sound->setPosition(irrklang::vec3df(pos.x, pos.y, pos.z)); + sound->setVelocity(irrklang::vec3df(vel.x, vel.y, vel.z)); sound->setVolume(volume); } diff --git a/SQCSim2021/audio.h b/SQCSim2021/audio.h index 1ff240c..8eca96a 100644 --- a/SQCSim2021/audio.h +++ b/SQCSim2021/audio.h @@ -11,18 +11,16 @@ private: irrklang::ISoundEngine* m_engine; irrklang::ISound* m_music; - irrklang::vec3df convertVector(Vector3f& vec) const; - public: Audio(); Audio(const char* music); ~Audio(); - void Update3DAudio(Vector3f& pos, Vector3f& dir, Vector3f& speed); + void Update3DAudio(Vector3f pos, Vector3f dir, Vector3f speed); - void Create3DAudioObj(irrklang::ISound* sound, const char* name, Vector3f& pos, Vector3f& speed, float volume); + void Create3DAudioObj(irrklang::ISound* sound, const char* name, Vector3f& pos, Vector3f& vel, float volume); - void Render3DAudioObj(irrklang::ISound* sound, Vector3f& pos, Vector3f& speed, float volume); + void Render3DAudioObj(irrklang::ISound* sound, Vector3f& pos, Vector3f& vel, float volume); void ToggleMusicState(); diff --git a/SQCSim2021/blockinfo.h b/SQCSim2021/blockinfo.h index 3b6c880..37fcf40 100644 --- a/SQCSim2021/blockinfo.h +++ b/SQCSim2021/blockinfo.h @@ -15,6 +15,7 @@ class BlockInfo void SetDurability(int durability); int GetDurability() const; + void Show() const; private: diff --git a/SQCSim2021/engine.cpp b/SQCSim2021/engine.cpp index 9ee179a..7e68dd8 100644 --- a/SQCSim2021/engine.cpp +++ b/SQCSim2021/engine.cpp @@ -28,8 +28,6 @@ void Engine::Init() glEnable(GL_LIGHTING); glEnable(GL_LINE_SMOOTH); glEnable(GL_CULL_FACE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Light GLfloat light0Pos[4] = { 0.0f, CHUNK_SIZE_Y, 0.0f, 1.0f }; @@ -69,9 +67,17 @@ void Engine::LoadResource() { LoadTexture(m_textureFloor, TEXTURE_PATH "grass.png"); LoadTexture(m_skybox.GetTexture(), TEXTURE_PATH "skybox.png"); LoadTexture(m_textureCube1, TEXTURE_PATH "metal1.png"); - LoadTexture(m_textureCube2, TEXTURE_PATH "metal2.png"); - LoadTexture(m_textureCube3, TEXTURE_PATH "metal3.png"); - LoadTexture(m_textureCube4, TEXTURE_PATH "metal4.png"); + LoadTexture(m_textureCrosshair, TEXTURE_PATH "cross.bmp"); + LoadTexture(m_textureFont, TEXTURE_PATH "font.bmp"); + + TextureAtlas::TextureIndex texCheckerIndex = m_textureAtlas.AddTexture(TEXTURE_PATH "checker.png"); + TextureAtlas::TextureIndex texDirtIndex = m_textureAtlas.AddTexture(TEXTURE_PATH "dirt.png"); + + if (!m_textureAtlas.Generate(128, false)) + { + std::cout << " Unable to generate texture atlas ..." << std::endl; + abort(); + } std::cout << " Loading and compiling shaders ..." << std::endl; if (!m_shader01.Load(SHADER_PATH "shader01.vert", SHADER_PATH "shader01.frag", true)) { @@ -87,8 +93,82 @@ void Engine::LoadResource() { void Engine::UnloadResource(){} -void Engine::Render(float elapsedTime) -{ +void Engine::DrawHud(float elapsedTime) { + // Setter le blend function , tout ce qui sera noir sera transparent + glDisable(GL_LIGHTING); + glColor4f(1.f, 1.f, 1.f, 1.f); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + glEnable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, Width(), 0, Height(), -1, 1); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + // Bind de la texture pour le font + m_textureFont.Bind(); + std::ostringstream ss; + ss << " Fps : " << GetFps(elapsedTime); + PrintText(10, Height() - 25, ss.str()); + ss.str(""); + ss << " Velocity : " << m_player.GetVelocity(); // IMPORTANT : on utilise l ’ operateur << pour afficher la position + PrintText(10, 10, ss.str()); + ss.str(""); + ss << " Direction : " << m_player.GetDirection(); + PrintText(10, 20, ss.str()); + ss.str(""); + ss << " Position : " << m_player.GetPosition(); + PrintText(10, 30, ss.str()); + // Affichage du crosshair + m_textureCrosshair.Bind(); + static const int crossSize = 32; + glLoadIdentity(); + glTranslated(Width() / 2 - crossSize / 2, Height() / 2 - crossSize / 2, 0); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2i(0, 0); + glTexCoord2f(1, 0); + glVertex2i(crossSize, 0); + glTexCoord2f(1, 1); + glVertex2i(crossSize, crossSize); + glTexCoord2f(0, 1); + glVertex2i(0, crossSize); + glEnd(); + glEnable(GL_LIGHTING); + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + +void Engine::PrintText(unsigned int x, unsigned int y, const std::string& t) { + glLoadIdentity(); + glTranslated(x, y, 0); + for (unsigned int i = 0; i < t.length(); ++i) { + float left = (float)((t[i] - 32) % 16) / 16.f; + float top = (float)((t[i] - 32) / 16) / 16.f; + top += .5f; + glBegin(GL_QUADS); + glTexCoord2f(left, 1.f - top - .0625f); + glVertex2f(0, 0); + glTexCoord2f(left + .0625f, 1.f - top - .0625f); + glVertex2f(12, 0); + glTexCoord2f(left + .0625f, 1.f - top); + glVertex2f(12, 12); + glTexCoord2f(left, 1.f - top); + glVertex2f(0, 12); + glEnd(); + glTranslated(8, 0, 0); + } +} + +int Engine::GetFps(float elapsedTime) const { return 1 / elapsedTime; } + +void Engine::Render(float elapsedTime) { static float gameTime = elapsedTime; gameTime += elapsedTime; @@ -103,6 +183,8 @@ void Engine::Render(float elapsedTime) glLoadIdentity(); m_player.Move(m_keyW, m_keyS, m_keyA, m_keyD, m_keySpace, m_keylshift, elapsedTime); + m_audio.Update3DAudio(m_player.GetPosition(), m_player.GetDirection(), m_player.GetVelocity()); // Ajustement du positionnement 3D avec les coordonnées du joueur et + // son vecteur de vélocité (pour l'effet Doppler) m_player.ApplyTransformation(all); m_player.ApplyTransformation(skybox, false); // Version d'ApplyTransformation qui ne tient compte que de la rotation // (donc l'objet ne bouge pas relativement au joueur, ce qui est pratique pour une skybox!). @@ -129,22 +211,20 @@ void Engine::Render(float elapsedTime) glEnd(); // Chunk - switch ((int)(gameTime * 5) % 4) { - case 0: m_textureCube1.Bind(); - break; - case 1: m_textureCube2.Bind(); - break; - case 2: m_textureCube3.Bind(); - break; - case 3: m_textureCube4.Bind(); - break; - } + m_textureAtlas.Bind(); + if (m_testChunk.IsDirty()) m_testChunk.Update(); m_testChunk.Render(); m_shader01.Disable(); + if (m_wireframe) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + DrawHud(elapsedTime); + if (m_wireframe) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } void Engine::KeyPressEvent(unsigned char key) diff --git a/SQCSim2021/engine.h b/SQCSim2021/engine.h index 99ff609..587c8ba 100644 --- a/SQCSim2021/engine.h +++ b/SQCSim2021/engine.h @@ -4,11 +4,12 @@ #include "openglcontext.h" #include "texture.h" #include "transformation.h" -#include "shader.h"" +#include "shader.h" #include "player.h" #include "chunk.h" #include "skybox.h" #include "audio.h" +#include "textureatlas.h" class Engine : public OpenglContext { @@ -28,17 +29,20 @@ public: private: bool LoadTexture(Texture& texture, const std::string& filename, bool stopOnError = true); + void DrawHud(float elapsedTime); + void PrintText(unsigned int x, unsigned int y, const std::string& t); + int GetFps(float elapsedTime) const; private: bool m_wireframe = false; Texture m_textureFloor; Texture m_textureSkybox; + Texture m_textureFont; + Texture m_textureCrosshair; Texture m_textureCube1; - Texture m_textureCube2; - Texture m_textureCube3; - Texture m_textureCube4; + TextureAtlas m_textureAtlas = TextureAtlas(128); Skybox m_skybox; Shader m_shader01; Chunk m_testChunk; diff --git a/SQCSim2021/media/textures/cross.bmp b/SQCSim2021/media/textures/cross.bmp new file mode 100644 index 0000000..bb94369 Binary files /dev/null and b/SQCSim2021/media/textures/cross.bmp differ diff --git a/SQCSim2021/media/textures/dirt.png b/SQCSim2021/media/textures/dirt.png new file mode 100644 index 0000000..714d575 Binary files /dev/null and b/SQCSim2021/media/textures/dirt.png differ diff --git a/SQCSim2021/media/textures/font.bmp b/SQCSim2021/media/textures/font.bmp new file mode 100644 index 0000000..9c9b98a Binary files /dev/null and b/SQCSim2021/media/textures/font.bmp differ diff --git a/SQCSim2021/player.cpp b/SQCSim2021/player.cpp index 91db755..7c6d01b 100644 --- a/SQCSim2021/player.cpp +++ b/SQCSim2021/player.cpp @@ -1,6 +1,8 @@ #include "player.h" -Player::Player(const Vector3f& position, float rotX, float rotY) : m_position(position), m_rotX(rotX), m_rotY(rotY) { } +Player::Player(const Vector3f& position, float rotX, float rotY) : m_position(position), m_rotX(rotX), m_rotY(rotY) { + m_velocity = Vector3f(0, 0, 0); +} void Player::TurnLeftRight(float value) { m_rotY += value; @@ -79,28 +81,37 @@ void Player::Move(bool front, bool back, bool left, bool right, bool jump, bool } // Ajoute l'accélération de saut et le view bobbing. - m_position.y += accjmp + (sin(gametime) - 0.5f) * ((abs(accWS) + abs(accAD)) / 2.f) / (10.f * m_topspeed); + m_velocity.y = accjmp + (sin(gametime) - 0.5f) * ((abs(accWS) + abs(accAD)) / 2.f) / (10.f * m_topspeed); + m_position.y += m_velocity.y; + if (front) { if (dbljump == 0) if (accWS < m_topspeed) accWS += elapsedTime * 30; else accWS = m_topspeed; if (dash) accWS *= accWS > 0.f ? 3.f : -1.f; - m_position.x += float(sin(yrotrad)) * elapsedTime * accWS; - m_position.z += float(-cos(yrotrad)) * elapsedTime * accWS; + m_velocity.x = float(sin(yrotrad)) * elapsedTime * accWS; + m_position.x += m_velocity.x; + m_velocity.z = float(-cos(yrotrad)) * elapsedTime * accWS; + m_position.z += m_velocity.z; + } else if (back) { if (dbljump == 0) if (accWS > -m_topspeed) accWS -= elapsedTime * 30; else accWS = -m_topspeed; if (dash) accWS *= accWS < 0.f? 3.f: -1.f; - m_position.x += float(-sin(yrotrad)) * elapsedTime * -accWS; - m_position.z += float(cos(yrotrad)) * elapsedTime * -accWS; + m_velocity.x = float(-sin(yrotrad)) * elapsedTime * -accWS; + m_position.x += m_velocity.x; + m_velocity.z = float(cos(yrotrad)) * elapsedTime * -accWS; + m_position.z += m_velocity.z; } else if (accWS != 0) { accWS = accWS > 0 ? accWS - elapsedTime * (m_position.y > 0.1f ? 10 : 120) : accWS + elapsedTime * (m_position.y > 0.1f ? 10 : 120); - m_position.x += float(sin(yrotrad)) * elapsedTime * accWS; - m_position.z += float(-cos(yrotrad)) * elapsedTime * accWS; + m_velocity.x = float(sin(yrotrad)) * elapsedTime * accWS; + m_position.x += m_velocity.x; + m_velocity.z = float(-cos(yrotrad)) * elapsedTime * accWS; + m_position.z += m_velocity.z; if (accWS < 1 && accWS > -1) accWS = 0; } @@ -108,27 +119,35 @@ void Player::Move(bool front, bool back, bool left, bool right, bool jump, bool if (dbljump == 0) if (accAD < m_topspeed) accAD += elapsedTime * 30; else accAD = m_topspeed; if (dash) accAD *= accAD > 0.f? 3.f: -1.f; - m_position.x += float(-cos(yrotrad)) * elapsedTime * accAD; - m_position.z += float(-sin(yrotrad)) * elapsedTime * accAD; + m_velocity.x = float(-cos(yrotrad)) * elapsedTime * accAD; + m_position.x += m_velocity.x; + m_velocity.z = float(-sin(yrotrad)) * elapsedTime * accAD; + m_position.z += m_velocity.z; } else if (right) { if (dbljump == 0) if (accAD > -m_topspeed) accAD -= elapsedTime * 30; else accAD = -m_topspeed; if (dash) accAD *= accAD < 0.f ? 3.f : -1.f; - m_position.x += float(cos(yrotrad)) * elapsedTime * -accAD; - m_position.z += float(sin(yrotrad)) * elapsedTime * -accAD; + m_velocity.x = float(cos(yrotrad)) * elapsedTime * -accAD; + m_position.x += m_velocity.x; + m_velocity.z = float(sin(yrotrad)) * elapsedTime * -accAD; + m_position.z += m_velocity.z; } else if (accAD != 0) { accAD = accAD > 0 ? accAD - elapsedTime * (m_position.y > 0.1f ? 10 : 120) : accAD + elapsedTime * (m_position.y > 0.1f ? 10 : 120); - m_position.x += float(-cos(yrotrad)) * elapsedTime * accAD; - m_position.z += float(-sin(yrotrad)) * elapsedTime * accAD; - if (accAD < 1 && accAD > -1) accAD = 0; + m_velocity.x = float(-cos(yrotrad)) * elapsedTime * accAD; + m_position.x += m_velocity.x; + m_velocity.z = float(-sin(yrotrad)) * elapsedTime * accAD; + m_position.z += m_velocity.z; + if (accAD < 1.f && accAD > -1.f) accAD = 0; } + + // Gestion de si le personnage va en diagonale, qu'il n'aille pas plus vite que s'il allait en ligne droite. - if ((accWS >= 0.f ? accWS : -accWS + accAD >= 0.f ? accAD : -accAD) > sqrtf(m_topspeed * m_topspeed + m_topspeed * m_topspeed)) { + if ((accWS >= 0.f ? accWS : -accWS + accAD >= 0.f ? accAD : -accAD) > sqrtf(exp2f(m_topspeed) * 2)) { accWS *= 0.8f; accAD *= 0.8f; } @@ -142,6 +161,8 @@ void Player::ApplyTransformation(Transformation& transformation, bool rel) const Vector3f Player::GetPosition() const { return m_position; } -Vector3f Player::GetDirection(bool velocity = false) const { - return Vector3f(); // Temporaire. -} +Vector3f Player::GetVelocity() const { return m_velocity; } + +Vector3f Player::GetDirection() const { return Vector3f(cos(m_rotY / 57.2957795056f) * cos(m_rotX / 57.2957795056f), + -sin(m_rotX / 57.2957795056f) , + sin(m_rotY / 57.2957795056f) * cos(m_rotX / 57.2957795056f)); } diff --git a/SQCSim2021/player.h b/SQCSim2021/player.h index 8891ec3..249cf2c 100644 --- a/SQCSim2021/player.h +++ b/SQCSim2021/player.h @@ -13,10 +13,12 @@ public: void ApplyTransformation(Transformation& transformation, bool rel = true) const; Vector3f GetPosition() const; - Vector3f GetDirection(bool velocity) const; + Vector3f GetDirection() const; + Vector3f GetVelocity() const; private: Vector3f m_position; + Vector3f m_velocity; float m_rotX = 0; float m_rotY = 0; float m_topspeed = 40; diff --git a/SQCSim2021/textureatlas.cpp b/SQCSim2021/textureatlas.cpp new file mode 100644 index 0000000..d293c84 --- /dev/null +++ b/SQCSim2021/textureatlas.cpp @@ -0,0 +1,193 @@ +#include "textureatlas.h" +#include + +// TODO +#include +#include +#include +#include "tool.h" + + +TextureAtlas::TextureAtlas(unsigned int nbTexture) : m_isValid(false), m_currentTextureIndex(0) +{ + if(nbTexture < 4) + nbTexture = 4; + + // Arrondir sur la puissance de 2 superieure + m_nbTexturePerSide = (int)sqrt((float)nbTexture); + if(m_nbTexturePerSide * m_nbTexturePerSide < nbTexture) + m_nbTexturePerSide++; + while(!IsPowerOfTwo(m_nbTexturePerSide)) + m_nbTexturePerSide++; +} + +TextureAtlas::~TextureAtlas() +{ + if(IsValid()) + glDeleteTextures(1, &m_textureId); +} + + +TextureAtlas::TextureIndex TextureAtlas::AddTexture(const std::string& fname) { + TextureList::iterator it = m_textureList.find(fname); + + if(it != m_textureList.end()) + return it->second.texIdx; + + TextureIndex id = m_currentTextureIndex++; + m_textureList.insert(std::make_pair(fname, TextureInfo((ILuint)-1, id))); + return id; +} + +bool TextureAtlas::Generate(int textureSize, bool mipmap) { + // TODO mipmap pas encore 100% parfait... + assert(!mipmap); + + if(!IsPowerOfTwo(textureSize)) + return false; + + // Initialize Devil only once: + static bool alreadyInitialized = false; + if(!alreadyInitialized) + { + ilInit(); + iluInit(); + alreadyInitialized = true; + } + + for(TextureList::iterator it = m_textureList.begin(); it != m_textureList.end(); ++it) + { + ILuint texid = it->second.texId; + if(texid == (ILuint)-1) + { + std::cout << "Loading " << it->first << " (id=" << it->second.texIdx << ")..." << std::endl; + ilGenImages(1, &texid); + ilBindImage(texid); + + ilOriginFunc(IL_ORIGIN_LOWER_LEFT); + ilEnable(IL_ORIGIN_SET); + + if (!ilLoadImage((const ILstring)it->first.c_str())) + return false; + + if (!ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE)) + return false; + + iluScale(textureSize, textureSize, 1); + + it->second.texId = texid; + } + } + + + //std::cout << ilGetInteger(IL_IMAGE_BPP) << std::endl; + //std::cout << ilGetInteger(IL_IMAGE_FORMAT) << std::endl; + //std::cout << ilGetInteger(IL_IMAGE_DEPTH) << std::endl; + //std::cout << ilGetInteger(IL_IMAGE_TYPE) << std::endl; + //std::cout << ilGetInteger(IL_IMAGE_WIDTH) << std::endl; + //std::cout << ilGetInteger(IL_IMAGE_HEIGHT) << std::endl; + + + + glGenTextures(1, &m_textureId); + glBindTexture(GL_TEXTURE_2D, m_textureId); + if(mipmap) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + int level = textureSize; + int oglLevel = 0; + int mipmapSize = textureSize * m_nbTexturePerSide; + while(mipmapSize != 0) + { + ILuint atlasTex; + ilGenImages(1, &atlasTex); + ilBindImage(atlasTex); + ilTexImage(mipmapSize, mipmapSize, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, 0); + ilClearColour(1, 0, 0, 1); + ilClearImage(); + + for(TextureList::iterator it = m_textureList.begin(); it != m_textureList.end(); ++it) + { + ILuint tmpImg; + ilGenImages(1, &tmpImg); + ilBindImage(tmpImg); + ilCopyImage(it->second.texId); + + iluImageParameter(ILU_FILTER, ILU_NEAREST); + //iluImageParameter(ILU_FILTER, ILU_BILINEAR); + if(level != textureSize) + iluScale(level, level, 1); + + char* data = new char[level * level * 4]; + ilCopyPixels(0, 0, 0, level, level, 1, IL_RGBA, IL_UNSIGNED_BYTE, data); + + + int imgIdx = it->second.texIdx; + int x = imgIdx % m_nbTexturePerSide; + int y = m_nbTexturePerSide - 1 - imgIdx / m_nbTexturePerSide; + ilBindImage(atlasTex); + ilSetPixels(x * level, y * level, 0, level, level, 1, IL_RGBA, IL_UNSIGNED_BYTE, data); + //ilOverlayImage(tmpImg, x * level, y * level, 0); + + delete [] data; + ilDeleteImages(1, &tmpImg); + } + + // TODO + //if(level == textureSize) + //{ + //ilEnable(IL_FILE_OVERWRITE); + //ilSaveImage("textureatlas.png"); + //} + + //std::cout << oglLevel << ":" << level << ":" << mipmapSize << std::endl; + glTexImage2D(GL_TEXTURE_2D, oglLevel++, GL_RGBA, ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT), 0, GL_RGBA, GL_UNSIGNED_BYTE, ilGetData()); + + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + //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_WRAP_R, GL_CLAMP); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + CHECK_GL_ERROR(); + + + ilDeleteImages(1, &atlasTex); + + if(!mipmap) + break; + + level /= 2; + mipmapSize /= 2; + } + + m_isValid = true; + return true; +} + + +bool TextureAtlas::IsValid() const { return m_isValid; } + +void TextureAtlas::Bind() const +{ + assert(IsValid()); + glBindTexture(GL_TEXTURE_2D, m_textureId); +} + +void TextureAtlas::TextureIndexToCoord(TextureIndex idx, float& u, float& v, float& w, float& h) const +{ + w = 1.f / (float)m_nbTexturePerSide; + h = 1.f / (float)m_nbTexturePerSide; + + u = (float)((unsigned int)idx % m_nbTexturePerSide) * w; + v = (float)(m_nbTexturePerSide - 1 - (unsigned int)idx / m_nbTexturePerSide) * h; +} diff --git a/SQCSim2021/textureatlas.h b/SQCSim2021/textureatlas.h new file mode 100644 index 0000000..1d717e1 --- /dev/null +++ b/SQCSim2021/textureatlas.h @@ -0,0 +1,45 @@ +#ifndef TEXTUREATLAS_H__ +#define TEXTUREATLAS_H__ +#include "define.h" +#include +#include +#include + +class TextureAtlas +{ +public: + typedef unsigned int TextureIndex; + +public: + TextureAtlas(unsigned int nbTexture); + ~TextureAtlas(); + TextureIndex AddTexture(const std::string& fname); + bool Generate(int textureSize, bool mipmap); + + bool IsValid() const; + void Bind() const; + + void TextureIndexToCoord(TextureIndex idx, float& u, float& v, float& w, float& h) const; + +private: + bool IsPowerOfTwo(unsigned int x) { return ((x != 0) && ((x & (~x + 1)) == x)); } + +private: + struct TextureInfo { + ILuint texId; + TextureIndex texIdx; + + TextureInfo(ILuint _texId, unsigned int _texIdx) : texId(_texId), texIdx(_texIdx) {} + }; + // On utilise un std::map pour avoir des valeurs uniques + typedef std::map TextureList; + TextureList m_textureList; + + TextureIndex m_currentTextureIndex; + GLuint m_textureId; + bool m_isValid; + unsigned int m_nbTexturePerSide; + +}; + +#endif // TEXTUREATLAS_H__