diff options
Diffstat (limited to 'src')
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 | |||
4 | template< typename ContainerT, typename PredicateT > | ||
5 | void 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 | |||
3 | AnimationSet::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 | |||
15 | void 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 | |||
27 | Rectangle 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 | |||
9 | class Animation { | ||
10 | public: | ||
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 | |||
37 | private: | ||
38 | |||
39 | size_t firstFrame_; | ||
40 | size_t numFrames_; | ||
41 | size_t delay_; | ||
42 | }; | ||
43 | |||
44 | class AnimationSet { | ||
45 | public: | ||
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 | |||
91 | private: | ||
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 | |||
4 | class Component { | ||
5 | public: | ||
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 | |||
5 | void AIActionContainer::addAction(std::shared_ptr<AIAction> action) | ||
6 | { | ||
7 | actions.push_back(action); | ||
8 | } | ||
9 | |||
10 | void 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 | |||
20 | void 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 | |||
38 | bool AIActionContainer::isDone() const | ||
39 | { | ||
40 | return currentAction == end(actions); | ||
41 | } | ||
42 | |||
43 | AI::AI(int chance) | ||
44 | { | ||
45 | this->chance = chance; | ||
46 | } | ||
47 | |||
48 | int AI::getChance() const | ||
49 | { | ||
50 | return chance; | ||
51 | } | ||
52 | |||
53 | AI& AIComponent::emplaceAI(int chance) | ||
54 | { | ||
55 | maxChance += chance; | ||
56 | ais.emplace_back(chance); | ||
57 | |||
58 | return ais.back(); | ||
59 | } | ||
60 | |||
61 | void 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 | |||
94 | MoveAIAction::MoveAIAction(Direction dir, int len, int speed) | ||
95 | { | ||
96 | this->dir = dir; | ||
97 | this->len = len; | ||
98 | this->speed = speed; | ||
99 | } | ||
100 | |||
101 | void MoveAIAction::start(Game& game, Entity& entity) | ||
102 | { | ||
103 | remaining = len; | ||
104 | } | ||
105 | |||
106 | void 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 | |||
139 | bool 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 | |||
11 | class 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 | |||
18 | class 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 | |||
30 | class AI : public AIActionContainer { | ||
31 | public: | ||
32 | AI(int chance); | ||
33 | |||
34 | int getChance() const; | ||
35 | |||
36 | private: | ||
37 | int chance; | ||
38 | }; | ||
39 | |||
40 | class 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 | |||
51 | class 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 | |||
8 | class AnimatableComponent : public Component { | ||
9 | public: | ||
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 | |||
54 | private: | ||
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 | |||
7 | class ControllableComponent : public Component { | ||
8 | public: | ||
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 | |||
80 | private: | ||
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 | |||
6 | MapCollisionComponent::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 | |||
35 | void 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 | |||
85 | void 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 | |||
152 | void 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 | |||
232 | MapCollisionComponent::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 | |||
8 | class Game; | ||
9 | |||
10 | class 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 | |||
6 | MapRenderComponent::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 | |||
37 | void 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 | |||
7 | class Map; | ||
8 | class Game; | ||
9 | |||
10 | class 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 | |||
9 | class MappableComponent : public Component { | ||
10 | public: | ||
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 | |||
134 | private: | ||
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 | |||
6 | class OrientableComponent : public Component { | ||
7 | public: | ||
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 | |||
61 | private: | ||
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 | |||
5 | void 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 | |||
25 | void 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 | |||
44 | void 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 | |||
7 | class Game; | ||
8 | |||
9 | class 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 | |||
9 | PlayerPhysicsComponent::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 | |||
18 | void 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 | |||
80 | void 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 | |||
7 | class Game; | ||
8 | |||
9 | class 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 | |||
3 | PlayerSpriteComponent::PlayerSpriteComponent() : sprite("res/Starla.png") | ||
4 | { | ||
5 | |||
6 | } | ||
7 | |||
8 | void 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 | |||
39 | void 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 | |||
7 | class Game; | ||
8 | |||
9 | class 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 | |||
6 | class PonderableComponent : public Component { | ||
7 | public: | ||
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 | |||
73 | private: | ||
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 | |||
3 | SimpleColliderComponent::SimpleColliderComponent(std::function<void (Game& game, Entity& collider)> callback) : callback(callback) | ||
4 | { | ||
5 | |||
6 | } | ||
7 | |||
8 | void 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 | |||
7 | class Game; | ||
8 | |||
9 | class 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 | |||
3 | StaticImageComponent::StaticImageComponent(const char* filename) : sprite(Texture(filename)) | ||
4 | { | ||
5 | |||
6 | } | ||
7 | |||
8 | void 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 | |||
7 | class Game; | ||
8 | |||
9 | class 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 | |||
6 | class TransformableComponent : public Component { | ||
7 | public: | ||
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 | |||
61 | private: | ||
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 | |||
4 | void 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 | |||
81 | void 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 | |||
6 | class Game; | ||
7 | |||
8 | class 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; | |||
7 | const int GAME_HEIGHT = 200; | 7 | const int GAME_HEIGHT = 200; |
8 | const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH; | 8 | const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH; |
9 | const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT - 1; | 9 | const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT - 1; |
10 | const int WALL_GAP = 6; | ||
11 | const int TILESET_COLS = 8; | ||
12 | const int FONT_COLS = 16; | ||
10 | 13 | ||
11 | const int FRAMES_PER_SECOND = 60; | 14 | const int FRAMES_PER_SECOND = 60; |
12 | const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND; | 15 | const 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 | |||
20 | const double NORMAL_GRAVITY = CALC_GRAVITY(TILE_HEIGHT*3.5, 0.233); | ||
21 | const double JUMP_GRAVITY = CALC_GRAVITY(TILE_HEIGHT*4.5, 0.3); | ||
22 | const double JUMP_VELOCITY = CALC_VELOCITY(TILE_HEIGHT*4.5, 0.3); | ||
23 | |||
24 | const 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 | |||
4 | enum 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 | |||
3 | void Entity::addComponent(std::shared_ptr<Component> c) | ||
4 | { | ||
5 | components.push_back(c); | ||
6 | } | ||
7 | |||
8 | void Entity::send(Game& game, const Message& msg) | ||
9 | { | ||
10 | for (auto component : components) | ||
11 | { | ||
12 | component->receive(game, *this, msg); | ||
13 | } | ||
14 | } | ||
15 | |||
16 | void Entity::tick(Game& game, double dt) | ||
17 | { | ||
18 | for (auto component : components) | ||
19 | { | ||
20 | component->tick(game, *this, dt); | ||
21 | } | ||
22 | } | ||
23 | |||
24 | void 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 | |||
32 | void Entity::render(Game& game, Texture& buffer) | ||
33 | { | ||
34 | for (auto component : components) | ||
35 | { | ||
36 | component->render(game, *this, buffer); | ||
37 | } | ||
38 | } | ||
39 | |||
40 | void 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 | |||
7 | class Game; | ||
8 | class Map; | ||
9 | class Entity; | ||
10 | class Component; | ||
11 | |||
12 | class 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 | |||
39 | class 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 | |||
55 | class 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 | |||
6 | template <> | ||
7 | std::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 | |||
12 | class EntityManager { | ||
13 | private: | ||
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 | |||
21 | public: | ||
22 | |||
23 | using id_type = database_type::size_type; | ||
24 | |||
25 | private: | ||
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 | |||
49 | public: | ||
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 | |||
207 | template <> | ||
208 | std::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 | |||
13 | void 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 | |||
95 | std::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 | |||
7 | class Entity; | ||
8 | class Map; | ||
9 | |||
10 | class 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 | ||
13 | Game::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 | |||
35 | void key_callback(GLFWwindow* window, int key, int, int action, int) | 16 | void 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 | ||
50 | void Game::execute(GLFWwindow* window) | 30 | Game::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 | ||
72 | void 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 | |||
117 | void 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 = ↦ | ||
136 | nextPosition = position; | ||
137 | } | ||
138 | 94 | ||
139 | void 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 | |||
147 | void Game::saveGame() | ||
148 | { | ||
149 | save = {currentMap, player->position}; | ||
150 | } | ||
151 | |||
152 | void Game::schedule(double time, std::function<void ()> callback) | ||
153 | { | ||
154 | scheduled.emplace_front(time, std::move(callback)); | ||
155 | } | ||
156 | |||
157 | void 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 | |||
175 | const 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 | ||
11 | class Entity; | 9 | class Game { |
12 | struct GLFWwindow; | 10 | public: |
13 | 11 | ||
14 | struct Savefile { | 12 | Game(GLFWwindow* window); |
15 | const Map* map; | ||
16 | std::pair<double, double> position; | ||
17 | }; | ||
18 | 13 | ||
19 | class 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 | |
38 | private: | ||
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 | ||
8 | int main() | 8 | int 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 | |||
10 | Map::Map(int id) | ||
11 | { | ||
12 | this->id = id; | ||
13 | mapdata = (int*) calloc(1, sizeof(int)); | ||
14 | } | ||
15 | |||
16 | Map::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 | |||
27 | Map::Map(Map&& map) : Map() | ||
28 | { | ||
29 | swap(*this, map); | ||
30 | } | ||
31 | |||
32 | Map::~Map() | ||
33 | { | ||
34 | free(mapdata); | ||
35 | } | ||
36 | |||
37 | Map& Map::operator= (Map map) | ||
38 | { | ||
39 | swap(*this, map); | ||
40 | |||
41 | return *this; | ||
42 | } | ||
43 | |||
44 | void 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 | |||
53 | int Map::getID() const | ||
54 | { | ||
55 | return id; | ||
56 | } | ||
57 | |||
58 | const int* Map::getMapdata() const | ||
59 | { | ||
60 | return mapdata; | ||
61 | } | ||
62 | |||
63 | std::string Map::getTitle() const | ||
64 | { | ||
65 | return title; | ||
66 | } | ||
67 | |||
68 | void 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 | |||
79 | bool Map::operator==(const Map& other) const | ||
80 | { | ||
81 | return id == other.id; | ||
82 | } | ||
83 | |||
84 | bool Map::operator!=(const Map& other) const | ||
85 | { | ||
86 | return id != other.id; | ||
87 | } | ||
88 | |||
89 | Map::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 | |||
98 | Map::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 | |||
107 | static const Map::Adjacent defaultAdjacent {}; | ||
108 | const 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 | |||
118 | bool 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 | |||
129 | void Map::setMapdata(int* mapdata) | ||
130 | { | ||
131 | free(this->mapdata); | ||
132 | this->mapdata = mapdata; | ||
133 | } | ||
134 | |||
135 | void Map::setTitle(std::string title) | ||
136 | { | ||
137 | this->title = title; | ||
138 | } | ||
139 | |||
140 | void 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 | |||
147 | void 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 | ||
8 | class Entity; | ||
9 | |||
10 | class Map { | 10 | class Map { |
11 | public: | 11 | public: |
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 | }; | 38 | private: |
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; | |||
17 | class Sound { | 20 | class 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; | |||
76 | void initMuxer() | 82 | void 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() | |||
98 | void playSound(const char* filename, float vol) | 104 | void 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 | ||
127 | Sound::~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; | |||
56 | static int mesh_numvertices; | 56 | static int mesh_numvertices; |
57 | 57 | ||
58 | GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path) | 58 | GLuint 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 | ||
558 | Texture& Texture::operator= (Texture tex) | 559 | Texture& 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 | |||
6 | class Game; | ||
7 | class Texture; | ||
8 | |||
9 | class System { | ||
10 | public: | ||
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 | |||
50 | protected: | ||
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 | |||
11 | class SystemManager { | ||
12 | private: | ||
13 | |||
14 | std::list<std::unique_ptr<System>> loop; | ||
15 | std::map<std::type_index, System*> systems; | ||
16 | |||
17 | public: | ||
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 | |||
6 | void 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 | |||
32 | void 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 | |||
61 | void 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 | |||
8 | class AnimatingSystem : public System { | ||
9 | public: | ||
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 | |||
7 | void 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 | |||
104 | void 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 | |||
7 | class ControllingSystem : public System { | ||
8 | public: | ||
9 | |||
10 | ControllingSystem(Game& game) : System(game) | ||
11 | { | ||
12 | } | ||
13 | |||
14 | void tick(double dt); | ||
15 | void input(int key, int action); | ||
16 | |||
17 | private: | ||
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 | |||
6 | template <typename Storage> | ||
7 | inline 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 | |||
19 | void 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 | |||
75 | void 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 | |||
6 | class MappingSystem : public System { | ||
7 | public: | ||
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 | |||
9 | void 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 | |||
54 | void 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 | |||
74 | void 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 | |||
94 | void 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 | |||
117 | void 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 | |||
144 | void 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 | |||
160 | void 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 | |||
197 | void 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 | |||
212 | void 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 | |||
227 | void 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 | |||
6 | class OrientingSystem : public System { | ||
7 | public: | ||
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 | |||
10 | void 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 | |||
164 | void 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 | |||
177 | void 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 | |||
9 | class PonderingSystem : public System { | ||
10 | public: | ||
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 | |||
20 | private: | ||
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 | ||
5 | World::World(const char* filename) | 7 | inline 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 | |||
18 | World::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 | ||
137 | const Map& World::getMap(int id) const | 98 | xmlFreeDoc(doc); |
138 | { | ||
139 | return maps.at(id); | ||
140 | } | ||
141 | |||
142 | const Map& World::getStartingMap() const | ||
143 | { | ||
144 | return maps.at(startMap); | ||
145 | } | ||
146 | |||
147 | std::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 | ||
7 | class World { | 8 | class World { |
8 | public: | 9 | public: |
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 | |||
33 | private: | ||
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 */ |