Add resource manager. Add tic tac toe board abstraction

This commit is contained in:
rexy712 2022-01-09 15:46:53 -08:00
parent 9a16c6ca69
commit 56e4599ea1
31 changed files with 557 additions and 679 deletions

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 <memory> //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<float> 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<tile[]> 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<GLfloat>&)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

View File

@ -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 <queue>
@ -33,6 +34,7 @@ namespace egn{
protected:
gfx::window m_window;
game_state_manager m_states_manager;
resource_manager m_res_manager;
std::queue<input_event> 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<game_state_iface>&&);
void pop_state(void);
private:
void setup_window_();
};

View File

@ -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;

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 <string>
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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 <map>
#include <utility> //pair, forward
namespace egn{
class resource_manager
{
private:
std::map<const char*,gfx::material> m_textures;
std::map<const char*,gfx::model> 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<class... Args>
std::pair<gfx::material*,bool> emplace_material(const char* key, Args&&... args);
gfx::material* get_material(const char* file);
bool has_model(const char* key)const;
template<class... Args>
std::pair<gfx::model*,bool> emplace_model(const char* key, Args&&... args);
gfx::model* get_model(const char* file);
};
template<class... Args>
std::pair<gfx::material*,bool> 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>(args)...);
return {&(*(ret.first)).second, true};
}
template<class... Args>
std::pair<gfx::model*,bool> 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>(args)...);
return {&(*(ret.first)).second, true};
}
}
#endif

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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<renderable_iface*> renderables;
std::vector<std::unique_ptr<egn::object_base>> objects;
std::vector<gfx::material> textures;
std::vector<std::unique_ptr<egn::camera_iface>> cameras;
std::vector<std::unique_ptr<gfx::model>> models;
};
#endif

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef OUR_DICK_UTIL_MINMAX_HPP
#define OUR_DICK_UTIL_MINMAX_HPP
//prevents inclusion of <algorithm> which triples compile times
namespace util{
template<typename T>
struct greater {
constexpr bool operator()(const T& left, const T& right)const{
return left > right;
}
};
template<typename T>
struct less {
constexpr bool operator()(const T& left, const T& right)const{
return left < right;
}
};
template<typename T, typename... Args>
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>(args)...) : max(right, std::forward<Args>(args)...);
}
return left > right ? left : right;
}
template<typename T, typename... Args>
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>(args)...) : min(right, std::forward<Args>(args)...);
}
return left < right ? left : right;
}
template<typename T, typename Compare>
static constexpr T maxc(const T& left, const T& right, Compare cmp){
return cmp(left, right) ? left : right;
}
template<typename T, typename Compare>
static constexpr T minc(const T& left, const T& right, Compare cmp){
return cmp(left, right) ? left : right;
}
}
#endif

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef OUR_DICK_UTIL_RING_BUFFER_HPP
#define OUR_DICK_UTIL_RING_BUFFER_HPP
#include <vector> //vector (duh)
#include <cstdlib> //size_t
#include <atomic> //atomic (duh)
#ifdef __cpp_lib_hardware_interference_size
#include <new> //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<typename T>
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<size_type> 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<typename... Args>
void construct(Args&&... args);
void destruct();
const_reference get()const&;
reference get()&;
rvalue_reference get()&&;
std::atomic<size_type>& turn();
const std::atomic<size_type>& turn()const;
};
private:
std::vector<slot> m_slots;
//keep head and tail on separate cache lines to prevent thread thrashing
alignas(cacheline_size) std::atomic<size_type> m_head;
alignas(cacheline_size) std::atomic<size_type> 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<typename... Args>
void emplace(Args&&... args);
template<typename... Args>
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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef OUR_DICK_UTIL_RING_BUFFER_TPP
#define OUR_DICK_UTIL_RING_BUFFER_TPP
#include <utility> //forward, move
#include <atomic> //memory_order, atomic
#include <cstring> //memcpy
namespace util{
template<typename T>
mpmc_ring_buffer<T>::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<typename T>
mpmc_ring_buffer<T>::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<typename T>
mpmc_ring_buffer<T>::slot::~slot(){
if(m_turn & active_bit){
destruct();
}
}
template<typename T>
template<typename... Args>
void mpmc_ring_buffer<T>::slot::construct(Args&&... args){
new (&m_data) value_type(std::forward<Args>(args)...);
}
template<typename T>
void mpmc_ring_buffer<T>::slot::destruct(){
reinterpret_cast<pointer>(&m_data)->~value_type();
}
template<typename T>
auto mpmc_ring_buffer<T>::slot::get()const& -> const_reference{
return reinterpret_cast<const_reference>(m_data);
}
template<typename T>
auto mpmc_ring_buffer<T>::slot::get()& -> reference{
return reinterpret_cast<reference>(m_data);
}
template<typename T>
auto mpmc_ring_buffer<T>::slot::get()&& -> rvalue_reference{
return std::move(reinterpret_cast<reference>(m_data));
}
template<typename T>
auto mpmc_ring_buffer<T>::slot::turn() -> std::atomic<size_type>&{
return m_turn;
}
template<typename T>
auto mpmc_ring_buffer<T>::slot::turn()const -> const std::atomic<size_type>&{
return m_turn;
}
template<typename T>
mpmc_ring_buffer<T>::mpmc_ring_buffer(size_type capacity):
m_slots(capacity),
m_head(0),
m_tail(0){}
template<typename T>
mpmc_ring_buffer<T>::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<typename T>
constexpr mpmc_ring_buffer<T>::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<typename T>
mpmc_ring_buffer<T>& mpmc_ring_buffer<T>::operator=(const mpmc_ring_buffer& m){
return (*this = mpmc_ring_buffer(m));
}
template<typename T>
constexpr mpmc_ring_buffer<T>& mpmc_ring_buffer<T>::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<typename T>
void mpmc_ring_buffer<T>::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<typename T>
void mpmc_ring_buffer<T>::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<typename T>
template<typename... Args>
void mpmc_ring_buffer<T>::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>(args)...);
//set in-use flag
s.turn().store((rotation_cnt(head) << 1) + 1, std::memory_order_release);
}
template<typename T>
template<typename... Args>
bool mpmc_ring_buffer<T>::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>(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<typename T>
void mpmc_ring_buffer<T>::push(const_reference t){
emplace(t);
}
template<typename T>
bool mpmc_ring_buffer<T>::try_push(const_reference t){
return try_emplace(t);
}
template<typename T>
void mpmc_ring_buffer<T>::push(rvalue_reference t){
emplace(std::move(t));
}
template<typename T>
bool mpmc_ring_buffer<T>::try_push(rvalue_reference t){
return try_emplace(std::move(t));
}
template<typename T>
void mpmc_ring_buffer<T>::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<typename T>
bool mpmc_ring_buffer<T>::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<typename T>
constexpr auto mpmc_ring_buffer<T>::rotation_cnt(size_type t) -> size_type{
return (t / m_slots.capacity());
}
}
#endif

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef OUR_DICK_SEQUENCE_HPP
#define OUR_DICK_SEQUENCE_HPP
#include <utility> //integer_sequence
namespace util{
//generate an integer sequence counting up from 0. eg 0,1,2,3...
template<int I, int... Is>
struct sequence_gen{
using type = typename sequence_gen<I-1, Is..., sizeof...(Is)>::type;
};
template<int... Is>
struct sequence_gen<0,Is...>{
using type = std::integer_sequence<int,Is...>;
};
}
#endif

