fixed plenty of bugs, added sponza, added jumping

This commit is contained in:
Anselme 2016-12-19 15:11:50 +01:00
parent b81630c28c
commit 9cfc6d581a
10 changed files with 138 additions and 34 deletions

View File

@ -6,7 +6,7 @@
class DefaultKeysMap : public IKeysMap class DefaultKeysMap : public IKeysMap
{ {
public: public:
enum{MAIN_ACTION, SECONDARY_ACTION, TERTIARY_ACTION, MOVE_FORWARD, MOVE_BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, enum{MAIN_ACTION, SECONDARY_ACTION, TERTIARY_ACTION, MOVE_FORWARD, MOVE_BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, JUMP,
TOGGLE_NOCLIP, TOGGLE_PHYSICS_DEBUG, TOGGLE_CONSOLE, TOGGLE_NOCLIP, TOGGLE_PHYSICS_DEBUG, TOGGLE_CONSOLE,
MOVE_CURSOR_LEFT, MOVE_CURSOR_RIGHT, PLOP_TEST, CLEAR_CONSOLE, MOVE_CURSOR_LEFT, MOVE_CURSOR_RIGHT, PLOP_TEST, CLEAR_CONSOLE,
EXIT_GAME,LAST_DEFAULT_ACTION}; EXIT_GAME,LAST_DEFAULT_ACTION};
@ -19,6 +19,7 @@ public:
keys.push_back( {MOVE_BACKWARD, sf::Keyboard::S, IKeysMap::HOLD} ); keys.push_back( {MOVE_BACKWARD, sf::Keyboard::S, IKeysMap::HOLD} );
keys.push_back( {STRAFE_LEFT, sf::Keyboard::Q, IKeysMap::HOLD} ); keys.push_back( {STRAFE_LEFT, sf::Keyboard::Q, IKeysMap::HOLD} );
keys.push_back( {STRAFE_RIGHT, sf::Keyboard::D, IKeysMap::HOLD} ); keys.push_back( {STRAFE_RIGHT, sf::Keyboard::D, IKeysMap::HOLD} );
keys.push_back( {JUMP, sf::Keyboard::Space, IKeysMap::PRESSED} );
keys.push_back( {TOGGLE_NOCLIP, sf::Keyboard::G, IKeysMap::PRESSED} ); keys.push_back( {TOGGLE_NOCLIP, sf::Keyboard::G, IKeysMap::PRESSED} );
keys.push_back( {TOGGLE_PHYSICS_DEBUG, sf::Keyboard::P, IKeysMap::PRESSED} ); keys.push_back( {TOGGLE_PHYSICS_DEBUG, sf::Keyboard::P, IKeysMap::PRESSED} );
keys.push_back( {TOGGLE_CONSOLE, sf::Keyboard::F3, IKeysMap::PRESSED} ); keys.push_back( {TOGGLE_CONSOLE, sf::Keyboard::F3, IKeysMap::PRESSED} );
@ -31,7 +32,7 @@ public:
static std::vector<int> getDefaultContext() static std::vector<int> getDefaultContext()
{ {
return {MAIN_ACTION, SECONDARY_ACTION, TERTIARY_ACTION, MOVE_FORWARD, MOVE_BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, TOGGLE_NOCLIP, TOGGLE_PHYSICS_DEBUG, TOGGLE_CONSOLE, EXIT_GAME}; return {MAIN_ACTION, SECONDARY_ACTION, TERTIARY_ACTION, MOVE_FORWARD, MOVE_BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, JUMP, TOGGLE_NOCLIP, TOGGLE_PHYSICS_DEBUG, TOGGLE_CONSOLE, EXIT_GAME};
} }
static std::vector<int> getShellContext() static std::vector<int> getShellContext()

View File

@ -19,7 +19,9 @@ Engine::Engine() :
m_physicsDebugNode(nullptr), m_physicsDebugNode(nullptr),
m_togglePhysicsDebugAction(NO_ACTION), m_togglePhysicsDebugAction(NO_ACTION),
m_toggleShellAction(NO_ACTION), m_toggleShellAction(NO_ACTION),
m_exitGameAction(NO_ACTION) m_exitGameAction(NO_ACTION),
m_showMouseAction(NO_ACTION),
m_mouseVisible(true)
{ {
m_clock = new sf::Clock(); m_clock = new sf::Clock();
m_clock->restart(); m_clock->restart();
@ -47,7 +49,7 @@ void Engine::createWindow(std::string title,
{ {
m_window = new sf::Window(sf::VideoMode(w, h), m_window = new sf::Window(sf::VideoMode(w, h),
title, title,
isWindowed ? sf::Style::Close : sf::Style::Fullscreen, isWindowed ? sf::Style::Close : sf::Style::None,
sf::ContextSettings(24, 8, 0, 3, 3, sf::ContextSettings::Attribute::Core)); sf::ContextSettings(24, 8, 0, 3, 3, sf::ContextSettings::Attribute::Core));
m_window->setFramerateLimit(60); m_window->setFramerateLimit(60);
m_input = new Input(m_window); m_input = new Input(m_window);
@ -158,6 +160,12 @@ void Engine::disablePhysicsDebug()
} }
} }
void Engine::toggleMouseVisibility()
{
m_mouseVisible = !m_mouseVisible;
m_window->setMouseCursorVisible(m_mouseVisible);
}
void Engine::setTogglePhysicsDebugAction(int action) void Engine::setTogglePhysicsDebugAction(int action)
{ {
m_togglePhysicsDebugAction = action; m_togglePhysicsDebugAction = action;
@ -173,6 +181,11 @@ void Engine::setExitGameAction(int action)
m_exitGameAction = action; m_exitGameAction = action;
} }
void Engine::setShowMouseAction(int action)
{
m_showMouseAction = action;
}
void Engine::outputShell(std::string str) const void Engine::outputShell(std::string str) const
{ {
m_sparrowshell->out(str); m_sparrowshell->out(str);
@ -190,13 +203,11 @@ void Engine::checkSpecialInputs()
disablePhysicsDebug(); disablePhysicsDebug();
} }
else if(action == m_toggleShellAction) else if(action == m_toggleShellAction)
{
m_sparrowshell->toggleShell(); m_sparrowshell->toggleShell();
}
else if(action == m_exitGameAction) else if(action == m_exitGameAction)
{
m_running = false; m_running = false;
} else if(action == m_showMouseAction)
toggleMouseVisibility();
} }
} }

