diff --git a/include/square.hpp b/include/board.hpp similarity index 60% rename from include/square.hpp rename to include/board.hpp index d4744ed..99266c0 100644 --- a/include/square.hpp +++ b/include/board.hpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -16,19 +16,25 @@ along with this program. If not, see . */ -#ifndef OUR_DICK_SQUARE_HPP -#define OUR_DICK_SQUARE_HPP +#ifndef OUR_DICK_BOARD_HPP +#define OUR_DICK_BOARD_HPP #include "graphics/mesh.hpp" #include "graphics/model.hpp" -#include "graphics/material.hpp" #include "graphics/shader_program.hpp" -#include "renderable.hpp" +#include "graphics/material.hpp" + #include "engine/object.hpp" +#include "renderable.hpp" +#include "engine/resource_manager.hpp" +#include "math/vec.hpp" +#include "config.hpp" + +#include //unique_ptr gfx::unified_mesh square_mesh(const gfx::material& blank, const gfx::material& o, const gfx::material& x); -class square : public renderable_iface , public egn::object_base +class tile : public renderable_iface, public egn::object_base { public: enum class value{ @@ -43,7 +49,7 @@ private: math::vec4 m_color_filter = {}; public: - square(gfx::model* model); + tile(gfx::model* model); void set_value(value v); value get_value()const; @@ -52,6 +58,32 @@ public: void render(gfx::shader_program&)override; + +}; +class board : public renderable_iface, public egn::object_base +{ +private: + std::unique_ptr m_tiles; +public: + board(egn::resource_manager& r); + ~board(void) = default; + + tile::value check_winner(void)const; + + bool is_full(void)const; + + void render(gfx::shader_program& shader); + + int click_collision_cheat(const math::vec3&)const; + + void set_tile(int index, tile::value value); + tile::value get_tile(int index)const; + +private: + tile::value check_rows_(void)const; + tile::value check_columns_(void)const; + tile::value check_diagonals_(void)const; }; + #endif diff --git a/include/engine/game.hpp b/include/engine/game.hpp index 2c0d7fb..6a89c05 100644 --- a/include/engine/game.hpp +++ b/include/engine/game.hpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -22,6 +22,7 @@ #include "observable.hpp" #include "game_state.hpp" #include "graphics/window.hpp" +#include "resource_manager.hpp" #include "input.hpp" #include @@ -33,6 +34,7 @@ namespace egn{ protected: gfx::window m_window; game_state_manager m_states_manager; + resource_manager m_res_manager; std::queue m_event_queue; double m_last_time; @@ -48,6 +50,12 @@ namespace egn{ void on_notify(const game_state_event& e)override; + resource_manager& resource_man(void); + const resource_manager& resource_man(void)const; + + void push_state(std::unique_ptr&&); + void pop_state(void); + private: void setup_window_(); }; diff --git a/include/engine/game_state.hpp b/include/engine/game_state.hpp index 7392930..fb8f1f6 100644 --- a/include/engine/game_state.hpp +++ b/include/engine/game_state.hpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -28,6 +28,8 @@ namespace egn{ + class game; + struct game_state_event { enum class state_type{ SHOULD_CLOSE, @@ -59,10 +61,10 @@ namespace egn{ class game_state_iface { protected: - game_state_manager* m_owner = nullptr; + game* m_owner = nullptr; protected: - game_state_iface(game_state_manager* owner); + game_state_iface(game* owner); game_state_iface(const game_state_iface& g) = default; game_state_iface(game_state_iface&& g) = default; diff --git a/include/graphics/image.hpp b/include/engine/image.hpp similarity index 65% rename from include/graphics/image.hpp rename to include/engine/image.hpp index 07c885c..002c744 100644 --- a/include/graphics/image.hpp +++ b/include/engine/image.hpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -16,10 +16,12 @@ along with this program. If not, see . */ -#ifndef OUR_DICK_GRAPHICS_IMAGE_HPP -#define OUR_DICK_GRAPHICS_IMAGE_HPP +#ifndef OUR_DICK_ENGINE_IMAGE_HPP +#define OUR_DICK_ENGINE_IMAGE_HPP -namespace gfx{ +#include + +namespace egn{ //class handling image loading from files class image @@ -52,6 +54,27 @@ namespace gfx{ unsigned char* data(); }; + class deferred_image + { + private: + std::string m_filename; + bool m_flip = false; + int m_req_chan = 0; + public: + deferred_image(const char* file, bool flip = false, int req_chan = 0); + deferred_image(const std::string& file, bool flip = false, int req_chan = 0); + deferred_image(const deferred_image&) = default; + deferred_image(deferred_image&&) = default; + + ~deferred_image(void) = default; + + deferred_image& operator=(const deferred_image&) = default; + deferred_image& operator=(deferred_image&&) = default; + + operator image(void)const; + image get_image(void)const; + }; + } #endif diff --git a/include/engine/resource_manager.hpp b/include/engine/resource_manager.hpp new file mode 100644 index 0000000..2346175 --- /dev/null +++ b/include/engine/resource_manager.hpp @@ -0,0 +1,78 @@ +/** + This file is a part of our_dick + Copyright (C) 2021 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +#ifndef OUR_DICK_ENGINE_RESOURCE_MANAGER_HPP +#define OUR_DICK_ENGINE_RESOURCE_MANAGER_HPP + +#include "engine/image.hpp" +#include "graphics/material.hpp" +#include "graphics/model.hpp" + +#include +#include //pair, forward + +namespace egn{ + + class resource_manager + { + private: + std::map m_textures; + std::map m_models; + + public: + resource_manager(void) = default; + resource_manager(const resource_manager&) = default; + resource_manager(resource_manager&&) = default; + + ~resource_manager(void) = default; + + resource_manager& operator=(const resource_manager&) = default; + resource_manager& operator=(resource_manager&&) = default; + + bool has_material(const char* key)const; + + template + std::pair emplace_material(const char* key, Args&&... args); + gfx::material* get_material(const char* file); + + bool has_model(const char* key)const; + + template + std::pair emplace_model(const char* key, Args&&... args); + gfx::model* get_model(const char* file); + }; + + + template + std::pair resource_manager::emplace_material(const char* key, Args&&... args){ + if(auto it = m_textures.find(key);it != m_textures.end()) + return {&(*it).second, false}; + auto ret = m_textures.emplace(key, std::forward(args)...); + return {&(*(ret.first)).second, true}; + } + template + std::pair resource_manager::emplace_model(const char* key, Args&&... args){ + if(auto it = m_models.find(key);it != m_models.end()) + return {&(*it).second, false}; + auto ret = m_models.emplace(key, std::forward(args)...); + return {&(*(ret.first)).second, true}; + } + +} + +#endif diff --git a/include/graphics/stb_alloc.hpp b/include/engine/stb_alloc.hpp similarity index 100% rename from include/graphics/stb_alloc.hpp rename to include/engine/stb_alloc.hpp diff --git a/include/graphics/stb_include.hpp b/include/engine/stb_include.hpp similarity index 100% rename from include/graphics/stb_include.hpp rename to include/engine/stb_include.hpp diff --git a/include/graphics/texture.hpp b/include/graphics/texture.hpp index 7a1f50d..2ef0abc 100644 --- a/include/graphics/texture.hpp +++ b/include/graphics/texture.hpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -19,7 +19,7 @@ #ifndef OUR_DICK_GRAPHICS_TEXTURE_HPP #define OUR_DICK_GRAPHICS_TEXTURE_HPP -#include "image.hpp" +#include "engine/image.hpp" #include "gl_include.hpp" #include "math/vec.hpp" @@ -88,7 +88,8 @@ namespace gfx{ texture(const unsigned char* data, GLenum format, GLsizei w, GLsizei h, GLenum type); texture(GLenum format, GLsizei w, GLsizei h, GLenum type); //create the texture with image data from 'i' - texture(const image& i); + texture(const egn::image& i); + texture(const egn::deferred_image& i); texture(const texture&) = delete; texture(texture&&); ~texture(); @@ -99,7 +100,9 @@ namespace gfx{ GLuint raw()const; //overwrite the current image data with 'i' - bool set_image(const image& i); + bool set_image(const unsigned char* data, GLenum format, GLsizei w, GLsizei h, GLenum type); + bool set_image(const egn::image& i); + bool set_image(const egn::deferred_image& i); //change wrap mode for both x and y void set_wrap_mode(wrap w); diff --git a/include/pause_state.hpp b/include/pause_state.hpp index 660fa14..224132a 100644 --- a/include/pause_state.hpp +++ b/include/pause_state.hpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -30,7 +30,7 @@ private: egn::game_state_iface* m_under_state; public: - pause_state(egn::game_state_manager& owner, egn::game_state_iface* under); + pause_state(egn::game& owner, egn::game_state_iface* under); void enter(); void leave(); diff --git a/include/play_state.hpp b/include/play_state.hpp index c30e992..b29ac72 100644 --- a/include/play_state.hpp +++ b/include/play_state.hpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -26,7 +26,6 @@ #include "sprite_renderer.hpp" #include "screen_renderer.hpp" #include "engine/camera.hpp" -#include "square.hpp" class play_state : public egn::game_state_iface { @@ -39,17 +38,12 @@ private: double m_last_time; public: - play_state(egn::game_state_manager& owner, int width, int height); + play_state(egn::game& owner, int width, int height); void enter()override; void leave()override; void handle_input(const egn::input_event& events)override; void update(double time)override; void render()override; - -private: - square::value check_win_condition_(); - bool is_board_full_(); - }; #endif diff --git a/include/scene.hpp b/include/scene.hpp index ffa72ca..a775698 100644 --- a/include/scene.hpp +++ b/include/scene.hpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -19,7 +19,6 @@ #ifndef OUR_DICK_SCENE_HPP #define OUR_DICK_SCENE_HPP -#include "square.hpp" #include "graphics/texture.hpp" //TODO: use material interface instead of direct texture #include "engine/camera.hpp" #include "renderable.hpp" @@ -31,9 +30,7 @@ struct scene { std::vector renderables; std::vector> objects; - std::vector textures; std::vector> cameras; - std::vector> models; }; #endif diff --git a/include/util/minmax.hpp b/include/util/minmax.hpp deleted file mode 100644 index d01c316..0000000 --- a/include/util/minmax.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/** - This file is a part of our_dick - Copyright (C) 2020 rexy712 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -#ifndef OUR_DICK_UTIL_MINMAX_HPP -#define OUR_DICK_UTIL_MINMAX_HPP - -//prevents inclusion of which triples compile times - -namespace util{ - - template - struct greater { - constexpr bool operator()(const T& left, const T& right)const{ - return left > right; - } - }; - - template - struct less { - constexpr bool operator()(const T& left, const T& right)const{ - return left < right; - } - }; - - template - static constexpr const T& max(const T& left, const T& right, Args&&... args){ - if constexpr(sizeof...(args) > 0){ - return left > right ? max(left, std::forward(args)...) : max(right, std::forward(args)...); - } - return left > right ? left : right; - } - template - static constexpr const T& min(const T& left, const T& right, Args&&... args){ - if constexpr(sizeof...(args) > 0){ - return left < right ? min(left, std::forward(args)...) : min(right, std::forward(args)...); - } - return left < right ? left : right; - } - template - static constexpr T maxc(const T& left, const T& right, Compare cmp){ - return cmp(left, right) ? left : right; - } - template - static constexpr T minc(const T& left, const T& right, Compare cmp){ - return cmp(left, right) ? left : right; - } - -} - -#endif diff --git a/include/util/ring_buffer.hpp b/include/util/ring_buffer.hpp deleted file mode 100644 index 0b1dadc..0000000 --- a/include/util/ring_buffer.hpp +++ /dev/null @@ -1,131 +0,0 @@ -/** - This file is a part of our_dick - Copyright (C) 2020 rexy712 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -#ifndef OUR_DICK_UTIL_RING_BUFFER_HPP -#define OUR_DICK_UTIL_RING_BUFFER_HPP - -#include //vector (duh) -#include //size_t -#include //atomic (duh) - - -#ifdef __cpp_lib_hardware_interference_size -#include //hardware_destructive_interference_size -#endif - -#ifndef __cpp_aligned_new -//TODO: custom aligned allocator -#error "Require aligned new allocation" -#endif - -namespace util{ - - //multiproducer, multiconsumer thread safe ring buffer with some attempts to optimize against thread thrashing - template - class mpmc_ring_buffer - { - public: - using value_type = T; - using size_type = size_t; - using pointer = value_type*; - using const_pointer = const value_type*; - using reference = value_type&; - using rvalue_reference = value_type&&; - using const_reference = const value_type&; - - private: - #if defined(__cpp_lib_hardware_interference_size) - // libc++ bug - // https://bugs.llvm.org/show_bug.cgi?id=41423 - #if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 11000 - static constexpr size_t cacheline_size = std::hardware_destructive_interference_size; - #else - static constexpr size_t cacheline_size = 64; - #endif - #else - //Best guess - static constexpr size_t cacheline_size = 64; - #endif - - class slot - { - public: - static constexpr size_type active_bit = 1; - private: - //ensure no false sharing with previous slot in queue - alignas(cacheline_size) std::atomic m_turn = {0}; - alignas(alignof(value_type)) unsigned char m_data[sizeof(value_type)] = {}; - //ensure no false sharing with following data - char cachline_padding[cacheline_size - (sizeof(m_data) + sizeof(m_turn))]; - public: - slot() = default; - slot(const slot& s); - slot(slot&& s); - ~slot(); - template - void construct(Args&&... args); - void destruct(); - - const_reference get()const&; - reference get()&; - rvalue_reference get()&&; - std::atomic& turn(); - const std::atomic& turn()const; - }; - - private: - std::vector m_slots; - //keep head and tail on separate cache lines to prevent thread thrashing - alignas(cacheline_size) std::atomic m_head; - alignas(cacheline_size) std::atomic m_tail; - - public: - explicit mpmc_ring_buffer(size_type capacity); - //copy/move NOT thread safe! requires external locking mechanism! - mpmc_ring_buffer(const mpmc_ring_buffer& m); - constexpr mpmc_ring_buffer(mpmc_ring_buffer&& m); - ~mpmc_ring_buffer() = default; - mpmc_ring_buffer& operator=(const mpmc_ring_buffer& m); - constexpr mpmc_ring_buffer& operator=(mpmc_ring_buffer&& m); - - //NOT thread safe! requires external locking mechanism! - void resize(size_type newcap); - //NOT thread safe! requires external locking mechanism! - void clear(); - - template - void emplace(Args&&... args); - template - bool try_emplace(Args&&... args); - - void push(const_reference t); - void push(rvalue_reference t); - bool try_push(const_reference t); - bool try_push(rvalue_reference t); - - void pop(reference t); - bool try_pop(reference t); - private: - constexpr size_type rotation_cnt(size_type t); - }; - -} - -#include "ring_buffer.tpp" - -#endif diff --git a/include/util/ring_buffer.tpp b/include/util/ring_buffer.tpp deleted file mode 100644 index d8aa67b..0000000 --- a/include/util/ring_buffer.tpp +++ /dev/null @@ -1,217 +0,0 @@ -/** - This file is a part of our_dick - Copyright (C) 2020 rexy712 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -#ifndef OUR_DICK_UTIL_RING_BUFFER_TPP -#define OUR_DICK_UTIL_RING_BUFFER_TPP - -#include //forward, move -#include //memory_order, atomic -#include //memcpy - -namespace util{ - template - mpmc_ring_buffer::slot::slot(const slot& s): - m_turn(s.m_turn.load(std::memory_order_acquire)) - { - memcpy(m_data, s.m_data, sizeof(s.m_data)); - } - template - mpmc_ring_buffer::slot::slot(slot&& s): - m_turn(s.m_turn.load(std::memory_order_acquire)) - { - memcpy(m_data, s.m_data, sizeof(s.m_data)); - } - template - mpmc_ring_buffer::slot::~slot(){ - if(m_turn & active_bit){ - destruct(); - } - } - template - template - void mpmc_ring_buffer::slot::construct(Args&&... args){ - new (&m_data) value_type(std::forward(args)...); - } - template - void mpmc_ring_buffer::slot::destruct(){ - reinterpret_cast(&m_data)->~value_type(); - } - - template - auto mpmc_ring_buffer::slot::get()const& -> const_reference{ - return reinterpret_cast(m_data); - } - template - auto mpmc_ring_buffer::slot::get()& -> reference{ - return reinterpret_cast(m_data); - } - template - auto mpmc_ring_buffer::slot::get()&& -> rvalue_reference{ - return std::move(reinterpret_cast(m_data)); - } - template - auto mpmc_ring_buffer::slot::turn() -> std::atomic&{ - return m_turn; - } - template - auto mpmc_ring_buffer::slot::turn()const -> const std::atomic&{ - return m_turn; - } - - template - mpmc_ring_buffer::mpmc_ring_buffer(size_type capacity): - m_slots(capacity), - m_head(0), - m_tail(0){} - - template - mpmc_ring_buffer::mpmc_ring_buffer(const mpmc_ring_buffer& m): - m_slots(m.m_slots), - m_head(m.m_head.load()), - m_tail(m.m_tail.load()){} - template - constexpr mpmc_ring_buffer::mpmc_ring_buffer(mpmc_ring_buffer&& m): - m_slots(std::move(m.m_slots)), - m_head(m.m_head.load()), - m_tail(m.m_tail.load()){} - template - mpmc_ring_buffer& mpmc_ring_buffer::operator=(const mpmc_ring_buffer& m){ - return (*this = mpmc_ring_buffer(m)); - } - template - constexpr mpmc_ring_buffer& mpmc_ring_buffer::operator=(mpmc_ring_buffer&& m){ - std::swap(m_slots, m.m_slots); - m_head = m.m_head.load(); - m_tail = m.m_tail.load(); - return *this; - } - - template - void mpmc_ring_buffer::resize(size_type newcap){ - mpmc_ring_buffer tmp(newcap); - size_type max = (m_head - m_tail) < newcap ? (m_head - m_tail) : newcap; - for(size_type i = m_tail, j = 0;j < max;++i, ++j){ - tmp.m_slots[j].get() = std::move(m_slots[i % m_slots.capacity()].get()); - tmp.m_slots[j].turn() |= 1; //in-use bit - } - tmp.m_head = max; - tmp.m_tail = 0; - *this = std::move(tmp); - } - template - void mpmc_ring_buffer::clear(){ - size_type head = m_head.load(std::memory_order_acquire); - for(size_type i = m_tail;i < head;++i){ - m_slots[i].destruct(); - m_slots[i].turn().store(0, std::memory_order_release); - } - m_head.store(0, std::memory_order_release); - m_tail.store(0, std::memory_order_release); - } - template - template - void mpmc_ring_buffer::emplace(Args&&... args){ - const size_type head = m_head.fetch_add(1, std::memory_order_seq_cst); - slot& s = m_slots[head % m_slots.capacity()]; - //lsb is in-use flag. wait for it to be 0 - while(rotation_cnt(head) << 1 != s.turn().load(std::memory_order_acquire)); - - s.construct(std::forward(args)...); - //set in-use flag - s.turn().store((rotation_cnt(head) << 1) + 1, std::memory_order_release); - } - template - template - bool mpmc_ring_buffer::try_emplace(Args&&... args){ - size_type head = m_head.load(std::memory_order_acquire); - while(1){ - slot& s = m_slots[head % m_slots.capacity()]; - if((rotation_cnt(head) << 1) == s.turn().load(std::memory_order_acquire)){ - if(m_head.compare_exchange_strong(head, head+1, std::memory_order_seq_cst)){ - s.construct(std::forward(args)...); - s.turn().store((rotation_cnt(head) << 1) + 1, std::memory_order_release); - return true; - } - }else{ - const size_type prev_head = head; - head = m_head.load(std::memory_order_acquire); - if(head == prev_head) - return false; - } - } - } - - template - void mpmc_ring_buffer::push(const_reference t){ - emplace(t); - } - template - bool mpmc_ring_buffer::try_push(const_reference t){ - return try_emplace(t); - } - template - void mpmc_ring_buffer::push(rvalue_reference t){ - emplace(std::move(t)); - } - template - bool mpmc_ring_buffer::try_push(rvalue_reference t){ - return try_emplace(std::move(t)); - } - - template - void mpmc_ring_buffer::pop(reference t){ - const size_type tail = m_tail.fetch_add(1, std::memory_order_seq_cst); - slot& s = m_slots[tail % m_slots.capacity()]; - - //lsb is in-use flag. wait for it to be 1 - while((rotation_cnt(tail) << 1) + 1 != s.turn().load(std::memory_order_acquire)); - - t = std::move(s).get(); - s.destruct(); - s.turn().store((rotation_cnt(tail) << 1) + 2, std::memory_order_release); - } - template - bool mpmc_ring_buffer::try_pop(reference t){ - size_type tail = m_tail.load(std::memory_order_acquire); - while(1){ - slot& s = m_slots[tail % m_slots.capacity()]; - if((rotation_cnt(tail) << 1) + 1 == s.turn().load(std::memory_order_acquire)){ - if(m_tail.compare_exchange_strong(tail, tail+1, std::memory_order_seq_cst)){ - t = std::move(s).get(); - s.destruct(); - s.turn().store((rotation_cnt(tail) << 1) + 2, std::memory_order_release); - return true; - } - }else{ - //if the tail hasn't moved, then we're still waiting on producer. - //if it has moved, another consumer took our data. try again. - const size_type prev_tail = tail; - tail = m_tail.load(std::memory_order_acquire); - if(tail == prev_tail) - return false; - } - } - } - template - constexpr auto mpmc_ring_buffer::rotation_cnt(size_type t) -> size_type{ - return (t / m_slots.capacity()); - } - -} - -#endif diff --git a/include/util/sequence.hpp b/include/util/sequence.hpp deleted file mode 100644 index 4ee947d..0000000 --- a/include/util/sequence.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/** - This file is a part of our_dick - Copyright (C) 2020 rexy712 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -#ifndef OUR_DICK_SEQUENCE_HPP -#define OUR_DICK_SEQUENCE_HPP - -#include //integer_sequence - -namespace util{ - //generate an integer sequence counting up from 0. eg 0,1,2,3... - template - struct sequence_gen{ - using type = typename sequence_gen::type; - }; - template - struct sequence_gen<0,Is...>{ - using type = std::integer_sequence; - }; - -} - -#endif diff --git a/makefile b/makefile index d44b5bf..0a7ac8d 100644 --- a/makefile +++ b/makefile @@ -26,7 +26,7 @@ DEPDIR::=$(OBJDIR)/dep LIBDIRS::=lib INCLUDE_DIRS::=include CFLAGS::=-std=c18 -Wall -pedantic -Wextra -CXXFLAGS::=-std=c++17 -Wall -pedantic -Wextra -fno-rtti -fno-exceptions +CXXFLAGS::=-std=c++20 -Wall -pedantic -Wextra -fno-rtti -fno-exceptions DEBUG_CFLAGS::= DEBUG_CXXFLAGS::=-DOUR_DICK_DEBUG=2 EXT::=cpp @@ -41,7 +41,7 @@ ifneq ($(WINDOWS),1) #*nix settings CC::=gcc CXX::=g++ - LDLIBS::=-lglfw -lglad -ldl -lm -lportaudio -lsndfile -lpthread + LDLIBS::=-lglfw -lglad -ldl -lm -lportaudio -lsndfile -lpthread -lrexy ifeq ($(shell uname -s),Linux) LDLIBS+=-lasound endif diff --git a/src/board.cpp b/src/board.cpp new file mode 100644 index 0000000..a515cbc --- /dev/null +++ b/src/board.cpp @@ -0,0 +1,209 @@ +/** + This file is a part of our_dick + Copyright (C) 2021rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +#include "board.hpp" +#include "math/mat.hpp" + +#include "graphics/gl_include.hpp" //GLfloat + + +gfx::unified_mesh square_mesh(const gfx::material& blank, const gfx::material& o, const gfx::material& x){ + static constexpr gfx::vertex s_vertices[] = { + {{-1.0f, 1.0f, 0.0f}, {}, {0.0f, 1.0f}}, + {{-1.0f, -1.0f, 0.0f}, {}, {0.0f, 0.0f}}, + {{ 1.0f, -1.0f, 0.0f}, {}, {1.0f, 0.0f}}, + {{ 1.0f, -1.0f, 0.0f}, {}, {1.0f, 0.0f}}, + {{ 1.0f, 1.0f, 0.0f}, {}, {1.0f, 1.0f}}, + {{-1.0f, 1.0f, 0.0f}, {}, {0.0f, 1.0f}} + }; + const gfx::material* mats[] = {&blank, &o, &x}; + + return gfx::unified_mesh{{s_vertices, sizeof(s_vertices) / sizeof(s_vertices[0])}, {mats, sizeof(mats) / sizeof(mats[0])}}; +} + + +tile::tile(gfx::model* model): + m_model(model){} + +void tile::set_value(value t){ + m_active_value = t; +} +auto tile::get_value()const -> value{ + return m_active_value; +} +void tile::set_color(const math::vec4& color){ + m_color_filter = color; +} + +void tile::render(gfx::shader_program& shader){ + shader.set_uniform("model_color", m_color_filter); + shader.set_uniform("texture1", *m_model->mesh(0).material().get_material((int)m_active_value)); + m_model->mesh(0).vertex().render(shader); +} + +board::board(egn::resource_manager& resman): + m_tiles(nullptr) +{ + gfx::material* blank, *o, *x; + gfx::model* sq; + blank = resman.emplace_material("assets/images/blank.jpg", egn::deferred_image("assets/images/blank.jpg", true)).first; + o = resman.emplace_material("assets/images/o.jpg", egn::deferred_image("assets/images/o.jpg", true)).first; + x = resman.emplace_material("assets/images/x.jpg", egn::deferred_image("assets/images/x.jpg", true)).first; + x = resman.emplace_material("assets/images/x.jpg", egn::deferred_image("assets/images/x.jpg", true)).first; + + if(!resman.has_model("square")){ + sq = resman.emplace_model("square", square_mesh(*blank, *o, *x)).first; + }else{ + sq = resman.get_model("square"); + } + + + + m_tiles.reset(new tile[9]{sq, sq, sq, sq, sq, sq, sq, sq, sq}); + + m_tiles[0].set_position({-2.125, 2.125, -1}); + m_tiles[1].set_position({-2.125, 0, -1}); + m_tiles[2].set_position({-2.125, -2.125, -1}); + m_tiles[3].set_position({ 0, 2.125, -1}); + m_tiles[4].set_position({ 0, 0, -1}); + m_tiles[5].set_position({ 0, -2.125, -1}); + m_tiles[6].set_position({ 2.125, 2.125, -1}); + m_tiles[7].set_position({ 2.125, 0, -1}); + m_tiles[8].set_position({ 2.125, -2.125, -1}); + +} + +void board::render(gfx::shader_program& shader){ + for(int i = 0;i < 9;++i){ + shader.set_uniform("model_mat", model_matrix() * m_tiles[i].model_matrix()); + m_tiles[i].render(shader); + } +} + +bool board::is_full(void)const{ + for(size_t i = 0;i < 9;++i){ + if(m_tiles[i].get_value() == tile::value::BLANK) + return false; + } + return true; +} + +int board::click_collision_cheat(const math::vec3& unproj_3)const{ + math::vec4 unproj_4 = {unproj_3[0], unproj_3[1], unproj_3[2], 1}; + math::vec4 mod_coord = model_matrix().inverse() * unproj_4; + mod_coord /= mod_coord[3]; + math::vec3 projected1 = {mod_coord[0], mod_coord[1], mod_coord[2]}; + + for(size_t i = 0;i < 9;++i){ + tile& sq = m_tiles[i]; + const math::vec3& sq_pos = sq.position(); + if((projected1.x() > (sq_pos.x() - 1.0f) && projected1.x() < (sq_pos.x() + 1.0f)) && + (projected1.y() > (sq_pos.y() - 1.0f) && projected1.y() < (sq_pos.y() + 1.0f))) + { + debug_print_succ("Clicked on square %lu\n", i); + return i; + } + } + return -1; +} + +void board::set_tile(int index, tile::value value){ + m_tiles[index].set_value(value); +} +tile::value board::get_tile(int index)const{ + return m_tiles[index].get_value(); +} + +tile::value board::check_winner(void)const{ + if(auto val = check_rows_();val != tile::value::BLANK) + return val; + if(auto val = check_columns_();val != tile::value::BLANK) + return val; + if(auto val = check_diagonals_();val != tile::value::BLANK) + return val; + + return tile::value::BLANK; +} +tile::value board::check_columns_(void)const{ + for(int i = 0;i < 3;++i){ + bool valid = true; + auto& start_sq = m_tiles[i*3]; + if(start_sq.get_value() == tile::value::BLANK) + continue; + + for(int l = 1;l < 3;++l){ + auto& cur_sq = m_tiles[i*3 + l]; + if(cur_sq.get_value() != start_sq.get_value()){ + valid = false; + break; + } + } + if(valid) + return start_sq.get_value(); + } + return tile::value::BLANK; +} +tile::value board::check_rows_(void)const{ + + for(int i = 0;i < 3;++i){ + bool valid = true; + auto& start_sq = m_tiles[i]; + if(start_sq.get_value() == tile::value::BLANK) + continue; + + for(int l = 1;l < 3;++l){ + auto& cur_sq = m_tiles[i + l*3]; + if(cur_sq.get_value() != start_sq.get_value()){ + valid = false; + break; + } + } + if(valid) + return start_sq.get_value(); + } + return tile::value::BLANK; +} +tile::value board::check_diagonals_(void)const{ + for(int i = 0;i < 2;++i){ + //check diagonals + int offset = 0; + int stride = 4; + for(int k = 0;k < 2;++k){ + bool valid = true; + auto& start_sq = m_tiles[offset]; + if(start_sq.get_value() == tile::value::BLANK){ + goto blank_continue; //bottom of loop + } + for(int l = 0;l < 3;++l){ + auto& cur_sq = m_tiles[l*stride + offset]; + if(cur_sq.get_value() != start_sq.get_value()){ + valid = false; + break; + } + } + if(valid) + return start_sq.get_value(); + + blank_continue: + offset = 2; + stride = 2; + } + } + return tile::value::BLANK; +} + diff --git a/src/engine/game.cpp b/src/engine/game.cpp index 39fa4b8..ccbf9d0 100644 --- a/src/engine/game.cpp +++ b/src/engine/game.cpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -91,6 +91,20 @@ namespace egn{ void game::on_notify(const game_state_event&){} + resource_manager& game::resource_man(void){ + return m_res_manager; + } + const resource_manager& game::resource_man(void)const{ + return m_res_manager; + } + void game::push_state(std::unique_ptr&& state){ + m_states_manager.push_state(std::move(state)); + } + void game::pop_state(void){ + m_states_manager.pop_state(); + } + + void game::setup_window_(){ glfwSetWindowUserPointer(m_window, this); glfwSetKeyCallback(m_window.raw(), handle_input_events); //TODO diff --git a/src/engine/game_state.cpp b/src/engine/game_state.cpp index db3c0e6..f047b6c 100644 --- a/src/engine/game_state.cpp +++ b/src/engine/game_state.cpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -69,7 +69,7 @@ namespace egn{ } - game_state_iface::game_state_iface(game_state_manager* owner): + game_state_iface::game_state_iface(game* owner): m_owner(owner){} } diff --git a/src/graphics/image.cpp b/src/engine/image.cpp similarity index 78% rename from src/graphics/image.cpp rename to src/engine/image.cpp index 5168df2..7515e8d 100644 --- a/src/graphics/image.cpp +++ b/src/engine/image.cpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -16,13 +16,13 @@ along with this program. If not, see . */ -#include "graphics/image.hpp" -#include "graphics/stb_include.hpp" +#include "engine/image.hpp" +#include "engine/stb_include.hpp" #include "config.hpp" #include //memcpy #include //exchange -namespace gfx{ +namespace egn{ image::image(const char* file, bool flip, int req_chan){ stbi_set_flip_vertically_on_load(flip); @@ -79,4 +79,20 @@ namespace gfx{ return m_data; } + + deferred_image::deferred_image(const char* file, bool flip, int req_chan): + m_filename(file), + m_flip(flip), + m_req_chan(req_chan){} + deferred_image::deferred_image(const std::string& file, bool flip, int req_chan): + m_filename(file), + m_flip(flip), + m_req_chan(req_chan){} + + deferred_image::operator image(void)const{ + return get_image(); + } + image deferred_image::get_image(void)const{ + return image(m_filename.c_str(), m_flip, m_req_chan); + } } diff --git a/src/engine/object.cpp b/src/engine/object.cpp index 24efe26..f9fa053 100644 --- a/src/engine/object.cpp +++ b/src/engine/object.cpp @@ -18,7 +18,6 @@ #include "engine/object.hpp" #include "config.hpp" -#include "util/minmax.hpp" namespace egn{ diff --git a/src/engine/resource_manager.cpp b/src/engine/resource_manager.cpp new file mode 100644 index 0000000..ba88262 --- /dev/null +++ b/src/engine/resource_manager.cpp @@ -0,0 +1,47 @@ +/** + This file is a part of our_dick + Copyright (C) 2021 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +#include "engine/resource_manager.hpp" + +namespace egn{ + + bool resource_manager::has_material(const char* key)const{ + if(auto it = m_textures.find(key);it != m_textures.end()) + return true; + return false; + } + + gfx::material* resource_manager::get_material(const char* file){ + if(auto it = m_textures.find(file);it != m_textures.end()) + return &(*it).second; + return nullptr; + } + + + bool resource_manager::has_model(const char* key)const{ + if(auto it = m_models.find(key);it != m_models.end()) + return true; + return false; + } + gfx::model* resource_manager::get_model(const char* file){ + if(auto it = m_models.find(file);it != m_models.end()) + return &(*it).second; + return nullptr; + } + +} diff --git a/src/graphics/stb.cpp b/src/engine/stb.cpp similarity index 96% rename from src/graphics/stb.cpp rename to src/engine/stb.cpp index 02827a7..7c402c6 100644 --- a/src/graphics/stb.cpp +++ b/src/engine/stb.cpp @@ -18,7 +18,7 @@ #define STB_IMAGE_IMPLEMENTATION -#include "graphics/stb_alloc.hpp" +#include "engine/stb_alloc.hpp" #define STBI_MALLOC(size) our_dick_stb_malloc(size) #define STBI_FREE(data) our_dick_stb_free(data) diff --git a/src/graphics/stb_alloc.cpp b/src/engine/stb_alloc.cpp similarity index 97% rename from src/graphics/stb_alloc.cpp rename to src/engine/stb_alloc.cpp index 3ca3e49..7867435 100644 --- a/src/graphics/stb_alloc.cpp +++ b/src/engine/stb_alloc.cpp @@ -16,7 +16,7 @@ along with this program. If not, see . */ -#include "graphics/stb_alloc.hpp" +#include "engine/stb_alloc.hpp" #include //size_t #include //new, delete diff --git a/src/graphics/texture.cpp b/src/graphics/texture.cpp index 6733d66..68ff2cd 100644 --- a/src/graphics/texture.cpp +++ b/src/graphics/texture.cpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -23,7 +23,8 @@ namespace gfx{ - static bool is_format_compatible(GLenum format, int channel_count){ + [[maybe_unused]] + static constexpr bool is_format_compatible(GLenum format, int channel_count){ switch(channel_count){ case 1: return format == GL_RED; @@ -36,6 +37,34 @@ namespace gfx{ }; return false; } + [[maybe_unused]] + static constexpr GLenum convert_channel_to_format(int channels){ + switch(channels){ + case 1: + return GL_RED; + case 2: + return GL_RG; + case 3: + return GL_RGB; + case 4: + return GL_RGBA; + }; + return GL_RED; + } + [[maybe_unused]] + static constexpr GLenum convert_format_to_channel(int channels){ + switch(channels){ + case GL_RED: + return 1; + case GL_RG: + return 2; + case GL_RGB: + return 3; + case GL_RGBA: + return 4; + }; + return 1; + } @@ -71,7 +100,12 @@ namespace gfx{ } texture::texture(GLenum format, GLsizei w, GLsizei h, GLenum type): texture(nullptr, format, w, h, type){} - texture::texture(const image& i): + texture::texture(const egn::image& i): + texture() + { + set_image(i); + } + texture::texture(const egn::deferred_image& i): texture() { set_image(i); @@ -90,46 +124,48 @@ namespace gfx{ return m_tex_id; } - bool texture::set_image(const image& i){ - if(!i){ + bool texture::set_image(const unsigned char* data, GLenum format, GLsizei w, GLsizei h, GLenum type){ + if(!data){ debug_print_error("Image is invalid\n"); return false; } - - if(m_width != i.get_width() || m_height != i.get_height() || !is_format_compatible(m_format, i.get_channels())){ + if(m_width != w || m_height != h || m_format != format){ if(m_format != 0){ debug_print_warn("Regenerating texture\n"); glDeleteTextures(1, &m_tex_id); glCreateTextures(GL_TEXTURE_2D, 1, &m_tex_id); } - m_width = i.get_width(); - m_height = i.get_height(); - switch(i.get_channels()){ - case 1: - m_format = GL_RED; + m_width = w; + m_height = h; + switch(format){ + case GL_RED: glTextureStorage2D(m_tex_id, 1, GL_R8, m_width, m_height); break; - case 2: - m_format = GL_RG; + case GL_RG: glTextureStorage2D(m_tex_id, 1, GL_RG8, m_width, m_height); break; - case 3: - m_format = GL_RGB; + case GL_RGB: glTextureStorage2D(m_tex_id, 1, GL_RGB8, m_width, m_height); break; - case 4: - m_format = GL_RGBA; + case GL_RGBA: glTextureStorage2D(m_tex_id, 1, GL_RGBA8, m_width, m_height); break; default: debug_print_error("Invalid format for texture\n"); return false; }; + m_format = format; } - glTextureSubImage2D(m_tex_id, 0, 0, 0, m_width, m_height, m_format, GL_UNSIGNED_BYTE, i.data()); + glTextureSubImage2D(m_tex_id, 0, 0, 0, m_width, m_height, m_format, type, data); glGenerateTextureMipmap(m_tex_id); return true; } + bool texture::set_image(const egn::image& i){ + return set_image(i.data(), convert_channel_to_format(i.get_channels()), i.get_width(), i.get_height(), GL_UNSIGNED_BYTE); + } + bool texture::set_image(const egn::deferred_image& i){ + return set_image(i.get_image()); + } void texture::set_wrap_mode(wrap w){ glTextureParameteri(m_tex_id, GL_TEXTURE_WRAP_S, static_cast(w)); diff --git a/src/graphics/vbo.cpp b/src/graphics/vbo.cpp index a1ce5b9..084ad4b 100644 --- a/src/graphics/vbo.cpp +++ b/src/graphics/vbo.cpp @@ -17,9 +17,9 @@ */ #include "graphics/vbo.hpp" -#include "util/minmax.hpp" #include "config.hpp" +#include #include //exchange, swap, move namespace gfx{ @@ -68,7 +68,7 @@ namespace gfx{ bool vbo::buffer(const void* data, size_t datasize){ if(datasize + m_buffer_size > get_cap()){ - if(!resize(util::max(datasize + m_buffer_size, get_cap() * 2))) + if(!resize(rexy::max(datasize + m_buffer_size, get_cap() * 2))) return false; } glNamedBufferSubData(m_buffer, get_size(), datasize, data); @@ -107,7 +107,7 @@ namespace gfx{ } bool vbo::copy_buffer(vbo& dest, const vbo& src){ - size_t bytes = util::min(dest.get_cap(), src.get_size()); + size_t bytes = rexy::min(dest.get_cap(), src.get_size()); scoped_vbo_map data(src.m_buffer, maptype::READ); if(!data.valid()) return false; diff --git a/src/graphics/window.cpp b/src/graphics/window.cpp index 577a6f5..fe1a2e0 100644 --- a/src/graphics/window.cpp +++ b/src/graphics/window.cpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -139,12 +139,16 @@ static void enable_opengl_debug_context(){ } return false; } + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-truncation" static char* copy_title(const char* src, size_t titlelen){ char* dest = new char[titlelen + 1]; strncpy(dest, src, titlelen); dest[titlelen] = 0; return dest; } +#pragma GCC diagnostic pop window::window(int width, int height, const char* title, bool makecurrent): window(s_default_cver_maj, s_default_cver_min, width, height, title, makecurrent){} diff --git a/src/pause_state.cpp b/src/pause_state.cpp index 7b0796a..489e8a1 100644 --- a/src/pause_state.cpp +++ b/src/pause_state.cpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -17,12 +17,13 @@ */ #include "pause_state.hpp" +#include "engine/game.hpp" #include "graphics/gl_include.hpp" //TODO #include "config.hpp" -pause_state::pause_state(egn::game_state_manager& owner, egn::game_state_iface* under): +pause_state::pause_state(egn::game& owner, egn::game_state_iface* under): game_state_iface(&owner), m_under_state(under){} @@ -35,7 +36,7 @@ void pause_state::handle_input(const egn::input_event& event){ m_owner->pop_state(); return; }else if(event.key == GLFW_KEY_ESCAPE && !event.mods && event.action == GLFW_PRESS){ - m_owner->notify({egn::game_state_event::state_type::SHOULD_CLOSE, 0, 0}); + m_owner->on_notify({egn::game_state_event::state_type::SHOULD_CLOSE, 0, 0}); } }else if(event.ev_type == egn::input_event::type::RESIZE){ m_under_state->handle_input(event); diff --git a/src/play_state.cpp b/src/play_state.cpp index 7688591..a205d2e 100644 --- a/src/play_state.cpp +++ b/src/play_state.cpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -21,39 +21,22 @@ #include #include "pause_state.hpp" #include "graphics/gl_include.hpp" //TODO: separate key definitions from GLFW -#include "graphics/image.hpp" //TODO: move image to engine namespace +#include "engine/image.hpp" //TODO: move image to engine namespace #include "math/math.hpp" -#include "square.hpp" #include "config.hpp" +#include "engine/game.hpp" +#include "board.hpp" -play_state::play_state(egn::game_state_manager& owner, int width, int height): +play_state::play_state(egn::game& owner, int width, int height): game_state_iface(&owner), m_sprite_renderer(width, height), m_screen_renderer(width, height, m_sprite_renderer.color_buffer()), m_current_player(rand() % 2) { debug_print("First player chosen is %c\n", m_current_player ? 'X' : 'O'); - m_scene.textures.emplace_back(gfx::image("assets/images/blank.jpg", true)); - m_scene.textures.emplace_back(gfx::image("assets/images/o.jpg", true)); - m_scene.textures.emplace_back(gfx::image("assets/images/x.jpg", true)); - m_scene.models.emplace_back(new gfx::model{gfx::unified_mesh(square_mesh(m_scene.textures[0], - m_scene.textures[1], - m_scene.textures[2]))}); - gfx::model& sm = *m_scene.models[0]; - for(int i = 0;i < 9;++i){ - m_scene.objects.emplace_back(new square(&sm)); - m_scene.renderables.emplace_back(static_cast(m_scene.objects[i].get())); - } - m_scene.objects[0]->set_position({-2, 2, -1}); - m_scene.objects[1]->set_position({-2, 0, -1}); - m_scene.objects[2]->set_position({-2, -2, -1}); - m_scene.objects[3]->set_position({ 0, 2, -1}); - m_scene.objects[4]->set_position({ 0, 0, -1}); - m_scene.objects[5]->set_position({ 0, -2, -1}); - m_scene.objects[6]->set_position({ 2, 2, -1}); - m_scene.objects[7]->set_position({ 2, 0, -1}); - m_scene.objects[8]->set_position({ 2, -2, -1}); + m_scene.objects.emplace_back(new board(m_owner->resource_man())); + m_scene.renderables.emplace_back(static_cast(m_scene.objects[0].get())); m_scene.cameras.emplace_back(new egn::ortho_camera(10 * ((float)width / height), 10, 0.1, 50)); m_main_camera = static_cast(m_scene.cameras[0].get()); @@ -71,7 +54,7 @@ void play_state::handle_input(const egn::input_event& ev){ m_owner->push_state(std::unique_ptr(new pause_state(*m_owner, this))); return; }else if(ev.key == GLFW_KEY_ESCAPE && !ev.mods && ev.action == GLFW_PRESS){ - m_owner->notify({egn::game_state_event::state_type::SHOULD_CLOSE, 0, 0}); + m_owner->on_notify({egn::game_state_event::state_type::SHOULD_CLOSE, 0, 0}); } }else if(ev.ev_type == egn::input_event::type::RESIZE){ if(ev.x > ev.y){ @@ -96,87 +79,27 @@ void play_state::handle_input(const egn::input_event& ev){ debug_print("projected click vector: (%f, %f, %f)\n", projected1.x(), projected1.y(), projected1.z()); - for(size_t i = 0;i < m_scene.objects.size();++i){ - square& sq = static_cast(*m_scene.objects[i]); - const math::vec3& sq_pos = sq.position(); - if((projected1.x() > (sq_pos.x() - 1.0f) && projected1.x() < (sq_pos.x() + 1.0f)) && - (projected1.y() > (sq_pos.y() - 1.0f) && projected1.y() < (sq_pos.y() + 1.0f))) - { - debug_print_succ("Clicked on square %lu\n", i); - if(sq.get_value() == square::value::BLANK){ - sq.set_value(((++m_current_player) %= 2) ? square::value::O : square::value::X); - } - break; - } + board& b = static_cast(*m_scene.objects[0]); + int index = b.click_collision_cheat(projected1); + + if(index >= 0 && b.get_tile(index) == tile::value::BLANK) + b.set_tile(index, (++m_current_player %= 2) ? tile::value::O : tile::value::X); + + tile::value winner = b.check_winner(); + if(winner != tile::value::BLANK){ + printf("Winner is %c\n", winner == tile::value::O ? 'O' : 'X'); + m_owner->on_notify({egn::game_state_event::state_type::SHOULD_CLOSE, 0, 0}); + }else if(b.is_full()){ + printf("Game is a tie\n"); + m_owner->on_notify({egn::game_state_event::state_type::SHOULD_CLOSE, 0, 0}); } } } } void play_state::update(double time_diff){ - square::value winner = check_win_condition_(); - if(winner != square::value::BLANK){ - printf("Winner is %c\n", winner == square::value::O ? 'O' : 'X'); - m_owner->notify({egn::game_state_event::state_type::SHOULD_CLOSE, 0, 0}); - }else if(is_board_full_()){ - printf("Game is a tie\n"); - m_owner->notify({egn::game_state_event::state_type::SHOULD_CLOSE, 0, 0}); - } } void play_state::render(){ m_sprite_renderer.set_vp_matrix(m_main_camera->get_projection_matrix() * m_main_camera->get_view_matrix()); m_sprite_renderer.render(m_scene); m_screen_renderer.render(m_scene); } - -square::value play_state::check_win_condition_(){ - square::value v = square::value::O; - for(int i = 0;i < 2;++i){ - for(int j = 0;j < 3;++j){ - //check columns - bool valid = true; - for(int l = 0;l < 3;++l){ - if(static_cast(*m_scene.objects[j*3 + l]).get_value() != v){ - valid = false; - break; - } - } - if(valid) - return v; - //check rows - valid = true; - for(int l = 0;l < 3;++l){ - if(static_cast(*m_scene.objects[j + l*3]).get_value() != v){ - valid = false; - break; - } - } - if(valid) - return v; - } - //check diagonals - int offset = 0; - int stride = 4; - for(int k = 0;k < 2;++k){ - bool valid = true; - for(int l = 0;l < 3;++l){ - if(static_cast(*m_scene.objects[l * stride + offset]).get_value() != v){ - valid = false; - break; - } - } - if(valid) - return v; - offset = 2; - stride = 2; - } - v = square::value::X; - } - return square::value::BLANK; -} -bool play_state::is_board_full_(){ - for(size_t i = 0;i < m_scene.objects.size();++i){ - if(static_cast(*m_scene.objects[i]).get_value() == square::value::BLANK) - return false; - } - return true; -} diff --git a/src/square.cpp b/src/square.cpp deleted file mode 100644 index d2433ed..0000000 --- a/src/square.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/** - This file is a part of our_dick - Copyright (C) 2020 rexy712 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -#include "square.hpp" -#include "graphics/gl_include.hpp" - -#include //swap - -gfx::unified_mesh square_mesh(const gfx::material& blank, const gfx::material& o, const gfx::material& x){ - static constexpr gfx::vertex s_vertices[] = { - {{-1.0f, 1.0f, 0.0f}, {}, {0.0f, 1.0f}}, - {{-1.0f, -1.0f, 0.0f}, {}, {0.0f, 0.0f}}, - {{ 1.0f, -1.0f, 0.0f}, {}, {1.0f, 0.0f}}, - {{ 1.0f, -1.0f, 0.0f}, {}, {1.0f, 0.0f}}, - {{ 1.0f, 1.0f, 0.0f}, {}, {1.0f, 1.0f}}, - {{-1.0f, 1.0f, 0.0f}, {}, {0.0f, 1.0f}} - }; - const gfx::material* mats[] = {&blank, &o, &x}; - - return gfx::unified_mesh{{s_vertices, sizeof(s_vertices) / sizeof(s_vertices[0])}, {mats, sizeof(mats) / sizeof(mats[0])}}; -} - - -square::square(gfx::model* model): - m_model(model){} - -void square::set_value(value t){ - m_active_value = t; -} -auto square::get_value()const -> value{ - return m_active_value; -} -void square::set_color(const math::vec4& color){ - m_color_filter = color; -} - -void square::render(gfx::shader_program& shader){ - shader.set_uniform("model_mat", model_matrix()); - shader.set_uniform("model_color", m_color_filter); - shader.set_uniform("texture1", *m_model->mesh(0).material().get_material((int)m_active_value)); - m_model->mesh(0).vertex().render(shader); -} - diff --git a/src/tic_tac_toe.cpp b/src/tic_tac_toe.cpp index a40bf5b..41e8db1 100644 --- a/src/tic_tac_toe.cpp +++ b/src/tic_tac_toe.cpp @@ -1,6 +1,6 @@ /** This file is a part of our_dick - Copyright (C) 2020 rexy712 + Copyright (C) 2020-2021 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -26,7 +26,7 @@ tic_tac_toe::tic_tac_toe(int width, int height): { m_window.make_current(); m_states_manager.add_observer(*this); - m_states_manager.push_state(std::unique_ptr(new play_state(m_states_manager, width, height))); + m_states_manager.push_state(std::unique_ptr(new play_state(*this, width, height))); } bool tic_tac_toe::is_game_over()const{