From 879c2c04d9c3879f871cfe79f9b25fd23c5184b4 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 11 Jun 2015 11:38:49 -0400 Subject: Wrote EntityManager --- src/main.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 4157350..29a364b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,9 @@ #include #include -#include "renderer.h" #include -#include "game.h" +#include "renderer.h" #include "muxer.h" +#include "entity_manager.h" int main() { @@ -14,8 +14,12 @@ int main() // Put this in a block so game goes out of scope before we destroy the renderer { - Game game {"res/maps.xml"}; - game.execute(window); + EntityManager manager; + + int eRef = manager.emplaceEntity(); + int eRef2 = manager.emplaceEntity(); + manager.setParent(eRef, eRef2); + printf("%d\n", manager.getParent(eRef)); } destroyMuxer(); -- cgit 1.4.1 From 55c8a14a7e2b2dadf0def3e09f970818164366f5 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 18 Jun 2015 12:14:05 -0400 Subject: Now displaying player character --- CMakeLists.txt | 4 + src/algorithms.h | 12 +++ src/components/sprite_renderable.cpp | 27 ++++++ src/components/sprite_renderable.h | 25 ++++++ src/components/transformable.cpp | 47 ++++++++++ src/components/transformable.h | 27 ++++++ src/entity_manager.cpp | 38 ++++++++ src/entity_manager.h | 169 +++++------------------------------ src/main.cpp | 25 +++++- src/system.h | 11 +++ src/systems/rendering.cpp | 21 +++++ src/systems/rendering.h | 16 ++++ 12 files changed, 270 insertions(+), 152 deletions(-) create mode 100644 src/algorithms.h create mode 100644 src/components/sprite_renderable.cpp create mode 100644 src/components/sprite_renderable.h create mode 100644 src/components/transformable.cpp create mode 100644 src/components/transformable.h create mode 100644 src/entity_manager.cpp create mode 100644 src/system.h create mode 100644 src/systems/rendering.cpp create mode 100644 src/systems/rendering.h (limited to 'src/main.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dfce6f..2bfde77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,10 @@ add_executable(Aromatherapy src/main.cpp src/renderer.cpp src/muxer.cpp + src/entity_manager.cpp + src/components/sprite_renderable.cpp + src/components/transformable.cpp + src/systems/rendering.cpp ) target_link_libraries(Aromatherapy ${ALL_LIBS}) install(TARGETS Aromatherapy RUNTIME DESTINATION ${BIN_DIR}) 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 @@ +#ifndef ALGORITHMS_H_1DDC517E +#define ALGORITHMS_H_1DDC517E + +template< typename ContainerT, typename PredicateT > +void erase_if( ContainerT& items, const PredicateT& predicate ) { + for( auto it = items.begin(); it != items.end(); ) { + if( predicate(*it) ) it = items.erase(it); + else ++it; + } +}; + +#endif /* end of include guard: ALGORITHMS_H_1DDC517E */ diff --git a/src/components/sprite_renderable.cpp b/src/components/sprite_renderable.cpp new file mode 100644 index 0000000..4c61111 --- /dev/null +++ b/src/components/sprite_renderable.cpp @@ -0,0 +1,27 @@ +#include "sprite_renderable.h" + +SpriteRenderableComponent::SpriteRenderableComponent(const char* filename, int frame_width, int frame_height, int frames_across) + : texture(filename), frame_width(frame_width), frame_height(frame_height), frames_across(frames_across) +{ + +} + +int SpriteRenderableComponent::getFrame() const +{ + return frame; +} + +void SpriteRenderableComponent::setFrame(int frame) +{ + this->frame = frame; +} + +const Texture& SpriteRenderableComponent::getTexture() const +{ + return texture; +} + +Rectangle SpriteRenderableComponent::getFrameRect() const +{ + return {frame_width * (frame % frames_across), frame_height * (frame / frames_across), frame_width, frame_height}; +} diff --git a/src/components/sprite_renderable.h b/src/components/sprite_renderable.h new file mode 100644 index 0000000..b4465c3 --- /dev/null +++ b/src/components/sprite_renderable.h @@ -0,0 +1,25 @@ +#ifndef SPRITE_RENDERABLE_H_D3AACBBF +#define SPRITE_RENDERABLE_H_D3AACBBF + +#include "component.h" +#include "renderer.h" + +class SpriteRenderableComponent : public Component { + public: + SpriteRenderableComponent(const char* filename, int frame_width, int frame_height, int frames_across); + + int getFrame() const; + void setFrame(int frame); + + const Texture& getTexture() const; + Rectangle getFrameRect() const; + + private: + Texture texture; + int frame_width; + int frame_height; + int frames_across; + int frame = 0; +}; + +#endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */ diff --git a/src/components/transformable.cpp b/src/components/transformable.cpp new file mode 100644 index 0000000..0d6b67e --- /dev/null +++ b/src/components/transformable.cpp @@ -0,0 +1,47 @@ +#include "transformable.h" + +TransformableComponent::TransformableComponent(double x, double y, int w, int h) + : x(x), y(y), w(w), h(h) +{ + +} + +double TransformableComponent::getX() const +{ + return x; +} + +double TransformableComponent::getY() const +{ + return y; +} + +int TransformableComponent::getW() const +{ + return w; +} + +int TransformableComponent::getH() const +{ + return h; +} + +void TransformableComponent::setX(double v) +{ + x = v; +} + +void TransformableComponent::setY(double v) +{ + y = v; +} + +void TransformableComponent::setW(int v) +{ + w = v; +} + +void TransformableComponent::setH(int v) +{ + h = v; +} diff --git a/src/components/transformable.h b/src/components/transformable.h new file mode 100644 index 0000000..87ba84d --- /dev/null +++ b/src/components/transformable.h @@ -0,0 +1,27 @@ +#ifndef LOCATABLE_H_39E526CA +#define LOCATABLE_H_39E526CA + +#include "component.h" + +class TransformableComponent : public Component { + public: + TransformableComponent(double x, double y, int w, int h); + + double getX() const; + double getY() const; + int getW() const; + int getH() const; + + void setX(double v); + void setY(double v); + void setW(int v); + void setH(int v); + + private: + double x; + double y; + int w; + int h; +}; + +#endif /* end of include guard: LOCATABLE_H_39E526CA */ diff --git a/src/entity_manager.cpp b/src/entity_manager.cpp new file mode 100644 index 0000000..4bdfe8a --- /dev/null +++ b/src/entity_manager.cpp @@ -0,0 +1,38 @@ +#ifndef ENTITY_MANAGER_CPP_42D78C22 +#define ENTITY_MANAGER_CPP_42D78C22 + +#include "entity_manager.h" + +template <> +std::set EntityManager::getEntitiesWithComponents<>(std::set& componentTypes) +{ + if (cachedComponents.count(componentTypes) == 1) + { + return cachedComponents[componentTypes]; + } + + std::set& cache = cachedComponents[componentTypes]; + for (auto& entity : entities) + { + EntityData& data = entity.second; + bool cacheEntity = true; + + for (auto& componentType : componentTypes) + { + if (data.components.count(componentType) == 0) + { + cacheEntity = false; + break; + } + } + + if (cacheEntity) + { + cache.insert(entity.first); + } + } + + return cache; +} + +#endif /* end of include guard: ENTITY_MANAGER_CPP_42D78C22 */ diff --git a/src/entity_manager.h b/src/entity_manager.h index 74e758c..5f0f2d4 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h @@ -6,70 +6,31 @@ #include #include #include "component.h" +#include "algorithms.h" class EntityManager { private: struct EntityData { - int parent = -1; std::map> components; }; std::map entities; - std::map> cachedChildren; std::map, std::set> cachedComponents; int nextEntityID = 0; - bool ensureNoParentCycles(int entity, int parent) + template + std::set getEntitiesWithComponentsHelper(std::set& componentTypes) { - EntityData& data = entities[parent]; - if (data.parent == entity) - { - return false; - } else if (data.parent == -1) - { - return true; - } + componentTypes.insert(typeid(T)); - return ensureNoParentCycles(entity, data.parent); + return getEntitiesWithComponents(componentTypes); } + template std::set getEntitiesWithComponents(std::set& componentTypes) { - if (cachedComponents.count(componentTypes) == 1) - { - return cachedComponents[componentTypes]; - } - - std::set& cache = cachedComponents[componentTypes]; - for (auto& entity : entities) - { - EntityData& data = entity.second; - bool cacheEntity = true; - - for (auto& componentType : componentTypes) - { - if (data.components.count(componentType) == 0) - { - cacheEntity = false; - break; - } - } - - if (cacheEntity) - { - cache.insert(entity.first); - } - } - - return cache; - } - - template std::set getEntitiesWithComponents(std::set& componentTypes) - { - componentTypes.insert(typeid(T)); - - return getEntitiesWithComponents(componentTypes); + return getEntitiesWithComponentsHelper(componentTypes); } public: @@ -107,26 +68,6 @@ class EntityManager { { assert(entities.count(entity) == 1); - EntityData& data = entities[entity]; - - // Destroy the children - std::set children = getChildren(entity); - for (int child : children) - { - EntityData& childData = entities[child]; - childData.parent = -1; - - deleteEntity(child); - } - - // Uncache children - cachedChildren.erase(entity); - - if ((data.parent != -1) && (cachedChildren.count(data.parent) == 1)) - { - cachedChildren[data.parent].erase(entity); - } - // Uncache components for (auto& cache : cachedComponents) { @@ -137,81 +78,8 @@ class EntityManager { entities.erase(entity); } - std::set getChildren(int parent) - { - assert(entities.count(parent) == 1); - - if (cachedChildren.count(parent) == 1) - { - return cachedChildren[parent]; - } - - std::set& cache = cachedChildren[parent]; - for (auto& entity : entities) - { - EntityData& data = entity.second; - if (data.parent == parent) - { - cache.insert(entity.first); - } - } - - return cache; - } - - void setParent(int entity, int parent) - { - assert(entities.count(entity) == 1); - assert(entities.count(parent) == 1); - assert(ensureNoParentCycles(entity, parent)); - - EntityData& data = entities[entity]; - - // Remove from old parent - if (data.parent != -1) - { - if (cachedChildren.count(data.parent) == 1) - { - cachedChildren[data.parent].erase(entity); - } - } - - data.parent = parent; - - // Cache new parent - if (cachedChildren.count(parent) == 1) - { - cachedChildren[parent].insert(entity); - } - } - - void setNoParent(int entity) - { - assert(entities.count(entity) == 1); - - EntityData& data = entities[entity]; - - // Remove from old parent - if (data.parent != -1) - { - if (cachedChildren.count(data.parent) == 1) - { - cachedChildren[data.parent].erase(entity); - } - } - - data.parent = -1; - } - - int getParent(int entity) - { - assert(entities.count(entity) == 1); - - EntityData& data = entities[entity]; - return data.parent; - } - - template T& emplaceComponent(int entity, Args&&... args) + template + T& emplaceComponent(int entity, Args&&... args) { assert(entities.count(entity) == 1); @@ -226,14 +94,15 @@ class EntityManager { data.components[componentType] = std::move(ptr); // Invalidate related caches - std::remove_if(begin(cachedComponents), end(cachedComponents), [&] (std::pair, int>& cache) { + erase_if(cachedComponents, [&componentType] (std::pair, std::set>& cache) { return cache.first.count(componentType) == 1; }); return component; } - template void removeComponent(int entity) + template + void removeComponent(int entity) { assert(entities.count(entity) == 1); @@ -255,7 +124,8 @@ class EntityManager { } } - template T& getComponent(int entity) + template + T& getComponent(int entity) { assert(entities.count(entity) == 1); @@ -264,16 +134,19 @@ class EntityManager { assert(data.components.count(componentType) == 1); - return *(data.components[componentType]); + return *((T*)data.components[componentType].get()); } - template std::set getEntitiesWithComponents() + template + std::set getEntitiesWithComponents() { std::set componentTypes; - componentTypes.insert(typeid(T)); - return getEntitiesWithComponents(componentTypes); + return getEntitiesWithComponentsHelper(componentTypes); } }; +template <> +std::set EntityManager::getEntitiesWithComponents<>(std::set& componentTypes); + #endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */ diff --git a/src/main.cpp b/src/main.cpp index 29a364b..dcf8d87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,22 +4,39 @@ #include "renderer.h" #include "muxer.h" #include "entity_manager.h" +#include "components/sprite_renderable.h" +#include "components/transformable.h" +#include "systems/rendering.h" int main() { srand(time(NULL)); GLFWwindow* window = initRenderer(); + glfwSwapInterval(1); + initMuxer(); // Put this in a block so game goes out of scope before we destroy the renderer { EntityManager manager; - int eRef = manager.emplaceEntity(); - int eRef2 = manager.emplaceEntity(); - manager.setParent(eRef, eRef2); - printf("%d\n", manager.getParent(eRef)); + int player = manager.emplaceEntity(); + manager.emplaceComponent(player, "res/Starla.png", 10, 12, 6); + manager.emplaceComponent(player, 203, 44, 10, 12); + + std::list> loop; + loop.push_back(std::unique_ptr(new RenderingSystem())); + + while (!glfwWindowShouldClose(window)) + { + for (auto& sys : loop) + { + sys->tick(manager, 1.0); + } + + glfwPollEvents(); + } } destroyMuxer(); diff --git a/src/system.h b/src/system.h new file mode 100644 index 0000000..85415f0 --- /dev/null +++ b/src/system.h @@ -0,0 +1,11 @@ +#ifndef SYSTEM_H_B61A8CEA +#define SYSTEM_H_B61A8CEA + +class EntityManager; + +class System { + public: + virtual void tick(EntityManager& manager, float dt) = 0; +}; + +#endif /* end of include guard: SYSTEM_H_B61A8CEA */ diff --git a/src/systems/rendering.cpp b/src/systems/rendering.cpp new file mode 100644 index 0000000..0034dc3 --- /dev/null +++ b/src/systems/rendering.cpp @@ -0,0 +1,21 @@ +#include "rendering.h" +#include "entity_manager.h" +#include "components/sprite_renderable.h" +#include "components/transformable.h" + +void RenderingSystem::tick(EntityManager& manager, float dt) +{ + texture.fill(texture.entirety(), 0, 0, 0); + + std::set spriteEntities = manager.getEntitiesWithComponents(); + for (int entity : spriteEntities) + { + auto& sprite = manager.getComponent(entity); + auto& transform = manager.getComponent(entity); + Rectangle dstrect {(int) transform.getX(), (int) transform.getY(), transform.getW(), transform.getH()}; + + texture.blit(sprite.getTexture(), sprite.getFrameRect(), dstrect); + } + + texture.renderScreen(); +} diff --git a/src/systems/rendering.h b/src/systems/rendering.h new file mode 100644 index 0000000..80ea79e --- /dev/null +++ b/src/systems/rendering.h @@ -0,0 +1,16 @@ +#ifndef RENDERING_H_76ABC02A +#define RENDERING_H_76ABC02A + +#include "system.h" +#include "renderer.h" +#include "consts.h" + +class RenderingSystem : public System { + public: + void tick(EntityManager& manager, float dt); + + private: + Texture texture {GAME_WIDTH, GAME_HEIGHT}; +}; + +#endif /* end of include guard: RENDERING_H_76ABC02A */ -- cgit 1.4.1 From 428c401f9c1053f7e13ffe641758dfb72791d8dc Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 26 Jun 2015 19:59:28 -0400 Subject: Player now moves --- CMakeLists.txt | 8 +- src/components/animatable.cpp | 27 ++++++ src/components/animatable.h | 31 +++++++ src/components/controllable.cpp | 71 +++++++++++++++ src/components/controllable.h | 36 ++++++++ src/components/droppable.cpp | 11 +++ src/components/droppable.h | 15 ++++ src/components/ponderable.cpp | 41 +++++++++ src/components/ponderable.h | 24 +++++ src/components/sprite_renderable.cpp | 27 ------ src/components/sprite_renderable.h | 25 ------ src/consts.h | 3 + src/direction.h | 11 +++ src/game.cpp | 75 ++++++++++++++++ src/game.h | 24 +++++ src/main.cpp | 25 +----- src/system.h | 10 ++- src/system_manager.h | 37 ++++++++ src/systems/controlling.cpp | 168 +++++++++++++++++++++++++++++++++++ src/systems/controlling.h | 26 ++++++ src/systems/pondering.cpp | 23 +++++ src/systems/pondering.h | 14 +++ src/systems/rendering.cpp | 12 +-- src/systems/rendering.h | 5 +- 24 files changed, 665 insertions(+), 84 deletions(-) create mode 100644 src/components/animatable.cpp create mode 100644 src/components/animatable.h create mode 100644 src/components/controllable.cpp create mode 100644 src/components/controllable.h create mode 100644 src/components/droppable.cpp create mode 100644 src/components/droppable.h create mode 100644 src/components/ponderable.cpp create mode 100644 src/components/ponderable.h delete mode 100644 src/components/sprite_renderable.cpp delete mode 100644 src/components/sprite_renderable.h create mode 100644 src/direction.h create mode 100644 src/game.cpp create mode 100644 src/game.h create mode 100644 src/system_manager.h create mode 100644 src/systems/controlling.cpp create mode 100644 src/systems/controlling.h create mode 100644 src/systems/pondering.cpp create mode 100644 src/systems/pondering.h (limited to 'src/main.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bfde77..9e4ac25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,9 +50,15 @@ add_executable(Aromatherapy src/renderer.cpp src/muxer.cpp src/entity_manager.cpp - src/components/sprite_renderable.cpp + src/game.cpp src/components/transformable.cpp + src/components/droppable.cpp + src/components/controllable.cpp + src/components/ponderable.cpp + src/components/animatable.cpp src/systems/rendering.cpp + src/systems/controlling.cpp + src/systems/pondering.cpp ) target_link_libraries(Aromatherapy ${ALL_LIBS}) install(TARGETS Aromatherapy RUNTIME DESTINATION ${BIN_DIR}) diff --git a/src/components/animatable.cpp b/src/components/animatable.cpp new file mode 100644 index 0000000..fcd277c --- /dev/null +++ b/src/components/animatable.cpp @@ -0,0 +1,27 @@ +#include "animatable.h" + +AnimatableComponent::AnimatableComponent(const char* filename, int frame_width, int frame_height, int frames_across) + : texture(filename), frame_width(frame_width), frame_height(frame_height), frames_across(frames_across) +{ + +} + +int AnimatableComponent::getFrame() const +{ + return frame; +} + +void AnimatableComponent::setFrame(int frame) +{ + this->frame = frame; +} + +const Texture& AnimatableComponent::getTexture() const +{ + return texture; +} + +Rectangle AnimatableComponent::getFrameRect() const +{ + return {frame_width * (frame % frames_across), frame_height * (frame / frames_across), frame_width, frame_height}; +} diff --git a/src/components/animatable.h b/src/components/animatable.h new file mode 100644 index 0000000..cf6ee54 --- /dev/null +++ b/src/components/animatable.h @@ -0,0 +1,31 @@ +#ifndef SPRITE_RENDERABLE_H_D3AACBBF +#define SPRITE_RENDERABLE_H_D3AACBBF + +#include "component.h" +#include "renderer.h" +#include "direction.h" + +class AnimatableComponent : public Component { + public: + AnimatableComponent(const char* filename, int frame_width, int frame_height, int frames_across); + + int getFrame() const; + void setFrame(int frame); + + const Texture& getTexture() const; + Rectangle getFrameRect() const; + + void setDirection(Direction dir) {}; + void setWalking(bool w) {}; + void setJumping(bool w) {}; + void setCrouching(bool w) {}; + + private: + Texture texture; + int frame_width; + int frame_height; + int frames_across; + int frame = 0; +}; + +#endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */ diff --git a/src/components/controllable.cpp b/src/components/controllable.cpp new file mode 100644 index 0000000..a4d45f2 --- /dev/null +++ b/src/components/controllable.cpp @@ -0,0 +1,71 @@ +#include "controllable.h" + +int ControllableComponent::getLeftKey() const +{ + return leftKey; +} + +void ControllableComponent::setLeftKey(int k) +{ + leftKey = k; +} + +int ControllableComponent::getRightKey() const +{ + return rightKey; +} + +void ControllableComponent::setRightKey(int k) +{ + rightKey = k; +} + +int ControllableComponent::getJumpKey() const +{ + return jumpKey; +} + +void ControllableComponent::setJumpKey(int k) +{ + jumpKey = k; +} + +int ControllableComponent::getDropKey() const +{ + return dropKey; +} + +void ControllableComponent::setDropKey(int k) +{ + dropKey = k; +} + +bool ControllableComponent::isFrozen() const +{ + return frozen; +} + +void ControllableComponent::setFrozen(bool f) +{ + frozen = f; +} + +bool ControllableComponent::isHoldingLeft() const +{ + return holdingLeft; +} + +void ControllableComponent::setHoldingLeft(bool f) +{ + holdingLeft = f; +} + +bool ControllableComponent::isHoldingRight() const +{ + return holdingRight; +} + +void ControllableComponent::setHoldingRight(bool f) +{ + holdingRight = f; +} diff --git a/src/components/controllable.h b/src/components/controllable.h new file mode 100644 index 0000000..317d68d --- /dev/null +++ b/src/components/controllable.h @@ -0,0 +1,36 @@ +#ifndef CONTROLLABLE_H_4E0B85B4 +#define CONTROLLABLE_H_4E0B85B4 + +#include "component.h" +#include "renderer.h" + +class ControllableComponent : public Component { + public: + int getLeftKey() const; + void setLeftKey(int k); + int getRightKey() const; + void setRightKey(int k); + int getJumpKey() const; + void setJumpKey(int k); + int getDropKey() const; + void setDropKey(int k); + + bool isFrozen() const; + void setFrozen(bool f); + bool isHoldingLeft() const; + void setHoldingLeft(bool f); + bool isHoldingRight() const; + void setHoldingRight(bool f); + + private: + int leftKey = GLFW_KEY_LEFT; + int rightKey = GLFW_KEY_RIGHT; + int jumpKey = GLFW_KEY_UP; + int dropKey = GLFW_KEY_DOWN; + + bool frozen = false; + bool holdingLeft = false; + bool holdingRight = false; +}; + +#endif /* end of include guard: CONTROLLABLE_H_4E0B85B4 */ diff --git a/src/components/droppable.cpp b/src/components/droppable.cpp new file mode 100644 index 0000000..534fd9a --- /dev/null +++ b/src/components/droppable.cpp @@ -0,0 +1,11 @@ +#include "droppable.h" + +void DroppableComponent::setDroppable(bool can) +{ + droppable = can; +} + +bool DroppableComponent::isDroppable() const +{ + return droppable; +} diff --git a/src/components/droppable.h b/src/components/droppable.h new file mode 100644 index 0000000..1f5608b --- /dev/null +++ b/src/components/droppable.h @@ -0,0 +1,15 @@ +#ifndef DROPPABLE_H_5DB254EF +#define DROPPABLE_H_5DB254EF + +#include "component.h" + +class DroppableComponent : public Component { + public: + void setDroppable(bool can); + bool isDroppable() const; + + private: + bool droppable = false; +}; + +#endif /* end of include guard: DROPPABLE_H_5DB254EF */ diff --git a/src/components/ponderable.cpp b/src/components/ponderable.cpp new file mode 100644 index 0000000..2cfa6a6 --- /dev/null +++ b/src/components/ponderable.cpp @@ -0,0 +1,41 @@ +#include "ponderable.h" + +double PonderableComponent::getVelocityX() const +{ + return velocityX; +} + +void PonderableComponent::setVelocityX(double v) +{ + velocityX = v; +} + +double PonderableComponent::getVelocityY() const +{ + return velocityY; +} + +void PonderableComponent::setVelocityY(double v) +{ + velocityY = v; +} + +double PonderableComponent::getAccelX() const +{ + return accelX; +} + +void PonderableComponent::setAccelX(double v) +{ + accelX = v; +} + +double PonderableComponent::getAccelY() const +{ + return accelY; +} + +void PonderableComponent::setAccelY(double v) +{ + accelY = v; +} diff --git a/src/components/ponderable.h b/src/components/ponderable.h new file mode 100644 index 0000000..5aab4b3 --- /dev/null +++ b/src/components/ponderable.h @@ -0,0 +1,24 @@ +#ifndef TANGIBLE_H_746DB3EE +#define TANGIBLE_H_746DB3EE + +#include "component.h" + +class PonderableComponent : public Component { + public: + double getVelocityX() const; + void setVelocityX(double v); + double getVelocityY() const; + void setVelocityY(double v); + double getAccelX() const; + void setAccelX(double v); + double getAccelY() const; + void setAccelY(double v); + + private: + double velocityX = 0.0; + double velocityY = 0.0; + double accelX = 0.0; + double accelY = 0.0; +}; + +#endif /* end of include guard: TANGIBLE_H_746DB3EE */ diff --git a/src/components/sprite_renderable.cpp b/src/components/sprite_renderable.cpp deleted file mode 100644 index 4c61111..0000000 --- a/src/components/sprite_renderable.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "sprite_renderable.h" - -SpriteRenderableComponent::SpriteRenderableComponent(const char* filename, int frame_width, int frame_height, int frames_across) - : texture(filename), frame_width(frame_width), frame_height(frame_height), frames_across(frames_across) -{ - -} - -int SpriteRenderableComponent::getFrame() const -{ - return frame; -} - -void SpriteRenderableComponent::setFrame(int frame) -{ - this->frame = frame; -} - -const Texture& SpriteRenderableComponent::getTexture() const -{ - return texture; -} - -Rectangle SpriteRenderableComponent::getFrameRect() const -{ - return {frame_width * (frame % frames_across), frame_height * (frame / frames_across), frame_width, frame_height}; -} diff --git a/src/components/sprite_renderable.h b/src/components/sprite_renderable.h deleted file mode 100644 index b4465c3..0000000 --- a/src/components/sprite_renderable.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef SPRITE_RENDERABLE_H_D3AACBBF -#define SPRITE_RENDERABLE_H_D3AACBBF - -#include "component.h" -#include "renderer.h" - -class SpriteRenderableComponent : public Component { - public: - SpriteRenderableComponent(const char* filename, int frame_width, int frame_height, int frames_across); - - int getFrame() const; - void setFrame(int frame); - - const Texture& getTexture() const; - Rectangle getFrameRect() const; - - private: - Texture texture; - int frame_width; - int frame_height; - int frames_across; - int frame = 0; -}; - -#endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */ diff --git a/src/consts.h b/src/consts.h index 804c761..4595719 100644 --- a/src/consts.h +++ b/src/consts.h @@ -11,4 +11,7 @@ const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT - 1; const int FRAMES_PER_SECOND = 60; const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND; +#define JUMP_VELOCITY(h, l) (-2 * (h) / (l)) +#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l)) + #endif diff --git a/src/direction.h b/src/direction.h new file mode 100644 index 0000000..32d6b41 --- /dev/null +++ b/src/direction.h @@ -0,0 +1,11 @@ +#ifndef DIRECTION_H_9C49EAFD +#define DIRECTION_H_9C49EAFD + +enum class Direction { + Left, + Right, + Up, + Down +}; + +#endif /* end of include guard: DIRECTION_H_9C49EAFD */ diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..b3fa9a8 --- /dev/null +++ b/src/game.cpp @@ -0,0 +1,75 @@ +#include "game.h" +#include "components/animatable.h" +#include "components/transformable.h" +#include "components/controllable.h" +#include "components/droppable.h" +#include "components/ponderable.h" +#include "systems/rendering.h" +#include "systems/controlling.h" +#include "systems/pondering.h" + +void key_callback(GLFWwindow* window, int key, int, int action, int) +{ + Game& game = *((Game*) glfwGetWindowUserPointer(window)); + + if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE)) + { + game.shouldQuit = true; + + return; + } + + game.systemManager.getSystem().input(key, action); +} + +Game::Game(GLFWwindow* window) : window(window) +{ + systemManager.emplaceSystem(*this); + systemManager.emplaceSystem(*this); + systemManager.emplaceSystem(*this); + + int player = entityManager.emplaceEntity(); + entityManager.emplaceComponent(player, "res/Starla.png", 10, 12, 6); + entityManager.emplaceComponent(player, 203, 44, 10, 12); + entityManager.emplaceComponent(player); + entityManager.emplaceComponent(player); + entityManager.emplaceComponent(player); + + glfwSwapInterval(1); + glfwSetWindowUserPointer(window, this); + glfwSetKeyCallback(window, key_callback); +} + +void Game::execute() +{ + double lastTime = glfwGetTime(); + const double dt = 0.01; + double accumulator = 0.0; + + while (!(shouldQuit || glfwWindowShouldClose(window))) + { + double currentTime = glfwGetTime(); + double frameTime = currentTime - lastTime; + lastTime = currentTime; + + glfwPollEvents(); + + accumulator += frameTime; + while (accumulator >= dt) + { + systemManager.getSystem().tick(dt); + systemManager.getSystem().tick(dt); + + accumulator -= dt; + } + + systemManager.getSystem().tick(frameTime); + } +} + +EntityManager& Game::getEntityManager() +{ + return entityManager; +} + + diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..3822700 --- /dev/null +++ b/src/game.h @@ -0,0 +1,24 @@ +#ifndef GAME_H_1014DDC9 +#define GAME_H_1014DDC9 + +#include "renderer.h" +#include "entity_manager.h" +#include "system_manager.h" + +class Game { + public: + Game(GLFWwindow* window); + + void execute(); + EntityManager& getEntityManager(); + + friend void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); + + private: + EntityManager entityManager; + SystemManager systemManager; + GLFWwindow* const window; + bool shouldQuit = false; +}; + +#endif /* end of include guard: GAME_H_1014DDC9 */ diff --git a/src/main.cpp b/src/main.cpp index dcf8d87..35749f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,10 +3,7 @@ #include #include "renderer.h" #include "muxer.h" -#include "entity_manager.h" -#include "components/sprite_renderable.h" -#include "components/transformable.h" -#include "systems/rendering.h" +#include "game.h" int main() { @@ -19,24 +16,8 @@ int main() // Put this in a block so game goes out of scope before we destroy the renderer { - EntityManager manager; - - int player = manager.emplaceEntity(); - manager.emplaceComponent(player, "res/Starla.png", 10, 12, 6); - manager.emplaceComponent(player, 203, 44, 10, 12); - - std::list> loop; - loop.push_back(std::unique_ptr(new RenderingSystem())); - - while (!glfwWindowShouldClose(window)) - { - for (auto& sys : loop) - { - sys->tick(manager, 1.0); - } - - glfwPollEvents(); - } + Game game {window}; + game.execute(); } destroyMuxer(); diff --git a/src/system.h b/src/system.h index 85415f0..e08db0a 100644 --- a/src/system.h +++ b/src/system.h @@ -1,11 +1,17 @@ #ifndef SYSTEM_H_B61A8CEA #define SYSTEM_H_B61A8CEA -class EntityManager; +class Game; class System { public: - virtual void tick(EntityManager& manager, float dt) = 0; + System(Game& game) + : game(game) {} + + virtual void tick(double dt) = 0; + + protected: + Game& game; }; #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..8f76db2 --- /dev/null +++ b/src/system_manager.h @@ -0,0 +1,37 @@ +#ifndef SYSTEM_MANAGER_H_544E6056 +#define SYSTEM_MANAGER_H_544E6056 + +#include +#include +#include +#include +#include "system.h" + +class SystemManager { + private: + std::list> loop; + std::map systems; + + public: + template + void emplaceSystem(Game& game, Args&&... args) + { + std::unique_ptr ptr = std::unique_ptr(new T(game, std::forward(args)...)); + std::type_index systemType = typeid(T); + + systems[systemType] = ptr.get(); + loop.push_back(std::move(ptr)); + } + + template + T& getSystem() + { + std::type_index systemType = typeid(T); + + assert(systems.count(systemType) == 1); + + return *((T*)systems[systemType]); + } +}; + +#endif /* end of include guard: SYSTEM_MANAGER_H_544E6056 */ diff --git a/src/systems/controlling.cpp b/src/systems/controlling.cpp new file mode 100644 index 0000000..b1e73ad --- /dev/null +++ b/src/systems/controlling.cpp @@ -0,0 +1,168 @@ +#include "controlling.h" +#include "game.h" +#include "components/controllable.h" +#include "components/ponderable.h" +#include "components/animatable.h" +#include "components/droppable.h" +#include "direction.h" +#include "muxer.h" +#include "consts.h" + +void ControllingSystem::tick(double dt) +{ + while (!actions.empty()) + { + int key = actions.front().first; + int action = actions.front().second; + + auto entities = game.getEntityManager().getEntitiesWithComponents(); + for (auto entity : entities) + { + auto& controllable = game.getEntityManager().getComponent(entity); + + if (action == GLFW_PRESS) + { + if (key == controllable.getLeftKey()) + { + controllable.setHoldingLeft(true); + + if (!controllable.isFrozen()) + { + walkLeft(entity); + } + } else if (key == controllable.getRightKey()) + { + controllable.setHoldingRight(true); + + if (!controllable.isFrozen()) + { + walkRight(entity); + } + } else if (key == controllable.getJumpKey()) + { + if (!controllable.isFrozen()) + { + jump(entity); + } + } else if (key == controllable.getDropKey()) + { + if (!controllable.isFrozen()) + { + drop(entity, true); + } + } + } else if (action == GLFW_RELEASE) + { + if (key == controllable.getLeftKey()) + { + controllable.setHoldingLeft(false); + + if (!controllable.isFrozen()) + { + if (controllable.isHoldingRight()) + { + walkRight(entity); + } else { + stopWalking(entity); + } + } + } else if (key == controllable.getRightKey()) + { + controllable.setHoldingRight(false); + + if (!controllable.isFrozen()) + { + if (controllable.isHoldingRight()) + { + walkLeft(entity); + } else { + stopWalking(entity); + } + } + } else if (key == controllable.getDropKey()) + { + if (!controllable.isFrozen()) + { + drop(entity, false); + } + } else if (key == controllable.getJumpKey()) + { + if (!controllable.isFrozen()) + { + stopJumping(entity); + } + } + } + } + + actions.pop(); + } +} + +void ControllingSystem::input(int key, int action) +{ + actions.push(std::make_pair(key, action)); +} + +void ControllingSystem::walkLeft(int entity) +{ + auto& ponderable = game.getEntityManager().getComponent(entity); + auto& animatable = game.getEntityManager().getComponent(entity); + + ponderable.setVelocityX(-90); + + animatable.setDirection(Direction::Left); + animatable.setWalking(true); +} + +void ControllingSystem::walkRight(int entity) +{ + auto& ponderable = game.getEntityManager().getComponent(entity); + auto& animatable = game.getEntityManager().getComponent(entity); + + ponderable.setVelocityX(90); + + animatable.setDirection(Direction::Right); + animatable.setWalking(true); +} + +void ControllingSystem::stopWalking(int entity) +{ + auto& ponderable = game.getEntityManager().getComponent(entity); + auto& animatable = game.getEntityManager().getComponent(entity); + + ponderable.setVelocityX(0); + + animatable.setWalking(false); +} + +void ControllingSystem::jump(int entity) +{ + auto& ponderable = game.getEntityManager().getComponent(entity); + auto& animatable = game.getEntityManager().getComponent(entity); + + playSound("res/Randomize87.wav", 0.25); + + ponderable.setVelocityY(JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3)); + ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3)); + + animatable.setJumping(true); +} + +void ControllingSystem::stopJumping(int entity) +{ + auto& ponderable = game.getEntityManager().getComponent(entity); + auto& animatable = game.getEntityManager().getComponent(entity); + + ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233)); + animatable.setJumping(false); +} + +void ControllingSystem::drop(int entity, bool start) +{ + auto& animatable = game.getEntityManager().getComponent(entity); + auto& droppable = game.getEntityManager().getComponent(entity); + + droppable.setDroppable(start); + animatable.setCrouching(start); +} diff --git a/src/systems/controlling.h b/src/systems/controlling.h new file mode 100644 index 0000000..61f86eb --- /dev/null +++ b/src/systems/controlling.h @@ -0,0 +1,26 @@ +#ifndef CONTROLLING_H_80B1BB8D +#define CONTROLLING_H_80B1BB8D + +#include "system.h" +#include + +class ControllingSystem : public System { + public: + ControllingSystem(Game& game) + : System(game) {} + + void tick(double dt); + void input(int key, int action); + + private: + void walkLeft(int entity); + void walkRight(int entity); + void stopWalking(int entity); + void jump(int entity); + void stopJumping(int entity); + void drop(int entity, bool start); + + std::queue> actions; +}; + +#endif /* end of include guard: CONTROLLING_H_80B1BB8D */ diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp new file mode 100644 index 0000000..96775d0 --- /dev/null +++ b/src/systems/pondering.cpp @@ -0,0 +1,23 @@ +#include "pondering.h" +#include "game.h" +#include "components/ponderable.h" +#include "components/transformable.h" + +void PonderingSystem::tick(double dt) +{ + auto entities = game.getEntityManager().getEntitiesWithComponents(); + + for (auto entity : entities) + { + auto& transformable = game.getEntityManager().getComponent(entity); + auto& ponderable = game.getEntityManager().getComponent(entity); + + // Accelerate + ponderable.setVelocityX(ponderable.getVelocityX() + ponderable.getAccelX() * dt); + ponderable.setVelocityY(ponderable.getVelocityY() + ponderable.getAccelY() * dt); + + // Move + transformable.setX(transformable.getX() + ponderable.getVelocityX() * dt); + transformable.setY(transformable.getY() + ponderable.getVelocityY() * dt); + } +} diff --git a/src/systems/pondering.h b/src/systems/pondering.h new file mode 100644 index 0000000..ad01a22 --- /dev/null +++ b/src/systems/pondering.h @@ -0,0 +1,14 @@ +#ifndef PONDERING_H_F2530E0E +#define PONDERING_H_F2530E0E + +#include "system.h" + +class PonderingSystem : public System { + public: + PonderingSystem(Game& game) + : System(game) {} + + void tick(double dt); +}; + +#endif /* end of include guard: PONDERING_H_F2530E0E */ diff --git a/src/systems/rendering.cpp b/src/systems/rendering.cpp index 0034dc3..251c2bc 100644 --- a/src/systems/rendering.cpp +++ b/src/systems/rendering.cpp @@ -1,17 +1,17 @@ #include "rendering.h" -#include "entity_manager.h" -#include "components/sprite_renderable.h" +#include "game.h" +#include "components/animatable.h" #include "components/transformable.h" -void RenderingSystem::tick(EntityManager& manager, float dt) +void RenderingSystem::tick(double dt) { texture.fill(texture.entirety(), 0, 0, 0); - std::set spriteEntities = manager.getEntitiesWithComponents(); + std::set spriteEntities = game.getEntityManager().getEntitiesWithComponents(); for (int entity : spriteEntities) { - auto& sprite = manager.getComponent(entity); - auto& transform = manager.getComponent(entity); + auto& sprite = game.getEntityManager().getComponent(entity); + auto& transform = game.getEntityManager().getComponent(entity); Rectangle dstrect {(int) transform.getX(), (int) transform.getY(), transform.getW(), transform.getH()}; texture.blit(sprite.getTexture(), sprite.getFrameRect(), dstrect); diff --git a/src/systems/rendering.h b/src/systems/rendering.h index 80ea79e..9b6e27e 100644 --- a/src/systems/rendering.h +++ b/src/systems/rendering.h @@ -7,7 +7,10 @@ class RenderingSystem : public System { public: - void tick(EntityManager& manager, float dt); + RenderingSystem(Game& game) + : System(game) {} + + void tick(double dt); private: Texture texture {GAME_WIDTH, GAME_HEIGHT}; -- cgit 1.4.1 From da3df061699203eccc9a0c98becaee3ce8050a4f Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Mon, 5 Feb 2018 11:51:24 -0500 Subject: Whitespace changes --- src/components/controllable.h | 6 +- src/components/droppable.h | 2 +- src/components/ponderable.h | 2 +- src/components/transformable.cpp | 2 +- src/components/transformable.h | 6 +- src/entity_manager.cpp | 8 +- src/entity_manager.h | 64 +++++------ src/game.cpp | 10 +- src/game.h | 6 +- src/main.cpp | 10 +- src/renderer.cpp | 228 +++++++++++++++++++-------------------- src/renderer.h | 2 +- src/system.h | 4 +- src/system_manager.h | 8 +- src/systems/controlling.cpp | 12 +-- src/systems/controlling.h | 6 +- src/systems/pondering.cpp | 6 +- src/systems/pondering.h | 2 +- src/systems/rendering.h | 4 +- 19 files changed, 194 insertions(+), 194 deletions(-) (limited to 'src/main.cpp') diff --git a/src/components/controllable.h b/src/components/controllable.h index 317d68d..baccf13 100644 --- a/src/components/controllable.h +++ b/src/components/controllable.h @@ -14,20 +14,20 @@ class ControllableComponent : public Component { void setJumpKey(int k); int getDropKey() const; void setDropKey(int k); - + bool isFrozen() const; void setFrozen(bool f); bool isHoldingLeft() const; void setHoldingLeft(bool f); bool isHoldingRight() const; void setHoldingRight(bool f); - + private: int leftKey = GLFW_KEY_LEFT; int rightKey = GLFW_KEY_RIGHT; int jumpKey = GLFW_KEY_UP; int dropKey = GLFW_KEY_DOWN; - + bool frozen = false; bool holdingLeft = false; bool holdingRight = false; diff --git a/src/components/droppable.h b/src/components/droppable.h index 1f5608b..83fcb9d 100644 --- a/src/components/droppable.h +++ b/src/components/droppable.h @@ -7,7 +7,7 @@ class DroppableComponent : public Component { public: void setDroppable(bool can); bool isDroppable() const; - + private: bool droppable = false; }; diff --git a/src/components/ponderable.h b/src/components/ponderable.h index 5aab4b3..c836d2a 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -13,7 +13,7 @@ class PonderableComponent : public Component { void setAccelX(double v); double getAccelY() const; void setAccelY(double v); - + private: double velocityX = 0.0; double velocityY = 0.0; diff --git a/src/components/transformable.cpp b/src/components/transformable.cpp index 0d6b67e..89b1e5d 100644 --- a/src/components/transformable.cpp +++ b/src/components/transformable.cpp @@ -3,7 +3,7 @@ TransformableComponent::TransformableComponent(double x, double y, int w, int h) : x(x), y(y), w(w), h(h) { - + } double TransformableComponent::getX() const diff --git a/src/components/transformable.h b/src/components/transformable.h index 87ba84d..69f4f0e 100644 --- a/src/components/transformable.h +++ b/src/components/transformable.h @@ -6,17 +6,17 @@ class TransformableComponent : public Component { public: TransformableComponent(double x, double y, int w, int h); - + double getX() const; double getY() const; int getW() const; int getH() const; - + void setX(double v); void setY(double v); void setW(int v); void setH(int v); - + private: double x; double y; diff --git a/src/entity_manager.cpp b/src/entity_manager.cpp index 4bdfe8a..9ad758b 100644 --- a/src/entity_manager.cpp +++ b/src/entity_manager.cpp @@ -10,13 +10,13 @@ std::set EntityManager::getEntitiesWithComponents<>(std::set& cache = cachedComponents[componentTypes]; for (auto& entity : entities) { EntityData& data = entity.second; bool cacheEntity = true; - + for (auto& componentType : componentTypes) { if (data.components.count(componentType) == 0) @@ -25,13 +25,13 @@ std::set EntityManager::getEntitiesWithComponents<>(std::set> components; }; - + std::map entities; std::map, std::set> cachedComponents; - + int nextEntityID = 0; - + template std::set getEntitiesWithComponentsHelper(std::set& componentTypes) { componentTypes.insert(typeid(T)); - + return getEntitiesWithComponents(componentTypes); } - + template std::set getEntitiesWithComponents(std::set& componentTypes) { return getEntitiesWithComponentsHelper(componentTypes); } - + public: EntityManager() = default; EntityManager(const EntityManager& copy) = delete; - + int emplaceEntity() { // Find a suitable entity ID @@ -44,76 +44,76 @@ class EntityManager { { nextEntityID++; } - + if (nextEntityID < 0) { nextEntityID = 0; - + while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0)) { nextEntityID++; } - + assert(nextEntityID >= 0); } - + // Initialize the data int id = nextEntityID++; entities[id]; - + return id; } - + void deleteEntity(int entity) { assert(entities.count(entity) == 1); - + // Uncache components for (auto& cache : cachedComponents) { cache.second.erase(entity); } - + // Destroy the data entities.erase(entity); } - + template T& emplaceComponent(int entity, Args&&... args) { assert(entities.count(entity) == 1); - + EntityData& data = entities[entity]; std::type_index componentType = typeid(T); - + assert(data.components.count(componentType) == 0); - + // Initialize the component std::unique_ptr ptr = std::unique_ptr(new T(std::forward(args)...)); T& component = *ptr; data.components[componentType] = std::move(ptr); - + // Invalidate related caches erase_if(cachedComponents, [&componentType] (std::pair, std::set>& cache) { return cache.first.count(componentType) == 1; }); - + return component; } - + template void removeComponent(int entity) { assert(entities.count(entity) == 1); - + EntityData& data = entities[entity]; std::type_index componentType = typeid(T); - + assert(data.components.count(componentType) == 1); - + // Destroy the component data.components.erase(componentType); - + // Uncache the component for (auto& cache : cachedComponents) { @@ -123,25 +123,25 @@ class EntityManager { } } } - + template T& getComponent(int entity) { assert(entities.count(entity) == 1); - + EntityData& data = entities[entity]; std::type_index componentType = typeid(T); - + assert(data.components.count(componentType) == 1); - + return *((T*)data.components[componentType].get()); } - + template std::set getEntitiesWithComponents() { std::set componentTypes; - + return getEntitiesWithComponentsHelper(componentTypes); } }; diff --git a/src/game.cpp b/src/game.cpp index b3fa9a8..5d1ec18 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -45,24 +45,24 @@ void Game::execute() double lastTime = glfwGetTime(); const double dt = 0.01; double accumulator = 0.0; - + while (!(shouldQuit || glfwWindowShouldClose(window))) { double currentTime = glfwGetTime(); double frameTime = currentTime - lastTime; lastTime = currentTime; - + glfwPollEvents(); - + accumulator += frameTime; while (accumulator >= dt) { systemManager.getSystem().tick(dt); systemManager.getSystem().tick(dt); - + accumulator -= dt; } - + systemManager.getSystem().tick(frameTime); } } diff --git a/src/game.h b/src/game.h index 3822700..ec667c8 100644 --- a/src/game.h +++ b/src/game.h @@ -8,12 +8,12 @@ class Game { public: Game(GLFWwindow* window); - + void execute(); EntityManager& getEntityManager(); - + friend void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); - + private: EntityManager entityManager; SystemManager systemManager; diff --git a/src/main.cpp b/src/main.cpp index 35749f5..d51da7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,20 +8,20 @@ int main() { srand(time(NULL)); - + GLFWwindow* window = initRenderer(); glfwSwapInterval(1); - + initMuxer(); - + // Put this in a block so game goes out of scope before we destroy the renderer { Game game {window}; game.execute(); } - + destroyMuxer(); destroyRenderer(); - + return 0; } diff --git a/src/renderer.cpp b/src/renderer.cpp index 99d5389..d0d2b75 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -56,11 +56,11 @@ static GLuint mesh_normalbuffer; static int mesh_numvertices; GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path) -{ +{ // Create the shaders GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); - + // Read the Vertex Shader code from the file std::string VertexShaderCode; 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) VertexShaderCode += "\n" + Line; VertexShaderStream.close(); } - + // Read the Fragment Shader code from the file std::string FragmentShaderCode; 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) FragmentShaderCode += "\n" + Line; FragmentShaderStream.close(); } - + GLint Result = GL_FALSE; int InfoLogLength; - + // Compile Vertex Shader printf("Compiling shader : %s\n", vertex_file_path); char const * VertexSourcePointer = VertexShaderCode.c_str(); glShaderSource(VertexShaderID, 1, &VertexSourcePointer , nullptr); glCompileShader(VertexShaderID); - + // Check Vertex Shader glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector VertexShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(VertexShaderID, InfoLogLength, nullptr, &VertexShaderErrorMessage[0]); fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]); - + // Compile Fragment Shader printf("Compiling shader : %s\n", fragment_file_path); char const * FragmentSourcePointer = FragmentShaderCode.c_str(); glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , nullptr); glCompileShader(FragmentShaderID); - + // Check Fragment Shader glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector FragmentShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(FragmentShaderID, InfoLogLength, nullptr, &FragmentShaderErrorMessage[0]); fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]); - + // Link the program fprintf(stdout, "Linking program\n"); GLuint ProgramID = glCreateProgram(); glAttachShader(ProgramID, VertexShaderID); glAttachShader(ProgramID, FragmentShaderID); glLinkProgram(ProgramID); - + // Check the program glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector ProgramErrorMessage( glm::max(InfoLogLength, int(1)) ); glGetProgramInfoLog(ProgramID, InfoLogLength, nullptr, &ProgramErrorMessage[0]); fprintf(stdout, "%s\n", &ProgramErrorMessage[0]); - + glDeleteShader(VertexShaderID); glDeleteShader(FragmentShaderID); - + return ProgramID; } @@ -135,14 +135,14 @@ void flipImageData(unsigned char* data, int width, int height, int comps) { unsigned char* data_copy = (unsigned char*) malloc(width*height*comps*sizeof(unsigned char)); memcpy(data_copy, data, width*height*comps); - + int row_size = width * comps; - + for (int i=0;i& out_vertices, std::v fprintf(stderr, "Could not open mesh file %s\n", filename); exit(1); } - + std::vector temp_vertices; std::vector temp_uvs; std::vector temp_normals; - + for (;;) { char lineHeader[256]; @@ -167,7 +167,7 @@ void loadMesh(const char* filename, std::vector& out_vertices, std::v { break; } - + if (!strncmp(lineHeader, "v", 2)) { glm::vec3 vertex; @@ -187,7 +187,7 @@ void loadMesh(const char* filename, std::vector& out_vertices, std::v { int vertexIDs[3], uvIDs[3], normalIDs[3]; 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]); - + for (int i=0; i<3; i++) { out_vertices.push_back(temp_vertices[vertexIDs[i] - 1]); @@ -202,24 +202,24 @@ void setFramebufferSize(GLFWwindow* w, int width, int height) { buffer_width = width; buffer_height = height; - + glDeleteFramebuffers(1, &bloom_framebuffer); glDeleteRenderbuffers(1, &bloom_depthbuffer); - + glGenFramebuffers(1, &bloom_framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT1}; glDrawBuffers(1, DrawBuffers); - + glGenRenderbuffers(1, &bloom_depthbuffer); glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); - + glDeleteTextures(1, &preBloomTex); glDeleteTextures(1, &bloomPassTex1); glDeleteTextures(1, &bloomPassTex2); - + glGenTextures(1, &preBloomTex); glBindTexture(GL_TEXTURE_2D, preBloomTex); 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) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + glGenTextures(1, &bloomPassTex1); glBindTexture(GL_TEXTURE_2D, bloomPassTex1); 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) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + glGenTextures(1, &bloomPassTex2); glBindTexture(GL_TEXTURE_2D, bloomPassTex2); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); @@ -252,20 +252,20 @@ GLFWwindow* initRenderer() fprintf(stderr, "Renderer already initialized\n"); exit(-1); } - + // Initialize GLFW if (!glfwInit()) { fprintf(stderr, "Failed to initialize GLFW\n"); exit(-1); } - + glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - + // Create a window window = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr); if (window == nullptr) @@ -274,7 +274,7 @@ GLFWwindow* initRenderer() glfwTerminate(); exit(-1); } - + glfwMakeContextCurrent(window); glewExperimental = true; // Needed in core profile if (glewInit() != GLEW_OK) @@ -282,37 +282,37 @@ GLFWwindow* initRenderer() fprintf(stderr, "Failed to initialize GLEW\n"); exit(-1); } - + glfwSetFramebufferSizeCallback(window, &setFramebufferSize); - + // Set up vertex array object glGenVertexArrays(1, &VertexArrayID); glBindVertexArray(VertexArrayID); - + // Enable depth testing glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); - + // Enable blending glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - + // Set up the framebuffer glGenFramebuffers(1, &generic_framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, DrawBuffers); - + glGenFramebuffers(1, &bloom_framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1}; glDrawBuffers(1, DrawBuffers2); - + glGenRenderbuffers(1, &bloom_depthbuffer); glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1024, 768); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); - + // Set up the NTSC rendering buffers glGenTextures(1, &renderedTex1); glBindTexture(GL_TEXTURE_2D, renderedTex1); @@ -322,7 +322,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); renderedTexBufs[0] = renderedTex1; - + glGenTextures(1, &renderedTex2); glBindTexture(GL_TEXTURE_2D, renderedTex2); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); @@ -331,7 +331,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); renderedTexBufs[1] = renderedTex2; - + // Set up bloom rendering buffers glGenTextures(1, &preBloomTex); glBindTexture(GL_TEXTURE_2D, preBloomTex); @@ -340,7 +340,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + glGenTextures(1, &bloomPassTex1); glBindTexture(GL_TEXTURE_2D, bloomPassTex1); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); @@ -348,7 +348,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + glGenTextures(1, &bloomPassTex2); glBindTexture(GL_TEXTURE_2D, bloomPassTex2); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); @@ -356,31 +356,31 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + curBuf = 0; - + // Load the mesh! std::vector mesh_vertices; std::vector mesh_uvs; std::vector mesh_normals; loadMesh("res/monitor-fef.obj", mesh_vertices, mesh_uvs, mesh_normals); - + mesh_numvertices = mesh_vertices.size(); - + glGenBuffers(1, &mesh_vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); glBufferData(GL_ARRAY_BUFFER, mesh_vertices.size() * sizeof(glm::vec3), &mesh_vertices[0], GL_STATIC_DRAW); - + glGenBuffers(1, &mesh_uvbuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); glBufferData(GL_ARRAY_BUFFER, mesh_uvs.size() * sizeof(glm::vec3), &mesh_uvs[0], GL_STATIC_DRAW); - + glGenBuffers(1, &mesh_normalbuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(glm::vec3), &mesh_normals[0], GL_STATIC_DRAW); - + // Load the vertices of a flat surface - GLfloat g_quad_vertex_buffer_data[] = { + GLfloat g_quad_vertex_buffer_data[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, @@ -392,7 +392,7 @@ GLFWwindow* initRenderer() glGenBuffers(1, &quad_vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW); - + glGenTextures(1, &artifactsTex); glBindTexture(GL_TEXTURE_2D, artifactsTex); int atdw, atdh; @@ -403,7 +403,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); glGenerateMipmap(GL_TEXTURE_2D); - + glGenTextures(1, &scanlinesTex); glBindTexture(GL_TEXTURE_2D, scanlinesTex); int stdw, stdh; @@ -414,7 +414,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); glGenerateMipmap(GL_TEXTURE_2D); - + // Load the shaders ntscShader = LoadShaders("shaders/ntsc.vertex", "shaders/ntsc.fragment"); finalShader = LoadShaders("shaders/final.vertex", "shaders/final.fragment"); @@ -422,9 +422,9 @@ GLFWwindow* initRenderer() fillShader = LoadShaders("shaders/fill.vertex", "shaders/fill.fragment"); bloom1Shader = LoadShaders("shaders/bloom1.vertex", "shaders/bloom1.fragment"); bloom2Shader = LoadShaders("shaders/bloom2.vertex", "shaders/bloom2.fragment"); - + rendererInitialized = true; - + return window; } @@ -435,13 +435,13 @@ void destroyRenderer() fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + // Delete the plane buffer glDeleteBuffers(1, &quad_vertexbuffer); glDeleteBuffers(1, &mesh_vertexbuffer); glDeleteBuffers(1, &mesh_uvbuffer); glDeleteBuffers(1, &mesh_normalbuffer); - + // Delete the shaders glDeleteProgram(ntscShader); glDeleteProgram(finalShader); @@ -449,7 +449,7 @@ void destroyRenderer() glDeleteProgram(fillShader); glDeleteProgram(bloom1Shader); glDeleteProgram(bloom2Shader); - + // Delete the NTSC rendering buffers glDeleteTextures(1, &renderedTex1); glDeleteTextures(1, &renderedTex2); @@ -458,18 +458,18 @@ void destroyRenderer() glDeleteTextures(1, &preBloomTex); glDeleteTextures(1, &bloomPassTex1); glDeleteTextures(1, &bloomPassTex2); - + // Delete the framebuffer glDeleteRenderbuffers(1, &bloom_depthbuffer); glDeleteFramebuffers(1, &bloom_framebuffer); glDeleteFramebuffers(1, &generic_framebuffer); - + // Delete the VAO glDeleteVertexArrays(1, &VertexArrayID); - + // Kill the window glfwTerminate(); - + rendererInitialized = false; } @@ -480,10 +480,10 @@ Texture::Texture(int width, int height) fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + this->width = width; this->height = height; - + glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); @@ -500,7 +500,7 @@ Texture::Texture(const char* filename) fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); unsigned char* data = stbi_load(filename, &width, &height, 0, 4); @@ -520,14 +520,14 @@ Texture::Texture(const Texture& tex) fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + width = tex.width; height = tex.height; - + unsigned char* data = (unsigned char*) malloc(4 * width * height); glBindTexture(GL_TEXTURE_2D, tex.texID); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - + glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); @@ -535,7 +535,7 @@ Texture::Texture(const Texture& tex) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - + free(data); } @@ -551,14 +551,14 @@ Texture::~Texture() fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + glDeleteTextures(1, &texID); } Texture& Texture::operator= (Texture tex) { swap(*this, tex); - + return *this; } @@ -576,17 +576,17 @@ void Texture::fill(Rectangle dstrect, int r, int g, int b) fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + // Target the framebuffer glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); - + // Set up the vertex attributes GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); - + GLfloat vertexbuffer_data[] = { minx, miny, maxx, miny, @@ -601,14 +601,14 @@ void Texture::fill(Rectangle dstrect, int r, int g, int b) glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - + glViewport(0, 0, width, height); glClear(GL_DEPTH_BUFFER_BIT); glUseProgram(fillShader); glUniform3f(glGetUniformLocation(fillShader, "vecColor"), r / 255.0, g / 255.0, b / 255.0); - + glDrawArrays(GL_TRIANGLES, 0, 6); - + glDisableVertexAttribArray(0); glDeleteBuffers(1, &vertexbuffer); } @@ -620,19 +620,19 @@ void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect, fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + alpha = glm::clamp(alpha, 0.0, 1.0); - + // Target the framebuffer glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); - + // Set up the vertex attributes GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); - + GLfloat vertexbuffer_data[] = { minx, miny, maxx, miny, @@ -645,12 +645,12 @@ void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect, glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - + GLfloat minu = (GLfloat) srcrect.x / srctex.width; GLfloat minv = 1 - ((GLfloat) srcrect.y / srctex.height); GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / srctex.width; GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / srctex.height); - + GLfloat texcoordbuffer_data[] = { minu, minv, maxu, minv, @@ -663,20 +663,20 @@ void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect, glBufferData(GL_ARRAY_BUFFER, sizeof(texcoordbuffer_data), texcoordbuffer_data, GL_STATIC_DRAW); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - + // Set up the shader glUseProgram(blitShader); glClear(GL_DEPTH_BUFFER_BIT); glViewport(0, 0, width, height); - + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, srctex.texID); glUniform1i(glGetUniformLocation(blitShader, "srctex"), 0); glUniform1f(glGetUniformLocation(blitShader, "alpha"), alpha); - + // Blit! glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - + // Unload everything glDisableVertexAttribArray(1); glDisableVertexAttribArray(0); @@ -691,11 +691,11 @@ void bloomPass1(GLuint srcTex, GLuint dstTex, bool horizontal, glm::vec2 srcRes, glViewport(0,0,dstRes.x,dstRes.y); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(bloom1Shader); - + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, srcTex); glUniform1i(glGetUniformLocation(bloom1Shader, "inTex"), 0); - + glm::vec2 offset = glm::vec2(0.0); if (horizontal) { @@ -703,9 +703,9 @@ void bloomPass1(GLuint srcTex, GLuint dstTex, bool horizontal, glm::vec2 srcRes, } else { offset.y = 1.2/srcRes.y; } - + glUniform2f(glGetUniformLocation(bloom1Shader, "offset"), offset.x, offset.y); - + glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); @@ -720,17 +720,17 @@ void Texture::renderScreen() const fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + // First we're going to composite our frame with the previous frame // We start by setting up the framebuffer glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexBufs[curBuf], 0); - + // Set up the shader glViewport(0,0,GAME_WIDTH,GAME_HEIGHT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(ntscShader); - + // Use the current frame texture, nearest neighbor and clamped to edge glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texID); @@ -739,7 +739,7 @@ void Texture::renderScreen() const glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glUniform1i(glGetUniformLocation(ntscShader, "curFrameSampler"), 0); - + // Use the previous frame composite texture, nearest neighbor and clamped to edge glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, renderedTexBufs[(curBuf + 1) % 2]); @@ -748,13 +748,13 @@ void Texture::renderScreen() const glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glUniform1i(glGetUniformLocation(ntscShader, "prevFrameSampler"), 1); - + // Load the NTSC artifact texture glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, artifactsTex); glUniform1i(glGetUniformLocation(ntscShader, "NTSCArtifactSampler"), 2); glUniform1f(glGetUniformLocation(ntscShader, "NTSCLerp"), curBuf * 1.0); - + if ((rand() % 60) == 0) { // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect! @@ -762,7 +762,7 @@ void Texture::renderScreen() const } else { glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0); } - + // Render our composition glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); @@ -776,7 +776,7 @@ void Texture::renderScreen() const glViewport(0,0,buffer_width,buffer_height); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(finalShader); - + // Use the composited frame texture, linearly filtered and filling in black for the border glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, renderedTexBufs[curBuf]); @@ -788,69 +788,69 @@ void Texture::renderScreen() const glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); glGenerateMipmap(GL_TEXTURE_2D); glUniform1i(glGetUniformLocation(finalShader, "rendertex"), 0); - + // Use the scanlines texture glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, scanlinesTex); glUniform1i(glGetUniformLocation(finalShader, "scanlinestex"), 1); - + // Initialize the MVP matrices glm::mat4 p_matrix = glm::perspective(42.5f, (float) buffer_width / (float) buffer_height, 0.1f, 100.0f); glm::mat4 v_matrix = glm::lookAt(glm::vec3(2,0,0), glm::vec3(0,0,0), glm::vec3(0,1,0)); glm::mat4 m_matrix = glm::mat4(1.0); glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix; - + glUniformMatrix4fv(glGetUniformLocation(finalShader, "MVP"), 1, GL_FALSE, &mvp_matrix[0][0]); glUniformMatrix4fv(glGetUniformLocation(finalShader, "worldMat"), 1, GL_FALSE, &m_matrix[0][0]); glUniform2f(glGetUniformLocation(finalShader, "resolution"), buffer_width, buffer_height); glUniform1f(glGetUniformLocation(finalShader, "iGlobalTime"), glfwGetTime()); - + glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - + glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - + glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - + glDrawArrays(GL_TRIANGLES, 0, mesh_numvertices); glDisableVertexAttribArray(2); glDisableVertexAttribArray(1); glDisableVertexAttribArray(0); - + // First pass of bloom! glm::vec2 buffer_size = glm::vec2(buffer_width, buffer_height); bloomPass1(preBloomTex, bloomPassTex1, true, buffer_size, buffer_size / 4.0f); bloomPass1(bloomPassTex1, bloomPassTex2, false, buffer_size / 4.0f, buffer_size / 4.0f); - + // Do the second pass of bloom and render to screen glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, buffer_width, buffer_height); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(bloom2Shader); - + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, preBloomTex); glUniform1i(glGetUniformLocation(bloom2Shader, "clearTex"), 0); - + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, bloomPassTex2); glUniform1i(glGetUniformLocation(bloom2Shader, "blurTex"), 1); - + glUniform1f(glGetUniformLocation(bloom2Shader, "iGlobalTime"), glfwGetTime()); - + glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); glDrawArrays(GL_TRIANGLES, 0, 6); glDisableVertexAttribArray(0); - + glfwSwapBuffers(window); - + curBuf = (curBuf + 1) % 2; } 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 { void blit(const Texture& src, Rectangle srcrect, Rectangle dstrect, double alpha = 1.0); void renderScreen() const; Rectangle entirety() const; - + private: GLuint texID; int width; diff --git a/src/system.h b/src/system.h index e08db0a..af3fb77 100644 --- a/src/system.h +++ b/src/system.h @@ -7,9 +7,9 @@ class System { public: System(Game& game) : game(game) {} - + virtual void tick(double dt) = 0; - + protected: Game& game; }; diff --git a/src/system_manager.h b/src/system_manager.h index 8f76db2..087b71c 100644 --- a/src/system_manager.h +++ b/src/system_manager.h @@ -18,18 +18,18 @@ class SystemManager { { std::unique_ptr ptr = std::unique_ptr(new T(game, std::forward(args)...)); std::type_index systemType = typeid(T); - + systems[systemType] = ptr.get(); loop.push_back(std::move(ptr)); } - + template T& getSystem() { std::type_index systemType = typeid(T); - + assert(systems.count(systemType) == 1); - + return *((T*)systems[systemType]); } }; diff --git a/src/systems/controlling.cpp b/src/systems/controlling.cpp index b1e73ad..456da3b 100644 --- a/src/systems/controlling.cpp +++ b/src/systems/controlling.cpp @@ -14,12 +14,12 @@ void ControllingSystem::tick(double dt) { int key = actions.front().first; int action = actions.front().second; - + auto entities = game.getEntityManager().getEntitiesWithComponents(); for (auto entity : entities) { auto& controllable = game.getEntityManager().getComponent(entity); - + if (action == GLFW_PRESS) { if (key == controllable.getLeftKey()) @@ -33,7 +33,7 @@ void ControllingSystem::tick(double dt) } else if (key == controllable.getRightKey()) { controllable.setHoldingRight(true); - + if (!controllable.isFrozen()) { walkRight(entity); @@ -56,7 +56,7 @@ void ControllingSystem::tick(double dt) if (key == controllable.getLeftKey()) { controllable.setHoldingLeft(false); - + if (!controllable.isFrozen()) { if (controllable.isHoldingRight()) @@ -69,7 +69,7 @@ void ControllingSystem::tick(double dt) } else if (key == controllable.getRightKey()) { controllable.setHoldingRight(false); - + if (!controllable.isFrozen()) { if (controllable.isHoldingRight()) @@ -94,7 +94,7 @@ void ControllingSystem::tick(double dt) } } } - + actions.pop(); } } diff --git a/src/systems/controlling.h b/src/systems/controlling.h index 61f86eb..30210b3 100644 --- a/src/systems/controlling.h +++ b/src/systems/controlling.h @@ -8,10 +8,10 @@ class ControllingSystem : public System { public: ControllingSystem(Game& game) : System(game) {} - + void tick(double dt); void input(int key, int action); - + private: void walkLeft(int entity); void walkRight(int entity); @@ -19,7 +19,7 @@ class ControllingSystem : public System { void jump(int entity); void stopJumping(int entity); void drop(int entity, bool start); - + std::queue> actions; }; diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 96775d0..50a8bc8 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -6,16 +6,16 @@ void PonderingSystem::tick(double dt) { auto entities = game.getEntityManager().getEntitiesWithComponents(); - + for (auto entity : entities) { auto& transformable = game.getEntityManager().getComponent(entity); auto& ponderable = game.getEntityManager().getComponent(entity); - + // Accelerate ponderable.setVelocityX(ponderable.getVelocityX() + ponderable.getAccelX() * dt); ponderable.setVelocityY(ponderable.getVelocityY() + ponderable.getAccelY() * dt); - + // Move transformable.setX(transformable.getX() + ponderable.getVelocityX() * dt); transformable.setY(transformable.getY() + ponderable.getVelocityY() * dt); diff --git a/src/systems/pondering.h b/src/systems/pondering.h index ad01a22..3fe5473 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -7,7 +7,7 @@ class PonderingSystem : public System { public: PonderingSystem(Game& game) : System(game) {} - + void tick(double dt); }; diff --git a/src/systems/rendering.h b/src/systems/rendering.h index 9b6e27e..cec72e2 100644 --- a/src/systems/rendering.h +++ b/src/systems/rendering.h @@ -9,9 +9,9 @@ class RenderingSystem : public System { public: RenderingSystem(Game& game) : System(game) {} - + void tick(double dt); - + private: Texture texture {GAME_WIDTH, GAME_HEIGHT}; }; -- cgit 1.4.1 From ed08b673c50b076042d8f0c49501372168142764 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 16 Feb 2018 16:04:32 -0500 Subject: Refactored renderer Renderer is basically now more C++'y, as it makes more use of classes (a lot of GL types have been wrapped), and the renderer itself is now a class. The monitor mesh is also now indexed. Tweaked the NTSC artifacting after inadvertently fixing a bug with the way the image was loaded. --- CMakeLists.txt | 6 +- shaders/final.fragment | 4 +- src/algorithms.h | 12 - src/animation.h | 2 +- src/components/controllable.h | 2 +- src/components/mappable.h | 2 +- src/entity_manager.h | 2 +- src/game.cpp | 19 +- src/game.h | 11 +- src/main.cpp | 17 +- src/renderer.cpp | 862 ------------------------------------------ src/renderer.h | 37 -- src/renderer/gl.h | 7 + src/renderer/mesh.cpp | 109 ++++++ src/renderer/mesh.h | 62 +++ src/renderer/renderer.cpp | 635 +++++++++++++++++++++++++++++++ src/renderer/renderer.h | 114 ++++++ src/renderer/shader.cpp | 84 ++++ src/renderer/shader.h | 58 +++ src/renderer/texture.cpp | 124 ++++++ src/renderer/texture.h | 52 +++ src/renderer/wrappers.h | 273 +++++++++++++ src/systems/animating.cpp | 3 +- src/systems/animating.h | 2 +- src/systems/mapping.cpp | 12 +- src/util.cpp | 30 ++ src/util.h | 41 ++ 27 files changed, 1631 insertions(+), 951 deletions(-) delete mode 100644 src/algorithms.h delete mode 100644 src/renderer.cpp delete mode 100644 src/renderer.h create mode 100644 src/renderer/gl.h create mode 100644 src/renderer/mesh.cpp create mode 100644 src/renderer/mesh.h create mode 100644 src/renderer/renderer.cpp create mode 100644 src/renderer/renderer.h create mode 100644 src/renderer/shader.cpp create mode 100644 src/renderer/shader.h create mode 100644 src/renderer/texture.cpp create mode 100644 src/renderer/texture.h create mode 100644 src/renderer/wrappers.h create mode 100644 src/util.cpp create mode 100644 src/util.h (limited to 'src/main.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 22bbc1a..3e7bcb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,12 +49,16 @@ link_directories( add_executable(Aromatherapy src/main.cpp - src/renderer.cpp src/muxer.cpp src/entity_manager.cpp src/game.cpp src/animation.cpp src/world.cpp + src/util.cpp + src/renderer/renderer.cpp + src/renderer/mesh.cpp + src/renderer/shader.cpp + src/renderer/texture.cpp src/systems/controlling.cpp src/systems/pondering.cpp src/systems/animating.cpp diff --git a/shaders/final.fragment b/shaders/final.fragment index 9a39597..2e38f38 100644 --- a/shaders/final.fragment +++ b/shaders/final.fragment @@ -15,8 +15,8 @@ const float Tuning_Dimming = 0.0; const float Tuning_Satur = 1.13; const float Tuning_ReflScalar = 0.3; const float Tuning_Barrel = 0;//0.12; -const float Tuning_Scanline_Brightness = 0.5;//0.45; -const float Tuning_Scanline_Opacity = 0.75;//0.55; +const float Tuning_Scanline_Brightness = 0.55; +const float Tuning_Scanline_Opacity = 0.55; const float Tuning_Diff_Brightness = 0.75; const float Tuning_Spec_Brightness = 0.5;//0.35; const float Tuning_Spec_Power = 50.0; diff --git a/src/algorithms.h b/src/algorithms.h deleted file mode 100644 index 80e3e27..0000000 --- a/src/algorithms.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef ALGORITHMS_H_1DDC517E -#define ALGORITHMS_H_1DDC517E - -template< typename ContainerT, typename PredicateT > -void erase_if( ContainerT& items, const PredicateT& predicate ) { - for( auto it = items.begin(); it != items.end(); ) { - if( predicate(*it) ) it = items.erase(it); - else ++it; - } -}; - -#endif /* end of include guard: ALGORITHMS_H_1DDC517E */ diff --git a/src/animation.h b/src/animation.h index 50446d0..58df616 100644 --- a/src/animation.h +++ b/src/animation.h @@ -1,7 +1,7 @@ #ifndef ANIMATION_H_74EB0901 #define ANIMATION_H_74EB0901 -#include "renderer.h" +#include "renderer/texture.h" #include #include #include diff --git a/src/components/controllable.h b/src/components/controllable.h index fa78c8b..1b12985 100644 --- a/src/components/controllable.h +++ b/src/components/controllable.h @@ -2,7 +2,7 @@ #define CONTROLLABLE_H_4E0B85B4 #include "component.h" -#include "renderer.h" +#include "renderer/gl.h" class ControllableComponent : public Component { public: diff --git a/src/components/mappable.h b/src/components/mappable.h index 7530919..2dbab77 100644 --- a/src/components/mappable.h +++ b/src/components/mappable.h @@ -3,7 +3,7 @@ #include #include "component.h" -#include "renderer.h" +#include "renderer/texture.h" #include "map.h" class MappableComponent : public Component { diff --git a/src/entity_manager.h b/src/entity_manager.h index 7fd82fc..65fa6ca 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h @@ -7,7 +7,7 @@ #include #include #include "component.h" -#include "algorithms.h" +#include "util.h" class EntityManager { private: diff --git a/src/game.cpp b/src/game.cpp index 1182689..228ff23 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10,12 +10,11 @@ #include "systems/mapping.h" #include "systems/orienting.h" #include "animation.h" -#include "renderer.h" #include "consts.h" void key_callback(GLFWwindow* window, int key, int, int action, int) { - Game& game = *((Game*) glfwGetWindowUserPointer(window)); + Game& game = *static_cast(glfwGetWindowUserPointer(window)); if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE)) { @@ -27,10 +26,7 @@ void key_callback(GLFWwindow* window, int key, int, int action, int) game.systemManager_.input(key, action); } -Game::Game( - GLFWwindow* window) : - window_(window), - world_("res/maps.xml") +Game::Game() : world_("res/maps.xml") { systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); @@ -65,8 +61,8 @@ Game::Game( systemManager_.getSystem().loadMap(world_.getStartingMapId()); glfwSwapInterval(1); - glfwSetWindowUserPointer(window_, this); - glfwSetKeyCallback(window_, key_callback); + glfwSetWindowUserPointer(renderer_.getWindow().getHandle(), this); + glfwSetKeyCallback(renderer_.getWindow().getHandle(), key_callback); } void Game::execute() @@ -76,7 +72,8 @@ void Game::execute() double accumulator = 0.0; Texture texture(GAME_WIDTH, GAME_HEIGHT); - while (!(shouldQuit_ || glfwWindowShouldClose(window_))) + while (!(shouldQuit_ || + glfwWindowShouldClose(renderer_.getWindow().getHandle()))) { double currentTime = glfwGetTime(); double frameTime = currentTime - lastTime; @@ -93,8 +90,8 @@ void Game::execute() } // Render - texture.fill(texture.entirety(), 0, 0, 0); + renderer_.fill(texture, texture.entirety(), 0, 0, 0); systemManager_.render(texture); - texture.renderScreen(); + renderer_.renderScreen(texture); } } diff --git a/src/game.h b/src/game.h index 346d67e..43e08da 100644 --- a/src/game.h +++ b/src/game.h @@ -1,18 +1,23 @@ #ifndef GAME_H_1014DDC9 #define GAME_H_1014DDC9 -#include "renderer.h" #include "entity_manager.h" #include "system_manager.h" #include "world.h" +#include "renderer/renderer.h" class Game { public: - Game(GLFWwindow* window); + Game(); void execute(); + inline Renderer& getRenderer() + { + return renderer_; + } + inline EntityManager& getEntityManager() { return entityManager_; @@ -37,7 +42,7 @@ public: private: - GLFWwindow* const window_; + Renderer renderer_; EntityManager entityManager_; SystemManager systemManager_; World world_; diff --git a/src/main.cpp b/src/main.cpp index d51da7d..ddbc15f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,27 +1,14 @@ -#include -#include -#include -#include "renderer.h" #include "muxer.h" #include "game.h" int main() { - srand(time(NULL)); - - GLFWwindow* window = initRenderer(); - glfwSwapInterval(1); - initMuxer(); - // Put this in a block so game goes out of scope before we destroy the renderer - { - Game game {window}; - game.execute(); - } + Game game; + game.execute(); destroyMuxer(); - destroyRenderer(); return 0; } diff --git a/src/renderer.cpp b/src/renderer.cpp deleted file mode 100644 index f840180..0000000 --- a/src/renderer.cpp +++ /dev/null @@ -1,862 +0,0 @@ -#include "renderer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "consts.h" - -// include stb_image -#define STB_IMAGE_IMPLEMENTATION -#define STBI_ONLY_PNG -#define STBI_ONLY_BMP -#include "stb_image.h" - -static bool rendererInitialized = false; - -static GLFWwindow* window; - -static GLuint generic_framebuffer; // The framebuffer -static GLuint bloom_framebuffer; -static GLuint bloom_depthbuffer; -static int buffer_width = 1024; -static int buffer_height = 768; - -static GLuint ntscShader; // The NTSC shader -static GLuint finalShader; // The passthrough shader -static GLuint blitShader; // The blitting shader -static GLuint fillShader; // The fill shader -static GLuint bloom1Shader; -static GLuint bloom2Shader; - -// The buffers for the NTSC rendering process -static GLuint renderedTexBufs[2]; -static int curBuf; -static GLuint artifactsTex; -static GLuint scanlinesTex; -static GLuint preBloomTex; -static GLuint bloomPassTex1; -static GLuint bloomPassTex2; - -// The VAO -static GLuint VertexArrayID; - -// A plane that fills the renderbuffer -static GLuint quad_vertexbuffer; - -// Buffers for the mesh -static GLuint mesh_vertexbuffer; -static GLuint mesh_uvbuffer; -static GLuint mesh_normalbuffer; -static int mesh_numvertices; - -GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path) -{ - // Create the shaders - GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); - GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); - - // Read the Vertex Shader code from the file - std::string VertexShaderCode; - std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); - if(VertexShaderStream.is_open()) - { - std::string Line = ""; - while(getline(VertexShaderStream, Line)) - VertexShaderCode += "\n" + Line; - VertexShaderStream.close(); - } - - // Read the Fragment Shader code from the file - std::string FragmentShaderCode; - std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); - if(FragmentShaderStream.is_open()){ - std::string Line = ""; - while(getline(FragmentShaderStream, Line)) - FragmentShaderCode += "\n" + Line; - FragmentShaderStream.close(); - } - - GLint Result = GL_FALSE; - int InfoLogLength; - - // Compile Vertex Shader - printf("Compiling shader : %s\n", vertex_file_path); - char const * VertexSourcePointer = VertexShaderCode.c_str(); - glShaderSource(VertexShaderID, 1, &VertexSourcePointer , nullptr); - glCompileShader(VertexShaderID); - - // Check Vertex Shader - glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); - glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); - std::vector VertexShaderErrorMessage(InfoLogLength); - glGetShaderInfoLog(VertexShaderID, InfoLogLength, nullptr, &VertexShaderErrorMessage[0]); - fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]); - - // Compile Fragment Shader - printf("Compiling shader : %s\n", fragment_file_path); - char const * FragmentSourcePointer = FragmentShaderCode.c_str(); - glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , nullptr); - glCompileShader(FragmentShaderID); - - // Check Fragment Shader - glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); - glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); - std::vector FragmentShaderErrorMessage(InfoLogLength); - glGetShaderInfoLog(FragmentShaderID, InfoLogLength, nullptr, &FragmentShaderErrorMessage[0]); - fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]); - - // Link the program - fprintf(stdout, "Linking program\n"); - GLuint ProgramID = glCreateProgram(); - glAttachShader(ProgramID, VertexShaderID); - glAttachShader(ProgramID, FragmentShaderID); - glLinkProgram(ProgramID); - - // Check the program - glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); - glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); - std::vector ProgramErrorMessage( glm::max(InfoLogLength, int(1)) ); - glGetProgramInfoLog(ProgramID, InfoLogLength, nullptr, &ProgramErrorMessage[0]); - fprintf(stdout, "%s\n", &ProgramErrorMessage[0]); - - glDeleteShader(VertexShaderID); - glDeleteShader(FragmentShaderID); - - return ProgramID; -} - -void flipImageData(unsigned char* data, int width, int height, int comps) -{ - unsigned char* data_copy = (unsigned char*) malloc(width*height*comps*sizeof(unsigned char)); - memcpy(data_copy, data, width*height*comps); - - int row_size = width * comps; - - for (int i=0;i& out_vertices, std::vector& out_uvs, std::vector& out_normals) -{ - out_vertices.clear(); - out_uvs.clear(); - out_normals.clear(); - - FILE* file = fopen(filename, "r"); - if (file == nullptr) - { - fprintf(stderr, "Could not open mesh file %s\n", filename); - exit(1); - } - - std::vector temp_vertices; - std::vector temp_uvs; - std::vector temp_normals; - - for (;;) - { - char lineHeader[256]; - int res = fscanf(file, "%s", lineHeader); - if (res == EOF) - { - break; - } - - if (!strncmp(lineHeader, "v", 2)) - { - glm::vec3 vertex; - fscanf(file, "%f %f %f\n", &vertex.x,&vertex.y,&vertex.z); - temp_vertices.push_back(vertex); - } else if (!strncmp(lineHeader, "vt", 3)) - { - glm::vec2 uv; - fscanf(file, "%f %f\n", &uv.x, &uv.y); - temp_uvs.push_back(uv); - } else if (!strncmp(lineHeader, "vn", 3)) - { - glm::vec3 normal; - fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z); - temp_normals.push_back(normal); - } else if (!strncmp(lineHeader, "f", 2)) - { - int vertexIDs[3], uvIDs[3], normalIDs[3]; - 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]); - - for (int i=0; i<3; i++) - { - out_vertices.push_back(temp_vertices[vertexIDs[i] - 1]); - out_uvs.push_back(temp_uvs[uvIDs[i] - 1]); - out_normals.push_back(temp_normals[normalIDs[i] - 1]); - } - } - } -} - -void setFramebufferSize(GLFWwindow* w, int width, int height) -{ - buffer_width = width; - buffer_height = height; - - glDeleteFramebuffers(1, &bloom_framebuffer); - glDeleteRenderbuffers(1, &bloom_depthbuffer); - - glGenFramebuffers(1, &bloom_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); - GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT1}; - glDrawBuffers(1, DrawBuffers); - - glGenRenderbuffers(1, &bloom_depthbuffer); - glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); - - glDeleteTextures(1, &preBloomTex); - glDeleteTextures(1, &bloomPassTex1); - glDeleteTextures(1, &bloomPassTex2); - - glGenTextures(1, &preBloomTex); - glBindTexture(GL_TEXTURE_2D, preBloomTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex1); - glBindTexture(GL_TEXTURE_2D, bloomPassTex1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex2); - glBindTexture(GL_TEXTURE_2D, bloomPassTex2); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} - -GLFWwindow* initRenderer() -{ - if (rendererInitialized) - { - fprintf(stderr, "Renderer already initialized\n"); - exit(-1); - } - - // Initialize GLFW - if (!glfwInit()) - { - fprintf(stderr, "Failed to initialize GLFW\n"); - exit(-1); - } - - glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3 - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - - // Create a window - window = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr); - if (window == nullptr) - { - fprintf(stderr, "Failed to open GLFW window\n"); - glfwTerminate(); - exit(-1); - } - - glfwMakeContextCurrent(window); - glewExperimental = true; // Needed in core profile - if (glewInit() != GLEW_OK) - { - fprintf(stderr, "Failed to initialize GLEW\n"); - exit(-1); - } - - glfwSetFramebufferSizeCallback(window, &setFramebufferSize); - - // Set up vertex array object - glGenVertexArrays(1, &VertexArrayID); - glBindVertexArray(VertexArrayID); - - // Enable depth testing - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - // Enable blending - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - // Set up the framebuffer - glGenFramebuffers(1, &generic_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; - glDrawBuffers(1, DrawBuffers); - - glGenFramebuffers(1, &bloom_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); - GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1}; - glDrawBuffers(1, DrawBuffers2); - - glfwGetFramebufferSize(window, &buffer_width, &buffer_height); - - glGenRenderbuffers(1, &bloom_depthbuffer); - glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, buffer_width, buffer_height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); - - // Set up the NTSC rendering buffers - glGenTextures(2, renderedTexBufs); - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[0]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[1]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // Set up bloom rendering buffers - glGenTextures(1, &preBloomTex); - glBindTexture(GL_TEXTURE_2D, preBloomTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width, buffer_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex1); - glBindTexture(GL_TEXTURE_2D, bloomPassTex1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width/4, buffer_height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex2); - glBindTexture(GL_TEXTURE_2D, bloomPassTex2); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width/4, buffer_height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - curBuf = 0; - - // Load the mesh! - std::vector mesh_vertices; - std::vector mesh_uvs; - std::vector mesh_normals; - - loadMesh("res/monitor-old.obj", mesh_vertices, mesh_uvs, mesh_normals); - - mesh_numvertices = mesh_vertices.size(); - - glGenBuffers(1, &mesh_vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_vertices.size() * sizeof(glm::vec3), mesh_vertices.data(), GL_STATIC_DRAW); - - glGenBuffers(1, &mesh_uvbuffer); - glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_uvs.size() * sizeof(glm::vec2), mesh_uvs.data(), GL_STATIC_DRAW); - - glGenBuffers(1, &mesh_normalbuffer); - glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(glm::vec3), mesh_normals.data(), GL_STATIC_DRAW); - - // Load the vertices of a flat surface - GLfloat g_quad_vertex_buffer_data[] = { - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, - }; - - glGenBuffers(1, &quad_vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW); - - glGenTextures(1, &artifactsTex); - glBindTexture(GL_TEXTURE_2D, artifactsTex); - int atdw, atdh; - unsigned char* artifactsTex_data = stbi_load("res/artifacts.bmp", &atdw, &atdh, 0, 3); - flipImageData(artifactsTex_data, atdw, atdh, 3); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, atdw, atdh, 0, GL_RGB, GL_UNSIGNED_BYTE, artifactsTex_data); - stbi_image_free(artifactsTex_data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); - glGenerateMipmap(GL_TEXTURE_2D); - - glGenTextures(1, &scanlinesTex); - glBindTexture(GL_TEXTURE_2D, scanlinesTex); - int stdw, stdh; - unsigned char* scanlinesTex_data = stbi_load("res/scanlines_333.bmp", &stdw, &stdh, 0, 3); - flipImageData(scanlinesTex_data, stdw, stdh, 3); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, atdw, atdh, 0, GL_RGB, GL_UNSIGNED_BYTE, scanlinesTex_data); - stbi_image_free(scanlinesTex_data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); - glGenerateMipmap(GL_TEXTURE_2D); - - // Load the shaders - ntscShader = LoadShaders("shaders/ntsc.vertex", "shaders/ntsc.fragment"); - finalShader = LoadShaders("shaders/final.vertex", "shaders/final.fragment"); - blitShader = LoadShaders("shaders/blit.vertex", "shaders/blit.fragment"); - fillShader = LoadShaders("shaders/fill.vertex", "shaders/fill.fragment"); - bloom1Shader = LoadShaders("shaders/bloom1.vertex", "shaders/bloom1.fragment"); - bloom2Shader = LoadShaders("shaders/bloom2.vertex", "shaders/bloom2.fragment"); - - rendererInitialized = true; - - return window; -} - -void destroyRenderer() -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - // Delete the plane buffer - glDeleteBuffers(1, &quad_vertexbuffer); - glDeleteBuffers(1, &mesh_vertexbuffer); - glDeleteBuffers(1, &mesh_uvbuffer); - glDeleteBuffers(1, &mesh_normalbuffer); - - // Delete the shaders - glDeleteProgram(ntscShader); - glDeleteProgram(finalShader); - glDeleteProgram(blitShader); - glDeleteProgram(fillShader); - glDeleteProgram(bloom1Shader); - glDeleteProgram(bloom2Shader); - - // Delete the NTSC rendering buffers - glDeleteTextures(2, renderedTexBufs); - glDeleteTextures(1, &artifactsTex); - glDeleteTextures(1, &scanlinesTex); - glDeleteTextures(1, &preBloomTex); - glDeleteTextures(1, &bloomPassTex1); - glDeleteTextures(1, &bloomPassTex2); - - // Delete the framebuffer - glDeleteRenderbuffers(1, &bloom_depthbuffer); - glDeleteFramebuffers(1, &bloom_framebuffer); - glDeleteFramebuffers(1, &generic_framebuffer); - - // Delete the VAO - glDeleteVertexArrays(1, &VertexArrayID); - - // Kill the window - glfwTerminate(); - - rendererInitialized = false; -} - -Texture::Texture(int width, int height) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - this->width = width; - this->height = height; - - glGenTextures(1, &texID); - glBindTexture(GL_TEXTURE_2D, texID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -} - -Texture::Texture(const char* filename) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - glGenTextures(1, &texID); - glBindTexture(GL_TEXTURE_2D, texID); - unsigned char* data = stbi_load(filename, &width, &height, 0, 4); - flipImageData(data, width, height, 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - stbi_image_free(data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} - -Texture::Texture(const Texture& tex) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - width = tex.width; - height = tex.height; - - unsigned char* data = (unsigned char*) malloc(4 * width * height); - glBindTexture(GL_TEXTURE_2D, tex.texID); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - - glGenTextures(1, &texID); - glBindTexture(GL_TEXTURE_2D, texID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - - free(data); -} - -Texture::Texture(Texture&& tex) : Texture(0, 0) -{ - swap(*this, tex); -} - -Texture::~Texture() -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - glDeleteTextures(1, &texID); -} - -Texture& Texture::operator= (Texture tex) -{ - swap(*this, tex); - - return *this; -} - -void swap(Texture& tex1, Texture& tex2) -{ - std::swap(tex1.width, tex2.width); - std::swap(tex1.height, tex2.height); - std::swap(tex1.texID, tex2.texID); -} - -void Texture::fill(Rectangle dstrect, int r, int g, int b) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - // Target the framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); - - // Set up the vertex attributes - GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; - GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); - GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; - GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); - - GLfloat vertexbuffer_data[] = { - minx, miny, - maxx, miny, - maxx, maxy, - minx, miny, - minx, maxy, - maxx, maxy - }; - GLuint vertexbuffer; - glGenBuffers(1, &vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glViewport(0, 0, width, height); - glClear(GL_DEPTH_BUFFER_BIT); - glUseProgram(fillShader); - glUniform3f(glGetUniformLocation(fillShader, "vecColor"), r / 255.0, g / 255.0, b / 255.0); - - glDrawArrays(GL_TRIANGLES, 0, 6); - - glDisableVertexAttribArray(0); - glDeleteBuffers(1, &vertexbuffer); -} - -void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect, double alpha) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - alpha = glm::clamp(alpha, 0.0, 1.0); - - // Target the framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); - - // Set up the vertex attributes - GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; - GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); - GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; - GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); - - GLfloat vertexbuffer_data[] = { - minx, miny, - maxx, miny, - minx, maxy, - maxx, maxy - }; - GLuint vertexbuffer; - glGenBuffers(1, &vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - GLfloat minu = (GLfloat) srcrect.x / srctex.width; - GLfloat minv = 1 - ((GLfloat) srcrect.y / srctex.height); - GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / srctex.width; - GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / srctex.height); - - GLfloat texcoordbuffer_data[] = { - minu, minv, - maxu, minv, - minu, maxv, - maxu, maxv - }; - GLuint texcoordbuffer; - glGenBuffers(1, &texcoordbuffer); - glBindBuffer(GL_ARRAY_BUFFER, texcoordbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(texcoordbuffer_data), texcoordbuffer_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - // Set up the shader - glUseProgram(blitShader); - glClear(GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, width, height); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, srctex.texID); - glUniform1i(glGetUniformLocation(blitShader, "srctex"), 0); - glUniform1f(glGetUniformLocation(blitShader, "alpha"), alpha); - - // Blit! - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - // Unload everything - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - glDeleteBuffers(1, &texcoordbuffer); - glDeleteBuffers(1, &vertexbuffer); -} - -void bloomPass1(GLuint srcTex, GLuint dstTex, bool horizontal, glm::vec2 srcRes, glm::vec2 dstRes) -{ - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstTex, 0); - glViewport(0,0,dstRes.x,dstRes.y); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(bloom1Shader); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, srcTex); - glUniform1i(glGetUniformLocation(bloom1Shader, "inTex"), 0); - - glm::vec2 offset = glm::vec2(0.0); - if (horizontal) - { - offset.x = 1.2/srcRes.x; - } else { - offset.y = 1.2/srcRes.y; - } - - glUniform2f(glGetUniformLocation(bloom1Shader, "offset"), offset.x, offset.y); - - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - glDrawArrays(GL_TRIANGLES, 0, 6); - glDisableVertexAttribArray(0); -} - -void Texture::renderScreen() const -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - // First we're going to composite our frame with the previous frame - // We start by setting up the framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexBufs[curBuf], 0); - - // Set up the shader - glViewport(0,0,GAME_WIDTH,GAME_HEIGHT); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(ntscShader); - - // Use the current frame texture, nearest neighbor and clamped to edge - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texID); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glUniform1i(glGetUniformLocation(ntscShader, "curFrameSampler"), 0); - - // Use the previous frame composite texture, nearest neighbor and clamped to edge - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[(curBuf + 1) % 2]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glUniform1i(glGetUniformLocation(ntscShader, "prevFrameSampler"), 1); - - // Load the NTSC artifact texture - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, artifactsTex); - glUniform1i(glGetUniformLocation(ntscShader, "NTSCArtifactSampler"), 2); - glUniform1f(glGetUniformLocation(ntscShader, "NTSCLerp"), curBuf * 1.0); - - if ((rand() % 60) == 0) - { - // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect! - glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0); - } else { - glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0); - } - - // Render our composition - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - glDrawArrays(GL_TRIANGLES, 0, 6); - glDisableVertexAttribArray(0); - - // We're going to render the screen now - glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, preBloomTex, 0); - glViewport(0,0,buffer_width,buffer_height); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(finalShader); - - // Use the composited frame texture, linearly filtered and filling in black for the border - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[curBuf]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - float border_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); - glGenerateMipmap(GL_TEXTURE_2D); - glUniform1i(glGetUniformLocation(finalShader, "rendertex"), 0); - - // Use the scanlines texture - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, scanlinesTex); - glUniform1i(glGetUniformLocation(finalShader, "scanlinestex"), 1); - - // Initialize the MVP matrices - glm::mat4 p_matrix = glm::perspective(glm::radians(25.0f), (float) buffer_width / (float) buffer_height, 0.1f, 100.0f); - glm::mat4 v_matrix = glm::lookAt(glm::vec3(3.75,0,0), glm::vec3(0,0,0), glm::vec3(0,1,0)); - glm::mat4 m_matrix = glm::mat4(1.0); - glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix; - - glUniformMatrix4fv(glGetUniformLocation(finalShader, "MVP"), 1, GL_FALSE, &mvp_matrix[0][0]); - glUniformMatrix4fv(glGetUniformLocation(finalShader, "worldMat"), 1, GL_FALSE, &m_matrix[0][0]); - glUniform2f(glGetUniformLocation(finalShader, "resolution"), buffer_width, buffer_height); - glUniform1f(glGetUniformLocation(finalShader, "iGlobalTime"), glfwGetTime()); - glUniform3f(glGetUniformLocation(finalShader, "frameColor"), 0.76f, 0.78f, 0.81f); - - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glEnableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glEnableVertexAttribArray(2); - glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glDrawArrays(GL_TRIANGLES, 0, mesh_numvertices); - glDisableVertexAttribArray(2); - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - - // First pass of bloom! - glm::vec2 buffer_size = glm::vec2(buffer_width, buffer_height); - bloomPass1(preBloomTex, bloomPassTex1, true, buffer_size, buffer_size / 4.0f); - bloomPass1(bloomPassTex1, bloomPassTex2, false, buffer_size / 4.0f, buffer_size / 4.0f); - - // Do the second pass of bloom and render to screen - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(0, 0, buffer_width, buffer_height); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(bloom2Shader); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, preBloomTex); - glUniform1i(glGetUniformLocation(bloom2Shader, "clearTex"), 0); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, bloomPassTex2); - glUniform1i(glGetUniformLocation(bloom2Shader, "blurTex"), 1); - - glUniform1f(glGetUniformLocation(bloom2Shader, "iGlobalTime"), glfwGetTime()); - - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - glDrawArrays(GL_TRIANGLES, 0, 6); - glDisableVertexAttribArray(0); - - glfwSwapBuffers(window); - - curBuf = (curBuf + 1) % 2; -} - -Rectangle Texture::entirety() const -{ - return {0, 0, width, height}; -} diff --git a/src/renderer.h b/src/renderer.h deleted file mode 100644 index 6dccf7a..0000000 --- a/src/renderer.h +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -#ifndef RENDERER_H -#define RENDERER_H - -struct Rectangle { - int x; - int y; - int w; - int h; -}; - -class Texture { - public: - Texture(int width, int height); - Texture(const char* file); - Texture(const Texture& tex); - Texture(Texture&& tex); - ~Texture(); - Texture& operator= (Texture tex); - friend void swap(Texture& tex1, Texture& tex2); - void fill(Rectangle loc, int r, int g, int b); - void blit(const Texture& src, Rectangle srcrect, Rectangle dstrect, double alpha = 1.0); - void renderScreen() const; - Rectangle entirety() const; - - private: - GLuint texID; - int width; - int height; -}; - -GLFWwindow* initRenderer(); -void destroyRenderer(); - -#endif diff --git a/src/renderer/gl.h b/src/renderer/gl.h new file mode 100644 index 0000000..4e98c42 --- /dev/null +++ b/src/renderer/gl.h @@ -0,0 +1,7 @@ +#ifndef GL_H_3EE4A268 +#define GL_H_3EE4A268 + +#include +#include + +#endif /* end of include guard: GL_H_3EE4A268 */ diff --git a/src/renderer/mesh.cpp b/src/renderer/mesh.cpp new file mode 100644 index 0000000..b06b723 --- /dev/null +++ b/src/renderer/mesh.cpp @@ -0,0 +1,109 @@ +#include "mesh.h" +#include +#include +#include +#include +#include "util.h" + +Mesh::Mesh(std::string filename) +{ + std::ifstream meshfile(filename); + if (!meshfile.is_open()) + { + throw std::invalid_argument("Could not open mesh file"); + } + + std::vector tempVertices; + std::vector tempUvs; + std::vector tempNormals; + + std::vector outVertices; + std::vector outUvs; + std::vector outNormals; + std::map elementIds; + std::vector indices; + + while (meshfile) + { + std::string linetype; + meshfile >> linetype; + + if (linetype == "v") + { + glm::vec3 vertex; + meshfile >> vertex.x >> vertex.y >> vertex.z; + + tempVertices.push_back(std::move(vertex)); + } else if (linetype == "vt") + { + glm::vec2 uv; + meshfile >> uv.x >> uv.y; + + tempUvs.push_back(std::move(uv)); + } else if (linetype == "vn") + { + glm::vec3 normal; + meshfile >> normal.x >> normal.y >> normal.z; + + tempNormals.push_back(std::move(normal)); + } else if (linetype == "f") + { + element elements[3]; + + meshfile + >> elements[0].vertexId >> chlit('/') + >> elements[0].uvId >> chlit('/') + >> elements[0].normalId + >> elements[1].vertexId >> chlit('/') + >> elements[1].uvId >> chlit('/') + >> elements[1].normalId + >> elements[2].vertexId >> chlit('/') + >> elements[2].uvId >> chlit('/') + >> elements[2].normalId; + + for (size_t i = 0; i < 3; i++) + { + if (!elementIds.count(elements[i])) + { + elementIds[elements[i]] = outVertices.size(); + + outVertices.push_back(tempVertices[elements[i].vertexId - 1]); + outUvs.push_back(tempUvs[elements[i].uvId - 1]); + outNormals.push_back(tempNormals[elements[i].normalId - 1]); + } + + indices.push_back(elementIds[elements[i]]); + } + } + } + + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + outVertices.size() * sizeof(glm::vec3), + outVertices.data(), + GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, uvBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + outUvs.size() * sizeof(glm::vec2), + outUvs.data(), + GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, normalBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + outNormals.size() * sizeof(glm::vec3), + outNormals.data(), + GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer_.getId()); + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + indices.size() * sizeof(unsigned short), + indices.data(), + GL_STATIC_DRAW); + + indexCount_ = indices.size(); +} diff --git a/src/renderer/mesh.h b/src/renderer/mesh.h new file mode 100644 index 0000000..06bf65d --- /dev/null +++ b/src/renderer/mesh.h @@ -0,0 +1,62 @@ +#ifndef MESH_H_76B72E12 +#define MESH_H_76B72E12 + +#include +#include "gl.h" +#include "wrappers.h" + +class Mesh { +public: + + Mesh(std::string filename); + + Mesh(const Mesh& other) = delete; + Mesh& operator=(const Mesh& other) = delete; + + inline GLuint getVertexBufferId() const + { + return vertexBuffer_.getId(); + } + + inline GLuint getUvBufferId() const + { + return uvBuffer_.getId(); + } + + inline GLuint getNormalBufferId() const + { + return normalBuffer_.getId(); + } + + inline GLuint getIndexBufferId() const + { + return indexBuffer_.getId(); + } + + inline size_t getIndexCount() const + { + return indexCount_; + } + +private: + + struct element { + size_t vertexId; + size_t uvId; + size_t normalId; + + bool operator<(const element& other) const + { + return std::tie(vertexId, uvId, normalId) < + std::tie(other.vertexId, other.uvId, other.normalId); + } + }; + + GLBuffer vertexBuffer_; + GLBuffer uvBuffer_; + GLBuffer normalBuffer_; + GLBuffer indexBuffer_; + size_t indexCount_; +}; + +#endif /* end of include guard: MESH_H_76B72E12 */ diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp new file mode 100644 index 0000000..6eef2f3 --- /dev/null +++ b/src/renderer/renderer.cpp @@ -0,0 +1,635 @@ +#include "renderer.h" +#include "consts.h" +#include "game.h" +#include +#include "texture.h" + +// include stb_image +#define STB_IMAGE_IMPLEMENTATION +#define STBI_ONLY_PNG +#define STBI_ONLY_BMP +#include "stb_image.h" + +void setFramebufferSize(GLFWwindow* w, int width, int height) +{ + Game& game = *static_cast(glfwGetWindowUserPointer(w)); + Renderer& renderer = game.getRenderer(); + + renderer.width_ = width; + renderer.height_ = height; + + renderer.bloomFb_ = {}; + renderer.bloomDepth_ = {}; + renderer.preBloomTex_ = {}; + renderer.bloomPassTex1_ = {}; + renderer.bloomPassTex2_ = {}; + + renderer.initializeFramebuffers(); +} + +bool Renderer::singletonInitialized_ = false; + +Renderer::Window::Window() +{ + // Initialize GLFW + if (!glfwInit()) + { + throw std::runtime_error("Failed to initialize GLFW"); + } + + glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3 + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + // Create a window + window_ = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr); + if (window_ == nullptr) + { + throw std::runtime_error("Failed to open GLFW window"); + } + + glfwMakeContextCurrent(window_); + + glewExperimental = true; // Needed in core profile + if (glewInit() != GLEW_OK) + { + throw std::runtime_error("Failed to initialize GLEW"); + } + + glfwSetFramebufferSizeCallback(window_, &setFramebufferSize); +} + +Renderer::Window::~Window() +{ + glfwTerminate(); +} + +Renderer::Renderer() : + monitor_("res/monitor-old.obj"), + ntscShader_("ntsc"), + finalShader_("final"), + blitShader_("blit"), + fillShader_("fill"), + bloom1Shader_("bloom1"), + bloom2Shader_("bloom2") +{ + if (singletonInitialized_) + { + throw std::logic_error("Singleton renderer already initialized"); + } + + singletonInitialized_ = true; + + // Set up vertex array object + glBindVertexArray(vao_.getId()); + + // Enable depth testing + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + // Enable blending + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Set up the rendering buffers and textures + glfwGetFramebufferSize(window_.getHandle(), &width_, &height_); + + initializeFramebuffers(); + + // Load the vertices of a flat surface + GLfloat g_quad_vertex_buffer_data[] = { + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + }; + + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 18, + g_quad_vertex_buffer_data, + GL_STATIC_DRAW); + + // Load NTSC artifacts + int atdw, atdh; + unsigned char* artifactsData = + stbi_load("res/artifacts.bmp", &atdw, &atdh, 0, 3); + + flipImageData(artifactsData, atdw, atdh, 3); + + glBindTexture(GL_TEXTURE_2D, artifactsTex_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + atdw, + atdh, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + artifactsData); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST_MIPMAP_NEAREST); + + glGenerateMipmap(GL_TEXTURE_2D); + stbi_image_free(artifactsData); + + // Load NTSC scanlines + unsigned char* scanlinesData = + stbi_load("res/scanlines_333.bmp", &atdw, &atdh, 0, 3); + + flipImageData(scanlinesData, atdw, atdh, 3); + + glBindTexture(GL_TEXTURE_2D, scanlinesTex_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + atdw, + atdh, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + scanlinesData); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST_MIPMAP_NEAREST); + + glGenerateMipmap(GL_TEXTURE_2D); + stbi_image_free(scanlinesData); +} + +void Renderer::initializeFramebuffers() +{ + // Set up the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; + glDrawBuffers(1, DrawBuffers); + + // Set up the bloom framebuffer and depthbuffer + glBindFramebuffer(GL_FRAMEBUFFER, bloomFb_.getId()); + GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1}; + glDrawBuffers(1, DrawBuffers2); + + glBindRenderbuffer(GL_RENDERBUFFER, bloomDepth_.getId()); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width_, height_); + glFramebufferRenderbuffer( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, + bloomDepth_.getId()); + + // Set up the NTSC rendering buffers + glBindTexture(GL_TEXTURE_2D, renderPages_[0].getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + GAME_WIDTH, + GAME_HEIGHT, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, renderPages_[1].getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + GAME_WIDTH, + GAME_HEIGHT, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // Set up bloom rendering buffers + glBindTexture(GL_TEXTURE_2D, preBloomTex_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + width_, + height_, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, bloomPassTex1_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + width_ / 4, + height_ / 4, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, bloomPassTex2_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + width_ / 4, + height_ / 4, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +Renderer::~Renderer() +{ + singletonInitialized_ = false; +} + +void Renderer::fill(Texture& tex, Rectangle dstrect, int r, int g, int b) +{ + // Target the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex.getId(), 0); + + // Set up the vertex attributes + int width = tex.getWidth(); + int height = tex.getHeight(); + + GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; + GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); + GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; + GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); + + GLfloat vertexData[] = { + minx, miny, + maxx, miny, + maxx, maxy, + minx, miny, + minx, maxy, + maxx, maxy + }; + + GLBuffer vertexBuffer; + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 12, + vertexData, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + glViewport(0, 0, tex.getWidth(), tex.getHeight()); + glClear(GL_DEPTH_BUFFER_BIT); + + fillShader_.use(); + glUniform3f( + fillShader_.getUniformLocation("vecColor"), + r / 255.0, + g / 255.0, + b / 255.0); + + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDisableVertexAttribArray(0); +} + +void Renderer::blit( + const Texture& src, + Texture& dst, + Rectangle srcrect, + Rectangle dstrect, + double alpha) +{ + alpha = glm::clamp(alpha, 0.0, 1.0); + + // Target the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst.getId(), 0); + + // Set up the vertex attributes + int width = dst.getWidth(); + int height = dst.getHeight(); + + GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; + GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); + GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; + GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); + + GLfloat vertexData[] = { + minx, miny, + maxx, miny, + minx, maxy, + maxx, maxy + }; + + GLBuffer vertexBuffer; + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 8, + vertexData, + GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + GLfloat minu = (GLfloat) srcrect.x / src.getWidth(); + GLfloat minv = 1 - ((GLfloat) srcrect.y / src.getHeight()); + GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / src.getWidth(); + GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / src.getHeight()); + + GLfloat uvData[] = { + minu, minv, + maxu, minv, + minu, maxv, + maxu, maxv + }; + + GLBuffer uvBuffer; + glBindBuffer(GL_ARRAY_BUFFER, uvBuffer.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 8, + uvData, + GL_STATIC_DRAW); + + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + // Set up the shader + blitShader_.use(); + glClear(GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, dst.getWidth(), dst.getHeight()); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, src.getId()); + glUniform1i(blitShader_.getUniformLocation("srctex"), 0); + glUniform1f(blitShader_.getUniformLocation("alpha"), alpha); + + // Blit! + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // Unload everything + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); +} + +void Renderer::bloomPass1( + const GLTexture& src, + GLTexture& dst, + bool horizontal, + glm::vec2 srcRes, + glm::vec2 dstRes) +{ + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst.getId(), 0); + glViewport(0,0,dstRes.x,dstRes.y); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + bloom1Shader_.use(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, src.getId()); + glUniform1i(bloom1Shader_.getUniformLocation("inTex"), 0); + + glm::vec2 offset = glm::vec2(0.0); + if (horizontal) + { + offset.x = 1.2/srcRes.x; + } else { + offset.y = 1.2/srcRes.y; + } + + glUniform2f(bloom1Shader_.getUniformLocation("offset"), offset.x, offset.y); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableVertexAttribArray(0); +} + +void Renderer::renderScreen(const Texture& tex) +{ + // First we're going to composite our frame with the previous frame + // We start by setting up the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + renderPages_[curBuf_].getId(), + 0); + + // Set up the shader + glViewport(0,0,GAME_WIDTH,GAME_HEIGHT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + ntscShader_.use(); + + // Use the current frame texture, nearest neighbor and clamped to edge + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tex.getId()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glUniform1i(ntscShader_.getUniformLocation("curFrameSampler"), 0); + + // Use the previous frame composite texture, nearest neighbor and clamped to + // edge + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, renderPages_[(curBuf_ + 1) % 2].getId()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glUniform1i(ntscShader_.getUniformLocation("prevFrameSampler"), 1); + + // Load the NTSC artifact texture + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, artifactsTex_.getId()); + glUniform1i(ntscShader_.getUniformLocation("NTSCArtifactSampler"), 2); + glUniform1f(ntscShader_.getUniformLocation("NTSCLerp"), curBuf_ * 1.0); + + // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect! + glUniform1f(ntscShader_.getUniformLocation("Tuning_NTSC"), 0.0); + + // Render our composition + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableVertexAttribArray(0); + + // We're going to render the screen now + glBindFramebuffer(GL_FRAMEBUFFER, bloomFb_.getId()); + glFramebufferTexture( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + preBloomTex_.getId(), + 0); + + glViewport(0,0,width_,height_); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + finalShader_.use(); + + // Use the composited frame texture, linearly filtered and filling in black + // for the border + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, renderPages_[curBuf_].getId()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + + float borderColor[] = {0.0f, 0.0f, 0.0f, 1.0f}; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); + + glGenerateMipmap(GL_TEXTURE_2D); + glUniform1i(finalShader_.getUniformLocation("rendertex"), 0); + + // Use the scanlines texture + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, scanlinesTex_.getId()); + glUniform1i(finalShader_.getUniformLocation("scanlinestex"), 1); + + // Initialize the MVP matrices + glm::mat4 p_matrix = glm::perspective( + glm::radians(25.0f), + static_cast(width_) / static_cast(height_), + 0.1f, + 100.0f); + + glm::mat4 v_matrix = glm::lookAt( + glm::vec3(3.75,0,0), // Camera + glm::vec3(0,0,0), // Center + glm::vec3(0,1,0)); // Up + + glm::mat4 m_matrix = glm::mat4(1.0); + glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix; + + glUniformMatrix4fv( + finalShader_.getUniformLocation("MVP"), + 1, + GL_FALSE, + &mvp_matrix[0][0]); + + glUniformMatrix4fv( + finalShader_.getUniformLocation("worldMat"), + 1, + GL_FALSE, + &m_matrix[0][0]); + + glUniform2f(finalShader_.getUniformLocation("resolution"), width_, height_); + glUniform1f(finalShader_.getUniformLocation("iGlobalTime"), glfwGetTime()); + + glUniform3f( + finalShader_.getUniformLocation("frameColor"), + 0.76f, + 0.78f, + 0.81f); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, monitor_.getVertexBufferId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, monitor_.getNormalBufferId()); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glEnableVertexAttribArray(2); + glBindBuffer(GL_ARRAY_BUFFER, monitor_.getUvBufferId()); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor_.getIndexBufferId()); + glDrawElements( + GL_TRIANGLES, + monitor_.getIndexCount(), + GL_UNSIGNED_SHORT, + nullptr); + + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); + + // First pass of bloom! + glm::vec2 bufferSize = glm::vec2(width_, height_); + + bloomPass1( + preBloomTex_, + bloomPassTex1_, + true, + bufferSize, + bufferSize / 4.0f); + + bloomPass1( + bloomPassTex1_, + bloomPassTex2_, + false, + bufferSize / 4.0f, + bufferSize / 4.0f); + + // Do the second pass of bloom and render to screen + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, width_, height_); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + bloom2Shader_.use(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, preBloomTex_.getId()); + glUniform1i(bloom2Shader_.getUniformLocation("clearTex"), 0); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, bloomPassTex2_.getId()); + glUniform1i(bloom2Shader_.getUniformLocation("blurTex"), 1); + + glUniform1f(bloom2Shader_.getUniformLocation("iGlobalTime"), glfwGetTime()); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableVertexAttribArray(0); + + glfwSwapBuffers(window_.getHandle()); + + curBuf_ = (curBuf_ + 1) % 2; +} diff --git a/src/renderer/renderer.h b/src/renderer/renderer.h new file mode 100644 index 0000000..0b10af5 --- /dev/null +++ b/src/renderer/renderer.h @@ -0,0 +1,114 @@ +#ifndef RENDERER_H +#define RENDERER_H + +#include "gl.h" +#include "wrappers.h" +#include "mesh.h" +#include "shader.h" +#include + +class Texture; +struct Rectangle; + +class Renderer { +public: + + class Window { + public: + + Window(); + + Window(const Window& other) = delete; + Window& operator=(const Window& other) = delete; + + ~Window(); + + inline GLFWwindow* getHandle() + { + return window_; + } + + private: + + GLFWwindow* window_; + }; + + static inline bool isSingletonInitialized() + { + return singletonInitialized_; + } + + Renderer(); + + Renderer(const Renderer& other) = delete; + Renderer& operator=(const Renderer& other) = delete; + + ~Renderer(); + + inline Window& getWindow() + { + return window_; + } + + void fill( + Texture& tex, + Rectangle loc, + int r, + int g, + int b); + + void blit( + const Texture& src, + Texture& dst, + Rectangle srcrect, + Rectangle dstrect, + double alpha = 1.0); + + void renderScreen(const Texture& tex); + +private: + + friend void setFramebufferSize(GLFWwindow* w, int width, int height); + + void initializeFramebuffers(); + + void bloomPass1( + const GLTexture& src, + GLTexture& dst, + bool horizontal, + glm::vec2 srcRes, + glm::vec2 dstRes); + + static bool singletonInitialized_; + + Window window_; + GLVertexArray vao_; + + GLFramebuffer genericFb_; + GLFramebuffer bloomFb_; + GLRenderbuffer bloomDepth_; + + GLTexture renderPages_[2]; + GLTexture preBloomTex_; + GLTexture bloomPassTex1_; + GLTexture bloomPassTex2_; + + Mesh monitor_; + GLBuffer quadBuffer_; + + GLTexture artifactsTex_; + GLTexture scanlinesTex_; + + Shader ntscShader_; + Shader finalShader_; + Shader blitShader_; + Shader fillShader_; + Shader bloom1Shader_; + Shader bloom2Shader_; + + size_t curBuf_ = 0; + int width_; + int height_; +}; + +#endif diff --git a/src/renderer/shader.cpp b/src/renderer/shader.cpp new file mode 100644 index 0000000..735fc22 --- /dev/null +++ b/src/renderer/shader.cpp @@ -0,0 +1,84 @@ +#include "shader.h" +#include +#include +#include "util.h" + +Shader::Shader(std::string name) +{ + GLShader vertexShader(GL_VERTEX_SHADER); + GLShader fragmentShader(GL_FRAGMENT_SHADER); + + std::ifstream vertexFile("shaders/" + name + ".vertex"); + std::ifstream fragmentFile("shaders/" + name + ".fragment"); + + std::string vertexCode(slurp(vertexFile)); + std::string fragmentCode(slurp(fragmentFile)); + + const char* vertexCodePtr = vertexCode.c_str(); + const char* fragmentCodePtr = fragmentCode.c_str(); + + glShaderSource(vertexShader.getId(), 1, &vertexCodePtr, nullptr); + glShaderSource(fragmentShader.getId(), 1, &fragmentCodePtr, nullptr); + + glCompileShader(vertexShader.getId()); + glCompileShader(fragmentShader.getId()); + +#ifdef DEBUG + GLint result = GL_FALSE; + int infoLogLength; + + glGetShaderiv(vertexShader.getId(), GL_COMPILE_STATUS, &result); + + if (result == GL_FALSE) + { + glGetShaderiv(vertexShader.getId(), GL_INFO_LOG_LENGTH, &infoLogLength); + + std::vector errMsg(infoLogLength); + glGetShaderInfoLog( + vertexShader.getId(), + infoLogLength, + nullptr, + errMsg.data()); + + throw std::gl_error("Could not compile shader", errMsg.data()); + } + + glGetShaderiv(fragmentShader.getId(), GL_COMPILE_STATUS, &result); + + if (result == GL_FALSE) + { + glGetShaderiv(fragmentShader.getId(), GL_INFO_LOG_LENGTH, &infoLogLength); + + std::vector errMsg(infoLogLength); + glGetShaderInfoLog( + fragmentShader.getId(), + infoLogLength, + nullptr, + errMsg.data()); + + throw std::gl_error("Could not compile shader", errMsg.data()); + } +#endif + + glAttachShader(program_.getId(), vertexShader.getId()); + glAttachShader(program_.getId(), fragmentShader.getId()); + glLinkProgram(program_.getId()); + +#ifdef DEBUG + glGetProgramiv(program_.getId(), GL_LINK_STATUS, &result); + + if (result == GL_FALSE) + { + glGetProgramiv(program_.getId(), GL_INFO_LOG_LENGTH, &infoLogLength); + + std::vector errMsg(infoLogLength); + glGetProgramInfoLog( + program_.getId(), + infoLogLength, + nullptr, + errMsg.data()); + + throw std::gl_error("Could not link shader program", errMsg.data()); + } +#endif +} diff --git a/src/renderer/shader.h b/src/renderer/shader.h new file mode 100644 index 0000000..d2c673c --- /dev/null +++ b/src/renderer/shader.h @@ -0,0 +1,58 @@ +#ifndef SHADER_H_25115B63 +#define SHADER_H_25115B63 + +#include +#include +#include "gl.h" +#include "wrappers.h" + +class gl_error : public std::logic_error { +public: + + gl_error( + const char* msg, + std::string info) : + std::logic_error(msg), + info_(std::move(info)) + { + } + + gl_error( + std::string& msg, + std::string info) : + std::logic_error(msg), + info_(std::move(info)) + { + } + + inline const std::string& getInfo() const + { + return info_; + } + +private: + + std::string info_; +}; + +class Shader { +public: + + Shader(std::string name); + + inline void use() + { + glUseProgram(program_.getId()); + } + + inline GLint getUniformLocation(const GLchar* name) + { + return glGetUniformLocation(program_.getId(), name); + } + +private: + + GLProgram program_; +}; + +#endif /* end of include guard: SHADER_H_25115B63 */ diff --git a/src/renderer/texture.cpp b/src/renderer/texture.cpp new file mode 100644 index 0000000..2728665 --- /dev/null +++ b/src/renderer/texture.cpp @@ -0,0 +1,124 @@ +#include "texture.h" +#include +#include "renderer.h" +#include "util.h" + +// include stb_image +#define STBI_ONLY_PNG +#define STBI_ONLY_BMP +#include "stb_image.h" + +Texture::Texture( + int width, + int height) : + width_(width), + height_(height) +{ + if (!Renderer::isSingletonInitialized()) + { + throw std::logic_error("Renderer needs to be initialized"); + } + + glBindTexture(GL_TEXTURE_2D, texture_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width_, + height_, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +} + +Texture::Texture(const char* filename) +{ + if (!Renderer::isSingletonInitialized()) + { + throw std::logic_error("Renderer needs to be initialized"); + } + + glBindTexture(GL_TEXTURE_2D, texture_.getId()); + unsigned char* data = stbi_load(filename, &width_, &height_, 0, 4); + flipImageData(data, width_, height_, 4); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width_, + height_, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + data); + + stbi_image_free(data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +Texture::Texture( + const Texture& tex) : + width_(tex.width_), + height_(tex.height_) +{ + if (!Renderer::isSingletonInitialized()) + { + throw std::logic_error("Renderer needs to be initialized"); + } + + unsigned char* data = new unsigned char[4 * width_ * height_]; + glBindTexture(GL_TEXTURE_2D, tex.getId()); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + + glBindTexture(GL_TEXTURE_2D, texture_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width_, + height_, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + data); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + + delete[] data; +} + +Texture::Texture(Texture&& tex) : Texture(0, 0) +{ + swap(*this, tex); +} + +Texture& Texture::operator= (Texture tex) +{ + swap(*this, tex); + + return *this; +} + +void swap(Texture& tex1, Texture& tex2) +{ + std::swap(tex1.width_, tex2.width_); + std::swap(tex1.height_, tex2.height_); + std::swap(tex1.texture_, tex2.texture_); +} + +Rectangle Texture::entirety() const +{ + return {0, 0, width_, height_}; +} diff --git a/src/renderer/texture.h b/src/renderer/texture.h new file mode 100644 index 0000000..3aa8773 --- /dev/null +++ b/src/renderer/texture.h @@ -0,0 +1,52 @@ +#ifndef TEXTURE_H_84EC6DF6 +#define TEXTURE_H_84EC6DF6 + +#include "wrappers.h" + +struct Rectangle { + int x; + int y; + int w; + int h; +}; + +class Texture { +public: + + Texture(int width, int height); + + Texture(const char* file); + + Texture(const Texture& tex); + + Texture(Texture&& tex); + + Texture& operator= (Texture tex); + + friend void swap(Texture& tex1, Texture& tex2); + + Rectangle entirety() const; + + inline GLuint getId() const + { + return texture_.getId(); + } + + inline int getWidth() const + { + return width_; + } + + inline int getHeight() const + { + return height_; + } + +private: + + GLTexture texture_; + int width_; + int height_; +}; + +#endif /* end of include guard: TEXTURE_H_84EC6DF6 */ diff --git a/src/renderer/wrappers.h b/src/renderer/wrappers.h new file mode 100644 index 0000000..c6edc11 --- /dev/null +++ b/src/renderer/wrappers.h @@ -0,0 +1,273 @@ +#ifndef WRAPPERS_H_1EE0965B +#define WRAPPERS_H_1EE0965B + +#include "gl.h" +#include + +class GLVertexArray { +public: + + GLVertexArray() + { + glGenVertexArrays(1, &id_); + } + + GLVertexArray(const GLVertexArray& other) = delete; + GLVertexArray& operator=(const GLVertexArray& other) = delete; + + GLVertexArray(GLVertexArray&& other) : GLVertexArray() + { + std::swap(id_, other.id_); + } + + GLVertexArray& operator=(GLVertexArray&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLVertexArray() + { + glDeleteVertexArrays(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLFramebuffer { +public: + + GLFramebuffer() + { + glGenFramebuffers(1, &id_); + } + + GLFramebuffer(const GLFramebuffer& other) = delete; + GLFramebuffer& operator=(const GLFramebuffer& other) = delete; + + GLFramebuffer(GLFramebuffer&& other) : GLFramebuffer() + { + std::swap(id_, other.id_); + } + + GLFramebuffer& operator=(GLFramebuffer&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLFramebuffer() + { + glDeleteFramebuffers(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLRenderbuffer { +public: + + GLRenderbuffer() + { + glGenRenderbuffers(1, &id_); + } + + GLRenderbuffer(const GLRenderbuffer& other) = delete; + GLRenderbuffer& operator=(const GLRenderbuffer& other) = delete; + + GLRenderbuffer(GLRenderbuffer&& other) : GLRenderbuffer() + { + std::swap(id_, other.id_); + } + + GLRenderbuffer& operator=(GLRenderbuffer&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLRenderbuffer() + { + glDeleteRenderbuffers(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLBuffer { +public: + + GLBuffer() + { + glGenBuffers(1, &id_); + } + + GLBuffer(const GLBuffer& other) = delete; + GLBuffer& operator=(const GLBuffer& other) = delete; + + GLBuffer(GLBuffer&& other) : GLBuffer() + { + std::swap(id_, other.id_); + } + + GLBuffer& operator=(GLBuffer&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLBuffer() + { + glDeleteBuffers(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLTexture { +public: + + GLTexture() + { + glGenTextures(1, &id_); + } + + GLTexture(const GLTexture& other) = delete; + GLTexture& operator=(const GLTexture& other) = delete; + + GLTexture(GLTexture&& other) : GLTexture() + { + std::swap(id_, other.id_); + } + + GLTexture& operator=(GLTexture&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLTexture() + { + glDeleteTextures(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLShader { +public: + + GLShader(GLenum type) + { + id_ = glCreateShader(type); + } + + GLShader(const GLShader& other) = delete; + GLShader& operator=(const GLShader& other) = delete; + + GLShader(GLShader&& other) : GLShader(GL_VERTEX_SHADER) + { + std::swap(id_, other.id_); + } + + GLShader& operator=(GLShader&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLShader() + { + glDeleteShader(id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLProgram { +public: + + GLProgram() + { + id_ = glCreateProgram(); + } + + GLProgram(const GLProgram& other) = delete; + GLProgram& operator=(const GLProgram& other) = delete; + + GLProgram(GLProgram&& other) : GLProgram() + { + std::swap(id_, other.id_); + } + + GLProgram& operator=(GLProgram&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLProgram() + { + glDeleteProgram(id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +#endif /* end of include guard: WRAPPERS_H_1EE0965B */ diff --git a/src/systems/animating.cpp b/src/systems/animating.cpp index 91fe925..22224c9 100644 --- a/src/systems/animating.cpp +++ b/src/systems/animating.cpp @@ -51,8 +51,9 @@ void AnimatingSystem::render(Texture& texture) transform.getH()}; const AnimationSet& aset = sprite.getAnimationSet(); - texture.blit( + game_.getRenderer().blit( aset.getTexture(), + texture, aset.getFrameRect(sprite.getFrame()), dstrect); } diff --git a/src/systems/animating.h b/src/systems/animating.h index d6a89a5..548bff1 100644 --- a/src/systems/animating.h +++ b/src/systems/animating.h @@ -3,7 +3,7 @@ #include "system.h" #include -#include "renderer.h" +#include "renderer/texture.h" class AnimatingSystem : public System { public: diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index 5b63ded..120a27a 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp @@ -48,7 +48,11 @@ void MappingSystem::render(Texture& texture) TILE_WIDTH, TILE_HEIGHT}; - texture.blit(mappable.getTileset(), std::move(src), std::move(dst)); + game_.getRenderer().blit( + mappable.getTileset(), + texture, + std::move(src), + std::move(dst)); } } @@ -67,7 +71,11 @@ void MappingSystem::render(Texture& texture) TILE_WIDTH, TILE_HEIGHT}; - texture.blit(mappable.getFont(), std::move(src), std::move(dst)); + game_.getRenderer().blit( + mappable.getFont(), + texture, + std::move(src), + std::move(dst)); } } } diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..f0c39fd --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,30 @@ +#include "util.h" + +std::string slurp(std::ifstream& in) +{ + std::stringstream sstr; + sstr << in.rdbuf(); + return sstr.str(); +} + +void flipImageData( + unsigned char* data, + int width, + int height, + int comps) +{ + unsigned char* dataCopy = new unsigned char[width * height * comps]; + memcpy(dataCopy, data, width * height * comps); + + int rowSize = width * comps; + + for (int i = 0; i < height; i++) + { + memcpy( + data + (rowSize * i), + dataCopy + (rowSize * (height - i - 1)), + rowSize); + } + + delete[] dataCopy; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..72cb0d3 --- /dev/null +++ b/src/util.h @@ -0,0 +1,41 @@ +#ifndef ALGORITHMS_H_1DDC517E +#define ALGORITHMS_H_1DDC517E + +#include +#include +#include + +template< typename ContainerT, typename PredicateT > +void erase_if( ContainerT& items, const PredicateT& predicate ) { + for( auto it = items.begin(); it != items.end(); ) { + if( predicate(*it) ) it = items.erase(it); + else ++it; + } +}; + +struct chlit +{ + chlit(char c) : c_(c) { } + char c_; +}; + +inline std::istream& operator>>(std::istream& is, chlit x) +{ + char c; + if (is >> c && c != x.c_) + { + is.setstate(std::iostream::failbit); + } + + return is; +} + +std::string slurp(std::ifstream& in); + +void flipImageData( + unsigned char* data, + int width, + int height, + int comps); + +#endif /* end of include guard: ALGORITHMS_H_1DDC517E */ -- cgit 1.4.1 From 83f51a6892629921b4cc482b986656a0a5cc5f6a Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 3 May 2018 14:41:01 -0400 Subject: Added simple AI implementation The new AutomatingSystem and AutomatableComponent are responsible for simple AI tasks. This currently is limited to moving entities at a certain speed for certain periods of time. These tasks are arranged as a set of behaviors, which are picked randomly when automation starts or when a behavior finishes executing. A behavior is a sequence of actions that run one after another. Currently, if an automated entity is blocked from moving by a collision, it will be coerced out of its intended path. This is because the automation parameters are stored as a speed and a duration, rather than a starting location and an ending location. This may end up being changed, or made configurable, as this is an early implementation of this feature and will need to be more complex later. Added an RNG object to the Game class, so that the AutomatingSystem can pick behaviors at random. --- CMakeLists.txt | 1 + src/components/automatable.h | 96 ++++++++++++++++++++++++ src/game.cpp | 4 +- src/game.h | 9 ++- src/main.cpp | 6 +- src/systems/automating.cpp | 71 ++++++++++++++++++ src/systems/automating.h | 19 +++++ src/systems/realizing.cpp | 174 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 377 insertions(+), 3 deletions(-) create mode 100644 src/components/automatable.h create mode 100644 src/systems/automating.cpp create mode 100644 src/systems/automating.h (limited to 'src/main.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index cd652e2..04ca668 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ add_executable(Aromatherapy src/systems/playing.cpp src/systems/scheduling.cpp src/systems/realizing.cpp + src/systems/automating.cpp vendor/stb_image.cpp ) diff --git a/src/components/automatable.h b/src/components/automatable.h new file mode 100644 index 0000000..b37945f --- /dev/null +++ b/src/components/automatable.h @@ -0,0 +1,96 @@ +#ifndef AUTOMATABLE_H_3D519131 +#define AUTOMATABLE_H_3D519131 + +#include "component.h" +#include +#include + +class AutomatableComponent : public Component { +public: + + /** + * Helper class that defines an automatable action. + */ + class Action { + public: + + /** + * The horizontal and vertical speed, in pixels/sec, that the entity should + * move at. + */ + double speedX; + double speedY; + + /** + * The duration of the action in seconds. + */ + double dur; + }; + + /** + * Helper type that defines a behavior that an entity can exhibit, which is a + * list of actions that are stepped through in sequence. + */ + using Behavior = std::vector; + + /** + * A group of behaviors that the entity can exhibit, which are picked at + * random at the start of automation and whenever a behavior completes. + * + * @managed_by RealizingSystem + */ + std::vector behaviors; + + /** + * A random distribution over the above behaviors. + * + * @managed_by RealizingSystem + */ + std::discrete_distribution behaviorDist; + + /** + * A flag indicating whether a behavior is currently executing. + * + * @managed_by AutomatingSystem + */ + bool behaviorRunning = false; + + /** + * A flag indicating whether an action is currently executing. + * + * @managed_by AutomatingSystem + */ + bool actionRunning = false; + + /** + * The index of the currently executing behavior, if there is one. + * + * @managed_by AutomatingSystem + */ + size_t currentBehavior; + + /** + * The index of the currently executing action, if there is one. + * + * @managed_by AutomatingSystem + */ + size_t currentAction; + + /** + * The amount of time remaining, in seconds, of the currently executing + * action. + * + * @managed_by AutomatingSystem + */ + double remaining; + + /** + * If this flag is disabled, the entity will be ignored by the automating + * system. + * + * @managed_by RealizingSystem + */ + bool active = false; +}; + +#endif /* end of include guard: AUTOMATABLE_H_3D519131 */ diff --git a/src/game.cpp b/src/game.cpp index d10c52c..bf2b10b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -12,6 +12,7 @@ #include "systems/playing.h" #include "systems/scheduling.h" #include "systems/realizing.h" +#include "systems/automating.h" #include "animation.h" #include "consts.h" @@ -29,12 +30,13 @@ void key_callback(GLFWwindow* window, int key, int, int action, int) game.systemManager_.input(key, action); } -Game::Game() +Game::Game(std::mt19937& rng) : rng_(rng) { systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); + systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); diff --git a/src/game.h b/src/game.h index 92a67d9..dc256c6 100644 --- a/src/game.h +++ b/src/game.h @@ -1,6 +1,7 @@ #ifndef GAME_H_1014DDC9 #define GAME_H_1014DDC9 +#include #include "entity_manager.h" #include "system_manager.h" #include "renderer/renderer.h" @@ -8,10 +9,15 @@ class Game { public: - Game(); + Game(std::mt19937& rng); void execute(); + inline std::mt19937& getRng() + { + return rng_; + } + inline Renderer& getRenderer() { return renderer_; @@ -36,6 +42,7 @@ public: private: + std::mt19937 rng_; Renderer renderer_; EntityManager entityManager_; SystemManager systemManager_; diff --git a/src/main.cpp b/src/main.cpp index ddbc15f..d59d0f9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,15 @@ +#include #include "muxer.h" #include "game.h" int main() { + std::random_device randomDevice; + std::mt19937 rng(randomDevice()); + initMuxer(); - Game game; + Game game(rng); game.execute(); destroyMuxer(); diff --git a/src/systems/automating.cpp b/src/systems/automating.cpp new file mode 100644 index 0000000..0d85957 --- /dev/null +++ b/src/systems/automating.cpp @@ -0,0 +1,71 @@ +#include "automating.h" +#include "game.h" +#include "components/automatable.h" +#include "components/ponderable.h" +#include "systems/pondering.h" + +void AutomatingSystem::tick(double dt) +{ + auto entities = game_.getEntityManager().getEntitiesWithComponents< + AutomatableComponent, + PonderableComponent>(); + + for (id_type entity : entities) + { + auto& automatable = game_.getEntityManager(). + getComponent(entity); + + if (!automatable.active) + { + continue; + } + + if (automatable.behaviorRunning && + (automatable.remaining <= 0.0)) + { + automatable.currentAction++; + automatable.actionRunning = false; + + if (automatable.currentAction == + automatable.behaviors[automatable.currentBehavior].size()) + { + automatable.behaviorRunning = false; + } + } + + if (!automatable.behaviorRunning) + { + automatable.currentBehavior = automatable.behaviorDist(game_.getRng()); + automatable.currentAction = 0; + automatable.behaviorRunning = true; + } + + AutomatableComponent::Action& curAction = + automatable.behaviors + [automatable.currentBehavior] + [automatable.currentAction]; + + if (!automatable.actionRunning) + { + automatable.remaining = curAction.dur; + automatable.actionRunning = true; + } + + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + ponderable.velX = curAction.speedX; + ponderable.velY = curAction.speedY; + + automatable.remaining -= dt; + } +} + +void AutomatingSystem::initPrototype(id_type prototype) +{ + auto& automatable = game_.getEntityManager(). + getComponent(prototype); + + automatable.behaviorRunning = false; + automatable.actionRunning = false; +} diff --git a/src/systems/automating.h b/src/systems/automating.h new file mode 100644 index 0000000..c78b7cf --- /dev/null +++ b/src/systems/automating.h @@ -0,0 +1,19 @@ +#ifndef AUTOMATING_H_E6E5D76E +#define AUTOMATING_H_E6E5D76E + +#include "system.h" + +class AutomatingSystem : public System { +public: + + AutomatingSystem(Game& game) : System(game) + { + } + + void tick(double dt); + + void initPrototype(id_type prototype); + +}; + +#endif /* end of include guard: AUTOMATING_H_E6E5D76E */ diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp index 3656acb..8e670ac 100644 --- a/src/systems/realizing.cpp +++ b/src/systems/realizing.cpp @@ -12,9 +12,11 @@ #include "components/playable.h" #include "components/ponderable.h" #include "components/transformable.h" +#include "components/automatable.h" #include "systems/mapping.h" #include "systems/animating.h" #include "systems/pondering.h" +#include "systems/automating.h" inline xmlChar* getProp(xmlNodePtr node, const char* attr) { @@ -27,6 +29,92 @@ inline xmlChar* getProp(xmlNodePtr node, const char* attr) return key; } +void parseAI( + xmlNodePtr node, + std::vector& behavior, + const std::map& items) +{ + xmlChar* key = nullptr; + + if (!xmlStrcmp( + node->name, + reinterpret_cast("switch"))) + { + key = getProp(node, "item"); + std::string switchItem = reinterpret_cast(key); + xmlFree(key); + + for (xmlNodePtr switchNode = node->xmlChildrenNode; + switchNode != nullptr; + switchNode = switchNode->next) + { + if (!xmlStrcmp( + switchNode->name, + reinterpret_cast("case"))) + { + key = getProp(switchNode, "value"); + int caseValue = atoi(reinterpret_cast(key)); + xmlFree(key); + + if (items.at(switchItem) == caseValue) + { + for (xmlNodePtr caseNode = switchNode->xmlChildrenNode; + caseNode != nullptr; + caseNode = caseNode->next) + { + parseAI( + caseNode, + behavior, + items); + } + } + } + } + } else if (!xmlStrcmp( + node->name, + reinterpret_cast("move"))) + { + key = getProp(node, "direction"); + std::string direction = reinterpret_cast(key); + xmlFree(key); + + key = getProp(node, "length-var"); + std::string lengthVar = reinterpret_cast(key); + xmlFree(key); + + key = getProp(node, "speed-var"); + std::string speedVar = reinterpret_cast(key); + xmlFree(key); + + double length = items.at(lengthVar); + double speed = items.at(speedVar); + + AutomatableComponent::Action action; + + if (direction == "left") + { + action.speedX = -speed; + action.speedY = 0; + } else if (direction == "right") + { + action.speedX = speed; + action.speedY = 0; + } else if (direction == "up") + { + action.speedX = 0; + action.speedY = -speed; + } else if (direction == "down") + { + action.speedX = 0; + action.speedY = speed; + } + + action.dur = length / speed; + + behavior.push_back(std::move(action)); + } +} + // TODO: neither the XML doc nor any of the emplaced entities are properly // destroyed if this method throws an exception. EntityManager::id_type RealizingSystem::initSingleton( @@ -211,6 +299,70 @@ EntityManager::id_type RealizingSystem::initSingleton( game_.getSystemManager().getSystem(). initializeBody(mapObject, PonderableComponent::Type::vacuumed); + // Look for any object configuration. + std::map items; + + for (xmlNodePtr objectNode = mapNode->xmlChildrenNode; + objectNode != nullptr; + objectNode = objectNode->next) + { + if (!xmlStrcmp( + objectNode->name, + reinterpret_cast("item"))) + { + key = getProp(objectNode, "id"); + std::string itemName = reinterpret_cast(key); + xmlFree(key); + + key = xmlNodeGetContent(objectNode); + int itemVal = atoi(reinterpret_cast(key)); + xmlFree(key); + + items[itemName] = itemVal; + } + } + + // Add any AI behaviors. + std::vector behaviorWeights; + + for (xmlNodePtr protoSubNode = prototypeNode->xmlChildrenNode; + protoSubNode != nullptr; + protoSubNode = protoSubNode->next) + { + if (!xmlStrcmp( + protoSubNode->name, + reinterpret_cast("ai"))) + { + if (!game_.getEntityManager(). + hasComponent(mapObject)) + { + game_.getEntityManager(). + emplaceComponent(mapObject); + } + + auto& automatable = game_.getEntityManager(). + getComponent(mapObject); + + key = getProp(protoSubNode, "chance"); + behaviorWeights.push_back(atof(reinterpret_cast(key))); + xmlFree(key); + + std::vector behavior; + + for (xmlNodePtr aiNode = protoSubNode->xmlChildrenNode; + aiNode != nullptr; + aiNode = aiNode->next) + { + parseAI( + aiNode, + behavior, + items); + } + + automatable.behaviors.push_back(std::move(behavior)); + } + } + mappable.objects.push_back(mapObject); } else if (!xmlStrcmp( mapNode->name, @@ -304,6 +456,7 @@ void RealizingSystem::loadMap(id_type mapEntity) auto& animating = game_.getSystemManager().getSystem(); auto& pondering = game_.getSystemManager().getSystem(); + auto& automating = game_.getSystemManager().getSystem(); std::set players = game_.getEntityManager().getEntitiesWithComponents< @@ -366,6 +519,11 @@ void RealizingSystem::loadMap(id_type mapEntity) pondering.initPrototype(prototype); } + if (game_.getEntityManager().hasComponent(prototype)) + { + automating.initPrototype(prototype); + } + enterActiveMap(prototype); } @@ -399,6 +557,14 @@ void RealizingSystem::enterActiveMap(id_type entity) ponderable.active = true; } + + if (game_.getEntityManager().hasComponent(entity)) + { + auto& automatable = game_.getEntityManager(). + getComponent(entity); + + automatable.active = true; + } } void RealizingSystem::leaveActiveMap(id_type entity) @@ -418,4 +584,12 @@ void RealizingSystem::leaveActiveMap(id_type entity) ponderable.active = false; } + + if (game_.getEntityManager().hasComponent(entity)) + { + auto& automatable = game_.getEntityManager(). + getComponent(entity); + + automatable.active = false; + } } -- cgit 1.4.1