View File

@ -32,10 +32,13 @@ public:
void enablePhysicsDebug(); void enablePhysicsDebug();
void disablePhysicsDebug(); void disablePhysicsDebug();
void toggleMouseVisibility();
// special inputs // special inputs
void setTogglePhysicsDebugAction(int action); void setTogglePhysicsDebugAction(int action);
void setToggleShellAction(int action); void setToggleShellAction(int action);
void setExitGameAction(int action); void setExitGameAction(int action);
void setShowMouseAction(int action);
void start(); void start();
void stop(); void stop();
@ -73,6 +76,8 @@ private:
int m_togglePhysicsDebugAction; int m_togglePhysicsDebugAction;
int m_toggleShellAction; int m_toggleShellAction;
int m_exitGameAction; int m_exitGameAction;
int m_showMouseAction;
bool m_mouseVisible;
void checkSpecialInputs(); void checkSpecialInputs();
}; };

View File

@ -15,6 +15,8 @@ void LightNode::update()
{ {
DirectionnalLight *l = (DirectionnalLight*)m_light; DirectionnalLight *l = (DirectionnalLight*)m_light;
l->setDir(glm::mat3(combinedTransform) * l->getDir()); l->setDir(glm::mat3(combinedTransform) * l->getDir());
if(l->isShadowCaster())
l->updateShadowMap(m_scene);
} }
break; break;

View File

