Use assimp for loading 3d models
This commit is contained in:
parent
96ac056a5d
commit
5a7e5cd10f
|
@ -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
|
||||
...
|
||||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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})
|
|
@ -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)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#include "simpleengine/camera.h"
|
||||
#include "simpleengine/ecs/component/model_componenet.h"
|
||||
#include "simpleengine/ecs/component/mesh_component.h"
|
||||
#include <simpleengine/ecs/component/model_component.h>
|
||||
#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 <simpleengine/game.h>
|
||||
#include <simpleengine/vertex.h>
|
||||
#include <simpleengine/gfx/shaders/core_3d_shader.h>
|
||||
#include <simpleengine/gfx/model.h>
|
||||
|
||||
//#include <simpleengine/scene.h>
|
||||
|
||||
|
@ -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<simpleengine::Entity>();
|
||||
entity->add_component<se::ModelComponent>(cube_vertices, cube_indicies, material, true);
|
||||
entity->add_component<se::MeshComponent>(cube_vertices, cube_indicies, material, true);
|
||||
entity->translate(3.5f, 0.f, 0.f); */
|
||||
|
||||
//auto entity = std::make_shared<se::gfx::M>(game.get_window(), core_shader, white_texture, "examples/dev_testing/resources/dragon.obj");
|
||||
auto entity = std::make_shared<simpleengine::Entity>();
|
||||
se::gfx::Model model(material, "examples/dev_testing/resources/dragon.obj");
|
||||
entity->add_component<se::ModelComponent>(model);
|
||||
entity->add_component<se::ModelComponent>("examples/dev_testing/resources/dragon.obj");
|
||||
entity->translate(12.f, -4.f, 0.f);
|
||||
|
||||
// Create a renderer and submit the entity into it.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../gfx/model.h"
|
||||
#include "../../gfx/mesh.h"
|
||||
#include "../../event/event.h"
|
||||
|
||||
#include <iostream>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "component.h"
|
||||
#include "../../gfx/model.h"
|
||||
#include "../../gfx/mesh.h"
|
||||
#include "../../gfx/material.h"
|
||||
|
||||
#include <iostream>
|
||||
|
@ -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<LitVertex> vertices, std::vector<GLuint> indicies, gfx::Material material,
|
||||
MeshComponent(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, gfx::Material material,
|
||||
bool calculate_normals = false): model(vertices, indicies, material) {
|
||||
|
||||
if (calculate_normals) {
|
||||
|
@ -29,7 +29,7 @@ namespace simpleengine {
|
|||
}
|
||||
}
|
||||
|
||||
ModelComponent(std::vector<LitVertex> vertices, std::vector<GLuint> indicies = std::vector<GLuint>(),
|
||||
MeshComponent(std::vector<LitVertex> vertices, std::vector<GLuint> indicies = std::vector<GLuint>(),
|
||||
std::optional<gfx::Material> 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;
|
||||
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "component.h"
|
||||
#include "../../gfx/model.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
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 {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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<typename T>
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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 <optional>
|
||||
#include <vector>
|
||||
|
||||
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> material;
|
||||
std::vector<LitVertex> vertices;
|
||||
std::vector<GLuint> indicies;
|
||||
|
||||
gfx::VBO ebo;
|
||||
gfx::VBO vbo;
|
||||
gfx::VAO vao;
|
||||
|
||||
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material);
|
||||
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> indicies = std::vector<GLuint>(), std::optional<Material> material = std::nullopt);
|
||||
Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> 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<std::string>& vertex_data, const std::vector<glm::vec2>& in_textures,
|
||||
const std::vector<glm::vec3>& in_normals, std::vector<GLuint>& out_indicies,
|
||||
std::vector<glm::vec2>& out_textures, std::vector<glm::vec3>& out_normals);
|
||||
};
|
||||
}
|
|
@ -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 <optional>
|
||||
#include <vector>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/scene.h>
|
||||
|
||||
//#include <assimp/mesh.h>
|
||||
|
||||
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> material;
|
||||
std::vector<LitVertex> vertices;
|
||||
std::vector<GLuint> indicies;
|
||||
std::vector<gfx::Mesh> meshes;
|
||||
|
||||
// Buffer objects
|
||||
gfx::VBO ebo;
|
||||
gfx::VBO vbo;
|
||||
gfx::VAO vao;
|
||||
Model(std::string file_path);
|
||||
|
||||
Model(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material);
|
||||
Model(std::vector<LitVertex> vertices, std::vector<GLuint> indicies = std::vector<GLuint>(), std::optional<Material> 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<std::string>& vertex_data, const std::vector<glm::vec2>& in_textures,
|
||||
const std::vector<glm::vec3>& in_normals, std::vector<GLuint>& out_indicies,
|
||||
std::vector<glm::vec2>& out_textures, std::vector<glm::vec3>& out_normals);
|
||||
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<Texture> load_material_textures(aiMaterial* material, aiTextureType* type, std::string type_name);
|
||||
};
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
#include "texture.h"
|
||||
#include "shader.h"
|
||||
//#include "renderable.h"
|
||||
#include "mesh.h"
|
||||
#include "model.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
@ -19,7 +20,7 @@ namespace simpleengine::gfx {
|
|||
class RenderingModel {
|
||||
public:
|
||||
std::shared_ptr<simpleengine::Entity> entity;
|
||||
std::unordered_map<uint32_t, gfx::Model&> component_models;
|
||||
std::unordered_map<uint32_t, gfx::Mesh&> component_models;
|
||||
|
||||
RenderingModel(std::shared_ptr<simpleengine::Entity> entity) : entity(entity) {
|
||||
|
||||
|
|
|
@ -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<unsigned char> buffer, bool img_2d = true, bool mipmap = true);
|
||||
Texture(std::vector<unsigned char> buffer, Type type = Type::TexT_DIFFUSE, bool img_2d = true, bool mipmap = true);
|
||||
|
||||
static Texture white_texture();
|
||||
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "gfx/model.h"
|
||||
#include "gfx/mesh.h"
|
||||
#include "entity.h"
|
||||
#include "event/event.h"
|
||||
#include "renderable.h"
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ pkgs.mkShell {
|
|||
glew
|
||||
glfw
|
||||
glm
|
||||
assimp
|
||||
(callPackage ./soil2.nix { })
|
||||
];
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
#include "gfx/mesh.h"
|
||||
#include <optional>
|
||||
|
||||
namespace simpleengine::gfx {
|
||||
Mesh::Mesh(std::vector<LitVertex> vertices, std::vector<GLuint> 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<LitVertex> vertices, std::vector<GLuint> indicies, std::optional<Material> 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<LitVertex> vertices, std::vector<GLuint> 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<std::string> split_string(std::string str, const char delim) {
|
||||
std::istringstream ss(str);
|
||||
|
||||
std::vector<std::string> 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<glm::vec3> obj_vertices;
|
||||
std::vector<glm::vec2> obj_textures;
|
||||
std::vector<glm::vec3> obj_normals;
|
||||
|
||||
// The texture coords and normals that have been sorted.
|
||||
std::vector<glm::vec2> textures;
|
||||
std::vector<glm::vec3> normals;
|
||||
|
||||
// Read the vertices, texture coords, and normals. Break when run into indices
|
||||
std::string line;
|
||||
while (std::getline(file_stream, line)) {
|
||||
std::vector<std::string> 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<std::string> line_tokens = split_string(line, ' ');
|
||||
std::vector<std::string> vertex1 = split_string(line_tokens[1], '/');
|
||||
std::vector<std::string> vertex2 = split_string(line_tokens[2], '/');
|
||||
std::vector<std::string> 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<std::string>& vertex_data, const std::vector<glm::vec2>& in_textures,
|
||||
const std::vector<glm::vec3>& in_normals, std::vector<GLuint>& out_indicies,
|
||||
std::vector<glm::vec2>& out_textures, std::vector<glm::vec3>& 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<glm::vec3> normals = std::vector<glm::vec3>(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];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,163 +1,114 @@
|
|||
#include "gfx/model.h"
|
||||
#include "gfx/material.h"
|
||||
#include "gfx/texture.h"
|
||||
#include "vector.h"
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <optional>
|
||||
|
||||
namespace simpleengine::gfx {
|
||||
Model::Model(std::vector<LitVertex> vertices, std::vector<GLuint> 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<LitVertex> vertices, std::vector<GLuint> indicies, std::optional<Material> 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<std::string> split_string(std::string str, const char delim) {
|
||||
std::istringstream ss(str);
|
||||
|
||||
std::vector<std::string> 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<glm::vec3> obj_vertices;
|
||||
std::vector<glm::vec2> obj_textures;
|
||||
std::vector<glm::vec3> obj_normals;
|
||||
model_directory = path.substr(0, path.find_last_of('/'));
|
||||
|
||||
// The texture coords and normals that have been sorted.
|
||||
std::vector<glm::vec2> textures;
|
||||
std::vector<glm::vec3> 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<std::string> 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<LitVertex> vertices;
|
||||
std::vector<unsigned int> indices;
|
||||
std::vector<Texture> 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<std::string> line_tokens = split_string(line, ' ');
|
||||
std::vector<std::string> vertex1 = split_string(line_tokens[1], '/');
|
||||
std::vector<std::string> vertex2 = split_string(line_tokens[2], '/');
|
||||
std::vector<std::string> vertex3 = split_string(line_tokens[3], '/');
|
||||
std::optional<gfx::Material> op_mat;
|
||||
|
||||
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));
|
||||
// TODO: Process material
|
||||
if(mesh->mMaterialIndex >= 0) {
|
||||
std::cout << "TODO: Process model materials!" << std::endl;
|
||||
|
||||
file_stream.close();
|
||||
/* aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
|
||||
std::vector<Texture> diffuseMaps = load_material_textures(material,
|
||||
aiTextureType_DIFFUSE, "texture_diffuse");
|
||||
|
||||
const int texture_id = 0;
|
||||
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
|
||||
|
||||
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<std::string>& vertex_data, const std::vector<glm::vec2>& in_textures,
|
||||
const std::vector<glm::vec3>& in_normals, std::vector<GLuint>& out_indicies,
|
||||
std::vector<glm::vec2>& out_textures, std::vector<glm::vec3>& 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<glm::vec3> normals = std::vector<glm::vec3>(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<Texture> 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<gfx::Material>(mat);
|
||||
|
||||
//return Mesh(vertices, indices, textures);
|
||||
return Mesh(vertices, indices, op_mat);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Texture> Model::load_material_textures(aiMaterial* material, aiTextureType* type, std::string type_name) {
|
||||
|
||||
}
|
||||
} // namespace simpleengine::gfx
|
|
@ -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 <algorithm>
|
||||
|
||||
namespace simpleengine::gfx {
|
||||
void Renderer::RenderingModel::update_buffers() {
|
||||
if (std::shared_ptr<ModelComponent> comp = entity->get_component<simpleengine::ModelComponent>()) {
|
||||
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<simpleengine::Component> 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>& 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>& 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<simpleengine::MeshComponent>()) {
|
||||
std::shared_ptr<MeshComponent> comp = entity->get_component<simpleengine::MeshComponent>();
|
||||
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<simpleengine::ModelComponent>()) {
|
||||
std::shared_ptr<ModelComponent> comp = entity->get_component<simpleengine::ModelComponent>();
|
||||
|
||||
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<Component> 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);
|
||||
}
|
||||
}
|
|
@ -4,16 +4,18 @@
|
|||
#include <stb_image.h>
|
||||
|
||||
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<unsigned char> buffer, bool img_2d, bool mipmap) :
|
||||
Texture(buffer.data(), buffer.size(), img_2d, mipmap) {
|
||||
Texture::Texture(std::vector<unsigned char> 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 {
|
||||
|
|
Loading…
Reference in New Issue