diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e21f8c..0f2c2cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,15 +24,6 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(NB_TARGET_LINUX ON) endif() -find_package(OpenGL) -add_subdirectory(../glfw ../glfw/build) - -include_directories(../glfw/include ../glad/include) - -set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) -set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) -set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) - if(NB_BUILD_TESTS) message(STATUS "Building tests") enable_testing() @@ -61,4 +52,11 @@ elseif (NB_TARGET_LINUX) add_compile_definitions(_NB_TARGET_LINUX) endif() +# External Dep paths +set(GLFW_PATH ../glfw/) +set(GLAD_PATH ../glad/) + +get_filename_component(GLFW_PATH ${GLFW_PATH} ABSOLUTE) +get_filename_component(GLAD_PATH ${GLAD_PATH} ABSOLUTE) + add_subdirectory(./engine) diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index ffbd7cd..c511c71 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -1,3 +1,3 @@ add_subdirectory(./NBCore) add_subdirectory(./NBEvents) -add_subdirectory(./NBWindow) \ No newline at end of file +add_subdirectory(./NBGraphics) \ No newline at end of file diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index dbeea5a..1deed87 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -1,8 +1,15 @@ +#include + #include "Logger.hpp" namespace nb { -nb::DefaultDebugLogger logger; -//logger.run(); +nb::DefaultDebugLogger logger(std::cout); + +static bool RUN_LOGGER(nb::DefaultDebugLogger& log) { + return log.run(); +} + +static const bool LOGGER_RUNNING = RUN_LOGGER(logger); } // namespace nb \ No newline at end of file diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 9a68c74..7d79ee9 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -35,5 +35,4 @@ TEST(ErrorTest, Test) { ASSERT_TRUE(nb::logger.isRunning()); nb::logger.log("Hey!"); - std::cout << "STRINGSTREAM:\n" << sstream.str(); } \ No newline at end of file diff --git a/engine/NBGraphics/Buffers.hpp b/engine/NBGraphics/Buffers.hpp new file mode 100644 index 0000000..1c57fe6 --- /dev/null +++ b/engine/NBGraphics/Buffers.hpp @@ -0,0 +1,320 @@ +#pragma once +#ifndef _NB_BUFFER +#define _NB_BUFFER + +#include "GLLoad.hpp" + +#include +#include +#include +#include + +#include "NBCore/Errors.hpp" + +namespace nb { + +typedef std::vector RawVec; + +static uint8_t GLSLTypeSize(GLenum type) { + switch(type) { + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_HALF_FLOAT: + return 2; + break; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + return 4; + break; + case GL_DOUBLE: + return 8; + break; + default: + return 1; + break; + } +} + +struct VertexAttributePointer { + GLuint buffer = 0; + int32_t offset = 0; + GLsizei stride = -1; + GLuint divisor = 0; +}; + +struct VertexAttribute { + GLint GLSLSize; + GLenum GLSLType; + GLboolean GLSLNormalization; + VertexAttributePointer ptr; +}; + +static bool isIndexInVertexAttribute(int i, const VertexAttribute& va) { + if ((i -= va.ptr.offset) < 0) { return false; } + return (i%va.ptr.stride) < GLSLTypeSize(va.GLSLType) * va.GLSLSize; +} + +typedef std::vector VertexAttributeList; + +template +RawVec vectorToRaw(const std::vector& vec) { + unsigned int num_bytes = vec.size() * sizeof(T); + RawVec ret(num_bytes); + memcpy(ret.data(), vec.data(), num_bytes); + return ret; +} + +template +RawVec concatVectorsToRaw(const std::vector& vec1, const std::vector& vec2) { + RawVec vec1_raw = vectorToRaw(vec1); + RawVec vec2_raw = vectorToRaw(vec2); + unsigned int vec1_raw_size = vec1_raw.size(); + unsigned int vec2_raw_size = vec2_raw.size(); + RawVec ret(vec1_raw_size + vec2_raw_size); + memcpy(ret.data(), vec1_raw.data(), vec1_raw_size); + memcpy(ret.data() + vec1_raw_size, vec2_raw.data(), vec2_raw_size); + return ret; +} + +template +std::vector rawToVector(const RawVec& vec) { + if (vec.size() % sizeof(T) != 0) { + throw std::runtime_error("Data size does not align to std::vector<" + std::string(typeid(T).name()) + ">."); + } + unsigned int num_elmts = vec.size() / sizeof(T); + std::vector ret(num_elmts); + memcpy(ret.data(), vec.data(), vec.size()); + + return ret; +} + +class BufferError : public std::runtime_error { +public: + const bool error; + BufferError(const std::string& msg, const std::string& file="", int line=-1) + : std::runtime_error(NB::formatDebugString(msg, file, line)), error(true) {} + BufferError(bool isError=true) : std::runtime_error(""), error(isError) {} +}; + + +template +class OpenGLObject { +public: + ~OpenGLObject() { remove(); } + + virtual void bind() const = 0; + virtual void unbind() const = 0; + virtual bool isInitialized() const = 0; + GLuint id() const { return _id; } + +protected: + OpenGLObject() = default; + OpenGLObject(const OpenGLObject& rhs) = delete; + OpenGLObject& operator=(const OpenGLObject& rhs) = delete; + + virtual void remove() const = 0; + + GLuint _id; +}; + +template +class Buffer : OpenGLObject> { +public: + using Base = OpenGLObject; + using Base::Base; + using BufferType::BufferType; + using BufferType::GLTarget; + + void bind() const { glBindBuffer(GLTarget, _id); } + void unbind() const { glBindBuffer(GLTarget, 0); } + +protected: + using Base::_id; + +}; + +/* +class Buffer : public OpenGLObject { +public: + Buffer( + GLenum buffer_type, + GLenum usage=GL_STATIC_DRAW + ) : _type(buffer_type), _usage(usage) { + glGenBuffers(1, &_id); + } + Buffer( + const RawVec& init_data, + GLenum buffer_type, + GLenum usage=GL_STATIC_DRAW + ) : _type{buffer_type}, _usage{usage} { data(init_data); } + Buffer( + unsigned int size, + GLenum buffer_type, + GLenum usage=GL_STATIC_DRAW + ) : Buffer(RawVec(size), buffer_type, usage) {} + + Buffer(Buffer&& rhs) { *this = std::move(rhs); } + Buffer& operator=(Buffer&& rhs) { + remove(); + _usage = rhs._usage; + _id = rhs._id; + rhs._id = 0; + return *this; + } + + GLenum usage() const { return _usage; } + unsigned int id() const { return _id; } + GLuint size() const { return _size; } + bool isInitialized() const override { return _id && glIsBuffer(_id) && bool(_size); } + RawVec data() const { + RawVec ret(_size); + bind(); + glGetBufferSubData(_type, 0, _size, ret.data()); + return ret; + } + void bind() const override { glBindBuffer(_type, _id); } + void unbind() const override { glBindBuffer(_type, 0); } + + GLenum usage(GLenum usage) { + _usage=usage; + data(data()); + return _usage; + } + void data(const RawVec& set_data) { + if (!glfwGetCurrentContext()) { + THROW_BUFFER_ERROR("No OpenGL context."); + } + bind(); + glBufferData(_type, set_data.size(), set_data.data(), _usage); + _size = set_data.size(); + } + void data(const RawVec& newData, unsigned int offset) { + if (newData.size()+offset > _size) { + THROW_BUFFER_ERROR("Attempting to overflow buffer of capacity " + std::to_string(_size) + "."); + } + bind(); + glBufferSubData(_type, offset, newData.size(), newData.data()); + } + void data(void* src, unsigned int offset, unsigned int size) { + if (size+offset > _size) { + THROW_BUFFER_ERROR("Attempting to overflow buffer of capacity " + std::to_string(_size) + "."); + } + bind(); + glBufferSubData(_type, offset, size, src); + } + +protected: + virtual void remove() const override { + unbind(); + if (_id) { glDeleteBuffers(1, &_id); } + } + + using OpenGLObject::_id; + GLenum _type; + GLenum _usage; + unsigned int _size = 0; +}; + + +class Texture : public OpenGLObject { +public: + Texture(GLenum tar=GL_TEXTURE_2D) : _target(tar) { glGenTextures(1, &_id); } + + Texture(Texture&& rhs) { *this=std::move(rhs); } + Texture& operator=(Texture&& rhs) { + _target = rhs._target; + _id = rhs._id; + rhs._id = 0; + return *this; + } + + void bind() const override { glBindTexture(_target, _id); } + void unbind() const override { glBindTexture(_target, 0); } + bool isInitialized() const override { return _id && glIsTexture(_id); } + +protected: + using OpenGLObject::_id; + GLenum _target; +}; + +class Framebuffer : public OpenGLObject { +public: + + Framebuffer(GLenum tar=GL_FRAMEBUFFER) : _target(tar) { glGenFramebuffers(1, &_id); } + + Framebuffer(Framebuffer&& rhs) { *this=std::move(rhs); } + Framebuffer& operator=(Framebuffer&& rhs) { + remove(); + _target = rhs._target; + _id = rhs._id; + rhs._id = 0; + return *this; + } + + void bind() const override { glBindFramebuffer(_target, _id); } + void unbind() const override { glBindFramebuffer(_target, 0); } + bool isInitialized() const override { return _id && glIsFramebuffer(_id); } + GLenum status() const { + bind(); + return glCheckFramebufferStatus(_target); + } + + +protected: + virtual void remove() const override { + unbind(); + if (_id) { glDeleteFramebuffers(1, &_id); } + } + using OpenGLObject::_id; + GLenum _target; +}; + +class Renderbuffer : public OpenGLObject { +public: + Renderbuffer(unsigned int x, unsigned int y, GLenum format=GL_RGBA32F, unsigned int multi=0) : Renderbuffer() { + storage(x, y, format, multi); + } + Renderbuffer() { glGenRenderbuffers(1, &_id); } + + + Renderbuffer(Renderbuffer&& rhs) { *this = std::move(rhs); } + Renderbuffer& operator=(Renderbuffer&& rhs) { + _format = rhs._format; + _id = rhs._id; + rhs._id = 0; + return *this; + } + + virtual void bind() const override { glBindRenderbuffer(GL_RENDERBUFFER, _id); } + virtual void unbind() const override { glBindRenderbuffer(GL_RENDERBUFFER, _id); } + virtual bool isInitialized() const override { return _id && glIsRenderbuffer(_id); } + + void storage(unsigned int x, unsigned int y, GLenum format=GL_RGBA32F, unsigned int multi=0) { + _sizex = x; + _sizey = y; + _format = format; + _multisample = multi; + bind(); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, _multisample, _format, _sizex, _sizey); + } + + +protected: + virtual void remove() const override { + unbind(); + if (_id) { glDeleteRenderbuffers(1, &_id); } + } + + using OpenGLObject::_id; + GLenum _format; + unsigned int _sizex{0}; + unsigned int _sizey{0}; + unsigned int _multisample{0}; + +}; + +*/ + +} // namespace NB +#endif // _NB_BUFFER diff --git a/engine/NBGraphics/CMakeLists.txt b/engine/NBGraphics/CMakeLists.txt new file mode 100644 index 0000000..32fa24f --- /dev/null +++ b/engine/NBGraphics/CMakeLists.txt @@ -0,0 +1,18 @@ +include_directories(./.) +include_directories(./..) + +find_package(OpenGL) +add_subdirectory(${GLFW_PATH} ${GLFW_PATH}/build) + +include_directories(${GLFW_PATH}/include ${GLAD_PATH}/include) + +set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) +set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) +set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) + +add_library(NBGraphics + ./src/Window.cpp + ./src/Buffers.cpp + ${GLAD_PATH}/src/glad.c +) +target_link_libraries(NBGraphics glfw3) diff --git a/engine/NBGraphics/Camera.hpp b/engine/NBGraphics/Camera.hpp new file mode 100644 index 0000000..35e109d --- /dev/null +++ b/engine/NBGraphics/Camera.hpp @@ -0,0 +1,151 @@ +#pragma once +#ifndef _NB_CAMERA +#define _NB_CAMERA + +#include +#include +#include +#include +#include + +namespace NB { + +class Camera { +public: + typedef glm::vec3 Vec3; + typedef glm::mat4 Mat4; + + enum CameraTypeEnum : unsigned char { + None, + Orthographic, + Perspective + }; + + const CameraTypeEnum CameraType = CameraTypeEnum::None; + + static Vec3 normCross(const Vec3&, const Vec3&); + static Vec3 transformVec(const Mat4&, const Vec3&); + + Camera( + const Vec3& pos=Vec3(0.0f, 0.0f, -1.0f), + const Vec3& tar=Vec3(0.0f, 0.0f, 0.0f), + const Vec3& up =Vec3(0.0f, 1.0f, 0.0f) + ); + + + Vec3 getPos() const; + Vec3 getTarget() const; + Vec3 getDirection() const; + Vec3 getWorldUp() const; + Vec3 getUp() const; + Vec3 getRight() const; + Mat4 getViewMatrix() const; + Mat4 getProjectionMatrix() const; + Mat4 getFlattenedMatrices() const; + bool isUpLocked() const; + + void setProjection(const Mat4&); + void setPos(const Vec3&); + void setTarget(const Vec3&); + void setDirection(const Vec3&); + void setWorldUp(const Vec3&); + void lockToWorldUp(bool lock); + void resetUp(); + void addPos(const Vec3&); + void panPos(const Vec3&); + void panPosRelative(const Vec3&); + void addTarget(const Vec3&); + void roll(float); + void pitch(float); + void yaw(float); + +protected: + Vec3 _pos; + Vec3 _tar; + Vec3 _dir; + Vec3 _world_up; + Vec3 _up; + Vec3 _right; + Mat4 _view; + Mat4 _proj; + bool _lock_world_up = true; + + void _calcLook(); + +}; + +class OrthographicCamera : public Camera { +public: + const CameraTypeEnum CameraType = CameraTypeEnum::Orthographic; + + OrthographicCamera( + const Vec3& pos=Vec3(0.0f, 0.0f, -1.0f), + const Vec3& tar=Vec3(0.0f, 0.0f, 0.0f), + const Vec3& up =Vec3(0.0f, 1.0f, 0.0f), + float left = -1.0f, + float right = 1.0f, + float bottom = -1.0f, + float top = 1.0f, + float near = 0.001f, + float far = 1.0f + ); + + float getLeftPlane() const; + float getRightPlane() const; + float getBottomPlane() const; + float getTopPlane() const; + float getNearPlane() const; + float getFarPlane() const; + + void setLeftPlane(float); + void setRightPlane(float); + void setBottomPlane(float); + void setTopPlane(float); + void setNearPlane(float); + void setFarPlane(float); + void setOrthographicProjection(float left=-1.0, float right=1.0, float bottom=-1.0, float top=1.0, float near=.001, float far=1.0); + void setViewingVolume(float width, float height, float depth); + +protected: + float _leftPlane, _rightPlane, _topPlane, _bottomPlane, _nearPlane, _farPlane; + + void _calcView(); + using Camera::setProjection; + +}; + +class PerspectiveCamera : public Camera { +public: + const CameraTypeEnum CameraType = CameraTypeEnum::Perspective; + + PerspectiveCamera( + const Vec3& pos=Vec3(0.0f, 0.0f, -1.0f), + const Vec3& tar=Vec3(0.0f, 0.0f, 0.0f), + const Vec3& up =Vec3(0.0f, 1.0f, 0.0f), + float fov = 45.0f, + float aspectRatio = 1.0f, + float near = 0.001f, + float far = 1.0f + ); + + float getFOV() const; + float getAspectRatio() const; + float getNearPlane() const; + float getFarPlane() const; + + void setFOV(float); + void setAspectRatio(float); + void setNearPlane(float); + void setFarPlane(float); + void setPerspectiveProjection(float fov=45, float aspectRatio=1.0f, float near=0.001f, float far=1.0f); + +protected: + float _fov, _ratio, _nearPlane, _farPlane; + + void _calcView(); + using Camera::setProjection; + +}; + +} +#endif // _NB_CAMERA \ No newline at end of file diff --git a/engine/NBGraphics/Draw.hpp b/engine/NBGraphics/Draw.hpp new file mode 100644 index 0000000..a9be811 --- /dev/null +++ b/engine/NBGraphics/Draw.hpp @@ -0,0 +1,84 @@ +#pragma once +#ifndef _NB_DRAW +#define _NB_DRAW + +#include + +#include +#include +#include +#include + +#include "Buffers.h" +#include "Shader.h" +#include "VAOManager.hpp" + +#define THROW_DRAW_ERROR(msg) throw DrawError(msg, __FILE__, __LINE__); + +namespace NB{ + +class DrawError : public std::runtime_error { +public: + DrawError(const std::string&, const std::string& file="", int line=-1); +}; + +uint8_t VerticesFromPrimitives(GLenum, unsigned int num_prims=1); + +uint8_t PrimitivesFromVertices(GLenum, unsigned int); + +void copyVertexAttribute(const VertexAttribute&, VertexAttribute&); + +class DrawBuffer { +public: +typedef std::shared_ptr BufferManagerPointer; + DrawBuffer(VertexAttributeList, GLenum prim_type=GL_TRIANGLES); + //DrawBuffer(std::initializer_list, std::initializer_list); + + unsigned int vertSize() const; + const std::shared_ptr shader() const; + unsigned int elementBufferID() const; + unsigned int vertexBufferID() const; + virtual void draw() const; + RawVec vertAttrData(unsigned int); + + VertexAttributeList changeVertLayout(unsigned int, VertexAttributePointer); + RawVec vertAttrData(unsigned int, const RawVec&); + virtual void elementData(const std::vector&); + virtual void elementData(unsigned int); + virtual void elementData(const std::vector&, unsigned int offset); + virtual void vertexData(const RawVec&); + virtual void vertexData(unsigned int num_verts); + virtual void vertexData(const RawVec&, unsigned int offset); + + BufferManagerPointer _vert_data; + BufferManagerPointer _elmt_data; + VAOManager _VAO; + const GLenum _gl_primitive_type=0; + virtual VertexAttributeList defaultVAO(VertexAttributeList); + + unsigned int _num_verts, _num_prims; +protected: +}; + +class DrawInstanceBuffer : public DrawBuffer { +public: + DrawInstanceBuffer(VertexAttributeList, VertexAttributeList, GLenum primt_type=GL_TRIANGLES); + + unsigned int instSize() const; + unsigned int instanceBufferID() const; + virtual void draw() const override; + + VertexAttributeList changeInstanceLayout(unsigned int, VertexAttributePointer); + virtual void instanceData(const RawVec&); + virtual void instanceData(unsigned int); + virtual void instanceData(const RawVec&, unsigned int offset); + + BufferManagerPointer _inst_data; + virtual VertexAttributeList defaultVAO(VertexAttributeList); + unsigned int _num_inst; + +protected: +}; + +} +#endif \ No newline at end of file diff --git a/engine/NBWindow/GLLoad.h b/engine/NBGraphics/GLLoad.hpp similarity index 100% rename from engine/NBWindow/GLLoad.h rename to engine/NBGraphics/GLLoad.hpp diff --git a/engine/NBGraphics/VAOManager.hpp b/engine/NBGraphics/VAOManager.hpp new file mode 100644 index 0000000..142882c --- /dev/null +++ b/engine/NBGraphics/VAOManager.hpp @@ -0,0 +1,75 @@ +#pragma once +#ifndef _NB_VAO_MANAGER +#define _NB_VAO_MANAGER + +#include + +#include +#include +#include + +#include "Buffers.h" + +#define THROW_VAO_ERROR(msg) throw VAOError(msg, __FILE__, __LINE__); + +namespace NB { + +class VAOError : public std::runtime_error { +public: + const bool error; + VAOError(const std::string& msg, const std::string& file="", int line=-1) + : std::runtime_error(NB::formatDebugString(msg, file, line)), error(true) {} + VAOError(bool isError=true) : std::runtime_error(""), error(isError) {} +}; + +class VAOManager : public OpenGLObject { +public: + typedef std::shared_ptr BufferManagerPointer; + //typedef BufferManager BufferManagerPointer; + + VAOManager(); + VAOManager( + std::vector, + BufferManagerPointer elmt_buf = nullptr, + const VertexAttributeList& vert_attrs = {} + ); + VAOManager( + BufferManagerPointer vert_bufs, + BufferManagerPointer elmt_buf = nullptr, + const VertexAttributeList& vert_attrs = {} + ) : VAOManager(std::vector(1, vert_bufs), elmt_buf, vert_attrs) {} + + VAOManager(VAOManager&& rhs); + VAOManager& operator=(VAOManager&& rhs); + + VertexAttributeList getLayout() const; + GLuint id() const; + unsigned int vertSize(GLuint) const; + std::vector getVertexBuffers() const; + bool isInitialized() const override; + RawVec attributeData(unsigned int); + + RawVec attributeData(unsigned int, const RawVec&); + void bind() const; + void unbind() const; + void addVBO(BufferManagerPointer); + void changeEBO(BufferManagerPointer); + VertexAttributeList addVertexAttributes(const VertexAttributeList&); + VertexAttributeList addVertexAttributes(VertexAttribute); + VertexAttributeList generate(); + VertexAttributeList generate(VertexAttributeList); + VertexAttributeList changeLayout(unsigned int, VertexAttributePointer); + + VAOError checkValid(const VertexAttributeList&); + +private: + void remove() const override; + + using OpenGLObject::_id; + std::map _vert_buffers; + BufferManagerPointer _elmt_buffer = nullptr; + VertexAttributeList _vert_attrs; +}; + +} // namespace NB +#endif // _NB_VAO_MANAGER \ No newline at end of file diff --git a/engine/NBWindow/Window.h b/engine/NBGraphics/Window.hpp similarity index 98% rename from engine/NBWindow/Window.h rename to engine/NBGraphics/Window.hpp index a5843cb..4cc787d 100644 --- a/engine/NBWindow/Window.h +++ b/engine/NBGraphics/Window.hpp @@ -2,7 +2,7 @@ #ifndef _NB_WINDOW #define _NB_WINDOW -#include "GLLoad.h" +#include "GLLoad.hpp" #include #include diff --git a/engine/NBGraphics/shader.hpp b/engine/NBGraphics/shader.hpp new file mode 100644 index 0000000..ca92fe3 --- /dev/null +++ b/engine/NBGraphics/shader.hpp @@ -0,0 +1,193 @@ +#pragma once +#ifndef _NB_SHADER +#define _NB_SHADER + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// #define _PREPROC_FUNC_PARAMS_ (const ShaderPreprocessor&, ShaderUnit&, unsigned int, const std::string&, std::vector&) + +namespace NB { + +class ShaderPreprocessorError : public std::runtime_error { +public: + enum Codes : unsigned char { + NONE, + FILE_NOT_FOUND, + BUILTIN_NOT_FOUND, + CUSTOM, + UNDEFINED + }; + + const Codes code; + + ShaderPreprocessorError(const std::string&, const std::string& file="", int line=-1); + ShaderPreprocessorError(Codes, const std::string& arg="", const std::string& file="", int line=-1); + +protected: + static std::string errorCodeParser(Codes, const std::string& arg=""); +}; + +class ShaderError : public std::runtime_error { +public: + ShaderError(const std::string&, const char* shad=nullptr, const std::string& file="", int line=-1); + +protected: + std::string formatString(const std::string&, const char* shad=nullptr, const std::string& file="", int line=-1); +}; + +struct File { + // typedef std::tuple FilePath; + struct FilePath { + std::string dir; + std::string basename; + std::string ext; + }; + FilePath path; + std::stringstream src; + std::map> include_map; + + File() {} + File(const File& rhs) { *this = rhs; } + + File& operator=(const File& rhs) { + path = rhs.path; + src.str(""); + src << rhs.src.rdbuf(); + include_map = rhs.include_map; + return *this; + } +}; + +// File::FilePath get_file_path(std::string); + +class ShaderPreprocessor; + +enum OpenGLProfiles { + Core, + Compatibility, + ES +}; + +struct ShaderUnit { + GLenum type = 0x0; + File file; + std::string preprocSource; + std::map defines; + short vMajor=0, vMinor=0; + OpenGLProfiles profile = Core; +}; + +class ShaderPreprocessor; + +class ShaderProgram { + friend ShaderPreprocessor; +public: + ShaderProgram() {} + ShaderProgram(const ShaderProgram& rhs) = delete; + ShaderProgram(ShaderProgram&& rhs); + + ~ShaderProgram(); + + ShaderProgram& operator=(const ShaderProgram& rhs) = delete; + ShaderProgram& operator=(ShaderProgram&& rhs); + + std::vector getShaders() const; + ShaderUnit getShaders(unsigned int) const; + void use() const; + unsigned int id() const; + + void setBool(const std::string& name, bool value) const; + void setInt(const std::string& name, int value) const; + void setUnsigned(const std::string& name, int value) const; + void setFloat(const std::string& name, float value) const; + void setMat4(const std::string& name, glm::mat4& value) const; + + static ShaderProgram CreateShaderProgram(std::vector&); + +private: + ShaderProgram(std::vector& shaders) : _shader_units(shaders){} + + std::vector _shader_units; + unsigned int _id; +}; + +class ShaderPreprocessor { +public: + typedef ShaderPreprocessorError::Codes Codes; + + enum TokenType { + TK, + DR, + WS, + NL, + LC, + BC + }; + static std::string TokenName(const TokenType&); + + std::map AcceptedExtensions = { + {".frag", GL_FRAGMENT_SHADER}, + {".fs", GL_FRAGMENT_SHADER}, + {".vert", GL_VERTEX_SHADER}, + {".vs", GL_VERTEX_SHADER}, + {".tess", 0x0}, + {".geom", GL_GEOMETRY_SHADER}, + {".comp", 0x0}, + {".shad", 0x0}, + {".glsl", 0x0} + }; + std::map AcceptedProfiles { + {"core", Core}, + {"compatibility", Compatibility}, + {"es", ES} + }; + std::vector Directories; + std::map BuiltIns; + + ShaderPreprocessor(); + + + File load(const std::string, bool builtin_first=false) const; + ShaderUnit& preprocess(const std::string&, ShaderUnit&) const; + ShaderUnit preprocess(File, GLenum shader_type=0x0) const; + ShaderUnit preprocess(const std::string&, GLenum shader_type=0x0) const; + ShaderProgram ReloadFromFile(const ShaderProgram& rhs) const; + ShaderProgram CreateShaderProgram(std::vector) const; + +private: + typedef std::pair Token; + typedef std::vector StringVec; + + inline bool directive_dispatch(ShaderUnit&, const std::string&) const; + inline std::vector tokenize(const std::string&) const; + + inline bool preprocessor_include(ShaderUnit&, const StringVec&, const std::string&) const; + inline bool preprocessor_version(ShaderUnit&, const StringVec&, const std::string&) const; + inline bool preprocessor_define(ShaderUnit&, const StringVec&, const std::string&) const; + // inline bool preprocessor_uniform(ShaderUnit&, const std::string&, const std::string&) const; + + File loadFromBase(const std::string, const std::string base="") const; + File loadFromDirectories(const std::string) const; + File loadFromBuiltIn(const std::string) const; + File load_BuiltInFirst(const std::string) const; + File load_FilesFirst(const std::string) const; +}; + +} +#endif \ No newline at end of file diff --git a/engine/NBGraphics/src/Buffers.cpp b/engine/NBGraphics/src/Buffers.cpp new file mode 100644 index 0000000..24f9115 --- /dev/null +++ b/engine/NBGraphics/src/Buffers.cpp @@ -0,0 +1,5 @@ +#include "Buffers.hpp" + +namespace nb { + +} \ No newline at end of file diff --git a/engine/NBGraphics/src/Camera.cpp b/engine/NBGraphics/src/Camera.cpp new file mode 100644 index 0000000..8431597 --- /dev/null +++ b/engine/NBGraphics/src/Camera.cpp @@ -0,0 +1,272 @@ +#include "Camera.h" +namespace NB { + +// Camera class +Camera::Camera(const Vec3& pos, const Vec3& tar, const Vec3& up) { + _pos = pos; + _tar = tar; + _world_up = glm::normalize(up); + _dir = glm::normalize(_tar-_pos); + _right = normCross(_dir, _world_up); + _up = normCross(_right, _dir); + _proj = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); + _calcLook(); +} + +void Camera::_calcLook() { + _view = glm::lookAt(_pos, _tar, (_lock_world_up)?_world_up:_up); +} + +glm::vec3 Camera::normCross(const Vec3& a, const Vec3& b) { + return glm::normalize(glm::cross(a, b)); +} + +glm::vec3 Camera::transformVec(const Mat4& mat, const Vec3& vec) { + return Vec3(mat * glm::vec4(vec, 1.0f)); +} + +glm::vec3 Camera::getPos() const { return _pos; } + +glm::vec3 Camera::getTarget() const { return _tar; } + +glm::vec3 Camera::getDirection() const { return _dir; } + +glm::vec3 Camera::getWorldUp() const { return _world_up; } + +glm::vec3 Camera::getUp() const { return _up; } + +glm::vec3 Camera::getRight() const { return _right; } + +glm::mat4 Camera::getViewMatrix() const { return _view; } + +glm::mat4 Camera::getProjectionMatrix() const { return _proj; } + +glm::mat4 Camera::getFlattenedMatrices() const { return _proj * _view; } + +bool Camera::isUpLocked() const { return _lock_world_up; } + +void Camera::setProjection(const Mat4& proj) { + _proj = proj; +} + +void Camera::setPos(const Vec3& pos) { + _pos = pos; + _calcLook(); +} + +void Camera::setTarget(const Vec3& tar) { + _tar = tar; + _dir = glm::normalize(_tar-_pos); + _right = normCross(_dir, _world_up); + _up = normCross(_right, _dir); + _calcLook(); +} + +void Camera::setDirection(const Vec3& dir) { + setTarget(glm::normalize(dir)+_pos); +} + +void Camera::setWorldUp(const Vec3& up) { + _world_up = up; + _right = normCross(_dir, _up); + _up = normCross(_right, _dir); + _calcLook(); +} + +void Camera::lockToWorldUp(bool lock) { + if (!_lock_world_up && lock) { + resetUp(); + } + _lock_world_up = lock; +} + +void Camera::resetUp() { + _right = normCross(_dir, _world_up); + _up = normCross(_right, _dir); + _calcLook(); +} + +void Camera::addPos(const Vec3& add) { + _pos += add; + _dir = glm::normalize(_tar-_pos); + if (_lock_world_up) { + _right = normCross(_dir, _world_up); + } else { + _right = normCross(_dir, _up); + _up = normCross(_right, _dir); + } + _calcLook(); +} + +void Camera::panPos(const Vec3& add) { + _tar += add; + addPos(add); +} + +void Camera::panPosRelative(const Vec3& add) { + panPos(add.x*_right + add.y*((_lock_world_up)?_world_up:_up) + add.z*_dir); +} + +void Camera::addTarget(const Vec3& add) { + _tar += add; + _dir = glm::normalize(_tar-_pos); + _right = normCross(_dir, _world_up); + _up = normCross(_right, _dir); + _calcLook(); +} + +void Camera::roll(float ang) { + if (!_lock_world_up) { + Mat4 rot_mat = glm::rotate(Mat4(1.0f), ang, _dir); + _right = transformVec(rot_mat, _right); + _up = transformVec(rot_mat, _up); + _calcLook(); + } +} + +void Camera::pitch(float ang) { + Mat4 rot_mat = glm::rotate(Mat4(1.0f), ang, _right); + _dir = transformVec(rot_mat, _dir); + _up = transformVec(rot_mat, _up); + _tar = _pos + _dir; + _calcLook(); +} + +void Camera::yaw(float ang) { + Mat4 rot_mat = glm::rotate(Mat4(1.0f), ang, ((_lock_world_up)?_world_up:_up)); + _dir = transformVec(rot_mat, _dir); + _right = transformVec(rot_mat, _right); + _up = normCross(_right, _dir); + _tar = _pos + _dir; + _calcLook(); +} + +// OrthographicCamera class +OrthographicCamera::OrthographicCamera( + const Vec3& pos, + const Vec3& tar, + const Vec3& up, + float left, + float right, + float bottom, + float top, + float near, + float far +) : Camera(pos, tar, up), _leftPlane(left), _rightPlane(right), _bottomPlane(bottom), _topPlane(top), _nearPlane(near), _farPlane(far) { + _calcView(); +} + +void OrthographicCamera::_calcView() { + setProjection(glm::ortho(_leftPlane, _rightPlane, _bottomPlane, _topPlane, _nearPlane, _farPlane)); +} + +float OrthographicCamera::getLeftPlane() const { return _leftPlane; } + +float OrthographicCamera::getRightPlane() const { return _rightPlane; } + +float OrthographicCamera::getBottomPlane() const { return _bottomPlane; } + +float OrthographicCamera::getTopPlane() const { return _topPlane; } + +float OrthographicCamera::getNearPlane() const { return _nearPlane; } + +float OrthographicCamera::getFarPlane() const { return _farPlane; } + +void OrthographicCamera::setLeftPlane(float left) { + _leftPlane = left; + _calcView(); +} + +void OrthographicCamera::setRightPlane(float right) { + _rightPlane = right; + _calcView(); +} + +void OrthographicCamera::setBottomPlane(float bottom) { + _bottomPlane = bottom; + _calcView(); +} + +void OrthographicCamera::setTopPlane(float top) { + _topPlane = top; + _calcView(); +} + +void OrthographicCamera::setNearPlane(float near) { + _nearPlane = near; + _calcView(); +} + +void OrthographicCamera::setFarPlane(float far) { + _farPlane = far; + _calcView(); +} + +void OrthographicCamera::setOrthographicProjection(float left, float right, float bottom, float top, float near, float far) { + _leftPlane = left; + _rightPlane = right; + _bottomPlane = bottom; + _topPlane = top; + _nearPlane = near; + _farPlane = far; + _calcView(); +} + +void OrthographicCamera::setViewingVolume(float width, float height, float depth) { + setOrthographicProjection(width/-2.0, width/2.0, height/-2.0, height/2.0, 0.01, depth); +} + +// PerspectiveCamera class +PerspectiveCamera::PerspectiveCamera( + const Vec3& pos, + const Vec3& tar, + const Vec3& up , + float fov, + float aspectRatio, + float near, + float far +) : Camera(pos, tar, up), _fov(fov), _ratio(aspectRatio), _nearPlane(near), _farPlane(far) { + _calcView(); +} + +void PerspectiveCamera::_calcView() { + setProjection(glm::perspective(glm::radians(_fov), _ratio, _nearPlane, _farPlane)); +} + +float PerspectiveCamera::getFOV() const { return _fov; } + +float PerspectiveCamera::getAspectRatio() const { return _ratio; } + +float PerspectiveCamera::getNearPlane() const { return _nearPlane; } + +float PerspectiveCamera::getFarPlane() const { return _farPlane; } + +void PerspectiveCamera::setFOV(float fov) { + _fov = fov; + _calcView(); +} + +void PerspectiveCamera::setAspectRatio(float aspectRatio) { + _ratio = aspectRatio; + _calcView(); +} + +void PerspectiveCamera::setNearPlane(float near) { + _nearPlane = near; + _calcView(); +} + +void PerspectiveCamera::setFarPlane(float far) { + _farPlane = far; + _calcView(); +} + +void PerspectiveCamera::setPerspectiveProjection(float fov, float aspectRatio, float near, float far) { + _fov = fov; + _ratio = aspectRatio; + _nearPlane = near; + _farPlane = far; + _calcView(); +} + +} \ No newline at end of file diff --git a/engine/NBGraphics/src/Draw.cpp b/engine/NBGraphics/src/Draw.cpp new file mode 100644 index 0000000..dc3fc05 --- /dev/null +++ b/engine/NBGraphics/src/Draw.cpp @@ -0,0 +1,307 @@ +#include "Draw.h" + +namespace NB{ + +DrawError::DrawError( + const std::string& msg, + const std::string& file, + int line) : std::runtime_error(NB::formatDebugString(msg, file, line)) {} + +uint8_t VerticesFromPrimitives(GLenum type, unsigned int num_prims) { + switch(type) { + case GL_POINTS: + return num_prims; + case GL_LINES: + return num_prims*2; + break; + case GL_LINE_STRIP: + return num_prims+1; + break; + case GL_LINE_LOOP: + return num_prims; + break; + case GL_TRIANGLES: + return num_prims*3; + break; + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + return num_prims+2; + break; + case GL_QUADS: + return 4*num_prims; + break; + case GL_QUAD_STRIP: + return 2*num_prims+2; + break; + default: + return num_prims; + break; + } +} + +uint8_t PrimitivesFromVertices(GLenum type, unsigned int num_verts) { + switch(type) { + case GL_POINTS: + return num_verts; + case GL_LINES: + return num_verts/2; + break; + case GL_LINE_STRIP: + return num_verts-1; + break; + case GL_LINE_LOOP: + return num_verts; + break; + case GL_TRIANGLES: + return num_verts/3; + break; + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + return num_verts-2; + break; + case GL_QUADS: + return num_verts/4; + break; + case GL_QUAD_STRIP: + return num_verts/2 - 1; + break; + default: + return num_verts; + break; + } +} + + +// DrawBuffer class +DrawBuffer::DrawBuffer(VertexAttributeList vas, GLenum prim_type) +: _gl_primitive_type(prim_type), _VAO() { + _vert_data = std::make_shared(GL_ARRAY_BUFFER); + _elmt_data = std::make_shared(GL_ELEMENT_ARRAY_BUFFER); + _VAO.addVBO(_vert_data); + _VAO.changeEBO(_elmt_data); + try { + throw _VAO.checkValid(vas); + } catch (VAOError vaoe) { + if (vaoe.error) { + _VAO.addVertexAttributes(DrawBuffer::defaultVAO(vas)); + } else { + _VAO.addVertexAttributes(vas); + } + } +} + +VertexAttributeList DrawBuffer::defaultVAO(VertexAttributeList vert_attrs) { + GLuint vert_id = _vert_data->id(); + unsigned int vert_size = 0; + for (const VertexAttribute& va : vert_attrs) { + vert_size += va.GLSLSize * GLSLTypeSize(va.GLSLType); + } + unsigned int curr_byte = 0; + for (VertexAttribute& va : vert_attrs) { + va.ptr.buffer = vert_id; + va.ptr.stride = vert_size; + va.ptr.offset = curr_byte; + va.ptr.divisor = 0; + curr_byte += va.GLSLSize * GLSLTypeSize(va.GLSLType); + } + return vert_attrs; +} + +VertexAttributeList DrawBuffer::changeVertLayout(unsigned int i, VertexAttributePointer vap) { + GLuint vert_id = _vert_data->id(); + vap.buffer = (vap.buffer) ? vap.buffer : vert_id; + VertexAttributeList vas = _VAO.getLayout(); + unsigned int idx = 0; + for (const VertexAttribute& va : vas) { + if (va.ptr.buffer == vert_id) { + if (idx == i) { + return _VAO.changeLayout(i, vap); + } + idx++; + } + } + THROW_DRAW_ERROR("Could not find vertex attribute with index " + std::to_string(i)); +} + +unsigned int DrawBuffer::vertSize() const { return _VAO.vertSize(_vert_data->id()); } + +void DrawBuffer::draw() const { + _VAO.bind(); + glDrawElements(_gl_primitive_type, _elmt_data->size() / GLSLTypeSize(GL_INT), GL_UNSIGNED_INT, 0); + _VAO.unbind(); +} + +unsigned int DrawBuffer::elementBufferID() const { return _elmt_data->id(); } + +unsigned int DrawBuffer::vertexBufferID() const { return _vert_data->id(); } + +RawVec DrawBuffer::vertAttrData(unsigned int i) { + if (!_vert_data->isInitialized()) { + throw DrawError("Vertex buffer is not initialized."); + } + return _VAO.attributeData(i); +} + +RawVec DrawBuffer::vertAttrData(unsigned int i, const RawVec& newdata) { + if (!(_vert_data->isInitialized())) { + VertexAttribute va = _VAO.getLayout()[i]; + vertexData(newdata.size() / (va.GLSLSize*GLSLTypeSize(va.GLSLType))); + std::cout << "From DrawBuffer::vertAttrData(int, RawVec) - vert buf size: " << _vert_data->size() << "\n"; + } + return _VAO.attributeData(i, newdata); +} + +void DrawBuffer::elementData(unsigned int num_prims) { + elementData(std::vector(VerticesFromPrimitives(_gl_primitive_type, num_prims))); +} + +void DrawBuffer::elementData(const std::vector& elements) { + _num_prims = PrimitivesFromVertices(_gl_primitive_type, elements.size()); + _elmt_data->data(vectorToRaw(elements)); +} + +void DrawBuffer::elementData(const std::vector& elements, unsigned int offset) { + _VAO.bind(); + if (!_elmt_data->isInitialized()) { + std::vector init_elmts(elements); + init_elmts.insert(init_elmts.cbegin(), offset, 0); + elementData(init_elmts, 0); + } else { + _elmt_data->data(vectorToRaw(elements), offset); + } + _VAO.unbind(); +} + +void DrawBuffer::vertexData(unsigned int num_verts) { + vertexData(RawVec(num_verts * vertSize())); +} + +void DrawBuffer::vertexData(const RawVec& vert_data) { + // Check for uninitialized Vertex Pointers. If so, will fallback to default VAO setup. + // Otherwise, set VAO to provided Vertex Atributes. + int vert_size = vertSize(); + if (vert_data.size() % vert_size != 0) { + THROW_DRAW_ERROR("Initializing data does not match vertex size of " + std::to_string(vert_size) + "."); + } + _num_verts = vert_data.size() / vert_size; + // TODO: Make it not static draw all the time + + _VAO.bind(); + _vert_data->data(vert_data); + _VAO.unbind(); +} + +void DrawBuffer::vertexData(const RawVec& data, unsigned int offset) { + _VAO.bind(); + if (!_vert_data->isInitialized()) { + RawVec load_data(offset); + load_data.insert(load_data.end(), data.begin(), data.end()); + vertexData(load_data, 0); + } else { + try{ + _vert_data->data(data, offset); + } catch(BufferError& e) { + THROW_DRAW_ERROR("NB::BufferError in loadVBO:\n\t" + std::string(e.what())); + } + } + _VAO.unbind(); +} + +// DrawInstanceBufferClass +DrawInstanceBuffer::DrawInstanceBuffer( + VertexAttributeList vert_vas, + VertexAttributeList inst_vas, + GLenum prim_type +): DrawBuffer(vert_vas, prim_type) { + _inst_data = std::make_shared(GL_ARRAY_BUFFER); + _VAO.addVBO(_inst_data); + try { + throw _VAO.checkValid(inst_vas); + } catch (VAOError vaoe) { + if (vaoe.error) { + _VAO.addVertexAttributes(defaultVAO(inst_vas)); + } else { + _VAO.addVertexAttributes(inst_vas); + } + } +} + +unsigned int DrawInstanceBuffer::instSize() const { return _VAO.vertSize(_inst_data->id()); } + +unsigned int DrawInstanceBuffer::instanceBufferID() const { return _inst_data->id(); } + +void DrawInstanceBuffer::instanceData(unsigned int num_inst) { + instanceData(RawVec(instSize() * num_inst)); +} + +void DrawInstanceBuffer::instanceData(const RawVec& inst_data) { + int inst_size = instSize(); + if (inst_data.size() % inst_size != 0) { + THROW_DRAW_ERROR("Initializing data does not match instance size of " + std::to_string(inst_size) + "."); + } + _num_inst = inst_data.size() / inst_size; + + _VAO.bind(); + _inst_data->data(inst_data); + _VAO.unbind(); +} + +void DrawInstanceBuffer::instanceData(const RawVec& data, unsigned int offset) { + _VAO.bind(); + if (!_inst_data->isInitialized()) { + RawVec load_data(offset); + load_data.insert(load_data.end(), data.begin(), data.end()); + instanceData(load_data, 0); + } else { + try{ + _inst_data->data(data, offset); + } catch(BufferError& e) { + THROW_DRAW_ERROR("NB::BufferError in loadIBO:\n\t" + std::string(e.what())); + } + } + _VAO.unbind(); +} + +VertexAttributeList DrawInstanceBuffer::defaultVAO(VertexAttributeList inst_attrs) { + GLuint inst_id = _inst_data->id(); + unsigned int vert_size = 0; + for (const VertexAttribute& va : inst_attrs) { + vert_size += va.GLSLSize * GLSLTypeSize(va.GLSLType); + } + unsigned int curr_byte = 0; + for (VertexAttribute& va : inst_attrs) { + va.ptr.buffer = inst_id; + va.ptr.stride = vert_size; + va.ptr.offset = curr_byte; + va.ptr.divisor = 1; + curr_byte += va.GLSLSize * GLSLTypeSize(va.GLSLType); + } + return inst_attrs; +} + +VertexAttributeList DrawInstanceBuffer::changeInstanceLayout(unsigned int i, VertexAttributePointer vap) { + GLuint inst_id = _inst_data->id(); + vap.buffer = (vap.buffer) ? vap.buffer : inst_id; + VertexAttributeList vas = _VAO.getLayout(); + unsigned int vas_size = vas.size(); + unsigned int inst_idx = 0; + unsigned int idx = 0; + for (const VertexAttribute& va : vas) { + if (va.ptr.buffer == inst_id) { + if (inst_idx == i) { + return _VAO.changeLayout(idx, vap); + } + inst_idx++; + } + idx++; + } + THROW_DRAW_ERROR("Could not find instance attribute with index " + std::to_string(i)); +} + +void DrawInstanceBuffer::draw() const { + _VAO.bind(); + glDrawElementsInstanced(_gl_primitive_type, _elmt_data->size() / GLSLTypeSize(GL_UNSIGNED_INT), GL_UNSIGNED_INT, (void*)_elmt_data->id(), _num_inst); + _VAO.unbind(); +} + +} \ No newline at end of file diff --git a/engine/NBGraphics/src/VAOManager.cpp b/engine/NBGraphics/src/VAOManager.cpp new file mode 100644 index 0000000..c9ea7d5 --- /dev/null +++ b/engine/NBGraphics/src/VAOManager.cpp @@ -0,0 +1,225 @@ +#include "VAOManager.hpp" + +namespace NB { + +using BufferManagerPointer = std::shared_ptr; + +VAOManager::VAOManager() { glGenVertexArrays(1, &_id); } + +VAOManager::VAOManager( + std::vector vert_bufs, + BufferManagerPointer elmt_buf, + const VertexAttributeList& vert_attrs +) : VAOManager() { + _elmt_buffer = elmt_buf; + for (BufferManagerPointer vb : vert_bufs) { + _vert_buffers[vb->id()] = vb; + } + if (vert_attrs.size()!=0) { + generate(vert_attrs); + } +} + +VAOManager::VAOManager(VAOManager&& rhs) { *this = std::move(rhs); } + +VAOManager& VAOManager::operator=(VAOManager&& rhs) { + remove(); + _vert_buffers = rhs._vert_buffers; + _elmt_buffer = rhs._elmt_buffer; + _vert_attrs = rhs._vert_attrs; + return *this; +} + +VertexAttributeList VAOManager::getLayout() const { return _vert_attrs; } + +GLuint VAOManager::id() const { return _id; } + +bool VAOManager::isInitialized() const { + return _id && glIsVertexArray(_id); +} + +void VAOManager::remove() const { + bind(); + for (int i{0}; i < _vert_attrs.size(); ++i) { + glDisableVertexAttribArray(i); + } + unbind(); + glDisableVertexAttribArray(_id); +} + +unsigned int VAOManager::vertSize(GLuint id) const { + unsigned int size = 0; + for (const VertexAttribute& va : _vert_attrs) { + if (va.ptr.buffer == id) { + size += va.GLSLSize * GLSLTypeSize(va.GLSLType); + } + } + return size; +} + +std::vector VAOManager::getVertexBuffers() const { + std::vector ret; + for (const auto& i : _vert_buffers) { + ret.emplace_back(i.second); + } + return ret; +} + +RawVec VAOManager::attributeData(unsigned int i) { + if (i <= _vert_attrs.size()) { + throw std::out_of_range("No vertex attribute exists for specified index"); + } + VertexAttribute attr = _vert_attrs[i]; + BufferManagerPointer buffer = _vert_buffers[attr.ptr.buffer]; + RawVec data = buffer->data(); + unsigned int attr_size = attr.GLSLSize*GLSLTypeSize(attr.GLSLType); + RawVec ret((buffer->size()-attr.ptr.offset-attr_size)*attr_size/attr.ptr.stride); + int data_size = data.size(); + for (int i{0}; i < data_size; ++i) { + if (isIndexInVertexAttribute(i, attr)) { + ret[i] = data[i]; + } + } + return ret; +} + +RawVec VAOManager::attributeData(unsigned int i, const RawVec& new_data) { + if (i >= _vert_attrs.size()) { + throw std::out_of_range("No vertex attribute exists for specified index."); + } + VertexAttribute attr = _vert_attrs[i]; + BufferManagerPointer buffer = _vert_buffers[attr.ptr.buffer]; + unsigned int attr_size = attr.GLSLSize*GLSLTypeSize(attr.GLSLType); + unsigned int offset = attr.ptr.offset; + unsigned int num_verts = buffer->size() / vertSize(buffer->id()); + if (num_verts*attr_size != new_data.size()) { + // WHY HERE???? + THROW_VAO_ERROR( + "Input data size of " + std::to_string(new_data.size()) + + " does not match data size for requested vertex attribute of total size " + std::to_string(num_verts*attr_size) + + "." + ); + } + uint64_t pos = uint64_t(new_data.data()); + for (int i{0}; idata((void*)(pos+i*attr_size), offset+i*attr.ptr.stride, attr_size); + } + return RawVec(new_data); +} + +void VAOManager::bind() const { + glBindVertexArray(_id); + if (_elmt_buffer) { _elmt_buffer->bind(); } +} + +void VAOManager::unbind() const { + glBindVertexArray(0); + if (_elmt_buffer) { _elmt_buffer->unbind(); } +} + +void VAOManager::addVBO(BufferManagerPointer vert_buf) { + GLuint vert_id = vert_buf->id(); + if (_vert_buffers.find(vert_id) == _vert_buffers.end()) { + _vert_buffers[vert_buf->id()] = vert_buf; + } else { + THROW_VAO_ERROR("Attempting to add identical VBO id of " + std::to_string(vert_id) + "."); + } +} + +void VAOManager::changeEBO(BufferManagerPointer ebo) { + _elmt_buffer = ebo; +} + +VertexAttributeList VAOManager::addVertexAttributes(const VertexAttributeList& vert_attrs) { + VertexAttributeList curr_vas = _vert_attrs; + curr_vas.insert(curr_vas.end(), vert_attrs.begin(), vert_attrs.end()); + try { + throw checkValid(curr_vas); + } catch (VAOError vaoe) { + if (vaoe.error) { + THROW_VAO_ERROR(vaoe.what()); + } + } + _vert_attrs = curr_vas; + generate(); + return _vert_attrs; +} + +VertexAttributeList VAOManager::addVertexAttributes(VertexAttribute vert_attr) { + return addVertexAttributes({vert_attr}); +} + +VertexAttributeList VAOManager::generate() { + bind(); + unsigned int num_attrs = _vert_attrs.size(); + VertexAttribute* va; + for (int i = 0; i < num_attrs; ++i) { + va = &(_vert_attrs[i]); + _vert_buffers[va->ptr.buffer]->bind(); + glVertexAttribPointer( + i, + va->GLSLSize, + va->GLSLType, + va->GLSLNormalization, + va->ptr.stride, + (void*)va->ptr.offset + ); + glVertexAttribDivisor(i, va->ptr.divisor); + glEnableVertexAttribArray(i); + } + if (_elmt_buffer != nullptr) { + _elmt_buffer->bind(); + } + unbind(); + return _vert_attrs; +} + +VertexAttributeList VAOManager::generate(VertexAttributeList vert_attrs) { + try { + throw checkValid(vert_attrs); + } catch (VAOError vaoe) { + if (vaoe.error) { + THROW_VAO_ERROR(vaoe.what()); + } + } + _vert_attrs.swap(vert_attrs); + return generate(); +} + +VertexAttributeList VAOManager::changeLayout(unsigned int i, VertexAttributePointer vap) { + _vert_attrs[i].ptr = vap; + bind(); + const VertexAttribute* va = &(_vert_attrs[i]); + glDisableVertexAttribArray(i); + _vert_buffers[va->ptr.buffer]->bind(); + glVertexAttribPointer( + _id, + va->GLSLSize, + va->GLSLType, + va->GLSLNormalization, + va->ptr.stride, + (void*)va->ptr.offset + ); + glVertexAttribDivisor(i, va->ptr.divisor); + glEnableVertexAttribArray(i); + unbind(); + return _vert_attrs; +} + +VAOError VAOManager::checkValid(const VertexAttributeList& vert_attrs) { + GLuint va_id; + unsigned int num_attrs = vert_attrs.size(); + for (int i = 0; i < num_attrs; ++i) { + va_id = vert_attrs[i].ptr.buffer; + if (_vert_buffers.find(va_id) == _vert_buffers.cend()) { + return VAOError("Attempting to point to unknown VBO of id " + std::to_string(va_id) + + " at Vertex Attribute " + std::to_string(i) + "."); + } + if (vert_attrs[i].ptr.stride<0) { + return VAOError("Invalid stride value at Vertex Attribute " + std::to_string(i) + "."); + } + } + return VAOError(false); +} + +} // namespace NB diff --git a/engine/NBWindow/src/Window.cpp b/engine/NBGraphics/src/Window.cpp similarity index 99% rename from engine/NBWindow/src/Window.cpp rename to engine/NBGraphics/src/Window.cpp index 5791a7f..a1c7dbf 100644 --- a/engine/NBWindow/src/Window.cpp +++ b/engine/NBGraphics/src/Window.cpp @@ -1,4 +1,4 @@ -#include "Window.h" +#include "Window.hpp" namespace NB { std::map Window::WindowContexts = {}; diff --git a/engine/NBGraphics/src/shader.cpp b/engine/NBGraphics/src/shader.cpp new file mode 100644 index 0000000..f24d86e --- /dev/null +++ b/engine/NBGraphics/src/shader.cpp @@ -0,0 +1,742 @@ +#include "Shader.h" + +// #define _PREPROC_FUNC_PARAM_NAMES_ (const ShaderPreprocessor& proc, ShaderUnit& shad, unsigned int linenum, const std::string& line, std::vector& params) + +namespace NB{ + +File::FilePath get_file_path(std::string name) { + const std::vector allowed_special_chars = { + '.', '!', '#', '$', '%', '&', '\'', '(', ')', '+', ',', '-', ';', '=', '@', '[', ']', '^', '_', '`', '~' + }; + std::vector path = {""}; + for (const char c : name) { + if (c == '/' || c == '\\') { + path.push_back(""); + } else if (std::isalnum(c)) { + path.back() += c; + } else { + bool spec_char_found = false; + for (const char sc : allowed_special_chars) { + if (c == sc) { + path.back() += c; + spec_char_found = true; + break; + } + } + if (!spec_char_found) { + throw std::runtime_error("'" + name + "' is not valid filepath."); + } + } + } + File::FilePath ret; + for (const auto& tk : path) { + if (tk == path.back()) { + size_t period = tk.find("."); + if (period == std::string::npos) { + ret.basename = tk; + ret.ext = ""; + } else { + ret.basename = tk.substr(0, period); + ret.ext = tk.substr(period); + } + } else { + ret.dir += tk + "/"; + } + } + return ret; +} + +// ShaderPreprocessorError class +ShaderPreprocessorError::ShaderPreprocessorError( + const std::string& msg, + const std::string& file, + int line +) : code(Codes::UNDEFINED), std::runtime_error(formatDebugString(msg, file, line)) {} + +ShaderPreprocessorError::ShaderPreprocessorError( + Codes err_code, + const std::string& arg, + const std::string& file, + int line +) : code(err_code), std::runtime_error(formatDebugString(errorCodeParser(err_code, arg), file, line)) {} + +std::string ShaderPreprocessorError::errorCodeParser(Codes err_code, const std::string& arg) { + switch(err_code) { + case Codes::FILE_NOT_FOUND: + return "File '" + arg + "' not found."; + case Codes::BUILTIN_NOT_FOUND: + return "Built-in '" + arg + "' not found."; + case Codes::CUSTOM: + case Codes::UNDEFINED: + return arg; + case Codes::NONE: + default: + return ""; + } +} + +// ShaderError class +ShaderError::ShaderError( + const std::string& msg, + const char* shad, + const std::string& file, + int line +) : std::runtime_error(formatString(msg, shad, file, line)) {} + +std::string ShaderError::formatString( + const std::string& msg, + const char* shad, + const std::string& file, + int line +) { + std::stringstream ret; + if (file != "") { + ret << "In file " << file; + if (line >= 0) { + ret << " at line " << line; + } + ret << ":\n\t"; + } + ret << msg; + if (shad != nullptr) { + ret << " with shader error: " << shad; + } + return ret.str(); +} + +// ShaderPreprocessor class +std::string ShaderPreprocessor::TokenName(const ShaderPreprocessor::TokenType& x) { + switch(x) { + case TK: + return "Token"; + break; + case DR: + return "Directive"; + break; + case WS: + return "Whitespace"; + break; + case NL: + return "NewLine"; + break; + case LC: + return "LineComment"; + break; + case BC: + return "BlockComment"; + break; + default: + return "Unrecognized"; + break; + } +} + +ShaderPreprocessor::ShaderPreprocessor() {} + +File ShaderPreprocessor::loadFromBase(const std::string path, const std::string base) const { + File ret; + std::ifstream filestream; + filestream.open(base + path); + if (filestream.is_open()) { + ret.path = get_file_path(base + path); + ret.src << filestream.rdbuf(); + return ret; + } + filestream.close(); + std::string ext; + for (const auto& kv : AcceptedExtensions) { + ext = kv.first; + filestream.open(base + path + ext); + if (filestream.is_open()) { + ret.path = get_file_path(base + path + ext); + ret.src << filestream.rdbuf(); + return ret; + } + filestream.close(); + } + throw ShaderPreprocessorError(Codes::FILE_NOT_FOUND, base + path); +} + +File ShaderPreprocessor::loadFromDirectories(const std::string name) const { + File ret; + std::ifstream fstream; + for (const std::string& path : Directories) { + fstream.open(path + name); + if (fstream.is_open()) { + ret.path = get_file_path(path + name); + ret.src << fstream.rdbuf(); + return ret; + } + fstream.close(); + } + throw ShaderPreprocessorError(Codes::FILE_NOT_FOUND, name); +} + +File ShaderPreprocessor::load(const std::string path, bool builtin_first) const { + if(builtin_first) { + return load_BuiltInFirst(path); + } + return load_FilesFirst(path); +} + +File ShaderPreprocessor::loadFromBuiltIn(const std::string name) const { + File ret; + //std::stringstream ret; + decltype(BuiltIns)::const_iterator builtin_it = BuiltIns.find(name); + if (builtin_it != BuiltIns.end()) { + ret.path = File::FilePath{"builtin:", name, ""}; + ret.src << builtin_it->second; + return ret; + } + throw ShaderPreprocessorError(Codes::BUILTIN_NOT_FOUND, name); +} + +File ShaderPreprocessor::load_FilesFirst(const std::string path) const { + try { + return loadFromBase(path); + } catch (ShaderPreprocessorError e) { + if (e.code == Codes::FILE_NOT_FOUND) { + try { + return loadFromDirectories(path); + } catch (ShaderPreprocessorError f) { + if (f.code == Codes::FILE_NOT_FOUND) { + try { + return loadFromBuiltIn(path); + } catch(ShaderPreprocessorError g) { + if (g.code == Codes::BUILTIN_NOT_FOUND) { + throw ShaderPreprocessorError(Codes::FILE_NOT_FOUND, path); + } else { throw g; } + } + } else { throw f; } + } + } else { throw e; } + } +} + +File ShaderPreprocessor::load_BuiltInFirst(const std::string path) const { + try { + return loadFromBuiltIn(path); + } catch (ShaderPreprocessorError f) { + if (f.code == Codes::BUILTIN_NOT_FOUND) { + try { + return loadFromDirectories(path); + } catch (ShaderPreprocessorError e) { + if (e.code == Codes::FILE_NOT_FOUND) { + return loadFromBase(path); + } else { + throw e; + } + } + } else { + throw f; + } + } + +} + +std::vector ShaderPreprocessor::tokenize(const std::string& code) const { + enum State { + FSlash, + WhiteSpace, + LineComment, + BlockComment, + BlockCommentEndStar, + Directive, + Token + }; + + std::vector tks; + + std::string token = ""; + State state = WhiteSpace; + for(char c : code) { + if (c==13) { + continue; + } + switch(state) { + case WhiteSpace: + if (c=='/') { + if (token != "") { tks.push_back({WS, token}); } + token = c; + state = FSlash; + } else if (c=='#') { + if (token != "") { tks.push_back({WS, token}); } + token = c; + state = Directive; + } else if (c=='\n') { + if (token != "") { tks.push_back({WS, token}); } + tks.push_back({NL, "\n"}); + token = ""; + state = WhiteSpace; + } else if (std::isblank(c)) { + token += c; + } else { + if (token != "") { tks.push_back({WS, token}); } + token = c; + state = Token; + } + break; + case FSlash: + if (c=='/') { + token += c; + state = LineComment; + } else if (c=='*') { + token += c; + state = BlockComment; + } else if (c=='\n') { + tks.push_back({TK, token}); + tks.push_back({NL, "\n"}); + token = ""; + state = WhiteSpace; + } else if (std::isblank(c)) { + tks.push_back({TK, token}); + token = c; + }else { + token += c; + state = Token; + } + break; + case LineComment: + if (c=='\n') { + tks.push_back({LC, token}); + tks.push_back({NL, "\n"}); + token = ""; + state = WhiteSpace; + } else { + token += c; + } + break; + case BlockComment: + token += c; + if (c=='*') { + state = BlockCommentEndStar; + } + break; + case BlockCommentEndStar: + token += c; + if (c=='/') { + tks.push_back({BC, token}); + token = ""; + state = WhiteSpace; + } else { + state = BlockComment; + } + break; + case Directive: + if (c=='\n') { + tks.push_back({DR, token}); + tks.push_back({NL, "\n"}); + token = ""; + state = WhiteSpace; + } else if (c=='/') { + tks.push_back({DR, token}); + token = c; + state = FSlash; + } else { + token += c; + } + break; + case Token: + if (c=='\n') { + tks.push_back({TK, token}); + tks.push_back({NL, "\n"}); + token = ""; + state = WhiteSpace; + } else if (std::isblank(c)) { + tks.push_back({TK, token}); + token = c; + state = WhiteSpace; + } else if (c=='/') { + tks.push_back({TK, token}); + token = c; + state = FSlash; + }else { + token += c; + } + break; + default: + break; + } + + } + + switch(state) { + case WhiteSpace: + if (token != "") { tks.push_back({WS, token}); } + case FSlash: + tks.push_back({TK, token}); + break; + case LineComment: + tks.push_back({LC, token}); + break; + case BlockComment: + case BlockCommentEndStar: + tks.push_back({BC, token}); + break; + case Directive: + tks.push_back({DR, token}); + break; + case Token: + tks.push_back({TK, token}); + break; + default: + break; + } + + return tks; +} + +ShaderUnit& ShaderPreprocessor::preprocess(const std::string& code, ShaderUnit& shad) const { + typedef ShaderPreprocessor::Token Token; + std::vector tks = tokenize(code); + + for (int i{0}; i < tks.size(); ++i) { + switch(tks[i].first) { + case DR: + directive_dispatch(shad, tks[i].second); + break; + case TK: + case NL: + case LC: + case BC: + case WS: + default: + shad.preprocSource += tks[i].second; + break; + } + } + + if (shad.vMajor == 0 && shad.vMinor == 0) { + shad.vMajor = 1; + shad.vMinor = 10; + } + return shad; +} + +ShaderUnit ShaderPreprocessor::preprocess(File file, GLenum shader_type) const { + ShaderUnit ret; + ret.file = file; + if (shader_type) { + ret.type = shader_type; + } else { + decltype(AcceptedExtensions.begin()) find_type = AcceptedExtensions.find(file.path.ext); + if (find_type != AcceptedExtensions.end()) { + ret.type = find_type->second; + } + } + preprocess(file.src.str(), ret); + return ret; +} + +ShaderUnit ShaderPreprocessor::preprocess(const std::string& code, GLenum shader_type) const { + File local; + local.path = File::FilePath{"live:", "live", ".shad"}; + return preprocess(local, shader_type); +} + +ShaderProgram ShaderPreprocessor::CreateShaderProgram(std::vector shads) const { + std::vector _shader_units; + for (const auto& name : shads) { + _shader_units.push_back(preprocess(load(name))); + } + return ShaderProgram::CreateShaderProgram(_shader_units); +} + +ShaderProgram ShaderPreprocessor::ReloadFromFile(const ShaderProgram& rhs) const { + std::vector shader_names; + shader_names.reserve(rhs._shader_units.size()); + std::string filename; + for (const ShaderUnit& shad : rhs._shader_units) { + filename = shad.file.path.dir + shad.file.path.basename + shad.file.path.ext; + shader_names.emplace_back(filename); + } + return CreateShaderProgram(shader_names); +} + +bool ShaderPreprocessor::directive_dispatch(ShaderUnit& shad, const std::string& line) const { + StringVec dir_tks = {""}; + for (char c : line) { + if (std::isblank(c)) { + if (dir_tks.back() != "") { + dir_tks.push_back(""); + } + } else { + dir_tks.back() += c; + } + } + if (!dir_tks.size()) { return false; } + + if (dir_tks[0][0] != '#') { return false; } + + if (dir_tks[0] == "#define") { + return preprocessor_define(shad, dir_tks, line); + } else if (dir_tks[0] == "#version") { + return preprocessor_version(shad, dir_tks, line); + } else if (dir_tks[0] == "#include") { + return preprocessor_include(shad, dir_tks, line); + } + return false; +} + +typedef std::vector StringVec; + +bool ShaderPreprocessor::preprocessor_include( + ShaderUnit& shad, + const StringVec& tokens, + const std::string& line +) const +{ + try { + if (tokens[0] != "#include") { return false; } + } catch (std::out_of_range e) { + return false; + } + std::string path = ""; + for (const auto& tk : tokens) { + if (tk != tokens.front()) { + path += tk; + } + } + // Add file-inclusion base + + // Do path cleanup + + // Restructure preprocessing data flow + std::string filename = path.substr(1, path.size()-2); + try { + if (path[0] == '"' && path.back() == '"') { + preprocess(load(filename).src.str(), shad); + return true; + } else if (path[0] == '<' && path.back() == '>') { + preprocess(load(filename, true).src.str(), shad); + return true; + } + } catch (ShaderPreprocessorError e) { + if (e.code == Codes::FILE_NOT_FOUND) { + std::cout << "COULD NOT FIND " << filename << ".\n"; + } else { + throw e; + } + } + return false; +} + +bool ShaderPreprocessor::preprocessor_define(ShaderUnit& shad, const StringVec& tokens, const std::string& line) const { + shad.preprocSource += line; + try { + if (tokens[0] != "#define") { return false; } + try { + shad.defines[tokens[1]] = tokens[2]; + } catch (std::length_error& f) { + shad.defines[tokens[1]] = ""; + } + return true; + } catch (std::out_of_range& e) { + return false; + } +} + +bool ShaderPreprocessor::preprocessor_version(ShaderUnit& shad, const StringVec& tokens, const std::string& line) const { + shad.preprocSource += line; + std::cout << "Shader version: "; + try { + if (tokens[0] != "#version") { return false; } + if (tokens[1].size() == 3) { + short vMajor = tokens[1][0]-'0'; + short vMinorA = tokens[1][1]-'0'; + short vMinorB = tokens[1][2]-'0'; + if (vMajor > 10 || vMinorA > 10 || vMinorB > 10) { + return false; + } + shad.vMajor = vMajor; + shad.vMinor = vMinorA*10 + vMinorB; + shad.profile = AcceptedProfiles.at(tokens[2]); + std::cout << shad.vMajor << "." << shad.vMinor << "\n"; + return true; + } else { + return false; + } + } catch (std::out_of_range& e) { + return false; + } +} + + +/* bool ShaderPreprocessor::preprocessor_uniform( + ShaderUnit& shad, + const std::string& type, + const std::string& name +) const { + std::string type_str = ""; + unsigned int type_str_len = 0; + for (const char& c : type) { + if (type_str_len) { + if (std::isdigit(c)) { + type_str += c; + continue; + } else if (c=='[') { + type_str += '_'; + }else if (c == ']' || std::isblank(c)){ + continue; + } else { + return false; + } + } else { + if (std::isalnum(c)) { + type_str += c; + continue; + } else if (c == '[') { + type_str_len = type_str.length(); + type_str += '_'; + continue; + } else { + return false; + } + } + } + std::string name_str = ""; + unsigned int name_str_len = 0; + for (const char& c : name) { + if (c == ';') { + break; + } + if (name_str_len) { + if (std::isdigit(c)) { + type_str.insert(type_str_len, 1, c); + type_str_len++; + continue; + } else if (c=='[') { + type_str.insert(type_str_len, "_"); + type_str_len++; + continue; + }else if (c == ']' || std::isblank(c)){ + continue; + } else { + return false; + } + } else { + if (std::isalnum(c)) { + name_str += c; + continue; + } else if ( c == '[') { + name_str_len = name_str.length(); + type_str.insert(type_str_len, "_"); + type_str_len++; + continue; + } else { + return false; + } + } + } + shad.uniforms.push_back(UniformHandle{ + name_str, + type_str, + 0x0, + 0x0 + }); + return true; +} */ + + +// ShaderProgram + +ShaderProgram::ShaderProgram(ShaderProgram&& rhs) { + _shader_units = rhs._shader_units; + _id = rhs._id; + rhs._id = 0; +} + +ShaderProgram::~ShaderProgram() { + glDeleteProgram(_id); +} + +ShaderProgram& ShaderProgram::operator=(ShaderProgram&& rhs) { + _shader_units = rhs._shader_units; + _id = rhs._id; + rhs._id = 0; + return *this; +} + + +ShaderProgram ShaderProgram::CreateShaderProgram(std::vector& shaders) { + int success; + ShaderProgram ret(shaders); + char infoLog[512]; + unsigned int shad_id; + std::vector shad_ids; + shad_ids.reserve(shaders.size()); + for (auto& shad : ret._shader_units) { + const char* source = shad.preprocSource.data(); + shad_id = glCreateShader(shad.type); + shad_ids.emplace_back(shad_id); + glShaderSource(shad_id, 1, &source, NULL); + glCompileShader(shad_id); + glGetShaderiv(shad_id, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(shad_id, 512, NULL, infoLog); + File::FilePath& fp = shad.file.path; + std::string filename = fp.dir + fp.basename + fp.ext; + // std::cout << "Could not compile '" + filename + "': " << infoLog << "\n"; + // return *ret; + throw ShaderError("Could not compile '" + filename + "'.", infoLog); + } + } + + ret._id = glCreateProgram(); + for(auto& id : shad_ids) { + glAttachShader(ret._id, id); + } + glLinkProgram(ret._id); + glGetProgramiv(ret._id, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(ret._id, 512, NULL, infoLog); + throw ShaderError("Could not link shader program.", infoLog); + } + for (auto& id : shad_ids) { + glDeleteShader(id); + } + return ret; +} + +unsigned int ShaderProgram::id() const { return _id; } + +void ShaderProgram::use() const { + glUseProgram(_id); +} + +std::vector ShaderProgram::getShaders() const { + return _shader_units; +} + +ShaderUnit ShaderProgram::getShaders(unsigned int idx) const { + return _shader_units[idx]; +} + +void ShaderProgram::setBool(const std::string& name, bool value) const { + glUniform1i(glGetUniformLocation(_id, name.c_str()), (int)value); +} + +void ShaderProgram::setInt(const std::string& name, int value) const { + glUniform1i(glGetUniformLocation(_id, name.c_str()), (int)value); +} + +void ShaderProgram::setFloat(const std::string& name, float value) const { + glUniform1f(glGetUniformLocation(_id, name.c_str()), (int)value); +} + +void ShaderProgram::setMat4(const std::string& name, glm::mat4& value) const { + glUniformMatrix4fv(glGetUniformLocation(_id, name.c_str()), 1, GL_FALSE, glm::value_ptr(value)); +} + +/* // Shader class +Shader::Shader() { _id = 0x0; } + +Shader::Shader(const Shader& cpy_shader) { _id = cpy_shader._id; } + +Shader& Shader::operator=(const Shader& cpy_shader) { _id = cpy_shader._id; return *this; } + +void Shader::use() const{ + glUseProgram(_id); +} + +*/ + +} \ No newline at end of file diff --git a/engine/NBWindow/CMakeLists.txt b/engine/NBWindow/CMakeLists.txt deleted file mode 100644 index a500676..0000000 --- a/engine/NBWindow/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -include_directories(./.) - - -add_library(NBWindow - ./src/Window.cpp - ./../../../glad/src/glad.c -) -target_link_libraries(NBWindow glfw)