diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..2cbfb4d --- /dev/null +++ b/.clang-format @@ -0,0 +1,178 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: false +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Right +PPIndentWidth: -1 +ReferenceAlignment: Pointer +ReflowComments: true +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + diff --git a/Box0.bin b/Box0.bin new file mode 100644 index 0000000..d7798ab Binary files /dev/null and b/Box0.bin differ diff --git a/Box0.gltf b/Box0.gltf new file mode 100644 index 0000000..7f603f0 --- /dev/null +++ b/Box0.gltf @@ -0,0 +1,142 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.800000011920929, + 0.0, + 0.0, + 1.0 + ], + "metallicFactor": 0.0 + }, + "name": "Red" + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 648, + "uri": "Box0.bin" + } + ] +} diff --git a/CMake/GetTinygltf.cmake b/CMake/GetTinygltf.cmake new file mode 100644 index 0000000..0112581 --- /dev/null +++ b/CMake/GetTinygltf.cmake @@ -0,0 +1,16 @@ +set(TINYGLTF_HEADER_ONLY ON CACHE INTERNAL "" FORCE) +set(TINYGLTF_INSTALL OFF CACHE INTERNAL "" FORCE) +set(TINYGLTF_BUILD_LOADER_EXAMPLE OFF CACHE INTERNAL "" FORCE) + +# Get the tinygltf header libraries. +include(FetchContent) +FetchContent_Declare( + tinygltf + GIT_REPOSITORY https://github.com/syoyo/tinygltf.git + GIT_TAG eec4c98862b7fb760b2fb70971d7b652e593af9f +) +FetchContent_MakeAvailable(tinygltf) + +message("Downloaded tinygltf library to: ${tinygltf_SOURCE_DIR}") + +#set(STB_INCLUDE_DIR ${stb_SOURCE_DIR}) \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e297f3d..53cdba1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") project(SimpleEngine) include(cmrc/CMakeRC.cmake) -include (CMake/GetStbLibraries.cmake) +include(CMake/GetStbLibraries.cmake) # Add some CMake options: option(SIMPLE_ENGINE_BUILD_EXAMPLES "Build example projects" ON) @@ -20,16 +20,7 @@ find_package(GLEW REQUIRED) find_package(glfw3 CONFIG REQUIRED) find_package(glm CONFIG REQUIRED) find_package(OpenGL REQUIRED) - -# Get the stb header libraries. -#include(FetchContent) -#FetchContent_Declare( -# stb -# GIT_REPOSITORY https://github.com/nothings/stb.git -# GIT_TAG 8b5f1f37b5b75829fc72d38e7b5d4bcbf8a26d55 -#) -#FetchContent_MakeAvailable(stb) -#message("Downloaded stb library to: ${stb_SOURCE_DIR}") +find_package(assimp REQUIRED) # Link sources file(GLOB_RECURSE source_list src/*.cpp) @@ -53,12 +44,14 @@ target_link_libraries(simpleengine PUBLIC GLEW::GLEW) target_link_libraries(simpleengine PUBLIC glfw) target_link_libraries(simpleengine PUBLIC ${GLM_LIBRARIES}) target_link_libraries(simpleengine PUBLIC ${OPENGL_LIBRARIES}) +target_link_libraries(simpleengine PUBLIC assimp) target_link_libraries(simpleengine PRIVATE simpleengine_resources) + target_include_directories(simpleengine PUBLIC ${STB_INCLUDE_DIR}) # Include some dependencies' include directories -include_directories(${OPENGL_INCLUDE_DIR}) -include_directories(${GLM_INCLUDE_DIRS}) +target_include_directories(simpleengine PUBLIC ${OPENGL_INCLUDE_DIR}) +target_include_directories(simpleengine PUBLIC ${GLM_INCLUDE_DIRS}) # Add examples as a target if the user has them enabled if (SIMPLE_ENGINE_BUILD_EXAMPLES) diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index 9d523ab..b85b390 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -1,9 +1,11 @@ #include "simpleengine/camera.h" -#include "simpleengine/ecs/component/model_componenet.h" +#include "simpleengine/ecs/component/mesh_component.h" +#include #include "simpleengine/ecs/entity.h" #include "simpleengine/entity_manager.h" #include "simpleengine/gfx/light.h" #include "simpleengine/gfx/material.h" +#include "simpleengine/gfx/mesh.h" #include "simpleengine/gfx/model.h" #include "simpleengine/gfx/renderer.h" #include "simpleengine/gfx/texture.h" @@ -16,6 +18,7 @@ #include #include #include +#include //#include @@ -166,13 +169,11 @@ int main(int argc, char *argv[]) { // Create the entity and add the model component to it. /* auto entity = std::make_shared(); - entity->add_component(cube_vertices, cube_indicies, material, true); + entity->add_component(cube_vertices, cube_indicies, material, true); entity->translate(3.5f, 0.f, 0.f); */ - //auto entity = std::make_shared(game.get_window(), core_shader, white_texture, "examples/dev_testing/resources/dragon.obj"); auto entity = std::make_shared(); - se::gfx::Model model(material, "examples/dev_testing/resources/dragon.obj"); - entity->add_component(model); + entity->add_component("examples/dev_testing/resources/dragon.obj"); entity->translate(12.f, -4.f, 0.f); // Create a renderer and submit the entity into it. diff --git a/include/simpleengine/ecs/component/component.h b/include/simpleengine/ecs/component/component.h index e2f03cf..d132f27 100644 --- a/include/simpleengine/ecs/component/component.h +++ b/include/simpleengine/ecs/component/component.h @@ -1,6 +1,6 @@ #pragma once -#include "../../gfx/model.h" +#include "../../gfx/mesh.h" #include "../../event/event.h" #include diff --git a/include/simpleengine/ecs/component/model_componenet.h b/include/simpleengine/ecs/component/mesh_component.h similarity index 64% rename from include/simpleengine/ecs/component/model_componenet.h rename to include/simpleengine/ecs/component/mesh_component.h index f944f15..3daff3e 100644 --- a/include/simpleengine/ecs/component/model_componenet.h +++ b/include/simpleengine/ecs/component/mesh_component.h @@ -1,7 +1,7 @@ #pragma once #include "component.h" -#include "../../gfx/model.h" +#include "../../gfx/mesh.h" #include "../../gfx/material.h" #include @@ -12,16 +12,16 @@ namespace simpleengine { * @brief A Model is a object that will be shown on the screen by a renderer. * */ - class ModelComponent : public simpleengine::Component { + class MeshComponent : public simpleengine::Component { public: - gfx::Model model; + gfx::Mesh model; //gfx::Material material; - ModelComponent(gfx::Model model) : model(model) { + MeshComponent(gfx::Mesh model) : model(model) { } - ModelComponent(std::vector vertices, std::vector indicies, gfx::Material material, + MeshComponent(std::vector vertices, std::vector indicies, gfx::Material material, bool calculate_normals = false): model(vertices, indicies, material) { if (calculate_normals) { @@ -29,7 +29,7 @@ namespace simpleengine { } } - ModelComponent(std::vector vertices, std::vector indicies = std::vector(), + MeshComponent(std::vector vertices, std::vector indicies = std::vector(), std::optional material = std::nullopt, bool calculate_normals = false) : model(vertices, indicies, material) { @@ -39,7 +39,7 @@ namespace simpleengine { } virtual void update(const float& delta_time) override { - std::cout << "Model Component update" << std::endl; + } }; } \ No newline at end of file diff --git a/include/simpleengine/ecs/component/model_component.h b/include/simpleengine/ecs/component/model_component.h new file mode 100644 index 0000000..9d6dfda --- /dev/null +++ b/include/simpleengine/ecs/component/model_component.h @@ -0,0 +1,30 @@ +#pragma once + +#include "component.h" +#include "../../gfx/model.h" + +#include +#include + +namespace simpleengine { + /** + * @brief A Model is a object that will be shown on the screen by a renderer. + * + */ + class ModelComponent : public simpleengine::Component { + public: + gfx::Model model; + + ModelComponent(gfx::Model model) : model(model) { + + } + + ModelComponent(std::string model_file_path) : model(model_file_path) { + + } + + virtual void update(const float& delta_time) override { + + } + }; +} \ No newline at end of file diff --git a/include/simpleengine/ecs/entity.h b/include/simpleengine/ecs/entity.h index 54ba8a4..e1e5bf9 100644 --- a/include/simpleengine/ecs/entity.h +++ b/include/simpleengine/ecs/entity.h @@ -54,13 +54,11 @@ namespace simpleengine { } virtual void update(const float& delta_time) override { - std::cout << "Update entity" << std::endl; - for (auto& component : components) { component->update(delta_time); } - rotate_y(delta_time * 10); + rotate_y(delta_time * 10); // TODO: Remove } template diff --git a/include/simpleengine/gfx/material.h b/include/simpleengine/gfx/material.h index 471286f..e28b496 100644 --- a/include/simpleengine/gfx/material.h +++ b/include/simpleengine/gfx/material.h @@ -15,7 +15,7 @@ namespace simpleengine::gfx { float shine; float reflectivity; - Material(Texture texture, float shine, float reflectivity, float specular_scalar, float ambient_scalar, float diffuse_scalar) : + Material(Texture texture, float shine = 1.f, float reflectivity = 0.f, float specular_scalar = 0.f, float ambient_scalar = 0.f, float diffuse_scalar = 0.f) : texture(texture), ambient_scalar(ambient_scalar), diffuse_scalar(diffuse_scalar), specular_scalar(specular_scalar), shine(shine), reflectivity(reflectivity) { diff --git a/include/simpleengine/gfx/mesh.h b/include/simpleengine/gfx/mesh.h new file mode 100644 index 0000000..a96ddc8 --- /dev/null +++ b/include/simpleengine/gfx/mesh.h @@ -0,0 +1,55 @@ +#pragma once + +#include "shader.h" +#include "../event/event.h" +#include "vao.h" +#include "vbo.h" +#include "../vertex.h" +#include "../renderable.h" +#include "../transformable.h" +#include "material.h" + +#include +#include + +namespace simpleengine::gfx { + /** + * @brief A Mesh is a object that will be shown on the screen by a renderer. + * + */ + class Mesh : public simpleengine::Event, public simpleengine::Transformable { + public: + std::optional material; + std::vector vertices; + std::vector indicies; + + gfx::VBO ebo; + gfx::VBO vbo; + gfx::VAO vao; + + Mesh(std::vector vertices, std::vector indicies, Material material); + Mesh(std::vector vertices, std::vector indicies = std::vector(), std::optional material = std::nullopt); + Mesh(std::vector vertices, std::vector indicies, Material material, gfx::VBO ebo, gfx::VBO vbo, gfx::VAO vao); + Mesh(Material material, std::string filename); + Mesh(Material material, std::ifstream file_stream); + + virtual void destroy() override; + + virtual void update(const float& delta_time) override; + + glm::vec3 compute_face_normal(const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& p3); + + /** + * @brief Calculate the normals of the model. + * + * @note This **will** overwrite the existing normals. + * + */ + void calculate_normals(); + + private: + void process_vertex(const std::vector& vertex_data, const std::vector& in_textures, + const std::vector& in_normals, std::vector& out_indicies, + std::vector& out_textures, std::vector& out_normals); + }; +} \ No newline at end of file diff --git a/include/simpleengine/gfx/model.h b/include/simpleengine/gfx/model.h index ac7bcdd..377cd24 100644 --- a/include/simpleengine/gfx/model.h +++ b/include/simpleengine/gfx/model.h @@ -1,55 +1,33 @@ #pragma once -#include "shader.h" -#include "../event/event.h" -#include "vao.h" -#include "vbo.h" -#include "../vertex.h" -#include "../renderable.h" -#include "../transformable.h" -#include "material.h" +#include "mesh.h" +#include "simpleengine/gfx/texture.h" -#include -#include +#include +#include +#include + +//#include namespace simpleengine::gfx { /** - * @brief A Model is a object that will be shown on the screen by a renderer. + * @brief A Model is a group of Meshes read from the 3D model file. + * + * The engine uses assimp, so all formats that it supports can be found here: + * https://github.com/assimp/assimp/blob/master/doc/Fileformats.md * */ - class Model : public simpleengine::Event, public simpleengine::Transformable { + class Model : public simpleengine::Transformable { + protected: + std::string model_directory; // May be needed public: - std::optional material; - std::vector vertices; - std::vector indicies; + std::vector meshes; - // Buffer objects - gfx::VBO ebo; - gfx::VBO vbo; - gfx::VAO vao; - - Model(std::vector vertices, std::vector indicies, Material material); - Model(std::vector vertices, std::vector indicies = std::vector(), std::optional material = std::nullopt); - Model(Material material, std::string filename); - Model(Material material, std::ifstream file_stream); - - virtual void destroy() override; - - virtual void update(const float& delta_time) override; - - glm::vec3 compute_face_normal(const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& p3); - - /** - * @brief Calculate the normals of the model. - * - * @note This **will** overwrite the existing normals. - * - */ - void calculate_normals(); - - private: - void process_vertex(const std::vector& vertex_data, const std::vector& in_textures, - const std::vector& in_normals, std::vector& out_indicies, - std::vector& out_textures, std::vector& out_normals); + Model(std::string file_path); + + void load_model(std::string path); + void process_node(aiNode* node, const aiScene* scene); + gfx::Mesh process_mesh(aiMesh* mesh, const aiScene* scene); + std::vector load_material_textures(aiMaterial* material, aiTextureType* type, std::string type_name); }; } \ No newline at end of file diff --git a/include/simpleengine/gfx/renderer.h b/include/simpleengine/gfx/renderer.h index 9e45b75..8ee23d7 100644 --- a/include/simpleengine/gfx/renderer.h +++ b/include/simpleengine/gfx/renderer.h @@ -5,6 +5,7 @@ #include "texture.h" #include "shader.h" //#include "renderable.h" +#include "mesh.h" #include "model.h" #include @@ -19,7 +20,7 @@ namespace simpleengine::gfx { class RenderingModel { public: std::shared_ptr entity; - std::unordered_map component_models; + std::unordered_map component_models; RenderingModel(std::shared_ptr entity) : entity(entity) { diff --git a/include/simpleengine/gfx/texture.h b/include/simpleengine/gfx/texture.h index 3fb2bd9..c956d38 100644 --- a/include/simpleengine/gfx/texture.h +++ b/include/simpleengine/gfx/texture.h @@ -19,10 +19,12 @@ namespace simpleengine::gfx { class Texture { private: - unsigned char* img_data; + unsigned char* img_data; // TODO Free this if its not used anymore unsigned int texture_id; - unsigned int image_type; + unsigned int image_type_gl; + + Texture() = default; public: /** * @brief The type of the texture @@ -36,8 +38,6 @@ namespace simpleengine::gfx { int height; int width; int channels; - float shine_damper = 1.f; - float reflectivity = 0.f; Type type; /** @@ -47,7 +47,7 @@ namespace simpleengine::gfx { * @param img_2d Whether or not the texture is 2D. * @param mipmap Whether or not to generate mipmaps for this texture. */ - Texture(const char* path, bool img_2d = true, bool mipmap = true); + Texture(const char* path, Type type = Type::TexT_DIFFUSE, bool img_2d = true, bool mipmap = true); /** * @brief Construct a new Texture object from the loaded file buffer. @@ -57,7 +57,7 @@ namespace simpleengine::gfx { * @param img_2d Whether or not the texture is 2D. * @param mipmap Whether or not to generate mipmaps for this texture. */ - Texture(const unsigned char *const buffer, int buffer_length, bool img_2d = true, bool mipmap = true); + Texture(const unsigned char *const buffer, int buffer_length, Type type = Type::TexT_DIFFUSE, bool img_2d = true, bool mipmap = true); /** * @brief Construct a new Texture object from the loaded file buffer. @@ -66,7 +66,9 @@ namespace simpleengine::gfx { * @param img_2d Whether or not the texture is 2D. * @param mipmap Whether or not to generate mipmaps for this texture. */ - Texture(std::vector buffer, bool img_2d = true, bool mipmap = true); + Texture(std::vector buffer, Type type = Type::TexT_DIFFUSE, bool img_2d = true, bool mipmap = true); + + static Texture white_texture(); void bind() const; void unbind() const; diff --git a/include/simpleengine/scene.h b/include/simpleengine/scene.h index 80931a4..ab24895 100644 --- a/include/simpleengine/scene.h +++ b/include/simpleengine/scene.h @@ -1,6 +1,6 @@ #pragma once -#include "gfx/model.h" +#include "gfx/mesh.h" #include "entity.h" #include "event/event.h" #include "renderable.h" diff --git a/resources/shaders/core/3d/fragment_core.glsl b/resources/shaders/core/3d/fragment_core.glsl index d134fa1..962e57b 100644 --- a/resources/shaders/core/3d/fragment_core.glsl +++ b/resources/shaders/core/3d/fragment_core.glsl @@ -37,7 +37,6 @@ void main() { vec3 final_specular = calculate_specular(unit_normal, shine_damper, reflectivity); fs_color = vec4(diffuse, 1.f) * texture(u_textures[id], vs_texcoord) + vec4(final_specular, 1.f); - //fs_color = texture(u_textures[1], vs_texcoord); } else { fs_color = vec4(vs_color, 1.f); // We don't add any reflectivity to solid colored vectors. } diff --git a/shell.nix b/shell.nix index 5a0ba1a..c9852e1 100644 --- a/shell.nix +++ b/shell.nix @@ -11,6 +11,7 @@ pkgs.mkShell { glew glfw glm + assimp (callPackage ./soil2.nix { }) ]; } \ No newline at end of file diff --git a/src/gfx/mesh.cpp b/src/gfx/mesh.cpp new file mode 100644 index 0000000..0119e15 --- /dev/null +++ b/src/gfx/mesh.cpp @@ -0,0 +1,167 @@ +#include "gfx/mesh.h" +#include + +namespace simpleengine::gfx { + Mesh::Mesh(std::vector vertices, std::vector indicies, Material material) : + material(std::make_optional(material)), vertices(vertices), indicies(indicies), + vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)), + vao(gfx::VAO::init()) { + + } + + Mesh::Mesh(std::vector vertices, std::vector indicies, std::optional material) : + material(material), vertices(vertices), indicies(indicies), + vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)), + vao(gfx::VAO::init()) { + + } + + Mesh::Mesh(std::vector vertices, std::vector indicies, Material material, gfx::VBO ebo, gfx::VBO vbo, gfx::VAO vao) : + vertices(vertices), indicies(indicies), material(material), ebo(ebo), vbo(vbo), vao(vao) { + + } + + Mesh::Mesh(Material material, std::string filename) : + Mesh(material, std::ifstream(filename, std::ios::in | std::ios::binary)) { + } + + std::vector split_string(std::string str, const char delim) { + std::istringstream ss(str); + + std::vector tokens; + size_t pos = 0; + std::string token; + while ((pos = str.find(delim)) != std::string::npos) { + token = str.substr(0, pos); + tokens.push_back(token); + str.erase(0, pos + 1); + } + tokens.push_back(str); + + return tokens; + } + + Mesh::Mesh(Material material, std::ifstream file_stream) : + vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)), + vao(gfx::VAO::init()), material(material) { + + if (!file_stream.is_open()) { + std::cerr << "File stream that was given to ObjModel::ObjModel is not open!" << std::endl; + throw std::runtime_error("Failed to open ObjModel model file"); + } + + // The vertices, texture coords, and normals that were read from the obj file + // these are not in a particular order. + std::vector obj_vertices; + std::vector obj_textures; + std::vector obj_normals; + + // The texture coords and normals that have been sorted. + std::vector textures; + std::vector normals; + + // Read the vertices, texture coords, and normals. Break when run into indices + std::string line; + while (std::getline(file_stream, line)) { + std::vector line_tokens = split_string(line, ' '); + + if (line_tokens.front() == "v") { + //glm::vec3 vertex(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); + obj_vertices.emplace_back(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); + } else if (line_tokens.front() == "vt") { + obj_textures.emplace_back(stof(line_tokens[1]), stof(line_tokens[2])); + } else if (line_tokens.front() == "vn") { + obj_normals.emplace_back(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); + } else if (line_tokens.front() == "f") { + auto size = obj_vertices.size(); + textures.resize(size); + normals.resize(size); + break; + } + } + + // Process the indicies. This will sort everything for storing inside of the Vertex list. + do { + if (!line.starts_with("f")) { + continue; + } + std::vector line_tokens = split_string(line, ' '); + std::vector vertex1 = split_string(line_tokens[1], '/'); + std::vector vertex2 = split_string(line_tokens[2], '/'); + std::vector vertex3 = split_string(line_tokens[3], '/'); + + process_vertex(vertex1, obj_textures, obj_normals, indicies, textures, normals); + process_vertex(vertex2, obj_textures, obj_normals, indicies, textures, normals); + process_vertex(vertex3, obj_textures, obj_normals, indicies, textures, normals); + } while (std::getline(file_stream, line)); + + file_stream.close(); + + const int texture_id = 0; + + std::cout << "Texture ID: " << texture_id << std::endl; + + // Insert everything into lit_vertices. + for (int i = 0; i < obj_vertices.size(); i++) { + vertices.emplace_back(simpleengine::Vectorf(obj_vertices.at(i)), glm::vec3(1.f), textures.at(i), normals.at(i), texture_id); + } + } + + void Mesh::process_vertex(const std::vector& vertex_data, const std::vector& in_textures, + const std::vector& in_normals, std::vector& out_indicies, + std::vector& out_textures, std::vector& out_normals) { + + // Get the index the current vertex and put it in indicies + int currentVertexIndex = stoi(vertex_data[0]) - 1; + out_indicies.push_back(currentVertexIndex); + + // Read texture coords + glm::vec2 current_tex = in_textures.at(stoi(vertex_data[1]) - 1); + current_tex.y = 1 - current_tex.y; + out_textures.at(currentVertexIndex) = current_tex; + + // Read normals + glm::vec3 current_norm = in_normals.at(stoi(vertex_data[2]) - 1); + out_normals.at(currentVertexIndex) = current_norm; + } + + void Mesh::destroy() { + this->ebo.destroy(); + this->vbo.destroy(); + this->vao.destroy(); + } + + void Mesh::update(const float& delta_time) { + this->rotate_y(1.f); + } + + glm::vec3 Mesh::compute_face_normal(const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& p3) { + // Uses p2 as a new origin for p1,p3 + auto a = p3 - p2; + auto b = p1 - p2; + + // Compute the cross product a X b to get the face normal + return glm::normalize(glm::cross(a, b)); + } + + void Mesh::calculate_normals() { + std::vector normals = std::vector(vertices.size()); + + for (int i = 0; i < indicies.size(); i+=3) { + const glm::vec3& a = vertices[indicies[i]].position; + const glm::vec3& b = vertices[indicies[i + 1]].position; + const glm::vec3& c = vertices[indicies[i + 2]].position; + glm::vec3 normal = compute_face_normal(a, b, c); + + normals[indicies[i]] += normal; + normals[indicies[i + 1]] += normal; + normals[indicies[i + 2]] += normal; + } + + for (int i = 0; i < normals.size(); i++) { + normals[i] = glm::normalize(normals[i]); + + vertices[i].normal = normals[i]; + } + } +} \ No newline at end of file diff --git a/src/gfx/model.cpp b/src/gfx/model.cpp index 0f35527..38ac258 100644 --- a/src/gfx/model.cpp +++ b/src/gfx/model.cpp @@ -1,163 +1,114 @@ #include "gfx/model.h" +#include "gfx/material.h" +#include "gfx/texture.h" +#include "vector.h" + +#include +#include +#include +#include #include namespace simpleengine::gfx { - Model::Model(std::vector vertices, std::vector indicies, Material material) : - material(std::make_optional(material)), vertices(vertices), indicies(indicies), - vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)), - vao(gfx::VAO::init()) { - + Model::Model(std::string file_path) { + load_model(file_path); } - Model::Model(std::vector vertices, std::vector indicies, std::optional material) : - material(material), vertices(vertices), indicies(indicies), - vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)), - vao(gfx::VAO::init()) { + void Model::load_model(std::string path) { + Assimp::Importer importer; - } + // assimp post processing options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html + const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); - Model::Model(Material material,std::string filename) : - Model(material, std::ifstream(filename, std::ios::in | std::ios::binary)) { - - } - - std::vector split_string(std::string str, const char delim) { - std::istringstream ss(str); - - std::vector tokens; - size_t pos = 0; - std::string token; - while ((pos = str.find(delim)) != std::string::npos) { - token = str.substr(0, pos); - tokens.push_back(token); - str.erase(0, pos + 1); - } - tokens.push_back(str); - - return tokens; - } - - Model::Model(Material material, std::ifstream file_stream) : - vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)), - vao(gfx::VAO::init()), material(material) { - - if (!file_stream.is_open()) { - std::cerr << "File stream that was given to ObjModel::ObjModel is not open!" << std::endl; - throw std::runtime_error("Failed to open ObjModel model file"); + if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { + std::cout << "ERROR::ASSIMP::" << importer.GetErrorString() << std::endl; + return; } - // The vertices, texture coords, and normals that were read from the obj file - // these are not in a particular order. - std::vector obj_vertices; - std::vector obj_textures; - std::vector obj_normals; + model_directory = path.substr(0, path.find_last_of('/')); - // The texture coords and normals that have been sorted. - std::vector textures; - std::vector normals; + process_node(scene->mRootNode, scene); + } - // Read the vertices, texture coords, and normals. Break when run into indices - std::string line; - while (std::getline(file_stream, line)) { - std::vector line_tokens = split_string(line, ' '); + void Model::process_node(aiNode* node, const aiScene* scene) { + // process all the node's meshes (if any) + for (int i = 0; i < node->mNumMeshes; i++) { + aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; + meshes.push_back(process_mesh(mesh, scene)); + } - if (line_tokens.front() == "v") { - //glm::vec3 vertex(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); - obj_vertices.emplace_back(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); - } else if (line_tokens.front() == "vt") { - obj_textures.emplace_back(stof(line_tokens[1]), stof(line_tokens[2])); - } else if (line_tokens.front() == "vn") { - obj_normals.emplace_back(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); - } else if (line_tokens.front() == "f") { - auto size = obj_vertices.size(); - textures.resize(size); - normals.resize(size); - break; + // then do the same for each of its children + for (int i = 0; i < node->mNumChildren; i++) { + process_node(node->mChildren[i], scene); + } + } + + gfx::Mesh Model::process_mesh(aiMesh* mesh, const aiScene* scene) { + std::vector vertices; + std::vector indices; + std::vector textures; + + for(unsigned int i = 0; i < mesh->mNumVertices; i++) { + LitVertex vertex; + vertex.color = glm::vec3(1.f); + vertex.texture_id = 0; + + simpleengine::Vectorf position(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z); + vertex.position = position; + + glm::vec3 normal(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z); + vertex.normal = normal; + + if(mesh->mTextureCoords[0]) { + glm::vec2 tex_coord(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y); + + vertex.tex_coord = tex_coord; + } + + vertices.push_back(vertex); + } + + // Process indices + for (int i = 0; i < mesh->mNumFaces; i++) { + aiFace face = mesh->mFaces[i]; + + for (int j = 0; j < face.mNumIndices; j++) { + indices.push_back(face.mIndices[j]); } } - // Process the indicies. This will sort everything for storing inside of the Vertex list. - do { - if (!line.starts_with("f")) { - continue; - } - std::vector line_tokens = split_string(line, ' '); - std::vector vertex1 = split_string(line_tokens[1], '/'); - std::vector vertex2 = split_string(line_tokens[2], '/'); - std::vector vertex3 = split_string(line_tokens[3], '/'); + std::optional op_mat; + + // TODO: Process material + if(mesh->mMaterialIndex >= 0) { + std::cout << "TODO: Process model materials!" << std::endl; + + /* aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex]; + std::vector diffuseMaps = load_material_textures(material, + aiTextureType_DIFFUSE, "texture_diffuse"); + + textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); - process_vertex(vertex1, obj_textures, obj_normals, indicies, textures, normals); - process_vertex(vertex2, obj_textures, obj_normals, indicies, textures, normals); - process_vertex(vertex3, obj_textures, obj_normals, indicies, textures, normals); - } while (std::getline(file_stream, line)); - - file_stream.close(); - - const int texture_id = 0; - - std::cout << "Texture ID: " << texture_id << std::endl; - - // Insert everything into lit_vertices. - for (int i = 0; i < obj_vertices.size(); i++) { - vertices.emplace_back(simpleengine::Vectorf(obj_vertices.at(i)), glm::vec3(1.f), textures.at(i), normals.at(i), texture_id); - } - } - - void Model::process_vertex(const std::vector& vertex_data, const std::vector& in_textures, - const std::vector& in_normals, std::vector& out_indicies, - std::vector& out_textures, std::vector& out_normals) { - - // Get the index the current vertex and put it in indicies - int currentVertexIndex = stoi(vertex_data[0]) - 1; - out_indicies.push_back(currentVertexIndex); - - // Read texture coords - glm::vec2 current_tex = in_textures.at(stoi(vertex_data[1]) - 1); - current_tex.y = 1 - current_tex.y; - out_textures.at(currentVertexIndex) = current_tex; - - // Read normals - glm::vec3 current_norm = in_normals.at(stoi(vertex_data[2]) - 1); - out_normals.at(currentVertexIndex) = current_norm; - } - - void Model::destroy() { - this->ebo.destroy(); - this->vbo.destroy(); - this->vao.destroy(); - } - - void Model::update(const float& delta_time) { - this->rotate_y(1.f); - } - - glm::vec3 Model::compute_face_normal(const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& p3) { - // Uses p2 as a new origin for p1,p3 - auto a = p3 - p2; - auto b = p1 - p2; - - // Compute the cross product a X b to get the face normal - return glm::normalize(glm::cross(a, b)); - } - - void Model::calculate_normals() { - std::vector normals = std::vector(vertices.size()); - - for (int i = 0; i < indicies.size(); i+=3) { - const glm::vec3& a = vertices[indicies[i]].position; - const glm::vec3& b = vertices[indicies[i + 1]].position; - const glm::vec3& c = vertices[indicies[i + 2]].position; - glm::vec3 normal = compute_face_normal(a, b, c); - - normals[indicies[i]] += normal; - normals[indicies[i + 1]] += normal; - normals[indicies[i + 2]] += normal; + std::vector specularMaps = load_material_textures(material, + aiTextureType_SPECULAR, "texture_specular"); + textures.insert(textures.end(), specularMaps.begin(), specularMaps.end()); */ } - for (int i = 0; i < normals.size(); i++) { - normals[i] = glm::normalize(normals[i]); + // TODO: After we start processing materials, this can be put in the else statement as a fallback. - vertices[i].normal = normals[i]; - } + auto white_texture = gfx::Texture::white_texture(); + //gfx::Material mat(white_texture); + + //gfx::Texture white_texture("examples/dev_testing/resources/white_texture.png"); + gfx::Material mat(white_texture, 1.f, 0.f, 0.f, 0.f, 0.f); + + op_mat = std::optional(mat); + + //return Mesh(vertices, indices, textures); + return Mesh(vertices, indices, op_mat); } -} \ No newline at end of file + + std::vector Model::load_material_textures(aiMaterial* material, aiTextureType* type, std::string type_name) { + + } +} // namespace simpleengine::gfx \ No newline at end of file diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index 6f14c22..8b2627b 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -1,52 +1,17 @@ #include "gfx/renderer.h" #include "ecs/component/component.h" #include "ecs/entity.h" -#include "gfx/model.h" +#include "gfx/mesh.h" #include "gfx/vao.h" #include "renderable.h" -#include "ecs/component/model_componenet.h" +#include "ecs/component/mesh_component.h" +#include "ecs/component/model_component.h" #include namespace simpleengine::gfx { - void Renderer::RenderingModel::update_buffers() { - if (std::shared_ptr comp = entity->get_component()) { - auto iter = component_models.find(comp->get_handle()); - if (iter == component_models.end()) { - std::cout << "Enabling buffer attributes for ModelComponent (" << comp->get_handle() << ")..." << std::endl; - - //iter->second = comp->model; - gfx::Model& model = comp->model; - gfx::VBO& vbo = model.vbo; - gfx::VBO& ebo = model.ebo; - gfx::VAO& vao = model.vao; - - vao.bind(); - vbo.buffer(model.vertices.data(), 0, sizeof(LitVertex) * model.vertices.size()); - - if (!model.indicies.empty()) { - ebo.buffer(model.indicies.data(), 0, model.indicies.size() * sizeof(GLuint)); - } - - // Enable VAO attributes - vao.enable_attrib(vbo, 0, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, position), false); - vao.enable_attrib(vbo, 1, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, color), false); - vao.enable_attrib(vbo, 2, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, normal), false); - vao.enable_attrib(vbo, 3, 2, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, tex_coord), false); - vao.enable_attrib(vbo, 4, 1, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, texture_id), false); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - component_models.emplace(comp->get_handle(), model); - - std::cout << "Enabled all buffer attributes for ModelComponent" << std::endl; - } else { - std::cout << "Already exists" << std::endl; - } - } - } + void create_mesh_buffers(std::shared_ptr comp, simpleengine::gfx::Mesh& mesh); void Renderer::RenderingModel::destroy_buffers() { std::cout << "Destroying entity models..." << std::endl; @@ -119,13 +84,13 @@ namespace simpleengine::gfx { shader.use(); for (auto& [handle, rendering] : rendering_models) { - if (rendering.component_models.size() > 0) { + if (rendering.component_models.size() >= 0) { std::shared_ptr& entity = rendering.entity; shader.set_uniform_matrix_4f("transform_matrix", entity->transform_matrix, false); - + for (const auto& pair : rendering.component_models) { - Model& model = pair.second; + Mesh& model = pair.second; std::optional& material = model.material; shader.set_uniform_int("u_textures", 0, false); @@ -151,4 +116,64 @@ namespace simpleengine::gfx { shader.unuse(); } + + void Renderer::RenderingModel::update_buffers() { + if (entity->has_component()) { + std::shared_ptr comp = entity->get_component(); + auto iter = component_models.find(comp->get_handle()); + if (iter == component_models.end()) { + std::cout << "Enabling buffer attributes for MeshComponent (" << comp->get_handle() << ")..." << std::endl; + + //iter->second = comp->model; + gfx::Mesh& mesh = comp->model; + create_mesh_buffers(comp, mesh); + component_models.emplace(comp->get_handle(), mesh); + + std::cout << "Enabled all buffer attributes for MeshComponent" << std::endl; + } else { + std::cout << "Already exists" << std::endl; + } + } else if (entity->has_component()) { + std::shared_ptr comp = entity->get_component(); + + auto iter = component_models.find(comp->get_handle()); + if (iter == component_models.end()) { + std::cout << "Enabling buffer attributes for ModelComponent (" << comp->get_handle() << ")..." << std::endl; + + // Store all the model's meshes + for (auto& mesh : comp->model.meshes) { + create_mesh_buffers(comp, mesh); + + component_models.emplace(comp->get_handle(), mesh); + } + + std::cout << "Enabled all buffer attributes for ModelComponent" << std::endl; + } else { + std::cout << "Already exists" << std::endl; + } + } + } + + void create_mesh_buffers(std::shared_ptr comp, gfx::Mesh& mesh) { + gfx::VBO& vbo = mesh.vbo; + gfx::VBO& ebo = mesh.ebo; + gfx::VAO& vao = mesh.vao; + + vao.bind(); + vbo.buffer(mesh.vertices.data(), 0, sizeof(LitVertex) * mesh.vertices.size()); + + if (!mesh.indicies.empty()) { + ebo.buffer(mesh.indicies.data(), 0, mesh.indicies.size() * sizeof(GLuint)); + } + + // Enable VAO attributes + vao.enable_attrib(vbo, 0, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, position), false); + vao.enable_attrib(vbo, 1, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, color), false); + vao.enable_attrib(vbo, 2, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, normal), false); + vao.enable_attrib(vbo, 3, 2, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, tex_coord), false); + vao.enable_attrib(vbo, 4, 1, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, texture_id), false); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + } } \ No newline at end of file diff --git a/src/gfx/texture.cpp b/src/gfx/texture.cpp index 1a7294f..dd119dc 100644 --- a/src/gfx/texture.cpp +++ b/src/gfx/texture.cpp @@ -4,16 +4,18 @@ #include namespace simpleengine::gfx { - Texture::Texture(const char* path, bool img_2d, bool mipmap) { - image_type = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; + Texture::Texture(const char* path, Type type, bool img_2d, bool mipmap): type(type) { + image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; glGenTextures(1, &texture_id); bind(); - glTexParameteri(image_type, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(image_type, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(image_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(image_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + int linear_param = mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; + + glTexParameteri(image_type_gl, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(image_type_gl, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param); + glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param); // Read 4 channels (RGBA) img_data = stbi_load(path, &width, &height, &channels, 4); @@ -24,33 +26,27 @@ namespace simpleengine::gfx { } std::cout << "Loaded image with a width of " << width << "px, a height of " << height << "px and " << channels << " channels" << std::endl; - glTexImage2D(image_type, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data); + glTexImage2D(image_type_gl, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data); if (mipmap) { - glGenerateMipmap(image_type); + glGenerateMipmap(image_type_gl); } unbind(); } - /** - * @brief Construct a new Texture object from the loaded file buffer. - * - * @param buffer The bytes of the loaded file. - * @param buffer_length The length of the buffer. - * @param img_2d Whether or not the texture is 2D. - * @param mipmap Whether or not to generate mipmaps for this texture. - */ - Texture::Texture(const unsigned char *const buffer, int buffer_length, bool img_2d, bool mipmap) { - image_type = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; + Texture::Texture(const unsigned char *const buffer, int buffer_length, Type type, bool img_2d, bool mipmap): type(type) { + image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; glGenTextures(1, &texture_id); bind(); - glTexParameteri(image_type, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(image_type, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(image_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(image_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + int linear_param = mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; + + glTexParameteri(image_type_gl, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(image_type_gl, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param); + glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param); // Read 4 channels (RGBA) img_data = stbi_load_from_memory(buffer, buffer_length, &width, &height, &channels, 4); @@ -61,33 +57,61 @@ namespace simpleengine::gfx { } std::cout << "Loaded image with a width of " << width << "px, a height of " << height << "px and " << channels << " channels" << std::endl; - glTexImage2D(image_type, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data); + glTexImage2D(image_type_gl, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data); if (mipmap) { - glGenerateMipmap(image_type); + glGenerateMipmap(image_type_gl); } unbind(); } - /** - * @brief Construct a new Texture object from the loaded file buffer. - * - * @param buffer The bytes of the loaded file. - * @param img_2d Whether or not the texture is 2D. - * @param mipmap Whether or not to generate mipmaps for this texture. - */ - Texture::Texture(std::vector buffer, bool img_2d, bool mipmap) : - Texture(buffer.data(), buffer.size(), img_2d, mipmap) { + Texture::Texture(std::vector buffer, Type type, bool img_2d, bool mipmap) : + Texture(buffer.data(), buffer.size(), type, img_2d, mipmap) { } + Texture Texture::white_texture() { + // Create the texture + int width = 128, height = 128; + int size = width * height * sizeof(unsigned char) * 4; + unsigned char* data = (unsigned char*) malloc(size); + + for(int i = 0; i < size; i++) { + data[i] = 255; + } + + Texture texture; + texture.image_type_gl = GL_TEXTURE_2D; + texture.width = width; + texture.height = height; + texture.channels = 4; + texture.type = Texture::Type::TexT_DIFFUSE; + texture.img_data = data; + + glGenTextures(1, &texture.texture_id); + texture.bind(); + + 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_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.img_data); + + texture.unbind(); + + + + return texture; + } + void Texture::bind() const { - glBindTexture(image_type, texture_id); + glBindTexture(image_type_gl, texture_id); } void Texture::unbind() const { - glBindTexture(image_type, 0); + glBindTexture(image_type_gl, 0); } unsigned int Texture::get_texture_id() const {