diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2a14a608ced625ac1a1bcd11c3e85b904f63ba7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +*.vscode + +*.o +*.obj +*.pdb + +*.a +*.dll +*.so +*.lib + +*.exe +*.git + +build/* +include/* +library/* +vcpkg_installed/* +old/* \ No newline at end of file diff --git a/CMakelists.txt b/CMakelists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ed6f26854f3a98e2dde36014ec43ca2c8e08846 --- /dev/null +++ b/CMakelists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 3.1) + +#============================================================== +# Configuration +#============================================================== + +set(PROJECT_NAME "Main") +set(EXECUTABLE_NAME "Main") + +set(CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD ${CXX_STANDARD}) + +if (MSVC) + add_compile_options(/EHsc) +endif() + +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +#===================================== +# Options +#===================================== + +if(WIN32) + option(CMAKE_TOOLCHAIN_FILE "C:/vcpkg/vcpkg/scripts/buildsystems/vcpkg.cmake") +elseif(UNIX) + option(CMAKE_TOOLCHAIN_FILE "/usr/local/share/vcpkg/scripts/buildsystems/vcpkg.cmake") +endif() + +#============================================================== +# Sources +#============================================================== + +set(SOURCES ${CMAKE_SOURCE_DIR}/source/) +set(LIBRARY ${CMAKE_SOURCE_DIR}/library/) +set(INCLUDE ${CMAKE_SOURCE_DIR}/include/) + +set(VCPK_INCLUDE ${CMAKE_SOURCE_DIR}/vcpkg_installed/*/include) +set(VCPK_INCLUDE ${CMAKE_SOURCE_DIR}/vcpkg_installed/*/lib) + +#============================================================== +# Build +#============================================================== + +project(${PROJECT_NAME}) +set(CURRENT_TARGET ${EXECUTABLE_NAME}) + +add_executable(${CURRENT_TARGET}) + +foreach(dir ${SOURCES}) + add_subdirectory(${dir}) +endforeach() + +set_property(TARGET ${CURRENT_TARGET} PROPERTY RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_SOURCE_DIR}>) + +#============================================================== +# Linking +#============================================================== + +target_include_directories(${CURRENT_TARGET} PRIVATE ${INCLUDE}) + +find_package(glfw3 REQUIRED) +find_package(GLEW REQUIRED) +find_package(glm CONFIG REQUIRED) +find_package(imgui REQUIRED) + +target_link_libraries(${CURRENT_TARGET} PRIVATE glfw) +target_link_libraries(${CURRENT_TARGET} PRIVATE GLEW::GLEW) +target_link_libraries(${CURRENT_TARGET} PRIVATE glm::glm-header-only) +target_link_libraries(${CURRENT_TARGET} PRIVATE imgui::imgui) + diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b925f9599c0a4c7b81d6de1e36ee6083b330d0a9 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Projet FIG + +## Building + +Debug mode : +```shell +cmake --build ./build +``` + +Release Mode : +```shell +cmake --build ./build --config Release +``` \ No newline at end of file diff --git a/source/CMakelists.txt b/source/CMakelists.txt new file mode 100644 index 0000000000000000000000000000000000000000..9faf4ac20bb8965699410280cda601902e960170 --- /dev/null +++ b/source/CMakelists.txt @@ -0,0 +1,4 @@ +target_include_directories(${CURRENT_TARGET} PRIVATE .) + +file(GLOB_RECURSE SOURCE ./**.cpp) +target_sources(${CURRENT_TARGET} PRIVATE ${SOURCE}) \ No newline at end of file diff --git a/source/engine/graphics/back.hpp b/source/engine/graphics/back.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d04d031424ab0d33ac0f044542d0372b57cc6f4f --- /dev/null +++ b/source/engine/graphics/back.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "back/buffers/ElementBuffer.hpp" +#include "back/buffers/FrameBuffer.hpp" +#include "back/buffers/VerticeBuffer.hpp" +#include "back/buffers/VertexArray.hpp" +#include "back/buffers/UniformeBuffer.hpp" + +#include "back/cameras/Target.hpp" +#include "back/cameras/View.hpp" +#include "back/cameras/Walkaround.hpp" + +#include "back/geometry/Geometry.hpp" +#include "back/geometry/Transform.hpp" + +#include "back/shaders/Program.hpp" +#include "back/shaders/Source.hpp" +#include "back/shaders/UniformObject.hpp" + +#include "back/textures/Shared_Material.hpp" \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/Buffer.hpp b/source/engine/graphics/back/buffers/Buffer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f2577d116a20c3d54c5901ca35e152d9ba92fda3 --- /dev/null +++ b/source/engine/graphics/back/buffers/Buffer.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include <GL/glew.h> + +namespace megu { + class Buffer { + public: + virtual void bind() const = 0; + virtual void unbind() const = 0; + virtual GLuint identifier() const = 0; + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/DynamicBuffer-impl.cpp b/source/engine/graphics/back/buffers/DynamicBuffer-impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53e0cf00fa09463e50c15dca75049f22b450219b --- /dev/null +++ b/source/engine/graphics/back/buffers/DynamicBuffer-impl.cpp @@ -0,0 +1,6 @@ +#include "DynamicBuffer.cpp" + +namespace megu { + template class DynamicBuffer<float, GL_ARRAY_BUFFER>; + template class DynamicBuffer<unsigned int, GL_ELEMENT_ARRAY_BUFFER>; +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/DynamicBuffer.cpp b/source/engine/graphics/back/buffers/DynamicBuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9da1b1c1711f4e37c6772fe947a926e2e5baa4c --- /dev/null +++ b/source/engine/graphics/back/buffers/DynamicBuffer.cpp @@ -0,0 +1,256 @@ +#include "DynamicBuffer.hpp" + +#include <GL/glew.h> +#include <exception> +#include <stdexcept> + +#include <iostream> + +namespace megu { + template <typename T, uint32_t Y> + DynamicBuffer<T,Y>::DynamicBuffer(size_t size, size_t array_size) + : _max_size(size),_size(array_size) { + + } + + template <typename T, uint32_t Y> + size_t DynamicBuffer<T,Y>::size() const { + return this->_size; + } + + template <typename T, uint32_t Y> + size_t DynamicBuffer<T,Y>::max_size() const { + return this->_max_size; + } + + template <typename T, uint32_t Y> + size_t DynamicBuffer<T,Y>::memory_size() const { + return this->_size * sizeof(T); + } + + template <typename T, uint32_t Y> + size_t DynamicBuffer<T,Y>::max_memory_size() const { + return this->_max_size * sizeof(T); + } + + template <typename T, uint32_t Y> + bool DynamicBuffer<T,Y>::empty() const { + return this->_size == 0; + } + + template <typename T, uint32_t Y> + bool DynamicBuffer<T,Y>::full() const { + return this->_size == this->_max_size; + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::set(const std::vector<T> & vertices) { + this->_max_size = vertices.size(); + this->_size = vertices.size(); + this->generate(vertices); + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::insert(const std::vector<T> & vertices, size_t pos) { + if(this->_size + vertices.size() > this->_max_size) { + std::vector<T> data = this->extract(); + data.insert(data.begin() + pos, vertices.begin(), vertices.end()); + this->set(data); + } + else { + if(this->identifier() != 0) { + this->bind(); + uint8_t * writer = static_cast<uint8_t *>(glMapBuffer(Y, GL_READ_WRITE)); + + if(pos < this->_size) { + memmove(writer + ((pos + vertices.size()) * sizeof(T)), writer + (pos * sizeof(T)), (this->_size-pos) * sizeof(T)); + } + memmove(writer + (pos * sizeof(T)), std::vector<T>(vertices).data(), vertices.size() * sizeof(T)); + glUnmapBuffer(Y); + + this->_size += vertices.size(); + + } + else { + this->generate(vertices); + } + } + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::replace(const std::vector<T> & vertices, size_t pos) { + if(this->empty()) { + throw std::range_error("Buffer is empty."); + } + + if(pos + vertices.size() > this->_size) { + throw std::overflow_error("Cannot replace datas out of buffer."); + } + + this->bind(); + glBufferSubData(Y, pos * sizeof(T),vertices.size() * sizeof(T), std::vector<T>(vertices).data()); + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::erase(size_t from, size_t to) { + if(this->empty()) { + throw std::range_error("Buffer is empty."); + } + + if(this->_size - to - from < 0) { + throw std::underflow_error("Cannot erase datas out of buffer."); + } + + this->bind(); + + uint8_t * writer = static_cast<uint8_t *>(glMapBuffer(Y, GL_READ_WRITE)); + memmove(writer + (from * sizeof(T)), writer + ((to+1) * sizeof(T)), (this->_size-to) * sizeof(T)); + glUnmapBuffer(Y); + + this->_size -= (to + 1 - from); + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::merge(const DynamicBuffer<T,Y> & vbo, size_t pos) { + if(this->_size + vbo._size > this->_max_size) { + throw std::overflow_error("Cannot add datas out of buffer."); + } + + if(pos < this->_size) { + this->bind(); + uint8_t * writer = static_cast<uint8_t *>(glMapBuffer(Y,GL_READ_WRITE)); + memmove(writer + (pos + vbo._size) * sizeof(T), writer + (pos * sizeof(T)), (this->_size-pos) * sizeof(T)); + glUnmapBuffer(Y); + } + + this->_size += vbo._size; + + glBindBuffer(GL_COPY_READ_BUFFER, vbo.identifier()); + glBindBuffer(GL_COPY_WRITE_BUFFER, this->identifier()); + + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, pos * sizeof(T),vbo._size * sizeof(T)); + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::resize(size_t max_size) { + if(this->_size > max_size) { + throw std::overflow_error("Cannot set a new max size that is greater than current size"); + } + + std::vector<T> save = this->extract(); + this->_max_size = max_size; + this->generate(save); + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::push_back(const std::vector<T> & vertices) { + this->insert(vertices, this->_size); + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::push_front(const std::vector<T> & vertices) { + this->insert(vertices, 0); + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::pop_back(size_t offset) { + if(offset > this->_size) { + throw std::underflow_error("Cannot erase datas out of buffer."); + } + + if(offset > 0) { + this->erase(this->_size-offset+1, this->_size); + } + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::pop_front(size_t offset) { + if(offset > this->_size) { + throw std::overflow_error("Cannot add datas out of buffer."); + } + + if(offset > 0) { + this->erase(0, offset-1); + } + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::regenerate(size_t max_size) { + this->_max_size = max_size; + this->generate({}); + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::reset(const std::vector<T> & data) { + this->set(data); + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::clear() { + this->generate({}); + } + + template <typename T, uint32_t Y> + T DynamicBuffer<T,Y>::back() const { + if(this->empty()) { + throw std::underflow_error("Cannot get data from empty buffer."); + } + + return this->operator[](0); + } + + template <typename T, uint32_t Y> + T DynamicBuffer<T,Y>::front() const { + if(this->empty()) { + throw std::underflow_error("Cannot get data from empty buffer."); + } + + return this->operator[](this->_size-1); + } + + template <typename T, uint32_t Y> + T DynamicBuffer<T,Y>::at(size_t index) const { + return this->operator[](index); + } + + template <typename T, uint32_t Y> + std::vector<T> DynamicBuffer<T,Y>::extract() const { + return this->extract(0, this->_size); + } + + template <typename T, uint32_t Y> + std::vector<T> DynamicBuffer<T,Y>::extract(size_t from,size_t to) const { + if(to > this->_size) { + throw std::overflow_error("Cannot extract datas out of buffer."); + } + + this->bind(); + void * writer = glMapBuffer(Y, GL_WRITE_ONLY); + std::vector<T> data{static_cast<T *>(writer) + from, static_cast<T *>(writer) + from + (to - from)}; + glUnmapBuffer(Y); + + return data; + } + + template <typename T, uint32_t Y> + T DynamicBuffer<T,Y>::operator[](size_t index) const { + return this->extract(index,index)[0]; + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::modify(std::function<void(void *)> modif) { + this->bind(); + modif(glMapBuffer(Y, GL_READ_WRITE)); + glUnmapBuffer(Y); + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::operator()(std::function<void(void *)> modif) { + this->modify(modif); + } + + template <typename T, uint32_t Y> + void DynamicBuffer<T,Y>::operator<<(const DynamicBuffer<T,Y> & buffer) { + this->merge(buffer); + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/DynamicBuffer.hpp b/source/engine/graphics/back/buffers/DynamicBuffer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c09a61006e90497bec4572b4545dfa0a97d4bc23 --- /dev/null +++ b/source/engine/graphics/back/buffers/DynamicBuffer.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include "Buffer.hpp" + +#include <stdint.h> +#include <vector> +#include <list> +#include <functional> + +namespace megu { + template <typename T, uint32_t Y> + class DynamicBuffer : public Buffer { + private: + size_t _max_size; + size_t _size; + + public: + DynamicBuffer() = delete; + DynamicBuffer(size_t, size_t=0); + DynamicBuffer(const DynamicBuffer &) = delete; + + virtual void generate(const std::vector<T> &) = 0; + + size_t size() const; + size_t max_size() const; + size_t memory_size() const; + size_t max_memory_size() const; + + bool empty() const; + bool full() const; + + void set(const std::vector<T> &); + + void insert(const std::vector<T> &, size_t pos); + void replace(const std::vector<T> &, size_t pos); + void erase(size_t from,size_t to); + + void merge(const DynamicBuffer<T,Y> &, size_t pos=0); + + void push_back(const std::vector<T> &); + void push_front(const std::vector<T> &); + + void regenerate(size_t max_size); + void reset(const std::vector<T> &); + void clear(); + + void resize(size_t max_size); + + void pop_back(size_t offset=1); + void pop_front(size_t offset=1); + + T back() const; + T front() const; + + T at(size_t index) const; + + std::vector<T> extract() const; + std::vector<T> extract(size_t from,size_t to) const; + + T operator[](size_t index) const; + + void modify(std::function<void(void *)>); + void operator()(std::function<void(void *)>); + + void operator<<(const DynamicBuffer<T,Y> &); + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/ElementBuffer.cpp b/source/engine/graphics/back/buffers/ElementBuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b316b7790fd80d03d143ce13807c66b5863a684e --- /dev/null +++ b/source/engine/graphics/back/buffers/ElementBuffer.cpp @@ -0,0 +1,90 @@ +#include "ElementBuffer.hpp" + +namespace megu { + ElementBuffer::ElementBuffer(const VertexArray & vao,size_t size,uint32_t mode) + : DynamicBuffer(size),_vao(&vao),_id(0),_mode(mode) { + this->generate({}); + } + + ElementBuffer::ElementBuffer(const VertexArray & vao,const std::vector<unsigned int> & indices,uint32_t mode) + : DynamicBuffer(indices.size(),indices.size()),_vao(&vao),_id(0),_mode(mode) { + this->generate(indices); + } + + ElementBuffer::~ElementBuffer() { + this->unbind(); + glDeleteBuffers(1,&this->_id); + } + + GLuint ElementBuffer::identifier() const { + return this->_id; + } + + void ElementBuffer::bind() const { + if(this->_id != 0) { + this->_vao->bind(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,this->_id); + } + } + + void ElementBuffer::unbind() const { + GLint ebo = 0; + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER, &ebo); + if(static_cast<GLuint>(ebo) == this->_id) { + this->_vao->unbind(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + } + + void ElementBuffer::generate(const std::vector<unsigned int> & vertices) { + this->_vao->bind(); + + if(this->_id != 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); + glDeleteBuffers(1,&this->_id); + } + + glGenBuffers(1,&this->_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,this->_id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER,this->max_size()*sizeof(unsigned int),vertices.size() == 0 ? NULL : std::vector<unsigned int>(vertices).data(),this->_mode); + + } + + bool ElementBuffer::operator==(const ElementBuffer & ebo) const { + return this->_id == ebo._id; + } + + bool ElementBuffer::operator!=(const ElementBuffer & ebo) const { + return this->_id != ebo._id; + } + + bool ElementBuffer::operator>(const ElementBuffer & ebo) const { + return this->_id > ebo._id; + } + + bool ElementBuffer::operator>=(const ElementBuffer & ebo) const { + return this->_id >= ebo._id; + } + + bool ElementBuffer::operator<(const ElementBuffer & ebo) const { + return this->_id < ebo._id; + } + + bool ElementBuffer::operator<=(const ElementBuffer & ebo) const { + return this->_id <= ebo._id; + } + + std::strong_ordering ElementBuffer::operator<=>(const ElementBuffer & ebo) const { + return this->_id <=> ebo._id; + } + + ElementBuffer & operator<<(ElementBuffer & ebo, const std::initializer_list<unsigned int> & data) { + ebo.push_back(data); + return ebo; + } + + ElementBuffer & operator<<(ElementBuffer & ebo, const std::vector<unsigned int> & data) { + ebo.push_back(data); + return ebo; + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/ElementBuffer.hpp b/source/engine/graphics/back/buffers/ElementBuffer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..43b693553ea4c20443c41c8d62835102a3708df4 --- /dev/null +++ b/source/engine/graphics/back/buffers/ElementBuffer.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include <compare> + +#include "DynamicBuffer.hpp" +#include "VertexArray.hpp" + +namespace megu { + class ElementBuffer : public DynamicBuffer<unsigned int, GL_ELEMENT_ARRAY_BUFFER> { + private: + const VertexArray * _vao; + GLuint _id; + GLuint _mode; + + public: + ElementBuffer() = delete; + ElementBuffer(const VertexArray & vao,size_t size=1024,uint32_t mode=GL_DYNAMIC_DRAW); + ElementBuffer(const VertexArray & vao,const std::vector<unsigned int> & indice,uint32_t mode=GL_DYNAMIC_DRAW); + ElementBuffer(const ElementBuffer &) = delete; + virtual ~ElementBuffer(); + + virtual inline GLuint identifier() const; + + virtual void bind() const; + virtual void unbind() const; + + virtual void generate(const std::vector<unsigned int> &); + + inline bool operator==(const ElementBuffer &) const; + inline bool operator!=(const ElementBuffer &) const; + inline bool operator<=(const ElementBuffer &) const; + inline bool operator>=(const ElementBuffer &) const; + + inline bool operator<(const ElementBuffer &) const; + inline bool operator>(const ElementBuffer &) const; + + inline std::strong_ordering operator<=>(const ElementBuffer &) const; + + friend ElementBuffer & operator<<(ElementBuffer &, const std::initializer_list<unsigned int> &); + friend ElementBuffer & operator<<(ElementBuffer &, const std::vector<unsigned int> &); + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/FrameBuffer.cpp b/source/engine/graphics/back/buffers/FrameBuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6be8653c4e36b8c32d6e43a21f1cf7639b72e1b6 --- /dev/null +++ b/source/engine/graphics/back/buffers/FrameBuffer.cpp @@ -0,0 +1,50 @@ +#include "FrameBuffer.hpp" + +#include <iostream> +#include "../../errors/OpenGL_Error.hpp" + +namespace megu { + FrameBuffer::FrameBuffer(GLuint width, GLuint height) + : _id(0), _rbo_id(0), _texture() { + glGenFramebuffers(1, &this->_id); + glBindFramebuffer(GL_FRAMEBUFFER, this->_id); + + this->_texture.store(width, height, NULL, Texture::Format::RGB); + this->_texture.setSmoothing(false); + this->_texture.setWraping(Texture::Wraping::CLAMP_TO_EDGE, Texture::Axis::S | Texture::Axis::T); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->_texture.identifier(), 0); + glGenRenderbuffers(1, &this->_rbo_id); + glBindRenderbuffer(GL_RENDERBUFFER, this->_rbo_id); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, this->_rbo_id); + + if(!this->usable()) { + std::cerr << "Incomplete FrameBuffer." << std::endl; + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + FrameBuffer::~FrameBuffer() { + glDeleteRenderbuffers(1, &this->_rbo_id); + glDeleteFramebuffers(1, &this->_id); + } + + bool FrameBuffer::usable() const { + this->bind(); + return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE; + } + + void FrameBuffer::bind() const { + glBindFramebuffer(GL_FRAMEBUFFER, this->_id); + } + + void FrameBuffer::unbind() const { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + void FrameBuffer::BindDefaultFrameBuffer() { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/FrameBuffer.hpp b/source/engine/graphics/back/buffers/FrameBuffer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..782ef844720d653a3dc7cec20c4c1e6da95fee3b --- /dev/null +++ b/source/engine/graphics/back/buffers/FrameBuffer.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "Buffer.hpp" +#include "../textures/Texture.hpp" + +namespace megu { + class FrameBuffer : public Buffer { + private: + GLuint _id; + GLuint _rbo_id; + Texture _texture; + + public: + FrameBuffer() = delete; + FrameBuffer(GLuint width, GLuint height); + virtual ~FrameBuffer(); + + inline const Texture & texture() const {return this->_texture;} + GLuint rbo_identifier() const {return this->_rbo_id;} + + inline virtual GLuint identifier() const {return this->_id;} + + bool usable() const; + + virtual void bind() const; + virtual void unbind() const; + + static void BindDefaultFrameBuffer(); + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/Layout.hpp b/source/engine/graphics/back/buffers/Layout.hpp new file mode 100644 index 0000000000000000000000000000000000000000..faab8e0d01d0b0519c3aee305dea954a26bbd7e7 --- /dev/null +++ b/source/engine/graphics/back/buffers/Layout.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include <list> +#include <numeric> +#include <stdint.h> + +namespace megu { + using Layout = std::list<uint8_t>; + using Layout_Initializer = std::initializer_list<uint8_t>; + + namespace layout { + inline size_t weight(const Layout & layout) { + return std::accumulate(layout.begin(), layout.end(), 0); + } + + enum Value : unsigned char { + POSITION = 3, + FLAT = 2, + COLOR = 3, + NORMAL = 3, + TEXTURE = 2, + BORDER = 2, + ID = 1, + }; + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/UniformeBuffer.hpp b/source/engine/graphics/back/buffers/UniformeBuffer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e1474ae3aaa32144894645b4e3de2efb4f95c1d3 --- /dev/null +++ b/source/engine/graphics/back/buffers/UniformeBuffer.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "Buffer.hpp" + +#include <optional> +#include <string> +#include <map> + +#include "../shaders/Program.hpp" + +namespace megu { + template <class T> + class UniformeBuffer : public Buffer { + private: + T * _data; + GLuint _id; + std::map<const Program *, GLuint> _programs; + + public: + UniformeBuffer(T * = nullptr); + virtual ~UniformeBuffer(); + + inline GLuint index(const Program & program) const {return this->_programs.at(&program);} + inline std::optional<T> data() const {this->_data != nullptr ? std::optional<T>(*this->_data) : std::optional<T>();} + + void setData(T *); + void attach(const std::string &, const Program &); + + inline virtual GLuint identifier() const {return this->_id;} + + virtual void bind() const; + virtual void unbind() const; + }; +} + +#include "UniformeBuffer.tpp" \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/UniformeBuffer.tpp b/source/engine/graphics/back/buffers/UniformeBuffer.tpp new file mode 100644 index 0000000000000000000000000000000000000000..805ecf0a2e2328e7784a9e4bf9c1ff4a1762faad --- /dev/null +++ b/source/engine/graphics/back/buffers/UniformeBuffer.tpp @@ -0,0 +1,45 @@ +#include "UniformeBuffer.hpp" + +namespace megu { + template <class T> + UniformeBuffer<T>::UniformeBuffer(T * data) + : _data(data), _id(0) { + glCreateBuffers(1, &this->_id); + glBindBuffer(GL_UNIFORM_BUFFER, this->_id); + glBufferData(GL_UNIFORM_BUFFER, sizeof(T), data, GL_DYNAMIC_DRAW); + } + + template <class T> + UniformeBuffer<T>::~UniformeBuffer() { + glDeleteBuffers(1, &this->_id); + } + + template <class T> + void UniformeBuffer<T>::setData(T * data) { + this->_data = data; + glBindBuffer(GL_UNIFORM_BUFFER, this->_id); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(T), data); + } + + template <class T> + void UniformeBuffer<T>::attach(const std::string & name, const Program & program) { + this->_programs.insert(std::pair<const Program *, GLuint>(&program, 0)); + glBindBuffer(GL_UNIFORM_BUFFER, this->_id); + this->_programs[&program] = glGetUniformBlockIndex(program.id(), name.c_str()); + glBindBufferBase(GL_UNIFORM_BUFFER, this->_programs[&program], this->_id); + } + + template <class T> + void UniformeBuffer<T>::bind() const { + glBindBuffer(GL_UNIFORM_BUFFER, this->_id); + } + + template <class T> + void UniformeBuffer<T>::unbind() const { + GLint binded = 0; + glGetIntegerv(GL_UNIFORM_BUFFER_BINDING, &binded); + if(static_cast<GLuint>(binded) == this->_id) { + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/VertexArray.cpp b/source/engine/graphics/back/buffers/VertexArray.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad2d67c556d534c00c85d73a8eae8456f0a9d27a --- /dev/null +++ b/source/engine/graphics/back/buffers/VertexArray.cpp @@ -0,0 +1,59 @@ +#include "VertexArray.hpp" + +namespace megu { + VertexArray::VertexArray(bool binded) + : _vao(0) { + glGenVertexArrays(1, &this->_vao); + + if(binded) { + this->bind(); + } + } + + VertexArray::~VertexArray() { + this->unbind(); + glDeleteVertexArrays(1,&this->_vao); + } + + void VertexArray::bind() const { + if(this->_vao != 0) { + glBindVertexArray(this->_vao); + } + } + + void VertexArray::unbind()const { + GLint vao; + glGetIntegerv(GL_ARRAY_BUFFER, &vao); + if(static_cast<GLuint>(vao) == this->_vao) { + glBindVertexArray(0); + } + } + + bool VertexArray::operator==(const VertexArray & vao) const { + return this->_vao == vao._vao; + } + + bool VertexArray::operator!=(const VertexArray & vao) const { + return this->_vao != vao._vao; + } + + bool VertexArray::operator>(const VertexArray & vao) const { + return this->_vao > vao._vao; + } + + bool VertexArray::operator>=(const VertexArray & vao) const { + return this->_vao >= vao._vao; + } + + bool VertexArray::operator<(const VertexArray & vao) const { + return this->_vao < vao._vao; + } + + bool VertexArray::operator<=(const VertexArray & vao) const { + return this->_vao <= vao._vao; + } + + std::strong_ordering VertexArray::operator<=>(const VertexArray & vao) const { + return this->_vao <=> vao._vao; + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/VertexArray.hpp b/source/engine/graphics/back/buffers/VertexArray.hpp new file mode 100644 index 0000000000000000000000000000000000000000..200a3eb6cf5eb96ab77bfcce74201ba415054c59 --- /dev/null +++ b/source/engine/graphics/back/buffers/VertexArray.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include <compare> +#include <GL/glew.h> + +#include "Buffer.hpp" + +namespace megu { + class VertexArray : public Buffer { + private: + GLuint _vao; + + public: + VertexArray(bool binded=false); + VertexArray(const VertexArray &) = delete; + virtual ~VertexArray(); + + virtual GLuint identifier() const {return this->_vao;} + + virtual void bind() const; + virtual void unbind() const; + + bool operator==(const VertexArray &) const; + bool operator!=(const VertexArray &) const; + bool operator<=(const VertexArray &) const; + bool operator>=(const VertexArray &) const; + + bool operator<(const VertexArray &) const; + bool operator>(const VertexArray &) const; + + std::strong_ordering operator<=>(const VertexArray &) const; + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/VerticeBuffer.cpp b/source/engine/graphics/back/buffers/VerticeBuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a883d5ae2ef0f4087ad422903ae3686db7bb5cd --- /dev/null +++ b/source/engine/graphics/back/buffers/VerticeBuffer.cpp @@ -0,0 +1,110 @@ +#include "VerticeBuffer.hpp" + +#include <list> + +namespace megu { + VerticeBuffer::VerticeBuffer(const VertexArray & vao,const Layout_Initializer & attributes,size_t size,uint32_t mode) + : DynamicBuffer(size), _vao(&vao), _id(0), _mode(mode), _layout(attributes) { + this->generate({}); + } + + VerticeBuffer::VerticeBuffer(const VertexArray & vao,const std::vector<float> & vertices, const Layout & attributes,uint32_t mode) + : DynamicBuffer(vertices.size(), vertices.size()), _vao(&vao), _id(0), _mode(mode), _layout(attributes) { + this->generate(vertices); + } + + VerticeBuffer::~VerticeBuffer() { + this->unbind(); + glDeleteBuffers(1, &this->_id); + } + + GLuint VerticeBuffer::identifier() const { + return this->_id; + } + + size_t VerticeBuffer::weight() const { + return layout::weight(this->_layout); + } + + size_t VerticeBuffer::vertices() const { + return this->size() / this->weight(); + } + + void VerticeBuffer::bind() const { + if(this->_id != 0) { + this->_vao->bind(); + glBindBuffer(GL_ARRAY_BUFFER, this->_id); + } + } + + void VerticeBuffer::unbind() const { + GLint vbo = 0; + glGetIntegerv(GL_ARRAY_BUFFER, &vbo); + if(static_cast<GLuint>(vbo) == this->_id) { + this->_vao->unbind(); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + } + + void VerticeBuffer::generate(const std::vector<float> & vertices) { + this->_vao->bind(); + + if(this->_id != 0) { + glBindBuffer(GL_ARRAY_BUFFER,0); + glDeleteBuffers(1, &this->_id); + } + + glGenBuffers(1,&this->_id); + glBindBuffer(GL_ARRAY_BUFFER, this->_id); + glBufferData(GL_ARRAY_BUFFER, this->max_size()*sizeof(float), vertices.size() == 0 ? NULL : vertices.data(), this->_mode); + + uint32_t layer = 0,accumulateWeight = 0,totalWeight = static_cast<uint32_t>(this->weight()); + for(uint8_t attribute : this->_layout) { + glVertexAttribPointer(layer, attribute, GL_FLOAT, GL_FALSE, totalWeight * sizeof(float), (void*)(accumulateWeight * sizeof(float))); + glEnableVertexAttribArray(layer++); + accumulateWeight += attribute; + } + } + + bool VerticeBuffer::compare(const Layout & layout) const { + return this->_layout == layout; + } + + bool VerticeBuffer::operator==(const VerticeBuffer & vbo) const { + return this->_id == vbo._id; + } + + bool VerticeBuffer::operator!=(const VerticeBuffer & vbo) const { + return this->_id != vbo._id; + } + + bool VerticeBuffer::operator>(const VerticeBuffer & vbo) const { + return this->_id > vbo._id; + } + + bool VerticeBuffer::operator>=(const VerticeBuffer & vbo) const { + return this->_id >= vbo._id; + } + + bool VerticeBuffer::operator<(const VerticeBuffer & vbo) const { + return this->_id < vbo._id; + } + + bool VerticeBuffer::operator<=(const VerticeBuffer & vbo) const { + return this->_id <= vbo._id; + } + + std::strong_ordering VerticeBuffer::operator<=>(const VerticeBuffer & vbo) const { + return this->_id <=> vbo._id; + } + + VerticeBuffer & operator<<(VerticeBuffer & vbo,const std::initializer_list<float> & data) { + vbo.push_back(data); + return vbo; + } + + VerticeBuffer & operator<<(VerticeBuffer & vbo,const std::vector<float> & data) { + vbo.push_back(data); + return vbo; + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/buffers/VerticeBuffer.hpp b/source/engine/graphics/back/buffers/VerticeBuffer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..215341125ea34c775ff394ffdd62a2247f3a6789 --- /dev/null +++ b/source/engine/graphics/back/buffers/VerticeBuffer.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "DynamicBuffer.hpp" + +#include <compare> + +#include "VertexArray.hpp" +#include "Layout.hpp" + +namespace megu { + class VerticeBuffer : public DynamicBuffer<float, GL_ARRAY_BUFFER> { + private: + const VertexArray * _vao; + GLuint _id; + GLuint _mode; + + Layout _layout; + + public: + VerticeBuffer() = delete; + VerticeBuffer(const VertexArray & vao, const Layout_Initializer &, size_t=2048, uint32_t=GL_DYNAMIC_DRAW); + VerticeBuffer(const VertexArray & vao, const std::vector<float> &, const Layout &, uint32_t=GL_DYNAMIC_DRAW); + VerticeBuffer(const VerticeBuffer &) = delete; + virtual ~VerticeBuffer(); + + const Layout & layout() const {return this->_layout;} + + size_t weight() const; + size_t vertices() const; + + virtual GLuint identifier() const; + + virtual void bind() const; + virtual void unbind() const; + + virtual void generate(const std::vector<float> &); + + bool compare(const Layout &) const; + + bool operator==(const VerticeBuffer &) const; + bool operator!=(const VerticeBuffer &) const; + bool operator<=(const VerticeBuffer &) const; + bool operator>=(const VerticeBuffer &) const; + + bool operator<(const VerticeBuffer &) const; + bool operator>(const VerticeBuffer &) const; + + std::strong_ordering operator<=>(const VerticeBuffer &) const; + + friend VerticeBuffer & operator<<(VerticeBuffer &, const std::initializer_list<float> &); + friend VerticeBuffer & operator<<(VerticeBuffer &, const std::vector<float> &); + }; + + +} \ No newline at end of file diff --git a/source/engine/graphics/back/cameras/Camera.hpp b/source/engine/graphics/back/cameras/Camera.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bc062fa1a20204fabf6300ac58e8631a6f7f4b8e --- /dev/null +++ b/source/engine/graphics/back/cameras/Camera.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include <glm/mat4x4.hpp> + +namespace megu { + class Camera { + protected: + enum Update_Flags { + NONE = 0, + VIEW = 1, + PROJECTION = 2, + }; + + public: + virtual const glm::mat4 & view() const = 0; + virtual const glm::mat4 & projection() const = 0; + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/cameras/Target.cpp b/source/engine/graphics/back/cameras/Target.cpp new file mode 100644 index 0000000000000000000000000000000000000000..522184419ba1c59a4843d09776d3d6184b678a2b --- /dev/null +++ b/source/engine/graphics/back/cameras/Target.cpp @@ -0,0 +1,84 @@ +#include "Target.hpp" + +#include <glm/gtc/matrix_transform.hpp> + +#include <iostream> + +namespace megu { + Target::Target(const glm::vec3 & position, const glm::vec3 & target, double fov, double near, double far) + : _position(position), _target(target), _rotation(0.f, 0.f, 0.f), _view(1.f), _projection(1.f), _fov(fov), _ratio(1.f), _near(near), _far(far), _update(0) { + this->update(Update_Flags::VIEW | Update_Flags::PROJECTION); + } + + void Target::update(uint8_t flags) const { + this->_update |= flags; + if(this->_update != Update_Flags::NONE) { + + if((this->_update & Update_Flags::VIEW) != 0) { + this->_view = glm::lookAt(this->_position, this->_target, glm::vec3(0.0f, 1.0f, 0.0f)); + this->_view = glm::rotate(this->_view, glm::radians(this->_rotation.x), {1.f, 0.f, 0.f}); + this->_view = glm::rotate(this->_view, glm::radians(this->_rotation.y), {0.f, 1.f, 0.f}); + this->_view = glm::rotate(this->_view, glm::radians(this->_rotation.z), {0.f, 0.f, 1.f}); + } + + if((this->_update & Update_Flags::PROJECTION) != 0) { + this->_projection = glm::perspective(glm::radians(this->_fov), this->_ratio, this->_near, this->_far); + } + + this->_update = Update_Flags::NONE; + } + } + + void Target::setPosition(double x, double y, double z) { + this->_position = {x, y, z}; + this->_update |= VIEW; + } + + void Target::setTarget(double x, double y, double z) { + this->_target = {x, y, z}; + this->_update |= VIEW; + } + + void Target::setRotation(double x, double y, double z) { + this->_rotation = {x, y, z}; + this->_update |= VIEW; + } + + void Target::setFov(double fov) { + this->_fov = fov; + this->_update |= PROJECTION; + } + + void Target::setRatio(double ratio) { + this->_ratio = ratio; + this->_update |= PROJECTION; + } + + void Target::setViewDistance(double near, double far) { + this->_near = near; + this->_far = far; + this->_update |= PROJECTION; + } + + void Target::move(const glm::vec3 & movement) { + this->_position += movement; + this->_update |= VIEW; + } + + void Target::rotate(const glm::vec3 & rotation) { + this->_rotation += rotation; + this->_view = glm::rotate(this->_view, glm::radians(rotation.x), {1.f, 0.f, 0.f}); + this->_view = glm::rotate(this->_view, glm::radians(rotation.y), {0.f, 1.f, 0.f}); + this->_view = glm::rotate(this->_view, glm::radians(rotation.z), {0.f, 0.f, 1.f}); + } + + const glm::mat4 & Target::view() const { + this->update(); + return this->_view; + } + + const glm::mat4 & Target::projection() const { + this->update(); + return this->_projection; + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/cameras/Target.hpp b/source/engine/graphics/back/cameras/Target.hpp new file mode 100644 index 0000000000000000000000000000000000000000..04bc2dfa58f2e48429caa799b523d478d4accef8 --- /dev/null +++ b/source/engine/graphics/back/cameras/Target.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include "Camera.hpp" + +#include <glm/vec3.hpp> + +namespace megu { + class Target : public Camera { + private: + glm::vec3 _position; + glm::vec3 _target; + glm::vec3 _rotation; + + mutable glm::mat4 _view; + mutable glm::mat4 _projection; + + double _fov; + double _ratio; + double _near; + double _far; + + mutable uint8_t _update; + + void update(uint8_t flags = NONE) const; + + public: + Target(const glm::vec3 & = {0.f, 0.f, 3.f}, const glm::vec3 & = {0.f, 0.f, 0.f}, double=65.f, double=0.1f, double=100.f); + + inline const glm::vec3 & getPosition() const {return this->_position;} + inline const glm::vec3 & getTarget() const {return this->_target;} + + inline double getFov() const {return this->_fov;} + inline double getRatio() const {return this->_ratio;} + inline double getNear() const {return this->_near;} + inline double getFar() const {return this->_far;} + + void setPosition(double, double, double); + void setTarget(double, double, double); + void setRotation(double, double, double); + + void setFov(double fov); + void setRatio(double ratio); + void setViewDistance(double near, double far); + + void move(const glm::vec3 & movement); + void rotate(const glm::vec3 & rotation); + + inline void move(double x, double y, double z = 0.0) {this->move({x, y, z});} + inline void rotate(double pitch, double yaw, double roll = 0.0) {this->rotate({pitch, yaw, roll});} + + const glm::mat4 & view() const; + const glm::mat4 & projection() const; + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/cameras/View.cpp b/source/engine/graphics/back/cameras/View.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f81d5cc6145a836b2c9a5e7c5081f99b7577e90 --- /dev/null +++ b/source/engine/graphics/back/cameras/View.cpp @@ -0,0 +1,69 @@ +#include "View.hpp" + +#include <glm/gtc/matrix_transform.hpp> + +namespace megu { + View::View(float x, float y, float w, float h, float near, float far) + : View({x, y}, {w, h}, near, far) {} + + View::View(const glm::vec2 & position, const glm::vec2 & dimension, float near, float far) + : _view(1.f), _projection(1.f), _position(position), _dimension(dimension), _roll(0.f), _near(near), _far(far), _update() { + this->update(Update_Flags::VIEW | Update_Flags::PROJECTION); + } + + void View::update(uint8_t flags) const { + this->_update |= flags; + if(this->_update != Update_Flags::NONE) { + if((this->_update & VIEW) != 0) { + this->_view = glm::rotate(this->_view, this->_roll, {0.0, 0.0, 1.0}); + } + + if((this->_update & PROJECTION) != 0) { + glm::vec2 center = {this->_position.x + this->_dimension.x / 2, this->_position.y + this->_dimension.y / 2}; + this->_projection = glm::ortho(center.x - this->_dimension.x/2, center.x + this->_dimension.x/2, center.y - this->_dimension.y/2, center.y + this->_dimension.y/2, this->_near, this->_far); + } + } + this->_update = Update_Flags::NONE; + } + + void View::setPosition(const glm::vec2 & position) { + this->_position = position; + this->_update |= Update_Flags::PROJECTION; + } + + void View::setDimension(const glm::vec2 & dimension) { + this->_dimension = dimension; + this->_update |= Update_Flags::PROJECTION; + } + + void View::setDistance(float near, float far) { + this->_near = near; + this->_far = far; + this->_update |= Update_Flags::PROJECTION; + } + + void View::move(const glm::vec2 & position) { + this->_position += position; + this->_update |= Update_Flags::PROJECTION; + } + + void View::setRoll(float roll) { + this->_roll = roll; + this->_update |= Update_Flags::VIEW; + } + + void View::roll(float roll) { + this->_roll += roll; + this->_update |= Update_Flags::VIEW; + } + + const glm::mat4 & View::view() const { + this->update(); + return this->_view; + } + + const glm::mat4 & View::projection() const { + this->update(); + return this->_projection; + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/cameras/View.hpp b/source/engine/graphics/back/cameras/View.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4792d6cf7292bb0bdbd0b72cc48f7e3089d9bb58 --- /dev/null +++ b/source/engine/graphics/back/cameras/View.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include "Camera.hpp" + +#include <glm/vec2.hpp> +#include <algorithm> +#include <iterator> +#include <set> + +namespace megu { + class View : public Camera { + private: + mutable glm::mat4 _view; + mutable glm::mat4 _projection; + glm::vec2 _position; + glm::vec2 _dimension; + + float _roll; + float _near; + float _far; + + mutable uint8_t _update; + + void update(uint8_t = NONE) const; + + public: + View() = delete; + View(float x, float y, float w, float h, float = -10, float = 10.0); + View(const glm::vec2 &, const glm::vec2 &, float = -10, float = 10.0); + + inline const glm::vec2 & position() const {return this->_position;} + inline const glm::vec2 & dimension() const {return this->_dimension;} + + inline float roll() const {return this->_roll;} + inline float getNear() const {return this->_near;} + inline float getFar() const {return this->_far;} + + void setPosition(const glm::vec2 &); + void setDimension(const glm::vec2 &); + void setRoll(float); + void setDistance(float near, float far); + + void move(const glm::vec2 &); + void roll(float); + + inline void move(float x, float y) {this->move({x, y});} + + const glm::mat4 & view() const; + const glm::mat4 & projection() const; + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/cameras/Walkaround.cpp b/source/engine/graphics/back/cameras/Walkaround.cpp new file mode 100644 index 0000000000000000000000000000000000000000..650cae67c5c0634574116dda9c0a3d9609fe2516 --- /dev/null +++ b/source/engine/graphics/back/cameras/Walkaround.cpp @@ -0,0 +1,102 @@ +#include "Walkaround.hpp" + +#include <glm/gtc/matrix_transform.hpp> + +namespace megu { + Walkaround::Walkaround() + : Walkaround(glm::vec3(0.f, 0.f, 3.f)) {} + + Walkaround::Walkaround(const glm::vec3 & position, double fov, double ratio, double near, double far) + : _view(1.f), + _projection(1.f), + _position(position), + _up(0.f, 1.f, 0.f), + _pitch(0.f), + _yaw(-90.f), + _roll(0.f), + _fov(fov), + _ratio(ratio), + _near(near), + _far(far), + _update(Update_Flags::NONE) { + this->update(Update_Flags::VIEW | Update_Flags::PROJECTION); + } + + void Walkaround::update(uint8_t flags) const { + this->_update |= flags; + if(this->_update != Update_Flags::NONE) { + if((this->_update & VIEW) != 0) { + glm::vec3 front; + front.x = static_cast<float>(std::cos(glm::radians(this->_yaw)) * std::cos(glm::radians(this->_pitch))); + front.y = static_cast<float>(std::sin(glm::radians(this->_pitch))); + front.z = static_cast<float>(std::sin(glm::radians(this->_yaw)) * std::cos(glm::radians(this->_pitch))); + + glm::vec right = glm::normalize(glm::cross(front, this->_up)); + glm::mat4 roll_mat = glm::rotate(glm::mat4(1.f), (float)glm::radians(this->_roll), front); + + this->_up = glm::normalize(glm::cross(right, front)); + this->_up = glm::mat3(roll_mat) * this->_up; + + this->_view = glm::lookAt(this->_position, this->_position + front, this->_up); + } + + if((this->_update & PROJECTION) != 0) { + this->_projection = glm::perspective(glm::radians(this->_fov), this->_ratio, this->_near, this->_far); + } + } + this->_update = Update_Flags::NONE; + } + + void Walkaround::setPosition(const glm::vec3 & position) { + this->_position = position; + this->_update |= Update_Flags::VIEW; + } + + void Walkaround::setPitch(double pitch) { + this->_pitch = pitch; + this->_update |= Update_Flags::VIEW; + } + + void Walkaround::setYaw(double yaw) { + this->_yaw = yaw; + this->_update |= Update_Flags::VIEW; + } + + void Walkaround::setRoll(double roll) { + this->_roll = std::fmod(roll, 360.0); + this->_update |= Update_Flags::VIEW; + } + + void Walkaround::setRatio(double ratio) { + this->_ratio = ratio; + this->_update |= Update_Flags::PROJECTION; + } + + void Walkaround::setDistance(double near, double far) { + this->_near = near; + this->_far = far; + this->_update |= Update_Flags::PROJECTION; + } + + void Walkaround::move(const glm::vec3 & movement) { + this->_position += movement; + this->_update |= Update_Flags::VIEW; + } + + void Walkaround::rotate(const glm::vec3 & rotation) { + this->_pitch += rotation.x; + this->_yaw += rotation.y; + this->_roll += rotation.z; + this->_update |= Update_Flags::VIEW; + } + + const glm::mat4 & Walkaround::view() const { + this->update(); + return this->_view; + } + + const glm::mat4 & Walkaround::projection() const { + this->update(); + return this->_projection; + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/cameras/Walkaround.hpp b/source/engine/graphics/back/cameras/Walkaround.hpp new file mode 100644 index 0000000000000000000000000000000000000000..893cfa95b37c72f04a22e93afcaed3a9f3d34fff --- /dev/null +++ b/source/engine/graphics/back/cameras/Walkaround.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include "Camera.hpp" + +#include <glm/vec3.hpp> + +namespace megu { + class Walkaround : public Camera { + private: + mutable glm::mat4 _view; + mutable glm::mat4 _projection; + + glm::vec3 _position; + mutable glm::vec3 _up; + + double _pitch; + double _yaw; + double _roll; + + double _fov; + double _ratio; + double _near; + double _far; + + mutable uint8_t _update; + + void update(uint8_t = NONE) const; + + public: + Walkaround(); + Walkaround(const glm::vec3 &, double = 70.0f, double = 1.f, double = 0.1f, double = 100.0f); + + inline const glm::vec3 & position() const {return this->_position;} + + inline double pitch() const {return this->_pitch;} + inline double roll() const {return this->_roll;} + inline double yaw() const {return this->_yaw;} + + inline double ratio() const {return this->_ratio;} + inline double getNear() const {return this->_near;} + inline double getFar() const {return this->_far;} + inline double fov() const {return this->_fov;} + + void setPosition(const glm::vec3 &); + void setPitch(double); + void setYaw(double); + void setRoll(double); + void setRatio(double); + void setDistance(double near, double far); + + void move(const glm::vec3 &); + void rotate(const glm::vec3 &); + + inline void move(double x, double y, double z = 0.0) {this->move({x, y, z});} + inline void rotate(double pitch, double yaw, double roll = 0.0) {this->rotate({pitch, yaw, roll});} + + inline void setRatio(double w, double h) {this->setRatio(w/h);} + + const glm::mat4 & view() const; + const glm::mat4 & projection() const; + + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/geometry/Transform.cpp b/source/engine/graphics/back/geometry/Transform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b931b5b59e2e6b651afe8743004f75f7122bd3b --- /dev/null +++ b/source/engine/graphics/back/geometry/Transform.cpp @@ -0,0 +1,87 @@ +#include "Transform.hpp" + +#include <glm/gtc/matrix_transform.hpp> + +#include <iostream> + +namespace megu { + Transform::Transform(const glm::mat4x4 & matrix) + : _model(matrix), _position(0.f, 0.f, 0.f), _rotation(0.f, 0.f, 0.f), _scaling(1.f, 1.f, 1.f), _origine(0.f, 0.f, 0.f), _updated(true) {} + + Transform::Transform(const glm::vec3 & position, float angle, uint8_t axis, const glm::vec3 & scaling) + : _model(1.0f), _position(position), _rotation(0, 0, 0), _scaling(scaling), _updated(true) { + this->setRotation(angle, axis); + } + + void Transform::setPosition(const glm::vec3 & position) { + this->_position = position; + this->_updated = true; + } + + void Transform::setRotation(float angle, uint8_t axis) { + if((axis & Axis::X) != 0) { + this->_rotation.x = angle; + } + + if((axis & Axis::Y) != 0) { + this->_rotation.y = angle; + } + + if((axis & Axis::Z) != 0) { + this->_rotation.z = angle; + } + + this->_updated = true; + } + + void Transform::setScaling(const glm::vec3 & scaling) { + this->_scaling = scaling; + this->_updated = true; + } + + void Transform::move(const glm::vec3 & position) { + this->_position += position; + this->_updated = true; + } + + void Transform::rotate(float angle, uint8_t axis) { + if((axis & Axis::X) != 0) { + this->_rotation.x += angle; + } + + if((axis & Axis::Y) != 0) { + this->_rotation.y += angle; + } + + if((axis & Axis::Z) != 0) { + this->_rotation.z += angle; + } + + this->_updated = true; + } + + void Transform::scale(const glm::vec3 & scaling) { + this->_scaling += scaling; + this->_updated = true; + } + + const glm::mat4x4 & Transform::model() const { + if(this->_updated) { + glm::mat4x4 model = glm::mat4x4(1.f); + + model = glm::translate(model, this->_position); + model = glm::translate(model, this->_origine); + + model = glm::rotate(model, glm::radians(this->_rotation.z), {0.f, 0.f, 1.f}); + model = glm::rotate(model, glm::radians(this->_rotation.y), {0.f, 1.f, 0.f}); + model = glm::rotate(model, glm::radians(this->_rotation.x), {1.f, 0.f, 0.f}); + + model = glm::translate(model, -this->_origine); + model = glm::scale(model, this->_scaling); + + this->_model = model; + this->_updated = false; + } + return this->_model; + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/geometry/Transform.hpp b/source/engine/graphics/back/geometry/Transform.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0f1ec2be7da951ead7e9d3e0e95b2f8ec25abed4 --- /dev/null +++ b/source/engine/graphics/back/geometry/Transform.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include <glm/vec3.hpp> +#include <glm/mat4x4.hpp> + +namespace megu { + class Transform { + private: + mutable glm::mat4 _model; + glm::vec3 _position; + glm::vec3 _rotation; + glm::vec3 _scaling; + glm::vec3 _origine; + mutable bool _updated; + + public: + enum Axis : unsigned char { + X = 1, + Y = 2, + Z = 4 + }; + + Transform(const glm::mat4 & = glm::mat4(1.f)); + Transform(const glm::vec3 &, float, uint8_t, const glm::vec3 & = {1.f, 1.f, 1.f}); + + inline const glm::vec3 & position() const {return this->_position;} + inline glm::vec3 & position() {return this->_position;} + + inline float x() const {return this->_position.x;} + inline float y() const {return this->_position.y;} + inline float z() const {return this->_position.z;} + + inline const glm::vec3 & rotation() const {return this->_rotation;} + inline glm::vec3 & rotation() {return this->_rotation;} + + inline float pitch() const {return this->_rotation.x;} + inline float yaw() const {return this->_rotation.y;} + inline float roll() const {return this->_rotation.z;} + + inline const glm::vec3 & scaling() const {return this->_scaling;} + inline glm::vec3 & scaling() {return this->_scaling;} + + inline const glm::vec3 & origine() const {return this->_origine;} + inline glm::vec3 & origine() {return this->_origine;} + + void setRotation(float, uint8_t); + + void setPosition(const glm::vec3 &); + inline void setPosition(float x, float y, float z = 0.0) {this->setPosition({x, y, z});} + + void setScaling(const glm::vec3 &); + inline void setScaling(float x, float y, float z = 0.0) {this->setScaling({x, y, z});} + + inline void setMatrix(const glm::mat4 & matrix) {this->_model = matrix;} + inline void setOrigine(const glm::vec3 & position) {this->_origine = position;} + + void rotate(float, uint8_t); + + void move(const glm::vec3 &); + inline void move(float x, float y, float z = 0.0f) {this->move({x, y, z});} + + void scale(const glm::vec3 &); + inline void scale(float x, float y, float z = 0.0f) {this->scale({x, y, z});} + + virtual const glm::mat4x4 & model() const; + + inline void translate(const glm::vec3 & translation) {this->move(translation);} + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/shaders/Program.cpp b/source/engine/graphics/back/shaders/Program.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa7f73d2b881f7c21e7801207bb84f39022594ba --- /dev/null +++ b/source/engine/graphics/back/shaders/Program.cpp @@ -0,0 +1,155 @@ +#include "Program.hpp" + +#include <GLM/gtc/type_ptr.hpp> +#include "../../errors/Shader_Error.hpp" + +namespace megu { + Program::Program() + : _id(0), _usable(false), _attached(NONE) { + this->_id = glCreateProgram(); + } + + Program::~Program() { + glDeleteProgram(this->_id); + } + + const uint8_t Program::Categorie(const Source::Categorie categorie) { + switch (categorie) { + case Source::Categorie::VERTEX: + return Bit_Categorie::VERTEX; + + case Source::Categorie::FRAGMENT: + return Bit_Categorie::FRAGMENT; + + case Source::Categorie::GEOMETRY: + return Bit_Categorie::GEOMETRY; + + case Source::Categorie::TESS_CONTROL: + return Bit_Categorie::TESS_CONTROL; + + case Source::Categorie::TESS_EVALUATION: + return Bit_Categorie::TESS_CONTROL; + + case Source::Categorie::COMPUTE: + return Bit_Categorie::COMPUTE; + + default: + return Bit_Categorie::NONE; + } + } + + void Program::attach(const Source & source) { + if(source.usable()) { + glAttachShader(this->_id, source.id()); + this->_attached |= Program::Categorie(source.categorie()); + } + } + + void Program::dettach(const Source & source) { + glDetachShader(this->_id, source.id()); + this->_attached = this->_attached & ~Program::Categorie(source.categorie()); + this->_usable = ((this->_attached & Bit_Categorie::VERTEX) != 0 && (this->_attached & Bit_Categorie::FRAGMENT) != 0); + } + + void Program::link() { + this->_usable = ((this->_attached & Bit_Categorie::VERTEX) != 0 && (this->_attached & Bit_Categorie::FRAGMENT) != 0); + if(this->_usable) { + glLinkProgram(this->_id); + + int success; + char infoLog[512]; + + glGetProgramiv(this->_id, GL_LINK_STATUS, &success); + if(!success) { + this->_usable = false; + glGetProgramInfoLog(this->_id, 512, NULL, infoLog); + throw error::shader_error(infoLog); + } + } + else { + if((this->_attached & Bit_Categorie::VERTEX) == 0) { + throw error::shader_error("Missing Vertex Source attached to Program"); + } + else if((this->_attached & Bit_Categorie::FRAGMENT) == 0) { + throw error::shader_error("Missing Fragment Source attached to Program"); + } + } + } + + void Program::use() const { + if(this->_usable) { + glUseProgram(this->_id); + } + } + + void Program::kill() { + this->_usable = false; + this->_attached = Bit_Categorie::NONE; + this->_id = glCreateProgram(); + } + + void Program::setUniform(const std::string & name, GLint value) const { + glUniform1i(glGetUniformLocation(this->_id, name.c_str()), value); + } + + void Program::setUniform(const std::string & name, GLuint value) const { + glUniform1ui(glGetUniformLocation(this->_id, name.c_str()), value); + } + + void Program::setUniform(const std::string & name, GLfloat value) const { + glUniform1f(glGetUniformLocation(this->_id, name.c_str()), value); + } + + void Program::setUniform(const std::string & name, GLdouble value) const { + glUniform1d(glGetUniformLocation(this->_id, name.c_str()), value); + } + + void Program::setUniform(const std::string & name, GLchar value) const { + this->setUniform(name,(GLint) value); + } + + void Program::setUniform(const std::string & name, const glm::mat4 & value) const { + glUniformMatrix4fv(glGetUniformLocation(this->_id, name.c_str()), 1, GL_FALSE, &value[0][0]); + } + + void Program::setUniform(const std::string & name, const glm::vec2 & value) const { + glUniform2f(glGetUniformLocation(this->_id, name.c_str()), value.x, value.y); + } + + void Program::setUniform(const std::string & name, const glm::vec3 & value) const { + glUniform3f(glGetUniformLocation(this->_id, name.c_str()), value.x, value.y, value.z); + } + + void Program::setUniform(const std::string & name, const glm::vec<3, uint32_t> & value) const { + glUniform3ui(glGetUniformLocation(this->_id, name.c_str()), value.x, value.y, value.z); + } + + void Program::setUniform(const std::string & name, const glm::vec<3, int32_t> & value) const { + glUniform3i(glGetUniformLocation(this->_id, name.c_str()), value.x, value.y, value.z); + } + + void Program::setUniform(const std::string & name, const glm::vec4 & value) const { + glUniform4f(glGetUniformLocation(this->_id, name.c_str()), value.x, value.y, value.z, value.w); + } + + void Program::setUniform(const std::string & name, const std::vector<GLint> & value) const { + glUniform1iv(glGetUniformLocation(this->_id, name.c_str()), static_cast<GLsizei>(value.size()), value.data()); + } + + void Program::setUniform(const std::string & name, const std::vector<GLfloat> & value) const { + glUniform1fv(glGetUniformLocation(this->_id, name.c_str()), static_cast<GLsizei>(value.size()), value.data()); + } + + void Program::setUniform(const std::string & name, const std::vector<glm::vec2> & value) const { + glUniform2fv(glGetUniformLocation(this->_id, name.c_str()), static_cast<GLsizei>(value.size()), (float *)value.data()); + } + + void Program::setUniform(const std::string & name, const std::vector<glm::vec4> & value) const { + glUniform4fv(glGetUniformLocation(this->_id, name.c_str()), static_cast<GLsizei>(value.size()), (float *)value.data()); + } + + void Program::setUniform(const std::string & name, const std::vector<glm::mat4> & value) const { + glUniformMatrix4fv(glGetUniformLocation(this->_id, name.c_str()), static_cast<GLsizei>(value.size()), GL_FALSE, glm::value_ptr(value[0])); + } + +} \ No newline at end of file diff --git a/source/engine/graphics/back/shaders/Program.hpp b/source/engine/graphics/back/shaders/Program.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a1b356262f3c1a9f015269da878cb980f8e646f3 --- /dev/null +++ b/source/engine/graphics/back/shaders/Program.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include <GL/glew.h> +#include <glm/mat4x4.hpp> +#include <vector> + +#include "Source.hpp" + +namespace megu { + class Program { + private: + GLuint _id; + bool _usable; + uint8_t _attached; + + protected: + enum Bit_Categorie { + NONE = 0, + VERTEX = 1, + FRAGMENT = 2, + GEOMETRY = 4, + TESS_CONTROL = 8, + TESS_EVALUATION = 16, + COMPUTE = 32, + }; + + static const uint8_t Categorie(const Source::Categorie); + + public: + Program(); + Program(const Program &) = delete; + Program(const Program &&) = delete; + Program operator=(const Program &) = delete; + virtual ~Program(); + + void attach(const Source &); + void dettach(const Source &); + void link(); + void kill(); + + virtual void use() const; + + inline GLuint id() const {return this->_id;} + inline bool usable() const {return this->_usable;} + + inline void operator<<(const Source & source) {this->attach(source);} + + void setUniform(const std::string &, GLint) const; + void setUniform(const std::string &, GLuint) const; + void setUniform(const std::string &, GLfloat) const; + void setUniform(const std::string &, GLdouble) const; + void setUniform(const std::string &, GLchar) const; + + void setUniform(const std::string &, const glm::vec2 &) const; + void setUniform(const std::string &, const glm::vec3 &) const; + void setUniform(const std::string &, const glm::vec<3, uint32_t> &) const; + void setUniform(const std::string &, const glm::vec<3, int32_t> &) const; + void setUniform(const std::string &, const glm::vec4 &) const; + + void setUniform(const std::string &, const glm::mat4 &) const; + + void setUniform(const std::string &, const std::vector<GLint> &) const; + void setUniform(const std::string &, const std::vector<GLfloat> &) const; + void setUniform(const std::string &, const std::vector<glm::vec2> &) const; + void setUniform(const std::string &, const std::vector<glm::vec4> &) const; + void setUniform(const std::string &, const std::vector<glm::mat4> &) const; + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/shaders/Source.cpp b/source/engine/graphics/back/shaders/Source.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aac5ab756eccbc710f203a340f9c3016b74fbe66 --- /dev/null +++ b/source/engine/graphics/back/shaders/Source.cpp @@ -0,0 +1,70 @@ +#include "Source.hpp" + +#include <filesystem> +#include <fstream> +#include <sstream> +#include <exception> + +#include "../../errors/Shader_Error.hpp" + +namespace megu { + Source::Source() + : _id(0), _categorie(Categorie::NONE), _path("") { + + } + + Source::Source(const std::filesystem::path & path, Categorie categorie) + : _id(0), _categorie(categorie), _path("") { + this->load(path, categorie); + } + + Source::~Source() { + glDeleteShader(this->_id); + } + + void Source::load(const std::filesystem::path & path, Categorie categorie) { + if(this->_id != 0) { + this->release(); + } + + if(!std::filesystem::exists(path)) { + throw std::runtime_error(std::string("Can't open : ").append(path.string())); + } + + + this->_path = path; + std::ifstream is(path); + + if(is.fail()) { + throw std::runtime_error("Stream fail."); + } + + std::stringstream buffer; + buffer << is.rdbuf(); + + std::string ssource = buffer.str(); + const char * ccsource = ssource.c_str(); + + this->_id = glCreateShader(static_cast<GLenum>(categorie)); + this->_categorie = categorie; + + + glShaderSource(this->_id,1,&ccsource,NULL); + glCompileShader(this->_id); + buffer.clear(); + + int success; + char infoLog[512]; + glGetShaderiv(this->_id, GL_COMPILE_STATUS, &success); + if(!success) { + glGetShaderInfoLog(this->_id, 512, NULL, infoLog); + throw error::shader_error(infoLog, &this->_path); + } + } + + void Source::release() { + glDeleteShader(this->_id); + this->_id = NO_SOURCE_ID; + this->_categorie = Categorie::NONE; + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/shaders/Source.hpp b/source/engine/graphics/back/shaders/Source.hpp new file mode 100644 index 0000000000000000000000000000000000000000..49a59f14f324b62c06d1788fa137ff4166155964 --- /dev/null +++ b/source/engine/graphics/back/shaders/Source.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include <GL/glew.h> +#include <filesystem> + +namespace megu { + class Source { + public: + enum class Categorie : GLenum { + NONE = 0, + VERTEX = GL_VERTEX_SHADER, + FRAGMENT = GL_FRAGMENT_SHADER, + GEOMETRY = GL_GEOMETRY_SHADER, + TESS_CONTROL = GL_TESS_CONTROL_SHADER, + TESS_EVALUATION = GL_TESS_EVALUATION_SHADER, + COMPUTE = GL_COMPUTE_SHADER, + }; + + private: + GLuint _id; + Categorie _categorie; + std::filesystem::path _path; + + protected: + static constexpr GLuint NO_SOURCE_ID = 0; + + public: + Source(); + Source(const std::filesystem::path &, Categorie categorie); + Source(const Source &) = delete; + Source(const Source &&) = delete; + Source operator=(const Source &) = delete; + ~Source(); + + void load(const std::filesystem::path &, Categorie categorie); + void release(); + + inline GLuint id() const {return this->_id;} + inline Categorie categorie() const {return this->_categorie;} + + inline bool usable() const {return this->_id != 0;} + inline const std::filesystem::path & path() const {return this->_path;} + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/shaders/UniformObject.hpp b/source/engine/graphics/back/shaders/UniformObject.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d323b37c4c6c4cdd75594f72a05400dd9e93c420 --- /dev/null +++ b/source/engine/graphics/back/shaders/UniformObject.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include <optional> +#include <variant> +#include <map> +#include <string> + +#include "Program.hpp" + +namespace megu { + template <class... Ts> + struct overloaded : Ts ... { + using Ts::operator()...; + }; + + template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>; + + template <typename ... T> + class UniformObject { + private: + Program * _program; + std::map<std::string, std::variant<T ...>> _values; + + public: + UniformObject() : _program(nullptr) {} + UniformObject(Program & p) : _program(&p) {} + ~UniformObject() {} + + template <typename U> + void add(const std::string & name, U data) { + this->_values.insert(std::pair<std::string, std::variant<T ...>>(name, std::variant<T ...>(data))); + } + + template <typename U> + void set(const std::string & name, U data) { + this->_values.insert_or_assign(name, std::variant<T ...>(data)); + } + + template <typename U> + U get(const std::string & name) const { + return std::get<U>(this->_values.at(name)); + } + + bool contain(const std::string & name) const { + return this->_values.contains(name); + } + + inline void apply() { + if(this->_program != nullptr) { + this->apply(*this->_program); + } + } + + void apply(const Program & prog) { + for(auto & value : this->_values) { + const std::string name = value.first; + + std::visit(overloaded{ + [&prog, &name](GLint & data) { // Avoid error when passing GLint for Sample2D. + prog.setUniform(name, data); + }, + [&prog, &name](auto & data){ + prog.setUniform(name, data); + } + }, value.second); + } + } + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/textures/Material.cpp b/source/engine/graphics/back/textures/Material.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee4b81bf7a6b3ae68e2f0f0357c9f518908ea611 --- /dev/null +++ b/source/engine/graphics/back/textures/Material.cpp @@ -0,0 +1,47 @@ +#include "Material.hpp" + +#include <exception> + +#define STB_IMAGE_IMPLEMENTATION +#include <stb/image/stb_image.h> + +namespace megu { + Material::Material() + : Texture(0, GL_TEXTURE_2D), _ressource("./") { + + } + + Material::Material(const std::string & path, bool invert, Texture::Format format) + : Texture(), _ressource() { + this->load(path, format, invert); + } + + void Material::load(const std::string & path, Texture::Format format, bool invert) { + this->_ressource = std::filesystem::canonical(path); + if(std::filesystem::is_directory(this->_ressource) || !std::filesystem::exists(this->_ressource)) { + throw std::runtime_error("Cannot load ressource !"); + } + + int width, height, nrChannels; + stbi_set_flip_vertically_on_load(invert); + unsigned char * data = stbi_load(path.c_str(), &width, &height, &nrChannels, 0); + if(format == Texture::AUTO) { + switch (nrChannels) { + case 3: + format = Texture::RGB; + break; + + case 4: + format = Texture::RGBA; + break; + + default: + format = Texture::RGBA; + break; + } + } + + this->store(width, height, data, format); + stbi_image_free(data); + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/textures/Material.hpp b/source/engine/graphics/back/textures/Material.hpp new file mode 100644 index 0000000000000000000000000000000000000000..04074a23937001cb17e51745ab1a5171a35eb5dc --- /dev/null +++ b/source/engine/graphics/back/textures/Material.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include <filesystem> +#include <string> + +#include "Texture.hpp" + +namespace megu { + class Material : public Texture { + private: + std::filesystem::path _ressource; + + public: + Material(); + Material(const Material &) = delete; + Material(const std::string &, bool = false, Texture::Format = Texture::RGBA); + Material operator=(const Material &) = delete; + + inline const std::filesystem::path & ressource() const {return this->_ressource;} + + void load(const std::string &, Texture::Format = AUTO, bool = false); + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/textures/Shared_Material.cpp b/source/engine/graphics/back/textures/Shared_Material.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2320d7cb267274b790fc8b782aefbb1156a4fa23 --- /dev/null +++ b/source/engine/graphics/back/textures/Shared_Material.cpp @@ -0,0 +1,140 @@ +#include "Shared_Material.hpp" + +namespace megu { + + std::map<std::filesystem::path,std::set<const Shared_Material *>> Shared_Material::_shared = std::map<std::filesystem::path,std::set<const Shared_Material *>>(); + + Shared_Material::Shared_Material() + : _material(std::make_shared<Material>()) { + + } + + Shared_Material::Shared_Material(const std::string & path, bool invert, Texture::Format format) + : _material(nullptr) { + if(!path.empty() && Shared_Material::_shared.contains(path)) { + this->_material = Shared_Material::_shared.at(path).begin().operator*()->_material; + Shared_Material::_shared.at(path).insert(this); + } + else { + this->_material = std::make_shared<Material>(path, invert, format); + Shared_Material::_shared.insert(std::pair<std::filesystem::path, std::set<const Shared_Material *>>(path, {this})); + } + } + + Shared_Material::Shared_Material(Material & material) + : _material(nullptr) { + if(!material.ressource().empty() && Shared_Material::_shared.contains(material.ressource())) { + this->_material = Shared_Material::_shared.at(material.ressource()).begin().operator*()->_material; + Shared_Material::_shared.at(material.ressource()).insert(this); + } + else { + this->_material = std::shared_ptr<Material>(&material); + Shared_Material::_shared.insert(std::pair<std::filesystem::path,std::set<const Shared_Material *>>(material.ressource(),{this})); + } + } + + Shared_Material::~Shared_Material() { + if(Shared_Material::_shared.contains(this->_material->ressource())) { + Shared_Material::_shared.at(this->_material->ressource()).erase(this); + if(Shared_Material::_shared.at(this->_material->ressource()).empty()) { + Shared_Material::_shared.erase(this->_material->ressource()); + } + } + } + + const Material & Shared_Material::material() const { + return *this->_material.get(); + } + + GLuint Shared_Material::identifier() const { + return this->_material->identifier(); + } + + GLuint Shared_Material::format() const { + return this->_material->type(); + } + + uint16_t Shared_Material::width() const { + return this->_material->width(); + } + + uint16_t Shared_Material::height() const { + return this->_material->height(); + } + + const std::filesystem::path & Shared_Material::path() const { + return this->_material->ressource(); + } + + void Shared_Material::bind() const { + this->_material->bind(); + } + + void Shared_Material::bind(uint32_t slot) const { + this->_material->bind(slot); + } + + void Shared_Material::load(const std::string & path, Texture::Format format, bool flip_y) { + if(!this->_material->ressource().empty()) { + Shared_Material::_shared.at(this->_material->ressource()).erase(this); + if(Shared_Material::_shared.at(this->_material->ressource()).empty()) { + Shared_Material::_shared.erase(this->_material->ressource()); + } + } + + if(Shared_Material::_shared.contains(path)) { + this->_material = Shared_Material::_shared.at(path).begin().operator*()->_material; + Shared_Material::_shared.at(path).insert(this); + } + else { + this->_material->load(path, format, flip_y); + Shared_Material::_shared.insert(std::pair<std::filesystem::path,std::set<const Shared_Material *>>(path,{this})); + } + } + + void Shared_Material::load(Material & material) { + if(!material.ressource().empty() && Shared_Material::_shared.contains(material.ressource())) { + this->_material = Shared_Material::_shared.at(material.ressource()).begin().operator*()->_material; + Shared_Material::_shared.at(material.ressource()).insert(this); + } + else { + this->_material = std::shared_ptr<Material>(&material); + } + } + + bool Shared_Material::valide() const { + return this->_material->valide(); + } + + bool Shared_Material::operator==(const Shared_Material & material) const { + return this->material() == material.material(); + } + + bool Shared_Material::operator!=(const Shared_Material & material) const { + return this->material() != material.material(); + } + + bool Shared_Material::operator>=(const Shared_Material & material) const { + return this->material() >= material.material(); + } + + bool Shared_Material::operator<=(const Shared_Material & material) const { + return this->material() <= material.material(); + } + + bool Shared_Material::operator>(const Shared_Material & material) const { + return this->material() > material.material(); + } + + bool Shared_Material::operator<(const Shared_Material & material) const { + return this->material() < material.material(); + } + + Material * Shared_Material::operator->() const { + return this->_material.get(); + } + + std::strong_ordering Shared_Material::operator<=>(const Shared_Material & material) const { + return this->material() <=> material.material(); + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/textures/Shared_Material.hpp b/source/engine/graphics/back/textures/Shared_Material.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9247bdf1c5913a8a4bfd39536d914be988fda28a --- /dev/null +++ b/source/engine/graphics/back/textures/Shared_Material.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include <memory> +#include <map> +#include <set> +#include <filesystem> +#include <optional> + +#include "Material.hpp" + +namespace megu { + class Shared_Material { + private: + std::shared_ptr<Material> _material; + static std::map<std::filesystem::path,std::set<const Shared_Material *>> _shared; + + public: + Shared_Material(); + Shared_Material(const std::string &, bool = false, Texture::Format = Texture::AUTO); + Shared_Material(Material &); + virtual ~Shared_Material(); + + const Material & material() const; + + GLuint identifier() const; + GLuint format() const; + + uint16_t width() const; + uint16_t height() const; + + const std::filesystem::path & path() const; + + void bind() const; + void bind(uint32_t slot) const; + + void load(const std::string &, Texture::Format=Texture::RGB, bool=true); + void load(Material &); + + bool valide() const; + + bool operator==(const Shared_Material &) const; + bool operator!=(const Shared_Material &) const; + bool operator>=(const Shared_Material &) const; + bool operator<=(const Shared_Material &) const; + bool operator>(const Shared_Material &) const; + bool operator<(const Shared_Material &) const; + + Material * operator->() const; + + std::strong_ordering operator<=>(const Shared_Material &) const; + + }; +} \ No newline at end of file diff --git a/source/engine/graphics/back/textures/Texture.cpp b/source/engine/graphics/back/textures/Texture.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0db023fa5bbcd9535ec222bdd644b4c6f6789bde --- /dev/null +++ b/source/engine/graphics/back/textures/Texture.cpp @@ -0,0 +1,122 @@ +#include "Texture.hpp" + +#include <exception> +#include <iostream> + +namespace megu { + Texture::Texture(GLuint slot, GLuint type) + : _id(0), _type(type), _slot(slot) { + glGenTextures(1, &this->_id); + + } + + Texture::~Texture() { + glDeleteTextures(1, &this->_id); + } + + void Texture::bind() const { + glActiveTexture(GL_TEXTURE0 + this->_slot); + glBindTexture(this->_type, this->_id); + } + + void Texture::bind(GLuint slot) const { + this->_slot = slot; + this->bind(); + } + + GLint Texture::width() const { + if(this->_id == 0) { + throw std::runtime_error("Void texture."); + } + + GLint width; + glGetTexLevelParameteriv(this->_type, 0, GL_TEXTURE_WIDTH, &width); + return width; + } + + GLint Texture::height() const { + if(this->_id == 0) { + throw std::runtime_error("Void texture."); + } + + GLint height; + glGetTexLevelParameteriv(this->_type, 0, GL_TEXTURE_HEIGHT, &height); + return height; + } + + void Texture::changeTextureSlot(GLuint slot) { + this->_slot = slot; + } + + void Texture::setWraping(Wraping wraping, uint32_t flags) { + glBindTexture(this->_type, this->_id); + if(flags != 0) { + if((flags & S) != 0) { + glTexParameteri(this->_type, GL_TEXTURE_WRAP_S, wraping); + } + + if((flags & T) != 0) { + glTexParameteri(this->_type, GL_TEXTURE_WRAP_T, wraping); + } + + if((flags & R) != 0) { + glTexParameteri(this->_type, GL_TEXTURE_WRAP_R, wraping); + } + } + } + + void Texture::setSmoothing(bool state) { + glBindTexture(this->_type, this->_id); + glTexParameteri(this->_type, GL_TEXTURE_MIN_FILTER, state ? GL_LINEAR : GL_NEAREST); + glTexParameteri(this->_type, GL_TEXTURE_MAG_FILTER, state ? GL_LINEAR : GL_NEAREST); + } + + void Texture::store(GLsizei width, GLsizei height, const void * data, GLuint format) { + if(this->valide()) { + glDeleteTextures(1, &this->_id); + glGenTextures(1, &this->_id); + } + + glBindTexture(this->_type, this->_id); + glTexImage2D(this->_type, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(this->_type); + this->setWraping(CLAMP_TO_BORDER, S | T ); + this->setSmoothing(false); + } + + bool Texture::valide() const { + return this->_id != 0; + } + + bool Texture::operator==(const Texture & texture) const { + return this->_id == texture._id; + } + + bool Texture::operator!=(const Texture & texture) const { + return this->_id != texture._id; + } + + bool Texture::operator>=(const Texture & texture) const { + return this->_id >= texture._id; + } + + bool Texture::operator<=(const Texture & texture) const { + return this->_id <= texture._id; + } + + bool Texture::operator>(const Texture & texture) const { + return this->_id > texture._id; + } + + bool Texture::operator<(const Texture & texture) const { + return this->_id < texture._id; + } + + std::strong_ordering Texture::operator<=>(const Texture & texture) const { + return this->_id <=> texture._id; + } + + void Texture::Unbind(GLuint type) { + glBindTexture(type, 0); + } +} \ No newline at end of file diff --git a/source/engine/graphics/back/textures/Texture.hpp b/source/engine/graphics/back/textures/Texture.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4eabc13b9944ecd2c949b23b8f27e18b67e7f5eb --- /dev/null +++ b/source/engine/graphics/back/textures/Texture.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include <GL/glew.h> +#include <compare> + +namespace megu { + class Texture { + private: + GLuint _id; + GLuint _type; + mutable GLuint _slot; + + public: + Texture(GLuint = 0, GLuint = GL_TEXTURE_2D); + Texture(const Texture &) = delete; + Texture & operator=(const Texture &) = delete; + ~Texture(); + + enum Wraping { + REPEAT = GL_REPEAT, + MIRRORED_REPEAT = GL_MIRRORED_REPEAT, + CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER, + CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE + }; + + enum Axis { + S = 1, + T = 2, + R = 4 + }; + + enum Format { + AUTO, + RGB = GL_RGB, + BGR = GL_BGR, + RGBA = GL_RGBA, + RED = GL_RED, + GREEN = GL_GREEN, + BLUE = GL_BLUE, + }; + + void bind() const; + void bind(GLuint) const; + + GLint width() const; + GLint height() const; + + inline GLuint slot() const {return this->_slot;} + inline GLuint type() const {return this->_type;} + inline GLuint identifier() const {return this->_id;} + + void changeTextureSlot(GLuint); + void setWraping(Wraping, uint32_t = S | T); + void setSmoothing(bool); + + void store(GLsizei, GLsizei, const void *, GLuint = RGBA); + bool valide() const; + + bool operator==(const Texture &) const; + bool operator!=(const Texture &) const; + bool operator>=(const Texture &) const; + bool operator<=(const Texture &) const; + bool operator>(const Texture &) const; + bool operator<(const Texture &) const; + + std::strong_ordering operator<=>(const Texture &) const; + + static void Unbind(GLuint = GL_TEXTURE_2D); + + + }; +} \ No newline at end of file diff --git a/source/engine/graphics/errors.hpp b/source/engine/graphics/errors.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c1dac55a2fbf545389d09d22bc9387cc3900d33b --- /dev/null +++ b/source/engine/graphics/errors.hpp @@ -0,0 +1,4 @@ +#pragma once + +#include "./errors/OpenGL_Error.hpp" +#include "./errors/Shader_Error.hpp" \ No newline at end of file diff --git a/source/engine/graphics/errors/OpenGL_Error.cpp b/source/engine/graphics/errors/OpenGL_Error.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6eb1910641032679b8a74bd02622a3a928d98781 --- /dev/null +++ b/source/engine/graphics/errors/OpenGL_Error.cpp @@ -0,0 +1,56 @@ +#include "OpenGL_Error.hpp" + +namespace megu::error { + opengl_error::opengl_error() + : opengl_error(glGetError()) {} + + opengl_error::opengl_error(GLenum code) + : _code(code) {} + + opengl_error::~opengl_error() {} + + const char * opengl_error::what() const noexcept { + switch (this->_code) { + case GL_NO_ERROR: + return "GL NO ERROR"; + + case GL_INVALID_ENUM: + return "GL INVALIDE ENUM"; + + case GL_INVALID_VALUE: + return "GL INVALID VALUE"; + + case GL_INVALID_OPERATION: + return "GL INVALID OPERATION"; + + case GL_STACK_OVERFLOW: + return "GL STACK OVERFLOW"; + + case GL_STACK_UNDERFLOW: + return "GL STACK UNDERFLOW"; + + case GL_OUT_OF_MEMORY: + return "GL OUT OF MEMORY"; + + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "GL INVALID FRAMEBUFFER OPERATION"; + + case GL_CONTEXT_LOST: + return "GL CONTEXT LOST"; + + default: + return "UNKNOWN GL ERROR"; + } + } + + void opengl_error::check(bool throws, std::ostream & os, const std::source_location & location) { + GLenum error = glGetError(); + if(error != GL_NO_ERROR) { + error::opengl_error exception(error); + if(throws) { + throw exception; + } + std::cerr << location.file_name() << "(" << location.line() << " : " << location.column() << ") : " << exception.what() << std::endl; + } + } +} \ No newline at end of file diff --git a/source/engine/graphics/errors/OpenGL_Error.hpp b/source/engine/graphics/errors/OpenGL_Error.hpp new file mode 100644 index 0000000000000000000000000000000000000000..341200a4ccd2311b190b475bb824b9406c72bef3 --- /dev/null +++ b/source/engine/graphics/errors/OpenGL_Error.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include <exception> +#include <GL/glew.h> +#include <iostream> +#include <source_location> + +namespace megu::error { + class opengl_error : public std::exception { + private: + GLenum _code; + + public: + opengl_error(); + opengl_error(GLenum error); + ~opengl_error(); + + virtual const char * what() const noexcept; + static void check(bool = false, std::ostream & = std::cerr, const std::source_location & = std::source_location::current()); + }; + + +} \ No newline at end of file diff --git a/source/engine/graphics/errors/Shader_Error.cpp b/source/engine/graphics/errors/Shader_Error.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed864f0b3b5b5d87c4548e10cedfab39969c9a3b --- /dev/null +++ b/source/engine/graphics/errors/Shader_Error.cpp @@ -0,0 +1,19 @@ +#include "Shader_Error.hpp" + +#include <iostream> +#include <sstream> + +namespace megu::error { + shader_error::shader_error(const char * message, const std::filesystem::path * path) + : _message(message) { + + this->_message = (path != nullptr ? std::filesystem::canonical(*path).string() + " : \n " : "Unknow : \n"); + this->_message.append(message); + } + + shader_error::~shader_error() {} + + const char * shader_error::what() const noexcept { + return this->_message.c_str(); + } +} \ No newline at end of file diff --git a/source/engine/graphics/errors/Shader_Error.hpp b/source/engine/graphics/errors/Shader_Error.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e98ac904a36420b56ba5465299a0a6e9be9484ac --- /dev/null +++ b/source/engine/graphics/errors/Shader_Error.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include <exception> +#include <string> +#include <source_location> + +#include "../back/shaders/Source.hpp" + +namespace megu::error { + class shader_error : public std::exception { + private: + std::string _message; + + public: + shader_error() = delete; + shader_error(const char *, const std::filesystem::path * = nullptr); + virtual ~shader_error(); + + virtual const char * what() const noexcept; + }; +} diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65dc652fb31193956f9ca609f5cc0ee16aa8e746 --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,6 @@ +#include <iostream> + +int main(int argc, const char * argv[]) { + std::cout << "Hello World !" << std::endl; + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000000000000000000000000000000000000..ade0a95183bb2ebcdbe220e91ab34ac57ebd38d7 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,15 @@ +{ + "dependencies": [ + "opengl", + "glew", + "glfw3", + "glm", + { + "name": "imgui", + "features": [ + "opengl3-binding", + "glfw-binding" + ] + } + ] +} \ No newline at end of file