@ -2,6 +2,7 @@
#include <btBulletCollisionCommon.h> #include <btBulletCollisionCommon.h>
#include <btBulletDynamicsCommon.h> #include <btBulletDynamicsCommon.h>
#include <BulletDynamics/Character/btKinematicCharacterController.h>
#include <glm/ext.hpp> #include <glm/ext.hpp>
@ -51,10 +52,12 @@ void FirstPersonCamera::setUpVector(const glm::vec3 &up)
computeView(); computeView();
} }
const float WALK_SPEED = 12.f; const float WALK_SPEED = 8.f;
const float PLAYER_RADIUS = 0.30f; const float PLAYER_RADIUS = 0.30f;
const float PLAYER_HEIGHT = 1.75f; const float PLAYER_HEIGHT = 1.75f;
const float EYES_OFFSET = 0.775f; const float EYES_OFFSET = 0.775f;
const float JUMP_VELOCITY = 5.f;
const float EPSILON = 1.f;
PlayerCharacterNode::PlayerCharacterNode(bool noClip) : PlayerCharacterNode::PlayerCharacterNode(bool noClip) :
m_noclipMode(noClip), m_noclipMode(noClip),
@ -75,18 +78,19 @@ PlayerCharacterNode::PlayerCharacterNode(bool noClip) :
m_rigidBody->setAngularFactor(0.0); m_rigidBody->setAngularFactor(0.0);
} }
void PlayerCharacterNode::setInputs(int forward, int backward, int strafeLeft, int strafeRight, int toggleNoClip) void PlayerCharacterNode::setInputs(int forward, int backward, int strafeLeft, int strafeRight, int jump, int toggleNoClip)
{ {
m_inputActions[FORWARD] = forward; m_inputActions[FORWARD] = forward;
m_inputActions[BACKWARD] = backward; m_inputActions[BACKWARD] = backward;
m_inputActions[STRAFE_LEFT] = strafeLeft; m_inputActions[STRAFE_LEFT] = strafeLeft;
m_inputActions[STRAFE_RIGHT] = strafeRight; m_inputActions[STRAFE_RIGHT] = strafeRight;
m_inputActions[JUMP] = jump;
m_inputActions[TOGGLE_NOCLIP] = toggleNoClip; m_inputActions[TOGGLE_NOCLIP] = toggleNoClip;
} }
void PlayerCharacterNode::setPosition(float x, float y, float z) void PlayerCharacterNode::setPosition(float x, float y, float z)
{ {
btTransform transform; btTransform transform = btTransform::getIdentity();
btVector3 pos(x, y, z); btVector3 pos(x, y, z);
transform.setOrigin(pos); transform.setOrigin(pos);
m_rigidBody->setWorldTransform(transform); m_rigidBody->setWorldTransform(transform);
@ -100,6 +104,7 @@ void PlayerCharacterNode::update()
// get events // get events
int walk = 0; int walk = 0;
int strafe = 0; int strafe = 0;
bool jump = false;
for(int action : input->getActions()) for(int action : input->getActions())
{ {
if(action == m_inputActions[FORWARD]) if(action == m_inputActions[FORWARD])
@ -110,6 +115,8 @@ void PlayerCharacterNode::update()
--strafe; --strafe;
else if(action == m_inputActions[STRAFE_RIGHT]) else if(action == m_inputActions[STRAFE_RIGHT])
++strafe; ++strafe;
else if(action == m_inputActions[JUMP])
jump = true;
else if(action == m_inputActions[TOGGLE_NOCLIP]) else if(action == m_inputActions[TOGGLE_NOCLIP])
toggleNoClip(); toggleNoClip();
} }
@ -124,6 +131,8 @@ void PlayerCharacterNode::update()
// update body movement // update body movement
const glm::vec3 &glmDir = m_fpsCamera.getDirection(); const glm::vec3 &glmDir = m_fpsCamera.getDirection();
const btVector3 &velocity = m_rigidBody->getLinearVelocity();
btVector3 targetVelocity(0.f, velocity.getY(), 0.f);
if(walk != 0 || strafe != 0) if(walk != 0 || strafe != 0)
{ {
glm::vec3 moveDir = glm::normalize(glmDir*walk + glm::cross(glmDir, glm::vec3(0, 1, 0))*strafe); glm::vec3 moveDir = glm::normalize(glmDir*walk + glm::cross(glmDir, glm::vec3(0, 1, 0))*strafe);
@ -134,19 +143,42 @@ void PlayerCharacterNode::update()
} }
else else
{ {
//TODO: if on ground + space pressed -> jump
glm::vec2 hPos = glm::normalize(glm::vec2(moveDir.x, moveDir.z))*WALK_SPEED; glm::vec2 hPos = glm::normalize(glm::vec2(moveDir.x, moveDir.z))*WALK_SPEED;
const btVector3 &velocity = m_rigidBody->getLinearVelocity(); targetVelocity.setX(hPos.x);
m_rigidBody->setLinearVelocity((velocity + btVector3(hPos.x, velocity.getY(), hPos.y)) / 2.f); // smooth movements targetVelocity.setZ(hPos.y);
} }
} }
// apply movements
if(m_noclipMode) if(m_noclipMode)
{ {
btTransform transform; btTransform transform = btTransform::getIdentity();
transform.setOrigin(m_noclip_pos); transform.setOrigin(m_noclip_pos);
m_rigidBody->setWorldTransform(transform); m_rigidBody->setWorldTransform(transform);
m_rigidBody->setLinearVelocity(btVector3(0, 0, 0)); m_rigidBody->setLinearVelocity(btVector3(0, 0, 0));
} }
else
{
float controlRatio = 0.2f; // 1 = total control, 0 = no control, can be seen as a slipperiness factor
btVector3 newVelocity = velocity*(1.f-controlRatio) + targetVelocity*controlRatio;
if(jump)
{/*
btVector3 start(pos);
start.setY(start.y() - PLAYER_HEIGHT/2.f);
btVector3 end(pos);
end.setY(end.y() - EPSILON);
btCollisionWorld::ClosestRayResultCallback RayCallback(start, end);
getEngine().getPhysics()->rayTest(start, end, RayCallback);
if(RayCallback.hasHit()) // if ground is nearby
{
//btVector3 normal = RayCallback.m_hitNormalWorld;
}*/
// raycasting not working yet
newVelocity.setY(JUMP_VELOCITY);
}
m_rigidBody->setLinearVelocity(newVelocity);
}
} }
void PlayerCharacterNode::toggleNoClip() void PlayerCharacterNode::toggleNoClip()

