summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/algorithms.h12
-rw-r--r--src/animation.cpp35
-rw-r--r--src/animation.h100
-rw-r--r--src/component.h11
-rw-r--r--src/components/ai.cpp142
-rw-r--r--src/components/ai.h73
-rw-r--r--src/components/animatable.h62
-rw-r--r--src/components/controllable.h92
-rw-r--r--src/components/map_collision.cpp241
-rw-r--r--src/components/map_collision.h47
-rw-r--r--src/components/map_render.cpp40
-rw-r--r--src/components/map_render.h19
-rw-r--r--src/components/mappable.h146
-rw-r--r--src/components/orientable.h69
-rw-r--r--src/components/physics_body.cpp66
-rw-r--r--src/components/physics_body.h20
-rw-r--r--src/components/player_physics.cpp118
-rw-r--r--src/components/player_physics.h25
-rw-r--r--src/components/player_sprite.cpp60
-rw-r--r--src/components/player_sprite.h23
-rw-r--r--src/components/ponderable.h83
-rw-r--r--src/components/simple_collider.cpp14
-rw-r--r--src/components/simple_collider.h18
-rw-r--r--src/components/static_image.cpp11
-rw-r--r--src/components/static_image.h18
-rw-r--r--src/components/transformable.h69
-rw-r--r--src/components/user_movement.cpp100
-rw-r--r--src/components/user_movement.h19
-rw-r--r--src/consts.h12
-rw-r--r--src/direction.h11
-rw-r--r--src/entity.cpp46
-rw-r--r--src/entity.h64
-rw-r--r--src/entity_manager.cpp39
-rw-r--r--src/entity_manager.h211
-rw-r--r--src/entityfactory.cpp182
-rw-r--r--src/entityfactory.h15
-rw-r--r--src/game.cpp220
-rw-r--r--src/game.h80
-rw-r--r--src/main.cpp18
-rw-r--r--src/map.cpp151
-rw-r--r--src/map.h99
-rw-r--r--src/muxer.cpp61
-rw-r--r--src/renderer.cpp229
-rw-r--r--src/renderer.h2
-rw-r--r--src/system.h55
-rw-r--r--src/system_manager.h68
-rw-r--r--src/systems/animating.cpp68
-rw-r--r--src/systems/animating.h23
-rw-r--r--src/systems/controlling.cpp107
-rw-r--r--src/systems/controlling.h22
-rw-r--r--src/systems/mapping.cpp141
-rw-r--r--src/systems/mapping.h19
-rw-r--r--src/systems/orienting.cpp236
-rw-r--r--src/systems/orienting.h35
-rw-r--r--src/systems/pondering.cpp268
-rw-r--r--src/systems/pondering.h32
-rw-r--r--src/world.cpp195
-rw-r--r--src/world.h48
58 files changed, 2439 insertions, 2051 deletions
diff --git a/src/algorithms.h b/src/algorithms.h new file mode 100644 index 0000000..80e3e27 --- /dev/null +++ b/src/algorithms.h
@@ -0,0 +1,12 @@
1#ifndef ALGORITHMS_H_1DDC517E
2#define ALGORITHMS_H_1DDC517E
3
4template< typename ContainerT, typename PredicateT >
5void erase_if( ContainerT& items, const PredicateT& predicate ) {
6 for( auto it = items.begin(); it != items.end(); ) {
7 if( predicate(*it) ) it = items.erase(it);
8 else ++it;
9 }
10};
11
12#endif /* end of include guard: ALGORITHMS_H_1DDC517E */
diff --git a/src/animation.cpp b/src/animation.cpp new file mode 100644 index 0000000..31ba21f --- /dev/null +++ b/src/animation.cpp
@@ -0,0 +1,35 @@
1#include "animation.h"
2
3AnimationSet::AnimationSet(
4 Texture texture,
5 int frameWidth,
6 int frameHeight,
7 int framesAcross) :
8 texture_(std::move(texture)),
9 frameWidth_(frameWidth),
10 frameHeight_(frameHeight),
11 framesAcross_(framesAcross)
12{
13}
14
15void AnimationSet::emplaceAnimation(
16 std::string animation,
17 size_t firstFrame,
18 size_t numFrames,
19 size_t delay)
20{
21 animations_.emplace(
22 std::piecewise_construct,
23 std::make_tuple(animation),
24 std::make_tuple(firstFrame, numFrames, delay));
25}
26
27Rectangle AnimationSet::getFrameRect(int frame) const
28{
29 return {
30 frameWidth_ * (frame % framesAcross_),
31 frameHeight_ * (frame / framesAcross_),
32 frameWidth_,
33 frameHeight_
34 };
35}
diff --git a/src/animation.h b/src/animation.h new file mode 100644 index 0000000..50446d0 --- /dev/null +++ b/src/animation.h
@@ -0,0 +1,100 @@
1#ifndef ANIMATION_H_74EB0901
2#define ANIMATION_H_74EB0901
3
4#include "renderer.h"
5#include <string>
6#include <map>
7#include <stdexcept>
8
9class Animation {
10public:
11
12 Animation(
13 size_t firstFrame,
14 size_t numFrames,
15 size_t delay) :
16 firstFrame_(firstFrame),
17 numFrames_(numFrames),
18 delay_(delay)
19 {
20 }
21
22 inline size_t getFirstFrame() const
23 {
24 return firstFrame_;
25 }
26
27 inline size_t getNumFrames() const
28 {
29 return numFrames_;
30 }
31
32 inline size_t getDelay() const
33 {
34 return delay_;
35 }
36
37private:
38
39 size_t firstFrame_;
40 size_t numFrames_;
41 size_t delay_;
42};
43
44class AnimationSet {
45public:
46
47 AnimationSet(
48 Texture texture,
49 int frameWidth,
50 int frameHeight,
51 int framesAcross);
52
53 void emplaceAnimation(
54 std::string animation,
55 size_t firstFrame,
56 size_t numFrames,
57 size_t delay);
58
59 inline const Animation& getAnimation(std::string animation) const
60 {
61 if (!animations_.count(animation))
62 {
63 throw std::invalid_argument("Animation does not exist");
64 }
65
66 return animations_.at(animation);
67 }
68
69 inline const Texture& getTexture() const
70 {
71 return texture_;
72 }
73
74 inline int getFrameWidth() const
75 {
76 return frameWidth_;
77 }
78
79 inline int getFrameHeight() const
80 {
81 return frameHeight_;
82 }
83
84 inline int getFramesAcross() const
85 {
86 return framesAcross_;
87 }
88
89 Rectangle getFrameRect(int frame) const;
90
91private:
92
93 std::map<std::string, Animation> animations_;
94 Texture texture_;
95 int frameWidth_;
96 int frameHeight_;
97 int framesAcross_;
98};
99
100#endif /* end of include guard: ANIMATION_H_74EB0901 */
diff --git a/src/component.h b/src/component.h new file mode 100644 index 0000000..b81dbee --- /dev/null +++ b/src/component.h
@@ -0,0 +1,11 @@
1#ifndef COMPONENT_H_F0CE4573
2#define COMPONENT_H_F0CE4573
3
4class Component {
5public:
6
7 virtual ~Component() = default;
8
9};
10
11#endif /* end of include guard: COMPONENT_H_F0CE4573 */
diff --git a/src/components/ai.cpp b/src/components/ai.cpp deleted file mode 100644 index 9f8c764..0000000 --- a/src/components/ai.cpp +++ /dev/null
@@ -1,142 +0,0 @@
1#include "ai.h"
2#include <cstdlib>
3#include "entity.h"
4
5void AIActionContainer::addAction(std::shared_ptr<AIAction> action)
6{
7 actions.push_back(action);
8}
9
10void AIActionContainer::start(Game& game, Entity& entity)
11{
12 currentAction = begin(actions);
13
14 if (currentAction != end(actions))
15 {
16 (*currentAction)->start(game, entity);
17 }
18}
19
20void AIActionContainer::perform(Game& game, Entity& entity, double dt)
21{
22 if (!isDone())
23 {
24 (*currentAction)->perform(game, entity, dt);
25
26 if ((*currentAction)->isDone())
27 {
28 currentAction++;
29
30 if (!isDone())
31 {
32 (*currentAction)->start(game, entity);
33 }
34 }
35 }
36}
37
38bool AIActionContainer::isDone() const
39{
40 return currentAction == end(actions);
41}
42
43AI::AI(int chance)
44{
45 this->chance = chance;
46}
47
48int AI::getChance() const
49{
50 return chance;
51}
52
53AI& AIComponent::emplaceAI(int chance)
54{
55 maxChance += chance;
56 ais.emplace_back(chance);
57
58 return ais.back();
59}
60
61void AIComponent::tick(Game& game, Entity& entity, double dt)
62{
63 if (currentAI == nullptr)
64 {
65 int toChoose = rand() % maxChance;
66 for (auto& ai : ais)
67 {
68 if (toChoose < ai.getChance())
69 {
70 currentAI = &ai;
71 break;
72 } else {
73 toChoose -= ai.getChance();
74 }
75 }
76
77 if (currentAI != nullptr)
78 {
79 currentAI->start(game, entity);
80 }
81 }
82
83 if (currentAI != nullptr)
84 {
85 currentAI->perform(game, entity, dt);
86
87 if (currentAI->isDone())
88 {
89 currentAI = nullptr;
90 }
91 }
92}
93
94MoveAIAction::MoveAIAction(Direction dir, int len, int speed)
95{
96 this->dir = dir;
97 this->len = len;
98 this->speed = speed;
99}
100
101void MoveAIAction::start(Game& game, Entity& entity)
102{
103 remaining = len;
104}
105
106void MoveAIAction::perform(Game&, Entity& entity, double dt)
107{
108 double dist = dt * speed;
109 remaining -= dist;
110
111 switch (dir)
112 {
113 case Direction::Left:
114 {
115 entity.position.first -= dist;
116 break;
117 }
118
119 case Direction::Right:
120 {
121 entity.position.first += dist;
122 break;
123 }
124
125 case Direction::Up:
126 {
127 entity.position.second -= dist;
128 break;
129 }
130
131 case Direction::Down:
132 {
133 entity.position.second += dist;
134 break;
135 }
136 }
137}
138
139bool MoveAIAction::isDone() const
140{
141 return remaining <= 0.0;
142}
diff --git a/src/components/ai.h b/src/components/ai.h deleted file mode 100644 index 840283b..0000000 --- a/src/components/ai.h +++ /dev/null
@@ -1,73 +0,0 @@
1#ifndef AI_H
2#define AI_H
3
4#include <list>
5#include <map>
6#include <string>
7#include <memory>
8
9#include "entity.h"
10
11class AIAction {
12 public:
13 virtual void start(Game& game, Entity& entity) = 0;
14 virtual void perform(Game& game, Entity& entity, double dt) = 0;
15 virtual bool isDone() const = 0;
16};
17
18class AIActionContainer {
19 public:
20 void addAction(std::shared_ptr<AIAction> action);
21 virtual void start(Game& game, Entity& entity);
22 virtual void perform(Game& game, Entity& entity, double dt);
23 virtual bool isDone() const;
24
25 private:
26 std::list<std::shared_ptr<AIAction>> actions;
27 std::list<std::shared_ptr<AIAction>>::iterator currentAction {end(actions)};
28};
29
30class AI : public AIActionContainer {
31 public:
32 AI(int chance);
33
34 int getChance() const;
35
36 private:
37 int chance;
38};
39
40class AIComponent : public Component {
41 public:
42 AI& emplaceAI(int chance);
43 void tick(Game& game, Entity& entity, double dt);
44
45 private:
46 int maxChance = 0;
47 std::list<AI> ais;
48 AI* currentAI = nullptr;
49};
50
51class MoveAIAction : public AIAction {
52 public:
53 enum class Direction {
54 Left,
55 Right,
56 Up,
57 Down
58 };
59
60 MoveAIAction(Direction dir, int len, int speed);
61
62 void start(Game& game, Entity& entity);
63 void perform(Game& game, Entity& entity, double dt);
64 bool isDone() const;
65
66 private:
67 Direction dir;
68 int len;
69 int speed;
70 double remaining;
71};
72
73#endif /* end of include guard: AI_H */
diff --git a/src/components/animatable.h b/src/components/animatable.h new file mode 100644 index 0000000..ed0133e --- /dev/null +++ b/src/components/animatable.h
@@ -0,0 +1,62 @@
1#ifndef SPRITE_RENDERABLE_H_D3AACBBF
2#define SPRITE_RENDERABLE_H_D3AACBBF
3
4#include "component.h"
5#include "animation.h"
6#include <string>
7
8class AnimatableComponent : public Component {
9public:
10
11 AnimatableComponent(
12 AnimationSet animationSet,
13 std::string animation) :
14 animationSet_(std::move(animationSet)),
15 animation_(std::move(animation))
16 {
17 }
18
19 inline size_t getFrame() const
20 {
21 return frame_;
22 }
23
24 inline void setFrame(size_t v)
25 {
26 frame_ = v;
27 }
28
29 inline size_t getCountdown() const
30 {
31 return countdown_;
32 }
33
34 inline void setCountdown(size_t v)
35 {
36 countdown_ = v;
37 }
38
39 inline const AnimationSet& getAnimationSet() const
40 {
41 return animationSet_;
42 }
43
44 inline const Animation& getAnimation() const
45 {
46 return animationSet_.getAnimation(animation_);
47 }
48
49 inline void setAnimation(std::string animation)
50 {
51 animation_ = std::move(animation);
52 }
53
54private:
55
56 AnimationSet animationSet_;
57 std::string animation_;
58 size_t frame_ = 0;
59 size_t countdown_ = 0;
60};
61
62#endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */
diff --git a/src/components/controllable.h b/src/components/controllable.h new file mode 100644 index 0000000..fa78c8b --- /dev/null +++ b/src/components/controllable.h
@@ -0,0 +1,92 @@
1#ifndef CONTROLLABLE_H_4E0B85B4
2#define CONTROLLABLE_H_4E0B85B4
3
4#include "component.h"
5#include "renderer.h"
6
7class ControllableComponent : public Component {
8public:
9
10 inline int getLeftKey() const
11 {
12 return leftKey_;
13 }
14
15 inline void setLeftKey(int k)
16 {
17 leftKey_ = k;
18 }
19
20 inline int getRightKey() const
21 {
22 return rightKey_;
23 }
24
25 inline void setRightKey(int k)
26 {
27 rightKey_ = k;
28 }
29
30 inline int getJumpKey() const
31 {
32 return jumpKey_;
33 }
34
35 inline void setJumpKey(int k)
36 {
37 jumpKey_ = k;
38 }
39
40 inline int getDropKey() const
41 {
42 return dropKey_;
43 }
44
45 inline void setDropKey(int k)
46 {
47 dropKey_ = k;
48 }
49
50 inline bool isFrozen() const
51 {
52 return frozen_;
53 }
54
55 inline void setFrozen(bool f)
56 {
57 frozen_ = f;
58 }
59
60 inline bool isHoldingLeft() const
61 {
62 return holdingLeft_;
63 }
64
65 inline void setHoldingLeft(bool f)
66 {
67 holdingLeft_ = f;
68 }
69
70 inline bool isHoldingRight() const
71 {
72 return holdingRight_;
73 }
74
75 inline void setHoldingRight(bool f)
76 {
77 holdingRight_ = f;
78 }
79
80private:
81
82 int leftKey_ = GLFW_KEY_LEFT;
83 int rightKey_ = GLFW_KEY_RIGHT;
84 int jumpKey_ = GLFW_KEY_UP;
85 int dropKey_ = GLFW_KEY_DOWN;
86
87 bool frozen_ = false;
88 bool holdingLeft_ = false;
89 bool holdingRight_ = false;
90};
91
92#endif /* end of include guard: CONTROLLABLE_H_4E0B85B4 */
diff --git a/src/components/map_collision.cpp b/src/components/map_collision.cpp deleted file mode 100644 index 3ad574b..0000000 --- a/src/components/map_collision.cpp +++ /dev/null
@@ -1,241 +0,0 @@
1#include "map_collision.h"
2#include "map.h"
3#include "game.h"
4#include "consts.h"
5
6MapCollisionComponent::MapCollisionComponent(const Map& map) : map(map)
7{
8 addCollision(-6, 0, MAP_HEIGHT*TILE_HEIGHT, Direction::left, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Left).type));
9 addCollision(GAME_WIDTH+6, 0, MAP_HEIGHT*TILE_HEIGHT, Direction::right, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Right).type));
10 addCollision(-6, 0, GAME_WIDTH, Direction::up, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Up).type));
11 addCollision(MAP_HEIGHT*TILE_HEIGHT+6, 0, GAME_WIDTH, Direction::down, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Down).type));
12
13 for (int i=0; i<MAP_WIDTH*MAP_HEIGHT; i++)
14 {
15 int x = i % MAP_WIDTH;
16 int y = i / MAP_WIDTH;
17 int tile = map.getMapdata()[i];
18
19 if ((tile > 0) && (tile < 28) && (!((tile >= 5) && (tile <= 7))))
20 {
21 addCollision(x*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::right, Collision::Type::wall);
22 addCollision((x+1)*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::left, Collision::Type::wall);
23 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::wall);
24 addCollision((y+1)*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::up, Collision::Type::wall);
25 } else if ((tile >= 5) && (tile <= 7))
26 {
27 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::platform);
28 } else if (tile == 42)
29 {
30 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::danger);
31 }
32 }
33}
34
35void MapCollisionComponent::addCollision(double axis, double lower, double
36 upper, Direction dir, Collision::Type type)
37{
38 std::list<Collision>::iterator it;
39
40 switch (dir)
41 {
42 case Direction::up:
43 it = up_collisions.begin();
44 for (; it!=up_collisions.end(); it++)
45 {
46 if (it->axis < axis) break;
47 }
48
49 up_collisions.insert(it, {axis, lower, upper, type});
50
51 break;
52 case Direction::down:
53 it = down_collisions.begin();
54 for (; it!=down_collisions.end(); it++)
55 {
56 if (it->axis > axis) break;
57 }
58
59 down_collisions.insert(it, {axis, lower, upper, type});
60
61 break;
62 case Direction::left:
63 it = left_collisions.begin();
64 for (; it!=left_collisions.end(); it++)
65 {
66 if (it->axis < axis) break;
67 }
68
69 left_collisions.insert(it, {axis, lower, upper, type});
70
71 break;
72 case Direction::right:
73 it = right_collisions.begin();
74 for (; it!=right_collisions.end(); it++)
75 {
76 if (it->axis > axis) break;
77 }
78
79 right_collisions.insert(it, {axis, lower, upper, type});
80
81 break;
82 }
83}
84
85void MapCollisionComponent::detectCollision(Game& game, Entity&, Entity& collider, std::pair<double, double> old_position)
86{
87 if (collider.position.first < old_position.first)
88 {
89 for (auto collision : left_collisions)
90 {
91 if (collision.axis > old_position.first) continue;
92 if (collision.axis < collider.position.first) break;
93
94 if ((old_position.second+collider.size.second > collision.lower) && (old_position.second < collision.upper))
95 {
96 // We have a collision!
97 processCollision(game, collider, collision, Direction::left, old_position);
98
99 break;
100 }
101 }
102 } else if (collider.position.first > old_position.first)
103 {
104 for (auto collision : right_collisions)
105 {
106 if (collision.axis < old_position.first+collider.size.first) continue;
107 if (collision.axis > collider.position.first+collider.size.first) break;
108
109 if ((old_position.second+collider.size.second > collision.lower) && (old_position.second < collision.upper))
110 {
111 // We have a collision!
112 processCollision(game, collider, collision, Direction::right, old_position);
113
114 break;
115 }
116 }
117 }
118
119 if (collider.position.second < old_position.second)
120 {
121 for (auto collision : up_collisions)
122 {
123 if (collision.axis > old_position.second) continue;
124 if (collision.axis < collider.position.second) break;
125
126 if ((collider.position.first+collider.size.first > collision.lower) && (collider.position.first < collision.upper))
127 {
128 // We have a collision!
129 processCollision(game, collider, collision, Direction::up, old_position);
130
131 break;
132 }
133 }
134 } else if (collider.position.second > old_position.second)
135 {
136 for (auto collision : down_collisions)
137 {
138 if (collision.axis < old_position.second+collider.size.second) continue;
139 if (collision.axis > collider.position.second+collider.size.second) break;
140
141 if ((collider.position.first+collider.size.first > collision.lower) && (collider.position.first < collision.upper))
142 {
143 // We have a collision!
144 processCollision(game, collider, collision, Direction::down, old_position);
145
146 break;
147 }
148 }
149 }
150}
151
152void MapCollisionComponent::processCollision(Game& game, Entity& collider, Collision collision, Direction dir, std::pair<double, double> old_position)
153{
154 if (collision.type == Collision::Type::wall)
155 {
156 if (dir == Direction::left)
157 {
158 collider.position.first = collision.axis;
159
160 Message msg(Message::Type::setHorizontalVelocity);
161 msg.velocity = 0.0;
162 collider.send(game, msg);
163 } else if (dir == Direction::right)
164 {
165 collider.position.first = collision.axis - collider.size.first;
166
167 Message msg(Message::Type::setHorizontalVelocity);
168 msg.velocity = 0.0;
169 collider.send(game, msg);
170 } else if (dir == Direction::up)
171 {
172 collider.position.second = collision.axis;
173
174 Message msg(Message::Type::setVerticalVelocity);
175 msg.velocity = 0.0;
176 collider.send(game, msg);
177 } else if (dir == Direction::down)
178 {
179 collider.position.second = collision.axis - collider.size.second;
180 collider.send(game, Message::Type::hitTheGround);
181 }
182 } else if (collision.type == Collision::Type::wrap)
183 {
184 if (dir == Direction::left)
185 {
186 collider.position.first = GAME_WIDTH-collider.size.first/2;
187 } else if (dir == Direction::right)
188 {
189 collider.position.first = -collider.size.first/2;
190 } else if (dir == Direction::up)
191 {
192 collider.position.second = GAME_HEIGHT-collider.size.second/2-1;
193 } else if (dir == Direction::down)
194 {
195 collider.position.second = -collider.size.second/2;
196 }
197 } else if (collision.type == Collision::Type::teleport)
198 {
199 if (dir == Direction::left)
200 {
201 game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Left).map), std::make_pair(GAME_WIDTH-collider.size.first/2, old_position.second));
202 } else if (dir == Direction::right)
203 {
204 game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Right).map), std::make_pair(-collider.size.first/2, old_position.second));
205 } else if (dir == Direction::up)
206 {
207 game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Up).map), std::make_pair(old_position.first, MAP_HEIGHT*TILE_HEIGHT-collider.size.second/2));
208 } else if (dir == Direction::down)
209 {
210 game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Down).map), std::make_pair(old_position.first, -collider.size.second/2));
211 }
212 } else if (collision.type == Collision::Type::reverse)
213 {
214 // TODO reverse
215 if (dir == Direction::right)
216 {
217 collider.position.first = collision.axis - collider.size.first;
218 collider.send(game, Message::Type::walkLeft);
219 }
220 } else if (collision.type == Collision::Type::platform)
221 {
222 Message msg(Message::Type::drop);
223 msg.dropAxis = collision.axis;
224
225 collider.send(game, msg);
226 } else if (collision.type == Collision::Type::danger)
227 {
228 game.playerDie();
229 }
230}
231
232MapCollisionComponent::Collision::Type MapCollisionComponent::collisionFromMoveType(Map::MoveType type)
233{
234 switch (type)
235 {
236 case Map::MoveType::Wall: return Collision::Type::wall;
237 case Map::MoveType::Wrap: return Collision::Type::wrap;
238 case Map::MoveType::Warp: return Collision::Type::teleport;
239 case Map::MoveType::ReverseWarp: return Collision::Type::reverse;
240 }
241}
diff --git a/src/components/map_collision.h b/src/components/map_collision.h deleted file mode 100644 index 18b9397..0000000 --- a/src/components/map_collision.h +++ /dev/null
@@ -1,47 +0,0 @@
1#ifndef MAP_COLLISION_H
2#define MAP_COLLISION_H
3
4#include "entity.h"
5#include "map.h"
6#include <list>
7
8class Game;
9
10class MapCollisionComponent : public Component {
11 public:
12 MapCollisionComponent(const Map& map);
13 void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position);
14
15 private:
16 enum class Direction {
17 up, left, down, right
18 };
19
20 struct Collision {
21 enum class Type {
22 wall,
23 wrap,
24 teleport,
25 reverse,
26 platform,
27 danger
28 };
29
30 double axis;
31 double lower;
32 double upper;
33 Type type;
34 };
35
36 void addCollision(double axis, double lower, double upper, Direction dir, Collision::Type type);
37 void processCollision(Game& game, Entity& collider, Collision collision, Direction dir, std::pair<double, double> old_position);
38 Collision::Type collisionFromMoveType(Map::MoveType type);
39
40 std::list<Collision> left_collisions;
41 std::list<Collision> right_collisions;
42 std::list<Collision> up_collisions;
43 std::list<Collision> down_collisions;
44 const Map& map;
45};
46
47#endif
diff --git a/src/components/map_render.cpp b/src/components/map_render.cpp deleted file mode 100644 index 45766e1..0000000 --- a/src/components/map_render.cpp +++ /dev/null
@@ -1,40 +0,0 @@
1#include "map_render.h"
2#include "map.h"
3#include "game.h"
4#include "consts.h"
5
6MapRenderComponent::MapRenderComponent(const Map& map) : screen(GAME_WIDTH, GAME_HEIGHT)
7{
8 screen.fill(screen.entirety(), 0, 0, 0);
9
10 Texture tiles("res/tiles.png");
11
12 for (int i=0; i<MAP_WIDTH*MAP_HEIGHT; i++)
13 {
14 int tile = map.getMapdata()[i];
15 int x = i % MAP_WIDTH;
16 int y = i / MAP_WIDTH;
17 Rectangle dst {x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
18 Rectangle src {tile%8*TILE_WIDTH, tile/8*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
19
20 if (tile > 0)
21 {
22 screen.blit(tiles, src, dst);
23 }
24 }
25
26 Texture font("res/font.bmp");
27 std::string map_name = map.getTitle();
28 int start_x = (40/2) - (map_name.length()/2);
29 for (size_t i=0; i<map_name.length(); i++)
30 {
31 Rectangle srcRect {map_name[i] % 16 * 8, map_name[i] / 16 * 8, 8, 8};
32 Rectangle dstRect {(start_x + (int)i)*8, 24*8, 8, 8};
33 screen.blit(font, srcRect, dstRect);
34 }
35}
36
37void MapRenderComponent::render(Game&, Entity&, Texture& buffer)
38{
39 buffer.blit(screen, screen.entirety(), buffer.entirety());
40}
diff --git a/src/components/map_render.h b/src/components/map_render.h deleted file mode 100644 index a232aa6..0000000 --- a/src/components/map_render.h +++ /dev/null
@@ -1,19 +0,0 @@
1#ifndef MAP_RENDER_H
2#define MAP_RENDER_H
3
4#include "entity.h"
5#include "renderer.h"
6
7class Map;
8class Game;
9
10class MapRenderComponent : public Component {
11 public:
12 MapRenderComponent(const Map& map);
13 void render(Game& game, Entity& entity, Texture& buffer);
14
15 private:
16 Texture screen;
17};
18
19#endif
diff --git a/src/components/mappable.h b/src/components/mappable.h new file mode 100644 index 0000000..7530919 --- /dev/null +++ b/src/components/mappable.h
@@ -0,0 +1,146 @@
1#ifndef MAPPABLE_H_0B0316FB
2#define MAPPABLE_H_0B0316FB
3
4#include <map>
5#include "component.h"
6#include "renderer.h"
7#include "map.h"
8
9class MappableComponent : public Component {
10public:
11
12 class Boundary {
13 public:
14
15 enum class Type {
16 wall,
17 wrap,
18 teleport,
19 reverse,
20 platform,
21 danger
22 };
23
24 Boundary(
25 double axis,
26 double lower,
27 double upper,
28 Type type) :
29 axis_(axis),
30 lower_(lower),
31 upper_(upper),
32 type_(type)
33 {
34 }
35
36 inline double getAxis() const
37 {
38 return axis_;
39 }
40
41 inline double getLower() const
42 {
43 return lower_;
44 }
45
46 inline double getUpper() const
47 {
48 return upper_;
49 }
50
51 inline Type getType() const
52 {
53 return type_;
54 }
55
56 private:
57
58 double axis_;
59 double lower_;
60 double upper_;
61 Type type_;
62 };
63
64 MappableComponent(
65 Texture tileset,
66 Texture font) :
67 tileset_(std::move(tileset)),
68 font_(std::move(font))
69 {
70 }
71
72 using asc_boundaries_type =
73 std::multimap<
74 double,
75 Boundary,
76 std::less<double>>;
77
78 using desc_boundaries_type =
79 std::multimap<
80 double,
81 Boundary,
82 std::greater<double>>;
83
84 inline size_t getMapId() const
85 {
86 return mapId_;
87 }
88
89 inline void setMapId(size_t v)
90 {
91 mapId_ = v;
92 }
93
94 inline desc_boundaries_type& getLeftBoundaries()
95 {
96 return leftBoundaries_;
97 }
98
99 inline asc_boundaries_type& getRightBoundaries()
100 {
101 return rightBoundaries_;
102 }
103
104 inline desc_boundaries_type& getUpBoundaries()
105 {
106 return upBoundaries_;
107 }
108
109 inline asc_boundaries_type& getDownBoundaries()
110 {
111 return downBoundaries_;
112 }
113
114 inline const Texture& getTileset() const
115 {
116 return tileset_;
117 }
118
119 inline void setTileset(Texture v)
120 {
121 tileset_ = std::move(v);
122 }
123
124 inline const Texture& getFont() const
125 {
126 return font_;
127 }
128
129 inline void setFont(Texture v)
130 {
131 font_ = std::move(v);
132 }
133
134private:
135
136 size_t mapId_ = -1;
137
138 desc_boundaries_type leftBoundaries_;
139 asc_boundaries_type rightBoundaries_;
140 desc_boundaries_type upBoundaries_;
141 asc_boundaries_type downBoundaries_;
142 Texture tileset_;
143 Texture font_;
144};
145
146#endif /* end of include guard: MAPPABLE_H_0B0316FB */
diff --git a/src/components/orientable.h b/src/components/orientable.h new file mode 100644 index 0000000..e356b78 --- /dev/null +++ b/src/components/orientable.h
@@ -0,0 +1,69 @@
1#ifndef ORIENTABLE_H_EDB6C4A1
2#define ORIENTABLE_H_EDB6C4A1
3
4#include "component.h"
5
6class OrientableComponent : public Component {
7public:
8
9 enum class WalkState {
10 still,
11 left,
12 right
13 };
14
15 enum class DropState {
16 none,
17 ready,
18 active
19 };
20
21 inline bool isFacingRight() const
22 {
23 return facingRight_;
24 }
25
26 inline void setFacingRight(bool v)
27 {
28 facingRight_ = v;
29 }
30
31 inline WalkState getWalkState() const
32 {
33 return walkState_;
34 }
35
36 inline void setWalkState(WalkState v)
37 {
38 walkState_ = v;
39 }
40
41 inline bool isJumping() const
42 {
43 return jumping_;
44 }
45
46 inline void setJumping(bool v)
47 {
48 jumping_ = v;
49 }
50
51 inline DropState getDropState() const
52 {
53 return dropState_;
54 }
55
56 inline void setDropState(DropState v)
57 {
58 dropState_ = v;
59 }
60
61private:
62
63 bool facingRight_ = false;
64 WalkState walkState_ = WalkState::still;
65 bool jumping_ = false;
66 DropState dropState_ = DropState::none;
67};
68
69#endif /* end of include guard: ORIENTABLE_H_EDB6C4A1 */
diff --git a/src/components/physics_body.cpp b/src/components/physics_body.cpp deleted file mode 100644 index 97394d1..0000000 --- a/src/components/physics_body.cpp +++ /dev/null
@@ -1,66 +0,0 @@
1#include "physics_body.h"
2#include "game.h"
3#include "consts.h"
4
5void PhysicsBodyComponent::receive(Game&, Entity&, const Message& msg)
6{
7 if (msg.type == Message::Type::walkLeft)
8 {
9 velocity.first = -90;
10 } else if (msg.type == Message::Type::walkRight)
11 {
12 velocity.first = 90;
13 } else if (msg.type == Message::Type::stopWalking)
14 {
15 velocity.first = 0.0;
16 } else if (msg.type == Message::Type::setHorizontalVelocity)
17 {
18 velocity.first = msg.velocity;
19 } else if (msg.type == Message::Type::setVerticalVelocity)
20 {
21 velocity.second = msg.velocity;
22 }
23}
24
25void PhysicsBodyComponent::tick(Game&, Entity& entity, double dt)
26{
27 // Accelerate
28 velocity.first += accel.first * dt;
29 velocity.second += accel.second * dt;
30
31 // Terminal velocity
32#define TERMINAL_VELOCITY_X (2 * TILE_WIDTH * FRAMES_PER_SECOND)
33#define TERMINAL_VELOCITY_Y (2 * TILE_HEIGHT * FRAMES_PER_SECOND)
34 if (velocity.first < -TERMINAL_VELOCITY_X) velocity.first = -TERMINAL_VELOCITY_X;
35 if (velocity.first > TERMINAL_VELOCITY_X) velocity.first = TERMINAL_VELOCITY_X;
36 if (velocity.second < -TERMINAL_VELOCITY_Y) velocity.second = -TERMINAL_VELOCITY_Y;
37 if (velocity.second > TERMINAL_VELOCITY_Y) velocity.second = TERMINAL_VELOCITY_Y;
38
39 // Do the movement
40 entity.position.first += velocity.first * dt;
41 entity.position.second += velocity.second * dt;
42}
43
44void PhysicsBodyComponent::detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position)
45{
46 // If already colliding, do nothing!
47 if ((old_position.first + collider.size.first > entity.position.first)
48 && (old_position.first < entity.position.first + entity.size.first)
49 && (old_position.second + collider.size.second > entity.position.second)
50 && (old_position.second < entity.position.second + entity.size.second))
51 {
52 return;
53 }
54
55 // If newly colliding, SHOCK AND HORROR!
56 if ((collider.position.first + collider.size.first > entity.position.first)
57 && (collider.position.first < entity.position.first + entity.size.first)
58 && (collider.position.second + collider.size.second > entity.position.second)
59 && (collider.position.second < entity.position.second + entity.size.second))
60 {
61 Message msg(Message::Type::collision);
62 msg.collisionEntity = &collider;
63
64 entity.send(game, msg);
65 }
66}
diff --git a/src/components/physics_body.h b/src/components/physics_body.h deleted file mode 100644 index 079cc51..0000000 --- a/src/components/physics_body.h +++ /dev/null
@@ -1,20 +0,0 @@
1#ifndef PHYSICS_BODY_H
2#define PHYSICS_BODY_H
3
4#include "entity.h"
5#include <utility>
6
7class Game;
8
9class PhysicsBodyComponent : public Component {
10 public:
11 void receive(Game& game, Entity& entity, const Message& msg);
12 void tick(Game& game, Entity& entity, double dt);
13 void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position);
14
15 protected:
16 std::pair<double, double> velocity;
17 std::pair<double, double> accel;
18};
19
20#endif
diff --git a/src/components/player_physics.cpp b/src/components/player_physics.cpp deleted file mode 100644 index 40e9948..0000000 --- a/src/components/player_physics.cpp +++ /dev/null
@@ -1,118 +0,0 @@
1#include "player_physics.h"
2#include "muxer.h"
3#include "game.h"
4#include "consts.h"
5
6#define JUMP_VELOCITY(h, l) (-2 * (h) / (l))
7#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l))
8
9PlayerPhysicsComponent::PlayerPhysicsComponent()
10{
11 jump_velocity = JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3);
12 jump_gravity = JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3);
13 jump_gravity_short = JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233);
14
15 accel.second = jump_gravity_short;
16}
17
18void PlayerPhysicsComponent::receive(Game&, Entity& entity, const Message& msg)
19{
20 if (msg.type == Message::Type::walkLeft)
21 {
22 velocity.first = -90;
23 direction = -1;
24 } else if (msg.type == Message::Type::walkRight)
25 {
26 velocity.first = 90;
27 direction = 1;
28 } else if (msg.type == Message::Type::stopWalking)
29 {
30 velocity.first = 0.0;
31 direction = 0;
32 } else if (msg.type == Message::Type::setHorizontalVelocity)
33 {
34 velocity.first = msg.velocity;
35 } else if (msg.type == Message::Type::setVerticalVelocity)
36 {
37 velocity.second = msg.velocity;
38 } else if (msg.type == Message::Type::hitTheGround)
39 {
40 if (isFalling)
41 {
42 playSound("res/Randomize27.wav", 0.05);
43 isFalling = false;
44 }
45
46 velocity.second = 0.0;
47 } else if (msg.type == Message::Type::jump)
48 {
49 playSound("res/Randomize87.wav", 0.25);
50
51 velocity.second = jump_velocity;
52 accel.second = jump_gravity;
53 } else if (msg.type == Message::Type::stopJump)
54 {
55 accel.second = jump_gravity_short;
56 } else if (msg.type == Message::Type::canDrop)
57 {
58 canDrop = true;
59 } else if (msg.type == Message::Type::cantDrop)
60 {
61 canDrop = false;
62 } else if (msg.type == Message::Type::drop)
63 {
64 if (canDrop)
65 {
66 canDrop = false;
67 } else {
68 entity.position.second = msg.dropAxis - entity.size.second;
69 velocity.second = 0;
70 }
71 } else if (msg.type == Message::Type::die)
72 {
73 frozen = true;
74 } else if (msg.type == Message::Type::stopDying)
75 {
76 frozen = false;
77 }
78}
79
80void PlayerPhysicsComponent::tick(Game& game, Entity& entity, double dt)
81{
82 // If frozen, do nothing
83 if (frozen)
84 {
85 return;
86 }
87
88 // Continue walking even if blocked earlier
89 if (velocity.first == 0)
90 {
91 if (direction < 0)
92 {
93 velocity.first = -90;
94 } else if (direction > 0)
95 {
96 velocity.first = 90;
97 }
98 }
99
100 // Increase gravity at the height of jump
101 if ((accel.second == jump_gravity) && (velocity.second >= 0))
102 {
103 accel.second = jump_gravity_short;
104 }
105
106 // Do the movement
107 std::pair<double, double> old_position = entity.position;
108 PhysicsBodyComponent::tick(game, entity, dt);
109
110 // Check for collisions
111 game.detectCollision(entity, old_position);
112
113 // Are we moving due to gravity?
114 if (velocity.second != 0.0)
115 {
116 isFalling = true;
117 }
118}
diff --git a/src/components/player_physics.h b/src/components/player_physics.h deleted file mode 100644 index 26f1fae..0000000 --- a/src/components/player_physics.h +++ /dev/null
@@ -1,25 +0,0 @@
1#ifndef PLAYER_PHYSICS_H
2#define PLAYER_PHYSICS_H
3
4#include "entity.h"
5#include "physics_body.h"
6
7class Game;
8
9class PlayerPhysicsComponent : public PhysicsBodyComponent {
10 public:
11 PlayerPhysicsComponent();
12 void tick(Game& game, Entity& entity, double dt);
13 void receive(Game& game, Entity& entity, const Message& msg);
14
15 private:
16 double jump_velocity;
17 double jump_gravity;
18 double jump_gravity_short;
19 int direction = 0;
20 bool canDrop = false;
21 bool frozen = false;
22 bool isFalling = false;
23};
24
25#endif
diff --git a/src/components/player_sprite.cpp b/src/components/player_sprite.cpp deleted file mode 100644 index 452a940..0000000 --- a/src/components/player_sprite.cpp +++ /dev/null
@@ -1,60 +0,0 @@
1#include "player_sprite.h"
2
3PlayerSpriteComponent::PlayerSpriteComponent() : sprite("res/Starla.png")
4{
5
6}
7
8void PlayerSpriteComponent::render(Game&, Entity& entity, Texture& buffer)
9{
10 animFrame++;
11
12 int frame = 0;
13 if (isMoving)
14 {
15 frame += 2;
16
17 if (animFrame % 20 < 10)
18 {
19 frame += 2;
20 }
21 }
22
23 if (facingLeft)
24 {
25 frame++;
26 }
27
28 double alpha = 1.0;
29 if (dying && (animFrame % 4 < 2))
30 {
31 alpha = 0.0;
32 }
33
34 Rectangle src_rect {frame*10, 0, 10, 12};
35 Rectangle dst_rect {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second};
36 buffer.blit(sprite, src_rect, dst_rect, alpha);
37}
38
39void PlayerSpriteComponent::receive(Game&, Entity&, const Message& msg)
40{
41 if (msg.type == Message::Type::walkLeft)
42 {
43 facingLeft = true;
44 isMoving = true;
45 } else if (msg.type == Message::Type::walkRight)
46 {
47 facingLeft = false;
48 isMoving = true;
49 } else if (msg.type == Message::Type::stopWalking)
50 {
51 isMoving = false;
52 } else if (msg.type == Message::Type::die)
53 {
54 dying = true;
55 isMoving = false;
56 } else if (msg.type == Message::Type::stopDying)
57 {
58 dying = false;
59 }
60}
diff --git a/src/components/player_sprite.h b/src/components/player_sprite.h deleted file mode 100644 index b1ac0af..0000000 --- a/src/components/player_sprite.h +++ /dev/null
@@ -1,23 +0,0 @@
1#ifndef PLAYER_SPRITE_H
2#define PLAYER_SPRITE_H
3
4#include "entity.h"
5#include "renderer.h"
6
7class Game;
8
9class PlayerSpriteComponent : public Component {
10 public:
11 PlayerSpriteComponent();
12 void render(Game& game, Entity& entity, Texture& buffer);
13 void receive(Game& game, Entity& entity, const Message& msg);
14
15 private:
16 Texture sprite;
17 int animFrame = 0;
18 bool facingLeft = false;
19 bool isMoving = false;
20 bool dying = false;
21};
22
23#endif
diff --git a/src/components/ponderable.h b/src/components/ponderable.h new file mode 100644 index 0000000..e21cbab --- /dev/null +++ b/src/components/ponderable.h
@@ -0,0 +1,83 @@
1#ifndef TANGIBLE_H_746DB3EE
2#define TANGIBLE_H_746DB3EE
3
4#include "component.h"
5
6class PonderableComponent : public Component {
7public:
8
9 enum class Type {
10 vacuumed,
11 freefalling
12 };
13
14 PonderableComponent(Type type) : type_(type)
15 {
16 }
17
18 inline Type getType() const
19 {
20 return type_;
21 }
22
23 inline double getVelocityX() const
24 {
25 return velX_;
26 }
27
28 inline void setVelocityX(double v)
29 {
30 velX_ = v;
31 }
32
33 inline double getVelocityY() const
34 {
35 return velY_;
36 }
37
38 inline void setVelocityY(double v)
39 {
40 velY_ = v;
41 }
42
43 inline double getAccelX() const
44 {
45 return accelX_;
46 }
47
48 inline void setAccelX(double v)
49 {
50 accelX_ = v;
51 }
52
53 inline double getAccelY() const
54 {
55 return accelY_;
56 }
57
58 inline void setAccelY(double v)
59 {
60 accelY_ = v;
61 }
62
63 inline bool isGrounded() const
64 {
65 return grounded_;
66 }
67
68 inline void setGrounded(bool v)
69 {
70 grounded_ = v;
71 }
72
73private:
74
75 double velX_ = 0.0;
76 double velY_ = 0.0;
77 double accelX_ = 0.0;
78 double accelY_ = 0.0;
79 Type type_ = Type::vacuumed;
80 bool grounded_ = false;
81};
82
83#endif /* end of include guard: TANGIBLE_H_746DB3EE */
diff --git a/src/components/simple_collider.cpp b/src/components/simple_collider.cpp deleted file mode 100644 index f4b414e..0000000 --- a/src/components/simple_collider.cpp +++ /dev/null
@@ -1,14 +0,0 @@
1#include "simple_collider.h"
2
3SimpleColliderComponent::SimpleColliderComponent(std::function<void (Game& game, Entity& collider)> callback) : callback(callback)
4{
5
6}
7
8void SimpleColliderComponent::receive(Game& game, Entity&, const Message& msg)
9{
10 if (msg.type == Message::Type::collision)
11 {
12 callback(game, *msg.collisionEntity);
13 }
14}
diff --git a/src/components/simple_collider.h b/src/components/simple_collider.h deleted file mode 100644 index 15d78cf..0000000 --- a/src/components/simple_collider.h +++ /dev/null
@@ -1,18 +0,0 @@
1#ifndef SIMPLE_COLLIDER_H
2#define SIMPLE_COLLIDER_H
3
4#include "entity.h"
5#include <functional>
6
7class Game;
8
9class SimpleColliderComponent : public Component {
10 public:
11 SimpleColliderComponent(std::function<void (Game& game, Entity& collider)> callback);
12 void receive(Game& game, Entity& entity, const Message& msg);
13
14 private:
15 std::function<void (Game& game, Entity& collider)> callback;
16};
17
18#endif
diff --git a/src/components/static_image.cpp b/src/components/static_image.cpp deleted file mode 100644 index 9fa8dca..0000000 --- a/src/components/static_image.cpp +++ /dev/null
@@ -1,11 +0,0 @@
1#include "static_image.h"
2
3StaticImageComponent::StaticImageComponent(const char* filename) : sprite(Texture(filename))
4{
5
6}
7
8void StaticImageComponent::render(Game&, Entity& entity, Texture& buffer)
9{
10 buffer.blit(sprite, sprite.entirety(), {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second});
11}
diff --git a/src/components/static_image.h b/src/components/static_image.h deleted file mode 100644 index 2dec78b..0000000 --- a/src/components/static_image.h +++ /dev/null
@@ -1,18 +0,0 @@
1#ifndef STATIC_IMAGE_H
2#define STATIC_IMAGE_H
3
4#include "entity.h"
5#include "renderer.h"
6
7class Game;
8
9class StaticImageComponent : public Component {
10 public:
11 StaticImageComponent(const char* filename);
12 void render(Game& game, Entity& entity, Texture& buffer);
13
14 private:
15 Texture sprite;
16};
17
18#endif
diff --git a/src/components/transformable.h b/src/components/transformable.h new file mode 100644 index 0000000..6ed2637 --- /dev/null +++ b/src/components/transformable.h
@@ -0,0 +1,69 @@
1#ifndef LOCATABLE_H_39E526CA
2#define LOCATABLE_H_39E526CA
3
4#include "component.h"
5
6class TransformableComponent : public Component {
7public:
8
9 TransformableComponent(
10 double x,
11 double y,
12 int w,
13 int h) :
14 x_(x),
15 y_(y),
16 w_(w),
17 h_(h)
18 {
19 }
20
21 inline double getX() const
22 {
23 return x_;
24 }
25
26 inline void setX(double v)
27 {
28 x_ = v;
29 }
30
31 inline double getY() const
32 {
33 return y_;
34 }
35
36 inline void setY(double v)
37 {
38 y_ = v;
39 }
40
41 inline int getW() const
42 {
43 return w_;
44 }
45
46 inline void setW(int v)
47 {
48 w_ = v;
49 }
50
51 inline int getH() const
52 {
53 return h_;
54 }
55
56 inline void setH(int v)
57 {
58 h_ = v;
59 }
60
61private:
62
63 double x_;
64 double y_;
65 int w_;
66 int h_;
67};
68
69#endif /* end of include guard: LOCATABLE_H_39E526CA */
diff --git a/src/components/user_movement.cpp b/src/components/user_movement.cpp deleted file mode 100644 index e499fee..0000000 --- a/src/components/user_movement.cpp +++ /dev/null
@@ -1,100 +0,0 @@
1#include "user_movement.h"
2#include "renderer.h"
3
4void UserMovementComponent::input(Game& game, Entity& entity, int key, int action)
5{
6 if (action == GLFW_PRESS)
7 {
8 if (key == GLFW_KEY_LEFT)
9 {
10 holdingLeft = true;
11
12 if (!frozen)
13 {
14 entity.send(game, Message::Type::walkLeft);
15 }
16 } else if (key == GLFW_KEY_RIGHT)
17 {
18 holdingRight = true;
19
20 if (!frozen)
21 {
22 entity.send(game, Message::Type::walkRight);
23 }
24 } else if (key == GLFW_KEY_UP)
25 {
26 if (!frozen)
27 {
28 entity.send(game, Message::Type::jump);
29 }
30 } else if (key == GLFW_KEY_DOWN)
31 {
32 if (!frozen)
33 {
34 entity.send(game, Message::Type::canDrop);
35 }
36 }
37 } else if (action == GLFW_RELEASE)
38 {
39 if (key == GLFW_KEY_LEFT)
40 {
41 holdingLeft = false;
42
43 if (!frozen)
44 {
45 if (holdingRight)
46 {
47 entity.send(game, Message::Type::walkRight);
48 } else {
49 entity.send(game, Message::Type::stopWalking);
50 }
51 }
52 } else if (key == GLFW_KEY_RIGHT)
53 {
54 holdingRight = false;
55
56 if (!frozen)
57 {
58 if (holdingLeft)
59 {
60 entity.send(game, Message::Type::walkLeft);
61 } else {
62 entity.send(game, Message::Type::stopWalking);
63 }
64 }
65 } else if (key == GLFW_KEY_DOWN)
66 {
67 if (!frozen)
68 {
69 entity.send(game, Message::Type::cantDrop);
70 }
71 } else if (key == GLFW_KEY_UP)
72 {
73 if (!frozen)
74 {
75 entity.send(game, Message::Type::stopJump);
76 }
77 }
78 }
79}
80
81void UserMovementComponent::receive(Game& game, Entity& entity, const Message& msg)
82{
83 if (msg.type == Message::Type::die)
84 {
85 frozen = true;
86
87 entity.send(game, Message::Type::stopWalking);
88 } else if (msg.type == Message::Type::stopDying)
89 {
90 frozen = false;
91
92 if (holdingLeft)
93 {
94 entity.send(game, Message::Type::walkLeft);
95 } else if (holdingRight)
96 {
97 entity.send(game, Message::Type::walkRight);
98 }
99 }
100}
diff --git a/src/components/user_movement.h b/src/components/user_movement.h deleted file mode 100644 index 1bcf05e..0000000 --- a/src/components/user_movement.h +++ /dev/null
@@ -1,19 +0,0 @@
1#ifndef USER_MOVEMENT_H
2#define USER_MOVEMENT_H
3
4#include "entity.h"
5
6class Game;
7
8class UserMovementComponent : public Component {
9 public:
10 void input(Game& game, Entity& entity, int key, int action);
11 void receive(Game&, Entity&, const Message& msg);
12
13 private:
14 bool holdingLeft = false;
15 bool holdingRight = false;
16 bool frozen = false;
17};
18
19#endif
diff --git a/src/consts.h b/src/consts.h index 804c761..581018d 100644 --- a/src/consts.h +++ b/src/consts.h
@@ -7,8 +7,20 @@ const int GAME_WIDTH = 320;
7const int GAME_HEIGHT = 200; 7const int GAME_HEIGHT = 200;
8const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH; 8const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH;
9const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT - 1; 9const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT - 1;
10const int WALL_GAP = 6;
11const int TILESET_COLS = 8;
12const int FONT_COLS = 16;
10 13
11const int FRAMES_PER_SECOND = 60; 14const int FRAMES_PER_SECOND = 60;
12const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND; 15const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND;
13 16
17#define CALC_VELOCITY(h, l) (-2 * (h) / (l))
18#define CALC_GRAVITY(h, l) (2 * ((h) / (l)) / (l))
19
20const double NORMAL_GRAVITY = CALC_GRAVITY(TILE_HEIGHT*3.5, 0.233);
21const double JUMP_GRAVITY = CALC_GRAVITY(TILE_HEIGHT*4.5, 0.3);
22const double JUMP_VELOCITY = CALC_VELOCITY(TILE_HEIGHT*4.5, 0.3);
23
24const double WALK_SPEED = 90;
25
14#endif 26#endif
diff --git a/src/direction.h b/src/direction.h new file mode 100644 index 0000000..9a4c801 --- /dev/null +++ b/src/direction.h
@@ -0,0 +1,11 @@
1#ifndef DIRECTION_H_9C49EAFD
2#define DIRECTION_H_9C49EAFD
3
4enum class Direction {
5 left,
6 right,
7 up,
8 down
9};
10
11#endif /* end of include guard: DIRECTION_H_9C49EAFD */
diff --git a/src/entity.cpp b/src/entity.cpp deleted file mode 100644 index 2b6cd7f..0000000 --- a/src/entity.cpp +++ /dev/null
@@ -1,46 +0,0 @@
1#include "entity.h"
2
3void Entity::addComponent(std::shared_ptr<Component> c)
4{
5 components.push_back(c);
6}
7
8void Entity::send(Game& game, const Message& msg)
9{
10 for (auto component : components)
11 {
12 component->receive(game, *this, msg);
13 }
14}
15
16void Entity::tick(Game& game, double dt)
17{
18 for (auto component : components)
19 {
20 component->tick(game, *this, dt);
21 }
22}
23
24void Entity::input(Game& game, int key, int action)
25{
26 for (auto component : components)
27 {
28 component->input(game, *this, key, action);
29 }
30}
31
32void Entity::render(Game& game, Texture& buffer)
33{
34 for (auto component : components)
35 {
36 component->render(game, *this, buffer);
37 }
38}
39
40void Entity::detectCollision(Game& game, Entity& collider, std::pair<double, double> old_position)
41{
42 for (auto component : components)
43 {
44 component->detectCollision(game, *this, collider, old_position);
45 }
46}
diff --git a/src/entity.h b/src/entity.h deleted file mode 100644 index 7f09f2d..0000000 --- a/src/entity.h +++ /dev/null
@@ -1,64 +0,0 @@
1#ifndef ENTITY_H
2#define ENTITY_H
3
4#include <list>
5#include "renderer.h"
6
7class Game;
8class Map;
9class Entity;
10class Component;
11
12class Message {
13 public:
14 enum class Type {
15 walkLeft,
16 walkRight,
17 stopWalking,
18 setHorizontalVelocity,
19 setVerticalVelocity,
20 collision,
21 jump,
22 stopJump,
23 drop,
24 canDrop,
25 cantDrop,
26 die,
27 stopDying,
28 hitTheGround
29 };
30
31 Message(Type type) : type(type) {}
32
33 Type type;
34 Entity* collisionEntity;
35 int dropAxis;
36 double velocity;
37};
38
39class Entity {
40 public:
41 void addComponent(std::shared_ptr<Component> c);
42 void send(Game& game, const Message& msg);
43 void tick(Game& game, double dt);
44 void input(Game& game, int key, int action);
45 void render(Game& game, Texture& buffer);
46 void detectCollision(Game& game, Entity& collider, std::pair<double, double> old_position);
47
48 std::pair<double, double> position;
49 std::pair<int, int> size;
50
51 private:
52 std::list<std::shared_ptr<Component>> components;
53};
54
55class Component {
56 public:
57 virtual void receive(Game&, Entity&, const Message&) {}
58 virtual void render(Game&, Entity&, Texture&) {}
59 virtual void tick(Game&, Entity&, double) {}
60 virtual void input(Game&, Entity&, int, int) {}
61 virtual void detectCollision(Game&, Entity&, Entity&, std::pair<double, double>) {}
62};
63
64#endif
diff --git a/src/entity_manager.cpp b/src/entity_manager.cpp new file mode 100644 index 0000000..f792e17 --- /dev/null +++ b/src/entity_manager.cpp
@@ -0,0 +1,39 @@
1#ifndef ENTITY_MANAGER_CPP_42D78C22
2#define ENTITY_MANAGER_CPP_42D78C22
3
4#include "entity_manager.h"
5
6template <>
7std::set<EntityManager::id_type> EntityManager::getEntitiesWithComponents<>(
8 std::set<std::type_index>& componentTypes)
9{
10 if (cachedComponents.count(componentTypes) == 1)
11 {
12 return cachedComponents[componentTypes];
13 }
14
15 std::set<id_type>& cache = cachedComponents[componentTypes];
16 for (id_type entity = 0; entity < entities.size(); entity++)
17 {
18 EntityData& data = entities[entity];
19 bool cacheEntity = true;
20
21 for (auto& componentType : componentTypes)
22 {
23 if (data.components.count(componentType) == 0)
24 {
25 cacheEntity = false;
26 break;
27 }
28 }
29
30 if (cacheEntity)
31 {
32 cache.insert(entity);
33 }
34 }
35
36 return cache;
37}
38
39#endif /* end of include guard: ENTITY_MANAGER_CPP_42D78C22 */
diff --git a/src/entity_manager.h b/src/entity_manager.h new file mode 100644 index 0000000..7fd82fc --- /dev/null +++ b/src/entity_manager.h
@@ -0,0 +1,211 @@
1#ifndef ENTITY_MANAGER_H_C5832F11
2#define ENTITY_MANAGER_H_C5832F11
3
4#include <map>
5#include <vector>
6#include <typeindex>
7#include <set>
8#include <stdexcept>
9#include "component.h"
10#include "algorithms.h"
11
12class EntityManager {
13private:
14
15 struct EntityData {
16 std::map<std::type_index, std::unique_ptr<Component>> components;
17 };
18
19 using database_type = std::vector<EntityData>;
20
21public:
22
23 using id_type = database_type::size_type;
24
25private:
26
27 database_type entities;
28 std::vector<bool> slotAvailable;
29 std::map<std::set<std::type_index>, std::set<id_type>> cachedComponents;
30
31 id_type nextEntityID = 0;
32
33 template <class T, class... R>
34 std::set<id_type> getEntitiesWithComponentsHelper(
35 std::set<std::type_index>& componentTypes)
36 {
37 componentTypes.insert(typeid(T));
38
39 return getEntitiesWithComponents<R...>(componentTypes);
40 }
41
42 template <class... R>
43 std::set<id_type> getEntitiesWithComponents(
44 std::set<std::type_index>& componentTypes)
45 {
46 return getEntitiesWithComponentsHelper<R...>(componentTypes);
47 }
48
49public:
50
51 EntityManager() = default;
52
53 EntityManager(const EntityManager& copy) = delete;
54
55 id_type emplaceEntity()
56 {
57 if (nextEntityID >= entities.size())
58 {
59 // If the database is saturated, add a new element for the new entity.
60 entities.emplace_back();
61 slotAvailable.push_back(false);
62
63 return nextEntityID++;
64 } else {
65 // If there is an available slot in the database, use it.
66 id_type id = nextEntityID++;
67 slotAvailable[id] = false;
68
69 // Fast forward the next available slot pointer to an available slot.
70 while ((nextEntityID < entities.size()) && !slotAvailable[nextEntityID])
71 {
72 nextEntityID++;
73 }
74
75 return id;
76 }
77 }
78
79 void deleteEntity(id_type entity)
80 {
81 if ((entity >= entities.size()) || slotAvailable[entity])
82 {
83 throw std::invalid_argument("Cannot delete non-existent entity");
84 }
85
86 // Uncache components
87 for (auto& cache : cachedComponents)
88 {
89 cache.second.erase(entity);
90 }
91
92 // Destroy the data
93 entities[entity].components.clear();
94
95 // Mark the slot as available
96 slotAvailable[entity] = true;
97
98 if (entity < nextEntityID)
99 {
100 nextEntityID = entity;
101 }
102 }
103
104 template <class T, class... Args>
105 T& emplaceComponent(id_type entity, Args&&... args)
106 {
107 if ((entity >= entities.size()) || slotAvailable[entity])
108 {
109 throw std::invalid_argument("Cannot get non-existent entity");
110 }
111
112 EntityData& data = entities[entity];
113 std::type_index componentType = typeid(T);
114
115 if (data.components.count(componentType))
116 {
117 throw std::invalid_argument("Cannot emplace already-existent component");
118 }
119
120 // Initialize the component
121 std::unique_ptr<T> ptr(new T(std::forward<Args>(args)...));
122 T& component = *ptr;
123 data.components[componentType] = std::move(ptr);
124
125 // Invalidate related caches
126 erase_if(
127 cachedComponents,
128 [&componentType] (
129 std::pair<const std::set<std::type_index>, std::set<id_type>>& cache) {
130 return cache.first.count(componentType) == 1;
131 });
132
133 return component;
134 }
135
136 template <class T>
137 void removeComponent(id_type entity)
138 {
139 if ((entity >= entities.size()) || slotAvailable[entity])
140 {
141 throw std::invalid_argument("Cannot get non-existent entity");
142 }
143
144 EntityData& data = entities[entity];
145 std::type_index componentType = typeid(T);
146
147 if (!data.components.count(componentType))
148 {
149 throw std::invalid_argument("Cannot delete non-existent component");
150 }
151
152 // Destroy the component
153 data.components.erase(componentType);
154
155 // Uncache the component
156 for (auto& cache : cachedComponents)
157 {
158 if (cache.first.count(componentType) == 1)
159 {
160 cache.second.erase(entity);
161 }
162 }
163 }
164
165 template <class T>
166 T& getComponent(id_type entity)
167 {
168 if ((entity >= entities.size()) || slotAvailable[entity])
169 {
170 throw std::invalid_argument("Cannot get non-existent entity");
171 }
172
173 EntityData& data = entities[entity];
174 std::type_index componentType = typeid(T);
175
176 if (!data.components.count(componentType))
177 {
178 throw std::invalid_argument("Cannot get non-existent component");
179 }
180
181 return *dynamic_cast<T*>(data.components[componentType].get());
182 }
183
184 template <class T>
185 bool hasComponent(id_type entity)
186 {
187 if ((entity >= entities.size()) || slotAvailable[entity])
188 {
189 throw std::invalid_argument("Cannot get non-existent entity");
190 }
191
192 EntityData& data = entities[entity];
193 std::type_index componentType = typeid(T);
194
195 return data.components.count(componentType);
196 }
197
198 template <class... R>
199 std::set<id_type> getEntitiesWithComponents()
200 {
201 std::set<std::type_index> componentTypes;
202
203 return getEntitiesWithComponentsHelper<R...>(componentTypes);
204 }
205};
206
207template <>
208std::set<EntityManager::id_type> EntityManager::getEntitiesWithComponents<>(
209 std::set<std::type_index>& componentTypes);
210
211#endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */
diff --git a/src/entityfactory.cpp b/src/entityfactory.cpp deleted file mode 100644 index b80fe99..0000000 --- a/src/entityfactory.cpp +++ /dev/null
@@ -1,182 +0,0 @@
1#include "entityfactory.h"
2#include <libxml/parser.h>
3#include "muxer.h"
4#include <cstdio>
5#include <map>
6#include <list>
7#include "components/static_image.h"
8#include "components/simple_collider.h"
9#include "components/physics_body.h"
10#include "components/ai.h"
11#include "game.h"
12
13void parseEntityAIData(AI& ai, xmlNodePtr node, const std::map<std::string, int>& items)
14{
15 xmlChar* key;
16
17 for (xmlNodePtr aiNode = node->xmlChildrenNode; aiNode != NULL; aiNode = aiNode->next)
18 {
19 if (!xmlStrcmp(aiNode->name, (xmlChar*) "move"))
20 {
21 MoveAIAction::Direction dir;
22 int len;
23 int speed;
24
25 key = xmlGetProp(aiNode, (xmlChar*) "direction");
26 if (key == 0) exit(2);
27 if (!xmlStrcmp(key, (xmlChar*) "left"))
28 {
29 dir = MoveAIAction::Direction::Left;
30 } else if (!xmlStrcmp(key, (xmlChar*) "right"))
31 {
32 dir = MoveAIAction::Direction::Right;
33 } else if (!xmlStrcmp(key, (xmlChar*) "up"))
34 {
35 dir = MoveAIAction::Direction::Up;
36 } else if (!xmlStrcmp(key, (xmlChar*) "down"))
37 {
38 dir = MoveAIAction::Direction::Down;
39 } else {
40 exit(2);
41 }
42 xmlFree(key);
43
44 key = xmlGetProp(aiNode, (xmlChar*) "length");
45 if (key != 0)
46 {
47 len = atoi((char*) key);
48 } else {
49 key = xmlGetProp(aiNode, (xmlChar*) "length-var");
50 if (key == 0) exit(2);
51 std::string varName = (char*) key;
52 len = items.at(varName);
53 }
54 xmlFree(key);
55
56 key = xmlGetProp(aiNode, (xmlChar*) "speed");
57 if (key != 0)
58 {
59 speed = atoi((char*) key);
60 } else {
61 key = xmlGetProp(aiNode, (xmlChar*) "speed-var");
62 if (key == 0) exit(2);
63 std::string varName = (char*) key;
64 speed = items.at(varName);
65 }
66 xmlFree(key);
67
68 ai.addAction(std::make_shared<MoveAIAction>(dir, len, speed));
69 } else if (!xmlStrcmp(aiNode->name, (xmlChar*) "switch"))
70 {
71 key = xmlGetProp(aiNode, (xmlChar*) "item");
72 if (key == 0) exit(2);
73 std::string switchItem = (char*) key;
74 xmlFree(key);
75
76 for (xmlNodePtr switchNode = aiNode->xmlChildrenNode; switchNode != NULL; switchNode = switchNode->next)
77 {
78 if (!xmlStrcmp(switchNode->name, (xmlChar*) "case"))
79 {
80 key = xmlGetProp(switchNode, (xmlChar*) "value");
81 if (key == 0) exit(2);
82 int caseValue = atoi((char*) key);
83 xmlFree(key);
84
85 if (items.at(switchItem) == caseValue)
86 {
87 parseEntityAIData(ai, switchNode, items);
88 }
89 }
90 }
91 }
92 }
93}
94
95std::shared_ptr<Entity> EntityFactory::createNamedEntity(const std::string name, const std::map<std::string, int>& items)
96{
97 xmlDocPtr doc = xmlParseFile("res/entities.xml");
98 if (doc == nullptr)
99 {
100 fprintf(stderr, "Error reading entities\n");
101 exit(-1);
102 }
103
104 xmlNodePtr top = xmlDocGetRootElement(doc);
105 if (top == nullptr)
106 {
107 fprintf(stderr, "Empty entities file\n");
108 exit(-1);
109 }
110
111 if (xmlStrcmp(top->name, (const xmlChar*) "entities"))
112 {
113 fprintf(stderr, "Invalid entities definition\n");
114 exit(-1);
115 }
116
117 auto entity = std::make_shared<Entity>();
118
119 xmlChar* key;
120 for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next)
121 {
122 if (!xmlStrcmp(node->name, (xmlChar*) "entity"))
123 {
124 key = xmlGetProp(node, (xmlChar*) "id");
125 if (key == 0) exit(-1);
126 std::string entityID = (char*) key;
127 xmlFree(key);
128
129 if (entityID == name)
130 {
131 key = xmlGetProp(node, (xmlChar*) "sprite");
132 if (key == 0) exit(-1);
133 auto spriteComponent = std::make_shared<StaticImageComponent>((char*) key);
134 entity->addComponent(spriteComponent);
135 xmlFree(key);
136
137 auto physicsComponent = std::make_shared<PhysicsBodyComponent>();
138 entity->addComponent(physicsComponent);
139
140 key = xmlGetProp(node, (xmlChar*) "width");
141 if (key == 0) exit(-1);
142 entity->size.first = atoi((char*) key);
143 xmlFree(key);
144
145 key = xmlGetProp(node, (xmlChar*) "height");
146 if (key == 0) exit(-1);
147 entity->size.second = atoi((char*) key);
148 xmlFree(key);
149
150 bool addAI = false;
151 auto aiComponent = std::make_shared<AIComponent>();
152
153 for (xmlNodePtr entityNode = node->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next)
154 {
155 if (!xmlStrcmp(entityNode->name, (xmlChar*) "ai"))
156 {
157 addAI = true;
158
159 xmlChar* chanceKey = xmlGetProp(entityNode, (xmlChar*) "chance");
160 if (chanceKey == 0) exit(2);
161 int chance = atoi((char*) chanceKey);
162 xmlFree(chanceKey);
163
164 AI& ai = aiComponent->emplaceAI(chance);
165 parseEntityAIData(ai, entityNode, items);
166 }
167 }
168
169 if (addAI)
170 {
171 entity->addComponent(aiComponent);
172 }
173
174 break;
175 }
176 }
177 }
178
179 xmlFreeDoc(doc);
180
181 return entity;
182}
diff --git a/src/entityfactory.h b/src/entityfactory.h deleted file mode 100644 index 56f7216..0000000 --- a/src/entityfactory.h +++ /dev/null
@@ -1,15 +0,0 @@
1#ifndef ENTITYFACTORY_H
2#define ENTITYFACTORY_H
3
4#include <string>
5#include <map>
6
7class Entity;
8class Map;
9
10class EntityFactory {
11 public:
12 static std::shared_ptr<Entity> createNamedEntity(const std::string name, const std::map<std::string, int>& items);
13};
14
15#endif
diff --git a/src/game.cpp b/src/game.cpp index 673c804..39bb3f1 100644 --- a/src/game.cpp +++ b/src/game.cpp
@@ -1,178 +1,100 @@
1#include "game.h" 1#include "game.h"
2#include <cstdlib> 2#include "components/animatable.h"
3#include "components/transformable.h"
4#include "components/controllable.h"
5#include "components/ponderable.h"
6#include "components/orientable.h"
7#include "systems/controlling.h"
8#include "systems/pondering.h"
9#include "systems/animating.h"
10#include "systems/mapping.h"
11#include "systems/orienting.h"
12#include "animation.h"
3#include "renderer.h" 13#include "renderer.h"
4#include "muxer.h"
5#include "map.h"
6#include "components/user_movement.h"
7#include "components/player_physics.h"
8#include "components/player_sprite.h"
9#include "components/map_render.h"
10#include "components/map_collision.h"
11#include "consts.h" 14#include "consts.h"
12 15
13Game::Game(const char* mapfile) : world(mapfile)
14{
15 // Set up entities
16 player = std::make_shared<Entity>();
17 player->position = world.getStartingPosition();
18 player->size = std::make_pair(10.0,12.0);
19
20 auto player_input = std::make_shared<UserMovementComponent>();
21 player->addComponent(player_input);
22
23 auto player_physics = std::make_shared<PlayerPhysicsComponent>();
24 player->addComponent(player_physics);
25
26 auto player_anim = std::make_shared<PlayerSpriteComponent>();
27 player->addComponent(player_anim);
28
29 const Map& startingMap = world.getStartingMap();
30 save = {&startingMap, player->position};
31
32 loadMap(startingMap, player->position);
33}
34
35void key_callback(GLFWwindow* window, int key, int, int action, int) 16void key_callback(GLFWwindow* window, int key, int, int action, int)
36{ 17{
37 Game* game = (Game*) glfwGetWindowUserPointer(window); 18 Game& game = *((Game*) glfwGetWindowUserPointer(window));
38 19
39 if ((key == GLFW_KEY_ESCAPE) && (action == GLFW_PRESS)) 20 if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE))
40 {
41 game->shouldQuit = true;
42 }
43
44 for (auto entity : game->entities)
45 { 21 {
46 entity->input(*game, key, action); 22 game.shouldQuit_ = true;
23
24 return;
47 } 25 }
26
27 game.systemManager_.input(key, action);
48} 28}
49 29
50void Game::execute(GLFWwindow* window) 30Game::Game(
31 GLFWwindow* window) :
32 window_(window),
33 world_("res/maps.xml")
51{ 34{
35 systemManager_.emplaceSystem<ControllingSystem>(*this);
36 systemManager_.emplaceSystem<OrientingSystem>(*this);
37 systemManager_.emplaceSystem<PonderingSystem>(*this);
38 systemManager_.emplaceSystem<MappingSystem>(*this);
39 systemManager_.emplaceSystem<AnimatingSystem>(*this);
40
41 int player = entityManager_.emplaceEntity();
42
43 AnimationSet playerGraphics {"res/Starla2.bmp", 10, 12, 6};
44 playerGraphics.emplaceAnimation("stillLeft", 3, 1, 1);
45 playerGraphics.emplaceAnimation("stillRight", 0, 1, 1);
46 playerGraphics.emplaceAnimation("walkingLeft", 4, 2, 10);
47 playerGraphics.emplaceAnimation("walkingRight", 1, 2, 10);
48
49 entityManager_.emplaceComponent<AnimatableComponent>(
50 player,
51 std::move(playerGraphics),
52 "stillLeft");
53
54 entityManager_.emplaceComponent<TransformableComponent>(
55 player,
56 203, 44, 10, 12);
57
58 systemManager_.getSystem<PonderingSystem>().initializeBody(
59 player,
60 PonderableComponent::Type::freefalling);
61
62 entityManager_.emplaceComponent<ControllableComponent>(player);
63 entityManager_.emplaceComponent<OrientableComponent>(player);
64
65 systemManager_.getSystem<MappingSystem>().loadMap(world_.getStartingMapId());
66
52 glfwSwapInterval(1); 67 glfwSwapInterval(1);
53 glfwSetWindowUserPointer(window, this); 68 glfwSetWindowUserPointer(window_, this);
54 glfwSetKeyCallback(window, key_callback); 69 glfwSetKeyCallback(window_, key_callback);
55 70}
56 Texture buffer(GAME_WIDTH, GAME_HEIGHT);
57 71
72void Game::execute()
73{
58 double lastTime = glfwGetTime(); 74 double lastTime = glfwGetTime();
59 const double dt = 0.01; 75 const double dt = 0.01;
60 double accumulator = 0.0; 76 double accumulator = 0.0;
61 77 Texture texture(GAME_WIDTH, GAME_HEIGHT);
62 while (!(shouldQuit || glfwWindowShouldClose(window))) 78
79 while (!(shouldQuit_ || glfwWindowShouldClose(window_)))
63 { 80 {
64 double currentTime = glfwGetTime(); 81 double currentTime = glfwGetTime();
65 double frameTime = currentTime - lastTime; 82 double frameTime = currentTime - lastTime;
66 lastTime = currentTime; 83 lastTime = currentTime;
67 84
68 // Should we load a new world?
69 if (newWorld)
70 {
71 newWorld = false;
72 entities.clear();
73 entities = std::move(nextEntities);
74
75 player->position = nextPosition;
76 }
77
78 // Handle input
79 glfwPollEvents(); 85 glfwPollEvents();
80 86
81 // Tick!
82 accumulator += frameTime; 87 accumulator += frameTime;
83 while (accumulator >= dt) 88 while (accumulator >= dt)
84 { 89 {
85 for (auto entity : entities) 90 systemManager_.tick(dt);
86 { 91
87 entity->tick(*this, dt);
88 }
89
90 accumulator -= dt; 92 accumulator -= dt;
91 } 93 }
92
93 // Do any scheduled tasks
94 for (auto& task : scheduled)
95 {
96 task.first -= frameTime;
97
98 if (task.first <= 0)
99 {
100 task.second();
101 }
102 }
103
104 scheduled.remove_if([] (std::pair<double, std::function<void ()>> value) { return value.first <= 0; });
105
106 // Do rendering
107 buffer.fill(buffer.entirety(), 0, 0, 0);
108 for (auto entity : entities)
109 {
110 entity->render(*this, buffer);
111 }
112
113 buffer.renderScreen();
114 }
115}
116
117void Game::loadMap(const Map& map, std::pair<double, double> position)
118{
119 auto mapEn = std::make_shared<Entity>();
120
121 auto map_render = std::make_shared<MapRenderComponent>(map);
122 mapEn->addComponent(map_render);
123
124 auto map_collision = std::make_shared<MapCollisionComponent>(map);
125 mapEn->addComponent(map_collision);
126
127 // Map in the back, player on top, rest of entities in between
128 nextEntities.clear();
129 nextEntities.push_back(mapEn);
130 map.createEntities(nextEntities);
131 nextEntities.push_back(player);
132
133 newWorld = true;
134
135 currentMap = &map;
136 nextPosition = position;
137}
138 94
139void Game::detectCollision(Entity& collider, std::pair<double, double> old_position) 95 // Render
140{ 96 texture.fill(texture.entirety(), 0, 0, 0);
141 for (auto entity : entities) 97 systemManager_.render(texture);
142 { 98 texture.renderScreen();
143 entity->detectCollision(*this, collider, old_position);
144 } 99 }
145} 100}
146
147void Game::saveGame()
148{
149 save = {currentMap, player->position};
150}
151
152void Game::schedule(double time, std::function<void ()> callback)
153{
154 scheduled.emplace_front(time, std::move(callback));
155}
156
157void Game::playerDie()
158{
159 player->send(*this, Message::Type::die);
160
161 playSound("res/Hit_Hurt5.wav", 0.25);
162
163 schedule(0.75, [&] () {
164 if (*currentMap != *save.map)
165 {
166 loadMap(*save.map, save.position);
167 } else {
168 player->position = save.position;
169 }
170
171 player->send(*this, Message::Type::stopDying);
172 });
173}
174
175const World& Game::getWorld() const
176{
177 return world;
178}
diff --git a/src/game.h b/src/game.h index dd4b2f7..346d67e 100644 --- a/src/game.h +++ b/src/game.h
@@ -1,45 +1,47 @@
1#ifndef GAME_H 1#ifndef GAME_H_1014DDC9
2#define GAME_H 2#define GAME_H_1014DDC9
3 3
4#include <memory> 4#include "renderer.h"
5#include <functional> 5#include "entity_manager.h"
6#include <list> 6#include "system_manager.h"
7#include <map>
8#include "map.h"
9#include "world.h" 7#include "world.h"
10 8
11class Entity; 9class Game {
12struct GLFWwindow; 10public:
13 11
14struct Savefile { 12 Game(GLFWwindow* window);
15 const Map* map;
16 std::pair<double, double> position;
17};
18 13
19class Game { 14 void execute();
20 public: 15
21 Game(const char* maps); 16 inline EntityManager& getEntityManager()
22 void execute(GLFWwindow* window); 17 {
23 void loadMap(const Map& map, std::pair<double, double> position); 18 return entityManager_;
24 void detectCollision(Entity& collider, std::pair<double, double> old_position); 19 }
25 void saveGame(); 20
26 void schedule(double time, std::function<void ()> callback); 21 inline SystemManager& getSystemManager()
27 void playerDie(); 22 {
28 const World& getWorld() const; 23 return systemManager_;
29 24 }
30 private: 25
31 friend void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); 26 inline const World& getWorld()
32 27 {
33 std::list<std::shared_ptr<Entity>> entities; 28 return world_;
34 std::list<std::shared_ptr<Entity>> nextEntities; 29 }
35 std::pair<double, double> nextPosition; 30
36 bool newWorld; 31 friend void key_callback(
37 std::shared_ptr<Entity> player; 32 GLFWwindow* window,
38 const Map* currentMap; 33 int key,
39 Savefile save; 34 int scancode,
40 std::list<std::pair<double, std::function<void ()>>> scheduled; 35 int action,
41 bool shouldQuit = false; 36 int mods);
42 World world; 37
38private:
39
40 GLFWwindow* const window_;
41 EntityManager entityManager_;
42 SystemManager systemManager_;
43 World world_;
44 bool shouldQuit_ = false;
43}; 45};
44 46
45#endif 47#endif /* end of include guard: GAME_H_1014DDC9 */
diff --git a/src/main.cpp b/src/main.cpp index 4157350..d51da7d 100644 --- a/src/main.cpp +++ b/src/main.cpp
@@ -1,25 +1,27 @@
1#include <ctime> 1#include <ctime>
2#include <list> 2#include <list>
3#include "renderer.h"
4#include <cstdlib> 3#include <cstdlib>
5#include "game.h" 4#include "renderer.h"
6#include "muxer.h" 5#include "muxer.h"
6#include "game.h"
7 7
8int main() 8int main()
9{ 9{
10 srand(time(NULL)); 10 srand(time(NULL));
11 11
12 GLFWwindow* window = initRenderer(); 12 GLFWwindow* window = initRenderer();
13 glfwSwapInterval(1);
14
13 initMuxer(); 15 initMuxer();
14 16
15 // Put this in a block so game goes out of scope before we destroy the renderer 17 // Put this in a block so game goes out of scope before we destroy the renderer
16 { 18 {
17 Game game {"res/maps.xml"}; 19 Game game {window};
18 game.execute(window); 20 game.execute();
19 } 21 }
20 22
21 destroyMuxer(); 23 destroyMuxer();
22 destroyRenderer(); 24 destroyRenderer();
23 25
24 return 0; 26 return 0;
25} 27}
diff --git a/src/map.cpp b/src/map.cpp deleted file mode 100644 index e3725b2..0000000 --- a/src/map.cpp +++ /dev/null
@@ -1,151 +0,0 @@
1#include "map.h"
2#include <cstdlib>
3#include <cstring>
4#include <map>
5#include "entityfactory.h"
6#include "entity.h"
7#include "game.h"
8#include "consts.h"
9
10Map::Map(int id)
11{
12 this->id = id;
13 mapdata = (int*) calloc(1, sizeof(int));
14}
15
16Map::Map(const Map& map)
17{
18 mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int));
19 memcpy(mapdata, map.mapdata, MAP_WIDTH*MAP_HEIGHT*sizeof(int));
20
21 id = map.id;
22 title = map.title;
23 adjacents = map.adjacents;
24 entities = map.entities;
25}
26
27Map::Map(Map&& map) : Map()
28{
29 swap(*this, map);
30}
31
32Map::~Map()
33{
34 free(mapdata);
35}
36
37Map& Map::operator= (Map map)
38{
39 swap(*this, map);
40
41 return *this;
42}
43
44void swap(Map& first, Map& second)
45{
46 std::swap(first.mapdata, second.mapdata);
47 std::swap(first.title, second.title);
48 std::swap(first.adjacents, second.adjacents);
49 std::swap(first.id, second.id);
50 std::swap(first.entities, second.entities);
51}
52
53int Map::getID() const
54{
55 return id;
56}
57
58const int* Map::getMapdata() const
59{
60 return mapdata;
61}
62
63std::string Map::getTitle() const
64{
65 return title;
66}
67
68void Map::createEntities(std::list<std::shared_ptr<Entity>>& entities) const
69{
70 for (auto data : this->entities)
71 {
72 auto entity = EntityFactory::createNamedEntity(data.name, data.items);
73 entity->position = data.position;
74
75 entities.push_back(entity);
76 }
77}
78
79bool Map::operator==(const Map& other) const
80{
81 return id == other.id;
82}
83
84bool Map::operator!=(const Map& other) const
85{
86 return id != other.id;
87}
88
89Map::MoveType Map::moveTypeForShort(std::string str)
90{
91 if (str == "wrap") return MoveType::Wrap;
92 if (str == "warp") return MoveType::Warp;
93 if (str == "reverseWarp") return MoveType::ReverseWarp;
94
95 return MoveType::Wall;
96}
97
98Map::MoveDir Map::moveDirForShort(std::string str)
99{
100 if (str == "right") return MoveDir::Right;
101 if (str == "up") return MoveDir::Up;
102 if (str == "down") return MoveDir::Down;
103
104 return MoveDir::Left;
105}
106
107static const Map::Adjacent defaultAdjacent {};
108const Map::Adjacent& Map::getAdjacent(MoveDir dir) const
109{
110 if (adjacents.count(dir) > 0)
111 {
112 return adjacents.at(dir);
113 } else {
114 return defaultAdjacent;
115 }
116}
117
118bool Map::moveTypeTakesMap(MoveType type)
119{
120 switch (type)
121 {
122 case MoveType::Wall: return false;
123 case MoveType::Wrap: return false;
124 case MoveType::Warp: return true;
125 case MoveType::ReverseWarp: return true;
126 }
127}
128
129void Map::setMapdata(int* mapdata)
130{
131 free(this->mapdata);
132 this->mapdata = mapdata;
133}
134
135void Map::setTitle(std::string title)
136{
137 this->title = title;
138}
139
140void Map::setAdjacent(MoveDir dir, MoveType type, int map)
141{
142 Adjacent& cur = adjacents[dir];
143 cur.type = type;
144 if (map != -1) cur.map = map;
145}
146
147void Map::addEntity(EntityData& data)
148{
149 entities.push_back(data);
150}
151
diff --git a/src/map.h b/src/map.h index 22333aa..9177870 100644 --- a/src/map.h +++ b/src/map.h
@@ -1,70 +1,45 @@
1#ifndef MAP_H 1#ifndef MAP_H_74055FC0
2#define MAP_H 2#define MAP_H_74055FC0
3 3
4#include <vector>
4#include <string> 5#include <string>
5#include <list> 6#include <list>
7#include <stdexcept>
6#include <map> 8#include <map>
7 9
8class Entity;
9
10class Map { 10class Map {
11 public: 11public:
12 Map(int id); 12
13 Map() : Map(-1) {} 13 Map(
14 Map(const Map& map); 14 int id,
15 Map(Map&& map); 15 std::vector<int> tiles,
16 ~Map(); 16 std::string title) :
17 Map& operator= (Map other); 17 id_(id),
18 friend void swap(Map& first, Map& second); 18 tiles_(std::move(tiles)),
19 19 title_(std::move(title))
20 enum class MoveType { 20 {
21 Wall, 21 }
22 Wrap, 22
23 Warp, 23 inline size_t getId() const
24 ReverseWarp 24 {
25 }; 25 return id_;
26 26 }
27 enum class MoveDir { 27
28 Left, 28 inline const std::vector<int>& getTiles() const
29 Right, 29 {
30 Up, 30 return tiles_;
31 Down 31 }
32 }; 32
33 33 inline const std::string& getTitle() const
34 struct EntityData { 34 {
35 std::string name; 35 return title_;
36 std::pair<int, int> position; 36 }
37 std::map<std::string, int> items; 37
38 }; 38private:
39 39
40 struct Adjacent { 40 int id_;
41 MoveType type = MoveType::Wall; 41 std::vector<int> tiles_;
42 int map = -1; 42 std::string title_;
43 };
44
45 static MoveType moveTypeForShort(std::string str);
46 static MoveDir moveDirForShort(std::string str);
47 static bool moveTypeTakesMap(MoveType type);
48
49 int getID() const;
50 const int* getMapdata() const;
51 std::string getTitle() const;
52 const Adjacent& getAdjacent(MoveDir dir) const;
53
54 void createEntities(std::list<std::shared_ptr<Entity>>& entities) const;
55 bool operator==(const Map& other) const;
56 bool operator!=(const Map& other) const;
57
58 void setMapdata(int* mapdata);
59 void setTitle(std::string title);
60 void setAdjacent(MoveDir dir, MoveType type, int map);
61 void addEntity(EntityData& data);
62 private:
63 int* mapdata;
64 std::string title;
65 int id;
66 std::list<EntityData> entities;
67 std::map<MoveDir, Adjacent> adjacents;
68}; 43};
69 44
70#endif 45#endif /* end of include guard: MAP_H_74055FC0 */
diff --git a/src/muxer.cpp b/src/muxer.cpp index d831e6d..ecce82b 100644 --- a/src/muxer.cpp +++ b/src/muxer.cpp
@@ -4,6 +4,9 @@
4#include <portaudio.h> 4#include <portaudio.h>
5#include <list> 5#include <list>
6#include <cmath> 6#include <cmath>
7#include <vector>
8#include <stdexcept>
9#include <sstream>
7 10
8#define SAMPLE_RATE (44100) 11#define SAMPLE_RATE (44100)
9#define DELAY_IN_SECS (0.075) 12#define DELAY_IN_SECS (0.075)
@@ -17,11 +20,14 @@ const int delaySize = SAMPLE_RATE * DELAY_IN_SECS;
17class Sound { 20class Sound {
18 public: 21 public:
19 Sound(const char* filename, float vol); 22 Sound(const char* filename, float vol);
20 ~Sound(); 23
21 24 inline bool isDone() const
22 float* ptr; 25 {
26 return pos >= data.size();
27 }
28
29 std::vector<float> data;
23 unsigned long pos; 30 unsigned long pos;
24 unsigned long len;
25 float vol; 31 float vol;
26}; 32};
27 33
@@ -45,29 +51,29 @@ int paMuxerCallback(const void*, void* outputBuffer, unsigned long framesPerBuff
45{ 51{
46 Muxer* muxer = (Muxer*) userData; 52 Muxer* muxer = (Muxer*) userData;
47 float* out = (float*) outputBuffer; 53 float* out = (float*) outputBuffer;
48 54
49 for (unsigned long i = 0; i<framesPerBuffer; i++) 55 for (unsigned long i = 0; i<framesPerBuffer; i++)
50 { 56 {
51 float in = 0.0; 57 float in = 0.0;
52 58
53 for (auto& sound : muxer->playing) 59 for (auto& sound : muxer->playing)
54 { 60 {
55 if (sound.pos < sound.len) 61 if (sound.pos < sound.data.size())
56 { 62 {
57 in += sound.ptr[sound.pos++] * sound.vol; 63 in += sound.data[sound.pos++] * sound.vol;
58 } 64 }
59 } 65 }
60 66
61 if (in > 1) in = 1; 67 if (in > 1) in = 1;
62 if (in < -1) in = -1; 68 if (in < -1) in = -1;
63 69
64 float sample = muxer->delay[muxer->delayPos] * GAIN; 70 float sample = muxer->delay[muxer->delayPos] * GAIN;
65 muxer->delay[muxer->delayPos] = in + (muxer->delay[muxer->delayPos] * FEEDBACK); 71 muxer->delay[muxer->delayPos] = in + (muxer->delay[muxer->delayPos] * FEEDBACK);
66 muxer->delayPos++; 72 muxer->delayPos++;
67 if (muxer->delayPos > delaySize) muxer->delayPos = 0; 73 if (muxer->delayPos > delaySize) muxer->delayPos = 0;
68 *out++ = (in * DRY) + (sample * WET); 74 *out++ = (in * DRY) + (sample * WET);
69 } 75 }
70 76
71 return 0; 77 return 0;
72} 78}
73 79
@@ -76,11 +82,11 @@ static Muxer* muxer;
76void initMuxer() 82void initMuxer()
77{ 83{
78 muxer = new Muxer(); 84 muxer = new Muxer();
79 85
80 dealWithPaError(Pa_Initialize()); 86 dealWithPaError(Pa_Initialize());
81 dealWithPaError(Pa_OpenDefaultStream(&muxer->stream, 0, 1, paFloat32, SAMPLE_RATE, paFramesPerBufferUnspecified, paMuxerCallback, muxer)); 87 dealWithPaError(Pa_OpenDefaultStream(&muxer->stream, 0, 1, paFloat32, SAMPLE_RATE, paFramesPerBufferUnspecified, paMuxerCallback, muxer));
82 dealWithPaError(Pa_StartStream(muxer->stream)); 88 dealWithPaError(Pa_StartStream(muxer->stream));
83 89
84 muxer->delay = (float*) calloc(delaySize, sizeof(float)); 90 muxer->delay = (float*) calloc(delaySize, sizeof(float));
85} 91}
86 92
@@ -89,7 +95,7 @@ void destroyMuxer()
89 dealWithPaError(Pa_AbortStream(muxer->stream)); 95 dealWithPaError(Pa_AbortStream(muxer->stream));
90 dealWithPaError(Pa_CloseStream(muxer->stream)); 96 dealWithPaError(Pa_CloseStream(muxer->stream));
91 dealWithPaError(Pa_Terminate()); 97 dealWithPaError(Pa_Terminate());
92 98
93 free(muxer->delay); 99 free(muxer->delay);
94 delete muxer; 100 delete muxer;
95 muxer = 0; 101 muxer = 0;
@@ -98,8 +104,8 @@ void destroyMuxer()
98void playSound(const char* filename, float vol) 104void playSound(const char* filename, float vol)
99{ 105{
100 // First, clear out any sounds that have finished playing 106 // First, clear out any sounds that have finished playing
101 muxer->playing.remove_if([] (Sound& value) { return value.pos >= value.len; }); 107 muxer->playing.remove_if([] (Sound& value) { return value.isDone(); });
102 108
103 // Then, add the new sound 109 // Then, add the new sound
104 muxer->playing.emplace_back(filename, vol); 110 muxer->playing.emplace_back(filename, vol);
105} 111}
@@ -110,21 +116,18 @@ Sound::Sound(const char* filename, float vol)
110 SNDFILE* file = sf_open(filename, SFM_READ, &info); 116 SNDFILE* file = sf_open(filename, SFM_READ, &info);
111 if (file == nullptr) 117 if (file == nullptr)
112 { 118 {
113 printf("LibSndFile error: %s\n", sf_strerror(file)); 119 std::ostringstream errmsg;
114 exit(-1); 120 errmsg << "LibSndFile error: ";
121 errmsg << sf_strerror(file);
122
123 throw std::logic_error(errmsg.str());
115 } 124 }
116 125
117 ptr = (float*) malloc(info.frames * info.channels * sizeof(float)); 126 data.resize(info.frames * info.channels);
118 len = info.frames * info.channels;
119 pos = 0; 127 pos = 0;
120 this->vol = vol; 128 this->vol = vol;
121
122 sf_readf_float(file, ptr, info.frames);
123
124 sf_close(file);
125}
126 129
127Sound::~Sound() 130 sf_readf_float(file, data.data(), info.frames);
128{ 131
129 free(ptr); 132 sf_close(file);
130} 133}
diff --git a/src/renderer.cpp b/src/renderer.cpp index ffe9d47..3945e09 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp
@@ -56,11 +56,11 @@ static GLuint mesh_normalbuffer;
56static int mesh_numvertices; 56static int mesh_numvertices;
57 57
58GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path) 58GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path)
59{ 59{
60 // Create the shaders 60 // Create the shaders
61 GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); 61 GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
62 GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); 62 GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
63 63
64 // Read the Vertex Shader code from the file 64 // Read the Vertex Shader code from the file
65 std::string VertexShaderCode; 65 std::string VertexShaderCode;
66 std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); 66 std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
@@ -71,7 +71,7 @@ GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path)
71 VertexShaderCode += "\n" + Line; 71 VertexShaderCode += "\n" + Line;
72 VertexShaderStream.close(); 72 VertexShaderStream.close();
73 } 73 }
74 74
75 // Read the Fragment Shader code from the file 75 // Read the Fragment Shader code from the file
76 std::string FragmentShaderCode; 76 std::string FragmentShaderCode;
77 std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); 77 std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
@@ -81,53 +81,53 @@ GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path)
81 FragmentShaderCode += "\n" + Line; 81 FragmentShaderCode += "\n" + Line;
82 FragmentShaderStream.close(); 82 FragmentShaderStream.close();
83 } 83 }
84 84
85 GLint Result = GL_FALSE; 85 GLint Result = GL_FALSE;
86 int InfoLogLength; 86 int InfoLogLength;
87 87
88 // Compile Vertex Shader 88 // Compile Vertex Shader
89 printf("Compiling shader : %s\n", vertex_file_path); 89 printf("Compiling shader : %s\n", vertex_file_path);
90 char const * VertexSourcePointer = VertexShaderCode.c_str(); 90 char const * VertexSourcePointer = VertexShaderCode.c_str();
91 glShaderSource(VertexShaderID, 1, &VertexSourcePointer , nullptr); 91 glShaderSource(VertexShaderID, 1, &VertexSourcePointer , nullptr);
92 glCompileShader(VertexShaderID); 92 glCompileShader(VertexShaderID);
93 93
94 // Check Vertex Shader 94 // Check Vertex Shader
95 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); 95 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
96 glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); 96 glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
97 std::vector<char> VertexShaderErrorMessage(InfoLogLength); 97 std::vector<char> VertexShaderErrorMessage(InfoLogLength);
98 glGetShaderInfoLog(VertexShaderID, InfoLogLength, nullptr, &VertexShaderErrorMessage[0]); 98 glGetShaderInfoLog(VertexShaderID, InfoLogLength, nullptr, &VertexShaderErrorMessage[0]);
99 fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]); 99 fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
100 100
101 // Compile Fragment Shader 101 // Compile Fragment Shader
102 printf("Compiling shader : %s\n", fragment_file_path); 102 printf("Compiling shader : %s\n", fragment_file_path);
103 char const * FragmentSourcePointer = FragmentShaderCode.c_str(); 103 char const * FragmentSourcePointer = FragmentShaderCode.c_str();
104 glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , nullptr); 104 glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , nullptr);
105 glCompileShader(FragmentShaderID); 105 glCompileShader(FragmentShaderID);
106 106
107 // Check Fragment Shader 107 // Check Fragment Shader
108 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); 108 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
109 glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); 109 glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
110 std::vector<char> FragmentShaderErrorMessage(InfoLogLength); 110 std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
111 glGetShaderInfoLog(FragmentShaderID, InfoLogLength, nullptr, &FragmentShaderErrorMessage[0]); 111 glGetShaderInfoLog(FragmentShaderID, InfoLogLength, nullptr, &FragmentShaderErrorMessage[0]);
112 fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]); 112 fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);
113 113
114 // Link the program 114 // Link the program
115 fprintf(stdout, "Linking program\n"); 115 fprintf(stdout, "Linking program\n");
116 GLuint ProgramID = glCreateProgram(); 116 GLuint ProgramID = glCreateProgram();
117 glAttachShader(ProgramID, VertexShaderID); 117 glAttachShader(ProgramID, VertexShaderID);
118 glAttachShader(ProgramID, FragmentShaderID); 118 glAttachShader(ProgramID, FragmentShaderID);
119 glLinkProgram(ProgramID); 119 glLinkProgram(ProgramID);
120 120
121 // Check the program 121 // Check the program
122 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); 122 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
123 glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); 123 glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
124 std::vector<char> ProgramErrorMessage( glm::max(InfoLogLength, int(1)) ); 124 std::vector<char> ProgramErrorMessage( glm::max(InfoLogLength, int(1)) );
125 glGetProgramInfoLog(ProgramID, InfoLogLength, nullptr, &ProgramErrorMessage[0]); 125 glGetProgramInfoLog(ProgramID, InfoLogLength, nullptr, &ProgramErrorMessage[0]);
126 fprintf(stdout, "%s\n", &ProgramErrorMessage[0]); 126 fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
127 127
128 glDeleteShader(VertexShaderID); 128 glDeleteShader(VertexShaderID);
129 glDeleteShader(FragmentShaderID); 129 glDeleteShader(FragmentShaderID);
130 130
131 return ProgramID; 131 return ProgramID;
132} 132}
133 133
@@ -135,14 +135,14 @@ void flipImageData(unsigned char* data, int width, int height, int comps)
135{ 135{
136 unsigned char* data_copy = (unsigned char*) malloc(width*height*comps*sizeof(unsigned char)); 136 unsigned char* data_copy = (unsigned char*) malloc(width*height*comps*sizeof(unsigned char));
137 memcpy(data_copy, data, width*height*comps); 137 memcpy(data_copy, data, width*height*comps);
138 138
139 int row_size = width * comps; 139 int row_size = width * comps;
140 140
141 for (int i=0;i<height;i++) 141 for (int i=0;i<height;i++)
142 { 142 {
143 memcpy(data + (row_size*i), data_copy + (row_size*(height-i-1)), row_size); 143 memcpy(data + (row_size*i), data_copy + (row_size*(height-i-1)), row_size);
144 } 144 }
145 145
146 free(data_copy); 146 free(data_copy);
147} 147}
148 148
@@ -154,11 +154,11 @@ void loadMesh(const char* filename, std::vector<glm::vec3>& out_vertices, std::v
154 fprintf(stderr, "Could not open mesh file %s\n", filename); 154 fprintf(stderr, "Could not open mesh file %s\n", filename);
155 exit(1); 155 exit(1);
156 } 156 }
157 157
158 std::vector<glm::vec3> temp_vertices; 158 std::vector<glm::vec3> temp_vertices;
159 std::vector<glm::vec2> temp_uvs; 159 std::vector<glm::vec2> temp_uvs;
160 std::vector<glm::vec3> temp_normals; 160 std::vector<glm::vec3> temp_normals;
161 161
162 for (;;) 162 for (;;)
163 { 163 {
164 char lineHeader[256]; 164 char lineHeader[256];
@@ -167,7 +167,7 @@ void loadMesh(const char* filename, std::vector<glm::vec3>& out_vertices, std::v
167 { 167 {
168 break; 168 break;
169 } 169 }
170 170
171 if (!strncmp(lineHeader, "v", 2)) 171 if (!strncmp(lineHeader, "v", 2))
172 { 172 {
173 glm::vec3 vertex; 173 glm::vec3 vertex;
@@ -187,7 +187,7 @@ void loadMesh(const char* filename, std::vector<glm::vec3>& out_vertices, std::v
187 { 187 {
188 int vertexIDs[3], uvIDs[3], normalIDs[3]; 188 int vertexIDs[3], uvIDs[3], normalIDs[3];
189 fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIDs[0], &uvIDs[0], &normalIDs[0], &vertexIDs[1], &uvIDs[1], &normalIDs[1], &vertexIDs[2], &uvIDs[2], &normalIDs[2]); 189 fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIDs[0], &uvIDs[0], &normalIDs[0], &vertexIDs[1], &uvIDs[1], &normalIDs[1], &vertexIDs[2], &uvIDs[2], &normalIDs[2]);
190 190
191 for (int i=0; i<3; i++) 191 for (int i=0; i<3; i++)
192 { 192 {
193 out_vertices.push_back(temp_vertices[vertexIDs[i] - 1]); 193 out_vertices.push_back(temp_vertices[vertexIDs[i] - 1]);
@@ -202,24 +202,24 @@ void setFramebufferSize(GLFWwindow* w, int width, int height)
202{ 202{
203 buffer_width = width; 203 buffer_width = width;
204 buffer_height = height; 204 buffer_height = height;
205 205
206 glDeleteFramebuffers(1, &bloom_framebuffer); 206 glDeleteFramebuffers(1, &bloom_framebuffer);
207 glDeleteRenderbuffers(1, &bloom_depthbuffer); 207 glDeleteRenderbuffers(1, &bloom_depthbuffer);
208 208
209 glGenFramebuffers(1, &bloom_framebuffer); 209 glGenFramebuffers(1, &bloom_framebuffer);
210 glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); 210 glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer);
211 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT1}; 211 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT1};
212 glDrawBuffers(1, DrawBuffers); 212 glDrawBuffers(1, DrawBuffers);
213 213
214 glGenRenderbuffers(1, &bloom_depthbuffer); 214 glGenRenderbuffers(1, &bloom_depthbuffer);
215 glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); 215 glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer);
216 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); 216 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
217 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); 217 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer);
218 218
219 glDeleteTextures(1, &preBloomTex); 219 glDeleteTextures(1, &preBloomTex);
220 glDeleteTextures(1, &bloomPassTex1); 220 glDeleteTextures(1, &bloomPassTex1);
221 glDeleteTextures(1, &bloomPassTex2); 221 glDeleteTextures(1, &bloomPassTex2);
222 222
223 glGenTextures(1, &preBloomTex); 223 glGenTextures(1, &preBloomTex);
224 glBindTexture(GL_TEXTURE_2D, preBloomTex); 224 glBindTexture(GL_TEXTURE_2D, preBloomTex);
225 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 225 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
@@ -227,7 +227,7 @@ void setFramebufferSize(GLFWwindow* w, int width, int height)
227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
230 230
231 glGenTextures(1, &bloomPassTex1); 231 glGenTextures(1, &bloomPassTex1);
232 glBindTexture(GL_TEXTURE_2D, bloomPassTex1); 232 glBindTexture(GL_TEXTURE_2D, bloomPassTex1);
233 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 233 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
@@ -235,7 +235,7 @@ void setFramebufferSize(GLFWwindow* w, int width, int height)
235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
236 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 236 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
238 238
239 glGenTextures(1, &bloomPassTex2); 239 glGenTextures(1, &bloomPassTex2);
240 glBindTexture(GL_TEXTURE_2D, bloomPassTex2); 240 glBindTexture(GL_TEXTURE_2D, bloomPassTex2);
241 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 241 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
@@ -252,20 +252,20 @@ GLFWwindow* initRenderer()
252 fprintf(stderr, "Renderer already initialized\n"); 252 fprintf(stderr, "Renderer already initialized\n");
253 exit(-1); 253 exit(-1);
254 } 254 }
255 255
256 // Initialize GLFW 256 // Initialize GLFW
257 if (!glfwInit()) 257 if (!glfwInit())
258 { 258 {
259 fprintf(stderr, "Failed to initialize GLFW\n"); 259 fprintf(stderr, "Failed to initialize GLFW\n");
260 exit(-1); 260 exit(-1);
261 } 261 }
262 262
263 glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing 263 glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
264 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3 264 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3
265 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 265 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
266 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this 266 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this
267 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 267 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
268 268
269 // Create a window 269 // Create a window
270 window = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr); 270 window = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr);
271 if (window == nullptr) 271 if (window == nullptr)
@@ -274,7 +274,7 @@ GLFWwindow* initRenderer()
274 glfwTerminate(); 274 glfwTerminate();
275 exit(-1); 275 exit(-1);
276 } 276 }
277 277
278 glfwMakeContextCurrent(window); 278 glfwMakeContextCurrent(window);
279 glewExperimental = true; // Needed in core profile 279 glewExperimental = true; // Needed in core profile
280 if (glewInit() != GLEW_OK) 280 if (glewInit() != GLEW_OK)
@@ -282,37 +282,37 @@ GLFWwindow* initRenderer()
282 fprintf(stderr, "Failed to initialize GLEW\n"); 282 fprintf(stderr, "Failed to initialize GLEW\n");
283 exit(-1); 283 exit(-1);
284 } 284 }
285 285
286 glfwSetFramebufferSizeCallback(window, &setFramebufferSize); 286 glfwSetFramebufferSizeCallback(window, &setFramebufferSize);
287 287
288 // Set up vertex array object 288 // Set up vertex array object
289 glGenVertexArrays(1, &VertexArrayID); 289 glGenVertexArrays(1, &VertexArrayID);
290 glBindVertexArray(VertexArrayID); 290 glBindVertexArray(VertexArrayID);
291 291
292 // Enable depth testing 292 // Enable depth testing
293 glEnable(GL_DEPTH_TEST); 293 glEnable(GL_DEPTH_TEST);
294 glDepthFunc(GL_LESS); 294 glDepthFunc(GL_LESS);
295 295
296 // Enable blending 296 // Enable blending
297 glEnable(GL_BLEND); 297 glEnable(GL_BLEND);
298 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 298 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
299 299
300 // Set up the framebuffer 300 // Set up the framebuffer
301 glGenFramebuffers(1, &generic_framebuffer); 301 glGenFramebuffers(1, &generic_framebuffer);
302 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); 302 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer);
303 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; 303 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
304 glDrawBuffers(1, DrawBuffers); 304 glDrawBuffers(1, DrawBuffers);
305 305
306 glGenFramebuffers(1, &bloom_framebuffer); 306 glGenFramebuffers(1, &bloom_framebuffer);
307 glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); 307 glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer);
308 GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1}; 308 GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1};
309 glDrawBuffers(1, DrawBuffers2); 309 glDrawBuffers(1, DrawBuffers2);
310 310
311 glGenRenderbuffers(1, &bloom_depthbuffer); 311 glGenRenderbuffers(1, &bloom_depthbuffer);
312 glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); 312 glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer);
313 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1024, 768); 313 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1024, 768);
314 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); 314 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer);
315 315
316 // Set up the NTSC rendering buffers 316 // Set up the NTSC rendering buffers
317 glGenTextures(1, &renderedTex1); 317 glGenTextures(1, &renderedTex1);
318 glBindTexture(GL_TEXTURE_2D, renderedTex1); 318 glBindTexture(GL_TEXTURE_2D, renderedTex1);
@@ -322,7 +322,7 @@ GLFWwindow* initRenderer()
322 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 322 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
323 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 323 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
324 renderedTexBufs[0] = renderedTex1; 324 renderedTexBufs[0] = renderedTex1;
325 325
326 glGenTextures(1, &renderedTex2); 326 glGenTextures(1, &renderedTex2);
327 glBindTexture(GL_TEXTURE_2D, renderedTex2); 327 glBindTexture(GL_TEXTURE_2D, renderedTex2);
328 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 328 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
@@ -331,7 +331,7 @@ GLFWwindow* initRenderer()
331 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 331 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
332 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 332 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
333 renderedTexBufs[1] = renderedTex2; 333 renderedTexBufs[1] = renderedTex2;
334 334
335 // Set up bloom rendering buffers 335 // Set up bloom rendering buffers
336 glGenTextures(1, &preBloomTex); 336 glGenTextures(1, &preBloomTex);
337 glBindTexture(GL_TEXTURE_2D, preBloomTex); 337 glBindTexture(GL_TEXTURE_2D, preBloomTex);
@@ -340,7 +340,7 @@ GLFWwindow* initRenderer()
340 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 340 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
341 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 341 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
342 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 342 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
343 343
344 glGenTextures(1, &bloomPassTex1); 344 glGenTextures(1, &bloomPassTex1);
345 glBindTexture(GL_TEXTURE_2D, bloomPassTex1); 345 glBindTexture(GL_TEXTURE_2D, bloomPassTex1);
346 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 346 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
@@ -348,7 +348,7 @@ GLFWwindow* initRenderer()
348 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 348 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
349 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 349 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
350 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 350 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
351 351
352 glGenTextures(1, &bloomPassTex2); 352 glGenTextures(1, &bloomPassTex2);
353 glBindTexture(GL_TEXTURE_2D, bloomPassTex2); 353 glBindTexture(GL_TEXTURE_2D, bloomPassTex2);
354 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 354 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
@@ -356,31 +356,32 @@ GLFWwindow* initRenderer()
356 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 356 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
357 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 357 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
358 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 358 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
359 359
360 curBuf = 0; 360 curBuf = 0;
361 361
362 // Load the mesh! 362 // Load the mesh!
363 std::vector<glm::vec3> mesh_vertices; 363 std::vector<glm::vec3> mesh_vertices;
364 std::vector<glm::vec2> mesh_uvs; 364 std::vector<glm::vec2> mesh_uvs;
365 std::vector<glm::vec3> mesh_normals; 365 std::vector<glm::vec3> mesh_normals;
366
366 loadMesh("res/monitor-old.obj", mesh_vertices, mesh_uvs, mesh_normals); 367 loadMesh("res/monitor-old.obj", mesh_vertices, mesh_uvs, mesh_normals);
367 368
368 mesh_numvertices = mesh_vertices.size(); 369 mesh_numvertices = mesh_vertices.size();
369 370
370 glGenBuffers(1, &mesh_vertexbuffer); 371 glGenBuffers(1, &mesh_vertexbuffer);
371 glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); 372 glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer);
372 glBufferData(GL_ARRAY_BUFFER, mesh_vertices.size() * sizeof(glm::vec3), &mesh_vertices[0], GL_STATIC_DRAW); 373 glBufferData(GL_ARRAY_BUFFER, mesh_vertices.size() * sizeof(glm::vec3), &mesh_vertices[0], GL_STATIC_DRAW);
373 374
374 glGenBuffers(1, &mesh_uvbuffer); 375 glGenBuffers(1, &mesh_uvbuffer);
375 glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); 376 glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer);
376 glBufferData(GL_ARRAY_BUFFER, mesh_uvs.size() * sizeof(glm::vec3), &mesh_uvs[0], GL_STATIC_DRAW); 377 glBufferData(GL_ARRAY_BUFFER, mesh_uvs.size() * sizeof(glm::vec3), &mesh_uvs[0], GL_STATIC_DRAW);
377 378
378 glGenBuffers(1, &mesh_normalbuffer); 379 glGenBuffers(1, &mesh_normalbuffer);
379 glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); 380 glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer);
380 glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(glm::vec3), &mesh_normals[0], GL_STATIC_DRAW); 381 glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(glm::vec3), &mesh_normals[0], GL_STATIC_DRAW);
381 382
382 // Load the vertices of a flat surface 383 // Load the vertices of a flat surface
383 GLfloat g_quad_vertex_buffer_data[] = { 384 GLfloat g_quad_vertex_buffer_data[] = {
384 -1.0f, -1.0f, 0.0f, 385 -1.0f, -1.0f, 0.0f,
385 1.0f, -1.0f, 0.0f, 386 1.0f, -1.0f, 0.0f,
386 -1.0f, 1.0f, 0.0f, 387 -1.0f, 1.0f, 0.0f,
@@ -392,7 +393,7 @@ GLFWwindow* initRenderer()
392 glGenBuffers(1, &quad_vertexbuffer); 393 glGenBuffers(1, &quad_vertexbuffer);
393 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); 394 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
394 glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW); 395 glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);
395 396
396 glGenTextures(1, &artifactsTex); 397 glGenTextures(1, &artifactsTex);
397 glBindTexture(GL_TEXTURE_2D, artifactsTex); 398 glBindTexture(GL_TEXTURE_2D, artifactsTex);
398 int atdw, atdh; 399 int atdw, atdh;
@@ -403,7 +404,7 @@ GLFWwindow* initRenderer()
403 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 404 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
404 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); 405 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
405 glGenerateMipmap(GL_TEXTURE_2D); 406 glGenerateMipmap(GL_TEXTURE_2D);
406 407
407 glGenTextures(1, &scanlinesTex); 408 glGenTextures(1, &scanlinesTex);
408 glBindTexture(GL_TEXTURE_2D, scanlinesTex); 409 glBindTexture(GL_TEXTURE_2D, scanlinesTex);
409 int stdw, stdh; 410 int stdw, stdh;
@@ -414,7 +415,7 @@ GLFWwindow* initRenderer()
414 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 415 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
415 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); 416 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
416 glGenerateMipmap(GL_TEXTURE_2D); 417 glGenerateMipmap(GL_TEXTURE_2D);
417 418
418 // Load the shaders 419 // Load the shaders
419 ntscShader = LoadShaders("shaders/ntsc.vertex", "shaders/ntsc.fragment"); 420 ntscShader = LoadShaders("shaders/ntsc.vertex", "shaders/ntsc.fragment");
420 finalShader = LoadShaders("shaders/final.vertex", "shaders/final.fragment"); 421 finalShader = LoadShaders("shaders/final.vertex", "shaders/final.fragment");
@@ -422,9 +423,9 @@ GLFWwindow* initRenderer()
422 fillShader = LoadShaders("shaders/fill.vertex", "shaders/fill.fragment"); 423 fillShader = LoadShaders("shaders/fill.vertex", "shaders/fill.fragment");
423 bloom1Shader = LoadShaders("shaders/bloom1.vertex", "shaders/bloom1.fragment"); 424 bloom1Shader = LoadShaders("shaders/bloom1.vertex", "shaders/bloom1.fragment");
424 bloom2Shader = LoadShaders("shaders/bloom2.vertex", "shaders/bloom2.fragment"); 425 bloom2Shader = LoadShaders("shaders/bloom2.vertex", "shaders/bloom2.fragment");
425 426
426 rendererInitialized = true; 427 rendererInitialized = true;
427 428
428 return window; 429 return window;
429} 430}
430 431
@@ -435,13 +436,13 @@ void destroyRenderer()
435 fprintf(stderr, "Renderer not initialized\n"); 436 fprintf(stderr, "Renderer not initialized\n");
436 exit(-1); 437 exit(-1);
437 } 438 }
438 439
439 // Delete the plane buffer 440 // Delete the plane buffer
440 glDeleteBuffers(1, &quad_vertexbuffer); 441 glDeleteBuffers(1, &quad_vertexbuffer);
441 glDeleteBuffers(1, &mesh_vertexbuffer); 442 glDeleteBuffers(1, &mesh_vertexbuffer);
442 glDeleteBuffers(1, &mesh_uvbuffer); 443 glDeleteBuffers(1, &mesh_uvbuffer);
443 glDeleteBuffers(1, &mesh_normalbuffer); 444 glDeleteBuffers(1, &mesh_normalbuffer);
444 445
445 // Delete the shaders 446 // Delete the shaders
446 glDeleteProgram(ntscShader); 447 glDeleteProgram(ntscShader);
447 glDeleteProgram(finalShader); 448 glDeleteProgram(finalShader);
@@ -449,7 +450,7 @@ void destroyRenderer()
449 glDeleteProgram(fillShader); 450 glDeleteProgram(fillShader);
450 glDeleteProgram(bloom1Shader); 451 glDeleteProgram(bloom1Shader);
451 glDeleteProgram(bloom2Shader); 452 glDeleteProgram(bloom2Shader);
452 453
453 // Delete the NTSC rendering buffers 454 // Delete the NTSC rendering buffers
454 glDeleteTextures(1, &renderedTex1); 455 glDeleteTextures(1, &renderedTex1);
455 glDeleteTextures(1, &renderedTex2); 456 glDeleteTextures(1, &renderedTex2);
@@ -458,18 +459,18 @@ void destroyRenderer()
458 glDeleteTextures(1, &preBloomTex); 459 glDeleteTextures(1, &preBloomTex);
459 glDeleteTextures(1, &bloomPassTex1); 460 glDeleteTextures(1, &bloomPassTex1);
460 glDeleteTextures(1, &bloomPassTex2); 461 glDeleteTextures(1, &bloomPassTex2);
461 462
462 // Delete the framebuffer 463 // Delete the framebuffer
463 glDeleteRenderbuffers(1, &bloom_depthbuffer); 464 glDeleteRenderbuffers(1, &bloom_depthbuffer);
464 glDeleteFramebuffers(1, &bloom_framebuffer); 465 glDeleteFramebuffers(1, &bloom_framebuffer);
465 glDeleteFramebuffers(1, &generic_framebuffer); 466 glDeleteFramebuffers(1, &generic_framebuffer);
466 467
467 // Delete the VAO 468 // Delete the VAO
468 glDeleteVertexArrays(1, &VertexArrayID); 469 glDeleteVertexArrays(1, &VertexArrayID);
469 470
470 // Kill the window 471 // Kill the window
471 glfwTerminate(); 472 glfwTerminate();
472 473
473 rendererInitialized = false; 474 rendererInitialized = false;
474} 475}
475 476
@@ -480,10 +481,10 @@ Texture::Texture(int width, int height)
480 fprintf(stderr, "Renderer not initialized\n"); 481 fprintf(stderr, "Renderer not initialized\n");
481 exit(-1); 482 exit(-1);
482 } 483 }
483 484
484 this->width = width; 485 this->width = width;
485 this->height = height; 486 this->height = height;
486 487
487 glGenTextures(1, &texID); 488 glGenTextures(1, &texID);
488 glBindTexture(GL_TEXTURE_2D, texID); 489 glBindTexture(GL_TEXTURE_2D, texID);
489 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); 490 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
@@ -500,7 +501,7 @@ Texture::Texture(const char* filename)
500 fprintf(stderr, "Renderer not initialized\n"); 501 fprintf(stderr, "Renderer not initialized\n");
501 exit(-1); 502 exit(-1);
502 } 503 }
503 504
504 glGenTextures(1, &texID); 505 glGenTextures(1, &texID);
505 glBindTexture(GL_TEXTURE_2D, texID); 506 glBindTexture(GL_TEXTURE_2D, texID);
506 unsigned char* data = stbi_load(filename, &width, &height, 0, 4); 507 unsigned char* data = stbi_load(filename, &width, &height, 0, 4);
@@ -520,14 +521,14 @@ Texture::Texture(const Texture& tex)
520 fprintf(stderr, "Renderer not initialized\n"); 521 fprintf(stderr, "Renderer not initialized\n");
521 exit(-1); 522 exit(-1);
522 } 523 }
523 524
524 width = tex.width; 525 width = tex.width;
525 height = tex.height; 526 height = tex.height;
526 527
527 unsigned char* data = (unsigned char*) malloc(4 * width * height); 528 unsigned char* data = (unsigned char*) malloc(4 * width * height);
528 glBindTexture(GL_TEXTURE_2D, tex.texID); 529 glBindTexture(GL_TEXTURE_2D, tex.texID);
529 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 530 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
530 531
531 glGenTextures(1, &texID); 532 glGenTextures(1, &texID);
532 glBindTexture(GL_TEXTURE_2D, texID); 533 glBindTexture(GL_TEXTURE_2D, texID);
533 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 534 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
@@ -535,7 +536,7 @@ Texture::Texture(const Texture& tex)
535 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 536 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
536 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 537 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
537 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 538 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
538 539
539 free(data); 540 free(data);
540} 541}
541 542
@@ -551,14 +552,14 @@ Texture::~Texture()
551 fprintf(stderr, "Renderer not initialized\n"); 552 fprintf(stderr, "Renderer not initialized\n");
552 exit(-1); 553 exit(-1);
553 } 554 }
554 555
555 glDeleteTextures(1, &texID); 556 glDeleteTextures(1, &texID);
556} 557}
557 558
558Texture& Texture::operator= (Texture tex) 559Texture& Texture::operator= (Texture tex)
559{ 560{
560 swap(*this, tex); 561 swap(*this, tex);
561 562
562 return *this; 563 return *this;
563} 564}
564 565
@@ -576,17 +577,17 @@ void Texture::fill(Rectangle dstrect, int r, int g, int b)
576 fprintf(stderr, "Renderer not initialized\n"); 577 fprintf(stderr, "Renderer not initialized\n");
577 exit(-1); 578 exit(-1);
578 } 579 }
579 580
580 // Target the framebuffer 581 // Target the framebuffer
581 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); 582 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer);
582 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); 583 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0);
583 584
584 // Set up the vertex attributes 585 // Set up the vertex attributes
585 GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; 586 GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0;
586 GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); 587 GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0);
587 GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; 588 GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0;
588 GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); 589 GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0);
589 590
590 GLfloat vertexbuffer_data[] = { 591 GLfloat vertexbuffer_data[] = {
591 minx, miny, 592 minx, miny,
592 maxx, miny, 593 maxx, miny,
@@ -601,14 +602,14 @@ void Texture::fill(Rectangle dstrect, int r, int g, int b)
601 glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); 602 glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW);
602 glEnableVertexAttribArray(0); 603 glEnableVertexAttribArray(0);
603 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); 604 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
604 605
605 glViewport(0, 0, width, height); 606 glViewport(0, 0, width, height);
606 glClear(GL_DEPTH_BUFFER_BIT); 607 glClear(GL_DEPTH_BUFFER_BIT);
607 glUseProgram(fillShader); 608 glUseProgram(fillShader);
608 glUniform3f(glGetUniformLocation(fillShader, "vecColor"), r / 255.0, g / 255.0, b / 255.0); 609 glUniform3f(glGetUniformLocation(fillShader, "vecColor"), r / 255.0, g / 255.0, b / 255.0);
609 610
610 glDrawArrays(GL_TRIANGLES, 0, 6); 611 glDrawArrays(GL_TRIANGLES, 0, 6);
611 612
612 glDisableVertexAttribArray(0); 613 glDisableVertexAttribArray(0);
613 glDeleteBuffers(1, &vertexbuffer); 614 glDeleteBuffers(1, &vertexbuffer);
614} 615}
@@ -620,19 +621,19 @@ void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect,
620 fprintf(stderr, "Renderer not initialized\n"); 621 fprintf(stderr, "Renderer not initialized\n");
621 exit(-1); 622 exit(-1);
622 } 623 }
623 624
624 alpha = glm::clamp(alpha, 0.0, 1.0); 625 alpha = glm::clamp(alpha, 0.0, 1.0);
625 626
626 // Target the framebuffer 627 // Target the framebuffer
627 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); 628 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer);
628 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); 629 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0);
629 630
630 // Set up the vertex attributes 631 // Set up the vertex attributes
631 GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; 632 GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0;
632 GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); 633 GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0);
633 GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; 634 GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0;
634 GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); 635 GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0);
635 636
636 GLfloat vertexbuffer_data[] = { 637 GLfloat vertexbuffer_data[] = {
637 minx, miny, 638 minx, miny,
638 maxx, miny, 639 maxx, miny,
@@ -645,12 +646,12 @@ void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect,
645 glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); 646 glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW);
646 glEnableVertexAttribArray(0); 647 glEnableVertexAttribArray(0);
647 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); 648 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
648 649
649 GLfloat minu = (GLfloat) srcrect.x / srctex.width; 650 GLfloat minu = (GLfloat) srcrect.x / srctex.width;
650 GLfloat minv = 1 - ((GLfloat) srcrect.y / srctex.height); 651 GLfloat minv = 1 - ((GLfloat) srcrect.y / srctex.height);
651 GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / srctex.width; 652 GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / srctex.width;
652 GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / srctex.height); 653 GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / srctex.height);
653 654
654 GLfloat texcoordbuffer_data[] = { 655 GLfloat texcoordbuffer_data[] = {
655 minu, minv, 656 minu, minv,
656 maxu, minv, 657 maxu, minv,
@@ -663,20 +664,20 @@ void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect,
663 glBufferData(GL_ARRAY_BUFFER, sizeof(texcoordbuffer_data), texcoordbuffer_data, GL_STATIC_DRAW); 664 glBufferData(GL_ARRAY_BUFFER, sizeof(texcoordbuffer_data), texcoordbuffer_data, GL_STATIC_DRAW);
664 glEnableVertexAttribArray(1); 665 glEnableVertexAttribArray(1);
665 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); 666 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
666 667
667 // Set up the shader 668 // Set up the shader
668 glUseProgram(blitShader); 669 glUseProgram(blitShader);
669 glClear(GL_DEPTH_BUFFER_BIT); 670 glClear(GL_DEPTH_BUFFER_BIT);
670 glViewport(0, 0, width, height); 671 glViewport(0, 0, width, height);
671 672
672 glActiveTexture(GL_TEXTURE0); 673 glActiveTexture(GL_TEXTURE0);
673 glBindTexture(GL_TEXTURE_2D, srctex.texID); 674 glBindTexture(GL_TEXTURE_2D, srctex.texID);
674 glUniform1i(glGetUniformLocation(blitShader, "srctex"), 0); 675 glUniform1i(glGetUniformLocation(blitShader, "srctex"), 0);
675 glUniform1f(glGetUniformLocation(blitShader, "alpha"), alpha); 676 glUniform1f(glGetUniformLocation(blitShader, "alpha"), alpha);
676 677
677 // Blit! 678 // Blit!
678 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 679 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
679 680
680 // Unload everything 681 // Unload everything
681 glDisableVertexAttribArray(1); 682 glDisableVertexAttribArray(1);
682 glDisableVertexAttribArray(0); 683 glDisableVertexAttribArray(0);
@@ -691,11 +692,11 @@ void bloomPass1(GLuint srcTex, GLuint dstTex, bool horizontal, glm::vec2 srcRes,
691 glViewport(0,0,dstRes.x,dstRes.y); 692 glViewport(0,0,dstRes.x,dstRes.y);
692 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 693 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
693 glUseProgram(bloom1Shader); 694 glUseProgram(bloom1Shader);
694 695
695 glActiveTexture(GL_TEXTURE0); 696 glActiveTexture(GL_TEXTURE0);
696 glBindTexture(GL_TEXTURE_2D, srcTex); 697 glBindTexture(GL_TEXTURE_2D, srcTex);
697 glUniform1i(glGetUniformLocation(bloom1Shader, "inTex"), 0); 698 glUniform1i(glGetUniformLocation(bloom1Shader, "inTex"), 0);
698 699
699 glm::vec2 offset = glm::vec2(0.0); 700 glm::vec2 offset = glm::vec2(0.0);
700 if (horizontal) 701 if (horizontal)
701 { 702 {
@@ -703,9 +704,9 @@ void bloomPass1(GLuint srcTex, GLuint dstTex, bool horizontal, glm::vec2 srcRes,
703 } else { 704 } else {
704 offset.y = 1.2/srcRes.y; 705 offset.y = 1.2/srcRes.y;
705 } 706 }
706 707
707 glUniform2f(glGetUniformLocation(bloom1Shader, "offset"), offset.x, offset.y); 708 glUniform2f(glGetUniformLocation(bloom1Shader, "offset"), offset.x, offset.y);
708 709
709 glEnableVertexAttribArray(0); 710 glEnableVertexAttribArray(0);
710 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); 711 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
711 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); 712 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
@@ -720,17 +721,17 @@ void Texture::renderScreen() const
720 fprintf(stderr, "Renderer not initialized\n"); 721 fprintf(stderr, "Renderer not initialized\n");
721 exit(-1); 722 exit(-1);
722 } 723 }
723 724
724 // First we're going to composite our frame with the previous frame 725 // First we're going to composite our frame with the previous frame
725 // We start by setting up the framebuffer 726 // We start by setting up the framebuffer
726 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); 727 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer);
727 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexBufs[curBuf], 0); 728 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexBufs[curBuf], 0);
728 729
729 // Set up the shader 730 // Set up the shader
730 glViewport(0,0,GAME_WIDTH,GAME_HEIGHT); 731 glViewport(0,0,GAME_WIDTH,GAME_HEIGHT);
731 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 732 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
732 glUseProgram(ntscShader); 733 glUseProgram(ntscShader);
733 734
734 // Use the current frame texture, nearest neighbor and clamped to edge 735 // Use the current frame texture, nearest neighbor and clamped to edge
735 glActiveTexture(GL_TEXTURE0); 736 glActiveTexture(GL_TEXTURE0);
736 glBindTexture(GL_TEXTURE_2D, texID); 737 glBindTexture(GL_TEXTURE_2D, texID);
@@ -739,7 +740,7 @@ void Texture::renderScreen() const
739 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 740 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
740 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 741 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
741 glUniform1i(glGetUniformLocation(ntscShader, "curFrameSampler"), 0); 742 glUniform1i(glGetUniformLocation(ntscShader, "curFrameSampler"), 0);
742 743
743 // Use the previous frame composite texture, nearest neighbor and clamped to edge 744 // Use the previous frame composite texture, nearest neighbor and clamped to edge
744 glActiveTexture(GL_TEXTURE1); 745 glActiveTexture(GL_TEXTURE1);
745 glBindTexture(GL_TEXTURE_2D, renderedTexBufs[(curBuf + 1) % 2]); 746 glBindTexture(GL_TEXTURE_2D, renderedTexBufs[(curBuf + 1) % 2]);
@@ -748,13 +749,13 @@ void Texture::renderScreen() const
748 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 749 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
749 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 750 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
750 glUniform1i(glGetUniformLocation(ntscShader, "prevFrameSampler"), 1); 751 glUniform1i(glGetUniformLocation(ntscShader, "prevFrameSampler"), 1);
751 752
752 // Load the NTSC artifact texture 753 // Load the NTSC artifact texture
753 glActiveTexture(GL_TEXTURE2); 754 glActiveTexture(GL_TEXTURE2);
754 glBindTexture(GL_TEXTURE_2D, artifactsTex); 755 glBindTexture(GL_TEXTURE_2D, artifactsTex);
755 glUniform1i(glGetUniformLocation(ntscShader, "NTSCArtifactSampler"), 2); 756 glUniform1i(glGetUniformLocation(ntscShader, "NTSCArtifactSampler"), 2);
756 glUniform1f(glGetUniformLocation(ntscShader, "NTSCLerp"), curBuf * 1.0); 757 glUniform1f(glGetUniformLocation(ntscShader, "NTSCLerp"), curBuf * 1.0);
757 758
758 if ((rand() % 60) == 0) 759 if ((rand() % 60) == 0)
759 { 760 {
760 // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect! 761 // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect!
@@ -762,7 +763,7 @@ void Texture::renderScreen() const
762 } else { 763 } else {
763 glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0); 764 glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0);
764 } 765 }
765 766
766 // Render our composition 767 // Render our composition
767 glEnableVertexAttribArray(0); 768 glEnableVertexAttribArray(0);
768 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); 769 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
@@ -776,7 +777,7 @@ void Texture::renderScreen() const
776 glViewport(0,0,buffer_width,buffer_height); 777 glViewport(0,0,buffer_width,buffer_height);
777 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 778 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
778 glUseProgram(finalShader); 779 glUseProgram(finalShader);
779 780
780 // Use the composited frame texture, linearly filtered and filling in black for the border 781 // Use the composited frame texture, linearly filtered and filling in black for the border
781 glActiveTexture(GL_TEXTURE0); 782 glActiveTexture(GL_TEXTURE0);
782 glBindTexture(GL_TEXTURE_2D, renderedTexBufs[curBuf]); 783 glBindTexture(GL_TEXTURE_2D, renderedTexBufs[curBuf]);
@@ -788,70 +789,70 @@ void Texture::renderScreen() const
788 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); 789 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
789 glGenerateMipmap(GL_TEXTURE_2D); 790 glGenerateMipmap(GL_TEXTURE_2D);
790 glUniform1i(glGetUniformLocation(finalShader, "rendertex"), 0); 791 glUniform1i(glGetUniformLocation(finalShader, "rendertex"), 0);
791 792
792 // Use the scanlines texture 793 // Use the scanlines texture
793 glActiveTexture(GL_TEXTURE1); 794 glActiveTexture(GL_TEXTURE1);
794 glBindTexture(GL_TEXTURE_2D, scanlinesTex); 795 glBindTexture(GL_TEXTURE_2D, scanlinesTex);
795 glUniform1i(glGetUniformLocation(finalShader, "scanlinestex"), 1); 796 glUniform1i(glGetUniformLocation(finalShader, "scanlinestex"), 1);
796 797
797 // Initialize the MVP matrices 798 // Initialize the MVP matrices
798 glm::mat4 p_matrix = glm::perspective(glm::radians(25.0f), (float) buffer_width / (float) buffer_height, 0.1f, 100.0f); 799 glm::mat4 p_matrix = glm::perspective(glm::radians(25.0f), (float) buffer_width / (float) buffer_height, 0.1f, 100.0f);
799 glm::mat4 v_matrix = glm::lookAt(glm::vec3(3.75,0,0), glm::vec3(0,0,0), glm::vec3(0,1,0)); 800 glm::mat4 v_matrix = glm::lookAt(glm::vec3(3.75,0,0), glm::vec3(0,0,0), glm::vec3(0,1,0));
800 glm::mat4 m_matrix = glm::mat4(1.0); 801 glm::mat4 m_matrix = glm::mat4(1.0);
801 glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix; 802 glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix;
802 803
803 glUniformMatrix4fv(glGetUniformLocation(finalShader, "MVP"), 1, GL_FALSE, &mvp_matrix[0][0]); 804 glUniformMatrix4fv(glGetUniformLocation(finalShader, "MVP"), 1, GL_FALSE, &mvp_matrix[0][0]);
804 glUniformMatrix4fv(glGetUniformLocation(finalShader, "worldMat"), 1, GL_FALSE, &m_matrix[0][0]); 805 glUniformMatrix4fv(glGetUniformLocation(finalShader, "worldMat"), 1, GL_FALSE, &m_matrix[0][0]);
805 glUniform2f(glGetUniformLocation(finalShader, "resolution"), buffer_width, buffer_height); 806 glUniform2f(glGetUniformLocation(finalShader, "resolution"), buffer_width, buffer_height);
806 glUniform1f(glGetUniformLocation(finalShader, "iGlobalTime"), glfwGetTime()); 807 glUniform1f(glGetUniformLocation(finalShader, "iGlobalTime"), glfwGetTime());
807 glUniform3f(glGetUniformLocation(finalShader, "frameColor"), 0.76f, 0.78f, 0.81f); 808 glUniform3f(glGetUniformLocation(finalShader, "frameColor"), 0.76f, 0.78f, 0.81f);
808 809
809 glEnableVertexAttribArray(0); 810 glEnableVertexAttribArray(0);
810 glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); 811 glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer);
811 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); 812 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
812 813
813 glEnableVertexAttribArray(1); 814 glEnableVertexAttribArray(1);
814 glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); 815 glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer);
815 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); 816 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
816 817
817 glEnableVertexAttribArray(2); 818 glEnableVertexAttribArray(2);
818 glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); 819 glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer);
819 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); 820 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
820 821
821 glDrawArrays(GL_TRIANGLES, 0, mesh_numvertices); 822 glDrawArrays(GL_TRIANGLES, 0, mesh_numvertices);
822 glDisableVertexAttribArray(2); 823 glDisableVertexAttribArray(2);
823 glDisableVertexAttribArray(1); 824 glDisableVertexAttribArray(1);
824 glDisableVertexAttribArray(0); 825 glDisableVertexAttribArray(0);
825 826
826 // First pass of bloom! 827 // First pass of bloom!
827 glm::vec2 buffer_size = glm::vec2(buffer_width, buffer_height); 828 glm::vec2 buffer_size = glm::vec2(buffer_width, buffer_height);
828 bloomPass1(preBloomTex, bloomPassTex1, true, buffer_size, buffer_size / 4.0f); 829 bloomPass1(preBloomTex, bloomPassTex1, true, buffer_size, buffer_size / 4.0f);
829 bloomPass1(bloomPassTex1, bloomPassTex2, false, buffer_size / 4.0f, buffer_size / 4.0f); 830 bloomPass1(bloomPassTex1, bloomPassTex2, false, buffer_size / 4.0f, buffer_size / 4.0f);
830 831
831 // Do the second pass of bloom and render to screen 832 // Do the second pass of bloom and render to screen
832 glBindFramebuffer(GL_FRAMEBUFFER, 0); 833 glBindFramebuffer(GL_FRAMEBUFFER, 0);
833 glViewport(0, 0, buffer_width, buffer_height); 834 glViewport(0, 0, buffer_width, buffer_height);
834 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 835 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
835 glUseProgram(bloom2Shader); 836 glUseProgram(bloom2Shader);
836 837
837 glActiveTexture(GL_TEXTURE0); 838 glActiveTexture(GL_TEXTURE0);
838 glBindTexture(GL_TEXTURE_2D, preBloomTex); 839 glBindTexture(GL_TEXTURE_2D, preBloomTex);
839 glUniform1i(glGetUniformLocation(bloom2Shader, "clearTex"), 0); 840 glUniform1i(glGetUniformLocation(bloom2Shader, "clearTex"), 0);
840 841
841 glActiveTexture(GL_TEXTURE1); 842 glActiveTexture(GL_TEXTURE1);
842 glBindTexture(GL_TEXTURE_2D, bloomPassTex2); 843 glBindTexture(GL_TEXTURE_2D, bloomPassTex2);
843 glUniform1i(glGetUniformLocation(bloom2Shader, "blurTex"), 1); 844 glUniform1i(glGetUniformLocation(bloom2Shader, "blurTex"), 1);
844 845
845 glUniform1f(glGetUniformLocation(bloom2Shader, "iGlobalTime"), glfwGetTime()); 846 glUniform1f(glGetUniformLocation(bloom2Shader, "iGlobalTime"), glfwGetTime());
846 847
847 glEnableVertexAttribArray(0); 848 glEnableVertexAttribArray(0);
848 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); 849 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
849 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); 850 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
850 glDrawArrays(GL_TRIANGLES, 0, 6); 851 glDrawArrays(GL_TRIANGLES, 0, 6);
851 glDisableVertexAttribArray(0); 852 glDisableVertexAttribArray(0);
852 853
853 glfwSwapBuffers(window); 854 glfwSwapBuffers(window);
854 855
855 curBuf = (curBuf + 1) % 2; 856 curBuf = (curBuf + 1) % 2;
856} 857}
857 858
diff --git a/src/renderer.h b/src/renderer.h index 84ad688..6dccf7a 100644 --- a/src/renderer.h +++ b/src/renderer.h
@@ -24,7 +24,7 @@ class Texture {
24 void blit(const Texture& src, Rectangle srcrect, Rectangle dstrect, double alpha = 1.0); 24 void blit(const Texture& src, Rectangle srcrect, Rectangle dstrect, double alpha = 1.0);
25 void renderScreen() const; 25 void renderScreen() const;
26 Rectangle entirety() const; 26 Rectangle entirety() const;
27 27
28 private: 28 private:
29 GLuint texID; 29 GLuint texID;
30 int width; 30 int width;
diff --git a/src/system.h b/src/system.h new file mode 100644 index 0000000..e630c48 --- /dev/null +++ b/src/system.h
@@ -0,0 +1,55 @@
1#ifndef SYSTEM_H_B61A8CEA
2#define SYSTEM_H_B61A8CEA
3
4#include "entity_manager.h"
5
6class Game;
7class Texture;
8
9class System {
10public:
11
12 using id_type = EntityManager::id_type;
13
14 System(Game& game) : game_(game)
15 {
16 }
17
18 virtual ~System() = default;
19
20 /**
21 * Updates the state of a system.
22 *
23 * @param dt - The amount of time in seconds that have passed since the last
24 * update.
25 */
26 virtual void tick(double)
27 {
28 }
29
30 /**
31 * Renders to a texture.
32 *
33 * @param texture - The surface to render to.
34 */
35 virtual void render(Texture&)
36 {
37 }
38
39 /**
40 * Processes keyboard input.
41 *
42 * @param key - The relevant key.
43 *
44 * @param action - The action performed (press, released, etc).
45 */
46 virtual void input(int, int)
47 {
48 }
49
50protected:
51
52 Game& game_;
53};
54
55#endif /* end of include guard: SYSTEM_H_B61A8CEA */
diff --git a/src/system_manager.h b/src/system_manager.h new file mode 100644 index 0000000..b03c3f2 --- /dev/null +++ b/src/system_manager.h
@@ -0,0 +1,68 @@
1#ifndef SYSTEM_MANAGER_H_544E6056
2#define SYSTEM_MANAGER_H_544E6056
3
4#include <list>
5#include <memory>
6#include <map>
7#include <typeindex>
8#include <stdexcept>
9#include "system.h"
10
11class SystemManager {
12private:
13
14 std::list<std::unique_ptr<System>> loop;
15 std::map<std::type_index, System*> systems;
16
17public:
18
19 template <class T, class... Args>
20 void emplaceSystem(Game& game, Args&&... args)
21 {
22 std::unique_ptr<T> ptr(new T(game, std::forward<Args>(args)...));
23 std::type_index systemType = typeid(T);
24
25 systems[systemType] = ptr.get();
26 loop.push_back(std::move(ptr));
27 }
28
29 template <class T>
30 T& getSystem()
31 {
32 std::type_index systemType = typeid(T);
33
34 if (!systems.count(systemType))
35 {
36 throw std::invalid_argument("Cannot get non-existent system");
37 }
38
39 return *dynamic_cast<T*>(systems[systemType]);
40 }
41
42 void tick(double dt)
43 {
44 for (std::unique_ptr<System>& sys : loop)
45 {
46 sys->tick(dt);
47 }
48 }
49
50 virtual void render(Texture& texture)
51 {
52 for (std::unique_ptr<System>& sys : loop)
53 {
54 sys->render(texture);
55 }
56 }
57
58 virtual void input(int key, int action)
59 {
60 for (std::unique_ptr<System>& sys : loop)
61 {
62 sys->input(key, action);
63 }
64 }
65
66};
67
68#endif /* end of include guard: SYSTEM_MANAGER_H_544E6056 */
diff --git a/src/systems/animating.cpp b/src/systems/animating.cpp new file mode 100644 index 0000000..91fe925 --- /dev/null +++ b/src/systems/animating.cpp
@@ -0,0 +1,68 @@
1#include "animating.h"
2#include "game.h"
3#include "components/animatable.h"
4#include "components/transformable.h"
5
6void AnimatingSystem::tick(double)
7{
8 std::set<id_type> spriteEntities =
9 game_.getEntityManager().getEntitiesWithComponents<AnimatableComponent>();
10
11 for (id_type entity : spriteEntities)
12 {
13 auto& sprite = game_.getEntityManager().
14 getComponent<AnimatableComponent>(entity);
15
16 sprite.setCountdown(sprite.getCountdown() + 1);
17
18 const Animation& anim = sprite.getAnimation();
19 if (sprite.getCountdown() >= anim.getDelay())
20 {
21 sprite.setFrame(sprite.getFrame() + 1);
22 sprite.setCountdown(0);
23
24 if (sprite.getFrame() >= anim.getFirstFrame() + anim.getNumFrames())
25 {
26 sprite.setFrame(anim.getFirstFrame());
27 }
28 }
29 }
30}
31
32void AnimatingSystem::render(Texture& texture)
33{
34 std::set<id_type> spriteEntities =
35 game_.getEntityManager().getEntitiesWithComponents<
36 AnimatableComponent,
37 TransformableComponent>();
38
39 for (id_type entity : spriteEntities)
40 {
41 auto& sprite = game_.getEntityManager().
42 getComponent<AnimatableComponent>(entity);
43
44 auto& transform = game_.getEntityManager().
45 getComponent<TransformableComponent>(entity);
46
47 Rectangle dstrect {
48 static_cast<int>(transform.getX()),
49 static_cast<int>(transform.getY()),
50 transform.getW(),
51 transform.getH()};
52
53 const AnimationSet& aset = sprite.getAnimationSet();
54 texture.blit(
55 aset.getTexture(),
56 aset.getFrameRect(sprite.getFrame()),
57 dstrect);
58 }
59}
60
61void AnimatingSystem::startAnimation(id_type entity, std::string animation)
62{
63 auto& sprite = game_.getEntityManager().
64 getComponent<AnimatableComponent>(entity);
65
66 sprite.setAnimation(animation);
67 sprite.setFrame(sprite.getAnimation().getFirstFrame());
68}
diff --git a/src/systems/animating.h b/src/systems/animating.h new file mode 100644 index 0000000..d6a89a5 --- /dev/null +++ b/src/systems/animating.h
@@ -0,0 +1,23 @@
1#ifndef ANIMATING_H_5BBF0094
2#define ANIMATING_H_5BBF0094
3
4#include "system.h"
5#include <string>
6#include "renderer.h"
7
8class AnimatingSystem : public System {
9public:
10
11 AnimatingSystem(Game& game) : System(game)
12 {
13 }
14
15 void tick(double dt);
16
17 void render(Texture& texture);
18
19 void startAnimation(id_type entity, std::string animation);
20
21};
22
23#endif /* end of include guard: ANIMATING_H_5BBF0094 */
diff --git a/src/systems/controlling.cpp b/src/systems/controlling.cpp new file mode 100644 index 0000000..e1609bd --- /dev/null +++ b/src/systems/controlling.cpp
@@ -0,0 +1,107 @@
1#include "controlling.h"
2#include "game.h"
3#include "components/controllable.h"
4#include "components/orientable.h"
5#include "systems/orienting.h"
6
7void ControllingSystem::tick(double)
8{
9 while (!actions_.empty())
10 {
11 int key = actions_.front().first;
12 int action = actions_.front().second;
13
14 auto entities = game_.getEntityManager().getEntitiesWithComponents<
15 ControllableComponent,
16 OrientableComponent>();
17
18 for (auto entity : entities)
19 {
20 auto& controllable = game_.getEntityManager().
21 getComponent<ControllableComponent>(entity);
22
23 auto& orienting = game_.getSystemManager().getSystem<OrientingSystem>();
24
25 if (action == GLFW_PRESS)
26 {
27 if (key == controllable.getLeftKey())
28 {
29 controllable.setHoldingLeft(true);
30
31 if (!controllable.isFrozen())
32 {
33 orienting.moveLeft(entity);
34 }
35 } else if (key == controllable.getRightKey())
36 {
37 controllable.setHoldingRight(true);
38
39 if (!controllable.isFrozen())
40 {
41 orienting.moveRight(entity);
42 }
43 } else if (key == controllable.getJumpKey())
44 {
45 if (!controllable.isFrozen())
46 {
47 orienting.jump(entity);
48 }
49 } else if (key == controllable.getDropKey())
50 {
51 if (!controllable.isFrozen())
52 {
53 orienting.drop(entity);
54 }
55 }
56 } else if (action == GLFW_RELEASE)
57 {
58 if (key == controllable.getLeftKey())
59 {
60 controllable.setHoldingLeft(false);
61
62 if (!controllable.isFrozen())
63 {
64 if (controllable.isHoldingRight())
65 {
66 orienting.moveRight(entity);
67 } else {
68 orienting.stopWalking(entity);
69 }
70 }
71 } else if (key == controllable.getRightKey())
72 {
73 controllable.setHoldingRight(false);
74
75 if (!controllable.isFrozen())
76 {
77 if (controllable.isHoldingLeft())
78 {
79 orienting.moveLeft(entity);
80 } else {
81 orienting.stopWalking(entity);
82 }
83 }
84 } else if (key == controllable.getDropKey())
85 {
86 if (!controllable.isFrozen())
87 {
88 orienting.stopDropping(entity);
89 }
90 } else if (key == controllable.getJumpKey())
91 {
92 if (!controllable.isFrozen())
93 {
94 orienting.stopJumping(entity);
95 }
96 }
97 }
98 }
99
100 actions_.pop();
101 }
102}
103
104void ControllingSystem::input(int key, int action)
105{
106 actions_.push(std::make_pair(key, action));
107}
diff --git a/src/systems/controlling.h b/src/systems/controlling.h new file mode 100644 index 0000000..01ed7a0 --- /dev/null +++ b/src/systems/controlling.h
@@ -0,0 +1,22 @@
1#ifndef CONTROLLING_H_80B1BB8D
2#define CONTROLLING_H_80B1BB8D
3
4#include "system.h"
5#include <queue>
6
7class ControllingSystem : public System {
8public:
9
10 ControllingSystem(Game& game) : System(game)
11 {
12 }
13
14 void tick(double dt);
15 void input(int key, int action);
16
17private:
18
19 std::queue<std::pair<int,int>> actions_;
20};
21
22#endif /* end of include guard: CONTROLLING_H_80B1BB8D */
diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp new file mode 100644 index 0000000..5b63ded --- /dev/null +++ b/src/systems/mapping.cpp
@@ -0,0 +1,141 @@
1#include "mapping.h"
2#include "components/mappable.h"
3#include "game.h"
4#include "consts.h"
5
6template <typename Storage>
7inline void addBoundary(
8 Storage& boundaries,
9 int axis,
10 int lower,
11 int upper,
12 MappableComponent::Boundary::Type type)
13{
14 boundaries.emplace(std::piecewise_construct,
15 std::tie(axis),
16 std::tie(axis, lower, upper, type));
17}
18
19void MappingSystem::render(Texture& texture)
20{
21 auto entities = game_.getEntityManager().getEntitiesWithComponents<
22 MappableComponent>();
23
24 for (id_type entity : entities)
25 {
26 auto& mappable = game_.getEntityManager().
27 getComponent<MappableComponent>(entity);
28
29 const Map& map = game_.getWorld().getMap(mappable.getMapId());
30
31 for (int i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++)
32 {
33 int x = i % MAP_WIDTH;
34 int y = i / MAP_WIDTH;
35 int tile = map.getTiles()[i];
36
37 if (tile > 0)
38 {
39 Rectangle dst {
40 x * TILE_WIDTH,
41 y * TILE_HEIGHT,
42 TILE_WIDTH,
43 TILE_HEIGHT};
44
45 Rectangle src {
46 (tile % TILESET_COLS) * TILE_WIDTH,
47 (tile / TILESET_COLS) * TILE_HEIGHT,
48 TILE_WIDTH,
49 TILE_HEIGHT};
50
51 texture.blit(mappable.getTileset(), std::move(src), std::move(dst));
52 }
53 }
54
55 int startX = ((GAME_WIDTH / TILE_WIDTH) / 2) - (map.getTitle().size() / 2);
56 for (size_t i = 0; i < map.getTitle().size(); i++)
57 {
58 Rectangle src {
59 (map.getTitle()[i] % FONT_COLS) * TILE_WIDTH,
60 (map.getTitle()[i] / FONT_COLS) * TILE_HEIGHT,
61 TILE_WIDTH,
62 TILE_HEIGHT};
63
64 Rectangle dst {
65 (startX + static_cast<int>(i)) * TILE_WIDTH,
66 24 * TILE_HEIGHT,
67 TILE_WIDTH,
68 TILE_HEIGHT};
69
70 texture.blit(mappable.getFont(), std::move(src), std::move(dst));
71 }
72 }
73}
74
75void MappingSystem::loadMap(size_t mapId)
76{
77 id_type mapEntity = game_.getEntityManager().emplaceEntity();
78
79 auto& mappable = game_.getEntityManager().
80 emplaceComponent<MappableComponent>(mapEntity,
81 Texture("res/tiles.png"),
82 Texture("res/font.bmp"));
83
84 mappable.setMapId(mapId);
85
86 const Map& map = game_.getWorld().getMap(mappable.getMapId());
87
88 for (size_t i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++)
89 {
90 size_t x = i % MAP_WIDTH;
91 size_t y = i / MAP_WIDTH;
92 int tile = map.getTiles()[i];
93
94 if ((tile >= 5) && (tile <= 7))
95 {
96 addBoundary(
97 mappable.getDownBoundaries(),
98 y * TILE_HEIGHT,
99 x * TILE_WIDTH,
100 (x + 1) * TILE_WIDTH,
101 MappableComponent::Boundary::Type::platform);
102 } else if ((tile > 0) && (tile < 28))
103 {
104 addBoundary(
105 mappable.getRightBoundaries(),
106 x * TILE_WIDTH,
107 y * TILE_HEIGHT,
108 (y+1) * TILE_HEIGHT,
109 MappableComponent::Boundary::Type::wall);
110
111 addBoundary(
112 mappable.getLeftBoundaries(),
113 (x+1) * TILE_WIDTH,
114 y * TILE_HEIGHT,
115 (y+1) * TILE_HEIGHT,
116 MappableComponent::Boundary::Type::wall);
117
118 addBoundary(
119 mappable.getDownBoundaries(),
120 y * TILE_HEIGHT,
121 x * TILE_WIDTH,
122 (x+1) * TILE_WIDTH,
123 MappableComponent::Boundary::Type::wall);
124
125 addBoundary(
126 mappable.getUpBoundaries(),
127 (y+1) * TILE_HEIGHT,
128 x * TILE_WIDTH,
129 (x+1) * TILE_WIDTH,
130 MappableComponent::Boundary::Type::wall);
131 } else if (tile == 42)
132 {
133 addBoundary(
134 mappable.getDownBoundaries(),
135 y * TILE_HEIGHT,
136 x * TILE_WIDTH,
137 (x+1) * TILE_WIDTH,
138 MappableComponent::Boundary::Type::danger);
139 }
140 }
141}
diff --git a/src/systems/mapping.h b/src/systems/mapping.h new file mode 100644 index 0000000..53d054b --- /dev/null +++ b/src/systems/mapping.h
@@ -0,0 +1,19 @@
1#ifndef MAPPING_H_33FC2294
2#define MAPPING_H_33FC2294
3
4#include "system.h"
5
6class MappingSystem : public System {
7public:
8
9 MappingSystem(Game& game) : System(game)
10 {
11 }
12
13 void render(Texture& texture);
14
15 void loadMap(size_t mapId);
16
17};
18
19#endif /* end of include guard: MAPPING_H_33FC2294 */
diff --git a/src/systems/orienting.cpp b/src/systems/orienting.cpp new file mode 100644 index 0000000..187bebc --- /dev/null +++ b/src/systems/orienting.cpp
@@ -0,0 +1,236 @@
1#include "orienting.h"
2#include "game.h"
3#include "components/orientable.h"
4#include "components/ponderable.h"
5#include "systems/animating.h"
6#include "consts.h"
7#include "muxer.h"
8
9void OrientingSystem::tick(double)
10{
11 auto entities = game_.getEntityManager().getEntitiesWithComponents<
12 OrientableComponent,
13 PonderableComponent>();
14
15 for (id_type entity : entities)
16 {
17 auto& orientable = game_.getEntityManager().
18 getComponent<OrientableComponent>(entity);
19
20 auto& ponderable = game_.getEntityManager().
21 getComponent<PonderableComponent>(entity);
22
23 switch (orientable.getWalkState())
24 {
25 case OrientableComponent::WalkState::still:
26 {
27 ponderable.setVelocityX(0);
28
29 break;
30 }
31
32 case OrientableComponent::WalkState::left:
33 {
34 ponderable.setVelocityX(-WALK_SPEED);
35
36 break;
37 }
38
39 case OrientableComponent::WalkState::right:
40 {
41 ponderable.setVelocityX(WALK_SPEED);
42
43 break;
44 }
45 }
46
47 if (orientable.isJumping() && (ponderable.getVelocityY() > 0))
48 {
49 orientable.setJumping(false);
50 }
51 }
52}
53
54void OrientingSystem::moveLeft(id_type entity)
55{
56 auto& ponderable = game_.getEntityManager().
57 getComponent<PonderableComponent>(entity);
58
59 auto& orientable = game_.getEntityManager().
60 getComponent<OrientableComponent>(entity);
61
62 orientable.setFacingRight(false);
63 orientable.setWalkState(OrientableComponent::WalkState::left);
64
65 auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>();
66 if (ponderable.isGrounded())
67 {
68 animating.startAnimation(entity, "walkingLeft");
69 } else {
70 animating.startAnimation(entity, "stillLeft");
71 }
72}
73
74void OrientingSystem::moveRight(id_type entity)
75{
76 auto& ponderable = game_.getEntityManager().
77 getComponent<PonderableComponent>(entity);
78
79 auto& orientable = game_.getEntityManager().
80 getComponent<OrientableComponent>(entity);
81
82 orientable.setFacingRight(true);
83 orientable.setWalkState(OrientableComponent::WalkState::right);
84
85 auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>();
86 if (ponderable.isGrounded())
87 {
88 animating.startAnimation(entity, "walkingRight");
89 } else {
90 animating.startAnimation(entity, "stillRight");
91 }
92}
93
94void OrientingSystem::stopWalking(id_type entity)
95{
96 auto& ponderable = game_.getEntityManager().
97 getComponent<PonderableComponent>(entity);
98
99 auto& orientable = game_.getEntityManager().
100 getComponent<OrientableComponent>(entity);
101
102 orientable.setWalkState(OrientableComponent::WalkState::still);
103
104 if (ponderable.isGrounded())
105 {
106 auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>();
107
108 if (orientable.isFacingRight())
109 {
110 animating.startAnimation(entity, "stillRight");
111 } else {
112 animating.startAnimation(entity, "stillLeft");
113 }
114 }
115}
116
117void OrientingSystem::jump(id_type entity)
118{
119 auto& ponderable = game_.getEntityManager().
120 getComponent<PonderableComponent>(entity);
121
122 if (ponderable.isGrounded())
123 {
124 auto& orientable = game_.getEntityManager().
125 getComponent<OrientableComponent>(entity);
126
127 orientable.setJumping(true);
128
129 playSound("res/Randomize87.wav", 0.25);
130
131 ponderable.setVelocityY(JUMP_VELOCITY);
132 ponderable.setAccelY(JUMP_GRAVITY);
133
134 auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>();
135 if (orientable.isFacingRight())
136 {
137 animating.startAnimation(entity, "stillRight");
138 } else {
139 animating.startAnimation(entity, "stillLeft");
140 }
141 }
142}
143
144void OrientingSystem::stopJumping(id_type entity)
145{
146 auto& orientable = game_.getEntityManager().
147 getComponent<OrientableComponent>(entity);
148
149 if (orientable.isJumping())
150 {
151 orientable.setJumping(false);
152
153 auto& ponderable = game_.getEntityManager().
154 getComponent<PonderableComponent>(entity);
155
156 ponderable.setAccelY(NORMAL_GRAVITY);
157 }
158}
159
160void OrientingSystem::land(id_type entity)
161{
162 auto& orientable = game_.getEntityManager().
163 getComponent<OrientableComponent>(entity);
164
165 auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>();
166
167 switch (orientable.getWalkState())
168 {
169 case OrientableComponent::WalkState::still:
170 {
171 if (orientable.isFacingRight())
172 {
173 animating.startAnimation(entity, "stillRight");
174 } else {
175 animating.startAnimation(entity, "stillLeft");
176 }
177
178 break;
179 }
180
181 case OrientableComponent::WalkState::left:
182 {
183 animating.startAnimation(entity, "walkingLeft");
184
185 break;
186 }
187
188 case OrientableComponent::WalkState::right:
189 {
190 animating.startAnimation(entity, "walkingRight");
191
192 break;
193 }
194 }
195}
196
197void OrientingSystem::startFalling(id_type entity)
198{
199 auto& orientable = game_.getEntityManager().
200 getComponent<OrientableComponent>(entity);
201
202 auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>();
203
204 if (orientable.isFacingRight())
205 {
206 animating.startAnimation(entity, "stillRight");
207 } else {
208 animating.startAnimation(entity, "stillLeft");
209 }
210}
211
212void OrientingSystem::drop(id_type entity)
213{
214 auto& orientable = game_.getEntityManager().
215 getComponent<OrientableComponent>(entity);
216
217 auto& ponderable = game_.getEntityManager().
218 getComponent<PonderableComponent>(entity);
219
220 if (ponderable.isGrounded()
221 && (orientable.getDropState() == OrientableComponent::DropState::none))
222 {
223 orientable.setDropState(OrientableComponent::DropState::ready);
224 }
225}
226
227void OrientingSystem::stopDropping(id_type entity)
228{
229 auto& orientable = game_.getEntityManager().
230 getComponent<OrientableComponent>(entity);
231
232 if (orientable.getDropState() == OrientableComponent::DropState::ready)
233 {
234 orientable.setDropState(OrientableComponent::DropState::none);
235 }
236}
diff --git a/src/systems/orienting.h b/src/systems/orienting.h new file mode 100644 index 0000000..4ded612 --- /dev/null +++ b/src/systems/orienting.h
@@ -0,0 +1,35 @@
1#ifndef ORIENTING_H_099F0C23
2#define ORIENTING_H_099F0C23
3
4#include "system.h"
5
6class OrientingSystem : public System {
7public:
8
9 OrientingSystem(Game& game) : System(game)
10 {
11 }
12
13 void tick(double dt);
14
15 void moveLeft(id_type entity);
16
17 void moveRight(id_type entity);
18
19 void stopWalking(id_type entity);
20
21 void jump(id_type entity);
22
23 void stopJumping(id_type entity);
24
25 void land(id_type entity);
26
27 void startFalling(id_type entity);
28
29 void drop(id_type entity);
30
31 void stopDropping(id_type entity);
32
33};
34
35#endif /* end of include guard: ORIENTING_H_099F0C23 */
diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp new file mode 100644 index 0000000..4a165b1 --- /dev/null +++ b/src/systems/pondering.cpp
@@ -0,0 +1,268 @@
1#include "pondering.h"
2#include "game.h"
3#include "components/ponderable.h"
4#include "components/transformable.h"
5#include "components/orientable.h"
6#include "components/mappable.h"
7#include "systems/orienting.h"
8#include "consts.h"
9
10void PonderingSystem::tick(double dt)
11{
12 auto entities = game_.getEntityManager().getEntitiesWithComponents<
13 PonderableComponent,
14 TransformableComponent>();
15
16 auto maps = game_.getEntityManager().getEntitiesWithComponents<
17 MappableComponent>();
18
19 for (id_type entity : entities)
20 {
21 auto& transformable = game_.getEntityManager().
22 getComponent<TransformableComponent>(entity);
23
24 auto& ponderable = game_.getEntityManager().
25 getComponent<PonderableComponent>(entity);
26
27 // Accelerate
28 ponderable.setVelocityX(
29 ponderable.getVelocityX() + ponderable.getAccelX() * dt);
30
31 ponderable.setVelocityY(
32 ponderable.getVelocityY() + ponderable.getAccelY() * dt);
33
34 const double oldX = transformable.getX();
35 const double oldY = transformable.getY();
36 const double oldRight = oldX + transformable.getW();
37 const double oldBottom = oldY + transformable.getH();
38
39 double newX = oldX + ponderable.getVelocityX() * dt;
40 double newY = oldY + ponderable.getVelocityY() * dt;
41
42 bool oldGrounded = ponderable.isGrounded();
43 ponderable.setGrounded(false);
44
45 for (id_type mapEntity : maps)
46 {
47 auto& mappable = game_.getEntityManager().
48 getComponent<MappableComponent>(mapEntity);
49
50 if (newX < oldX)
51 {
52 for (auto it = mappable.getLeftBoundaries().lower_bound(oldX);
53 (it != std::end(mappable.getLeftBoundaries())) && (it->first >= newX);
54 it++)
55 {
56 if ((oldBottom > it->second.getLower())
57 && (oldY < it->second.getUpper()))
58 {
59 // We have a collision!
60 processCollision(
61 entity,
62 Direction::left,
63 newX,
64 newY,
65 it->first,
66 it->second.getType());
67 }
68 }
69 } else if (newX > oldX)
70 {
71 for (auto it = mappable.getRightBoundaries().lower_bound(oldRight);
72 (it != std::end(mappable.getRightBoundaries()))
73 && (it->first <= (newX + transformable.getW()));
74 it++)
75 {
76 if ((oldBottom > it->second.getLower())
77 && (oldY < it->second.getUpper()))
78 {
79 // We have a collision!
80 processCollision(
81 entity,
82 Direction::right,
83 newX,
84 newY,
85 it->first,
86 it->second.getType());
87 }
88 }
89 }
90
91 if (newY < oldY)
92 {
93 for (auto it = mappable.getUpBoundaries().lower_bound(oldY);
94 (it != std::end(mappable.getUpBoundaries())) && (it->first >= newY);
95 it++)
96 {
97 if ((oldRight > it->second.getLower())
98 && (oldX < it->second.getUpper()))
99 {
100 // We have a collision!
101 processCollision(
102 entity,
103 Direction::up,
104 newX,
105 newY,
106 it->first,
107 it->second.getType());
108 }
109 }
110 } else if (newY > oldY)
111 {
112 for (auto it = mappable.getDownBoundaries().lower_bound(oldBottom);
113 (it != std::end(mappable.getDownBoundaries()))
114 && (it->first <= (newY + transformable.getH()));
115 it++)
116 {
117 if ((oldRight > it->second.getLower())
118 && (oldX < it->second.getUpper()))
119 {
120 // We have a collision!
121 processCollision(
122 entity,
123 Direction::down,
124 newX,
125 newY,
126 it->first,
127 it->second.getType());
128 }
129 }
130 }
131 }
132
133 // Move
134 transformable.setX(newX);
135 transformable.setY(newY);
136
137 // Perform cleanup for orientable entites
138 if (game_.getEntityManager().hasComponent<OrientableComponent>(entity))
139 {
140 auto& orientable = game_.getEntityManager().
141 getComponent<OrientableComponent>(entity);
142
143 // Handle changes in groundedness
144 if (ponderable.isGrounded() != oldGrounded)
145 {
146 if (ponderable.isGrounded())
147 {
148 game_.getSystemManager().getSystem<OrientingSystem>().land(entity);
149 } else {
150 game_.getSystemManager().
151 getSystem<OrientingSystem>().startFalling(entity);
152 }
153 }
154
155 // Complete dropping, if necessary
156 if (orientable.getDropState() == OrientableComponent::DropState::active)
157 {
158 orientable.setDropState(OrientableComponent::DropState::none);
159 }
160 }
161 }
162}
163
164void PonderingSystem::initializeBody(
165 id_type entity,
166 PonderableComponent::Type type)
167{
168 auto& ponderable = game_.getEntityManager().
169 emplaceComponent<PonderableComponent>(entity, type);
170
171 if (type == PonderableComponent::Type::freefalling)
172 {
173 ponderable.setAccelY(NORMAL_GRAVITY);
174 }
175}
176
177void PonderingSystem::processCollision(
178 id_type entity,
179 Direction dir,
180 double& newX,
181 double& newY,
182 int axis,
183 MappableComponent::Boundary::Type type)
184{
185 auto& ponderable = game_.getEntityManager().
186 getComponent<PonderableComponent>(entity);
187
188 auto& transformable = game_.getEntityManager().
189 getComponent<TransformableComponent>(entity);
190
191 bool touchedGround = false;
192
193 switch (type)
194 {
195 case MappableComponent::Boundary::Type::wall:
196 {
197 switch (dir)
198 {
199 case Direction::left:
200 {
201 newX = axis;
202 ponderable.setVelocityX(0.0);
203
204 break;
205 }
206
207 case Direction::right:
208 {
209 newX = axis - transformable.getW();
210 ponderable.setVelocityX(0.0);
211
212 break;
213 }
214
215 case Direction::up:
216 {
217 newY = axis;
218 ponderable.setVelocityY(0.0);
219
220 break;
221 }
222
223 case Direction::down:
224 {
225 touchedGround = true;
226
227 break;
228 }
229 }
230
231 break;
232 }
233
234 case MappableComponent::Boundary::Type::platform:
235 {
236 if (game_.getEntityManager().hasComponent<OrientableComponent>(entity))
237 {
238 auto& orientable = game_.getEntityManager().
239 getComponent<OrientableComponent>(entity);
240
241 if (orientable.getDropState() != OrientableComponent::DropState::none)
242 {
243 orientable.setDropState(OrientableComponent::DropState::active);
244 } else {
245 touchedGround = true;
246 }
247 } else {
248 touchedGround = true;
249 }
250
251 break;
252 }
253
254 default:
255 {
256 // Not yet implemented.
257
258 break;
259 }
260 }
261
262 if (touchedGround)
263 {
264 newY = axis - transformable.getH();
265 ponderable.setVelocityY(0.0);
266 ponderable.setGrounded(true);
267 }
268}
diff --git a/src/systems/pondering.h b/src/systems/pondering.h new file mode 100644 index 0000000..a16622b --- /dev/null +++ b/src/systems/pondering.h
@@ -0,0 +1,32 @@
1#ifndef PONDERING_H_F2530E0E
2#define PONDERING_H_F2530E0E
3
4#include "system.h"
5#include "components/mappable.h"
6#include "components/ponderable.h"
7#include "direction.h"
8
9class PonderingSystem : public System {
10public:
11
12 PonderingSystem(Game& game) : System(game)
13 {
14 }
15
16 void tick(double dt);
17
18 void initializeBody(id_type entity, PonderableComponent::Type type);
19
20private:
21
22 void processCollision(
23 id_type entity,
24 Direction dir,
25 double& newX,
26 double& newY,
27 int axis,
28 MappableComponent::Boundary::Type type);
29
30};
31
32#endif /* end of include guard: PONDERING_H_F2530E0E */
diff --git a/src/world.cpp b/src/world.cpp index 0c61c47..9b1e4f6 100644 --- a/src/world.cpp +++ b/src/world.cpp
@@ -1,150 +1,99 @@
1#include "world.h" 1#include "world.h"
2#include <libxml/parser.h> 2#include <libxml/parser.h>
3#include <stdexcept>
4#include <cstring>
3#include "consts.h" 5#include "consts.h"
4 6
5World::World(const char* filename) 7inline xmlChar* getProp(xmlNodePtr node, const char* attr)
6{ 8{
7 xmlDocPtr doc = xmlParseFile(filename); 9 xmlChar* key = xmlGetProp(node, reinterpret_cast<const xmlChar*>(attr));
10 if (key == nullptr)
11 {
12 throw std::invalid_argument("Error parsing world file");
13 }
14
15 return key;
16}
17
18World::World(std::string filename)
19{
20 xmlDocPtr doc = xmlParseFile(filename.c_str());
8 if (doc == nullptr) 21 if (doc == nullptr)
9 { 22 {
10 exit(2); 23 throw std::invalid_argument("Cannot find world file");
11 } 24 }
12 25
13 xmlNodePtr top = xmlDocGetRootElement(doc); 26 xmlNodePtr top = xmlDocGetRootElement(doc);
14 if (top == nullptr) 27 if (top == nullptr)
15 { 28 {
16 exit(2); 29 throw std::invalid_argument("Error parsing world file");
17 } 30 }
18 31
19 if (xmlStrcmp(top->name, (const xmlChar*) "world")) 32 if (xmlStrcmp(top->name, reinterpret_cast<const xmlChar*>("world")))
20 { 33 {
21 exit(2); 34 throw std::invalid_argument("Error parsing world file");
22 } 35 }
23 36
24 xmlChar* startxKey = xmlGetProp(top, (xmlChar*) "startx"); 37 xmlChar* key = nullptr;
25 if (startxKey == 0) exit(2); 38
26 startX = atoi((char*) startxKey); 39 key = getProp(top, "startx");
27 xmlFree(startxKey); 40 startX_ = atoi(reinterpret_cast<char*>(key));
28 41 xmlFree(key);
29 xmlChar* startyKey = xmlGetProp(top, (xmlChar*) "starty"); 42
30 if (startyKey == 0) exit(2); 43 key = getProp(top, "starty");
31 startY = atoi((char*) startyKey); 44 startY_ = atoi(reinterpret_cast<char*>(key));
32 xmlFree(startyKey); 45 xmlFree(key);
33 46
34 xmlChar* startmapKey = xmlGetProp(top, (xmlChar*) "startmap"); 47 key = getProp(top, "startmap");
35 if (startxKey == 0) exit(2); 48 startMap_ = atoi(reinterpret_cast<char*>(key));
36 startMap = atoi((char*) startmapKey); 49 xmlFree(key);
37 xmlFree(startmapKey); 50
38 51 for (xmlNodePtr node = top->xmlChildrenNode;
39 for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) 52 node != nullptr;
53 node = node->next)
40 { 54 {
41 if (!xmlStrcmp(node->name, (const xmlChar*) "map")) 55 if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("map")))
42 { 56 {
43 xmlChar* idKey = xmlGetProp(node, (xmlChar*) "id"); 57 key = getProp(node, "id");
44 if (idKey == 0) exit(2); 58 size_t mapId = atoi(reinterpret_cast<char*>(key));
45 int theId = atoi((char*) idKey); 59 xmlFree(key);
46 xmlFree(idKey); 60
47 61 key = getProp(node, "title");
48 maps.emplace(theId, theId); 62 std::string mapTitle(reinterpret_cast<char*>(key));
49 Map& map = maps[theId]; 63 xmlFree(key);
50 64
51 xmlChar* titleKey = xmlGetProp(node, (xmlChar*) "title"); 65 std::vector<int> mapTiles;
52 if (titleKey == 0) exit(2); 66
53 map.setTitle((char*) titleKey); 67 for (xmlNodePtr mapNode = node->xmlChildrenNode;
54 xmlFree(titleKey); 68 mapNode != nullptr;
55 69 mapNode = mapNode->next)
56 for (xmlNodePtr mapNode = node->xmlChildrenNode; mapNode != NULL; mapNode = mapNode->next)
57 { 70 {
58 if (!xmlStrcmp(mapNode->name, (const xmlChar*) "environment")) 71 if (!xmlStrcmp(
72 mapNode->name,
73 reinterpret_cast<const xmlChar*>("environment")))
59 { 74 {
60 xmlChar* key = xmlNodeGetContent(mapNode); 75 key = xmlNodeGetContent(mapNode);
61 int* mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); 76
62 mapdata[0] = atoi(strtok((char*) key, ",\n")); 77 mapTiles.clear();
63 for (int i=1; i<(MAP_WIDTH*MAP_HEIGHT); i++) 78 mapTiles.push_back(atoi(strtok(reinterpret_cast<char*>(key), ",\n")));
79 for (size_t i = 1; i < (MAP_WIDTH * MAP_HEIGHT); i++)
64 { 80 {
65 mapdata[i] = atoi(strtok(NULL, ",\n")); 81 mapTiles.push_back(atoi(strtok(nullptr, ",\n")));
66 } 82 }
67 map.setMapdata(mapdata); 83
68 xmlFree(key); 84 xmlFree(key);
69 } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "entity"))
70 {
71 Map::EntityData data;
72
73 xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type");
74 if (typeKey == 0) exit(2);
75 data.name = (char*) typeKey;
76 xmlFree(typeKey);
77
78 xmlChar* xKey = xmlGetProp(mapNode, (const xmlChar*) "x");
79 if (xKey == 0) exit(2);
80 data.position.first = atoi((char*) xKey);
81 xmlFree(xKey);
82
83 xmlChar* yKey = xmlGetProp(mapNode, (const xmlChar*) "y");
84 if (yKey == 0) exit(2);
85 data.position.second = atoi((char*) yKey);
86 xmlFree(yKey);
87
88 for (xmlNodePtr entityNode = mapNode->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next)
89 {
90 if (!xmlStrcmp(entityNode->name, (xmlChar*) "item"))
91 {
92 xmlChar* itemIdKey = xmlGetProp(entityNode, (const xmlChar*) "id");
93 if (itemIdKey == 0) exit(2);
94 std::string itemId = (char*) itemIdKey;
95 xmlFree(itemIdKey);
96
97 xmlChar* itemIdVal = xmlNodeGetContent(entityNode);
98 if (itemIdVal == 0) exit(2);
99 data.items[itemId] = atoi((char*) itemIdVal);
100 xmlFree(itemIdVal);
101 }
102 }
103
104 map.addEntity(data);
105 } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "adjacent"))
106 {
107 Map::MoveDir direction;
108 Map::MoveType moveType;
109 int mapId = 0;
110
111 xmlChar* dirKey = xmlGetProp(mapNode, (const xmlChar*) "dir");
112 if (dirKey == 0) exit(2);
113 direction = Map::moveDirForShort((char*) dirKey);
114 xmlFree(dirKey);
115
116 xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type");
117 if (typeKey == 0) exit(2);
118 moveType = Map::moveTypeForShort((char*) typeKey);
119 xmlFree(typeKey);
120
121 xmlChar* mapIdKey = xmlGetProp(mapNode, (const xmlChar*) "map");
122 if (mapIdKey != 0)
123 {
124 mapId = atoi((char*) mapIdKey);
125 }
126 xmlFree(mapIdKey);
127
128 map.setAdjacent(direction, moveType, mapId);
129 } 85 }
130 } 86 }
87
88 maps_.emplace(
89 std::piecewise_construct,
90 std::forward_as_tuple(mapId),
91 std::forward_as_tuple(
92 mapId,
93 std::move(mapTiles),
94 std::move(mapTitle)));
131 } 95 }
132 } 96 }
133
134 xmlFreeDoc(doc);
135}
136 97
137const Map& World::getMap(int id) const 98 xmlFreeDoc(doc);
138{
139 return maps.at(id);
140}
141
142const Map& World::getStartingMap() const
143{
144 return maps.at(startMap);
145}
146
147std::pair<int, int> World::getStartingPosition() const
148{
149 return std::make_pair(startX, startY);
150} 99}
diff --git a/src/world.h b/src/world.h index f566487..b88adf4 100644 --- a/src/world.h +++ b/src/world.h
@@ -1,21 +1,41 @@
1#ifndef WORLD_H 1#ifndef WORLD_H_153C698B
2#define WORLD_H 2#define WORLD_H_153C698B
3 3
4#include <map> 4#include <map>
5#include <string>
5#include "map.h" 6#include "map.h"
6 7
7class World { 8class World {
8 public: 9public:
9 World(const char* filename); 10
10 const Map& getMap(int id) const; 11 explicit World(std::string filename);
11 const Map& getStartingMap() const; 12
12 std::pair<int, int> getStartingPosition() const; 13 inline const Map& getMap(size_t id) const
13 14 {
14 private: 15 return maps_.at(id);
15 std::map<int, Map> maps; 16 }
16 int startMap; 17
17 int startX; 18 inline size_t getStartingMapId() const
18 int startY; 19 {
20 return startMap_;
21 }
22
23 inline int getStartingX() const
24 {
25 return startX_;
26 }
27
28 inline int getStartingY() const
29 {
30 return startY_;
31 }
32
33private:
34
35 std::map<size_t, Map> maps_;
36 size_t startMap_;
37 int startX_;
38 int startY_;
19}; 39};
20 40
21#endif /* end of include guard: WORLD_H */ 41#endif /* end of include guard: WORLD_H_153C698B */