GUI
This commit is contained in:
parent
fbf2e8858e
commit
c3c432c369
@ -32,6 +32,7 @@
|
||||
<ClInclude Include="shader.h" />
|
||||
<ClInclude Include="skybox.h" />
|
||||
<ClInclude Include="texture.h" />
|
||||
<ClInclude Include="textureatlas.h" />
|
||||
<ClInclude Include="tool.h" />
|
||||
<ClInclude Include="transformation.h" />
|
||||
<ClInclude Include="vector3.h" />
|
||||
@ -48,6 +49,7 @@
|
||||
<ClCompile Include="shader.cpp" />
|
||||
<ClCompile Include="skybox.cpp" />
|
||||
<ClCompile Include="texture.cpp" />
|
||||
<ClCompile Include="textureatlas.cpp" />
|
||||
<ClCompile Include="tool.cpp" />
|
||||
<ClCompile Include="transformation.cpp" />
|
||||
<ClCompile Include="vertexbuffer.cpp" />
|
||||
|
@ -62,6 +62,9 @@
|
||||
<ClInclude Include="audio.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="textureatlas.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="blockinfo.cpp">
|
||||
@ -103,5 +106,8 @@
|
||||
<ClCompile Include="audio.cpp">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="textureatlas.cpp">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -15,6 +15,7 @@ class BlockInfo
|
||||
void SetDurability(int durability);
|
||||
int GetDurability() const;
|
||||
|
||||
|
||||
void Show() const;
|
||||
|
||||
private:
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
BIN
SQCSim2021/media/textures/cross.bmp
Normal file
BIN
SQCSim2021/media/textures/cross.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
SQCSim2021/media/textures/dirt.png
Normal file
BIN
SQCSim2021/media/textures/dirt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 684 KiB |
BIN
SQCSim2021/media/textures/font.bmp
Normal file
BIN
SQCSim2021/media/textures/font.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 192 KiB |
@ -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)); }
|
||||
|
@ -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;
|
||||
|
193
SQCSim2021/textureatlas.cpp
Normal file
193
SQCSim2021/textureatlas.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
#include "textureatlas.h"
|
||||
#include <cmath>
|
||||
|
||||
// TODO
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
#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;
|
||||
}
|
45
SQCSim2021/textureatlas.h
Normal file
45
SQCSim2021/textureatlas.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef TEXTUREATLAS_H__
|
||||
#define TEXTUREATLAS_H__
|
||||
#include "define.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <IL/ilu.h>
|
||||
|
||||
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<std::string, TextureInfo> TextureList;
|
||||
TextureList m_textureList;
|
||||
|
||||
TextureIndex m_currentTextureIndex;
|
||||
GLuint m_textureId;
|
||||
bool m_isValid;
|
||||
unsigned int m_nbTexturePerSide;
|
||||
|
||||
};
|
||||
|
||||
#endif // TEXTUREATLAS_H__
|
Loading…
Reference in New Issue
Block a user