View File

@ -41,12 +41,12 @@ class PlayerCharacterNode : public CameraNode
std::vector<int> m_inputActions; std::vector<int> m_inputActions;
enum PlayerAction {FORWARD, BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, TOGGLE_NOCLIP}; enum PlayerAction {FORWARD, BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, JUMP, TOGGLE_NOCLIP};
public: public:
PlayerCharacterNode(bool noClip = true); PlayerCharacterNode(bool noClip = true);
void setInputs(int forward, int backward, int strafe_left, int strafe_right, int toggleNoClip = NO_ACTION); void setInputs(int forward, int backward, int strafe_left, int strafe_right, int jump = NO_ACTION, int toggleNoClip = NO_ACTION);
void setPosition(float x, float y, float z); void setPosition(float x, float y, float z);

View File

@ -81,9 +81,9 @@ void generateTerrain(SceneTree *scene, btDiscreteDynamicsWorld *world)
mat->specular = glm::vec3(0.1f); mat->specular = glm::vec3(0.1f);
mat->emission = glm::vec3(0.5f, 0.1f, 0.1f); mat->emission = glm::vec3(0.5f, 0.1f, 0.1f);
for(int x=-6; x<6; ++x) for(int x=-3; x<3; ++x)
for(int y=-3; y<3; ++y) for(int y=-2; y<2; ++y)
for(int z=-6; z<6; ++z) for(int z=-3; z<3; ++z)
{ {
Chunk *chunk = new Chunk(&gen); // ! WARNING ! : chunk pointer is lost and never deleted Chunk *chunk = new Chunk(&gen); // ! WARNING ! : chunk pointer is lost and never deleted
glm::vec3 pos(x, y, z); glm::vec3 pos(x, y, z);
@ -102,29 +102,59 @@ void generateTerrain(SceneTree *scene, btDiscreteDynamicsWorld *world)
} }
} }
void generateSponza(SceneTree *scene, btDiscreteDynamicsWorld *world)
{
GraphicalContainerNode* sponzaContainer = new GraphicalContainerNode();
scene->getRootObject()->addChild(sponzaContainer);
Loader::setTexDirectory("../data/sponza/");
std::vector<Mesh*> meshes = Loader::loadMesh("sponza.obj");
Loader::setTexDirectory("../data/");
for(Mesh* m : meshes)
{
if(m->getName().find("fabric") != std::string::npos)
delete m; // moyen crade de se débarasser temporairement des rideaux
else
{
m->initGL();
MeshNode *node = new MeshNode(m);
node->setTransform(glm::scale(glm::mat4(), glm::vec3(0.01f)));
sponzaContainer->addChild(node);
world->addRigidBody(node->buildStaticCollider());
}
}
}
int main(int argc, char** argv){ int main(int argc, char** argv){
enum Mode { SIMPLEST_TEST, TERRAIN_TEST, FULLSCREEN_DEMO }; enum Mode { SIMPLEST_TEST, TERRAIN_TEST, SPONZA_TEST, FULLSCREEN_DEMO };
Mode mode = SIMPLEST_TEST; Mode mode = SIMPLEST_TEST;
if(argc > 1) if(argc > 1)
{ {
std::string modeStr(argv[1]); std::string modeStr(argv[1]);
if(modeStr == "terrain") if(modeStr == "terrain")
mode = TERRAIN_TEST; mode = TERRAIN_TEST;
else if(modeStr == "sponza")
mode = SPONZA_TEST;
else if(modeStr == "demo") else if(modeStr == "demo")
mode = FULLSCREEN_DEMO; mode = FULLSCREEN_DEMO;
else if(modeStr == "simple") else if(modeStr == "simple")
mode = SIMPLEST_TEST; mode = SIMPLEST_TEST;
else else
std::cout << "AVAILABLE MODES : simple(default) / terrain / demo" << std::endl; std::cout << "AVAILABLE MODES : simple(default) / terrain / sponza / demo" << std::endl;
} }
Engine engine; Engine engine;
Loader::setObjDirectory("../data/");
Loader::setMtlDirectory("../data/");
Loader::setTexDirectory("../data/");
// this creates the opengl context // this creates the opengl context
// the opengl context must exist before any opengl class is used (texture, pipeline, etc..) // the opengl context must exist before any opengl class is used (texture, pipeline, etc..)
if(mode == FULLSCREEN_DEMO) if(mode == FULLSCREEN_DEMO && mode == SPONZA_TEST)
engine.createWindow("Sparrow Engine Testing Environment", 1920, 1080, false); {
engine.createWindow("Sparrow Engine Testing Environment", 1920, 1080, true);
engine.toggleMouseVisibility();
}
else else
engine.createWindow("Sparrow Engine Testing Environment"); engine.createWindow("Sparrow Engine Testing Environment");
@ -161,10 +191,9 @@ int main(int argc, char** argv){
*/ */
// first person player controller // first person player controller
PlayerCharacterNode *player = new PlayerCharacterNode(false); PlayerCharacterNode *player = new PlayerCharacterNode(false);
player->setInputs(DefaultKeysMap::MOVE_FORWARD, DefaultKeysMap::MOVE_BACKWARD, DefaultKeysMap::STRAFE_LEFT, DefaultKeysMap::STRAFE_RIGHT, DefaultKeysMap::TOGGLE_NOCLIP); player->setInputs(DefaultKeysMap::MOVE_FORWARD, DefaultKeysMap::MOVE_BACKWARD, DefaultKeysMap::STRAFE_LEFT, DefaultKeysMap::STRAFE_RIGHT, DefaultKeysMap::JUMP, DefaultKeysMap::TOGGLE_NOCLIP);
scene->getRootObject()->addChild(player); scene->getRootObject()->addChild(player);
scene->setMainCamera(player); scene->setMainCamera(player);
player->setPosition(0.f, 15.f, 0.f);
engine.getPhysics()->addRigidBody(player->getRigidbody()); engine.getPhysics()->addRigidBody(player->getRigidbody());
// throw cubes and spheres with mouse clicks // throw cubes and spheres with mouse clicks
@ -172,14 +201,34 @@ int main(int argc, char** argv){
scene->getRootObject()->addChild(potator); scene->getRootObject()->addChild(potator);
// lighting // lighting
LightNode *sunLight = new LightNode(new DirectionnalLight(glm::vec3(5, 8, -2), glm::vec3(1.f)));
LightNode *ambientLight = new LightNode(new AmbientLight()); LightNode *ambientLight = new LightNode(new AmbientLight());
DirectionnalLight* sun = new DirectionnalLight(glm::vec3(5, 8, -2), glm::vec3(0.9f));
LightNode *sunLight = new LightNode(sun);
LightNode *fillLight = new LightNode(new DirectionnalLight(glm::vec3(8, -4, 1), glm::vec3(0.1f)));
scene->getRootObject()->addChild(ambientLight); scene->getRootObject()->addChild(ambientLight);
scene->getRootObject()->addChild(sunLight); scene->getRootObject()->addChild(sunLight);
scene->getRootObject()->addChild(fillLight);
// terrain // terrain
if(mode != SIMPLEST_TEST) if(mode != SIMPLEST_TEST)
generateTerrain(scene, engine.getPhysics()); {
sun->initShadowMap(4096);
if(mode == SPONZA_TEST)
{
generateSponza(scene, engine.getPhysics());
player->setPosition(0.f, 2.f, 0.f);
sun->setShadowView(glm::vec3(30, 30, 50));
}
else
{
generateTerrain(scene, engine.getPhysics());
player->setPosition(0.f, 15.f, 0.f);
sun->setShadowView(glm::vec3(130, 130, 70));
}
}
// shell output tests // shell output tests
engine.outputShell("Hello World!"); engine.outputShell("Hello World!");

View File

@ -66,9 +66,6 @@ Potator::Potator(PlayerCharacterNode * player,
m_cubeMesh->addTriangle(id+7, id+5, id+6); m_cubeMesh->addTriangle(id+7, id+5, id+6);
} }
Loader::setObjDirectory("../data/");
Loader::setMtlDirectory("../data/");
Loader::setTexDirectory("../data/");
Image* wood = Loader::loadImage("woodbox.jpg", false); Image* wood = Loader::loadImage("woodbox.jpg", false);
PhongMaterial *mat = new PhongMaterial(); PhongMaterial *mat = new PhongMaterial();
mat->setTexture(PhongMaterial::DIFFUSE_SLOT, new Texture(wood), "wood_texture"); mat->setTexture(PhongMaterial::DIFFUSE_SLOT, new Texture(wood), "wood_texture");

View File

@ -31,12 +31,14 @@ std::string* Loader::loadTextFile(const std::string &filename)
return str; return str;
} }
Image* Loader::loadImage(const std::string &filename, bool hasAlpha) Image* Loader::loadImage(const std::string &filename, bool hasAlpha, bool reversed)
{ {
sf::Image sfImg; sf::Image sfImg;
bool ok = sfImg.loadFromFile(tex_directory+filename); bool ok = sfImg.loadFromFile(tex_directory+filename);
if(!ok) if(!ok)
return NULL; return NULL;
if(reversed)
sfImg.flipVertically();
Image* img = new Image(); Image* img = new Image();
img->depth = hasAlpha ? 32 : 24; img->depth = hasAlpha ? 32 : 24;
img->width = sfImg.getSize().x; img->width = sfImg.getSize().x;
@ -98,7 +100,7 @@ Font* Loader::loadFont(const std::string &description_file, const std::string &t
font->addCharInfo(id,char_info); font->addCharInfo(id,char_info);
} }
Image* fucking_image_of_doom = loadImage(texture_file); Image* fucking_image_of_doom = loadImage(texture_file, true, false);
if(fucking_image_of_doom == NULL) if(fucking_image_of_doom == NULL)
printf("can't load \"%s\".\n", texture_file.c_str()); printf("can't load \"%s\".\n", texture_file.c_str());
Texture* texture = new Texture(fucking_image_of_doom, false); // mipmaps are doing a very bad job at interpolating alpha component Texture* texture = new Texture(fucking_image_of_doom, false); // mipmaps are doing a very bad job at interpolating alpha component
@ -229,6 +231,7 @@ std::vector<Mesh*> Loader::loadMesh(const std::string &filename){
RESOURCE_ADD(currentMat,Material,material_name); RESOURCE_ADD(currentMat,Material,material_name);
} }
currentMesh->setMaterial(currentMat); currentMesh->setMaterial(currentMat);
currentMesh->setName(material_name);
} }
break; break;
default: default:
@ -250,6 +253,10 @@ std::vector<Mesh*> Loader::loadMesh(const std::string &filename){
else else
{ {
Mesh* m = meshes[i]; Mesh* m = meshes[i];
if(m->normals.empty())
m->computeNormals();
if(m->getFlags() & (1 << Mesh::MATERIAL_PHONG_NORMAL_MAP))
m->computeTangents();
m->mergeVertices(); m->mergeVertices();
} }
} }

View File

@ -17,7 +17,7 @@ class Loader
public: public:
static std::string* loadTextFile(const std::string &filename); static std::string* loadTextFile(const std::string &filename);
static Image* loadImage(const std::string &filename, bool hasAlpha = true); static Image* loadImage(const std::string &filename, bool hasAlpha = true, bool reversed = true);
static std::vector<Mesh*> loadMesh(const std::string &filename); static std::vector<Mesh*> loadMesh(const std::string &filename);
static Font* loadFont(const std::string &texture, const std::string &description); static Font* loadFont(const std::string &texture, const std::string &description);
static bool loadMTL(const std::string &filename); static bool loadMTL(const std::string &filename);