Added lighting using ltbl library.
This commit is contained in:
parent
7df94496e0
commit
e0b0db8cf7
18 changed files with 202 additions and 26 deletions
26
res/shaders/light_attenuation_shader.frag
Normal file
26
res/shaders/light_attenuation_shader.frag
Normal file
|
@ -0,0 +1,26 @@
|
|||
uniform vec2 lightPos;
|
||||
|
||||
uniform vec3 lightColor;
|
||||
|
||||
uniform float radius;
|
||||
|
||||
uniform float bleed;
|
||||
|
||||
uniform float linearizeFactor;
|
||||
|
||||
void main()
|
||||
{
|
||||
float dist = length(lightPos - gl_FragCoord.xy);
|
||||
|
||||
float distFromFalloff = radius - dist;
|
||||
|
||||
// Still has absolute falloff point
|
||||
float attenuation = distFromFalloff * (bleed / pow(dist, 2.0) + linearizeFactor / radius);
|
||||
|
||||
// Optional, clamp it to prevent overcoloring
|
||||
attenuation = clamp(attenuation, 0.0, 1.0);
|
||||
|
||||
vec4 color = vec4(attenuation, attenuation, attenuation, 1.0) * vec4(lightColor.r, lightColor.g, lightColor.b, 1.0);
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
BIN
res/textures/light_fin.png
Normal file
BIN
res/textures/light_fin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
7
res/yaml/light.yaml
Normal file
7
res/yaml/light.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Color values for player lights, each between 0 and 255
|
||||
color_red: 255
|
||||
color_green: 255
|
||||
color_blue: 127
|
||||
|
||||
# Total angle of the player light cone
|
||||
light_cone_angle: 90.0
|
67
src/Game.cpp
67
src/Game.cpp
|
@ -13,6 +13,7 @@
|
|||
#include "sprites/Enemy.h"
|
||||
#include "sprites/Player.h"
|
||||
#include "sprites/items/HealthOrb.h"
|
||||
#include "util/Angles.h"
|
||||
#include "util/Loader.h"
|
||||
#include "util/Yaml.h"
|
||||
|
||||
|
@ -22,12 +23,15 @@
|
|||
Game::Game(tgui::Window& window) :
|
||||
mWindow(window),
|
||||
mWorldView(Vector2f(0, 0), mWindow.getView().getSize()),
|
||||
mGenerator(mWorld, mPathfinder, Yaml("generation.yaml")) {
|
||||
mLightSystem(AABB(Vec2f(-100000, -100000), Vec2f(100000, 10000)), &window,
|
||||
"res/textures/light_fin.png", "res/shaders/light_attenuation_shader.frag"),
|
||||
mGenerator(mWorld, mPathfinder, mLightSystem, Yaml("generation.yaml")) {
|
||||
mWindow.setFramerateLimit(FPS_GOAL);
|
||||
mWindow.setKeyRepeatEnabled(false);
|
||||
srand(time(nullptr));
|
||||
|
||||
initPlayer();
|
||||
initLight();
|
||||
|
||||
mCrosshairTexture = Loader::i().fromFile<sf::Texture>("crosshair.png");
|
||||
mCrosshair.setTexture(*mCrosshairTexture, true);
|
||||
|
@ -47,7 +51,15 @@ Game::Game(tgui::Window& window) :
|
|||
mPickupInstruction->setTextSize(14);
|
||||
}
|
||||
|
||||
void Game::initPlayer() {
|
||||
/**
|
||||
* Closes window.
|
||||
*/
|
||||
Game::~Game() {
|
||||
mWindow.close();
|
||||
}
|
||||
|
||||
void
|
||||
Game::initPlayer() {
|
||||
Character::EquippedItems playerItems = {
|
||||
Weapon::WeaponType::PISTOL, Weapon::WeaponType::KNIFE,
|
||||
Gadget::GadgetType::NONE, Gadget::GadgetType::NONE
|
||||
|
@ -58,11 +70,37 @@ void Game::initPlayer() {
|
|||
mWorld.insertCharacter(mPlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes window.
|
||||
*/
|
||||
Game::~Game() {
|
||||
mWindow.close();
|
||||
void
|
||||
Game::initLight() {
|
||||
Yaml config("light.yaml");
|
||||
Color3f lightColor(config.get("color_red", 0) / 255.0f,
|
||||
config.get("color_green", 0) / 255.0f,
|
||||
config.get("color_blue", 0) / 255.0f);
|
||||
mLightSystem.m_checkForHullIntersect = false;
|
||||
mLightSystem.m_useBloom = false;
|
||||
|
||||
mPlayerAreaLight->m_radius = 250.0f;
|
||||
mPlayerAreaLight->m_size = 1.0f;
|
||||
mPlayerAreaLight->m_softSpreadAngle = 0;
|
||||
mPlayerAreaLight->m_spreadAngle = 2.0f * M_PI;
|
||||
mPlayerAreaLight->m_intensity = 1.1f;
|
||||
mPlayerAreaLight->m_bleed = 0;
|
||||
mPlayerAreaLight->m_color = lightColor;
|
||||
mPlayerDirectionLight->m_linearizeFactor = 0.5;
|
||||
mPlayerAreaLight->CalculateAABB();
|
||||
mLightSystem.AddLight(mPlayerAreaLight);
|
||||
|
||||
mPlayerDirectionLight->m_radius = 500.0f;
|
||||
mPlayerDirectionLight->m_size = 25.0f;
|
||||
mPlayerDirectionLight->m_softSpreadAngle = 0.1f * M_PI;
|
||||
mPlayerDirectionLight->m_spreadAngle =
|
||||
degreeToRadian(config.get("light_cone_angle", 0.0f));
|
||||
mPlayerDirectionLight->m_intensity = 5;
|
||||
mPlayerDirectionLight->m_bleed = 0;
|
||||
mPlayerDirectionLight->m_color = lightColor;
|
||||
mPlayerDirectionLight->m_linearizeFactor = 1;
|
||||
mPlayerDirectionLight->CalculateAABB();
|
||||
mLightSystem.AddLight(mPlayerDirectionLight);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,9 +111,9 @@ Game::loop() {
|
|||
while (!mQuit) {
|
||||
input();
|
||||
|
||||
int elapsed = mClock.restart().asMilliseconds();
|
||||
if (mPaused)
|
||||
elapsed = 0;
|
||||
int elapsed = (mPaused)
|
||||
? 0
|
||||
: mClock.restart().asMilliseconds();
|
||||
|
||||
mWorld.think(elapsed);
|
||||
if (mPlayer->getHealth() == 0) {
|
||||
|
@ -301,6 +339,15 @@ Game::render() {
|
|||
mWindow.setView(mWorldView);
|
||||
mWindow.draw(mWorld);
|
||||
|
||||
// Update light
|
||||
mPlayerAreaLight->SetCenter(mPlayer->getPosition().toVec2f());
|
||||
mPlayerDirectionLight->SetCenter(mPlayer->getPosition().toVec2f());
|
||||
mPlayerDirectionLight->SetDirectionAngle(degreeToRadian(90 - mPlayer->getDirection()));
|
||||
|
||||
mLightSystem.SetView(mWorldView);
|
||||
mLightSystem.RenderLights();
|
||||
mLightSystem.RenderLightTexture();
|
||||
|
||||
// Render GUI and static stuff.
|
||||
mWindow.setView(mWindow.getDefaultView());
|
||||
mWindow.drawGUI();
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
#include <TGUI/TGUI.hpp>
|
||||
|
||||
#include <LTBL/Light/LightSystem.h>
|
||||
#include <LTBL/Light/Light_Point.h>
|
||||
|
||||
#include "generator/Generator.h"
|
||||
#include "Pathfinder.h"
|
||||
#include "World.h"
|
||||
|
@ -39,6 +42,7 @@ private:
|
|||
Vector2<float> convertCoordinates(int x, int y);
|
||||
void updateGui();
|
||||
void initPlayer();
|
||||
void initLight();
|
||||
|
||||
private:
|
||||
static const int FPS_GOAL = 60;
|
||||
|
@ -57,7 +61,11 @@ private:
|
|||
|
||||
World mWorld;
|
||||
Pathfinder mPathfinder;
|
||||
ltbl::LightSystem mLightSystem;
|
||||
Generator mGenerator;
|
||||
ltbl::Light_Point* mPlayerAreaLight = new ltbl::Light_Point();
|
||||
ltbl::Light_Point* mPlayerDirectionLight = new ltbl::Light_Point();
|
||||
|
||||
std::shared_ptr<Player> mPlayer;
|
||||
|
||||
bool mQuit = false;
|
||||
|
|
|
@ -24,14 +24,16 @@
|
|||
/**
|
||||
* Generates new random seed.
|
||||
*/
|
||||
Generator::Generator(World& world, Pathfinder& pathfinder, const Yaml& config) :
|
||||
Generator::Generator(World& world, Pathfinder& pathfinder,
|
||||
ltbl::LightSystem& lightSystem, const Yaml& config) :
|
||||
mAreaSize(config.get("generate_area_size", 1)),
|
||||
mMaxRange((config.get("generate_area_range", 1.0f) / mAreaSize) / Tile::TILE_SIZE.x),
|
||||
mRoomSizeValue(config.get("room_size_value", 1.0f)),
|
||||
mRoomConnectionValue(config.get("room_connection_value", 1.0f)),
|
||||
mEnemyGenerationChance(config.get("enemy_generation_chance", 0.0f) * 2 - 1),
|
||||
mWorld(world),
|
||||
mPathfinder(pathfinder) {
|
||||
mPathfinder(pathfinder),
|
||||
mLightSystem(lightSystem) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -188,6 +190,12 @@ Generator::connectRooms(const Vector2i& start) {
|
|||
for (const auto& p : path) {
|
||||
mTiles[p.x][p.y] = Tile::Type::FLOOR;
|
||||
Tile::setTile(p, Tile::Type::FLOOR, mWorld);
|
||||
for (auto it = mHulls.begin(); it != mHulls.end(); it++)
|
||||
if ((*it)->GetWorldCenter() == Tile::toPosition(Vector2i(p.x, p.y)).toVec2f()) {
|
||||
mLightSystem.RemoveConvexHull(*it);
|
||||
mHulls.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -245,11 +253,24 @@ Generator::generateTiles(const sf::IntRect& area) {
|
|||
mTiles[x][y] = Tile::Type::FLOOR;
|
||||
|
||||
connectRooms(start);
|
||||
|
||||
for (int x = area.left; x < area.left + area.width; x++)
|
||||
for (int y = area.top; y < area.top + area.height; y++)
|
||||
for (int y = area.top; y < area.top + area.height; y++) {
|
||||
mWorld.insert(std::shared_ptr<Sprite>(
|
||||
new Tile(Vector2i(x, y), mTiles[x][y])));
|
||||
if (mTiles[x][y] == Tile::Type::WALL) {
|
||||
ltbl::ConvexHull* tileHull = new ltbl::ConvexHull();
|
||||
tileHull->m_vertices.push_back(Vec2f(-37.5f, 37.5f));
|
||||
tileHull->m_vertices.push_back(Vec2f(-37.5f, -37.5f));
|
||||
tileHull->m_vertices.push_back(Vec2f( 37.5f, -37.5f));
|
||||
tileHull->m_vertices.push_back(Vec2f( 37.5f, 37.5f));
|
||||
tileHull->m_renderLightOverHull = false;
|
||||
tileHull->CalculateNormals();
|
||||
tileHull->CalculateAABB();
|
||||
tileHull->SetWorldCenter(Tile::toPosition(Vector2i(x, y)).toVec2f());
|
||||
mLightSystem.AddConvexHull(tileHull);
|
||||
mHulls.push_back(tileHull);
|
||||
}
|
||||
}
|
||||
|
||||
generateAreas(area);
|
||||
mPathfinder.generatePortals();
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
#include <LTBL/Light/LightSystem.h>
|
||||
|
||||
#include "../sprites/abstract/Character.h"
|
||||
#include "../sprites/Tile.h"
|
||||
#include "SimplexNoise.h"
|
||||
|
@ -24,7 +26,8 @@ class Yaml;
|
|||
*/
|
||||
class Generator : public sf::Drawable {
|
||||
public:
|
||||
explicit Generator(World& world, Pathfinder& pathfinder, const Yaml& config);
|
||||
explicit Generator(World& world, Pathfinder& pathfinder,
|
||||
ltbl::LightSystem& lightSystem, const Yaml& config);
|
||||
void generateCurrentAreaIfNeeded(const Vector2f& position,
|
||||
const Character::EquippedItems& playerItems);
|
||||
Vector2f getPlayerSpawn() const;
|
||||
|
@ -51,6 +54,7 @@ private:
|
|||
|
||||
World& mWorld;
|
||||
Pathfinder& mPathfinder;
|
||||
ltbl::LightSystem& mLightSystem;
|
||||
/// Contains values of all tiles that have yet been generated.
|
||||
array mTiles;
|
||||
/// Stores where tiles have already been generated.
|
||||
|
@ -59,6 +63,7 @@ private:
|
|||
SimplexNoise mTileNoise;
|
||||
/// Perlin noise used for character placement.
|
||||
SimplexNoise mCharacterNoise;
|
||||
std::vector<ltbl::ConvexHull*> mHulls;
|
||||
/// Used only for debug drawing.
|
||||
std::vector<std::vector<Vector2i> > mPaths;
|
||||
};
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "util/Yaml.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
#include "util/Vector.h"
|
||||
|
||||
/**
|
||||
* Creates Game object.
|
||||
*/
|
||||
|
@ -21,6 +23,7 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
tgui::Window window(sf::VideoMode(1024, 768, 32), "Dungeon Gunner",
|
||||
sf::Style::Close | sf::Style::Titlebar);
|
||||
Vector2f::SCREEN_HEIGHT = window.getSize().y;
|
||||
|
||||
if (!window.globalFont.loadFromFile("res/DejaVuSans.ttf"))
|
||||
LOG_W("Failed to load font at 'res/DejaVuSans.ttf'");
|
||||
|
|
|
@ -22,8 +22,8 @@ const Vector2i Tile::TILE_SIZE = Vector2i(75, 75);
|
|||
*
|
||||
* @param pType Type of the tile to create.
|
||||
*/
|
||||
Tile::Tile(const Vector2i& position, Type type) :
|
||||
Rectangle(Vector2f(thor::cwiseProduct(position, TILE_SIZE)),
|
||||
Tile::Tile(const Vector2i& tilePosition, Type type) :
|
||||
Rectangle(toPosition(tilePosition),
|
||||
CATEGORY_WORLD, (isSolid(type)) ? 0xffff : 0,
|
||||
Yaml(getConfig(type))), mType(type) {
|
||||
}
|
||||
|
@ -42,8 +42,7 @@ Tile::setTile(const Vector2i& position, Type type, World& world) {
|
|||
std::shared_ptr<Tile> converted = std::dynamic_pointer_cast<Tile>(c);
|
||||
// Direct comparison of floats as both are from the same generation
|
||||
// on the same CPU.
|
||||
if (converted.get() != nullptr &&
|
||||
converted->getPosition() == worldPosition &&
|
||||
if (converted && converted->getPosition() == worldPosition &&
|
||||
converted->getType() != type) {
|
||||
world.remove(converted);
|
||||
break;
|
||||
|
@ -78,6 +77,14 @@ Tile::isSolid(Type type) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a tile position to world/pixel position.
|
||||
*/
|
||||
Vector2f
|
||||
Tile::toPosition(const Vector2i& tilePosition) {
|
||||
return Vector2f(thor::cwiseProduct(tilePosition, TILE_SIZE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Type of this tile.
|
||||
*/
|
||||
|
|
|
@ -24,12 +24,13 @@ public:
|
|||
static const Vector2i TILE_SIZE; //< Tile size in pixels.
|
||||
|
||||
public:
|
||||
explicit Tile(const Vector2i& position, Type type);
|
||||
explicit Tile(const Vector2i& tilePosition, Type type);
|
||||
Type getType() const;
|
||||
|
||||
static void setTile(const Vector2i& position, Type type, World& world);
|
||||
static std::string getConfig(Type type);
|
||||
static bool isSolid(Type type);
|
||||
static Vector2f toPosition(const Vector2i& tilePosition);
|
||||
|
||||
private:
|
||||
Type mType;
|
||||
|
|
|
@ -45,10 +45,15 @@ Sprite::getSpeed() const {
|
|||
* Returns the angle of the sprite.
|
||||
*/
|
||||
Vector2f
|
||||
Sprite::getDirection() const {
|
||||
Sprite::getDirectionVector() const {
|
||||
return thor::rotatedVector(Vector2f(0, - 1), mShape.getRotation());
|
||||
}
|
||||
|
||||
float
|
||||
Sprite::getDirection() const {
|
||||
return mShape.getRotation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this object should be deleted.
|
||||
*/
|
||||
|
|
|
@ -48,7 +48,8 @@ public:
|
|||
|
||||
Vector2f getPosition() const;
|
||||
Vector2f getSpeed() const;
|
||||
Vector2f getDirection() const;
|
||||
Vector2f getDirectionVector() const;
|
||||
float getDirection() const;
|
||||
bool getDelete() const;
|
||||
Category getCategory() const;
|
||||
Vector2f getSize() const;
|
||||
|
|
|
@ -35,7 +35,7 @@ void
|
|||
RingOfFire::onThink(int elapsed) {
|
||||
if (mCurrentWave < mWavesPerUse && mTimer.isExpired()) {
|
||||
for (int angle = mCurrentWave * 10; angle <= 360; angle += 360 / mBulletsPerWave) {
|
||||
Vector2f direction(thor::rotatedVector(mCharacter->getDirection(), (float) angle) *
|
||||
Vector2f direction(thor::rotatedVector(mCharacter->getDirectionVector(), (float) angle) *
|
||||
mCharacter->getRadius());
|
||||
|
||||
std::shared_ptr<Sprite> projectile(new Bullet(mCharacter->getPosition() + direction,
|
||||
|
|
|
@ -22,7 +22,7 @@ Shield::onUse(Character& character) {
|
|||
mCharacter = &character;
|
||||
if (mRotatingShield)
|
||||
mRotatingShield->setDelete(true);
|
||||
Vector2f offset = mCharacter->getDirection() * mCharacter->getRadius();
|
||||
Vector2f offset = mCharacter->getDirectionVector() * mCharacter->getRadius();
|
||||
mRotatingShield = std::shared_ptr<RotatingShield>(
|
||||
new RotatingShield(mCharacter->getPosition() + offset));
|
||||
mCharacter->mWorld.insert(mRotatingShield);
|
||||
|
|
|
@ -181,7 +181,7 @@ Weapon::setHolder(Character& holder) {
|
|||
*/
|
||||
void
|
||||
Weapon::insertProjectile(float angle) {
|
||||
Vector2f offset(mHolder->getDirection() * mHolder->getRadius());
|
||||
Vector2f offset(mHolder->getDirectionVector() * mHolder->getRadius());
|
||||
|
||||
float spread = (mHolder->getSpeed() == Vector2f())
|
||||
? mSpread
|
||||
|
@ -189,7 +189,7 @@ Weapon::insertProjectile(float angle) {
|
|||
std::uniform_real_distribution<float> distribution(- spread, spread);
|
||||
angle += distribution(mGenerator) + 90.0f;
|
||||
|
||||
Vector2f direction(thor::rotatedVector(mHolder->getDirection(), angle));
|
||||
Vector2f direction(thor::rotatedVector(mHolder->getDirectionVector(), angle));
|
||||
|
||||
std::shared_ptr<Sprite> projectile(new Bullet(mHolder->getPosition() + offset,
|
||||
*mHolder, direction, mProjectile, mProjectileSpeed,
|
||||
|
|
18
src/util/Angles.cpp
Normal file
18
src/util/Angles.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Angles.cpp
|
||||
*
|
||||
* Created on: 12.09.2013
|
||||
* Author: felix
|
||||
*/
|
||||
|
||||
#include "Angles.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
float radianToDegree(float radian) {
|
||||
return radian * 180 / M_PI;
|
||||
}
|
||||
|
||||
float degreeToRadian(float degree) {
|
||||
return degree * M_PI / 180;
|
||||
}
|
15
src/util/Angles.h
Normal file
15
src/util/Angles.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Angles.h
|
||||
*
|
||||
* Created on: 12.09.2013
|
||||
* Author: felix
|
||||
*/
|
||||
|
||||
#ifndef ANGLES_H_
|
||||
#define ANGLES_H_
|
||||
|
||||
float radianToDegree(float radian);
|
||||
|
||||
float degreeToRadian(float degree);
|
||||
|
||||
#endif /* ANGLES_H_ */
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include <SFML/System.hpp>
|
||||
|
||||
#include <LTBL/Constructs/Vec2f.h>
|
||||
|
||||
/**
|
||||
* Vector class with comparison operator. All other operators are inherited
|
||||
* from sf::Vector2.
|
||||
|
@ -17,6 +19,9 @@
|
|||
template <typename T>
|
||||
class Vector2 : public sf::Vector2<T> {
|
||||
public:
|
||||
/// Needed for conversion to Vec2f.
|
||||
static int SCREEN_HEIGHT;
|
||||
|
||||
Vector2() : sf::Vector2<T>() {};
|
||||
Vector2(T x, T y) : sf::Vector2<T>(x, y) {};
|
||||
/**
|
||||
|
@ -26,8 +31,15 @@ public:
|
|||
template <typename U>
|
||||
Vector2(const sf::Vector2<U>& vector) : sf::Vector2<T>(vector) {};
|
||||
|
||||
Vec2f
|
||||
toVec2f() {
|
||||
return Vec2f(sf::Vector2f::x, SCREEN_HEIGHT - sf::Vector2f::y);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
int Vector2<T>::SCREEN_HEIGHT = 0;
|
||||
|
||||
/**
|
||||
* Comparison operator meant for containers like std::set.
|
||||
*
|
||||
|
|
Reference in a new issue