View File

@ -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

209
src/board.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<float>& 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<GLfloat>& unproj_3)const{
math::vec4<GLfloat> unproj_4 = {unproj_3[0], unproj_3[1], unproj_3[2], 1};
math::vec4<GLfloat> mod_coord = model_matrix().inverse() * unproj_4;
mod_coord /= mod_coord[3];
math::vec3<GLfloat> 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<GLfloat>& 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;
}

View File

@ -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<game_state_iface>&& 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

View File

@ -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){}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "graphics/image.hpp"
#include "graphics/stb_include.hpp"
#include "engine/image.hpp"
#include "engine/stb_include.hpp"
#include "config.hpp"
#include <cstring> //memcpy
#include <utility> //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);
}
}

View File

@ -18,7 +18,6 @@
#include "engine/object.hpp"
#include "config.hpp"
#include "util/minmax.hpp"
namespace egn{

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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;
}
}

View File

@ -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)

View File

@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "graphics/stb_alloc.hpp"
#include "engine/stb_alloc.hpp"
#include <cstdlib> //size_t
#include <new> //new, delete

View File

@ -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<GLint>(w));

View File

@ -17,9 +17,9 @@
*/
#include "graphics/vbo.hpp"
#include "util/minmax.hpp"
#include "config.hpp"
#include <rexy/utility.hpp>
#include <utility> //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<void> data(src.m_buffer, maptype::READ);
if(!data.valid())
return false;

View File

@ -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){}

View File

@ -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);

View File

@ -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 <queue>
#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<square*>(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<board*>(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<egn::ortho_camera*>(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<game_state_iface>(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<square&>(*m_scene.objects[i]);
const math::vec3<GLfloat>& 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<board&>(*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<square&>(*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<square&>(*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<square&>(*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<square&>(*m_scene.objects[i]).get_value() == square::value::BLANK)
return false;
}
return true;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "square.hpp"
#include "graphics/gl_include.hpp"
#include <utility> //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<float>& 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);
}

View File

@ -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<egn::game_state_iface>(new play_state(m_states_manager, width, height)));
m_states_manager.push_state(std::unique_ptr<egn::game_state_iface>(new play_state(*this, width, height)));
}
bool tic_tac_toe::is_game_over()const{