diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b70f98..b6c2321 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,9 @@ cmake_minimum_required(VERSION 3.8) project(pixwerx) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/etc/cmake") + set (CMAKE_CXX_STANDARD 17) add_subdirectory(src) +add_subdirectory(share) diff --git a/etc/cmake/Findmkdocs.cmake b/etc/cmake/Findmkdocs.cmake new file mode 100644 index 0000000..ec4fe31 --- /dev/null +++ b/etc/cmake/Findmkdocs.cmake @@ -0,0 +1,51 @@ +# - Find mkdocs +# This module finds if mkdocs is installed. This code sets the following +# variables: +# +# MKDOCS_EXECUTABLE = full path to the mkdocs binary +# +# Copyright (c) 2015 Marcel Bollmann +# based on FindPHP5.cmake by Mathieu Malaterre, found at +# +# + +find_program(MKDOCS_EXECUTABLE mkdocs) + +if(MKDOCS_EXECUTABLE) + execute_process(COMMAND ${MKDOCS_EXECUTABLE} --version + RESULT_VARIABLE res + OUTPUT_VARIABLE var + ERROR_VARIABLE var + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE) + if(res) + if(${mkdocs_FIND_REQUIRED}) + message(FATAL_ERROR "Error executing mkdocs --version") + elseif(NOT mkdocs_FIND_QUIETLY) + message(WARNING "Warning, could not run mkdocs --version") + endif() + else() + if(var MATCHES ".*mkdocs, version [0-9]+\\.[0-9]+\\.[0-9_.]+.*") + string(REGEX REPLACE ".*mkdocs, version ([0-9]+\\.[0-9]+\\.[0-9_.]+).*" + "\\1" MKDOCS_VERSION_STRING "${var}") + else() + if(NOT mkdocs_FIND_QUIETLY) + message(WARNING "regex not supported: {$var}.") + endif() + endif() + + string( REGEX REPLACE "([0-9]+).*" "\\1" MKDOCS_VERSION_MAJOR "${MKDOCS_VERSION_STRING}" ) + string( REGEX REPLACE "[0-9]+\\.([0-9]+).*" "\\1" MKDOCS_VERSION_MINOR "${MKDOCS_VERSION_STRING}" ) + string( REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" MKDOCS_VERSION_PATCH "${MKDOCS_VERSION_STRING}" ) + set(MKDOCS_VERSION ${MKDOCS_VERSION_MAJOR}.${MKDOCS_VERSION_MINOR}.${MKDOCS_VERSION_PATCH}) + endif() +endif() + +mark_as_advanced( + MKDOCS_EXECUTABLE + ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(mkdocs + REQUIRED_VARS MKDOCS_EXECUTABLE + VERSION_VAR MKDOCS_VERSION) diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt new file mode 100644 index 0000000..eb0be27 --- /dev/null +++ b/share/CMakeLists.txt @@ -0,0 +1,20 @@ +find_package(mkdocs 1.0) + +# if(MKDOCS_FOUND) +# configure_file(mkdocs.yml "${CMAKE_CURRENT_BINARY_DIR}/mkdocs.yml" COPYONLY) +# set(MKDOCS_FLAGS +# --site-dir "${CMAKE_CURRENT_BINARY_DIR}/docs/user/" +# --config-file "${CMAKE_CURRENT_BINARY_DIR}/mkdocs.yml" +# ) +# if(DEBUG_MODE) +# list(APPEND MKDOCS_FLAGS --clean --verbose) +# endif() +# add_custom_target(docs-user +# ${MKDOCS_EXECUTABLE} build ${MKDOCS_FLAGS} +# WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" +# COMMENT "Generating user documentation" +# ) +# add_dependencies(docs docs-user) +# else() +# message(STATUS "SKIPPING generation of user documentation (mkdocs not found)") +# endif() diff --git a/share/docs/index.md b/share/docs/index.md new file mode 100644 index 0000000..d388039 --- /dev/null +++ b/share/docs/index.md @@ -0,0 +1,17 @@ +# Welcome to MkDocs + +For full documentation visit [mkdocs.org](https://mkdocs.org). + +## Commands + +* `mkdocs new [dir-name]` - Create a new project. +* `mkdocs serve` - Start the live-reloading docs server. +* `mkdocs build` - Build the documentation site. +* `mkdocs help` - Print this help message. + +## Project layout + + mkdocs.yml # The configuration file. + docs/ + index.md # The documentation homepage. + ... # Other markdown pages, images and other files. diff --git a/share/mkdocs.yml b/share/mkdocs.yml new file mode 100644 index 0000000..14bd6c7 --- /dev/null +++ b/share/mkdocs.yml @@ -0,0 +1 @@ +site_name: pixwerx engine diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 97fca95..2965454 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,6 @@ add_subdirectory(system) #add_subdirectory(ui) add_subdirectory(scripting) add_subdirectory(visual) - +add_subdirectory(geometry) add_subdirectory(engine) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b4e5051..216bc78 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -2,6 +2,7 @@ set(hdrs include/pw/core/debug.hpp include/pw/core/axisangle.hpp +# include/pw/core/buffer.hpp include/pw/core/core.hpp include/pw/core/math.hpp include/pw/core/matrixbase.hpp @@ -13,12 +14,15 @@ set(hdrs include/pw/core/point.hpp include/pw/core/size.hpp include/pw/core/timer.hpp + include/pw/core/mesh.hpp include/pw/core/globals.hpp ) set(srcs + src/buffer.cpp src/image.cpp src/debug.cpp + src/mesh.cpp src/core.cpp src/serialize.cpp src/timer.cpp diff --git a/src/core/include/pw/core/buffer.hpp b/src/core/include/pw/core/buffer.hpp index dc80c89..5f894c3 100644 --- a/src/core/include/pw/core/buffer.hpp +++ b/src/core/include/pw/core/buffer.hpp @@ -1,4 +1,11 @@ -#ifndef BUFFER_HPP -#define BUFFER_HPP +#ifndef PW_CORE_BUFFER_HPP +#define PW_CORE_BUFFER_HPP -#endif // BUFFER_HPP +#include +#include + + + + + +#endif // PW_CORE_BUFFER_HPP diff --git a/src/core/include/pw/core/math.hpp b/src/core/include/pw/core/math.hpp index 6c828dd..1a10a3b 100644 --- a/src/core/include/pw/core/math.hpp +++ b/src/core/include/pw/core/math.hpp @@ -6,18 +6,21 @@ namespace pw { const static double __PW_PI = 3.1415926535897932384626433832795028841971693993751058209; +const static double __RAD2DEG = 180.0 / __PW_PI; +const static double __DEG2RAD = __PW_PI / 180.0; + template inline const T pi() { return static_cast(__PW_PI); } template -inline static double rad_to_deg(const T& angle_in_radian) { - return static_cast(angle_in_radian * T(180.) / pi()); +inline static T rad_to_deg(const T& angle_in_radian) { + return angle_in_radian * __RAD2DEG; } template -inline static double deg_to_rad(const T& angle_in_degree) { - return static_cast(angle_in_degree * pi() / T(180.)); +inline static T deg_to_rad(const T& angle_in_degree) { + return angle_in_degree * __DEG2RAD; } } diff --git a/src/core/include/pw/core/mesh.hpp b/src/core/include/pw/core/mesh.hpp index c7f7c97..0d40f7e 100644 --- a/src/core/include/pw/core/mesh.hpp +++ b/src/core/include/pw/core/mesh.hpp @@ -1,17 +1,17 @@ -#ifndef PW_SCENE_MESH_HPP -#define PW_SCENE_MESH_HPP +#ifndef PW_CORE_MESH_HPP +#define PW_CORE_MESH_HPP -#include -#include +#include +#include namespace pw { -class mesh : public component { +class mesh { public: - using component::component; - typedef std::vector index_t; - typedef std::vector vertex_t; + typedef std::vector indexarray_t; + typedef std::vector vertex3array_t; + typedef std::vector vertex2array_t; enum topology_type { triangles, @@ -23,20 +23,24 @@ public: points }; + void set_indices(const indexarray_t& v) { _indices = v; } + void set_vertices(const vertex3array_t& v) { _vertices = v; } + + const indexarray_t& indices() const { return _indices; } + const vertex3array_t& vertices() const { return _vertices; } + + void reset(); protected: - // index data - // vertex d ata - // normal data - // color data - // uv data - // tangents data - - - // boundary + indexarray_t _indices; //!< indices according to topology type + vertex3array_t _vertices; //!< geometry data + vertex3array_t _normals; //!< normal data + vertex3array_t _colors; //!< color data + std::vector _uvs; //!< storing multiple UV sets + // TODO add weights, tangents etc. pp. }; } diff --git a/src/core/src/buffer.cpp b/src/core/src/buffer.cpp new file mode 100644 index 0000000..5bfff35 --- /dev/null +++ b/src/core/src/buffer.cpp @@ -0,0 +1,5 @@ +#include "pw/core/buffer.hpp" + +namespace pw { + +} diff --git a/src/core/src/mesh.cpp b/src/core/src/mesh.cpp index 981ea1a..1423211 100644 --- a/src/core/src/mesh.cpp +++ b/src/core/src/mesh.cpp @@ -1,9 +1,8 @@ -#include "pw/scene/mesh.hpp" +#include "pw/core/mesh.hpp" namespace pw { - } diff --git a/src/deps/CMakeLists.txt b/src/deps/CMakeLists.txt index c267051..2542fca 100644 --- a/src/deps/CMakeLists.txt +++ b/src/deps/CMakeLists.txt @@ -1,5 +1,12 @@ + +set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "Build the GLFW example programs" FORCE) +set(GLFW_BUILD_TESTS OFF CACHE BOOL "Build the GLFW test programs" FORCE) +set(GLFW_BUILD_DOCS OFF CACHE BOOL "Build the GLFW documentation" FORCE) +set(GLFW_INSTALL OFF CACHE BOOL "Generate installation target" FORCE) + add_subdirectory(glfw-3.2.1) add_subdirectory(lua-5.3.5) add_subdirectory(glad) + #add_subdirectory(arrrgh) diff --git a/src/deps/glad/CMakeLists.txt b/src/deps/glad/CMakeLists.txt index f10b64c..4dc5f6e 100644 --- a/src/deps/glad/CMakeLists.txt +++ b/src/deps/glad/CMakeLists.txt @@ -1,4 +1,11 @@ +cmake_minimum_required(VERSION 3.8) project(glad) -add_subdirectory(src) +add_library(glad STATIC src/glad.c) + +target_include_directories( + glad + PUBLIC + include + ) diff --git a/src/deps/glad/src/CMakeLists.txt b/src/deps/glad/src/CMakeLists.txt deleted file mode 100644 index 73ddadb..0000000 --- a/src/deps/glad/src/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) -add_library(glad STATIC glad.c) diff --git a/src/geometry/CMakeLists.txt b/src/geometry/CMakeLists.txt new file mode 100644 index 0000000..aff3169 --- /dev/null +++ b/src/geometry/CMakeLists.txt @@ -0,0 +1,29 @@ + +set(hdrs + include/pw/geometry/primitives.hpp + ) + +set(srcs + src/primitives.cpp + ) + +add_library(pwgeometry + STATIC + ${hdrs} + ${srcs} + ) + +target_include_directories( + pwgeometry + PUBLIC + include + ) + +target_include_directories( + pwgeometry + PUBLIC + ) + +target_link_libraries(pwgeometry pwcore) + +#add_subdirectory(tests) diff --git a/src/geometry/include/pw/geometry/primitives.hpp b/src/geometry/include/pw/geometry/primitives.hpp new file mode 100644 index 0000000..c034ccc --- /dev/null +++ b/src/geometry/include/pw/geometry/primitives.hpp @@ -0,0 +1,21 @@ +#ifndef PW_GEOMETRY_PRIMITIVES_HPP +#define PW_GEOMETRY_PRIMITIVES_HPP + +#include + +namespace pw { + + struct primitives { + + static mesh box(real_t size_x, real_t size_y, real_t size_z); + + static mesh sphere(real_t radius,int divisions_latitude,int divisions_longitude); + + static mesh cone(); + + static mesh pyramid(); + }; + +}; + +#endif diff --git a/src/geometry/src/CMakeLists.txt b/src/geometry/src/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/geometry/src/primitives.cpp b/src/geometry/src/primitives.cpp new file mode 100644 index 0000000..86381c1 --- /dev/null +++ b/src/geometry/src/primitives.cpp @@ -0,0 +1,87 @@ +#include "pw/geometry/primitives.hpp" + +namespace pw { + +mesh primitives::box(real_t size_x,real_t size_y, real_t size_z) +{ + mesh m; + + mesh::vertex3array_t vertices; + + vertices.push_back(vector3(-size_x / 2,-size_y / 2, size_z / 2)); // 0 + vertices.push_back(vector3( size_x / 2,-size_y / 2, size_z / 2)); // 1 + vertices.push_back(vector3( size_x / 2, size_y / 2, size_z / 2)); // 2 + vertices.push_back(vector3(-size_x / 2, size_y / 2, size_z / 2)); // 3 + + vertices.push_back(vector3(-size_x / 2,-size_y / 2,-size_z / 2)); // 4 + vertices.push_back(vector3( size_x / 2,-size_y / 2,-size_z / 2)); // 5 + vertices.push_back(vector3( size_x / 2, size_y / 2,-size_z / 2)); // 6 + vertices.push_back(vector3(-size_x / 2, size_y / 2,-size_z / 2)); // 7 + + mesh::indexarray_t indices = { + 0, 1, 2, // 0 + 2, 3, 0, // 1 + 1, 5, 6, // 2 + 6, 2, 1, // 3 + 5, 4, 7, // 4 + 7, 6, 5, // 5 + 4, 0, 3, // 6 + 3, 7, 4, // 7 + 3, 2, 6, // 8 + 6, 7, 3, // 9 + 4, 5, 1, // 10 + 1, 0, 4 // 11 + }; + + m.set_indices(indices); + + return m; +} + +mesh primitives::sphere(real_t radius,int divisions_latitude,int divisions_longitude) +{ + using std::cos; + using std::sin; + + const real_t _division_lat = real_t(360.0) / divisions_latitude; + const real_t _division_lon = real_t(360.0) / divisions_longitude; + +// res = new tpPrimitive(tpPrimitive::kTriangleStrip); + + //res->setPrimitiveType(tpPrimitive::kLineStrip); + +// real_t _latitude, _longitude; + real_t dToR; + real_t x, y, z; + + for (real_t _latitude = 0; _latitude < 360; _latitude += _division_lat) + { + for (real_t _longitude = 0; _longitude < 360; _longitude += _division_lon) + { + x = sin ( deg_to_rad(_longitude) ) * cos ( (_latitude + _division_lat) ); + y = sin ( deg_to_rad(_latitude + _division_lat) ); + z = cos ( deg_to_rad(_longitude) * cos ( deg_to_rad(_latitude + _division_lat) ) ); + + // assign the second normal and vertex +// res->addVertexNormal(tpVec3r(x * radius,y * radius,z * radius), +// tpVec3r(x,y,z) +// ); + + // calculate the coordinates + x = sin ( deg_to_rad(_longitude) ) * cos (deg_to_rad(_latitude) ); + y = sin ( deg_to_rad(_latitude) ); + z = cos ( deg_to_rad(_longitude) ) * cos (deg_to_rad(_latitude) ); + + // assign a normal and a vertex +// res->addVertexNormal( +// tpVec3r(x * radius,y * radius,z * radius), +// tpVec3r(x,y,z) +// ); + + } + } + + +} + +} diff --git a/src/scene/CMakeLists.txt b/src/scene/CMakeLists.txt index ccff4ab..d5d7950 100644 --- a/src/scene/CMakeLists.txt +++ b/src/scene/CMakeLists.txt @@ -3,7 +3,7 @@ set(hdrs include/pw/scene/camera.hpp include/pw/scene/component.hpp include/pw/scene/node.hpp - include/pw/scene/mesh.hpp +# include/pw/scene/mesh.hpp include/pw/scene/scene.hpp include/pw/scene/transform.hpp include/pw/scene/traverser.hpp @@ -13,7 +13,7 @@ set(srcs src/node.cpp src/camera.cpp src/component.cpp - src/mesh.cpp +# src/mesh.cpp src/scene.cpp src/transform.cpp src/traverser.cpp diff --git a/src/scene/include/pw/scene/camera.hpp b/src/scene/include/pw/scene/camera.hpp index 66dede6..a8bd0c7 100644 --- a/src/scene/include/pw/scene/camera.hpp +++ b/src/scene/include/pw/scene/camera.hpp @@ -62,8 +62,8 @@ protected: real_t _ortho_size = 2; - private: + matrix4x4 _projection; }; diff --git a/src/scripts/demos/simple_000.lua b/src/scripts/demos/simple_000.lua index 5931cc3..3f69c1e 100644 --- a/src/scripts/demos/simple_000.lua +++ b/src/scripts/demos/simple_000.lua @@ -78,11 +78,9 @@ do if (pw.input:get().mouse_button == 1) then print(pw.input:get().mouse_position.x,pw.input:get().mouse_position.y) --- w.fullscreen = not w.fullscreen +-- w.fullscreen = not w.fullscreen end - - -- print("update") end diff --git a/src/system/CMakeLists.txt b/src/system/CMakeLists.txt index 606904c..f475113 100644 --- a/src/system/CMakeLists.txt +++ b/src/system/CMakeLists.txt @@ -1,25 +1,25 @@ set(hdrs - include/pw/system/window.hpp - include/pw/system/input.hpp - ) + include/pw/system/window.hpp + include/pw/system/input.hpp + ) set(srcs - src/window.cpp - src/input.cpp - ) + src/window.cpp + src/input.cpp + ) add_library(pwsystem - STATIC - ${hdrs} - ${srcs} - ) + STATIC + ${hdrs} + ${srcs} + ) target_include_directories( - pwsystem - PUBLIC - include - ) + pwsystem + PUBLIC + include + ) target_link_libraries(pwsystem pwcore pwvisual glfw glad) diff --git a/src/visual/CMakeLists.txt b/src/visual/CMakeLists.txt index 423dcb9..23eec8b 100644 --- a/src/visual/CMakeLists.txt +++ b/src/visual/CMakeLists.txt @@ -1,11 +1,13 @@ set(hdrs include/pw/visual/renderer.hpp + include/pw/visual/shader.hpp include/pw/visual/context.hpp ) set(srcs src/renderer.cpp + src/shader.cpp src/context.cpp ) @@ -21,6 +23,6 @@ target_include_directories( include ) -target_link_libraries(pwvisual pwscene) +target_link_libraries(pwvisual pwscene glad) #add_subdirectory(tests) diff --git a/src/visual/include/pw/visual/renderer.hpp b/src/visual/include/pw/visual/renderer.hpp index 7941ecd..547102f 100644 --- a/src/visual/include/pw/visual/renderer.hpp +++ b/src/visual/include/pw/visual/renderer.hpp @@ -1,15 +1,29 @@ #ifndef PW_VISUAL_RENDERER_HPP #define PW_VISUAL_RENDERER_HPP -#include +//#include +//#include + +#include +#include + +#include namespace pw { -class context; - class renderer { +public: - void render(context& context); + void render(const mesh& mesh, + const matrix4x4& model_matrix, + const matrix4x4& view_matrix, + const matrix4x4& projection_matrix + ); + +protected: + + struct impl; + std::unique_ptr _impl; }; diff --git a/src/visual/include/pw/visual/shader.hpp b/src/visual/include/pw/visual/shader.hpp new file mode 100644 index 0000000..84d58df --- /dev/null +++ b/src/visual/include/pw/visual/shader.hpp @@ -0,0 +1,41 @@ +#ifndef PW_VISUAL_SHADER_HPP +#define PW_VISUAL_SHADER_HPP + +#include +#include + +#include + +namespace pw { + +class shader { +public: + + shader(); + + enum code_type { + vertex, //< + fragment, + geometry, + compute + }; + + void set_source(const std::string& c,code_type t); + std::string source(code_type t) { return _source[t]; } + +// void set_attributes(const std::vector > &attributes); + + bool ready() const; + +protected: + + std::map _source; + + struct impl; + std::unique_ptr _impl; + +}; + +} + +#endif diff --git a/src/visual/src/renderer.cpp b/src/visual/src/renderer.cpp index 26a9e32..a79227d 100644 --- a/src/visual/src/renderer.cpp +++ b/src/visual/src/renderer.cpp @@ -1,9 +1,69 @@ #include "pw/visual/renderer.hpp" +#include "pw/core/mesh.hpp" + +#include "glad/glad.h" + namespace pw { -void renderer::render(pw::context &context) -{ -} + +struct renderer::impl { + + GLuint _vao = 0; + std::vector _vbos; + + impl(renderer& ) + { + } + + void create(std::shared_ptr mesh) + { + glGenVertexArrays(1,&_vao); + glBindVertexArray(_vao); + + size_t arrays_needed = 0; + + // should bail out here + if (!mesh->vertices().empty()) arrays_needed++; + if (!mesh->indices().empty()) arrays_needed++; + + // TODO: implement the other arrays + + _vbos.resize(arrays_needed); + + glGenBuffers(_vbos.size(), _vbos.data()); + + // vertices + glBindBuffer(GL_ARRAY_BUFFER, _vbos[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(mesh->vertices().front()) * mesh->vertices().size(), mesh->vertices().data(), + GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + // indices + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbos[1]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(mesh->indices().front()) * mesh->indices().size(), mesh->indices().data(), + GL_STATIC_DRAW); + + + // stop binding + glBindVertexArray(0); + + } + + void destroy() + { + glDeleteVertexArrays(1,&_vao); + for (auto vbo : _vbos) + glDeleteBuffers(1,&vbo); + + _vbos.clear(); + } +}; + +//pipeline > n*pass +//compositor +// render to fbo > + } diff --git a/src/visual/src/shader.cpp b/src/visual/src/shader.cpp new file mode 100644 index 0000000..29560e4 --- /dev/null +++ b/src/visual/src/shader.cpp @@ -0,0 +1,177 @@ +#include "pw/visual/shader.hpp" +#include "pw/core/debug.hpp" + + + +#include "glad/glad.h" + +namespace pw { + +// TODO: move this to a separate implementation + +struct shader::impl +{ + shader& _shader; + + GLuint _shader_program; + std::vector _shader_stages; + + impl(shader& s) + : _shader(s) + { + } + + ~impl() + { + clear(); + } + + bool is_valid() + { + return glIsProgram(_shader_program); + } + + void build() + { + + for (auto s : _shader._source) + { + GLuint shader_type = 0; + switch (s.first) { + case shader::vertex: + shader_type = GL_VERTEX_SHADER; + break; + case shader::compute: + shader_type = GL_COMPUTE_SHADER; + break; + case shader::geometry: + shader_type = GL_GEOMETRY_SHADER; + break; + case shader::fragment: + shader_type = GL_FRAGMENT_SHADER; + break; + } + + GLuint shaderId = glCreateShader(shader_type); + + char* src = const_cast(s.second.c_str()); + GLint size = static_cast(s.second.length()); + + glShaderSource(shaderId , 1, &src, &size); + + glCompileShader(shaderId); + + GLint is_compiled = GL_FALSE; + glGetShaderiv(shaderId, GL_COMPILE_STATUS, &is_compiled); + if(is_compiled == GL_FALSE) + { + + GLint log_length; + + glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &log_length); + + char* log_buffer = new char[log_length]; + + glGetShaderInfoLog(shaderId, log_length, &log_length, log_buffer); + + // TODO - handle errors! + + std::string info_log_string(log_buffer); + + delete [] log_buffer; + + debug::e() << info_log_string; + + break; + } + + _shader_stages.push_back(shaderId); + + } + + _shader_program = glCreateProgram(); + + + for (auto s : _shader_stages) + glAttachShader(_shader_program,s); + + + // attribute binding ... + + /* Bind attribute index 0 (coordinates) to in_Position and attribute index 1 (color) to in_Color */ + /* Attribute locations must be setup before calling glLinkProgram. */ +// glBindAttribLocation(shaderprogram, 0, "in_Position"); +// glBindAttribLocation(shaderprogram, 1, "in_Color"); + + glLinkProgram(_shader_program); + + GLint is_linked = 0; + glGetProgramiv(_shader_program, GL_LINK_STATUS, &is_linked); + if(is_linked == GL_FALSE) + { + + GLint log_length; + + /* Noticed that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv. */ + glGetProgramiv(_shader_program, GL_INFO_LOG_LENGTH, &log_length); + + /* The maxLength includes the NULL character */ + char* info_log = new char[log_length]; + + /* Notice that glGetProgramInfoLog, not glGetShaderInfoLog. */ + glGetProgramInfoLog(_shader_program, log_length, &log_length, info_log); + + + std::string info_log_string; + + debug::e() << info_log_string; + + + /* Handle the error in an appropriate way such as displaying a message or writing to a log file. */ + /* In this simple program, we'll just leave */ + delete [] info_log; + + return; + } + } + + + void use() + { + glUseProgram(_shader_program); + } + + void clear() + { + if (is_valid()) { + glDeleteProgram(_shader_program); + + for (auto s : _shader_stages) + { + glDeleteShader(s); + } + } + } + + void set_uniform(const std::string& name,const matrix4x4f& m) + { + GLint l = glGetUniformLocation(_shader_program,name.c_str()); + glUniformMatrix4fv(l,1,GL_FALSE,m.data()); // TODO transpose? + } + +}; + + + +shader::shader() +{ + _impl = make_unique(*this); +} + +bool shader::ready() const +{ + return _impl->is_valid(); +} + + +}