From 60072c1d8089ffd3294e76636198d14710be95b8 Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Sat, 9 Sep 2017 07:55:22 +0100 Subject: Restructuring --- CMakeLists.txt | 91 +-- include/YAGE/Math/math.h | 14 - include/YAGE/Math/matrix.h | 424 ----------- include/YAGE/Physics/README.org | 27 - include/YAGE/Physics/body.h | 56 -- include/YAGE/Physics/collider.h | 43 -- include/YAGE/Physics/collisionbody.h | 28 - include/YAGE/Physics/particlebody.h | 33 - include/YAGE/Physics/physics.h | 19 - include/YAGE/Physics/rectanglecollider.h | 30 - include/YAGE/Physics/rigidbody.h | 28 - include/YAGE/camera2d.h | 38 - include/YAGE/glslprogram.h | 52 -- include/YAGE/imageloader.h | 27 - include/YAGE/inputmanager.h | 28 - include/YAGE/iomanager.h | 27 - include/YAGE/picopng.h | 20 - include/YAGE/resourcemanager.h | 31 - include/YAGE/sprite.h | 52 -- include/YAGE/spritebatch.h | 105 --- include/YAGE/spritesheet.h | 25 - include/YAGE/texture.h | 25 - include/YAGE/texturecache.h | 32 - include/YAGE/vertex.h | 84 --- include/YAGE/window.h | 55 -- include/YAGE/yage.h | 63 -- src/body.cpp | 34 - src/camera2d.cpp | 45 -- src/glslprogram.cpp | 162 ----- src/imageloader.cpp | 60 -- src/inputmanager.cpp | 33 - src/iomanager.cpp | 42 -- src/particlebody.cpp | 54 -- src/picopng.cpp | 1118 ------------------------------ src/rectanglecollider.cpp | 36 - src/resourcemanager.cpp | 21 - src/rigidbody.cpp | 20 - src/sprite.cpp | 97 --- src/spritebatch.cpp | 193 ------ src/texturecache.cpp | 30 - src/window.cpp | 97 --- yage/CMakeLists.txt | 33 + yage/base/CMakeLists.txt | 13 + yage/base/camera2d.cpp | 45 ++ yage/base/camera2d.h | 38 + yage/base/glslprogram.cpp | 162 +++++ yage/base/glslprogram.h | 52 ++ yage/base/imageloader.cpp | 60 ++ yage/base/imageloader.h | 27 + yage/base/inputmanager.cpp | 33 + yage/base/inputmanager.h | 28 + yage/base/iomanager.cpp | 42 ++ yage/base/iomanager.h | 27 + yage/base/picopng.cpp | 1118 ++++++++++++++++++++++++++++++ yage/base/picopng.h | 20 + yage/base/resourcemanager.cpp | 21 + yage/base/resourcemanager.h | 31 + yage/base/sprite.cpp | 97 +++ yage/base/sprite.h | 52 ++ yage/base/spritebatch.cpp | 193 ++++++ yage/base/spritebatch.h | 105 +++ yage/base/spritesheet.h | 25 + yage/base/texture.h | 25 + yage/base/texturecache.cpp | 30 + yage/base/texturecache.h | 32 + yage/base/vertex.h | 84 +++ yage/base/window.cpp | 97 +++ yage/base/window.h | 55 ++ yage/math/CMakeLists.txt | 1 + yage/math/math.h | 14 + yage/math/matrix.h | 424 +++++++++++ yage/physics/CMakeLists.txt | 6 + yage/physics/README.org | 27 + yage/physics/body.cpp | 34 + yage/physics/body.h | 56 ++ yage/physics/collider.h | 43 ++ yage/physics/collisionbody.h | 28 + yage/physics/particlebody.cpp | 54 ++ yage/physics/particlebody.h | 33 + yage/physics/physics.h | 19 + yage/physics/rectanglecollider.cpp | 36 + yage/physics/rectanglecollider.h | 30 + yage/physics/rigidbody.cpp | 20 + yage/physics/rigidbody.h | 28 + yage/yage.h | 63 ++ 85 files changed, 3489 insertions(+), 3471 deletions(-) delete mode 100644 include/YAGE/Math/math.h delete mode 100644 include/YAGE/Math/matrix.h delete mode 100644 include/YAGE/Physics/README.org delete mode 100644 include/YAGE/Physics/body.h delete mode 100644 include/YAGE/Physics/collider.h delete mode 100644 include/YAGE/Physics/collisionbody.h delete mode 100644 include/YAGE/Physics/particlebody.h delete mode 100644 include/YAGE/Physics/physics.h delete mode 100644 include/YAGE/Physics/rectanglecollider.h delete mode 100644 include/YAGE/Physics/rigidbody.h delete mode 100644 include/YAGE/camera2d.h delete mode 100644 include/YAGE/glslprogram.h delete mode 100644 include/YAGE/imageloader.h delete mode 100644 include/YAGE/inputmanager.h delete mode 100644 include/YAGE/iomanager.h delete mode 100644 include/YAGE/picopng.h delete mode 100644 include/YAGE/resourcemanager.h delete mode 100644 include/YAGE/sprite.h delete mode 100644 include/YAGE/spritebatch.h delete mode 100644 include/YAGE/spritesheet.h delete mode 100644 include/YAGE/texture.h delete mode 100644 include/YAGE/texturecache.h delete mode 100644 include/YAGE/vertex.h delete mode 100644 include/YAGE/window.h delete mode 100644 include/YAGE/yage.h delete mode 100644 src/body.cpp delete mode 100644 src/camera2d.cpp delete mode 100644 src/glslprogram.cpp delete mode 100644 src/imageloader.cpp delete mode 100644 src/inputmanager.cpp delete mode 100644 src/iomanager.cpp delete mode 100644 src/particlebody.cpp delete mode 100644 src/picopng.cpp delete mode 100644 src/rectanglecollider.cpp delete mode 100644 src/resourcemanager.cpp delete mode 100644 src/rigidbody.cpp delete mode 100644 src/sprite.cpp delete mode 100644 src/spritebatch.cpp delete mode 100644 src/texturecache.cpp delete mode 100644 src/window.cpp create mode 100644 yage/CMakeLists.txt create mode 100644 yage/base/CMakeLists.txt create mode 100644 yage/base/camera2d.cpp create mode 100644 yage/base/camera2d.h create mode 100644 yage/base/glslprogram.cpp create mode 100644 yage/base/glslprogram.h create mode 100644 yage/base/imageloader.cpp create mode 100644 yage/base/imageloader.h create mode 100644 yage/base/inputmanager.cpp create mode 100644 yage/base/inputmanager.h create mode 100644 yage/base/iomanager.cpp create mode 100644 yage/base/iomanager.h create mode 100644 yage/base/picopng.cpp create mode 100644 yage/base/picopng.h create mode 100644 yage/base/resourcemanager.cpp create mode 100644 yage/base/resourcemanager.h create mode 100644 yage/base/sprite.cpp create mode 100644 yage/base/sprite.h create mode 100644 yage/base/spritebatch.cpp create mode 100644 yage/base/spritebatch.h create mode 100644 yage/base/spritesheet.h create mode 100644 yage/base/texture.h create mode 100644 yage/base/texturecache.cpp create mode 100644 yage/base/texturecache.h create mode 100644 yage/base/vertex.h create mode 100644 yage/base/window.cpp create mode 100644 yage/base/window.h create mode 100644 yage/math/CMakeLists.txt create mode 100644 yage/math/math.h create mode 100644 yage/math/matrix.h create mode 100644 yage/physics/CMakeLists.txt create mode 100644 yage/physics/README.org create mode 100644 yage/physics/body.cpp create mode 100644 yage/physics/body.h create mode 100644 yage/physics/collider.h create mode 100644 yage/physics/collisionbody.h create mode 100644 yage/physics/particlebody.cpp create mode 100644 yage/physics/particlebody.h create mode 100644 yage/physics/physics.h create mode 100644 yage/physics/rectanglecollider.cpp create mode 100644 yage/physics/rectanglecollider.h create mode 100644 yage/physics/rigidbody.cpp create mode 100644 yage/physics/rigidbody.h create mode 100644 yage/yage.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 05359e78..7897ad1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,81 +1,46 @@ -# ---------------------------------------------------------------------------- -# CMakeLists.txt -# -# Copyright (c) 2017 Yann Herklotz Grave -- MIT License -# See file LICENSE for more details -# ---------------------------------------------------------------------------- - cmake_minimum_required(VERSION 3.0) # yage library cmakelists.txt -project(yage) - -# set version numbers -set(YAGE_MAJOR_VERSION 0) -set(YAGE_MINOR_VERSION 1) -set(YAGE_PATCH_VERSION 1) -set(YAGE_VERSION - "v${YAGE_MAJOR_VERSION}.${YAGE_MINOR_VERSION}.${YAGE_PATCH_VERSION}") +project(YetAnotherGameEngine) # set standard set(CMAKE_CXX_STANDARD 14) # set the test sources -set(YAGE_SOURCE_DIR "${PROJECT_SOURCE_DIR}/src") -set(YAGE_TEST_DIR "${PROJECT_SOURCE_DIR}/test") +set(YAGE_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src) +set(YAGE_TEST_DIR ${PROJECT_SOURCE_DIR}/test) set(YAGE_LIBRARIES ${PROJECT_NAME}) -# add include directory -set(YAGE_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include") - # set binary directory -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/bin") - -# add sources to library -set(YAGE_SOURCES - "${PROJECT_SOURCE_DIR}/src/body.cpp" - "${PROJECT_SOURCE_DIR}/src/camera2d.cpp" - "${PROJECT_SOURCE_DIR}/src/glslprogram.cpp" - "${PROJECT_SOURCE_DIR}/src/imageloader.cpp" - "${PROJECT_SOURCE_DIR}/src/inputmanager.cpp" - "${PROJECT_SOURCE_DIR}/src/iomanager.cpp" - "${PROJECT_SOURCE_DIR}/src/particlebody.cpp" - "${PROJECT_SOURCE_DIR}/src/picopng.cpp" - "${PROJECT_SOURCE_DIR}/src/rectanglecollider.cpp" - "${PROJECT_SOURCE_DIR}/src/resourcemanager.cpp" - "${PROJECT_SOURCE_DIR}/src/rigidbody.cpp" - "${PROJECT_SOURCE_DIR}/src/spritebatch.cpp" - "${PROJECT_SOURCE_DIR}/src/sprite.cpp" - "${PROJECT_SOURCE_DIR}/src/texturecache.cpp" - "${PROJECT_SOURCE_DIR}/src/window.cpp") - -add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/lib") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) # find libraries find_package(OpenGL REQUIRED) find_package(GLEW REQUIRED) + +# todo: change this to find_package include(FindPkgConfig) pkg_search_module(SDL2 REQUIRED sdl2) -# set include directory -include_directories(${YAGE_INCLUDE_DIR}) - -# make it a static library -add_library(${PROJECT_NAME} ${YAGE_SOURCES}) - -set(YAGE_LIB_DEP_L "yage;${OPENGL_LIBRARIES};${GLEW_LIBRARIES};${SDL2_LIBRARIES}") - -# enable tests -enable_testing() -set(SIMULATION_RUNS 1000) - -function(make_test test_name cycles) - add_executable(${test_name} "${YAGE_TEST_DIR}/${test_name}.cpp") - target_link_libraries(${test_name} gtest_main ${YAGE_LIB_DEP_L}) - add_test(NAME ${test_name} COMMAND ${test_name} --gtest_repeat=${cycles} --gtest_break_on_failure) -endfunction(make_test) - -make_test(yagetest ${SIMULATION_RUNS}) -make_test(matrixtest ${SIMULATION_RUNS}) -make_test(particlebodytest ${SIMULATION_RUNS}) -make_test(windowtest ${SIMULATION_RUNS}) +# adding libraries +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/yage) + +if(ENABLE_TESTING) + # enable tests + enable_testing() + set(SIMULATION_RUNS 1000) + + function(make_test test_name cycles) + add_executable(${test_name} ${YAGE_TEST_DIR}/${test_name}.cpp) + target_link_libraries(${test_name} + gtest_main + yage) + add_test(NAME ${test_name} COMMAND ${test_name} --gtest_repeat=${cycles} --gtest_break_on_failure) + endfunction(make_test) + + make_test(yagetest ${SIMULATION_RUNS}) + make_test(matrixtest ${SIMULATION_RUNS}) + make_test(particlebodytest ${SIMULATION_RUNS}) + make_test(windowtest ${SIMULATION_RUNS}) +endif(ENABLE_TESTING) diff --git a/include/YAGE/Math/math.h b/include/YAGE/Math/math.h deleted file mode 100644 index b729dbe6..00000000 --- a/include/YAGE/Math/math.h +++ /dev/null @@ -1,14 +0,0 @@ -/* ---------------------------------------------------------------------------- - * math.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef YAGE_MATH_H -#define YAGE_MATH_H - -#include "matrix.h" - -#endif diff --git a/include/YAGE/Math/matrix.h b/include/YAGE/Math/matrix.h deleted file mode 100644 index 3992acfe..00000000 --- a/include/YAGE/Math/matrix.h +++ /dev/null @@ -1,424 +0,0 @@ -/* ---------------------------------------------------------------------------- - * matrix.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -/** @file - */ - -#ifndef YAGE_MATH_MATRIX_H -#define YAGE_MATH_MATRIX_H - -#include -#include -#include -#include -#include -#include - -namespace yage -{ - -template -class Matrix; - -/** @internal Namespace for internal details. - * - * Detail Namespace - * ================ - * - * This is the namespace used for implementation detail. - */ -namespace detail -{ - -/** @internal Internal Row class used by the Matrix class to return the - * internal data structure of the Matrix. - * - * Row - * === - * - * Internal Row class to return a value in the row of the matrix. - */ -template -class Row -{ -private: - Matrix *parent_; - int index_; - -public: - Row(Matrix *parent, int index) - : parent_(parent), index_(index) - { - } - - Type &operator[](int col) - { - // The index is the y-position of the element in the matrix - return parent_->data_[index_ * Cols + col]; - } - - const Type &operator[](int col) const - { - return parent_->data_[index_ * Cols + col]; - } -}; - -} // namespace detail - -/** Base Matrix class used by other similar classes. - */ -template -class Matrix -{ - // friended with the row class so that it can access protected member data. - friend class detail::Row; - -protected: - /// Vector containing the data of the matrix. - std::vector data_; - -public: - /// Initializes the size of the data_ vector. - Matrix() : data_(Rows * Cols) {} - Matrix(const std::vector &data) : data_(data) {} - - /// Returns the row size of the Matrix. - int rowSize() const { return Rows; } - - /// Returns the column size of the Matrix. - int colSize() const { return Cols; } - - /** Return the row specified row as a Matrix with only one row. - * - * @param row Row number to be returned. - * @return The row that is specified by the row variables. - */ - Matrix<1, Cols, Type> getRow(int row) const - { - Matrix<1, Cols, Type> rowMatrix; - for (int i = 0; i < Cols; ++i) { - rowMatrix[0][i] = data_[row][i]; - } - return rowMatrix; - } - - /** Get a specific column in a column vector. - * - * @param col Column number to be returned. - * @return Column Matrix of the selected column. - */ - Matrix getCol(int col) const - { - Matrix colMatrix; - for (int i = 0; i < Rows; ++i) { - colMatrix[i][0] = data_[i][col]; - } - return colMatrix; - } - - /** Iterator support for the start. - * - * @return Iterator pointing to the start of the data. - */ - typename std::vector::iterator begin() { return data_.begin(); } - - /** Iterator support for the end. - * - * @return Iterator pointing to the end of the data. - */ - typename std::vector::iterator end() { return data_.end(); } - - /** Prints out the matrix, but can also be implemented by other classes to - * print data differently. - * - * @bug When printing certain matrices, it omits a row or column. Still - * need to determine under which conditions. - */ - virtual std::string toString() const - { - std::stringstream ss; - ss << '['; - for (int i = 0; i < Rows - 1; ++i) { - ss << '['; - for (int j = 0; j < Cols - 1; ++j) { - ss << data_[i * Cols + j] << ' '; - } - ss << data_[(Rows - 1) * Cols + Cols - 1] << "],"; - } - ss << '['; - for (int j = 0; j < Cols - 1; ++j) { - ss << data_[(Rows - 1) * Cols + j] << ' '; - } - ss << data_[(Rows - 1) * Cols + Cols - 1] << "]]"; - return ss.str(); - } - - detail::Row operator[](int row) - { - return detail::Row(this, row); - } - - detail::Row operator[](int row) const - { - return detail::Row((Matrix *)this, - row); - } - - Matrix &operator+=(const Matrix &rhs) - { - std::vector out; - out.reserve(data_.size()); - std::transform(data_.begin(), data_.end(), rhs.data_.begin(), - std::back_inserter(out), - [](Type a, Type b) { return a + b; }); - data_ = std::move(out); - return *this; - } - - Matrix &operator-=(const Matrix &rhs) - { - std::vector out; - out.reserve(data_.size()); - std::transform(data_.begin(), data_.end(), rhs.begin(), - std::back_inserter(out), - [](Type a, Type b) { return a - b; }); - data_ = std::move(out); - return *this; - } -}; - -template -Matrix operator+(Matrix lhs, const Matrix &rhs) -{ - lhs += rhs; - return lhs; -} - -template -Matrix operator-(Matrix lhs, const Matrix &rhs) -{ - lhs -= rhs; - return lhs; -} - -template -Matrix operator+(Matrix lhs, const T &rhs) -{ - for (auto &data : lhs) { - data += rhs; - } - return lhs; -} - -template -Matrix operator+(const T &lhs, Matrix rhs) -{ - for (auto &data : rhs) { - data += lhs; - } - return rhs; -} - -template -Matrix operator-(Matrix lhs, const T &rhs) -{ - for (auto &data : lhs) { - data -= rhs; - } - return lhs; -} - -template -Matrix operator-(const T &lhs, Matrix rhs) -{ - for (auto &data : rhs) { - data = lhs - data; - } - return rhs; -} - -template -Matrix operator*(Matrix lhs, const T &rhs) -{ - for (auto &data : lhs) { - data *= rhs; - } - return lhs; -} - -template -Matrix operator*(const T &lhs, Matrix rhs) -{ - for (auto &data : rhs) { - data *= lhs; - } - return rhs; -} - -template -Matrix operator/(Matrix lhs, const T &rhs) -{ - for (auto &data : lhs) { - data /= rhs; - } - return lhs; -} - -template -bool operator==(const Matrix &lhs, const Matrix &rhs) -{ - for (int i = 0; i < M; ++i) { - for (int j = 0; j < N; ++j) { - if (lhs[i][j] != rhs[i][j]) { - return false; - } - } - } - return true; -} - -template -std::ostream &operator<<(std::ostream &os, const Matrix &mat) -{ - return os << mat.toString(); -} - -template -class Vector : public Matrix -{ -public: - Vector() : Matrix() {} - Vector(const Matrix &other) - : Matrix(other) - { - } - - Vector(const std::vector &data) - : Matrix(data) - { - } - - Type &operator[](int col) { return this->data_[col]; } - - const Type &operator[](int col) const { return this->data_[col]; } - - std::string toString() const override - { - std::stringstream ss; - ss << "["; - for (std::size_t i = 0; i < this->data_.size() - 1; ++i) { - ss << this->data_[i] << " "; - } - ss << this->data_[this->data_.size() - 1] << "]"; - return ss.str(); - } -}; - -/** 2D Vector class. - * - * Two dimensional vector class. - */ -template -class Vector2 : public Vector<2, Type> -{ -public: - Vector2() : Vector<2, Type>() {} - Vector2(const std::vector &data) : Vector<2, Type>(data) {} - - Vector2(Type x, Type y) - { - this->data_[0] = x; - this->data_[1] = y; - } - - Vector2(const Matrix<2, 1, Type> &other) : Vector<2, Type>(other) {} - - Type &x() { return this->data_[0]; } - - const Type &x() const { return this->data_[0]; } - - Type &y() { return this->data_[1]; } - - const Type &y() const { return this->data_[1]; } -}; - -/** Definition of a 2D vector. - */ -using Vector2d = Vector2; - -/** Namespace containing functions that operate on matrices. - * - * Implementations defined here are meant to operate on anything that inherits - * from the base Matrix class. - */ -namespace matrix -{ - -/** Transposes a matrix and returns the result - * - * @param m input matrix. - */ -template -Matrix transpose(const Matrix &m) -{ - Matrix trans; - for (int i = 0; i < M; ++i) { - for (int j = 0; j < N; ++j) { - trans[j][i] = m[i][j]; - } - } - return trans; -} - -/** Returns the dot product between two vectors - * - * @param m1,m2 Input matrices. - */ -template -T dot(const Matrix &m1, const Matrix &m2) -{ - T sum = 0; - for (int i = 0; i < R; ++i) { - sum += m1[i][0] * m2[i][0]; - } - return sum; -} - -/** Multiplies two matrices together. - * - * @param m1,m2 Matrix inputs - * - * Requires the two matrices to be compatible with multiplication. - */ -template -Matrix multiply(const Matrix &m1, const Matrix &m2) -{ - /// @todo Think if this should be a static_assert. - if (N != P) { - throw std::runtime_error( - "Matrices don't have the right dimensions for multiplication"); - } - - Matrix res; - - /// Performs multiplication by getting the rows and columns, transposing - /// one of them and then doting the result. - for (int i = 0; i < M; ++i) { - for (int j = 0; j < Q; ++j) { - res[i][j] = dot(transpose(m1.getRow(i)), m2.getCol(j)); - } - } - - return res; -} - -} // namespace matrix - -} // namespace yage - -#endif diff --git a/include/YAGE/Physics/README.org b/include/YAGE/Physics/README.org deleted file mode 100644 index 0620cc93..00000000 --- a/include/YAGE/Physics/README.org +++ /dev/null @@ -1,27 +0,0 @@ -#+ TITLE : README -#+ DATE : <2017 - 04 - 17 Mon> -#+ AUTHOR: -#+ EMAIL : yannherklotz @yann - arch -#+ OPTIONS : ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline -#+ OPTIONS : author : t c : nil creator : comment d : (not"LOGBOOK") date : t -#+ OPTIONS : e : t email : nil f : t inline : t num : t p : nil pri : nil stat : t -#+ OPTIONS : tags : t tasks : t tex : t timestamp : t toc : t todo : t | : t -#+ CREATOR : Emacs 25.1.1(Org mode 8.2.10) -#+ DESCRIPTION: -#+ EXCLUDE_TAGS : noexport -#+ KEYWORDS: -#+ LANGUAGE : en -#+ SELECT_TAGS : export - -*Physics Engine - - **Acceleration, - speed and position - - I have a = dv / dt; -v = dp / dt; - -I am going to use the second order runga kutta method with a = 0, b = 1, - alpha = - 1 / 2 and beta = - 1 / 2 diff --git a/include/YAGE/Physics/body.h b/include/YAGE/Physics/body.h deleted file mode 100644 index bd33a9ac..00000000 --- a/include/YAGE/Physics/body.h +++ /dev/null @@ -1,56 +0,0 @@ -/* ---------------------------------------------------------------------------- - * body.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef YAGE_PHYSICS_BODY_H -#define YAGE_PHYSICS_BODY_H - -#include - -namespace yage -{ -class Body -{ -public: - // gravity constant - static const double GRAVITY; - -protected: - // center of mass of the object - Vector2d position_ = Vector2d(0, 0); - - // mass of the object - double mass_ = 1; - - // current velocity of the object - Vector2d velocity_ = Vector2d(0, 0); - - // boolean that defines if gravity can act on the object - bool gravity_ = true; - - // current acceleration - Vector2d acceleration_ = Vector2d(0, 0); - - // force acting on the body - Vector2d force_ = Vector2d(0, 0); - -public: - // apply force to the object and update the velocity - virtual void applyForce(const Vector2d &force) = 0; - virtual void update() = 0; - - double xPosition() const; - double yPosition() const; - -protected: - // protected constructor to initialize member variables - Body(Vector2d position = Vector2d(0, 0), double mass = 1, - Vector2d velocity = Vector2d(0, 0), bool gravity = false); -}; -} // namespace yage - -#endif diff --git a/include/YAGE/Physics/collider.h b/include/YAGE/Physics/collider.h deleted file mode 100644 index 2fd2ff89..00000000 --- a/include/YAGE/Physics/collider.h +++ /dev/null @@ -1,43 +0,0 @@ -/* ---------------------------------------------------------------------------- - * collider.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef YAGE_PHYSICS_COLLIDER_H -#define YAGE_PHYSICS_COLLIDER_H - -#include - -namespace yage -{ - -// The Collider class helps collision detection by providing a general shape -// for different shapes to have their own collision algorithms. -class Collider -{ -protected: - // position of the object - glm::vec2 position_; - - // size of the object - glm::vec2 size_; - -public: - Collider(const glm::vec2 &position, const glm::vec2 &size) - : position_(position), size_(size) - { - } - - // function that checks if two colliders are colliding - virtual bool collides(const Collider &collider) const = 0; - - // function that returns if a point is inside the shape - virtual bool inside(const glm::vec2 &point) const = 0; -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/Physics/collisionbody.h b/include/YAGE/Physics/collisionbody.h deleted file mode 100644 index 715c4a54..00000000 --- a/include/YAGE/Physics/collisionbody.h +++ /dev/null @@ -1,28 +0,0 @@ -/* ---------------------------------------------------------------------------- - * collisionbody.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef YAGE_COLLISION_BODY_H -#define YAGE_COLLISION_BODY_H - -#include "body.h" - -namespace yage -{ - -// a collision body will be a body that is static and not affected by gravity, -// with infinite mass -class CollisionBody : public Body -{ -public: - CollisionBody(); - virtual ~CollisionBody(); -}; - -} // yage - -#endif diff --git a/include/YAGE/Physics/particlebody.h b/include/YAGE/Physics/particlebody.h deleted file mode 100644 index a0b9bdad..00000000 --- a/include/YAGE/Physics/particlebody.h +++ /dev/null @@ -1,33 +0,0 @@ -/* ---------------------------------------------------------------------------- - * particlebody.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef YAGE_PHYSICS_PARTICLE_BODY_H -#define YAGE_PHYSICS_PARTICLE_BODY_H - -#include "body.h" - -#include - -namespace yage -{ - -class ParticleBody : public Body -{ -public: - ParticleBody(const Vector2d &position = Vector2d(0, 0), double mass = 1, - const Vector2d &velocity = Vector2d(0, 0), - bool gravity = true); - - // apply a force to the rigid body - void applyForce(const Vector2d &force) override; - void update() override; -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/Physics/physics.h b/include/YAGE/Physics/physics.h deleted file mode 100644 index 900f4b6a..00000000 --- a/include/YAGE/Physics/physics.h +++ /dev/null @@ -1,19 +0,0 @@ -/* ---------------------------------------------------------------------------- - * physics.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef YAGE_PHYSICS_H -#define YAGE_PHYSICS_H - -#include "body.h" -#include "collider.h" -#include "collisionbody.h" -#include "particlebody.h" -#include "rectanglecollider.h" -#include "rigidbody.h" - -#endif diff --git a/include/YAGE/Physics/rectanglecollider.h b/include/YAGE/Physics/rectanglecollider.h deleted file mode 100644 index c009f665..00000000 --- a/include/YAGE/Physics/rectanglecollider.h +++ /dev/null @@ -1,30 +0,0 @@ -/* ---------------------------------------------------------------------------- - * rectanglecollider.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef YAGE_RECTANGLE_COLLIDER_H -#define YAGE_RECTANGLE_COLLIDER_H - -#include "collider.h" - -#include - -namespace yage -{ - -class RectangleCollider : public Collider -{ -public: - RectangleCollider(const glm::vec2 &position, const glm::vec2 &size); - - bool collides(const Collider &collider) const override; - bool inside(const glm::vec2 &point) const override; -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/Physics/rigidbody.h b/include/YAGE/Physics/rigidbody.h deleted file mode 100644 index 67ccb4ca..00000000 --- a/include/YAGE/Physics/rigidbody.h +++ /dev/null @@ -1,28 +0,0 @@ -/* ---------------------------------------------------------------------------- - * rigidbody.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef YAGE_RIGID_BODY_H -#define YAGE_RIGID_BODY_H - -#include "particlebody.h" - -#include - -namespace yage -{ - -class RigidBody : public ParticleBody -{ -public: - RigidBody(const Vector2d &position = Vector2d(0, 0), double mass = 1, - const Vector2d &velocity = Vector2d(0, 0), bool gravity = true); -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/camera2d.h b/include/YAGE/camera2d.h deleted file mode 100644 index a60893ac..00000000 --- a/include/YAGE/camera2d.h +++ /dev/null @@ -1,38 +0,0 @@ -/* ---------------------------------------------------------------------------- - * camera2d.h - * - * Copyright (c) 2017 Yann Herklotz Grave - * MIT License, see LICENSE file for more details. - * ---------------------------------------------------------------------------- - */ - -#ifndef YAGE_CAMERA2D_H -#define YAGE_CAMERA2D_H - -#include "glslprogram.h" - -#include -#include - -namespace yage -{ - -class Camera2D -{ -private: - bool update_matrix_ = true; - float scale_ = 1; - glm::vec2 position_; - glm::mat4 camera_matrix_; - glm::mat4 ortho_matrix_; - -public: - Camera2D(int screen_width = 1280, int screen_height = 720); - - void update(GlslProgram &program); - void move(const glm::vec2 &direction); -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/glslprogram.h b/include/YAGE/glslprogram.h deleted file mode 100644 index fbe5ac5c..00000000 --- a/include/YAGE/glslprogram.h +++ /dev/null @@ -1,52 +0,0 @@ -/* ---------------------------------------------------------------------------- - * glslprogram.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef GLSL_PROGRAM_H -#define GLSL_PROGRAM_H - -#include - -#include - -namespace yage -{ - -class GlslProgram -{ -private: - /// compiled shader program id - GLuint program_id_ = 0; - GLuint vertex_shader_id_ = 0; - GLuint fragment_shader_id_ = 0; - int attribute_index_ = 0; - - /// compiles one shader - void compileShader(const GLuint &shader, const std::string &file_path); - -public: - GlslProgram() = default; - GlslProgram(const GlslProgram &) = delete; - GlslProgram(GlslProgram &&) = delete; - ~GlslProgram(); - - GlslProgram &operator=(const GlslProgram &) = delete; - GlslProgram &operator=(GlslProgram &&) = delete; - - /// compiles vertex and fragment shader - void compileShaders(const std::string &vertex_shader_path, - const std::string &fragment_shader_path); - void linkShaders(); - void addAttribute(const std::string &attribute_name); - GLint getUniformLocation(const std::string &uniform_name); - void use(); - void unuse(); -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/imageloader.h b/include/YAGE/imageloader.h deleted file mode 100644 index 8d5c5cd1..00000000 --- a/include/YAGE/imageloader.h +++ /dev/null @@ -1,27 +0,0 @@ -/* ---------------------------------------------------------------------------- - * imageloader.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef IMAGE_LOADER_H -#define IMAGE_LOADER_H - -#include "texture.h" - -#include - -namespace yage -{ - -class ImageLoader -{ -public: - static Texture loadPng(const std::string &file_path); -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/inputmanager.h b/include/YAGE/inputmanager.h deleted file mode 100644 index 84728fff..00000000 --- a/include/YAGE/inputmanager.h +++ /dev/null @@ -1,28 +0,0 @@ -/* ---------------------------------------------------------------------------- - * inputmanager.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef INPUT_MANAGER_H -#define INPUT_MANAGER_H - -#include - -namespace yage -{ - -class InputManager -{ -private: - std::unordered_map key_map_; - -public: - void keyPressed(unsigned key); - void keyReleased(unsigned key); - bool isKeyPressed(unsigned key) const; -}; -} // namespace yage -#endif diff --git a/include/YAGE/iomanager.h b/include/YAGE/iomanager.h deleted file mode 100644 index 95abd652..00000000 --- a/include/YAGE/iomanager.h +++ /dev/null @@ -1,27 +0,0 @@ -/* ---------------------------------------------------------------------------- - * iomanager.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef IO_MANAGER_H -#define IO_MANAGER_H - -#include -#include - -namespace yage -{ - -class IoManager -{ -public: - static bool readFileToBuffer(const std::string &file_path, - std::vector &buffer); -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/picopng.h b/include/YAGE/picopng.h deleted file mode 100644 index 095bf68a..00000000 --- a/include/YAGE/picopng.h +++ /dev/null @@ -1,20 +0,0 @@ -/* ---------------------------------------------------------------------------- - * picopng.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include -#include - -namespace yage -{ - -extern int decodePNG(std::vector &out_image, - unsigned long &image_width, unsigned long &image_height, - const unsigned char *in_png, size_t in_size, - bool convert_to_rgba32 = true); - -} // namespace yage diff --git a/include/YAGE/resourcemanager.h b/include/YAGE/resourcemanager.h deleted file mode 100644 index 3c5081c4..00000000 --- a/include/YAGE/resourcemanager.h +++ /dev/null @@ -1,31 +0,0 @@ -/* ---------------------------------------------------------------------------- - * resourcemanager.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef RESOURCE_MANAGER_H -#define RESOURCE_MANAGER_H - -#include "texture.h" -#include "texturecache.h" - -#include - -namespace yage -{ - -class ResourceManager -{ -private: - static TextureCache texture_cache_; - -public: - static Texture getTexture(const std::string &texture_path); -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/sprite.h b/include/YAGE/sprite.h deleted file mode 100644 index 5b9baf91..00000000 --- a/include/YAGE/sprite.h +++ /dev/null @@ -1,52 +0,0 @@ -/* ---------------------------------------------------------------------------- - * sprite.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -/** @file - */ - -#ifndef SPRITE_H -#define SPRITE_H - -#include "texture.h" - -#include - -#include - -namespace yage -{ - -/** @deprecated Use SpriteBatch instead - */ -class Sprite -{ -private: - float x_; - float y_; - float width_; - float height_; - GLuint vbo_id_ = 0; - Texture texture_; - -public: - Sprite(); - Sprite(const Sprite &) = delete; - Sprite(Sprite &&) = delete; - ~Sprite(); - - Sprite &operator=(const Sprite &) = delete; - Sprite &operator=(Sprite &&) = delete; - - void init(float x, float y, float width, float height, - const std::string &texture_path); - void draw(); -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/spritebatch.h b/include/YAGE/spritebatch.h deleted file mode 100644 index 7235bd25..00000000 --- a/include/YAGE/spritebatch.h +++ /dev/null @@ -1,105 +0,0 @@ -/* ---------------------------------------------------------------------------- - * spritebatch.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef YAGE_SPRITE_BATCH_H -#define YAGE_SPRITE_BATCH_H - -#include "vertex.h" - -#include -#include - -#include - -namespace yage -{ - -class SpriteBatch; - -/** Glyph with information of the texture. - */ -class Glyph -{ -private: - GLuint texture_; - float depth_; - Vertex top_left_; - Vertex top_right_; - Vertex bottom_right_; - Vertex bottom_left_; - -public: - Glyph(GLuint texture, float depth, const Vertex &top_left, - const Vertex &top_right, const Vertex &bottom_right, - const Vertex &bottom_left); - - GLuint texture() const { return texture_; } - float depth() const { return depth_; } - Vertex top_left() const { return top_left_; } - Vertex top_right() const { return top_right_; } - Vertex bottom_right() const { return bottom_right_; } - Vertex bottom_left() const { return bottom_left_; } -}; - -class RenderBatch -{ - friend SpriteBatch; - -private: - GLsizei num_vertices_; - GLint offset_; - GLuint texture_; - -public: - RenderBatch(GLint offset, GLsizei num_vertices, GLuint texture); - - GLint offset() const { return offset_; } - GLsizei num_vertices() const { return num_vertices_; } - GLuint texture() const { return texture_; } -}; - -class SpriteBatch -{ -public: - static const int NUM_VERTICES = 6; - -private: - GLuint vbo_ = 0; - GLuint vao_ = 0; - std::vector glyphs_; - std::vector glyph_ptrs_; - std::vector render_batches_; - -public: - SpriteBatch(); - SpriteBatch(const SpriteBatch &) = delete; - SpriteBatch(SpriteBatch &&) = delete; - ~SpriteBatch(); - - SpriteBatch &operator=(const SpriteBatch &) = delete; - SpriteBatch &operator=(SpriteBatch &&) = delete; - - // initialize vaos and vbos - void init(); - void begin(); - void end(); - // adds a sprite to the sprite batch to be rendered later - void draw(const glm::vec4 &destination_rect, const glm::vec4 &uv_rect, - GLuint texture, const Color &color, float depth); - // render the batch - void render(); - -private: - void createVertexArray(); - void createRenderBatches(); - void sortGlyphs(); -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/spritesheet.h b/include/YAGE/spritesheet.h deleted file mode 100644 index 2b70ad8b..00000000 --- a/include/YAGE/spritesheet.h +++ /dev/null @@ -1,25 +0,0 @@ -/* ---------------------------------------------------------------------------- - * spritesheet.h - * - * Copyright (c) 2017 Yann Herklotz Grave - * MIT License, see LICENSE file for more details. - * ---------------------------------------------------------------------------- - */ - -#ifndef YAGE_SPRITESHEET_H -#define YAGE_SPRITESHEET_H - -#include "texture.h" - -namespace yage -{ - -class SpriteSheet -{ -private: - Texture texture_; -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/texture.h b/include/YAGE/texture.h deleted file mode 100644 index d1fdcbf2..00000000 --- a/include/YAGE/texture.h +++ /dev/null @@ -1,25 +0,0 @@ -/* ---------------------------------------------------------------------------- - * texture.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef GL_TEXTURE_H -#define GL_TEXTURE_H - -#include - -namespace yage -{ - -struct Texture { - GLuint id; - int width; - int height; -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/texturecache.h b/include/YAGE/texturecache.h deleted file mode 100644 index 414c9ec3..00000000 --- a/include/YAGE/texturecache.h +++ /dev/null @@ -1,32 +0,0 @@ -/* ---------------------------------------------------------------------------- - * texturecache.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef TEXTURE_CACHE_H -#define TEXTURE_CACHE_H - -#include "texture.h" - -#include - -namespace yage -{ - -class TextureCache -{ -private: - std::unordered_map texture_map_; - -public: - TextureCache(); - - Texture getTexture(const std::string &texture_path); -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/vertex.h b/include/YAGE/vertex.h deleted file mode 100644 index 15b46ed9..00000000 --- a/include/YAGE/vertex.h +++ /dev/null @@ -1,84 +0,0 @@ -/* ---------------------------------------------------------------------------- - * vertex.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef VERTEX_H -#define VERTEX_H - -#include - -namespace yage -{ - -struct Position { - float x; - float y; - - Position() = default; - - Position(float x_, float y_) : x(x_), y(y_) {} -}; - -struct Color { - GLubyte r; - GLubyte g; - GLubyte b; - GLubyte a; - - Color() = default; - - Color(GLubyte r_, GLubyte g_, GLubyte b_, GLubyte a_) - : r(r_), g(g_), b(b_), a(a_) - { - } -}; - -struct UV { - float u; - float v; - - UV() = default; - - UV(float u_, float v_) : u(u_), v(v_) {} -}; - -struct Vertex { - Position position; - Color color; - UV uv; - - Vertex() = default; - - Vertex(const Position &position_, const Color &color_, const UV &uv_) - : position(position_), color(color_), uv(uv_) - { - } - - void setPosition(float x, float y) - { - position.x = x; - position.y = y; - } - - void setColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a) - { - color.r = r; - color.g = g; - color.b = b; - color.a = a; - } - - void setUv(float u, float v) - { - uv.u = u; - uv.v = v; - } -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/window.h b/include/YAGE/window.h deleted file mode 100644 index 8639e075..00000000 --- a/include/YAGE/window.h +++ /dev/null @@ -1,55 +0,0 @@ -/* ---------------------------------------------------------------------------- - * window.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#ifndef WINDOW_H -#define WINDOW_H - -#include - -#include - -namespace yage -{ - -// window flags that can change it's appearance -enum WindowFlags : unsigned { - SHOWN = 0x1, - HIDDEN = 0x2, - FULLSCREEN = 0x4, - BORDERLESS = 0x8, -}; - -// window wrapper around SDL_Window pointer -class Window -{ -private: - /// window handle - SDL_Window *window_ = nullptr; - -public: - Window(); - Window(const Window &) = delete; - Window(Window &&) = delete; - /// destroys the window handle - ~Window(); - - Window &operator=(const Window &) = delete; - Window &operator=(Window &&) = delete; - - /// create the window, initialize the handle and update the width and height - void create(const std::string &window_name, int width, int height, - unsigned flags = WindowFlags::SHOWN); - /// swap the buffer - void swapBuffer(); - /// clear buffer - void clearBuffer(); -}; - -} // namespace yage - -#endif diff --git a/include/YAGE/yage.h b/include/YAGE/yage.h deleted file mode 100644 index 6157e6bf..00000000 --- a/include/YAGE/yage.h +++ /dev/null @@ -1,63 +0,0 @@ -/* ---------------------------------------------------------------------------- - * yage.h - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -/** @file Includes all the headers in the main YAGE project. - * - * This does not include - */ - -#ifndef YAGE_YAGE_H -#define YAGE_YAGE_H - -#include "camera2d.h" -#include "glslprogram.h" -#include "imageloader.h" -#include "inputmanager.h" -#include "iomanager.h" -#include "picopng.h" -#include "resourcemanager.h" -#include "spritebatch.h" -#include "texture.h" -#include "vertex.h" -#include "window.h" - -#include - -#include - -/** Project namespace. - * - * Avoids collision as all the classes and global functions are wrapped in. - * it. - */ -namespace yage -{ - -/** Initializes YAGE. - * - * This is only there to initialize SDL2. - * - * @return Returns true if the initialization was successful. - */ -bool init() -{ - return SDL_Init(SDL_INIT_VIDEO); -} - -/** Quit and cleanup YAGE - * - * SDL2 needs to clean itself up. - */ -void quit() -{ - SDL_Quit(); -} - -} // namespace yage - -#endif diff --git a/src/body.cpp b/src/body.cpp deleted file mode 100644 index 8d38e70a..00000000 --- a/src/body.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* ---------------------------------------------------------------------------- - * body.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include - -#include - -namespace yage -{ - -const double Body::GRAVITY = -9.81; - -double Body::xPosition() const -{ - return position_[0]; -} - -double Body::yPosition() const -{ - return position_[1]; -} - -Body::Body(Vector2d position, double mass, Vector2d velocity, bool gravity) - : position_(std::move(position)), mass_(mass), - velocity_(std::move(velocity)), gravity_(gravity) -{ -} - -} // namespace yage diff --git a/src/camera2d.cpp b/src/camera2d.cpp deleted file mode 100644 index 292f998a..00000000 --- a/src/camera2d.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* ---------------------------------------------------------------------------- - * camera2d.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include - -#include - -namespace yage -{ - -Camera2D::Camera2D(int screen_width, int screen_height) - : position_(0.f, 0.f), camera_matrix_(1.f), - ortho_matrix_( - glm::ortho(0.f, (float)screen_width, 0.f, (float)screen_height)) -{ -} - -void Camera2D::update(GlslProgram &program) -{ - if (update_matrix_) { - glm::vec3 translate(-position_.x, -position_.y, 0.f); - glm::vec3 scale(scale_, scale_, 0.f); - - camera_matrix_ = glm::translate(ortho_matrix_, translate); - camera_matrix_ = glm::scale(glm::mat4(1.f), scale) * camera_matrix_; - - update_matrix_ = false; - } - - GLint matrix_location = program.getUniformLocation("P"); - glUniformMatrix4fv(matrix_location, 1, GL_FALSE, &(camera_matrix_[0][0])); -} - -void Camera2D::move(const glm::vec2 &direction) -{ - position_ += direction; - update_matrix_ = true; -} - -} // namespace yage diff --git a/src/glslprogram.cpp b/src/glslprogram.cpp deleted file mode 100644 index 11a3191e..00000000 --- a/src/glslprogram.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* ---------------------------------------------------------------------------- - * glslprogram.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include - -#include -#include -#include - -namespace yage -{ - -GlslProgram::~GlslProgram() -{ - // cleanup all the shaders and the program - if (fragment_shader_id_ != 0) { - glDeleteShader(fragment_shader_id_); - } - - if (vertex_shader_id_ != 0) { - glDeleteShader(vertex_shader_id_); - } - - if (program_id_ != 0) { - glDeleteProgram(program_id_); - } -} - -void GlslProgram::compileShader(const GLuint &shader, - const std::string &file_path) -{ - // get a string with the input from the shader file - std::ifstream file(file_path); - if (!file.is_open()) { - throw std::runtime_error("Failed to open '" + file_path + "'"); - } - - std::string content = ""; - std::string line; - - while (std::getline(file, line)) { - content += line + "\n"; - } - file.close(); - - // cast source to a c string to get the address of it and input it for - // compilation - const auto *vertex_source = (const GLchar *)content.c_str(); - glShaderSource(shader, 1, &vertex_source, nullptr); - glCompileShader(shader); - - // check if compilation was successful - GLint is_compiled = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, (int *)&is_compiled); - - // if it isn't compiled throw exception to clean up - if (is_compiled == GL_FALSE) { - GLint max_length = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length); - - std::vector error_log(max_length); - glGetShaderInfoLog(shader, max_length, &max_length, &error_log[0]); - std::string error_log_str((const char *)&error_log[0]); - - throw std::runtime_error("Couldn't compile " + file_path + " : " + - error_log_str); - } -} - -void GlslProgram::compileShaders(const std::string &vertex_shader_path, - const std::string &fragment_shader_path) -{ - // create the program that will be run on GPU - program_id_ = glCreateProgram(); - - // create vertex shader - vertex_shader_id_ = glCreateShader(GL_VERTEX_SHADER); - if (vertex_shader_id_ == 0) { - throw std::runtime_error("Vertex shader failed to be created"); - } - - // create fragment shader - fragment_shader_id_ = glCreateShader(GL_FRAGMENT_SHADER); - if (fragment_shader_id_ == 0) { - throw std::runtime_error("Fragment shader failed to be created"); - } - - // compile the two shaders - compileShader(vertex_shader_id_, vertex_shader_path); - compileShader(fragment_shader_id_, fragment_shader_path); -} - -void GlslProgram::linkShaders() -{ - // attach the shaders that we want - glAttachShader(program_id_, vertex_shader_id_); - glAttachShader(program_id_, fragment_shader_id_); - - // link our program - glLinkProgram(program_id_); - - GLint is_linked = 0; - glGetProgramiv(program_id_, GL_LINK_STATUS, (int *)&is_linked); - if (is_linked == GL_FALSE) { - GLint max_length = 0; - glGetProgramiv(program_id_, GL_INFO_LOG_LENGTH, &max_length); - - std::vector error_log(max_length); - glGetProgramInfoLog(program_id_, max_length, &max_length, - &error_log[0]); - - std::string error_log_str((const char *)&error_log[0]); - - throw std::runtime_error("Could not link program : " + error_log_str); - } - - // detach shaders after successful link - glDetachShader(program_id_, fragment_shader_id_); - glDetachShader(program_id_, vertex_shader_id_); - - // we can then delete the shaders once we have the program - glDeleteShader(fragment_shader_id_); - glDeleteShader(vertex_shader_id_); -} - -void GlslProgram::addAttribute(const std::string &attribute_name) -{ - glBindAttribLocation(program_id_, attribute_index_++, - attribute_name.c_str()); -} - -GLint GlslProgram::getUniformLocation(const std::string &uniform_name) -{ - GLint location = glGetUniformLocation(program_id_, uniform_name.c_str()); - if ((GLuint)location == GL_INVALID_INDEX) { - throw std::runtime_error("'" + uniform_name + "' not found"); - } - return location; -} - -void GlslProgram::use() -{ - glUseProgram(program_id_); - for (int i = 0; i < attribute_index_; ++i) { - glEnableVertexAttribArray(i); - } -} - -void GlslProgram::unuse() -{ - for (int i = 0; i < attribute_index_; ++i) { - glDisableVertexAttribArray(i); - } - glUseProgram(0); -} - -} // namespace yage diff --git a/src/imageloader.cpp b/src/imageloader.cpp deleted file mode 100644 index 812110d8..00000000 --- a/src/imageloader.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* ---------------------------------------------------------------------------- - * imageloader.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include -#include -#include - -#include - -namespace yage -{ - -Texture ImageLoader::loadPng(const std::string &file_path) -{ - Texture texture = {}; - - std::vector in; - std::vector out; - unsigned long width, height; - - if (!IoManager::readFileToBuffer(file_path, in)) { - throw std::runtime_error("Failed to load '" + file_path + - "' to buffer"); - } - - int error_code = decodePNG(out, width, height, &in[0], in.size()); - if (error_code != 0) { - throw std::runtime_error("Failed to load '" + file_path + - "' to png with error code" + - std::to_string(error_code)); - } - - glGenTextures(1, &texture.id); - - glBindTexture(GL_TEXTURE_2D, texture.id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, &out[0]); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR); - - glGenerateMipmap(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, 0); - - texture.width = (int)width; - texture.height = (int)height; - - return texture; -} - -} // namespace yage diff --git a/src/inputmanager.cpp b/src/inputmanager.cpp deleted file mode 100644 index d429abd7..00000000 --- a/src/inputmanager.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* ---------------------------------------------------------------------------- - * inputmanager.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include - -namespace yage -{ - -void InputManager::keyPressed(unsigned key) -{ - key_map_[key] = true; -} - -void InputManager::keyReleased(unsigned key) -{ - key_map_[key] = false; -} - -bool InputManager::isKeyPressed(unsigned key) const -{ - auto key_index = key_map_.find(key); - if (key_index != key_map_.end()) { - return key_index->second; - } - return false; -} - -} // namespace yage diff --git a/src/iomanager.cpp b/src/iomanager.cpp deleted file mode 100644 index 93ab41c9..00000000 --- a/src/iomanager.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* ---------------------------------------------------------------------------- - * iomanager.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include - -#include -#include - -namespace yage -{ - -bool IoManager::readFileToBuffer(const std::string &file_path, - std::vector &buffer) -{ - std::ifstream file(file_path, std::ios::binary); - if (!file.is_open()) { - throw std::runtime_error("Could not open '" + file_path + "'"); - } - - // seek to the end - file.seekg(0, std::ios::end); - - // get the file size - int file_size = file.tellg(); - file.seekg(0, std::ios::beg); - - // reduce file size by header bytes - file_size -= file.tellg(); - - buffer.resize(file_size); - file.read((char *)&buffer[0], file_size); - file.close(); - - return true; -} - -} // namespace yage diff --git a/src/particlebody.cpp b/src/particlebody.cpp deleted file mode 100644 index bdb81eac..00000000 --- a/src/particlebody.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* ---------------------------------------------------------------------------- - * particlebody.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include - -#include -#include - -namespace yage -{ - -ParticleBody::ParticleBody(const Vector2d &position, double mass, - const Vector2d &velocity, bool gravity) - : Body(position, mass, velocity, gravity) -{ -} - -void ParticleBody::applyForce(const Vector2d &force) -{ - force_ += force; -} - -void ParticleBody::update() -{ - // set the time_step for 60fps - double time_step = 1.0 / 60.0; - - // set the last acceleration - Vector2d last_acceleration = acceleration_; - - // update the position of the body - position_ += velocity_ * time_step + - (0.5 * last_acceleration * std::pow(time_step, 2)); - - // update the acceleration - if (gravity_) { - acceleration_ = - Vector2d(force_.x() / mass_, (GRAVITY + force_.y()) / mass_); - } else { - acceleration_ = Vector2d(force_.x() / mass_, force_.y() / mass_); - } - - Vector2d avg_acceleration = (acceleration_ + last_acceleration) / 2.0; - - // update the velocity of the body - velocity_ += avg_acceleration * time_step; -} - -} // namespace yage diff --git a/src/picopng.cpp b/src/picopng.cpp deleted file mode 100644 index dcc4b367..00000000 --- a/src/picopng.cpp +++ /dev/null @@ -1,1118 +0,0 @@ -#include -#include - -namespace yage -{ - -/* - decodePNG: The picoPNG function, decodes a PNG file buffer in memory, into a - raw pixel buffer. - out_image: output parameter, this will contain the raw pixels after decoding. - By default the output is 32-bit RGBA color. - The std::vector is automatically resized to the correct size. - image_width: output_parameter, this will contain the width of the image in - pixels. - image_height: output_parameter, this will contain the height of the image in - pixels. - in_png: pointer to the buffer of the PNG file in memory. To get it from a file - on - disk, load it and store it in a memory buffer yourself first. - in_size: size of the input PNG file in bytes. - convert_to_rgba32: optional parameter, true by default. - Set to true to get the output in RGBA 32-bit (8 bit per channel) color format - no matter what color type the original PNG image had. This gives predictable, - useable data from any random input PNG. - Set to false to do no color conversion at all. The result then has the same - data - type as the PNG image, which can range from 1 bit to 64 bits per pixel. - Information about the color type or palette colors are not provided. You need - to know this information yourself to be able to use the data so this only - works for trusted PNG files. Use LodePNG instead of picoPNG if you need this - information. - return: 0 if success, not 0 if some error occured. -*/ -int decodePNG(std::vector &out_image, unsigned long &image_width, - unsigned long &image_height, const unsigned char *in_png, - size_t in_size, bool convert_to_rgba32) -{ - // picoPNG version 20101224 - // Copyright (c) 2005-2010 Lode Vandevenne - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must - // not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must - // not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source - // distribution. - - // picoPNG is a PNG decoder in one C++ function of around 500 lines. Use - // picoPNG for - // programs that need only 1 .cpp file. Since it's a single function, it's - // very limited, - // it can convert a PNG to raw pixel data either converted to 32-bit RGBA - // color or - // with no color conversion at all. For anything more complex, another tiny - // library - // is available: LodePNG (lodepng.c(pp)), which is a single source and - // header file. - // Apologies for the compact code style, it's to make this tiny. - - static const unsigned long LENBASE[29] = { - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, - 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; - static const unsigned long LENEXTRA[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, - 4, 4, 4, 4, 5, 5, 5, 5, 0}; - static const unsigned long DISTBASE[30] = { - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, - 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, - 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; - static const unsigned long DISTEXTRA[30] = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, - 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; - static const unsigned long CLCL[19] = { - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, - 11, 4, 12, 3, 13, 2, 14, 1, 15}; // code length code lengths - struct Zlib // nested functions for zlib decompression - { - static unsigned long readBitFromStream(size_t &bitp, - const unsigned char *bits) - { - unsigned long result = (bits[bitp >> 3] >> (bitp & 0x7)) & 1; - bitp++; - return result; - } - static unsigned long readBitsFromStream(size_t &bitp, - const unsigned char *bits, - size_t nbits) - { - unsigned long result = 0; - for (size_t i = 0; i < nbits; i++) { - result += (readBitFromStream(bitp, bits)) << i; - } - return result; - } - struct HuffmanTree { - int makeFromLengths(const std::vector &bitlen, - unsigned long maxbitlen) - { // make tree given the lengths - unsigned long numcodes = (unsigned long)(bitlen.size()), - treepos = 0, nodefilled = 0; - std::vector tree1d(numcodes), - blcount(maxbitlen + 1, 0), nextcode(maxbitlen + 1, 0); - for (unsigned long bits = 0; bits < numcodes; bits++) { - blcount[bitlen[bits]]++; // count number of instances of - } - // each code length - for (unsigned long bits = 1; bits <= maxbitlen; bits++) { - nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) - << 1; - } - for (unsigned long n = 0; n < numcodes; n++) { - if (bitlen[n] != 0) { - tree1d[n] = - nextcode[bitlen[n]]++; // generate all the codes - } - } - tree2d.clear(); - tree2d.resize(numcodes * 2, 32767); // 32767 here means the - // tree2d isn't filled - // there yet - for (unsigned long n = 0; n < numcodes; n++) { // the codes - for (unsigned long i = 0; i < bitlen[n]; - i++) // the bits for this code - { - unsigned long bit = - (tree1d[n] >> (bitlen[n] - i - 1)) & 1; - if (treepos > numcodes - 2) { - return 55; - } - if (tree2d[2 * treepos + bit] == - 32767) // not yet filled in - { - if (i + 1 == bitlen[n]) { - tree2d[2 * treepos + bit] = n; - treepos = 0; - } // last bit - else { - tree2d[2 * treepos + bit] = - ++nodefilled + numcodes; - treepos = nodefilled; - } // addresses are encoded as values > numcodes - } else { - treepos = tree2d[2 * treepos + bit] - - numcodes; // subtract numcodes from - } - // address to get address value - } - } - return 0; - } - int decode(bool &decoded, unsigned long &result, size_t &treepos, - unsigned long bit) const - { // Decodes a symbol from the tree - unsigned long numcodes = (unsigned long)tree2d.size() / 2; - if (treepos >= numcodes) { - return 11; // error: you appeared outside the codetree - } - result = tree2d[2 * treepos + bit]; - decoded = (result < numcodes); - treepos = decoded ? 0 : result - numcodes; - return 0; - } - std::vector tree2d; // 2D representation of a - // huffman tree: The one - // dimension is "0" or "1", the - // other contains all nodes and - // leaves of the tree. - }; - struct Inflator { - int error; - void inflate(std::vector &out, - const std::vector &in, size_t inpos = 0) - { - size_t bp = 0, pos = 0; // bit pointer and byte pointer - error = 0; - unsigned long BFINAL = 0; - while (!BFINAL && !error) { - if (bp >> 3 >= in.size()) { - error = 52; - return; - } // error, bit pointer will jump past memory - BFINAL = readBitFromStream(bp, &in[inpos]); - unsigned long BTYPE = readBitFromStream(bp, &in[inpos]); - BTYPE += 2 * readBitFromStream(bp, &in[inpos]); - if (BTYPE == 3) { - error = 20; - return; - } // error: invalid BTYPE - else if (BTYPE == 0) { - inflateNoCompression(out, &in[inpos], bp, pos, - in.size()); - } else { - inflateHuffmanBlock(out, &in[inpos], bp, pos, in.size(), - BTYPE); - } - } - if (!error) { - out.resize(pos); // Only now we know the true size of out, - } - // resize it to that - } - void generateFixedTrees(HuffmanTree &tree, - HuffmanTree &treeD) // get the tree of a - // deflated block with - // fixed tree - { - std::vector bitlen(288, 8), bitlenD(32, 5); - ; - for (size_t i = 144; i <= 255; i++) { - bitlen[i] = 9; - } - for (size_t i = 256; i <= 279; i++) { - bitlen[i] = 7; - } - tree.makeFromLengths(bitlen, 15); - treeD.makeFromLengths(bitlenD, 15); - } - HuffmanTree codetree, codetreeD, - codelengthcodetree; // the code tree for Huffman codes, dist - // codes, and code length codes - unsigned long huffmanDecodeSymbol(const unsigned char *in, - size_t &bp, - const HuffmanTree &codetree, - size_t inlength) - { // decode a single symbol from given list of - // bits with given code tree. return value - // is the symbol - bool decoded; - unsigned long ct; - for (size_t treepos = 0;;) { - if ((bp & 0x07) == 0 && (bp >> 3) > inlength) { - error = 10; - return 0; - } // error: end reached without endcode - error = codetree.decode(decoded, ct, treepos, - readBitFromStream(bp, in)); - if (error) { - return 0; // stop, an error happened - } - if (decoded) { - return ct; - } - } - } - void getTreeInflateDynamic(HuffmanTree &tree, HuffmanTree &treeD, - const unsigned char *in, size_t &bp, - size_t inlength) - { // get the tree of a deflated block with - // dynamic tree, the tree itself is also - // Huffman compressed with a known tree - std::vector bitlen(288, 0), bitlenD(32, 0); - if (bp >> 3 >= inlength - 2) { - error = 49; - return; - } // the bit pointer is or will go past the memory - size_t HLIT = readBitsFromStream(bp, in, 5) + - 257; // number of literal/length codes + 257 - size_t HDIST = readBitsFromStream(bp, in, 5) + - 1; // number of dist codes + 1 - size_t HCLEN = readBitsFromStream(bp, in, 4) + - 4; // number of code length codes + 4 - std::vector codelengthcode( - 19); // lengths of tree to decode the lengths of the - // dynamic tree - for (size_t i = 0; i < 19; i++) { - codelengthcode[CLCL[i]] = - (i < HCLEN) ? readBitsFromStream(bp, in, 3) : 0; - } - error = codelengthcodetree.makeFromLengths(codelengthcode, 7); - if (error) { - return; - } - size_t i = 0, replength; - while (i < HLIT + HDIST) { - unsigned long code = huffmanDecodeSymbol( - in, bp, codelengthcodetree, inlength); - if (error) { - return; - } - if (code <= 15) { - if (i < HLIT) { - bitlen[i++] = code; - } else { - bitlenD[i++ - HLIT] = code; - } - } // a length code - else if (code == 16) // repeat previous - { - if (bp >> 3 >= inlength) { - error = 50; - return; - } // error, bit pointer jumps past memory - replength = 3 + readBitsFromStream(bp, in, 2); - unsigned long value; // set value to the previous code - if ((i - 1) < HLIT) { - value = bitlen[i - 1]; - } else { - value = bitlenD[i - HLIT - 1]; - } - for (size_t n = 0; n < replength; - n++) // repeat this value in the next lengths - { - if (i >= HLIT + HDIST) { - error = 13; - return; - } // error: i is larger than the amount of codes - if (i < HLIT) { - bitlen[i++] = value; - } else { - bitlenD[i++ - HLIT] = value; - } - } - } else if (code == 17) // repeat "0" 3-10 times - { - if (bp >> 3 >= inlength) { - error = 50; - return; - } // error, bit pointer jumps past memory - replength = 3 + readBitsFromStream(bp, in, 3); - for (size_t n = 0; n < replength; - n++) // repeat this value in the next lengths - { - if (i >= HLIT + HDIST) { - error = 14; - return; - } // error: i is larger than the amount of codes - if (i < HLIT) { - bitlen[i++] = 0; - } else { - bitlenD[i++ - HLIT] = 0; - } - } - } else if (code == 18) // repeat "0" 11-138 times - { - if (bp >> 3 >= inlength) { - error = 50; - return; - } // error, bit pointer jumps past memory - replength = 11 + readBitsFromStream(bp, in, 7); - for (size_t n = 0; n < replength; - n++) // repeat this value in the next lengths - { - if (i >= HLIT + HDIST) { - error = 15; - return; - } // error: i is larger than the amount of codes - if (i < HLIT) { - bitlen[i++] = 0; - } else { - bitlenD[i++ - HLIT] = 0; - } - } - } else { - error = 16; - return; - } // error: somehow an unexisting code appeared. This can - // never happen. - } - if (bitlen[256] == 0) { - error = 64; - return; - } // the length of the end code 256 must be larger than 0 - error = tree.makeFromLengths(bitlen, 15); - if (error) { - return; // now we've finally got HLIT and HDIST, so - } - // generate the code trees, and the function is - // done - error = treeD.makeFromLengths(bitlenD, 15); - if (error) { - return; - } - } - void inflateHuffmanBlock(std::vector &out, - const unsigned char *in, size_t &bp, - size_t &pos, size_t inlength, - unsigned long btype) - { - if (btype == 1) { - generateFixedTrees(codetree, codetreeD); - } else if (btype == 2) { - getTreeInflateDynamic(codetree, codetreeD, in, bp, - inlength); - if (error) { - return; - } - } - for (;;) { - unsigned long code = - huffmanDecodeSymbol(in, bp, codetree, inlength); - if (error) { - return; - } - if (code == 256) { - return; // end code - } else if (code <= 255) // literal symbol - { - if (pos >= out.size()) { - out.resize((pos + 1) * 2); // reserve more room - } - out[pos++] = (unsigned char)(code); - } else if (code >= 257 && code <= 285) // length code - { - size_t length = LENBASE[code - 257], - numextrabits = LENEXTRA[code - 257]; - if ((bp >> 3) >= inlength) { - error = 51; - return; - } // error, bit pointer will jump past memory - length += readBitsFromStream(bp, in, numextrabits); - unsigned long codeD = - huffmanDecodeSymbol(in, bp, codetreeD, inlength); - if (error) { - return; - } - if (codeD > 29) { - error = 18; - return; - } // error: invalid dist code (30-31 are never used) - unsigned long dist = DISTBASE[codeD], - numextrabitsD = DISTEXTRA[codeD]; - if ((bp >> 3) >= inlength) { - error = 51; - return; - } // error, bit pointer will jump past memory - dist += readBitsFromStream(bp, in, numextrabitsD); - size_t start = pos, back = start - dist; // backwards - if (pos + length >= out.size()) { - out.resize((pos + length) * 2); // reserve more - } - // room - for (size_t i = 0; i < length; i++) { - out[pos++] = out[back++]; - if (back >= start) { - back = start - dist; - } - } - } - } - } - void inflateNoCompression(std::vector &out, - const unsigned char *in, size_t &bp, - size_t &pos, size_t inlength) - { - while ((bp & 0x7) != 0) { - bp++; // go to first boundary of byte - } - size_t p = bp / 8; - if (p >= inlength - 4) { - error = 52; - return; - } // error, bit pointer will jump past memory - unsigned long LEN = in[p] + 256 * in[p + 1], - NLEN = in[p + 2] + 256 * in[p + 3]; - p += 4; - if (LEN + NLEN != 65535) { - error = 21; - return; - } // error: NLEN is not one's complement of LEN - if (pos + LEN >= out.size()) { - out.resize(pos + LEN); - } - if (p + LEN > inlength) { - error = 23; - return; - } // error: reading outside of in buffer - for (unsigned long n = 0; n < LEN; n++) { - out[pos++] = in[p++]; // read LEN bytes of literal data - } - bp = p * 8; - } - }; - int - decompress(std::vector &out, - const std::vector &in) // returns error value - { - Inflator inflator; - if (in.size() < 2) { - return 53; - } // error, size of zlib data too small - if ((in[0] * 256 + in[1]) % 31 != 0) { - return 24; - } // error: 256 * in[0] + in[1] must be a multiple of 31, the - // FCHECK value is supposed to be made that way - unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, - FDICT = (in[1] >> 5) & 1; - if (CM != 8 || CINFO > 7) { - return 25; - } // error: only compression method 8: inflate with sliding window - // of 32k is supported by the PNG spec - if (FDICT != 0) { - return 26; - } // error: the specification of PNG says about the zlib stream: - // "The additional flags shall not specify a preset dictionary." - inflator.inflate(out, in, 2); - return inflator - .error; // note: adler32 checksum was skipped and ignored - } - }; - struct PNG // nested functions for PNG decoding - { - struct Info { - unsigned long width, height, colorType, bitDepth, compressionMethod, - filterMethod, interlaceMethod, key_r, key_g, key_b; - bool key_defined; // is a transparent color key given? - std::vector palette; - } info; - int error; - void decode(std::vector &out, const unsigned char *in, - size_t size, bool convert_to_rgba32) - { - error = 0; - if (size == 0 || in == nullptr) { - error = 48; - return; - } // the given data is empty - readPngHeader(&in[0], size); - if (error) { - return; - } - size_t pos = 33; // first byte of the first chunk after the header - std::vector idat; // the data from idat chunks - bool IEND = false, known_type = true; - info.key_defined = false; - while (!IEND) // loop through the chunks, ignoring unknown chunks - // and stopping at IEND chunk. IDAT data is put at - // the start of the in buffer - { - if (pos + 8 >= size) { - error = 30; - return; - } // error: size of the in buffer too small to contain next - // chunk - size_t chunkLength = read32bitInt(&in[pos]); - pos += 4; - if (chunkLength > 2147483647) { - error = 63; - return; - } - if (pos + chunkLength >= size) { - error = 35; - return; - } // error: size of the in buffer too small to contain next - // chunk - if (in[pos + 0] == 'I' && in[pos + 1] == 'D' && - in[pos + 2] == 'A' && - in[pos + 3] == - 'T') // IDAT chunk, containing compressed image data - { - idat.insert(idat.end(), &in[pos + 4], - &in[pos + 4 + chunkLength]); - pos += (4 + chunkLength); - } else if (in[pos + 0] == 'I' && in[pos + 1] == 'E' && - in[pos + 2] == 'N' && in[pos + 3] == 'D') { - pos += 4; - IEND = true; - } else if (in[pos + 0] == 'P' && in[pos + 1] == 'L' && - in[pos + 2] == 'T' && - in[pos + 3] == 'E') // palette chunk (PLTE) - { - pos += 4; // go after the 4 letters - info.palette.resize(4 * (chunkLength / 3)); - if (info.palette.size() > (4 * 256)) { - error = 38; - return; - } // error: palette too big - for (size_t i = 0; i < info.palette.size(); i += 4) { - for (size_t j = 0; j < 3; j++) { - info.palette[i + j] = in[pos++]; // RGB - } - info.palette[i + 3] = 255; // alpha - } - } else if (in[pos + 0] == 't' && in[pos + 1] == 'R' && - in[pos + 2] == 'N' && - in[pos + 3] == - 'S') // palette transparency chunk (tRNS) - { - pos += 4; // go after the 4 letters - if (info.colorType == 3) { - if (4 * chunkLength > info.palette.size()) { - error = 39; - return; - } // error: more alpha values given than there are - // palette entries - for (size_t i = 0; i < chunkLength; i++) { - info.palette[4 * i + 3] = in[pos++]; - } - } else if (info.colorType == 0) { - if (chunkLength != 2) { - error = 40; - return; - } // error: this chunk must be 2 bytes for greyscale - // image - info.key_defined = true; - info.key_r = info.key_g = info.key_b = - 256 * in[pos] + in[pos + 1]; - pos += 2; - } else if (info.colorType == 2) { - if (chunkLength != 6) { - error = 41; - return; - } // error: this chunk must be 6 bytes for RGB image - info.key_defined = true; - info.key_r = 256 * in[pos] + in[pos + 1]; - pos += 2; - info.key_g = 256 * in[pos] + in[pos + 1]; - pos += 2; - info.key_b = 256 * in[pos] + in[pos + 1]; - pos += 2; - } else { - error = 42; - return; - } // error: tRNS chunk not allowed for other color models - } else // it's not an implemented chunk type, so ignore it: - // skip over the data - { - if (!(in[pos + 0] & 32)) { - error = 69; - return; - } // error: unknown critical chunk (5th bit of first byte - // of chunk type is 0) - pos += (chunkLength + 4); // skip 4 letters and - // uninterpreted data of - // unimplemented chunk - known_type = false; - } - pos += 4; // step over CRC (which is ignored) - } - unsigned long bpp = getBpp(info); - std::vector scanlines( - ((info.width * (info.height * bpp + 7)) / 8) + - info.height); // now the out buffer will be filled - Zlib zlib; // decompress with the Zlib decompressor - error = zlib.decompress(scanlines, idat); - if (error) { - return; // stop if the zlib decompressor returned an error - } - size_t bytewidth = (bpp + 7) / 8, - outlength = (info.height * info.width * bpp + 7) / 8; - out.resize(outlength); // time to fill the out buffer - unsigned char *out_ = - outlength ? &out[0] : nullptr; // use a regular pointer to the - // std::vector for faster code if - // compiled without optimization - if (info.interlaceMethod == 0) // no interlace, just filter - { - size_t linestart = 0, - linelength = (info.width * bpp + 7) / - 8; // length in bytes of a scanline, - // excluding the filtertype byte - if (bpp >= 8) { // byte per byte - for (unsigned long y = 0; y < info.height; y++) { - unsigned long filterType = scanlines[linestart]; - const unsigned char *prevline = - (y == 0) ? nullptr - : &out_[(y - 1) * info.width * bytewidth]; - unFilterScanline(&out_[linestart - y], - &scanlines[linestart + 1], prevline, - bytewidth, filterType, linelength); - if (error) { - return; - } - linestart += - (1 + linelength); // go to start of next scanline - } - } else // less than 8 bits per pixel, so fill it up bit per bit - { - std::vector templine( - (info.width * bpp + 7) >> 3); // only used if bpp < 8 - for (size_t y = 0, obp = 0; y < info.height; y++) { - unsigned long filterType = scanlines[linestart]; - const unsigned char *prevline = - (y == 0) ? nullptr - : &out_[(y - 1) * info.width * bytewidth]; - unFilterScanline(&templine[0], - &scanlines[linestart + 1], prevline, - bytewidth, filterType, linelength); - if (error) { - return; - } - for (size_t bp = 0; bp < info.width * bpp;) { - setBitOfReversedStream( - obp, out_, - readBitFromReversedStream(bp, &templine[0])); - } - linestart += - (1 + linelength); // go to start of next scanline - } - } - } else // interlaceMethod is 1 (Adam7) - { - size_t passw[7] = {(info.width + 7) / 8, (info.width + 3) / 8, - (info.width + 3) / 4, (info.width + 1) / 4, - (info.width + 1) / 2, (info.width + 0) / 2, - (info.width + 0) / 1}; - size_t passh[7] = {(info.height + 7) / 8, (info.height + 7) / 8, - (info.height + 3) / 8, (info.height + 3) / 4, - (info.height + 1) / 4, (info.height + 1) / 2, - (info.height + 0) / 2}; - size_t passstart[7] = {0}; - size_t pattern[28] = {0, 4, 0, 2, 0, 1, 0, 0, 0, 4, - 0, 2, 0, 1, 8, 8, 4, 4, 2, 2, - 1, 8, 8, 8, 4, 4, 2, 2}; // values for the - // adam7 passes - for (int i = 0; i < 6; i++) { - passstart[i + 1] = passstart[i] + - passh[i] * ((passw[i] ? 1 : 0) + - (passw[i] * bpp + 7) / 8); - } - std::vector scanlineo((info.width * bpp + 7) / - 8), - scanlinen((info.width * bpp + 7) / - 8); //"old" and "new" scanline - for (int i = 0; i < 7; i++) { - adam7Pass(&out_[0], &scanlinen[0], &scanlineo[0], - &scanlines[passstart[i]], info.width, pattern[i], - pattern[i + 7], pattern[i + 14], pattern[i + 21], - passw[i], passh[i], bpp); - } - } - if (convert_to_rgba32 && (info.colorType != 6 || - info.bitDepth != 8)) // conversion needed - { - std::vector data = out; - error = convert(out, &data[0], info, info.width, info.height); - } - } - void readPngHeader(const unsigned char *in, - size_t inlength) // read the information from the - // header and store it in the Info - { - if (inlength < 29) { - error = 27; - return; - } // error: the data length is smaller than the length of the - // header - if (in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || - in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { - error = 28; - return; - } // no PNG signature - if (in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || - in[15] != 'R') { - error = 29; - return; - } // error: it doesn't start with a IHDR chunk! - info.width = read32bitInt(&in[16]); - info.height = read32bitInt(&in[20]); - info.bitDepth = in[24]; - info.colorType = in[25]; - info.compressionMethod = in[26]; - if (in[26] != 0) { - error = 32; - return; - } // error: only compression method 0 is allowed in the - // specification - info.filterMethod = in[27]; - if (in[27] != 0) { - error = 33; - return; - } // error: only filter method 0 is allowed in the specification - info.interlaceMethod = in[28]; - if (in[28] > 1) { - error = 34; - return; - } // error: only interlace methods 0 and 1 exist in the - // specification - error = checkColorValidity(info.colorType, info.bitDepth); - } - void unFilterScanline(unsigned char *recon, - const unsigned char *scanline, - const unsigned char *precon, size_t bytewidth, - unsigned long filterType, size_t length) - { - switch (filterType) { - case 0: - for (size_t i = 0; i < length; i++) { - recon[i] = scanline[i]; - } - break; - case 1: - for (size_t i = 0; i < bytewidth; i++) { - recon[i] = scanline[i]; - } - for (size_t i = bytewidth; i < length; i++) { - recon[i] = scanline[i] + recon[i - bytewidth]; - } - break; - case 2: - if (precon) { - for (size_t i = 0; i < length; i++) { - recon[i] = scanline[i] + precon[i]; - } - } else { - for (size_t i = 0; i < length; i++) { - recon[i] = scanline[i]; - } - } - break; - case 3: - if (precon) { - for (size_t i = 0; i < bytewidth; i++) { - recon[i] = scanline[i] + precon[i] / 2; - } - for (size_t i = bytewidth; i < length; i++) { - recon[i] = scanline[i] + - ((recon[i - bytewidth] + precon[i]) / 2); - } - } else { - for (size_t i = 0; i < bytewidth; i++) { - recon[i] = scanline[i]; - } - for (size_t i = bytewidth; i < length; i++) { - recon[i] = scanline[i] + recon[i - bytewidth] / 2; - } - } - break; - case 4: - if (precon) { - for (size_t i = 0; i < bytewidth; i++) { - recon[i] = - scanline[i] + paethPredictor(0, precon[i], 0); - } - for (size_t i = bytewidth; i < length; i++) { - recon[i] = - scanline[i] + paethPredictor(recon[i - bytewidth], - precon[i], - precon[i - bytewidth]); - } - } else { - for (size_t i = 0; i < bytewidth; i++) { - recon[i] = scanline[i]; - } - for (size_t i = bytewidth; i < length; i++) { - recon[i] = scanline[i] + - paethPredictor(recon[i - bytewidth], 0, 0); - } - } - break; - default: - error = 36; - return; // error: unexisting filter type given - } - } - void adam7Pass(unsigned char *out, unsigned char *linen, - unsigned char *lineo, const unsigned char *in, - unsigned long w, size_t passleft, size_t passtop, - size_t spacex, size_t spacey, size_t passw, size_t passh, - unsigned long bpp) - { // filter and reposition the pixels - // into the output when the image - // is Adam7 interlaced. This - // function can only do it after - // the full image is already - // decoded. The out buffer must - // have the correct allocated - // memory size already. - if (passw == 0) { - return; - } - size_t bytewidth = (bpp + 7) / 8, - linelength = 1 + ((bpp * passw + 7) / 8); - for (unsigned long y = 0; y < passh; y++) { - unsigned char filterType = in[y * linelength], - *prevline = (y == 0) ? nullptr : lineo; - unFilterScanline(linen, &in[y * linelength + 1], prevline, - bytewidth, filterType, (w * bpp + 7) / 8); - if (error) { - return; - } - if (bpp >= 8) { - for (size_t i = 0; i < passw; i++) { - for (size_t b = 0; b < bytewidth; - b++) { // b = current byte of this pixel - out[bytewidth * w * (passtop + spacey * y) + - bytewidth * (passleft + spacex * i) + b] = - linen[bytewidth * i + b]; - } - } - } else { - for (size_t i = 0; i < passw; i++) { - size_t obp = bpp * w * (passtop + spacey * y) + - bpp * (passleft + spacex * i), - bp = i * bpp; - for (size_t b = 0; b < bpp; b++) { - setBitOfReversedStream( - obp, out, - readBitFromReversedStream(bp, &linen[0])); - } - } - } - unsigned char *temp = linen; - linen = lineo; - lineo = temp; // swap the two buffer pointers "line old" and - // "line new" - } - } - static unsigned long - readBitFromReversedStream(size_t &bitp, const unsigned char *bits) - { - unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1; - bitp++; - return result; - } - static unsigned long - readBitsFromReversedStream(size_t &bitp, const unsigned char *bits, - unsigned long nbits) - { - unsigned long result = 0; - for (size_t i = nbits - 1; i < nbits; i--) { - result += ((readBitFromReversedStream(bitp, bits)) << i); - } - return result; - } - void setBitOfReversedStream(size_t &bitp, unsigned char *bits, - unsigned long bit) - { - bits[bitp >> 3] |= (bit << (7 - (bitp & 0x7))); - bitp++; - } - unsigned long read32bitInt(const unsigned char *buffer) - { - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | - buffer[3]; - } - int checkColorValidity( - unsigned long colorType, - unsigned long bd) // return type is a LodePNG error code - { - if ((colorType == 2 || colorType == 4 || colorType == 6)) { - if (!(bd == 8 || bd == 16)) { - return 37; - } else { - return 0; - } - } else if (colorType == 0) { - if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) { - return 37; - } else { - return 0; - } - } else if (colorType == 3) { - if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8)) { - return 37; - } else { - return 0; - } - } else { - return 31; // unexisting color type - } - } - unsigned long getBpp(const Info &info) - { - if (info.colorType == 2) { - return (3 * info.bitDepth); - } else if (info.colorType >= 4) { - return (info.colorType - 2) * info.bitDepth; - } else { - return info.bitDepth; - } - } - int convert(std::vector &out, const unsigned char *in, - Info &infoIn, unsigned long w, unsigned long h) - { // converts from any color type to - // 32-bit. return value = LodePNG error - // code - size_t numpixels = w * h, bp = 0; - out.resize(numpixels * 4); - unsigned char *out_ = - out.empty() - ? nullptr - : &out[0]; // faster if compiled without optimization - if (infoIn.bitDepth == 8 && infoIn.colorType == 0) { // greyscale - for (size_t i = 0; i < numpixels; i++) { - out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[i]; - out_[4 * i + 3] = - (infoIn.key_defined && in[i] == infoIn.key_r) ? 0 : 255; - } - } else if (infoIn.bitDepth == 8 && infoIn.colorType == 2) { // RGB - // color - for (size_t i = 0; i < numpixels; i++) { - for (size_t c = 0; c < 3; c++) { - out_[4 * i + c] = in[3 * i + c]; - } - out_[4 * i + 3] = (infoIn.key_defined == 1 && - in[3 * i + 0] == infoIn.key_r && - in[3 * i + 1] == infoIn.key_g && - in[3 * i + 2] == infoIn.key_b) - ? 0 - : 255; - } - } else if (infoIn.bitDepth == 8 && - infoIn.colorType == 3) { // indexed color (palette) - for (size_t i = 0; i < numpixels; i++) { - if (4U * in[i] >= infoIn.palette.size()) { - return 46; - } - for (size_t c = 0; c < 4; c++) { - out_[4 * i + c] = - infoIn.palette[4 * in[i] + c]; // get rgb colors - } - // from the palette - } - } else if (infoIn.bitDepth == 8 && - infoIn.colorType == 4) { // greyscale with alpha - for (size_t i = 0; i < numpixels; i++) { - out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = - in[2 * i + 0]; - out_[4 * i + 3] = in[2 * i + 1]; - } - } else if (infoIn.bitDepth == 8 && infoIn.colorType == 6) { - for (size_t i = 0; i < numpixels; i++) { - for (size_t c = 0; c < 4; c++) { - out_[4 * i + c] = in[4 * i + c]; // RGB with alpha - } - } - } else if (infoIn.bitDepth == 16 && - infoIn.colorType == 0) { // greyscale - for (size_t i = 0; i < numpixels; i++) { - out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = - in[2 * i]; - out_[4 * i + 3] = (infoIn.key_defined && - 256U * in[i] + in[i + 1] == infoIn.key_r) - ? 0 - : 255; - } - } else if (infoIn.bitDepth == 16 && - infoIn.colorType == 2) { // RGB color - for (size_t i = 0; i < numpixels; i++) { - for (size_t c = 0; c < 3; c++) { - out_[4 * i + c] = in[6 * i + 2 * c]; - } - out_[4 * i + 3] = - (infoIn.key_defined && - 256U * in[6 * i + 0] + in[6 * i + 1] == infoIn.key_r && - 256U * in[6 * i + 2] + in[6 * i + 3] == infoIn.key_g && - 256U * in[6 * i + 4] + in[6 * i + 5] == infoIn.key_b) - ? 0 - : 255; - } - } else if (infoIn.bitDepth == 16 && - infoIn.colorType == 4) { // greyscale with alpha - for (size_t i = 0; i < numpixels; i++) { - out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = - in[4 * i]; // most significant byte - out_[4 * i + 3] = in[4 * i + 2]; - } - } else if (infoIn.bitDepth == 16 && infoIn.colorType == 6) { - for (size_t i = 0; i < numpixels; i++) { - for (size_t c = 0; c < 4; c++) { - out_[4 * i + c] = in[8 * i + 2 * c]; // RGB with alpha - } - } - } else if (infoIn.bitDepth < 8 && - infoIn.colorType == 0) { // greyscale - for (size_t i = 0; i < numpixels; i++) { - unsigned long value = - (readBitsFromReversedStream(bp, in, infoIn.bitDepth) * - 255) / - ((1 << infoIn.bitDepth) - - 1); // scale value from 0 to 255 - out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = - (unsigned char)(value); - out_[4 * i + 3] = - (infoIn.key_defined && value && - ((1U << infoIn.bitDepth) - 1U) == infoIn.key_r && - ((1U << infoIn.bitDepth) - 1U)) - ? 0 - : 255; - } - } else if (infoIn.bitDepth < 8 && - infoIn.colorType == 3) { // palette - for (size_t i = 0; i < numpixels; i++) { - unsigned long value = - readBitsFromReversedStream(bp, in, infoIn.bitDepth); - if (4 * value >= infoIn.palette.size()) { - return 47; - } - for (size_t c = 0; c < 4; c++) { - out_[4 * i + c] = - infoIn.palette[4 * value + c]; // get rgb colors - } - // from the palette - } - } - return 0; - } - unsigned char - paethPredictor(short a, short b, - short c) // Paeth predicter, used by PNG filter type 4 - { - short p = a + b - c, pa = p > a ? (p - a) : (a - p), - pb = p > b ? (p - b) : (b - p), - pc = p > c ? (p - c) : (c - p); - return (unsigned char)((pa <= pb && pa <= pc) ? a - : pb <= pc ? b : c); - } - }; - PNG decoder; - decoder.decode(out_image, in_png, in_size, convert_to_rgba32); - image_width = decoder.info.width; - image_height = decoder.info.height; - return decoder.error; -} - -} // namespace yage diff --git a/src/rectanglecollider.cpp b/src/rectanglecollider.cpp deleted file mode 100644 index 64887278..00000000 --- a/src/rectanglecollider.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* ---------------------------------------------------------------------------- - * rectanglecollider.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include - -namespace yage -{ - -RectangleCollider::RectangleCollider(const glm::vec2 &position, - const glm::vec2 &size) - : Collider(position, size) -{ -} - -bool RectangleCollider::collides(const Collider &collider) const -{ - for (int i = position_.x; i < position_.x + size_.x; ++i) { - for (int j = position_.y; j < position_.y + size_.y; ++j) { - return collider.inside(glm::vec2(i, j)); - } - } - return false; -} - -inline bool RectangleCollider::inside(const glm::vec2 &point) const -{ - return position_.x < point.x && position_.x + size_.x > point.x && - position_.y < point.y && position_.y + size_.y > point.y; -} - -} // namespace yage diff --git a/src/resourcemanager.cpp b/src/resourcemanager.cpp deleted file mode 100644 index 473ea37e..00000000 --- a/src/resourcemanager.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* ---------------------------------------------------------------------------- - * resourcemanager.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include - -namespace yage -{ - -TextureCache ResourceManager::texture_cache_; - -Texture ResourceManager::getTexture(const std::string &texture_path) -{ - return texture_cache_.getTexture(texture_path); -} - -} // namespace yage diff --git a/src/rigidbody.cpp b/src/rigidbody.cpp deleted file mode 100644 index dcab5f2f..00000000 --- a/src/rigidbody.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* ---------------------------------------------------------------------------- - * rigidbody.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include - -namespace yage -{ - -RigidBody::RigidBody(const Vector2d &position, double mass, - const Vector2d &velocity, bool gravity) - : ParticleBody(position, mass, velocity, gravity) -{ -} - -} // namespace yage diff --git a/src/sprite.cpp b/src/sprite.cpp deleted file mode 100644 index 68e08e5d..00000000 --- a/src/sprite.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* ---------------------------------------------------------------------------- - * sprite.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include -#include -#include - -#include - -namespace yage -{ - -Sprite::Sprite() = default; - -Sprite::~Sprite() -{ - if (vbo_id_ != 0) { - glDeleteBuffers(1, &vbo_id_); - } -} - -void Sprite::init(float x, float y, float width, float height, - const std::string &texture_path) -{ - x_ = x; - y_ = y; - width_ = width; - height_ = height; - texture_ = ResourceManager::getTexture(texture_path); - - if (vbo_id_ == 0) { - glGenBuffers(1, &vbo_id_); - } - - Vertex vertex_data[6]; - - vertex_data[0].setPosition(x + width, y + height); - vertex_data[0].setUv(1.f, 1.f); - - vertex_data[1].setPosition(x, y + height); - vertex_data[1].setUv(0.f, 1.f); - - vertex_data[2].setPosition(x, y); - vertex_data[2].setUv(0.f, 0.f); - - vertex_data[3].setPosition(x, y); - vertex_data[3].setUv(0.f, 0.f); - - vertex_data[4].setPosition(x + width, y + height); - vertex_data[4].setUv(1.f, 1.f); - - vertex_data[5].setPosition(x + width, y); - vertex_data[5].setUv(1.f, 0.f); - - for (auto &i : vertex_data) { - i.setColor(255, 0, 255, 255); - } - - vertex_data[1].setColor(0, 255, 255, 255); - vertex_data[4].setColor(255, 0, 0, 255); - - glBindBuffer(GL_ARRAY_BUFFER, vbo_id_); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, - GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void Sprite::draw() -{ - glBindTexture(GL_TEXTURE_2D, texture_.id); - glBindBuffer(GL_ARRAY_BUFFER, vbo_id_); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), - (void *)offsetof(Vertex, position)); - glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), - (void *)offsetof(Vertex, color)); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), - (void *)offsetof(Vertex, uv)); - glDrawArrays(GL_TRIANGLES, 0, 6); - - glDisableVertexAttribArray(2); - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -} // namespace yage diff --git a/src/spritebatch.cpp b/src/spritebatch.cpp deleted file mode 100644 index ac98130b..00000000 --- a/src/spritebatch.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* ---------------------------------------------------------------------------- - * spritebatch.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include - -#include -#include - -namespace yage -{ - -const int SpriteBatch::NUM_VERTICES; - -Glyph::Glyph(GLuint texture, float depth, const Vertex &top_left, - const Vertex &top_right, const Vertex &bottom_right, - const Vertex &bottom_left) - : texture_(texture), depth_(depth), top_left_(top_left), - top_right_(top_right), bottom_right_(bottom_right), - bottom_left_(bottom_left) -{ -} - -RenderBatch::RenderBatch(GLint offset, GLsizei num_vertices, GLuint texture) - : num_vertices_(num_vertices), offset_(offset), texture_(texture) -{ -} - -SpriteBatch::SpriteBatch() = default; - -SpriteBatch::~SpriteBatch() -{ - if (vao_ != 0) { - glDeleteVertexArrays(1, &vao_); - } - - if (vbo_ != 0) { - glDeleteVertexArrays(1, &vbo_); - } -} - -void SpriteBatch::init() -{ - createVertexArray(); -} - -void SpriteBatch::begin() -{ - glyphs_.clear(); - glyph_ptrs_.clear(); - render_batches_.clear(); -} - -void SpriteBatch::end() -{ - sortGlyphs(); - createRenderBatches(); -} - -void SpriteBatch::draw(const glm::vec4 &destination_rect, - const glm::vec4 &uv_rect, GLuint texture, - const Color &color, float depth) -{ - Vertex top_left, top_right, bottom_right, bottom_left; - - top_left.color = color; - top_left.setPosition(destination_rect.x, - destination_rect.y + destination_rect.w); - top_left.setUv(uv_rect.x, uv_rect.y + uv_rect.w); - - top_right.color = color; - top_right.setPosition(destination_rect.x + destination_rect.z, - destination_rect.y + destination_rect.w); - top_right.setUv(uv_rect.x + uv_rect.z, uv_rect.y + uv_rect.w); - - bottom_right.color = color; - bottom_right.setPosition(destination_rect.x + destination_rect.z, - destination_rect.y); - bottom_right.setUv(uv_rect.x + uv_rect.z, uv_rect.y); - - bottom_left.color = color; - bottom_left.setPosition(destination_rect.x, destination_rect.y); - bottom_left.setUv(uv_rect.x, uv_rect.y); - - // deal with fragmenting by creating vector of pointers - glyphs_.emplace_back(texture, depth, top_left, top_right, bottom_right, - bottom_left); - glyph_ptrs_.push_back(&glyphs_.back()); -} - -void SpriteBatch::render() -{ - glBindVertexArray(vao_); - for (auto &&batch : render_batches_) { - glBindTexture(GL_TEXTURE_2D, batch.texture()); - glDrawArrays(GL_TRIANGLES, batch.offset(), batch.num_vertices()); - } - glBindVertexArray(0); -} - -void SpriteBatch::createVertexArray() -{ - if (vao_ == 0) { - glGenVertexArrays(1, &vao_); - if (vao_ == 0) { - throw std::runtime_error("glGenVertexArrays failed"); - } - } - // bind vertex array object - glBindVertexArray(vao_); - - if (vbo_ == 0) { - glGenBuffers(1, &vbo_); - if (vbo_ == 0) { - throw std::runtime_error("glGenBuffers failed"); - } - } - // bind vertex buffer object - glBindBuffer(GL_ARRAY_BUFFER, vbo_); - - // enable vertex attribute arrays - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - - // set the vertex attribute pointers - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), - (void *)offsetof(Vertex, position)); - glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), - (void *)offsetof(Vertex, color)); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), - (void *)offsetof(Vertex, uv)); - glDrawArrays(GL_TRIANGLES, 0, 6); - - // unbind vertex array object - glBindVertexArray(0); -} - -void SpriteBatch::createRenderBatches() -{ - std::vector vertices; - if (glyph_ptrs_.empty()) { - return; - } - - render_batches_.reserve(glyph_ptrs_.size() * NUM_VERTICES); - - for (int i = 0; i < (int)glyph_ptrs_.size(); ++i) { - if (i == 0 || (i > 0 && (glyph_ptrs_[i]->texture() != - glyph_ptrs_[i - 1]->texture()))) { - render_batches_.emplace_back(i * NUM_VERTICES, NUM_VERTICES, - glyph_ptrs_[i]->texture()); - } else { - render_batches_.back().num_vertices_ += NUM_VERTICES; - } - - vertices.push_back(glyph_ptrs_[i]->bottom_left()); - vertices.push_back(glyph_ptrs_[i]->top_left()); - vertices.push_back(glyph_ptrs_[i]->top_right()); - vertices.push_back(glyph_ptrs_[i]->bottom_left()); - vertices.push_back(glyph_ptrs_[i]->bottom_right()); - vertices.push_back(glyph_ptrs_[i]->top_right()); - - // bind vbo - glBindBuffer(GL_ARRAY_BUFFER, vbo_); - // orphan the buffer - glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), nullptr, - GL_DYNAMIC_DRAW); - // upload the data - glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(Vertex), - vertices.data()); - // unbind buffer - glBindBuffer(GL_ARRAY_BUFFER, 0); - } -} - -void SpriteBatch::sortGlyphs() -{ - // sort using introsort or quicksort - std::sort(glyph_ptrs_.begin(), glyph_ptrs_.end(), - [](Glyph *a, Glyph *b) -> bool { - if (a->depth() == b->depth()) { - return a->texture() < b->texture(); - } - return a->depth() < b->depth(); - }); -} - -} // namespace yage diff --git a/src/texturecache.cpp b/src/texturecache.cpp deleted file mode 100644 index fda5fcd9..00000000 --- a/src/texturecache.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* ---------------------------------------------------------------------------- - * texturecache.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include -#include - -namespace yage -{ - -TextureCache::TextureCache() = default; - -Texture TextureCache::getTexture(const std::string &texture_path) -{ - auto itr = texture_map_.find(texture_path); - - if (itr == texture_map_.end()) { - Texture new_texture = ImageLoader::loadPng(texture_path); - texture_map_.insert(make_pair(texture_path, new_texture)); - return new_texture; - } - - return itr->second; -} - -} // namespace yage diff --git a/src/window.cpp b/src/window.cpp deleted file mode 100644 index 143b1d5d..00000000 --- a/src/window.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* ---------------------------------------------------------------------------- - * window.cpp - * - * Copyright (c) 2017 Yann Herklotz Grave -- MIT License - * See file LICENSE for more details - * ---------------------------------------------------------------------------- - */ - -#include -#include - -#include -#include - -namespace yage -{ - -Window::Window() = default; - -Window::~Window() -{ - SDL_DestroyWindow(window_); -} - -void Window::create(const std::string &window_name, int width, int height, - unsigned flags) -{ - Uint32 gl_window_states = 0; - - // set the correct input flags - if (flags & WindowFlags::SHOWN) { - gl_window_states |= SDL_WINDOW_OPENGL; - } - if (flags & WindowFlags::HIDDEN) { - gl_window_states |= SDL_WINDOW_HIDDEN; - } - if (flags & WindowFlags::FULLSCREEN) { - gl_window_states |= SDL_WINDOW_FULLSCREEN; - } - if (flags & WindowFlags::BORDERLESS) { - gl_window_states |= SDL_WINDOW_BORDERLESS; - } - - // SDL_GL options - - // SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 4); - // SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 5); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - - // create the SDL window - window_ = SDL_CreateWindow(window_name.c_str(), SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, width, height, - gl_window_states); - if (window_ == nullptr) { - throw std::runtime_error("SDL_CreateWindow failed"); - } - - // initialize the GL context in the window - SDL_GLContext gl_context = SDL_GL_CreateContext(window_); - if (gl_context == nullptr) { - throw std::runtime_error("SDL_GL_CreateContext failed"); - } - - // initialize glew - GLenum error = glewInit(); - if (error != GLEW_OK) { - throw std::runtime_error("glewInit failed"); - } - - // print out the current OpenGL version to debug - std::cout << "*** OpenGL version: " << glGetString(GL_VERSION) - << " ***\n"; - - // set vsync on instead of custom fps limiting - SDL_GL_SetSwapInterval(1); - // set the clear color to black - glClearColor(0.f, 0.5f, 0.f, 1.f); - // set alpha blending - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -} - -void Window::swapBuffer() -{ - // swap the window buffer - SDL_GL_SwapWindow(window_); -} - -void Window::clearBuffer() -{ - // set the clear depth - glClearDepth(1.f); - // clears buffer with clear color - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - -} // namespace yage diff --git a/yage/CMakeLists.txt b/yage/CMakeLists.txt new file mode 100644 index 00000000..d45ffa90 --- /dev/null +++ b/yage/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_policy(SET CMP0048 NEW) + +project(yage + VERSION 0.1.1.0 + LANGUAGES CXX + ) + +include(base/CMakeLists.txt) +include(physics/CMakeLists.txt) +include(math/CMakeLists.txt) + +set(YAGE_SOURCES + ${YAGE_BASE_SOURCES} + ${YAGE_PHYSICS_SOURCES} + ${YAGE_MATH_SOURCES} + ) + +set(${PROJECT_NAME}_DIR + ${PROJECT_SOURCE_DIR}) + +add_library(${PROJECT_NAME} + ${YAGE_SOURCES} + ) + +target_include_directories(${PROJECT_NAME} + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ) + +target_link_libraries(${PROJECT_NAME} + ${OPENGL_LIBRARIES} + ${GLEW_LIBRARIES} + ${SDL2_LIBRARIES} + ) diff --git a/yage/base/CMakeLists.txt b/yage/base/CMakeLists.txt new file mode 100644 index 00000000..acdb78bf --- /dev/null +++ b/yage/base/CMakeLists.txt @@ -0,0 +1,13 @@ +set(YAGE_BASE_SOURCES + base/imageloader.cpp + base/window.cpp + base/texturecache.cpp + base/glslprogram.cpp + base/spritebatch.cpp + base/resourcemanager.cpp + base/sprite.cpp + base/inputmanager.cpp + base/picopng.cpp + base/camera2d.cpp + base/iomanager.cpp + ) diff --git a/yage/base/camera2d.cpp b/yage/base/camera2d.cpp new file mode 100644 index 00000000..292f998a --- /dev/null +++ b/yage/base/camera2d.cpp @@ -0,0 +1,45 @@ +/* ---------------------------------------------------------------------------- + * camera2d.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include + +#include + +namespace yage +{ + +Camera2D::Camera2D(int screen_width, int screen_height) + : position_(0.f, 0.f), camera_matrix_(1.f), + ortho_matrix_( + glm::ortho(0.f, (float)screen_width, 0.f, (float)screen_height)) +{ +} + +void Camera2D::update(GlslProgram &program) +{ + if (update_matrix_) { + glm::vec3 translate(-position_.x, -position_.y, 0.f); + glm::vec3 scale(scale_, scale_, 0.f); + + camera_matrix_ = glm::translate(ortho_matrix_, translate); + camera_matrix_ = glm::scale(glm::mat4(1.f), scale) * camera_matrix_; + + update_matrix_ = false; + } + + GLint matrix_location = program.getUniformLocation("P"); + glUniformMatrix4fv(matrix_location, 1, GL_FALSE, &(camera_matrix_[0][0])); +} + +void Camera2D::move(const glm::vec2 &direction) +{ + position_ += direction; + update_matrix_ = true; +} + +} // namespace yage diff --git a/yage/base/camera2d.h b/yage/base/camera2d.h new file mode 100644 index 00000000..a60893ac --- /dev/null +++ b/yage/base/camera2d.h @@ -0,0 +1,38 @@ +/* ---------------------------------------------------------------------------- + * camera2d.h + * + * Copyright (c) 2017 Yann Herklotz Grave + * MIT License, see LICENSE file for more details. + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_CAMERA2D_H +#define YAGE_CAMERA2D_H + +#include "glslprogram.h" + +#include +#include + +namespace yage +{ + +class Camera2D +{ +private: + bool update_matrix_ = true; + float scale_ = 1; + glm::vec2 position_; + glm::mat4 camera_matrix_; + glm::mat4 ortho_matrix_; + +public: + Camera2D(int screen_width = 1280, int screen_height = 720); + + void update(GlslProgram &program); + void move(const glm::vec2 &direction); +}; + +} // namespace yage + +#endif diff --git a/yage/base/glslprogram.cpp b/yage/base/glslprogram.cpp new file mode 100644 index 00000000..11a3191e --- /dev/null +++ b/yage/base/glslprogram.cpp @@ -0,0 +1,162 @@ +/* ---------------------------------------------------------------------------- + * glslprogram.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include + +#include +#include +#include + +namespace yage +{ + +GlslProgram::~GlslProgram() +{ + // cleanup all the shaders and the program + if (fragment_shader_id_ != 0) { + glDeleteShader(fragment_shader_id_); + } + + if (vertex_shader_id_ != 0) { + glDeleteShader(vertex_shader_id_); + } + + if (program_id_ != 0) { + glDeleteProgram(program_id_); + } +} + +void GlslProgram::compileShader(const GLuint &shader, + const std::string &file_path) +{ + // get a string with the input from the shader file + std::ifstream file(file_path); + if (!file.is_open()) { + throw std::runtime_error("Failed to open '" + file_path + "'"); + } + + std::string content = ""; + std::string line; + + while (std::getline(file, line)) { + content += line + "\n"; + } + file.close(); + + // cast source to a c string to get the address of it and input it for + // compilation + const auto *vertex_source = (const GLchar *)content.c_str(); + glShaderSource(shader, 1, &vertex_source, nullptr); + glCompileShader(shader); + + // check if compilation was successful + GLint is_compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, (int *)&is_compiled); + + // if it isn't compiled throw exception to clean up + if (is_compiled == GL_FALSE) { + GLint max_length = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length); + + std::vector error_log(max_length); + glGetShaderInfoLog(shader, max_length, &max_length, &error_log[0]); + std::string error_log_str((const char *)&error_log[0]); + + throw std::runtime_error("Couldn't compile " + file_path + " : " + + error_log_str); + } +} + +void GlslProgram::compileShaders(const std::string &vertex_shader_path, + const std::string &fragment_shader_path) +{ + // create the program that will be run on GPU + program_id_ = glCreateProgram(); + + // create vertex shader + vertex_shader_id_ = glCreateShader(GL_VERTEX_SHADER); + if (vertex_shader_id_ == 0) { + throw std::runtime_error("Vertex shader failed to be created"); + } + + // create fragment shader + fragment_shader_id_ = glCreateShader(GL_FRAGMENT_SHADER); + if (fragment_shader_id_ == 0) { + throw std::runtime_error("Fragment shader failed to be created"); + } + + // compile the two shaders + compileShader(vertex_shader_id_, vertex_shader_path); + compileShader(fragment_shader_id_, fragment_shader_path); +} + +void GlslProgram::linkShaders() +{ + // attach the shaders that we want + glAttachShader(program_id_, vertex_shader_id_); + glAttachShader(program_id_, fragment_shader_id_); + + // link our program + glLinkProgram(program_id_); + + GLint is_linked = 0; + glGetProgramiv(program_id_, GL_LINK_STATUS, (int *)&is_linked); + if (is_linked == GL_FALSE) { + GLint max_length = 0; + glGetProgramiv(program_id_, GL_INFO_LOG_LENGTH, &max_length); + + std::vector error_log(max_length); + glGetProgramInfoLog(program_id_, max_length, &max_length, + &error_log[0]); + + std::string error_log_str((const char *)&error_log[0]); + + throw std::runtime_error("Could not link program : " + error_log_str); + } + + // detach shaders after successful link + glDetachShader(program_id_, fragment_shader_id_); + glDetachShader(program_id_, vertex_shader_id_); + + // we can then delete the shaders once we have the program + glDeleteShader(fragment_shader_id_); + glDeleteShader(vertex_shader_id_); +} + +void GlslProgram::addAttribute(const std::string &attribute_name) +{ + glBindAttribLocation(program_id_, attribute_index_++, + attribute_name.c_str()); +} + +GLint GlslProgram::getUniformLocation(const std::string &uniform_name) +{ + GLint location = glGetUniformLocation(program_id_, uniform_name.c_str()); + if ((GLuint)location == GL_INVALID_INDEX) { + throw std::runtime_error("'" + uniform_name + "' not found"); + } + return location; +} + +void GlslProgram::use() +{ + glUseProgram(program_id_); + for (int i = 0; i < attribute_index_; ++i) { + glEnableVertexAttribArray(i); + } +} + +void GlslProgram::unuse() +{ + for (int i = 0; i < attribute_index_; ++i) { + glDisableVertexAttribArray(i); + } + glUseProgram(0); +} + +} // namespace yage diff --git a/yage/base/glslprogram.h b/yage/base/glslprogram.h new file mode 100644 index 00000000..fbe5ac5c --- /dev/null +++ b/yage/base/glslprogram.h @@ -0,0 +1,52 @@ +/* ---------------------------------------------------------------------------- + * glslprogram.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef GLSL_PROGRAM_H +#define GLSL_PROGRAM_H + +#include + +#include + +namespace yage +{ + +class GlslProgram +{ +private: + /// compiled shader program id + GLuint program_id_ = 0; + GLuint vertex_shader_id_ = 0; + GLuint fragment_shader_id_ = 0; + int attribute_index_ = 0; + + /// compiles one shader + void compileShader(const GLuint &shader, const std::string &file_path); + +public: + GlslProgram() = default; + GlslProgram(const GlslProgram &) = delete; + GlslProgram(GlslProgram &&) = delete; + ~GlslProgram(); + + GlslProgram &operator=(const GlslProgram &) = delete; + GlslProgram &operator=(GlslProgram &&) = delete; + + /// compiles vertex and fragment shader + void compileShaders(const std::string &vertex_shader_path, + const std::string &fragment_shader_path); + void linkShaders(); + void addAttribute(const std::string &attribute_name); + GLint getUniformLocation(const std::string &uniform_name); + void use(); + void unuse(); +}; + +} // namespace yage + +#endif diff --git a/yage/base/imageloader.cpp b/yage/base/imageloader.cpp new file mode 100644 index 00000000..812110d8 --- /dev/null +++ b/yage/base/imageloader.cpp @@ -0,0 +1,60 @@ +/* ---------------------------------------------------------------------------- + * imageloader.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include +#include +#include + +#include + +namespace yage +{ + +Texture ImageLoader::loadPng(const std::string &file_path) +{ + Texture texture = {}; + + std::vector in; + std::vector out; + unsigned long width, height; + + if (!IoManager::readFileToBuffer(file_path, in)) { + throw std::runtime_error("Failed to load '" + file_path + + "' to buffer"); + } + + int error_code = decodePNG(out, width, height, &in[0], in.size()); + if (error_code != 0) { + throw std::runtime_error("Failed to load '" + file_path + + "' to png with error code" + + std::to_string(error_code)); + } + + glGenTextures(1, &texture.id); + + glBindTexture(GL_TEXTURE_2D, texture.id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, &out[0]); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR); + + glGenerateMipmap(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, 0); + + texture.width = (int)width; + texture.height = (int)height; + + return texture; +} + +} // namespace yage diff --git a/yage/base/imageloader.h b/yage/base/imageloader.h new file mode 100644 index 00000000..8d5c5cd1 --- /dev/null +++ b/yage/base/imageloader.h @@ -0,0 +1,27 @@ +/* ---------------------------------------------------------------------------- + * imageloader.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef IMAGE_LOADER_H +#define IMAGE_LOADER_H + +#include "texture.h" + +#include + +namespace yage +{ + +class ImageLoader +{ +public: + static Texture loadPng(const std::string &file_path); +}; + +} // namespace yage + +#endif diff --git a/yage/base/inputmanager.cpp b/yage/base/inputmanager.cpp new file mode 100644 index 00000000..d429abd7 --- /dev/null +++ b/yage/base/inputmanager.cpp @@ -0,0 +1,33 @@ +/* ---------------------------------------------------------------------------- + * inputmanager.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include + +namespace yage +{ + +void InputManager::keyPressed(unsigned key) +{ + key_map_[key] = true; +} + +void InputManager::keyReleased(unsigned key) +{ + key_map_[key] = false; +} + +bool InputManager::isKeyPressed(unsigned key) const +{ + auto key_index = key_map_.find(key); + if (key_index != key_map_.end()) { + return key_index->second; + } + return false; +} + +} // namespace yage diff --git a/yage/base/inputmanager.h b/yage/base/inputmanager.h new file mode 100644 index 00000000..84728fff --- /dev/null +++ b/yage/base/inputmanager.h @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------------- + * inputmanager.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef INPUT_MANAGER_H +#define INPUT_MANAGER_H + +#include + +namespace yage +{ + +class InputManager +{ +private: + std::unordered_map key_map_; + +public: + void keyPressed(unsigned key); + void keyReleased(unsigned key); + bool isKeyPressed(unsigned key) const; +}; +} // namespace yage +#endif diff --git a/yage/base/iomanager.cpp b/yage/base/iomanager.cpp new file mode 100644 index 00000000..93ab41c9 --- /dev/null +++ b/yage/base/iomanager.cpp @@ -0,0 +1,42 @@ +/* ---------------------------------------------------------------------------- + * iomanager.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include + +#include +#include + +namespace yage +{ + +bool IoManager::readFileToBuffer(const std::string &file_path, + std::vector &buffer) +{ + std::ifstream file(file_path, std::ios::binary); + if (!file.is_open()) { + throw std::runtime_error("Could not open '" + file_path + "'"); + } + + // seek to the end + file.seekg(0, std::ios::end); + + // get the file size + int file_size = file.tellg(); + file.seekg(0, std::ios::beg); + + // reduce file size by header bytes + file_size -= file.tellg(); + + buffer.resize(file_size); + file.read((char *)&buffer[0], file_size); + file.close(); + + return true; +} + +} // namespace yage diff --git a/yage/base/iomanager.h b/yage/base/iomanager.h new file mode 100644 index 00000000..95abd652 --- /dev/null +++ b/yage/base/iomanager.h @@ -0,0 +1,27 @@ +/* ---------------------------------------------------------------------------- + * iomanager.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef IO_MANAGER_H +#define IO_MANAGER_H + +#include +#include + +namespace yage +{ + +class IoManager +{ +public: + static bool readFileToBuffer(const std::string &file_path, + std::vector &buffer); +}; + +} // namespace yage + +#endif diff --git a/yage/base/picopng.cpp b/yage/base/picopng.cpp new file mode 100644 index 00000000..dcc4b367 --- /dev/null +++ b/yage/base/picopng.cpp @@ -0,0 +1,1118 @@ +#include +#include + +namespace yage +{ + +/* + decodePNG: The picoPNG function, decodes a PNG file buffer in memory, into a + raw pixel buffer. + out_image: output parameter, this will contain the raw pixels after decoding. + By default the output is 32-bit RGBA color. + The std::vector is automatically resized to the correct size. + image_width: output_parameter, this will contain the width of the image in + pixels. + image_height: output_parameter, this will contain the height of the image in + pixels. + in_png: pointer to the buffer of the PNG file in memory. To get it from a file + on + disk, load it and store it in a memory buffer yourself first. + in_size: size of the input PNG file in bytes. + convert_to_rgba32: optional parameter, true by default. + Set to true to get the output in RGBA 32-bit (8 bit per channel) color format + no matter what color type the original PNG image had. This gives predictable, + useable data from any random input PNG. + Set to false to do no color conversion at all. The result then has the same + data + type as the PNG image, which can range from 1 bit to 64 bits per pixel. + Information about the color type or palette colors are not provided. You need + to know this information yourself to be able to use the data so this only + works for trusted PNG files. Use LodePNG instead of picoPNG if you need this + information. + return: 0 if success, not 0 if some error occured. +*/ +int decodePNG(std::vector &out_image, unsigned long &image_width, + unsigned long &image_height, const unsigned char *in_png, + size_t in_size, bool convert_to_rgba32) +{ + // picoPNG version 20101224 + // Copyright (c) 2005-2010 Lode Vandevenne + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must + // not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must + // not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source + // distribution. + + // picoPNG is a PNG decoder in one C++ function of around 500 lines. Use + // picoPNG for + // programs that need only 1 .cpp file. Since it's a single function, it's + // very limited, + // it can convert a PNG to raw pixel data either converted to 32-bit RGBA + // color or + // with no color conversion at all. For anything more complex, another tiny + // library + // is available: LodePNG (lodepng.c(pp)), which is a single source and + // header file. + // Apologies for the compact code style, it's to make this tiny. + + static const unsigned long LENBASE[29] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, + 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; + static const unsigned long LENEXTRA[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static const unsigned long DISTBASE[30] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, + 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, + 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; + static const unsigned long DISTEXTRA[30] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + static const unsigned long CLCL[19] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, + 11, 4, 12, 3, 13, 2, 14, 1, 15}; // code length code lengths + struct Zlib // nested functions for zlib decompression + { + static unsigned long readBitFromStream(size_t &bitp, + const unsigned char *bits) + { + unsigned long result = (bits[bitp >> 3] >> (bitp & 0x7)) & 1; + bitp++; + return result; + } + static unsigned long readBitsFromStream(size_t &bitp, + const unsigned char *bits, + size_t nbits) + { + unsigned long result = 0; + for (size_t i = 0; i < nbits; i++) { + result += (readBitFromStream(bitp, bits)) << i; + } + return result; + } + struct HuffmanTree { + int makeFromLengths(const std::vector &bitlen, + unsigned long maxbitlen) + { // make tree given the lengths + unsigned long numcodes = (unsigned long)(bitlen.size()), + treepos = 0, nodefilled = 0; + std::vector tree1d(numcodes), + blcount(maxbitlen + 1, 0), nextcode(maxbitlen + 1, 0); + for (unsigned long bits = 0; bits < numcodes; bits++) { + blcount[bitlen[bits]]++; // count number of instances of + } + // each code length + for (unsigned long bits = 1; bits <= maxbitlen; bits++) { + nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) + << 1; + } + for (unsigned long n = 0; n < numcodes; n++) { + if (bitlen[n] != 0) { + tree1d[n] = + nextcode[bitlen[n]]++; // generate all the codes + } + } + tree2d.clear(); + tree2d.resize(numcodes * 2, 32767); // 32767 here means the + // tree2d isn't filled + // there yet + for (unsigned long n = 0; n < numcodes; n++) { // the codes + for (unsigned long i = 0; i < bitlen[n]; + i++) // the bits for this code + { + unsigned long bit = + (tree1d[n] >> (bitlen[n] - i - 1)) & 1; + if (treepos > numcodes - 2) { + return 55; + } + if (tree2d[2 * treepos + bit] == + 32767) // not yet filled in + { + if (i + 1 == bitlen[n]) { + tree2d[2 * treepos + bit] = n; + treepos = 0; + } // last bit + else { + tree2d[2 * treepos + bit] = + ++nodefilled + numcodes; + treepos = nodefilled; + } // addresses are encoded as values > numcodes + } else { + treepos = tree2d[2 * treepos + bit] - + numcodes; // subtract numcodes from + } + // address to get address value + } + } + return 0; + } + int decode(bool &decoded, unsigned long &result, size_t &treepos, + unsigned long bit) const + { // Decodes a symbol from the tree + unsigned long numcodes = (unsigned long)tree2d.size() / 2; + if (treepos >= numcodes) { + return 11; // error: you appeared outside the codetree + } + result = tree2d[2 * treepos + bit]; + decoded = (result < numcodes); + treepos = decoded ? 0 : result - numcodes; + return 0; + } + std::vector tree2d; // 2D representation of a + // huffman tree: The one + // dimension is "0" or "1", the + // other contains all nodes and + // leaves of the tree. + }; + struct Inflator { + int error; + void inflate(std::vector &out, + const std::vector &in, size_t inpos = 0) + { + size_t bp = 0, pos = 0; // bit pointer and byte pointer + error = 0; + unsigned long BFINAL = 0; + while (!BFINAL && !error) { + if (bp >> 3 >= in.size()) { + error = 52; + return; + } // error, bit pointer will jump past memory + BFINAL = readBitFromStream(bp, &in[inpos]); + unsigned long BTYPE = readBitFromStream(bp, &in[inpos]); + BTYPE += 2 * readBitFromStream(bp, &in[inpos]); + if (BTYPE == 3) { + error = 20; + return; + } // error: invalid BTYPE + else if (BTYPE == 0) { + inflateNoCompression(out, &in[inpos], bp, pos, + in.size()); + } else { + inflateHuffmanBlock(out, &in[inpos], bp, pos, in.size(), + BTYPE); + } + } + if (!error) { + out.resize(pos); // Only now we know the true size of out, + } + // resize it to that + } + void generateFixedTrees(HuffmanTree &tree, + HuffmanTree &treeD) // get the tree of a + // deflated block with + // fixed tree + { + std::vector bitlen(288, 8), bitlenD(32, 5); + ; + for (size_t i = 144; i <= 255; i++) { + bitlen[i] = 9; + } + for (size_t i = 256; i <= 279; i++) { + bitlen[i] = 7; + } + tree.makeFromLengths(bitlen, 15); + treeD.makeFromLengths(bitlenD, 15); + } + HuffmanTree codetree, codetreeD, + codelengthcodetree; // the code tree for Huffman codes, dist + // codes, and code length codes + unsigned long huffmanDecodeSymbol(const unsigned char *in, + size_t &bp, + const HuffmanTree &codetree, + size_t inlength) + { // decode a single symbol from given list of + // bits with given code tree. return value + // is the symbol + bool decoded; + unsigned long ct; + for (size_t treepos = 0;;) { + if ((bp & 0x07) == 0 && (bp >> 3) > inlength) { + error = 10; + return 0; + } // error: end reached without endcode + error = codetree.decode(decoded, ct, treepos, + readBitFromStream(bp, in)); + if (error) { + return 0; // stop, an error happened + } + if (decoded) { + return ct; + } + } + } + void getTreeInflateDynamic(HuffmanTree &tree, HuffmanTree &treeD, + const unsigned char *in, size_t &bp, + size_t inlength) + { // get the tree of a deflated block with + // dynamic tree, the tree itself is also + // Huffman compressed with a known tree + std::vector bitlen(288, 0), bitlenD(32, 0); + if (bp >> 3 >= inlength - 2) { + error = 49; + return; + } // the bit pointer is or will go past the memory + size_t HLIT = readBitsFromStream(bp, in, 5) + + 257; // number of literal/length codes + 257 + size_t HDIST = readBitsFromStream(bp, in, 5) + + 1; // number of dist codes + 1 + size_t HCLEN = readBitsFromStream(bp, in, 4) + + 4; // number of code length codes + 4 + std::vector codelengthcode( + 19); // lengths of tree to decode the lengths of the + // dynamic tree + for (size_t i = 0; i < 19; i++) { + codelengthcode[CLCL[i]] = + (i < HCLEN) ? readBitsFromStream(bp, in, 3) : 0; + } + error = codelengthcodetree.makeFromLengths(codelengthcode, 7); + if (error) { + return; + } + size_t i = 0, replength; + while (i < HLIT + HDIST) { + unsigned long code = huffmanDecodeSymbol( + in, bp, codelengthcodetree, inlength); + if (error) { + return; + } + if (code <= 15) { + if (i < HLIT) { + bitlen[i++] = code; + } else { + bitlenD[i++ - HLIT] = code; + } + } // a length code + else if (code == 16) // repeat previous + { + if (bp >> 3 >= inlength) { + error = 50; + return; + } // error, bit pointer jumps past memory + replength = 3 + readBitsFromStream(bp, in, 2); + unsigned long value; // set value to the previous code + if ((i - 1) < HLIT) { + value = bitlen[i - 1]; + } else { + value = bitlenD[i - HLIT - 1]; + } + for (size_t n = 0; n < replength; + n++) // repeat this value in the next lengths + { + if (i >= HLIT + HDIST) { + error = 13; + return; + } // error: i is larger than the amount of codes + if (i < HLIT) { + bitlen[i++] = value; + } else { + bitlenD[i++ - HLIT] = value; + } + } + } else if (code == 17) // repeat "0" 3-10 times + { + if (bp >> 3 >= inlength) { + error = 50; + return; + } // error, bit pointer jumps past memory + replength = 3 + readBitsFromStream(bp, in, 3); + for (size_t n = 0; n < replength; + n++) // repeat this value in the next lengths + { + if (i >= HLIT + HDIST) { + error = 14; + return; + } // error: i is larger than the amount of codes + if (i < HLIT) { + bitlen[i++] = 0; + } else { + bitlenD[i++ - HLIT] = 0; + } + } + } else if (code == 18) // repeat "0" 11-138 times + { + if (bp >> 3 >= inlength) { + error = 50; + return; + } // error, bit pointer jumps past memory + replength = 11 + readBitsFromStream(bp, in, 7); + for (size_t n = 0; n < replength; + n++) // repeat this value in the next lengths + { + if (i >= HLIT + HDIST) { + error = 15; + return; + } // error: i is larger than the amount of codes + if (i < HLIT) { + bitlen[i++] = 0; + } else { + bitlenD[i++ - HLIT] = 0; + } + } + } else { + error = 16; + return; + } // error: somehow an unexisting code appeared. This can + // never happen. + } + if (bitlen[256] == 0) { + error = 64; + return; + } // the length of the end code 256 must be larger than 0 + error = tree.makeFromLengths(bitlen, 15); + if (error) { + return; // now we've finally got HLIT and HDIST, so + } + // generate the code trees, and the function is + // done + error = treeD.makeFromLengths(bitlenD, 15); + if (error) { + return; + } + } + void inflateHuffmanBlock(std::vector &out, + const unsigned char *in, size_t &bp, + size_t &pos, size_t inlength, + unsigned long btype) + { + if (btype == 1) { + generateFixedTrees(codetree, codetreeD); + } else if (btype == 2) { + getTreeInflateDynamic(codetree, codetreeD, in, bp, + inlength); + if (error) { + return; + } + } + for (;;) { + unsigned long code = + huffmanDecodeSymbol(in, bp, codetree, inlength); + if (error) { + return; + } + if (code == 256) { + return; // end code + } else if (code <= 255) // literal symbol + { + if (pos >= out.size()) { + out.resize((pos + 1) * 2); // reserve more room + } + out[pos++] = (unsigned char)(code); + } else if (code >= 257 && code <= 285) // length code + { + size_t length = LENBASE[code - 257], + numextrabits = LENEXTRA[code - 257]; + if ((bp >> 3) >= inlength) { + error = 51; + return; + } // error, bit pointer will jump past memory + length += readBitsFromStream(bp, in, numextrabits); + unsigned long codeD = + huffmanDecodeSymbol(in, bp, codetreeD, inlength); + if (error) { + return; + } + if (codeD > 29) { + error = 18; + return; + } // error: invalid dist code (30-31 are never used) + unsigned long dist = DISTBASE[codeD], + numextrabitsD = DISTEXTRA[codeD]; + if ((bp >> 3) >= inlength) { + error = 51; + return; + } // error, bit pointer will jump past memory + dist += readBitsFromStream(bp, in, numextrabitsD); + size_t start = pos, back = start - dist; // backwards + if (pos + length >= out.size()) { + out.resize((pos + length) * 2); // reserve more + } + // room + for (size_t i = 0; i < length; i++) { + out[pos++] = out[back++]; + if (back >= start) { + back = start - dist; + } + } + } + } + } + void inflateNoCompression(std::vector &out, + const unsigned char *in, size_t &bp, + size_t &pos, size_t inlength) + { + while ((bp & 0x7) != 0) { + bp++; // go to first boundary of byte + } + size_t p = bp / 8; + if (p >= inlength - 4) { + error = 52; + return; + } // error, bit pointer will jump past memory + unsigned long LEN = in[p] + 256 * in[p + 1], + NLEN = in[p + 2] + 256 * in[p + 3]; + p += 4; + if (LEN + NLEN != 65535) { + error = 21; + return; + } // error: NLEN is not one's complement of LEN + if (pos + LEN >= out.size()) { + out.resize(pos + LEN); + } + if (p + LEN > inlength) { + error = 23; + return; + } // error: reading outside of in buffer + for (unsigned long n = 0; n < LEN; n++) { + out[pos++] = in[p++]; // read LEN bytes of literal data + } + bp = p * 8; + } + }; + int + decompress(std::vector &out, + const std::vector &in) // returns error value + { + Inflator inflator; + if (in.size() < 2) { + return 53; + } // error, size of zlib data too small + if ((in[0] * 256 + in[1]) % 31 != 0) { + return 24; + } // error: 256 * in[0] + in[1] must be a multiple of 31, the + // FCHECK value is supposed to be made that way + unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, + FDICT = (in[1] >> 5) & 1; + if (CM != 8 || CINFO > 7) { + return 25; + } // error: only compression method 8: inflate with sliding window + // of 32k is supported by the PNG spec + if (FDICT != 0) { + return 26; + } // error: the specification of PNG says about the zlib stream: + // "The additional flags shall not specify a preset dictionary." + inflator.inflate(out, in, 2); + return inflator + .error; // note: adler32 checksum was skipped and ignored + } + }; + struct PNG // nested functions for PNG decoding + { + struct Info { + unsigned long width, height, colorType, bitDepth, compressionMethod, + filterMethod, interlaceMethod, key_r, key_g, key_b; + bool key_defined; // is a transparent color key given? + std::vector palette; + } info; + int error; + void decode(std::vector &out, const unsigned char *in, + size_t size, bool convert_to_rgba32) + { + error = 0; + if (size == 0 || in == nullptr) { + error = 48; + return; + } // the given data is empty + readPngHeader(&in[0], size); + if (error) { + return; + } + size_t pos = 33; // first byte of the first chunk after the header + std::vector idat; // the data from idat chunks + bool IEND = false, known_type = true; + info.key_defined = false; + while (!IEND) // loop through the chunks, ignoring unknown chunks + // and stopping at IEND chunk. IDAT data is put at + // the start of the in buffer + { + if (pos + 8 >= size) { + error = 30; + return; + } // error: size of the in buffer too small to contain next + // chunk + size_t chunkLength = read32bitInt(&in[pos]); + pos += 4; + if (chunkLength > 2147483647) { + error = 63; + return; + } + if (pos + chunkLength >= size) { + error = 35; + return; + } // error: size of the in buffer too small to contain next + // chunk + if (in[pos + 0] == 'I' && in[pos + 1] == 'D' && + in[pos + 2] == 'A' && + in[pos + 3] == + 'T') // IDAT chunk, containing compressed image data + { + idat.insert(idat.end(), &in[pos + 4], + &in[pos + 4 + chunkLength]); + pos += (4 + chunkLength); + } else if (in[pos + 0] == 'I' && in[pos + 1] == 'E' && + in[pos + 2] == 'N' && in[pos + 3] == 'D') { + pos += 4; + IEND = true; + } else if (in[pos + 0] == 'P' && in[pos + 1] == 'L' && + in[pos + 2] == 'T' && + in[pos + 3] == 'E') // palette chunk (PLTE) + { + pos += 4; // go after the 4 letters + info.palette.resize(4 * (chunkLength / 3)); + if (info.palette.size() > (4 * 256)) { + error = 38; + return; + } // error: palette too big + for (size_t i = 0; i < info.palette.size(); i += 4) { + for (size_t j = 0; j < 3; j++) { + info.palette[i + j] = in[pos++]; // RGB + } + info.palette[i + 3] = 255; // alpha + } + } else if (in[pos + 0] == 't' && in[pos + 1] == 'R' && + in[pos + 2] == 'N' && + in[pos + 3] == + 'S') // palette transparency chunk (tRNS) + { + pos += 4; // go after the 4 letters + if (info.colorType == 3) { + if (4 * chunkLength > info.palette.size()) { + error = 39; + return; + } // error: more alpha values given than there are + // palette entries + for (size_t i = 0; i < chunkLength; i++) { + info.palette[4 * i + 3] = in[pos++]; + } + } else if (info.colorType == 0) { + if (chunkLength != 2) { + error = 40; + return; + } // error: this chunk must be 2 bytes for greyscale + // image + info.key_defined = true; + info.key_r = info.key_g = info.key_b = + 256 * in[pos] + in[pos + 1]; + pos += 2; + } else if (info.colorType == 2) { + if (chunkLength != 6) { + error = 41; + return; + } // error: this chunk must be 6 bytes for RGB image + info.key_defined = true; + info.key_r = 256 * in[pos] + in[pos + 1]; + pos += 2; + info.key_g = 256 * in[pos] + in[pos + 1]; + pos += 2; + info.key_b = 256 * in[pos] + in[pos + 1]; + pos += 2; + } else { + error = 42; + return; + } // error: tRNS chunk not allowed for other color models + } else // it's not an implemented chunk type, so ignore it: + // skip over the data + { + if (!(in[pos + 0] & 32)) { + error = 69; + return; + } // error: unknown critical chunk (5th bit of first byte + // of chunk type is 0) + pos += (chunkLength + 4); // skip 4 letters and + // uninterpreted data of + // unimplemented chunk + known_type = false; + } + pos += 4; // step over CRC (which is ignored) + } + unsigned long bpp = getBpp(info); + std::vector scanlines( + ((info.width * (info.height * bpp + 7)) / 8) + + info.height); // now the out buffer will be filled + Zlib zlib; // decompress with the Zlib decompressor + error = zlib.decompress(scanlines, idat); + if (error) { + return; // stop if the zlib decompressor returned an error + } + size_t bytewidth = (bpp + 7) / 8, + outlength = (info.height * info.width * bpp + 7) / 8; + out.resize(outlength); // time to fill the out buffer + unsigned char *out_ = + outlength ? &out[0] : nullptr; // use a regular pointer to the + // std::vector for faster code if + // compiled without optimization + if (info.interlaceMethod == 0) // no interlace, just filter + { + size_t linestart = 0, + linelength = (info.width * bpp + 7) / + 8; // length in bytes of a scanline, + // excluding the filtertype byte + if (bpp >= 8) { // byte per byte + for (unsigned long y = 0; y < info.height; y++) { + unsigned long filterType = scanlines[linestart]; + const unsigned char *prevline = + (y == 0) ? nullptr + : &out_[(y - 1) * info.width * bytewidth]; + unFilterScanline(&out_[linestart - y], + &scanlines[linestart + 1], prevline, + bytewidth, filterType, linelength); + if (error) { + return; + } + linestart += + (1 + linelength); // go to start of next scanline + } + } else // less than 8 bits per pixel, so fill it up bit per bit + { + std::vector templine( + (info.width * bpp + 7) >> 3); // only used if bpp < 8 + for (size_t y = 0, obp = 0; y < info.height; y++) { + unsigned long filterType = scanlines[linestart]; + const unsigned char *prevline = + (y == 0) ? nullptr + : &out_[(y - 1) * info.width * bytewidth]; + unFilterScanline(&templine[0], + &scanlines[linestart + 1], prevline, + bytewidth, filterType, linelength); + if (error) { + return; + } + for (size_t bp = 0; bp < info.width * bpp;) { + setBitOfReversedStream( + obp, out_, + readBitFromReversedStream(bp, &templine[0])); + } + linestart += + (1 + linelength); // go to start of next scanline + } + } + } else // interlaceMethod is 1 (Adam7) + { + size_t passw[7] = {(info.width + 7) / 8, (info.width + 3) / 8, + (info.width + 3) / 4, (info.width + 1) / 4, + (info.width + 1) / 2, (info.width + 0) / 2, + (info.width + 0) / 1}; + size_t passh[7] = {(info.height + 7) / 8, (info.height + 7) / 8, + (info.height + 3) / 8, (info.height + 3) / 4, + (info.height + 1) / 4, (info.height + 1) / 2, + (info.height + 0) / 2}; + size_t passstart[7] = {0}; + size_t pattern[28] = {0, 4, 0, 2, 0, 1, 0, 0, 0, 4, + 0, 2, 0, 1, 8, 8, 4, 4, 2, 2, + 1, 8, 8, 8, 4, 4, 2, 2}; // values for the + // adam7 passes + for (int i = 0; i < 6; i++) { + passstart[i + 1] = passstart[i] + + passh[i] * ((passw[i] ? 1 : 0) + + (passw[i] * bpp + 7) / 8); + } + std::vector scanlineo((info.width * bpp + 7) / + 8), + scanlinen((info.width * bpp + 7) / + 8); //"old" and "new" scanline + for (int i = 0; i < 7; i++) { + adam7Pass(&out_[0], &scanlinen[0], &scanlineo[0], + &scanlines[passstart[i]], info.width, pattern[i], + pattern[i + 7], pattern[i + 14], pattern[i + 21], + passw[i], passh[i], bpp); + } + } + if (convert_to_rgba32 && (info.colorType != 6 || + info.bitDepth != 8)) // conversion needed + { + std::vector data = out; + error = convert(out, &data[0], info, info.width, info.height); + } + } + void readPngHeader(const unsigned char *in, + size_t inlength) // read the information from the + // header and store it in the Info + { + if (inlength < 29) { + error = 27; + return; + } // error: the data length is smaller than the length of the + // header + if (in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || + in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { + error = 28; + return; + } // no PNG signature + if (in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || + in[15] != 'R') { + error = 29; + return; + } // error: it doesn't start with a IHDR chunk! + info.width = read32bitInt(&in[16]); + info.height = read32bitInt(&in[20]); + info.bitDepth = in[24]; + info.colorType = in[25]; + info.compressionMethod = in[26]; + if (in[26] != 0) { + error = 32; + return; + } // error: only compression method 0 is allowed in the + // specification + info.filterMethod = in[27]; + if (in[27] != 0) { + error = 33; + return; + } // error: only filter method 0 is allowed in the specification + info.interlaceMethod = in[28]; + if (in[28] > 1) { + error = 34; + return; + } // error: only interlace methods 0 and 1 exist in the + // specification + error = checkColorValidity(info.colorType, info.bitDepth); + } + void unFilterScanline(unsigned char *recon, + const unsigned char *scanline, + const unsigned char *precon, size_t bytewidth, + unsigned long filterType, size_t length) + { + switch (filterType) { + case 0: + for (size_t i = 0; i < length; i++) { + recon[i] = scanline[i]; + } + break; + case 1: + for (size_t i = 0; i < bytewidth; i++) { + recon[i] = scanline[i]; + } + for (size_t i = bytewidth; i < length; i++) { + recon[i] = scanline[i] + recon[i - bytewidth]; + } + break; + case 2: + if (precon) { + for (size_t i = 0; i < length; i++) { + recon[i] = scanline[i] + precon[i]; + } + } else { + for (size_t i = 0; i < length; i++) { + recon[i] = scanline[i]; + } + } + break; + case 3: + if (precon) { + for (size_t i = 0; i < bytewidth; i++) { + recon[i] = scanline[i] + precon[i] / 2; + } + for (size_t i = bytewidth; i < length; i++) { + recon[i] = scanline[i] + + ((recon[i - bytewidth] + precon[i]) / 2); + } + } else { + for (size_t i = 0; i < bytewidth; i++) { + recon[i] = scanline[i]; + } + for (size_t i = bytewidth; i < length; i++) { + recon[i] = scanline[i] + recon[i - bytewidth] / 2; + } + } + break; + case 4: + if (precon) { + for (size_t i = 0; i < bytewidth; i++) { + recon[i] = + scanline[i] + paethPredictor(0, precon[i], 0); + } + for (size_t i = bytewidth; i < length; i++) { + recon[i] = + scanline[i] + paethPredictor(recon[i - bytewidth], + precon[i], + precon[i - bytewidth]); + } + } else { + for (size_t i = 0; i < bytewidth; i++) { + recon[i] = scanline[i]; + } + for (size_t i = bytewidth; i < length; i++) { + recon[i] = scanline[i] + + paethPredictor(recon[i - bytewidth], 0, 0); + } + } + break; + default: + error = 36; + return; // error: unexisting filter type given + } + } + void adam7Pass(unsigned char *out, unsigned char *linen, + unsigned char *lineo, const unsigned char *in, + unsigned long w, size_t passleft, size_t passtop, + size_t spacex, size_t spacey, size_t passw, size_t passh, + unsigned long bpp) + { // filter and reposition the pixels + // into the output when the image + // is Adam7 interlaced. This + // function can only do it after + // the full image is already + // decoded. The out buffer must + // have the correct allocated + // memory size already. + if (passw == 0) { + return; + } + size_t bytewidth = (bpp + 7) / 8, + linelength = 1 + ((bpp * passw + 7) / 8); + for (unsigned long y = 0; y < passh; y++) { + unsigned char filterType = in[y * linelength], + *prevline = (y == 0) ? nullptr : lineo; + unFilterScanline(linen, &in[y * linelength + 1], prevline, + bytewidth, filterType, (w * bpp + 7) / 8); + if (error) { + return; + } + if (bpp >= 8) { + for (size_t i = 0; i < passw; i++) { + for (size_t b = 0; b < bytewidth; + b++) { // b = current byte of this pixel + out[bytewidth * w * (passtop + spacey * y) + + bytewidth * (passleft + spacex * i) + b] = + linen[bytewidth * i + b]; + } + } + } else { + for (size_t i = 0; i < passw; i++) { + size_t obp = bpp * w * (passtop + spacey * y) + + bpp * (passleft + spacex * i), + bp = i * bpp; + for (size_t b = 0; b < bpp; b++) { + setBitOfReversedStream( + obp, out, + readBitFromReversedStream(bp, &linen[0])); + } + } + } + unsigned char *temp = linen; + linen = lineo; + lineo = temp; // swap the two buffer pointers "line old" and + // "line new" + } + } + static unsigned long + readBitFromReversedStream(size_t &bitp, const unsigned char *bits) + { + unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1; + bitp++; + return result; + } + static unsigned long + readBitsFromReversedStream(size_t &bitp, const unsigned char *bits, + unsigned long nbits) + { + unsigned long result = 0; + for (size_t i = nbits - 1; i < nbits; i--) { + result += ((readBitFromReversedStream(bitp, bits)) << i); + } + return result; + } + void setBitOfReversedStream(size_t &bitp, unsigned char *bits, + unsigned long bit) + { + bits[bitp >> 3] |= (bit << (7 - (bitp & 0x7))); + bitp++; + } + unsigned long read32bitInt(const unsigned char *buffer) + { + return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | + buffer[3]; + } + int checkColorValidity( + unsigned long colorType, + unsigned long bd) // return type is a LodePNG error code + { + if ((colorType == 2 || colorType == 4 || colorType == 6)) { + if (!(bd == 8 || bd == 16)) { + return 37; + } else { + return 0; + } + } else if (colorType == 0) { + if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) { + return 37; + } else { + return 0; + } + } else if (colorType == 3) { + if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8)) { + return 37; + } else { + return 0; + } + } else { + return 31; // unexisting color type + } + } + unsigned long getBpp(const Info &info) + { + if (info.colorType == 2) { + return (3 * info.bitDepth); + } else if (info.colorType >= 4) { + return (info.colorType - 2) * info.bitDepth; + } else { + return info.bitDepth; + } + } + int convert(std::vector &out, const unsigned char *in, + Info &infoIn, unsigned long w, unsigned long h) + { // converts from any color type to + // 32-bit. return value = LodePNG error + // code + size_t numpixels = w * h, bp = 0; + out.resize(numpixels * 4); + unsigned char *out_ = + out.empty() + ? nullptr + : &out[0]; // faster if compiled without optimization + if (infoIn.bitDepth == 8 && infoIn.colorType == 0) { // greyscale + for (size_t i = 0; i < numpixels; i++) { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[i]; + out_[4 * i + 3] = + (infoIn.key_defined && in[i] == infoIn.key_r) ? 0 : 255; + } + } else if (infoIn.bitDepth == 8 && infoIn.colorType == 2) { // RGB + // color + for (size_t i = 0; i < numpixels; i++) { + for (size_t c = 0; c < 3; c++) { + out_[4 * i + c] = in[3 * i + c]; + } + out_[4 * i + 3] = (infoIn.key_defined == 1 && + in[3 * i + 0] == infoIn.key_r && + in[3 * i + 1] == infoIn.key_g && + in[3 * i + 2] == infoIn.key_b) + ? 0 + : 255; + } + } else if (infoIn.bitDepth == 8 && + infoIn.colorType == 3) { // indexed color (palette) + for (size_t i = 0; i < numpixels; i++) { + if (4U * in[i] >= infoIn.palette.size()) { + return 46; + } + for (size_t c = 0; c < 4; c++) { + out_[4 * i + c] = + infoIn.palette[4 * in[i] + c]; // get rgb colors + } + // from the palette + } + } else if (infoIn.bitDepth == 8 && + infoIn.colorType == 4) { // greyscale with alpha + for (size_t i = 0; i < numpixels; i++) { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = + in[2 * i + 0]; + out_[4 * i + 3] = in[2 * i + 1]; + } + } else if (infoIn.bitDepth == 8 && infoIn.colorType == 6) { + for (size_t i = 0; i < numpixels; i++) { + for (size_t c = 0; c < 4; c++) { + out_[4 * i + c] = in[4 * i + c]; // RGB with alpha + } + } + } else if (infoIn.bitDepth == 16 && + infoIn.colorType == 0) { // greyscale + for (size_t i = 0; i < numpixels; i++) { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = + in[2 * i]; + out_[4 * i + 3] = (infoIn.key_defined && + 256U * in[i] + in[i + 1] == infoIn.key_r) + ? 0 + : 255; + } + } else if (infoIn.bitDepth == 16 && + infoIn.colorType == 2) { // RGB color + for (size_t i = 0; i < numpixels; i++) { + for (size_t c = 0; c < 3; c++) { + out_[4 * i + c] = in[6 * i + 2 * c]; + } + out_[4 * i + 3] = + (infoIn.key_defined && + 256U * in[6 * i + 0] + in[6 * i + 1] == infoIn.key_r && + 256U * in[6 * i + 2] + in[6 * i + 3] == infoIn.key_g && + 256U * in[6 * i + 4] + in[6 * i + 5] == infoIn.key_b) + ? 0 + : 255; + } + } else if (infoIn.bitDepth == 16 && + infoIn.colorType == 4) { // greyscale with alpha + for (size_t i = 0; i < numpixels; i++) { + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = + in[4 * i]; // most significant byte + out_[4 * i + 3] = in[4 * i + 2]; + } + } else if (infoIn.bitDepth == 16 && infoIn.colorType == 6) { + for (size_t i = 0; i < numpixels; i++) { + for (size_t c = 0; c < 4; c++) { + out_[4 * i + c] = in[8 * i + 2 * c]; // RGB with alpha + } + } + } else if (infoIn.bitDepth < 8 && + infoIn.colorType == 0) { // greyscale + for (size_t i = 0; i < numpixels; i++) { + unsigned long value = + (readBitsFromReversedStream(bp, in, infoIn.bitDepth) * + 255) / + ((1 << infoIn.bitDepth) - + 1); // scale value from 0 to 255 + out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = + (unsigned char)(value); + out_[4 * i + 3] = + (infoIn.key_defined && value && + ((1U << infoIn.bitDepth) - 1U) == infoIn.key_r && + ((1U << infoIn.bitDepth) - 1U)) + ? 0 + : 255; + } + } else if (infoIn.bitDepth < 8 && + infoIn.colorType == 3) { // palette + for (size_t i = 0; i < numpixels; i++) { + unsigned long value = + readBitsFromReversedStream(bp, in, infoIn.bitDepth); + if (4 * value >= infoIn.palette.size()) { + return 47; + } + for (size_t c = 0; c < 4; c++) { + out_[4 * i + c] = + infoIn.palette[4 * value + c]; // get rgb colors + } + // from the palette + } + } + return 0; + } + unsigned char + paethPredictor(short a, short b, + short c) // Paeth predicter, used by PNG filter type 4 + { + short p = a + b - c, pa = p > a ? (p - a) : (a - p), + pb = p > b ? (p - b) : (b - p), + pc = p > c ? (p - c) : (c - p); + return (unsigned char)((pa <= pb && pa <= pc) ? a + : pb <= pc ? b : c); + } + }; + PNG decoder; + decoder.decode(out_image, in_png, in_size, convert_to_rgba32); + image_width = decoder.info.width; + image_height = decoder.info.height; + return decoder.error; +} + +} // namespace yage diff --git a/yage/base/picopng.h b/yage/base/picopng.h new file mode 100644 index 00000000..095bf68a --- /dev/null +++ b/yage/base/picopng.h @@ -0,0 +1,20 @@ +/* ---------------------------------------------------------------------------- + * picopng.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include +#include + +namespace yage +{ + +extern int decodePNG(std::vector &out_image, + unsigned long &image_width, unsigned long &image_height, + const unsigned char *in_png, size_t in_size, + bool convert_to_rgba32 = true); + +} // namespace yage diff --git a/yage/base/resourcemanager.cpp b/yage/base/resourcemanager.cpp new file mode 100644 index 00000000..473ea37e --- /dev/null +++ b/yage/base/resourcemanager.cpp @@ -0,0 +1,21 @@ +/* ---------------------------------------------------------------------------- + * resourcemanager.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include + +namespace yage +{ + +TextureCache ResourceManager::texture_cache_; + +Texture ResourceManager::getTexture(const std::string &texture_path) +{ + return texture_cache_.getTexture(texture_path); +} + +} // namespace yage diff --git a/yage/base/resourcemanager.h b/yage/base/resourcemanager.h new file mode 100644 index 00000000..3c5081c4 --- /dev/null +++ b/yage/base/resourcemanager.h @@ -0,0 +1,31 @@ +/* ---------------------------------------------------------------------------- + * resourcemanager.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef RESOURCE_MANAGER_H +#define RESOURCE_MANAGER_H + +#include "texture.h" +#include "texturecache.h" + +#include + +namespace yage +{ + +class ResourceManager +{ +private: + static TextureCache texture_cache_; + +public: + static Texture getTexture(const std::string &texture_path); +}; + +} // namespace yage + +#endif diff --git a/yage/base/sprite.cpp b/yage/base/sprite.cpp new file mode 100644 index 00000000..68e08e5d --- /dev/null +++ b/yage/base/sprite.cpp @@ -0,0 +1,97 @@ +/* ---------------------------------------------------------------------------- + * sprite.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include +#include +#include + +#include + +namespace yage +{ + +Sprite::Sprite() = default; + +Sprite::~Sprite() +{ + if (vbo_id_ != 0) { + glDeleteBuffers(1, &vbo_id_); + } +} + +void Sprite::init(float x, float y, float width, float height, + const std::string &texture_path) +{ + x_ = x; + y_ = y; + width_ = width; + height_ = height; + texture_ = ResourceManager::getTexture(texture_path); + + if (vbo_id_ == 0) { + glGenBuffers(1, &vbo_id_); + } + + Vertex vertex_data[6]; + + vertex_data[0].setPosition(x + width, y + height); + vertex_data[0].setUv(1.f, 1.f); + + vertex_data[1].setPosition(x, y + height); + vertex_data[1].setUv(0.f, 1.f); + + vertex_data[2].setPosition(x, y); + vertex_data[2].setUv(0.f, 0.f); + + vertex_data[3].setPosition(x, y); + vertex_data[3].setUv(0.f, 0.f); + + vertex_data[4].setPosition(x + width, y + height); + vertex_data[4].setUv(1.f, 1.f); + + vertex_data[5].setPosition(x + width, y); + vertex_data[5].setUv(1.f, 0.f); + + for (auto &i : vertex_data) { + i.setColor(255, 0, 255, 255); + } + + vertex_data[1].setColor(0, 255, 255, 255); + vertex_data[4].setColor(255, 0, 0, 255); + + glBindBuffer(GL_ARRAY_BUFFER, vbo_id_); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, + GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void Sprite::draw() +{ + glBindTexture(GL_TEXTURE_2D, texture_.id); + glBindBuffer(GL_ARRAY_BUFFER, vbo_id_); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), + (void *)offsetof(Vertex, position)); + glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), + (void *)offsetof(Vertex, color)); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), + (void *)offsetof(Vertex, uv)); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); + + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +} // namespace yage diff --git a/yage/base/sprite.h b/yage/base/sprite.h new file mode 100644 index 00000000..5b9baf91 --- /dev/null +++ b/yage/base/sprite.h @@ -0,0 +1,52 @@ +/* ---------------------------------------------------------------------------- + * sprite.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +/** @file + */ + +#ifndef SPRITE_H +#define SPRITE_H + +#include "texture.h" + +#include + +#include + +namespace yage +{ + +/** @deprecated Use SpriteBatch instead + */ +class Sprite +{ +private: + float x_; + float y_; + float width_; + float height_; + GLuint vbo_id_ = 0; + Texture texture_; + +public: + Sprite(); + Sprite(const Sprite &) = delete; + Sprite(Sprite &&) = delete; + ~Sprite(); + + Sprite &operator=(const Sprite &) = delete; + Sprite &operator=(Sprite &&) = delete; + + void init(float x, float y, float width, float height, + const std::string &texture_path); + void draw(); +}; + +} // namespace yage + +#endif diff --git a/yage/base/spritebatch.cpp b/yage/base/spritebatch.cpp new file mode 100644 index 00000000..ac98130b --- /dev/null +++ b/yage/base/spritebatch.cpp @@ -0,0 +1,193 @@ +/* ---------------------------------------------------------------------------- + * spritebatch.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include + +#include +#include + +namespace yage +{ + +const int SpriteBatch::NUM_VERTICES; + +Glyph::Glyph(GLuint texture, float depth, const Vertex &top_left, + const Vertex &top_right, const Vertex &bottom_right, + const Vertex &bottom_left) + : texture_(texture), depth_(depth), top_left_(top_left), + top_right_(top_right), bottom_right_(bottom_right), + bottom_left_(bottom_left) +{ +} + +RenderBatch::RenderBatch(GLint offset, GLsizei num_vertices, GLuint texture) + : num_vertices_(num_vertices), offset_(offset), texture_(texture) +{ +} + +SpriteBatch::SpriteBatch() = default; + +SpriteBatch::~SpriteBatch() +{ + if (vao_ != 0) { + glDeleteVertexArrays(1, &vao_); + } + + if (vbo_ != 0) { + glDeleteVertexArrays(1, &vbo_); + } +} + +void SpriteBatch::init() +{ + createVertexArray(); +} + +void SpriteBatch::begin() +{ + glyphs_.clear(); + glyph_ptrs_.clear(); + render_batches_.clear(); +} + +void SpriteBatch::end() +{ + sortGlyphs(); + createRenderBatches(); +} + +void SpriteBatch::draw(const glm::vec4 &destination_rect, + const glm::vec4 &uv_rect, GLuint texture, + const Color &color, float depth) +{ + Vertex top_left, top_right, bottom_right, bottom_left; + + top_left.color = color; + top_left.setPosition(destination_rect.x, + destination_rect.y + destination_rect.w); + top_left.setUv(uv_rect.x, uv_rect.y + uv_rect.w); + + top_right.color = color; + top_right.setPosition(destination_rect.x + destination_rect.z, + destination_rect.y + destination_rect.w); + top_right.setUv(uv_rect.x + uv_rect.z, uv_rect.y + uv_rect.w); + + bottom_right.color = color; + bottom_right.setPosition(destination_rect.x + destination_rect.z, + destination_rect.y); + bottom_right.setUv(uv_rect.x + uv_rect.z, uv_rect.y); + + bottom_left.color = color; + bottom_left.setPosition(destination_rect.x, destination_rect.y); + bottom_left.setUv(uv_rect.x, uv_rect.y); + + // deal with fragmenting by creating vector of pointers + glyphs_.emplace_back(texture, depth, top_left, top_right, bottom_right, + bottom_left); + glyph_ptrs_.push_back(&glyphs_.back()); +} + +void SpriteBatch::render() +{ + glBindVertexArray(vao_); + for (auto &&batch : render_batches_) { + glBindTexture(GL_TEXTURE_2D, batch.texture()); + glDrawArrays(GL_TRIANGLES, batch.offset(), batch.num_vertices()); + } + glBindVertexArray(0); +} + +void SpriteBatch::createVertexArray() +{ + if (vao_ == 0) { + glGenVertexArrays(1, &vao_); + if (vao_ == 0) { + throw std::runtime_error("glGenVertexArrays failed"); + } + } + // bind vertex array object + glBindVertexArray(vao_); + + if (vbo_ == 0) { + glGenBuffers(1, &vbo_); + if (vbo_ == 0) { + throw std::runtime_error("glGenBuffers failed"); + } + } + // bind vertex buffer object + glBindBuffer(GL_ARRAY_BUFFER, vbo_); + + // enable vertex attribute arrays + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + // set the vertex attribute pointers + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), + (void *)offsetof(Vertex, position)); + glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), + (void *)offsetof(Vertex, color)); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), + (void *)offsetof(Vertex, uv)); + glDrawArrays(GL_TRIANGLES, 0, 6); + + // unbind vertex array object + glBindVertexArray(0); +} + +void SpriteBatch::createRenderBatches() +{ + std::vector vertices; + if (glyph_ptrs_.empty()) { + return; + } + + render_batches_.reserve(glyph_ptrs_.size() * NUM_VERTICES); + + for (int i = 0; i < (int)glyph_ptrs_.size(); ++i) { + if (i == 0 || (i > 0 && (glyph_ptrs_[i]->texture() != + glyph_ptrs_[i - 1]->texture()))) { + render_batches_.emplace_back(i * NUM_VERTICES, NUM_VERTICES, + glyph_ptrs_[i]->texture()); + } else { + render_batches_.back().num_vertices_ += NUM_VERTICES; + } + + vertices.push_back(glyph_ptrs_[i]->bottom_left()); + vertices.push_back(glyph_ptrs_[i]->top_left()); + vertices.push_back(glyph_ptrs_[i]->top_right()); + vertices.push_back(glyph_ptrs_[i]->bottom_left()); + vertices.push_back(glyph_ptrs_[i]->bottom_right()); + vertices.push_back(glyph_ptrs_[i]->top_right()); + + // bind vbo + glBindBuffer(GL_ARRAY_BUFFER, vbo_); + // orphan the buffer + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), nullptr, + GL_DYNAMIC_DRAW); + // upload the data + glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(Vertex), + vertices.data()); + // unbind buffer + glBindBuffer(GL_ARRAY_BUFFER, 0); + } +} + +void SpriteBatch::sortGlyphs() +{ + // sort using introsort or quicksort + std::sort(glyph_ptrs_.begin(), glyph_ptrs_.end(), + [](Glyph *a, Glyph *b) -> bool { + if (a->depth() == b->depth()) { + return a->texture() < b->texture(); + } + return a->depth() < b->depth(); + }); +} + +} // namespace yage diff --git a/yage/base/spritebatch.h b/yage/base/spritebatch.h new file mode 100644 index 00000000..7235bd25 --- /dev/null +++ b/yage/base/spritebatch.h @@ -0,0 +1,105 @@ +/* ---------------------------------------------------------------------------- + * spritebatch.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_SPRITE_BATCH_H +#define YAGE_SPRITE_BATCH_H + +#include "vertex.h" + +#include +#include + +#include + +namespace yage +{ + +class SpriteBatch; + +/** Glyph with information of the texture. + */ +class Glyph +{ +private: + GLuint texture_; + float depth_; + Vertex top_left_; + Vertex top_right_; + Vertex bottom_right_; + Vertex bottom_left_; + +public: + Glyph(GLuint texture, float depth, const Vertex &top_left, + const Vertex &top_right, const Vertex &bottom_right, + const Vertex &bottom_left); + + GLuint texture() const { return texture_; } + float depth() const { return depth_; } + Vertex top_left() const { return top_left_; } + Vertex top_right() const { return top_right_; } + Vertex bottom_right() const { return bottom_right_; } + Vertex bottom_left() const { return bottom_left_; } +}; + +class RenderBatch +{ + friend SpriteBatch; + +private: + GLsizei num_vertices_; + GLint offset_; + GLuint texture_; + +public: + RenderBatch(GLint offset, GLsizei num_vertices, GLuint texture); + + GLint offset() const { return offset_; } + GLsizei num_vertices() const { return num_vertices_; } + GLuint texture() const { return texture_; } +}; + +class SpriteBatch +{ +public: + static const int NUM_VERTICES = 6; + +private: + GLuint vbo_ = 0; + GLuint vao_ = 0; + std::vector glyphs_; + std::vector glyph_ptrs_; + std::vector render_batches_; + +public: + SpriteBatch(); + SpriteBatch(const SpriteBatch &) = delete; + SpriteBatch(SpriteBatch &&) = delete; + ~SpriteBatch(); + + SpriteBatch &operator=(const SpriteBatch &) = delete; + SpriteBatch &operator=(SpriteBatch &&) = delete; + + // initialize vaos and vbos + void init(); + void begin(); + void end(); + // adds a sprite to the sprite batch to be rendered later + void draw(const glm::vec4 &destination_rect, const glm::vec4 &uv_rect, + GLuint texture, const Color &color, float depth); + // render the batch + void render(); + +private: + void createVertexArray(); + void createRenderBatches(); + void sortGlyphs(); +}; + +} // namespace yage + +#endif diff --git a/yage/base/spritesheet.h b/yage/base/spritesheet.h new file mode 100644 index 00000000..2b70ad8b --- /dev/null +++ b/yage/base/spritesheet.h @@ -0,0 +1,25 @@ +/* ---------------------------------------------------------------------------- + * spritesheet.h + * + * Copyright (c) 2017 Yann Herklotz Grave + * MIT License, see LICENSE file for more details. + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_SPRITESHEET_H +#define YAGE_SPRITESHEET_H + +#include "texture.h" + +namespace yage +{ + +class SpriteSheet +{ +private: + Texture texture_; +}; + +} // namespace yage + +#endif diff --git a/yage/base/texture.h b/yage/base/texture.h new file mode 100644 index 00000000..d1fdcbf2 --- /dev/null +++ b/yage/base/texture.h @@ -0,0 +1,25 @@ +/* ---------------------------------------------------------------------------- + * texture.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef GL_TEXTURE_H +#define GL_TEXTURE_H + +#include + +namespace yage +{ + +struct Texture { + GLuint id; + int width; + int height; +}; + +} // namespace yage + +#endif diff --git a/yage/base/texturecache.cpp b/yage/base/texturecache.cpp new file mode 100644 index 00000000..fda5fcd9 --- /dev/null +++ b/yage/base/texturecache.cpp @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------------- + * texturecache.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include +#include + +namespace yage +{ + +TextureCache::TextureCache() = default; + +Texture TextureCache::getTexture(const std::string &texture_path) +{ + auto itr = texture_map_.find(texture_path); + + if (itr == texture_map_.end()) { + Texture new_texture = ImageLoader::loadPng(texture_path); + texture_map_.insert(make_pair(texture_path, new_texture)); + return new_texture; + } + + return itr->second; +} + +} // namespace yage diff --git a/yage/base/texturecache.h b/yage/base/texturecache.h new file mode 100644 index 00000000..414c9ec3 --- /dev/null +++ b/yage/base/texturecache.h @@ -0,0 +1,32 @@ +/* ---------------------------------------------------------------------------- + * texturecache.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef TEXTURE_CACHE_H +#define TEXTURE_CACHE_H + +#include "texture.h" + +#include + +namespace yage +{ + +class TextureCache +{ +private: + std::unordered_map texture_map_; + +public: + TextureCache(); + + Texture getTexture(const std::string &texture_path); +}; + +} // namespace yage + +#endif diff --git a/yage/base/vertex.h b/yage/base/vertex.h new file mode 100644 index 00000000..15b46ed9 --- /dev/null +++ b/yage/base/vertex.h @@ -0,0 +1,84 @@ +/* ---------------------------------------------------------------------------- + * vertex.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef VERTEX_H +#define VERTEX_H + +#include + +namespace yage +{ + +struct Position { + float x; + float y; + + Position() = default; + + Position(float x_, float y_) : x(x_), y(y_) {} +}; + +struct Color { + GLubyte r; + GLubyte g; + GLubyte b; + GLubyte a; + + Color() = default; + + Color(GLubyte r_, GLubyte g_, GLubyte b_, GLubyte a_) + : r(r_), g(g_), b(b_), a(a_) + { + } +}; + +struct UV { + float u; + float v; + + UV() = default; + + UV(float u_, float v_) : u(u_), v(v_) {} +}; + +struct Vertex { + Position position; + Color color; + UV uv; + + Vertex() = default; + + Vertex(const Position &position_, const Color &color_, const UV &uv_) + : position(position_), color(color_), uv(uv_) + { + } + + void setPosition(float x, float y) + { + position.x = x; + position.y = y; + } + + void setColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a) + { + color.r = r; + color.g = g; + color.b = b; + color.a = a; + } + + void setUv(float u, float v) + { + uv.u = u; + uv.v = v; + } +}; + +} // namespace yage + +#endif diff --git a/yage/base/window.cpp b/yage/base/window.cpp new file mode 100644 index 00000000..143b1d5d --- /dev/null +++ b/yage/base/window.cpp @@ -0,0 +1,97 @@ +/* ---------------------------------------------------------------------------- + * window.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include +#include + +#include +#include + +namespace yage +{ + +Window::Window() = default; + +Window::~Window() +{ + SDL_DestroyWindow(window_); +} + +void Window::create(const std::string &window_name, int width, int height, + unsigned flags) +{ + Uint32 gl_window_states = 0; + + // set the correct input flags + if (flags & WindowFlags::SHOWN) { + gl_window_states |= SDL_WINDOW_OPENGL; + } + if (flags & WindowFlags::HIDDEN) { + gl_window_states |= SDL_WINDOW_HIDDEN; + } + if (flags & WindowFlags::FULLSCREEN) { + gl_window_states |= SDL_WINDOW_FULLSCREEN; + } + if (flags & WindowFlags::BORDERLESS) { + gl_window_states |= SDL_WINDOW_BORDERLESS; + } + + // SDL_GL options + + // SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 4); + // SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 5); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + // create the SDL window + window_ = SDL_CreateWindow(window_name.c_str(), SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, width, height, + gl_window_states); + if (window_ == nullptr) { + throw std::runtime_error("SDL_CreateWindow failed"); + } + + // initialize the GL context in the window + SDL_GLContext gl_context = SDL_GL_CreateContext(window_); + if (gl_context == nullptr) { + throw std::runtime_error("SDL_GL_CreateContext failed"); + } + + // initialize glew + GLenum error = glewInit(); + if (error != GLEW_OK) { + throw std::runtime_error("glewInit failed"); + } + + // print out the current OpenGL version to debug + std::cout << "*** OpenGL version: " << glGetString(GL_VERSION) + << " ***\n"; + + // set vsync on instead of custom fps limiting + SDL_GL_SetSwapInterval(1); + // set the clear color to black + glClearColor(0.f, 0.5f, 0.f, 1.f); + // set alpha blending + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +void Window::swapBuffer() +{ + // swap the window buffer + SDL_GL_SwapWindow(window_); +} + +void Window::clearBuffer() +{ + // set the clear depth + glClearDepth(1.f); + // clears buffer with clear color + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +} // namespace yage diff --git a/yage/base/window.h b/yage/base/window.h new file mode 100644 index 00000000..8639e075 --- /dev/null +++ b/yage/base/window.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------------- + * window.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef WINDOW_H +#define WINDOW_H + +#include + +#include + +namespace yage +{ + +// window flags that can change it's appearance +enum WindowFlags : unsigned { + SHOWN = 0x1, + HIDDEN = 0x2, + FULLSCREEN = 0x4, + BORDERLESS = 0x8, +}; + +// window wrapper around SDL_Window pointer +class Window +{ +private: + /// window handle + SDL_Window *window_ = nullptr; + +public: + Window(); + Window(const Window &) = delete; + Window(Window &&) = delete; + /// destroys the window handle + ~Window(); + + Window &operator=(const Window &) = delete; + Window &operator=(Window &&) = delete; + + /// create the window, initialize the handle and update the width and height + void create(const std::string &window_name, int width, int height, + unsigned flags = WindowFlags::SHOWN); + /// swap the buffer + void swapBuffer(); + /// clear buffer + void clearBuffer(); +}; + +} // namespace yage + +#endif diff --git a/yage/math/CMakeLists.txt b/yage/math/CMakeLists.txt new file mode 100644 index 00000000..761ab59f --- /dev/null +++ b/yage/math/CMakeLists.txt @@ -0,0 +1 @@ +set(YAGE_MATH_SOURCES) diff --git a/yage/math/math.h b/yage/math/math.h new file mode 100644 index 00000000..b729dbe6 --- /dev/null +++ b/yage/math/math.h @@ -0,0 +1,14 @@ +/* ---------------------------------------------------------------------------- + * math.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_MATH_H +#define YAGE_MATH_H + +#include "matrix.h" + +#endif diff --git a/yage/math/matrix.h b/yage/math/matrix.h new file mode 100644 index 00000000..3992acfe --- /dev/null +++ b/yage/math/matrix.h @@ -0,0 +1,424 @@ +/* ---------------------------------------------------------------------------- + * matrix.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +/** @file + */ + +#ifndef YAGE_MATH_MATRIX_H +#define YAGE_MATH_MATRIX_H + +#include +#include +#include +#include +#include +#include + +namespace yage +{ + +template +class Matrix; + +/** @internal Namespace for internal details. + * + * Detail Namespace + * ================ + * + * This is the namespace used for implementation detail. + */ +namespace detail +{ + +/** @internal Internal Row class used by the Matrix class to return the + * internal data structure of the Matrix. + * + * Row + * === + * + * Internal Row class to return a value in the row of the matrix. + */ +template +class Row +{ +private: + Matrix *parent_; + int index_; + +public: + Row(Matrix *parent, int index) + : parent_(parent), index_(index) + { + } + + Type &operator[](int col) + { + // The index is the y-position of the element in the matrix + return parent_->data_[index_ * Cols + col]; + } + + const Type &operator[](int col) const + { + return parent_->data_[index_ * Cols + col]; + } +}; + +} // namespace detail + +/** Base Matrix class used by other similar classes. + */ +template +class Matrix +{ + // friended with the row class so that it can access protected member data. + friend class detail::Row; + +protected: + /// Vector containing the data of the matrix. + std::vector data_; + +public: + /// Initializes the size of the data_ vector. + Matrix() : data_(Rows * Cols) {} + Matrix(const std::vector &data) : data_(data) {} + + /// Returns the row size of the Matrix. + int rowSize() const { return Rows; } + + /// Returns the column size of the Matrix. + int colSize() const { return Cols; } + + /** Return the row specified row as a Matrix with only one row. + * + * @param row Row number to be returned. + * @return The row that is specified by the row variables. + */ + Matrix<1, Cols, Type> getRow(int row) const + { + Matrix<1, Cols, Type> rowMatrix; + for (int i = 0; i < Cols; ++i) { + rowMatrix[0][i] = data_[row][i]; + } + return rowMatrix; + } + + /** Get a specific column in a column vector. + * + * @param col Column number to be returned. + * @return Column Matrix of the selected column. + */ + Matrix getCol(int col) const + { + Matrix colMatrix; + for (int i = 0; i < Rows; ++i) { + colMatrix[i][0] = data_[i][col]; + } + return colMatrix; + } + + /** Iterator support for the start. + * + * @return Iterator pointing to the start of the data. + */ + typename std::vector::iterator begin() { return data_.begin(); } + + /** Iterator support for the end. + * + * @return Iterator pointing to the end of the data. + */ + typename std::vector::iterator end() { return data_.end(); } + + /** Prints out the matrix, but can also be implemented by other classes to + * print data differently. + * + * @bug When printing certain matrices, it omits a row or column. Still + * need to determine under which conditions. + */ + virtual std::string toString() const + { + std::stringstream ss; + ss << '['; + for (int i = 0; i < Rows - 1; ++i) { + ss << '['; + for (int j = 0; j < Cols - 1; ++j) { + ss << data_[i * Cols + j] << ' '; + } + ss << data_[(Rows - 1) * Cols + Cols - 1] << "],"; + } + ss << '['; + for (int j = 0; j < Cols - 1; ++j) { + ss << data_[(Rows - 1) * Cols + j] << ' '; + } + ss << data_[(Rows - 1) * Cols + Cols - 1] << "]]"; + return ss.str(); + } + + detail::Row operator[](int row) + { + return detail::Row(this, row); + } + + detail::Row operator[](int row) const + { + return detail::Row((Matrix *)this, + row); + } + + Matrix &operator+=(const Matrix &rhs) + { + std::vector out; + out.reserve(data_.size()); + std::transform(data_.begin(), data_.end(), rhs.data_.begin(), + std::back_inserter(out), + [](Type a, Type b) { return a + b; }); + data_ = std::move(out); + return *this; + } + + Matrix &operator-=(const Matrix &rhs) + { + std::vector out; + out.reserve(data_.size()); + std::transform(data_.begin(), data_.end(), rhs.begin(), + std::back_inserter(out), + [](Type a, Type b) { return a - b; }); + data_ = std::move(out); + return *this; + } +}; + +template +Matrix operator+(Matrix lhs, const Matrix &rhs) +{ + lhs += rhs; + return lhs; +} + +template +Matrix operator-(Matrix lhs, const Matrix &rhs) +{ + lhs -= rhs; + return lhs; +} + +template +Matrix operator+(Matrix lhs, const T &rhs) +{ + for (auto &data : lhs) { + data += rhs; + } + return lhs; +} + +template +Matrix operator+(const T &lhs, Matrix rhs) +{ + for (auto &data : rhs) { + data += lhs; + } + return rhs; +} + +template +Matrix operator-(Matrix lhs, const T &rhs) +{ + for (auto &data : lhs) { + data -= rhs; + } + return lhs; +} + +template +Matrix operator-(const T &lhs, Matrix rhs) +{ + for (auto &data : rhs) { + data = lhs - data; + } + return rhs; +} + +template +Matrix operator*(Matrix lhs, const T &rhs) +{ + for (auto &data : lhs) { + data *= rhs; + } + return lhs; +} + +template +Matrix operator*(const T &lhs, Matrix rhs) +{ + for (auto &data : rhs) { + data *= lhs; + } + return rhs; +} + +template +Matrix operator/(Matrix lhs, const T &rhs) +{ + for (auto &data : lhs) { + data /= rhs; + } + return lhs; +} + +template +bool operator==(const Matrix &lhs, const Matrix &rhs) +{ + for (int i = 0; i < M; ++i) { + for (int j = 0; j < N; ++j) { + if (lhs[i][j] != rhs[i][j]) { + return false; + } + } + } + return true; +} + +template +std::ostream &operator<<(std::ostream &os, const Matrix &mat) +{ + return os << mat.toString(); +} + +template +class Vector : public Matrix +{ +public: + Vector() : Matrix() {} + Vector(const Matrix &other) + : Matrix(other) + { + } + + Vector(const std::vector &data) + : Matrix(data) + { + } + + Type &operator[](int col) { return this->data_[col]; } + + const Type &operator[](int col) const { return this->data_[col]; } + + std::string toString() const override + { + std::stringstream ss; + ss << "["; + for (std::size_t i = 0; i < this->data_.size() - 1; ++i) { + ss << this->data_[i] << " "; + } + ss << this->data_[this->data_.size() - 1] << "]"; + return ss.str(); + } +}; + +/** 2D Vector class. + * + * Two dimensional vector class. + */ +template +class Vector2 : public Vector<2, Type> +{ +public: + Vector2() : Vector<2, Type>() {} + Vector2(const std::vector &data) : Vector<2, Type>(data) {} + + Vector2(Type x, Type y) + { + this->data_[0] = x; + this->data_[1] = y; + } + + Vector2(const Matrix<2, 1, Type> &other) : Vector<2, Type>(other) {} + + Type &x() { return this->data_[0]; } + + const Type &x() const { return this->data_[0]; } + + Type &y() { return this->data_[1]; } + + const Type &y() const { return this->data_[1]; } +}; + +/** Definition of a 2D vector. + */ +using Vector2d = Vector2; + +/** Namespace containing functions that operate on matrices. + * + * Implementations defined here are meant to operate on anything that inherits + * from the base Matrix class. + */ +namespace matrix +{ + +/** Transposes a matrix and returns the result + * + * @param m input matrix. + */ +template +Matrix transpose(const Matrix &m) +{ + Matrix trans; + for (int i = 0; i < M; ++i) { + for (int j = 0; j < N; ++j) { + trans[j][i] = m[i][j]; + } + } + return trans; +} + +/** Returns the dot product between two vectors + * + * @param m1,m2 Input matrices. + */ +template +T dot(const Matrix &m1, const Matrix &m2) +{ + T sum = 0; + for (int i = 0; i < R; ++i) { + sum += m1[i][0] * m2[i][0]; + } + return sum; +} + +/** Multiplies two matrices together. + * + * @param m1,m2 Matrix inputs + * + * Requires the two matrices to be compatible with multiplication. + */ +template +Matrix multiply(const Matrix &m1, const Matrix &m2) +{ + /// @todo Think if this should be a static_assert. + if (N != P) { + throw std::runtime_error( + "Matrices don't have the right dimensions for multiplication"); + } + + Matrix res; + + /// Performs multiplication by getting the rows and columns, transposing + /// one of them and then doting the result. + for (int i = 0; i < M; ++i) { + for (int j = 0; j < Q; ++j) { + res[i][j] = dot(transpose(m1.getRow(i)), m2.getCol(j)); + } + } + + return res; +} + +} // namespace matrix + +} // namespace yage + +#endif diff --git a/yage/physics/CMakeLists.txt b/yage/physics/CMakeLists.txt new file mode 100644 index 00000000..46c97596 --- /dev/null +++ b/yage/physics/CMakeLists.txt @@ -0,0 +1,6 @@ +set(YAGE_PHYSICS_SOURCES + physics/rectanglecollider.cpp + physics/rigidbody.cpp + physics/particlebody.cpp + physics/body.cpp + ) diff --git a/yage/physics/README.org b/yage/physics/README.org new file mode 100644 index 00000000..0620cc93 --- /dev/null +++ b/yage/physics/README.org @@ -0,0 +1,27 @@ +#+ TITLE : README +#+ DATE : <2017 - 04 - 17 Mon> +#+ AUTHOR: +#+ EMAIL : yannherklotz @yann - arch +#+ OPTIONS : ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline +#+ OPTIONS : author : t c : nil creator : comment d : (not"LOGBOOK") date : t +#+ OPTIONS : e : t email : nil f : t inline : t num : t p : nil pri : nil stat : t +#+ OPTIONS : tags : t tasks : t tex : t timestamp : t toc : t todo : t | : t +#+ CREATOR : Emacs 25.1.1(Org mode 8.2.10) +#+ DESCRIPTION: +#+ EXCLUDE_TAGS : noexport +#+ KEYWORDS: +#+ LANGUAGE : en +#+ SELECT_TAGS : export + +*Physics Engine + + **Acceleration, + speed and position + + I have a = dv / dt; +v = dp / dt; + +I am going to use the second order runga kutta method with a = 0, b = 1, + alpha = + 1 / 2 and beta = + 1 / 2 diff --git a/yage/physics/body.cpp b/yage/physics/body.cpp new file mode 100644 index 00000000..8d38e70a --- /dev/null +++ b/yage/physics/body.cpp @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------------- + * body.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include + +#include + +namespace yage +{ + +const double Body::GRAVITY = -9.81; + +double Body::xPosition() const +{ + return position_[0]; +} + +double Body::yPosition() const +{ + return position_[1]; +} + +Body::Body(Vector2d position, double mass, Vector2d velocity, bool gravity) + : position_(std::move(position)), mass_(mass), + velocity_(std::move(velocity)), gravity_(gravity) +{ +} + +} // namespace yage diff --git a/yage/physics/body.h b/yage/physics/body.h new file mode 100644 index 00000000..bd33a9ac --- /dev/null +++ b/yage/physics/body.h @@ -0,0 +1,56 @@ +/* ---------------------------------------------------------------------------- + * body.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_PHYSICS_BODY_H +#define YAGE_PHYSICS_BODY_H + +#include + +namespace yage +{ +class Body +{ +public: + // gravity constant + static const double GRAVITY; + +protected: + // center of mass of the object + Vector2d position_ = Vector2d(0, 0); + + // mass of the object + double mass_ = 1; + + // current velocity of the object + Vector2d velocity_ = Vector2d(0, 0); + + // boolean that defines if gravity can act on the object + bool gravity_ = true; + + // current acceleration + Vector2d acceleration_ = Vector2d(0, 0); + + // force acting on the body + Vector2d force_ = Vector2d(0, 0); + +public: + // apply force to the object and update the velocity + virtual void applyForce(const Vector2d &force) = 0; + virtual void update() = 0; + + double xPosition() const; + double yPosition() const; + +protected: + // protected constructor to initialize member variables + Body(Vector2d position = Vector2d(0, 0), double mass = 1, + Vector2d velocity = Vector2d(0, 0), bool gravity = false); +}; +} // namespace yage + +#endif diff --git a/yage/physics/collider.h b/yage/physics/collider.h new file mode 100644 index 00000000..2fd2ff89 --- /dev/null +++ b/yage/physics/collider.h @@ -0,0 +1,43 @@ +/* ---------------------------------------------------------------------------- + * collider.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_PHYSICS_COLLIDER_H +#define YAGE_PHYSICS_COLLIDER_H + +#include + +namespace yage +{ + +// The Collider class helps collision detection by providing a general shape +// for different shapes to have their own collision algorithms. +class Collider +{ +protected: + // position of the object + glm::vec2 position_; + + // size of the object + glm::vec2 size_; + +public: + Collider(const glm::vec2 &position, const glm::vec2 &size) + : position_(position), size_(size) + { + } + + // function that checks if two colliders are colliding + virtual bool collides(const Collider &collider) const = 0; + + // function that returns if a point is inside the shape + virtual bool inside(const glm::vec2 &point) const = 0; +}; + +} // namespace yage + +#endif diff --git a/yage/physics/collisionbody.h b/yage/physics/collisionbody.h new file mode 100644 index 00000000..715c4a54 --- /dev/null +++ b/yage/physics/collisionbody.h @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------------- + * collisionbody.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_COLLISION_BODY_H +#define YAGE_COLLISION_BODY_H + +#include "body.h" + +namespace yage +{ + +// a collision body will be a body that is static and not affected by gravity, +// with infinite mass +class CollisionBody : public Body +{ +public: + CollisionBody(); + virtual ~CollisionBody(); +}; + +} // yage + +#endif diff --git a/yage/physics/particlebody.cpp b/yage/physics/particlebody.cpp new file mode 100644 index 00000000..bdb81eac --- /dev/null +++ b/yage/physics/particlebody.cpp @@ -0,0 +1,54 @@ +/* ---------------------------------------------------------------------------- + * particlebody.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include + +#include +#include + +namespace yage +{ + +ParticleBody::ParticleBody(const Vector2d &position, double mass, + const Vector2d &velocity, bool gravity) + : Body(position, mass, velocity, gravity) +{ +} + +void ParticleBody::applyForce(const Vector2d &force) +{ + force_ += force; +} + +void ParticleBody::update() +{ + // set the time_step for 60fps + double time_step = 1.0 / 60.0; + + // set the last acceleration + Vector2d last_acceleration = acceleration_; + + // update the position of the body + position_ += velocity_ * time_step + + (0.5 * last_acceleration * std::pow(time_step, 2)); + + // update the acceleration + if (gravity_) { + acceleration_ = + Vector2d(force_.x() / mass_, (GRAVITY + force_.y()) / mass_); + } else { + acceleration_ = Vector2d(force_.x() / mass_, force_.y() / mass_); + } + + Vector2d avg_acceleration = (acceleration_ + last_acceleration) / 2.0; + + // update the velocity of the body + velocity_ += avg_acceleration * time_step; +} + +} // namespace yage diff --git a/yage/physics/particlebody.h b/yage/physics/particlebody.h new file mode 100644 index 00000000..a0b9bdad --- /dev/null +++ b/yage/physics/particlebody.h @@ -0,0 +1,33 @@ +/* ---------------------------------------------------------------------------- + * particlebody.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_PHYSICS_PARTICLE_BODY_H +#define YAGE_PHYSICS_PARTICLE_BODY_H + +#include "body.h" + +#include + +namespace yage +{ + +class ParticleBody : public Body +{ +public: + ParticleBody(const Vector2d &position = Vector2d(0, 0), double mass = 1, + const Vector2d &velocity = Vector2d(0, 0), + bool gravity = true); + + // apply a force to the rigid body + void applyForce(const Vector2d &force) override; + void update() override; +}; + +} // namespace yage + +#endif diff --git a/yage/physics/physics.h b/yage/physics/physics.h new file mode 100644 index 00000000..900f4b6a --- /dev/null +++ b/yage/physics/physics.h @@ -0,0 +1,19 @@ +/* ---------------------------------------------------------------------------- + * physics.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_PHYSICS_H +#define YAGE_PHYSICS_H + +#include "body.h" +#include "collider.h" +#include "collisionbody.h" +#include "particlebody.h" +#include "rectanglecollider.h" +#include "rigidbody.h" + +#endif diff --git a/yage/physics/rectanglecollider.cpp b/yage/physics/rectanglecollider.cpp new file mode 100644 index 00000000..64887278 --- /dev/null +++ b/yage/physics/rectanglecollider.cpp @@ -0,0 +1,36 @@ +/* ---------------------------------------------------------------------------- + * rectanglecollider.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include + +namespace yage +{ + +RectangleCollider::RectangleCollider(const glm::vec2 &position, + const glm::vec2 &size) + : Collider(position, size) +{ +} + +bool RectangleCollider::collides(const Collider &collider) const +{ + for (int i = position_.x; i < position_.x + size_.x; ++i) { + for (int j = position_.y; j < position_.y + size_.y; ++j) { + return collider.inside(glm::vec2(i, j)); + } + } + return false; +} + +inline bool RectangleCollider::inside(const glm::vec2 &point) const +{ + return position_.x < point.x && position_.x + size_.x > point.x && + position_.y < point.y && position_.y + size_.y > point.y; +} + +} // namespace yage diff --git a/yage/physics/rectanglecollider.h b/yage/physics/rectanglecollider.h new file mode 100644 index 00000000..c009f665 --- /dev/null +++ b/yage/physics/rectanglecollider.h @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------------- + * rectanglecollider.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_RECTANGLE_COLLIDER_H +#define YAGE_RECTANGLE_COLLIDER_H + +#include "collider.h" + +#include + +namespace yage +{ + +class RectangleCollider : public Collider +{ +public: + RectangleCollider(const glm::vec2 &position, const glm::vec2 &size); + + bool collides(const Collider &collider) const override; + bool inside(const glm::vec2 &point) const override; +}; + +} // namespace yage + +#endif diff --git a/yage/physics/rigidbody.cpp b/yage/physics/rigidbody.cpp new file mode 100644 index 00000000..dcab5f2f --- /dev/null +++ b/yage/physics/rigidbody.cpp @@ -0,0 +1,20 @@ +/* ---------------------------------------------------------------------------- + * rigidbody.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include + +namespace yage +{ + +RigidBody::RigidBody(const Vector2d &position, double mass, + const Vector2d &velocity, bool gravity) + : ParticleBody(position, mass, velocity, gravity) +{ +} + +} // namespace yage diff --git a/yage/physics/rigidbody.h b/yage/physics/rigidbody.h new file mode 100644 index 00000000..67ccb4ca --- /dev/null +++ b/yage/physics/rigidbody.h @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------------- + * rigidbody.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_RIGID_BODY_H +#define YAGE_RIGID_BODY_H + +#include "particlebody.h" + +#include + +namespace yage +{ + +class RigidBody : public ParticleBody +{ +public: + RigidBody(const Vector2d &position = Vector2d(0, 0), double mass = 1, + const Vector2d &velocity = Vector2d(0, 0), bool gravity = true); +}; + +} // namespace yage + +#endif diff --git a/yage/yage.h b/yage/yage.h new file mode 100644 index 00000000..6157e6bf --- /dev/null +++ b/yage/yage.h @@ -0,0 +1,63 @@ +/* ---------------------------------------------------------------------------- + * yage.h + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +/** @file Includes all the headers in the main YAGE project. + * + * This does not include + */ + +#ifndef YAGE_YAGE_H +#define YAGE_YAGE_H + +#include "camera2d.h" +#include "glslprogram.h" +#include "imageloader.h" +#include "inputmanager.h" +#include "iomanager.h" +#include "picopng.h" +#include "resourcemanager.h" +#include "spritebatch.h" +#include "texture.h" +#include "vertex.h" +#include "window.h" + +#include + +#include + +/** Project namespace. + * + * Avoids collision as all the classes and global functions are wrapped in. + * it. + */ +namespace yage +{ + +/** Initializes YAGE. + * + * This is only there to initialize SDL2. + * + * @return Returns true if the initialization was successful. + */ +bool init() +{ + return SDL_Init(SDL_INIT_VIDEO); +} + +/** Quit and cleanup YAGE + * + * SDL2 needs to clean itself up. + */ +void quit() +{ + SDL_Quit(); +} + +} // namespace yage + +#endif -- cgit