Initial commit
This commit is contained in:
commit
d1a99961b1
15
.gitignore
vendored
Executable file
15
.gitignore
vendored
Executable file
@ -0,0 +1,15 @@
|
||||
*.vcxproj
|
||||
*.vcxproj.filters
|
||||
*.vcxproj.user
|
||||
*.sln
|
||||
*.dbscn
|
||||
*.make
|
||||
*.code-workspace
|
||||
Makefile
|
||||
|
||||
.vscode/
|
||||
bin/
|
||||
/vendor/premake-core/
|
||||
.vs/
|
||||
AS_DEBUG/
|
||||
Tasks/
|
22
Build-Service.lua
Executable file
22
Build-Service.lua
Executable file
@ -0,0 +1,22 @@
|
||||
require("premakeExtensions/premake-vscode")
|
||||
|
||||
workspace "Deer"
|
||||
architecture "x64"
|
||||
configurations { "Debug", "Release", "Dist" }
|
||||
startproject "App"
|
||||
|
||||
|
||||
OutputDir = "%{cfg.system}-%{cfg.architecture}/%{cfg.buildcfg}"
|
||||
|
||||
group "core"
|
||||
include "Deer/Build-Service.lua"
|
||||
group ""
|
||||
|
||||
group "external"
|
||||
include "Deer/vendor/spdlog/Build.lua"
|
||||
include "Deer/vendor/angelScript/Build.lua"
|
||||
group ""
|
||||
|
||||
group "Runtime"
|
||||
include "DeerServer/Build.lua"
|
||||
group ""
|
57
Deer/Build-Service.lua
Normal file
57
Deer/Build-Service.lua
Normal file
@ -0,0 +1,57 @@
|
||||
project "DeerService"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
cppdialect "C++20"
|
||||
targetdir "bin/%{cfg.buildcfg}"
|
||||
staticruntime "off"
|
||||
|
||||
|
||||
files {
|
||||
"src/Deer/**.h",
|
||||
"src/Deer/**.cpp"
|
||||
}
|
||||
includedirs
|
||||
{
|
||||
"src",
|
||||
"Include",
|
||||
"vendor/spdlog/include",
|
||||
"vendor/glm",
|
||||
"vendor/entt/include",
|
||||
"vendor/cereal/include",
|
||||
"vendor/angelScript/include"
|
||||
}
|
||||
|
||||
targetdir ("../bin/" .. OutputDir .. "/%{prj.name}")
|
||||
objdir ("../bin/int/" .. OutputDir .. "/%{prj.name}")
|
||||
|
||||
filter "system:windows"
|
||||
systemversion "latest"
|
||||
defines { "WINDOWS"}
|
||||
defines { }
|
||||
|
||||
filter "system:linux"
|
||||
toolset "clang"
|
||||
buildoptions { "-std=c++20" }
|
||||
defines { "LINUX"}
|
||||
files {
|
||||
"src/Plattform/linux/**.h",
|
||||
"src/Plattform/linux/**.cpp"
|
||||
}
|
||||
|
||||
|
||||
filter "configurations:Debug"
|
||||
defines { "DEBUG" }
|
||||
runtime "Debug"
|
||||
symbols "On"
|
||||
|
||||
filter "configurations:Release"
|
||||
defines { "RELEASE" }
|
||||
runtime "Release"
|
||||
optimize "On"
|
||||
symbols "On"
|
||||
|
||||
filter "configurations:Dist"
|
||||
defines { "DIST" }
|
||||
runtime "Release"
|
||||
optimize "On"
|
||||
symbols "Off"
|
112
Deer/Build.lua
Executable file
112
Deer/Build.lua
Executable file
@ -0,0 +1,112 @@
|
||||
project "Deer"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
cppdialect "C++20"
|
||||
targetdir "bin/%{cfg.buildcfg}"
|
||||
staticruntime "off"
|
||||
|
||||
files {
|
||||
"src/Deer/**.h",
|
||||
"src/Deer/**.cpp",
|
||||
"src/DeerRender/**.h",
|
||||
"src/DeerRender/**.cpp",
|
||||
"src/Plattform/OpenGL/**.h",
|
||||
"src/Plattform/OpenGL/**.cpp",
|
||||
"src/Plattform/ImGUI/**.h",
|
||||
"src/Plattform/ImGUI/**.cpp",
|
||||
"vendor/ImGuizmo/**.cpp",
|
||||
"vendor/stb/stb_image.cpp"
|
||||
}
|
||||
|
||||
links { "spdlog", "GLFW", "glad", "ImGui", "angelScript" }
|
||||
defines { "DEER_RENDER" }
|
||||
|
||||
includedirs
|
||||
{
|
||||
"src",
|
||||
"Include",
|
||||
"vendor/spdlog/include",
|
||||
"vendor/GLFW/include",
|
||||
"vendor/glad/include",
|
||||
"vendor/imgui",
|
||||
"vendor/glm",
|
||||
"vendor/stb",
|
||||
"vendor/ImGuizmo",
|
||||
"vendor/entt/include",
|
||||
"vendor/cereal/include",
|
||||
"vendor/objload/include/objload",
|
||||
"vendor/angelScript/include"
|
||||
}
|
||||
|
||||
targetdir ("../bin/" .. OutputDir .. "/%{prj.name}")
|
||||
objdir ("../bin/int/" .. OutputDir .. "/%{prj.name}")
|
||||
|
||||
filter "system:windows"
|
||||
systemversion "latest"
|
||||
defines {"WINDOWS"}
|
||||
files {
|
||||
"src/Plattform/windows/**.h",
|
||||
"src/Plattform/windows/**.cpp"
|
||||
}
|
||||
|
||||
filter "system:linux"
|
||||
toolset "clang"
|
||||
defines {"LINUX"}
|
||||
buildoptions { "-std=c++20" }
|
||||
|
||||
local gtk_libs = os.outputof("pkg-config --libs gtk+-3.0")
|
||||
|
||||
links { "GL" }
|
||||
-- Files for GTK
|
||||
includedirs {
|
||||
"/usr/include/gtk-3.0", -- GTK3 headers
|
||||
"/usr/include/gdk-pixbuf-2.0", -- GDK Pixbuf headers
|
||||
"/usr/include/cairo", -- Cairo graphics library headers
|
||||
"/usr/include/pango-1.0", -- Pango text layout and rendering headers
|
||||
"/usr/include/atk-1.0", -- ATK accessibility toolkit headers
|
||||
"/usr/include/gdk-3.0", -- GDK headers
|
||||
"/usr/include/glib-2.0", -- GLib headers
|
||||
"/usr/lib/x86_64-linux-gnu/glib-2.0/include", -- GLib additional headers
|
||||
"/usr/include/harfbuzz"
|
||||
}
|
||||
|
||||
-- Link libraries for GTK3 and its dependencies
|
||||
links {
|
||||
"gtk-3", -- GTK3 library
|
||||
"gdk-3", -- GDK library
|
||||
"glib-2.0", -- GLib library
|
||||
"pango-1.0", -- Pango library
|
||||
"atk-1.0", -- ATK library
|
||||
"cairo", -- Cairo graphics library
|
||||
"gdk_pixbuf-2.0", -- GDK Pixbuf library
|
||||
"gio-2.0", -- GIO library
|
||||
"gobject-2.0", -- GObject library
|
||||
"pthread" -- POSIX threads library
|
||||
}
|
||||
|
||||
|
||||
links { "pthread" }
|
||||
buildoptions { "-pthread" }
|
||||
linkoptions { "-pthread" }
|
||||
|
||||
files {
|
||||
"src/Plattform/Linux/**.h",
|
||||
"src/Plattform/Linux/**.cpp"
|
||||
}
|
||||
|
||||
filter "configurations:Debug"
|
||||
defines { "DEBUG" }
|
||||
runtime "Debug"
|
||||
symbols "On"
|
||||
|
||||
filter "configurations:Release"
|
||||
defines { "RELEASE" }
|
||||
runtime "Release"
|
||||
optimize "On"
|
||||
symbols "On"
|
||||
|
||||
filter "configurations:Dist"
|
||||
defines { "DIST" }
|
||||
runtime "Release"
|
||||
optimize "On"
|
||||
symbols "Off"
|
65
Deer/Include/Deer/Application.h
Executable file
65
Deer/Include/Deer/Application.h
Executable file
@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
#include "Deer/Memory.h"
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
#include "DeerRender/Events/ApplicationEvent.h"
|
||||
#include "DeerRender/Events/Event.h"
|
||||
#include "DeerRender/Window.h"
|
||||
#endif
|
||||
|
||||
namespace Deer {
|
||||
class ImGuiLayer;
|
||||
namespace Core {
|
||||
extern int argc;
|
||||
extern char** argv;
|
||||
} // namespace Core
|
||||
|
||||
class Timestep {
|
||||
public:
|
||||
Timestep(float time = 0.0f) : m_time(time) {}
|
||||
|
||||
float getSeconds() const { return m_time; }
|
||||
float getMilliseconds() const { return m_time * 1000; }
|
||||
|
||||
private:
|
||||
float m_time;
|
||||
};
|
||||
|
||||
class Application {
|
||||
public:
|
||||
Application();
|
||||
~Application();
|
||||
|
||||
static Application* s_application;
|
||||
|
||||
int run();
|
||||
|
||||
virtual int onInit() { return 0; }
|
||||
virtual int onPreInit() { return 0; }
|
||||
virtual void onShutdown() {}
|
||||
virtual void onUpdate(Timestep delta) {}
|
||||
|
||||
private:
|
||||
bool m_running;
|
||||
float m_lastFrameTime = 0.0f;
|
||||
#ifdef DEER_RENDER
|
||||
public:
|
||||
Application(const WindowProps& props = WindowProps());
|
||||
|
||||
virtual void onRender(Timestep delta) {}
|
||||
virtual void onImGUI() {}
|
||||
virtual void onEvent(Event& event) {}
|
||||
|
||||
Scope<Window> m_window;
|
||||
|
||||
private:
|
||||
Scope<ImGuiLayer> m_imGuiLayer;
|
||||
const WindowProps m_windowProps;
|
||||
|
||||
virtual void onEventCallback(Event& e);
|
||||
void initializeWindow();
|
||||
bool onWindowClose(WindowCloseEvent& e);
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace Deer
|
82
Deer/Include/Deer/Asset.h
Executable file
82
Deer/Include/Deer/Asset.h
Executable file
@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Deer/DataStore.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "Deer/Path.h"
|
||||
|
||||
namespace Deer {
|
||||
template <typename T>
|
||||
class Asset {
|
||||
public:
|
||||
Asset() : m_assetID(0), m_assetLocation("null") {}
|
||||
Asset(uint32_t id, const std::filesystem::path& assetLocation)
|
||||
: m_assetID(id), m_assetLocation(assetLocation) {
|
||||
try {
|
||||
uint32_t size;
|
||||
uint8_t* data = DataStore::readFile(assetLocation, &size);
|
||||
|
||||
value = T::create(data, size);
|
||||
|
||||
delete[] data;
|
||||
} catch (const std::string& error) {
|
||||
DEER_CORE_ERROR("Error loading asset {0}\n{1}",
|
||||
assetLocation.generic_string().c_str(),
|
||||
error.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t getAssetID() const { return m_assetID; }
|
||||
inline Path& getAssetLocation() { return m_assetLocation; }
|
||||
|
||||
Ref<T> value;
|
||||
|
||||
private:
|
||||
uint32_t m_assetID;
|
||||
Path m_assetLocation;
|
||||
};
|
||||
|
||||
template <>
|
||||
class Asset<void> {
|
||||
public:
|
||||
Asset() : m_assetID(0), m_assetLocation("null") {}
|
||||
Asset(uint32_t id, const std::filesystem::path& assetLocation)
|
||||
: m_assetID(id), m_assetLocation(assetLocation) {}
|
||||
|
||||
inline uint32_t getAssetID() const { return m_assetID; }
|
||||
inline Path& getAssetLocation() { return m_assetLocation; }
|
||||
|
||||
Ref<void> value;
|
||||
|
||||
private:
|
||||
uint32_t m_assetID;
|
||||
Path m_assetLocation;
|
||||
};
|
||||
|
||||
namespace AssetManager {
|
||||
extern std::vector<Asset<void>> assets;
|
||||
|
||||
template <typename T>
|
||||
inline Asset<T>& getAsset(uint32_t assetID) {
|
||||
return *(Asset<T>*)&(assets[assetID]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline uint32_t loadAsset(const std::filesystem::path& assetLocation) {
|
||||
for (size_t id = 0; id < assets.size(); ++id) {
|
||||
if (assets[id].getAssetLocation() == assetLocation) return id;
|
||||
}
|
||||
|
||||
uint32_t assetID = assets.size();
|
||||
|
||||
Asset<T> asset(assetID, assetLocation);
|
||||
assets.push_back(*(Asset<void>*)&(asset));
|
||||
return assetID;
|
||||
}
|
||||
|
||||
inline const std::filesystem::path getAssetLocation(uint32_t assetID) {
|
||||
return assets[assetID].getAssetLocation();
|
||||
}
|
||||
} // namespace AssetManager
|
||||
} // namespace Deer
|
68
Deer/Include/Deer/ComponentScript.h
Executable file
68
Deer/Include/Deer/ComponentScript.h
Executable file
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class asITypeInfo;
|
||||
class asIScriptObject;
|
||||
class asIScriptFunction;
|
||||
class asIScriptContext;
|
||||
|
||||
namespace Deer {
|
||||
struct ScriptAttribute;
|
||||
using ScriptAttributeMap = std::unordered_map<std::string, ScriptAttribute>;
|
||||
|
||||
struct ScriptAttribute {
|
||||
std::string name;
|
||||
int typeID;
|
||||
int location;
|
||||
int internalID;
|
||||
bool isPrivate;
|
||||
|
||||
ScriptAttribute(const char* _name = "", int _type = 0,
|
||||
bool _isPrivate = 0, int _location = 0,
|
||||
int _internalID = 0)
|
||||
: typeID(_type),
|
||||
name(_name),
|
||||
isPrivate(_isPrivate),
|
||||
location(_location),
|
||||
internalID(_internalID) {}
|
||||
};
|
||||
|
||||
class ComponentScriptInstance {
|
||||
public:
|
||||
ComponentScriptInstance() = default;
|
||||
~ComponentScriptInstance();
|
||||
|
||||
void updateInternalVars();
|
||||
void start();
|
||||
|
||||
asIScriptObject* m_object;
|
||||
asIScriptFunction* m_updateFunction;
|
||||
asIScriptFunction* m_startFuction;
|
||||
};
|
||||
|
||||
class ComponentScript {
|
||||
public:
|
||||
ComponentScript() : m_typeInfo(nullptr) {}
|
||||
ComponentScript(asITypeInfo* typeInfo);
|
||||
|
||||
inline const std::string& getName() { return m_scriptID; }
|
||||
inline const ScriptAttributeMap& getAttributes() {
|
||||
return m_attributes;
|
||||
}
|
||||
inline const ScriptAttribute getAttribute(
|
||||
const std::string& attributeID) {
|
||||
return m_attributes[attributeID];
|
||||
}
|
||||
|
||||
inline asITypeInfo* getTypeInfo() { return m_typeInfo; }
|
||||
|
||||
private:
|
||||
asITypeInfo* m_typeInfo;
|
||||
|
||||
ScriptAttributeMap m_attributes;
|
||||
std::string m_scriptID;
|
||||
};
|
||||
|
||||
ScriptAttributeMap extractAttributes(asITypeInfo* typeInfo);
|
||||
} // namespace Deer
|
62
Deer/Include/Deer/Components.h
Executable file
62
Deer/Include/Deer/Components.h
Executable file
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include "Deer/Memory.h"
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "glm/glm.hpp"
|
||||
#include "glm/gtc/quaternion.hpp"
|
||||
|
||||
namespace Deer {
|
||||
class ComponentScriptInstance;
|
||||
|
||||
struct TagComponent {
|
||||
std::string tag;
|
||||
uint32_t entityUID;
|
||||
|
||||
TagComponent() = default;
|
||||
TagComponent(const TagComponent&) = default;
|
||||
TagComponent(std::string name, uint32_t _id = 0)
|
||||
: tag(name), entityUID(_id) {}
|
||||
};
|
||||
|
||||
struct ScriptComponent {
|
||||
std::string scriptID;
|
||||
Ref<ComponentScriptInstance> roeInstance;
|
||||
|
||||
ScriptComponent() = default;
|
||||
ScriptComponent(const ScriptComponent&) = default;
|
||||
ScriptComponent(std::string _scriptID) : scriptID(_scriptID) {}
|
||||
};
|
||||
|
||||
struct RelationshipComponent {
|
||||
uint32_t parent_UID = 0;
|
||||
std::vector<uint32_t> children;
|
||||
|
||||
RelationshipComponent() = default;
|
||||
RelationshipComponent(const RelationshipComponent&) = default;
|
||||
RelationshipComponent(uint32_t parent) : parent_UID(parent) {}
|
||||
};
|
||||
|
||||
struct TransformComponent {
|
||||
glm::vec3 position = glm::vec3(0.0f);
|
||||
glm::vec3 scale = glm::vec3(1.0f);
|
||||
glm::quat rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
TransformComponent() = default;
|
||||
TransformComponent(glm::vec3 _position) : position(_position) {}
|
||||
TransformComponent(const TransformComponent&) = default;
|
||||
|
||||
inline const glm::vec3 getEulerAngles() {
|
||||
return glm::degrees(glm::eulerAngles(rotation));
|
||||
}
|
||||
inline void setEulerAngles(const glm::vec3& eulerAngles) {
|
||||
rotation = glm::quat(glm::radians(eulerAngles));
|
||||
}
|
||||
|
||||
glm::mat4 getMatrix() const;
|
||||
};
|
||||
} // namespace Deer
|
37
Deer/Include/Deer/DataStore.h
Executable file
37
Deer/Include/Deer/DataStore.h
Executable file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Deer/Path.h"
|
||||
|
||||
#define DEER_SCENE_PATH "scenes"
|
||||
#define DEER_SCRIPT_PATH "scripts"
|
||||
#define DEER_SHADER_PATH "shaders"
|
||||
#define DEER_VOXEL_PATH "voxels"
|
||||
#define DEER_VOXEL_DATA_PATH "voxels/data"
|
||||
#define DEER_VOXEL_ASPECT_PATH "voxels/aspect"
|
||||
#define DEER_VOXEL_TEXTURE_PATH "voxels/textures"
|
||||
#define DEER_VOXEL_SHADER_PATH "voxels/shaders"
|
||||
#define DEER_OBJECT_PATH "objects"
|
||||
|
||||
#define DEER_BIN_PATH "bin"
|
||||
#define DEER_TEMP_PATH "tmp"
|
||||
|
||||
namespace Deer {
|
||||
namespace DataStore {
|
||||
void createFolder(const Path& path);
|
||||
|
||||
void saveFile(const Path&, uint8_t* data, uint32_t size);
|
||||
uint8_t* readFile(const Path&, uint32_t* size);
|
||||
void deleteFile(const Path&);
|
||||
|
||||
// Refactor----
|
||||
void compressFiles(std::vector<Path> files, const Path& path);
|
||||
std::vector<Path> getFiles(const Path& path,
|
||||
const std::string& extension);
|
||||
// Refactor----
|
||||
|
||||
extern Path rootPath;
|
||||
} // namespace DataStore
|
||||
} // namespace Deer
|
27
Deer/Include/Deer/EntryPoint.h
Executable file
27
Deer/Include/Deer/EntryPoint.h
Executable file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include "Deer/Application.h"
|
||||
#include "Deer/Log.h"
|
||||
|
||||
extern Deer::Application* createApplication(int argc, char** argv);
|
||||
|
||||
namespace Deer {
|
||||
int Main(int argc, char** argv) {
|
||||
Core::argc = argc;
|
||||
Core::argv = argv;
|
||||
|
||||
Log::init();
|
||||
DEER_CORE_TRACE("Initializing");
|
||||
|
||||
Application* app = createApplication(argc, argv);
|
||||
|
||||
int runResult = app->run();
|
||||
delete app;
|
||||
|
||||
DEER_CORE_TRACE("Deinitializing");
|
||||
Log::shutdown();
|
||||
|
||||
return runResult;
|
||||
}
|
||||
} // namespace Deer
|
||||
|
||||
int main(int argc, char** argv) { return Deer::Main(argc, argv); }
|
141
Deer/Include/Deer/Enviroment.h
Executable file
141
Deer/Include/Deer/Enviroment.h
Executable file
@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Deer/Components.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "entt/entt.hpp"
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
#include "DeerRender/Render/FrameBuffer.h"
|
||||
#include "DeerRender/SceneCamera.h"
|
||||
#endif
|
||||
|
||||
namespace Deer {
|
||||
class Entity;
|
||||
using EntityMap = std::unordered_map<uint32_t, Entity>;
|
||||
|
||||
class Environment {
|
||||
public:
|
||||
Environment();
|
||||
~Environment();
|
||||
|
||||
void clear();
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
void render(SceneCamera& camera);
|
||||
#endif
|
||||
|
||||
Entity& getEntity(uint32_t id);
|
||||
Entity& createEntity(const std::string& name = std::string());
|
||||
Entity createEmptyEntity();
|
||||
|
||||
// FEO
|
||||
uint32_t tryGetMainCamera();
|
||||
void setMainCamera(Entity& entity);
|
||||
|
||||
Entity& getRoot();
|
||||
|
||||
public:
|
||||
entt::registry m_registry;
|
||||
EntityMap m_entities;
|
||||
|
||||
uint32_t m_rootEntity = 0;
|
||||
uint32_t m_mainCamera = 0;
|
||||
|
||||
private:
|
||||
uint32_t m_idCreationOffset = 0;
|
||||
inline uint32_t pullEntityID() {
|
||||
m_idCreationOffset++;
|
||||
return m_idCreationOffset;
|
||||
}
|
||||
|
||||
friend class Entity;
|
||||
};
|
||||
|
||||
class Entity {
|
||||
public:
|
||||
Entity() {}
|
||||
|
||||
static Entity nullEntity;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T& addComponent(Args&&... args) const {
|
||||
DEER_CORE_ASSERT(
|
||||
!m_environment->m_registry.all_of<T>(m_entityHandle),
|
||||
"Entity already have component {0}", typeid(T).name());
|
||||
|
||||
return m_environment->m_registry.emplace<T>(
|
||||
m_entityHandle, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& getComponent() const {
|
||||
DEER_CORE_ASSERT(
|
||||
m_environment->m_registry.all_of<T>(m_entityHandle),
|
||||
"Entity has no component {0}", typeid(T).name());
|
||||
|
||||
return m_environment->m_registry.get<T>(m_entityHandle);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool hasComponent() const {
|
||||
return m_environment->m_registry.all_of<T>(m_entityHandle);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void removeComponent() const {
|
||||
DEER_CORE_ASSERT(
|
||||
m_environment->m_registry.all_of<T>(m_entityHandle),
|
||||
"Entity does not have component {0}", typeid(T).name());
|
||||
|
||||
m_environment->m_registry.remove<T>(m_entityHandle);
|
||||
}
|
||||
|
||||
Entity& duplicate();
|
||||
void destroy();
|
||||
|
||||
Entity& getParent();
|
||||
inline uint32_t getParentUID() { return m_parentUID; }
|
||||
|
||||
// TODO, enable transfer entitys from difrent enviroments
|
||||
void setParent(Entity& parent);
|
||||
bool isDescendant(Entity& parent);
|
||||
|
||||
uint32_t getParentUID() const { return m_parentUID; }
|
||||
uint32_t getUID() const { return m_entityUID; }
|
||||
|
||||
Environment* getEnvironment() const { return m_environment; }
|
||||
std::vector<uint32_t>& getChildren();
|
||||
|
||||
bool isRoot() { return m_isRoot; }
|
||||
glm::mat4 getWorldMatrix();
|
||||
glm::mat4 getRelativeMatrix();
|
||||
|
||||
void updateInternalVars();
|
||||
|
||||
inline bool isValid() const {
|
||||
return m_entityUID != 0 && m_environment != nullptr &&
|
||||
m_environment->m_registry.valid(m_entityHandle);
|
||||
}
|
||||
inline bool operator==(const Entity& b) const {
|
||||
return m_environment == b.m_environment &&
|
||||
m_entityUID == b.m_entityUID;
|
||||
}
|
||||
|
||||
private:
|
||||
Entity(entt::entity handle, Environment* scene);
|
||||
bool removeChild(Entity& child);
|
||||
|
||||
entt::entity m_entityHandle = entt::null;
|
||||
Environment* m_environment = nullptr;
|
||||
uint32_t m_entityUID = 0;
|
||||
uint32_t m_parentUID = 0;
|
||||
bool m_isRoot = false;
|
||||
|
||||
friend class Environment;
|
||||
friend class std::unordered_map<uint32_t, Entity>;
|
||||
};
|
||||
} // namespace Deer
|
66
Deer/Include/Deer/Log.h
Executable file
66
Deer/Include/Deer/Log.h
Executable file
@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
#include "Deer/Memory.h"
|
||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
namespace spdlog {
|
||||
class logger;
|
||||
}
|
||||
|
||||
namespace Deer {
|
||||
class Log {
|
||||
public:
|
||||
static void init();
|
||||
static void shutdown();
|
||||
|
||||
static void coreTrace(const char* msg);
|
||||
|
||||
static inline Ref<spdlog::logger>& getCoreLogger() {
|
||||
return coreLogger;
|
||||
}
|
||||
static inline Ref<spdlog::logger>& getClientLogger() {
|
||||
return clientLogger;
|
||||
}
|
||||
static inline Ref<spdlog::logger>& getScriptLogger() {
|
||||
return scriptLogger;
|
||||
}
|
||||
|
||||
private:
|
||||
static Ref<spdlog::logger> coreLogger;
|
||||
static Ref<spdlog::logger> clientLogger;
|
||||
static Ref<spdlog::logger> scriptLogger;
|
||||
};
|
||||
} // namespace Deer
|
||||
|
||||
#define DEER_CORE_TRACE(...) Deer::Log::getCoreLogger()->trace(__VA_ARGS__)
|
||||
#define DEER_CORE_INFO(...) Deer::Log::getCoreLogger()->info(__VA_ARGS__)
|
||||
#define DEER_CORE_WARN(...) Deer::Log::getCoreLogger()->warn(__VA_ARGS__)
|
||||
#define DEER_CORE_ERROR(...) Deer::Log::getCoreLogger()->error(__VA_ARGS__)
|
||||
|
||||
#define DEER_SCRIPT_TRACE(...) Deer::Log::getScriptLogger()->trace(__VA_ARGS__)
|
||||
#define DEER_SCRIPT_INFO(...) Deer::Log::getScriptLogger()->info(__VA_ARGS__)
|
||||
#define DEER_SCRIPT_WARN(...) Deer::Log::getScriptLogger()->warn(__VA_ARGS__)
|
||||
#define DEER_SCRIPT_ERROR(...) Deer::Log::getScriptLogger()->error(__VA_ARGS__)
|
||||
|
||||
#ifdef LINUX
|
||||
#define DEER_CORE_ASSERT(condition, ...) \
|
||||
if (!(condition)) { \
|
||||
Deer::Log::getCoreLogger()->error(__VA_ARGS__); \
|
||||
}
|
||||
#define DEER_SCRIPT_ASSERT(condition, ...) \
|
||||
if (!(condition)) { \
|
||||
Deer::Log::getScriptLogger()->error(__VA_ARGS__); \
|
||||
}
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
#define DEER_CORE_ASSERT(condition, ...) \
|
||||
if (!(condition)) { \
|
||||
Deer::Log::getCoreLogger()->error(__VA_ARGS__); \
|
||||
__debugbreak(); \
|
||||
}
|
||||
#define DEER_SCRIPT_ASSERT(condition, ...) \
|
||||
if (!(condition)) { \
|
||||
Deer::Log::getScriptLogger()->error(__VA_ARGS__); \
|
||||
__debugbreak(); \
|
||||
}
|
||||
#endif
|
18
Deer/Include/Deer/Memory.h
Normal file
18
Deer/Include/Deer/Memory.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
|
||||
namespace Deer {
|
||||
template <typename T>
|
||||
using Scope = std::unique_ptr<T>;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
constexpr auto MakeScope(Args&&... args) {
|
||||
return std::make_unique<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using Ref = std::shared_ptr<T>;
|
||||
|
||||
template <typename T>
|
||||
using WeakRef = std::weak_ptr<T>;
|
||||
} // namespace Deer
|
8
Deer/Include/Deer/Path.h
Executable file
8
Deer/Include/Deer/Path.h
Executable file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include <filesystem>
|
||||
|
||||
namespace Deer {
|
||||
using Path = std::filesystem::path;
|
||||
|
||||
Path toLowerCasePath(const Path& inputPath);
|
||||
} // namespace Deer
|
61
Deer/Include/Deer/Scene.h
Executable file
61
Deer/Include/Deer/Scene.h
Executable file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include "Deer/DataStore.h"
|
||||
#include "Deer/Memory.h"
|
||||
#include "Deer/Path.h"
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
#include "DeerRender/GizmoRenderer.h"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Deer {
|
||||
class VoxelWorld;
|
||||
class VoxelWorldProps;
|
||||
class Environment;
|
||||
|
||||
class Scene {
|
||||
public:
|
||||
Scene();
|
||||
|
||||
void createVoxelWorld(const VoxelWorldProps&);
|
||||
void deleteVoxelWorld();
|
||||
void clear();
|
||||
|
||||
void beginExecution();
|
||||
void updateInternalVars();
|
||||
void endExecution();
|
||||
|
||||
public:
|
||||
inline Ref<Environment>& getMainEnviroment() { return m_enviroment; }
|
||||
inline Ref<VoxelWorld>& getVoxelWorld() { return m_voxelWorld; }
|
||||
inline bool getExecutingState() { return m_isExecuting; }
|
||||
|
||||
private:
|
||||
Ref<Environment> m_enviroment;
|
||||
Ref<VoxelWorld> m_voxelWorld;
|
||||
|
||||
bool m_isExecuting = false;
|
||||
#ifdef DEER_RENDER
|
||||
public:
|
||||
void render();
|
||||
void render(SceneCamera);
|
||||
inline GizmoRenderer& getMainGizmoRenderer() { return m_gizmoRenderer; }
|
||||
|
||||
private:
|
||||
GizmoRenderer m_gizmoRenderer;
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace SceneDataStore {
|
||||
Scene loadScene(const Path& name);
|
||||
|
||||
void deleteSceneJson(const Path& name);
|
||||
void exportSceneJson(Scene& scene, const Path& name);
|
||||
void exportScenesBin();
|
||||
|
||||
void exportRuntimeScene(Scene& scene);
|
||||
Scene importRuntimeScene();
|
||||
} // namespace SceneDataStore
|
||||
} // namespace Deer
|
49
Deer/Include/Deer/ScriptEngine.h
Executable file
49
Deer/Include/Deer/ScriptEngine.h
Executable file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Deer/ComponentScript.h"
|
||||
#include "Deer/Memory.h"
|
||||
|
||||
class asIScriptEngine;
|
||||
class asIScriptModule;
|
||||
class asIScriptContext;
|
||||
class asIScriptFunction;
|
||||
class asITypeInfo;
|
||||
|
||||
namespace Deer {
|
||||
class Scene;
|
||||
class Entity;
|
||||
class ComponentScript;
|
||||
|
||||
using ComponentScriptMap = std::unordered_map<std::string, ComponentScript>;
|
||||
|
||||
namespace ScriptEngine {
|
||||
extern asIScriptContext* m_context;
|
||||
extern bool m_isCompilationValid;
|
||||
extern ComponentScriptMap m_componentScripts;
|
||||
extern Scene* m_scene;
|
||||
|
||||
void compileScriptEngine(const std::filesystem::path& scriptPath);
|
||||
void shutdownScriptEngine();
|
||||
|
||||
void beginExecutionContext(Scene* executingScene);
|
||||
void endExecutionContext();
|
||||
|
||||
inline asIScriptContext* getExecutionContext() { return m_context; }
|
||||
inline bool isCompilationValid() { return m_isCompilationValid; }
|
||||
|
||||
inline ComponentScriptMap& getComponentScripts() {
|
||||
return m_componentScripts;
|
||||
}
|
||||
inline ComponentScript& getComponentScript(
|
||||
const std::string& scriptID) {
|
||||
return m_componentScripts[scriptID];
|
||||
}
|
||||
|
||||
Ref<ComponentScriptInstance> createComponentScriptInstance(
|
||||
const std::string& scriptID, Entity& scriptEntity);
|
||||
} // namespace ScriptEngine
|
||||
} // namespace Deer
|
295
Deer/Include/Deer/Voxel.h
Executable file
295
Deer/Include/Deer/Voxel.h
Executable file
@ -0,0 +1,295 @@
|
||||
// Structure definition for voxel and voxel manipulation
|
||||
// copyright Copyright (c) 2025 Deer
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Deer/Memory.h"
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
#include "DeerRender/VoxelAspect.h"
|
||||
|
||||
namespace Deer {
|
||||
class Texture2D;
|
||||
class Shader;
|
||||
} // namespace Deer
|
||||
#endif
|
||||
|
||||
#define VOXEL_INFO_TYPE_AIR "air"
|
||||
#define VOXEL_INFO_TYPE_VOXEL "voxel"
|
||||
#define VOXEL_INFO_TYPE_TRANSPARENT_VOXEL "transparentVoxel"
|
||||
#define VOXEL_INFO_TYPE_CUSTOM "custom"
|
||||
|
||||
#define CHUNK_SIZE_X 32
|
||||
#define CHUNK_SIZE_Y 32
|
||||
#define CHUNK_SIZE_Z 32
|
||||
#define CHUNK_SIZE(axis) \
|
||||
((axis == 0) ? CHUNK_SIZE_X : (axis == 1) ? CHUNK_SIZE_Y : CHUNK_SIZE_Z)
|
||||
|
||||
#define LAYER_VOXELS CHUNK_SIZE_X* CHUNK_SIZE_Z
|
||||
#define CHUNK_VOXELS CHUNK_SIZE_X* CHUNK_SIZE_Y* CHUNK_SIZE_Z
|
||||
|
||||
// TODO: Change this to be a inline function
|
||||
#define VOXEL_POSITION(id) \
|
||||
id.z + id.y* CHUNK_SIZE_Z + id.x* CHUNK_SIZE_Z* CHUNK_SIZE_Y
|
||||
#define LAYER_VOXEL_POSITION(id) id.z + id.x* CHUNK_SIZE_Z
|
||||
|
||||
#define X_AXIS 0
|
||||
#define Y_AXIS 1
|
||||
#define Z_AXIS 2
|
||||
|
||||
// TODO: Change this to be a inline function
|
||||
#define NORMAL_DIR(axis, normal) normalDirs[axis + normal * 3]
|
||||
|
||||
namespace Deer {
|
||||
struct Voxel;
|
||||
struct LayerVoxel;
|
||||
|
||||
extern Voxel nullVoxel;
|
||||
extern Voxel emptyVoxel;
|
||||
extern LayerVoxel nullLayerVoxel;
|
||||
extern int normalDirs[3 * 6];
|
||||
|
||||
enum NormalDirection : uint8_t {
|
||||
NORMAL_LEFT = 0,
|
||||
NORMAL_RIGHT = 1,
|
||||
NORMAL_DOWN = 2,
|
||||
NORMAL_UP = 3,
|
||||
NORMAL_BACK = 4,
|
||||
NORMAL_FRONT = 5
|
||||
};
|
||||
|
||||
enum class VoxelInfoType : uint8_t {
|
||||
Air = 0,
|
||||
Voxel = 1,
|
||||
TransparentVoxel = 2,
|
||||
Custom = 3
|
||||
};
|
||||
|
||||
// Defines the general data of a voxel id stored in the array
|
||||
// VoxelData::voxelsInfo
|
||||
struct VoxelInfo {
|
||||
std::string name;
|
||||
VoxelInfoType type = VoxelInfoType::Air;
|
||||
};
|
||||
|
||||
// Namespace to load and manage voxel data
|
||||
namespace VoxelData {
|
||||
// List of the voxels loaded with loadVoxelsData()
|
||||
extern std::vector<VoxelInfo> voxelsInfo;
|
||||
|
||||
// Loads basic voxel data from folder DEER_VOXEL_DATA_PATH defined in
|
||||
// DataStore.h
|
||||
void loadVoxelsData();
|
||||
void createExampleVoxelData();
|
||||
|
||||
int32_t getVoxelID(const std::string&);
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
// List of the voxels Aspect loaded with loadVoxelsAspect()
|
||||
extern std::vector<VoxelAspect> voxelsAspect;
|
||||
|
||||
// Loads voxel aspect from folder DEER_VOXEL_ASPECT_PATH defined in
|
||||
// DataStore.h
|
||||
void loadVoxelsAspect();
|
||||
void createExampleVoxelAspect();
|
||||
|
||||
// Generates the texture atlas that the voxels demanded from folder
|
||||
// DEER_VOXEL_TEXTURE_PATH defined in DataStore.h Warning : This
|
||||
// function must be called with a render context, otherwise this will
|
||||
// crash
|
||||
void generateTextureAtlas();
|
||||
// Loads the shaders for rendering chunks from folder
|
||||
// DEER_VOXEL_SHADER_PATH defined in DataStore.h
|
||||
void loadVoxelsShaders();
|
||||
|
||||
// Returns with & height of the texture atlas generated
|
||||
// Warning: If you call this before generate Texture Atlas the return
|
||||
// value will be 0
|
||||
int getVoxelTextureAtlasSize();
|
||||
// Texture atlas created with generateTextureAtlas() call
|
||||
// Warning: You must have called generateTextureAtlas() in order to work
|
||||
Ref<Texture2D>& getVoxelColorTextureAtlas();
|
||||
// Returns the shader created with loadVoxelsShaders()
|
||||
// Warning: You must have called loadVoxelsShaders() in order to work
|
||||
Ref<Shader>& getSolidVoxelShader();
|
||||
|
||||
#endif
|
||||
} // namespace VoxelData
|
||||
|
||||
// Structure to define what a voxel inside a world must have
|
||||
struct Voxel {
|
||||
// Reference to the voxel id
|
||||
uint16_t id = 0;
|
||||
|
||||
Voxel() = default;
|
||||
Voxel(uint16_t _id) : id(_id) {}
|
||||
|
||||
inline bool operator==(const Voxel& b) const { return id == b.id; }
|
||||
inline bool isVoxelType() const {
|
||||
return VoxelData::voxelsInfo[id].type == VoxelInfoType::Voxel;
|
||||
}
|
||||
};
|
||||
|
||||
// Structure to define the general cordinates of a voxel in the world
|
||||
struct VoxelCordinates {
|
||||
union {
|
||||
struct {
|
||||
int32_t x, y, z;
|
||||
};
|
||||
std::array<int32_t, 3> data;
|
||||
};
|
||||
|
||||
VoxelCordinates(int32_t _x = 0, int32_t _y = 0, int32_t _z = 0)
|
||||
: x(_x), y(_y), z(_z) {}
|
||||
|
||||
inline int32_t& operator[](int id) { return data[id]; }
|
||||
inline bool operator==(const VoxelCordinates& b) const {
|
||||
return x == b.x && y == b.y && z == b.z;
|
||||
}
|
||||
inline bool isNull() const { return x < 0 || y < 0 || z < 0; }
|
||||
inline void makeNull() { x = -1; }
|
||||
};
|
||||
|
||||
// Stucture that defines the info of a layer voxel
|
||||
struct LayerVoxel {
|
||||
uint16_t height = 0;
|
||||
#ifdef DEER_RENDER
|
||||
uint16_t ambient_light_height = 0;
|
||||
#endif
|
||||
|
||||
LayerVoxel() = default;
|
||||
LayerVoxel(uint16_t _height) : height(_height) {}
|
||||
};
|
||||
|
||||
// Returning info of a raycast
|
||||
struct VoxelRayResult {
|
||||
float distance = 0;
|
||||
VoxelCordinates hitPos;
|
||||
uint8_t face = 0;
|
||||
};
|
||||
|
||||
// Coordinates of a chunk
|
||||
struct ChunkID {
|
||||
union {
|
||||
struct {
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t z;
|
||||
};
|
||||
std::array<uint16_t, 3> axis;
|
||||
};
|
||||
|
||||
ChunkID(uint16_t _x = 0, uint16_t _y = 0, uint16_t _z = 0)
|
||||
: x(_x), y(_y), z(_z) {}
|
||||
|
||||
inline bool operator==(const ChunkID& b) const {
|
||||
return x == b.x && y == b.y && z == b.z;
|
||||
}
|
||||
inline uint16_t& operator[](size_t i) { return axis[i]; }
|
||||
};
|
||||
|
||||
struct ChunkIDHash {
|
||||
size_t operator()(const ChunkID& chunk) const {
|
||||
size_t h1 = std::hash<uint16_t>{}(chunk.x);
|
||||
size_t h2 = std::hash<uint16_t>{}(chunk.y);
|
||||
size_t h3 = std::hash<uint16_t>{}(chunk.z);
|
||||
|
||||
size_t result = h1;
|
||||
result = result * 31 + h2;
|
||||
result = result * 31 + h3;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// Cordinates of a Layer
|
||||
struct LayerID {
|
||||
uint16_t x = 0;
|
||||
uint16_t z = 0;
|
||||
|
||||
LayerID() = default;
|
||||
LayerID(uint16_t _x, uint16_t _z) : x(_x), z(_z) {}
|
||||
inline bool operator==(const LayerID& b) const {
|
||||
return x == b.x && z == b.z;
|
||||
}
|
||||
};
|
||||
|
||||
// Coordinates of a layer voxel relative to the Layer Chunk
|
||||
struct LayerVoxelID {
|
||||
uint8_t x = 0;
|
||||
uint8_t z = 0;
|
||||
|
||||
LayerVoxelID() = default;
|
||||
LayerVoxelID(uint8_t _x, uint8_t _z = 0) : x(_x), z(_z) {}
|
||||
};
|
||||
|
||||
// Coordinates of a voxel inside a Chunk
|
||||
struct ChunkVoxelID {
|
||||
union {
|
||||
struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t z;
|
||||
};
|
||||
std::array<uint8_t, 3> axis;
|
||||
};
|
||||
|
||||
ChunkVoxelID(uint8_t _x = 0, uint8_t _y = 0, uint8_t _z = 0)
|
||||
: x(_x), y(_y), z(_z) {}
|
||||
inline uint8_t& operator[](size_t i) { return axis[i]; }
|
||||
};
|
||||
|
||||
// Extracts the chunk coordinaes and the chunk voxel coordinates from a
|
||||
// world position
|
||||
inline void extractChunkCordinates(uint32_t x, uint32_t y, uint32_t z,
|
||||
ChunkID& _chunkID,
|
||||
ChunkVoxelID& _chunkVoxelID) {
|
||||
uint16_t posX = x;
|
||||
uint16_t posY = y;
|
||||
uint16_t posZ = z;
|
||||
|
||||
_chunkID.x = posX >> 5;
|
||||
_chunkID.y = posY >> 5;
|
||||
_chunkID.z = posZ >> 5;
|
||||
|
||||
_chunkVoxelID.x = posX & 31;
|
||||
_chunkVoxelID.y = posY & 31;
|
||||
_chunkVoxelID.z = posZ & 31;
|
||||
}
|
||||
|
||||
// Extracts the chunk coordinaes and the chunk voxel chunk coordinates from
|
||||
// a world position
|
||||
inline void extractChunkCordinates(VoxelCordinates coords,
|
||||
ChunkID& _chunkID,
|
||||
ChunkVoxelID& _chunkVoxelID) {
|
||||
uint16_t posX = coords.x;
|
||||
uint16_t posY = coords.y;
|
||||
uint16_t posZ = coords.z;
|
||||
|
||||
_chunkID.x = posX >> 5;
|
||||
_chunkID.y = posY >> 5;
|
||||
_chunkID.z = posZ >> 5;
|
||||
|
||||
_chunkVoxelID.x = posX & 31;
|
||||
_chunkVoxelID.y = posY & 31;
|
||||
_chunkVoxelID.z = posZ & 31;
|
||||
}
|
||||
|
||||
// Extracts the layer chunk coordinaes and the layer chunk voxel coordinates
|
||||
// from a world position
|
||||
inline void extractLayerCordinates(uint32_t x, uint32_t z,
|
||||
LayerID& _layerID,
|
||||
LayerVoxelID& _layerVoxelID) {
|
||||
uint16_t posX = x;
|
||||
uint16_t posZ = z;
|
||||
|
||||
_layerID.x = posX >> 5;
|
||||
_layerID.z = posZ >> 5;
|
||||
|
||||
_layerVoxelID.x = posX & 31;
|
||||
_layerVoxelID.z = posZ & 31;
|
||||
}
|
||||
} // namespace Deer
|
229
Deer/Include/Deer/VoxelWorld.h
Executable file
229
Deer/Include/Deer/VoxelWorld.h
Executable file
@ -0,0 +1,229 @@
|
||||
// copyright Copyright (c) 2025 Deer
|
||||
#pragma once
|
||||
#include <array>
|
||||
|
||||
#include "Deer/Memory.h"
|
||||
#include "Deer/Voxel.h"
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
#include "DeerRender/LightVoxel.h"
|
||||
#endif
|
||||
|
||||
#include "glm/glm.hpp"
|
||||
|
||||
namespace Deer {
|
||||
class Chunk;
|
||||
class Layer;
|
||||
struct SceneCamera;
|
||||
struct VoxelWorldProps;
|
||||
struct VoxelWorldRenderData;
|
||||
|
||||
// Properties of a Voxel World
|
||||
struct VoxelWorldProps {
|
||||
union {
|
||||
struct {
|
||||
uint8_t chunkSizeX;
|
||||
uint8_t chunkSizeY;
|
||||
uint8_t chunkSizeZ;
|
||||
};
|
||||
std::array<uint8_t, 3> axis;
|
||||
};
|
||||
|
||||
VoxelWorldProps() = default;
|
||||
VoxelWorldProps(uint8_t _chunkSizeX, uint8_t _chunkSizeY,
|
||||
uint8_t _chunkSizeZ)
|
||||
: chunkSizeX(_chunkSizeX),
|
||||
chunkSizeY(_chunkSizeY),
|
||||
chunkSizeZ(_chunkSizeZ) {}
|
||||
|
||||
inline uint8_t &operator[](size_t i) { return axis[i]; }
|
||||
|
||||
// Returns the count of chunks
|
||||
inline int getChunkCount() const {
|
||||
return chunkSizeX * chunkSizeY * chunkSizeZ;
|
||||
}
|
||||
// Returns the count of layers
|
||||
inline int getLayerCount() const { return chunkSizeX * chunkSizeZ; }
|
||||
// Returns the internal id of a chunk relative to a Voxel World Props
|
||||
// from a chunk id
|
||||
inline int getWorldChunkID(ChunkID chunkID) const {
|
||||
return chunkID.z + chunkID.y * chunkSizeZ +
|
||||
chunkID.x * chunkSizeZ * chunkSizeY;
|
||||
}
|
||||
// Returns the internal id of a layer relative to a Voxel World Props
|
||||
// from a Layer id
|
||||
inline int getWorldLayerID(LayerID layerID) const {
|
||||
return layerID.z + layerID.x * chunkSizeZ;
|
||||
}
|
||||
|
||||
// Extracts the LayerID from a internal Layer id relative to Voxel World
|
||||
// Props
|
||||
inline LayerID getLayerID(int id) const {
|
||||
LayerID l_id;
|
||||
|
||||
l_id.x = id / chunkSizeZ;
|
||||
id -= l_id.x * chunkSizeZ;
|
||||
|
||||
l_id.z = id;
|
||||
return l_id;
|
||||
}
|
||||
// Extracts the ChunkID from a internal Chunk id relative to Voxel World
|
||||
// Props
|
||||
inline ChunkID getChunkID(int id) const {
|
||||
ChunkID c_id;
|
||||
|
||||
c_id.x = id / (chunkSizeZ * chunkSizeY);
|
||||
id -= c_id.x * (chunkSizeZ * chunkSizeY);
|
||||
|
||||
c_id.y = id / chunkSizeZ;
|
||||
id -= c_id.y * chunkSizeZ;
|
||||
|
||||
c_id.z = id;
|
||||
return c_id;
|
||||
}
|
||||
|
||||
// Checks if the Chunk id is inside the voxel World bounds
|
||||
inline bool isValid(ChunkID chunkID) const {
|
||||
return chunkID.x >= 0 && chunkID.x < chunkSizeX && chunkID.y >= 0 &&
|
||||
chunkID.y < chunkSizeY && chunkID.z >= 0 &&
|
||||
chunkID.z < chunkSizeZ;
|
||||
}
|
||||
|
||||
// Checks if the Layer id is inside the voxel World bounds
|
||||
inline bool isValid(LayerID layerID) const {
|
||||
return layerID.x >= 0 && layerID.x < chunkSizeX && layerID.z >= 0 &&
|
||||
layerID.z < chunkSizeZ;
|
||||
}
|
||||
|
||||
// Returns the max amount of voxels in the Voxel World Props
|
||||
inline int getMaxVoxelCount() const {
|
||||
return getChunkCount() * CHUNK_VOXELS;
|
||||
}
|
||||
|
||||
// Clamps the coordinates of a Voxel World Coordinates to be inside the
|
||||
// voxel world props
|
||||
inline void clampCordinates(VoxelCordinates &coords) const {
|
||||
if (coords.x < 0)
|
||||
coords.x = 0;
|
||||
else if (coords.x >= chunkSizeX * CHUNK_SIZE_X)
|
||||
coords.x = chunkSizeX * CHUNK_SIZE_X - 1;
|
||||
|
||||
if (coords.y < 0)
|
||||
coords.y = 0;
|
||||
else if (coords.y >= chunkSizeY * CHUNK_SIZE_Y)
|
||||
coords.y = chunkSizeY * CHUNK_SIZE_Y - 1;
|
||||
|
||||
if (coords.z < 0)
|
||||
coords.z = 0;
|
||||
else if (coords.z >= chunkSizeZ * CHUNK_SIZE_Z)
|
||||
coords.z = chunkSizeZ * CHUNK_SIZE_Z - 1;
|
||||
}
|
||||
|
||||
// Takes 2 Voxel coordinates and outputs them in the same variables
|
||||
// being the min with the min values and the max with the max This is
|
||||
// useful for loops
|
||||
inline void clampAndSetMinMax(VoxelCordinates &min,
|
||||
VoxelCordinates &max) const {
|
||||
VoxelCordinates a_cache = min;
|
||||
VoxelCordinates b_cache = max;
|
||||
|
||||
for (int x = 0; x < 3; x++) {
|
||||
if (a_cache[x] > b_cache[x]) {
|
||||
max[x] = a_cache[x];
|
||||
min[x] = b_cache[x];
|
||||
} else {
|
||||
min[x] = a_cache[x];
|
||||
max[x] = b_cache[x];
|
||||
}
|
||||
}
|
||||
|
||||
clampCordinates(min);
|
||||
clampCordinates(max);
|
||||
}
|
||||
};
|
||||
|
||||
// Class to manage the voxels
|
||||
class VoxelWorld {
|
||||
public:
|
||||
// Warning: Do not change the voxel data content since that could make
|
||||
// undefined behaviour
|
||||
VoxelWorld(const VoxelWorldProps &props);
|
||||
// This class can not be copyed
|
||||
// TODO: Make a function to duplicate a voxel World
|
||||
VoxelWorld(const VoxelWorld &) = delete;
|
||||
VoxelWorld &operator=(VoxelWorld &) = delete;
|
||||
|
||||
// Returns the voxel in a voxel coordinates
|
||||
Voxel readVoxel(VoxelCordinates);
|
||||
// Sets the voxel in the coordinates to the value
|
||||
void setVoxel(VoxelCordinates, Voxel value);
|
||||
|
||||
// Fills a space with the voxel value inside the 2 coordinates
|
||||
// Note that you don't have to give then ordeered by min and max
|
||||
void fillVoxels(VoxelCordinates, VoxelCordinates, Voxel value);
|
||||
// Remplaces the ref voxel with the value of a space inside the 2
|
||||
// coordinates
|
||||
// Note that you don't have to give then ordeered by min and max
|
||||
void remplaceVoxels(VoxelCordinates, VoxelCordinates, Voxel ref,
|
||||
Voxel value);
|
||||
|
||||
// Returns the layer data of a woorld coordinates
|
||||
// Note out of bounds will return a default Layer Voxel
|
||||
LayerVoxel readLayerVoxel(int x, int z);
|
||||
// Calculates the max height of a layer in a space
|
||||
// Note out of bounds will return a 0 of height
|
||||
// Tip: this will calculate, you should use the cached height in a layer
|
||||
// voxel
|
||||
uint16_t calculateLayerVoxelHeight(int x, int z);
|
||||
|
||||
// Raycast a ray from a source and dir
|
||||
VoxelRayResult rayCast(glm::vec3 position, glm::vec3 dir,
|
||||
float maxDistance = 10.0f);
|
||||
// Raycast a ray from a source and dir ignoring if the ray stats inside
|
||||
// a voxel
|
||||
VoxelRayResult rayCast_editor(glm::vec3 position, glm::vec3 dir,
|
||||
float maxDistance = 10.0f);
|
||||
|
||||
// Returns the voxel world props used in the voxel world
|
||||
// Note that you can't change the world size unless you create a new
|
||||
// Voxel World
|
||||
inline const VoxelWorldProps &getVoxelWorldProps() const {
|
||||
return m_worldProps;
|
||||
}
|
||||
#ifdef DEER_RENDER
|
||||
public:
|
||||
// Renders the current voxel world with a specified scene camera
|
||||
void render(const SceneCamera &);
|
||||
// Generates the next chunk mesh
|
||||
void bakeNextChunk();
|
||||
|
||||
// Light data
|
||||
VoxelLight readLight(VoxelCordinates);
|
||||
VoxelLight &modLight(VoxelCordinates);
|
||||
|
||||
private:
|
||||
Scope<VoxelWorldRenderData> m_renderData;
|
||||
|
||||
// Chunk vertex creation
|
||||
void genSolidVoxel(ChunkID chunkID, ChunkVoxelID chunkVoxelID);
|
||||
|
||||
// --- Light propagation ---
|
||||
// Warning: This function is private and needs to have min and max
|
||||
// clamped and in order
|
||||
void bakeVoxelLight(VoxelCordinates min, VoxelCordinates max);
|
||||
void bakeVoxelLightFromPoint(VoxelCordinates);
|
||||
void bakeAmbientLight(int minX, int maxX, int minZ, int maxZ);
|
||||
void bakeAmbientLightFromPoint(int x, int z);
|
||||
|
||||
void resolveNextAmbientLightPropagation();
|
||||
void resolveNextVoxelLightPropagation();
|
||||
#endif
|
||||
private:
|
||||
VoxelWorldProps m_worldProps;
|
||||
|
||||
Scope<Chunk[]> m_chunks;
|
||||
Scope<Layer[]> m_layers;
|
||||
|
||||
LayerVoxel &modLayerVoxel(int x, int z);
|
||||
};
|
||||
} // namespace Deer
|
47
Deer/Include/DeerRender/Components.h
Executable file
47
Deer/Include/DeerRender/Components.h
Executable file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include "Deer/Components.h"
|
||||
|
||||
#include "DeerRender/Render/VertexArray.h"
|
||||
#include "DeerRender/Render/Shader.h"
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include "glm/gtc/quaternion.hpp"
|
||||
#include "glm/glm.hpp"
|
||||
#include "glm/gtc/matrix_transform.hpp"
|
||||
|
||||
#define MAX_TEXTURE_BINDINGS 4
|
||||
|
||||
namespace Deer {
|
||||
struct MeshRenderComponent {
|
||||
MeshRenderComponent() = default;
|
||||
MeshRenderComponent(const MeshRenderComponent&) = default;
|
||||
MeshRenderComponent(uint32_t _mesh, uint32_t _shader) : shaderAssetID(_shader), meshAssetID(_mesh) { }
|
||||
|
||||
uint32_t shaderAssetID = 0;
|
||||
uint32_t meshAssetID = 0;
|
||||
};
|
||||
|
||||
struct TextureBindingComponent {
|
||||
TextureBindingComponent() {
|
||||
for (int x = 0; x < MAX_TEXTURE_BINDINGS; x++) {
|
||||
textureAssetID[x] = 0;
|
||||
textureBindID[x] = 0;
|
||||
}
|
||||
}
|
||||
TextureBindingComponent(const TextureBindingComponent&) = default;
|
||||
|
||||
uint32_t textureAssetID[MAX_TEXTURE_BINDINGS];
|
||||
unsigned char textureBindID[MAX_TEXTURE_BINDINGS];
|
||||
};
|
||||
|
||||
struct CameraComponent {
|
||||
CameraComponent() = default;
|
||||
CameraComponent(const CameraComponent&) = default;
|
||||
CameraComponent(float _fov, float _aspect, float _nearZ, float _farZ) : fov(_fov), aspect(_aspect), nearZ(_nearZ), farZ(_farZ) { }
|
||||
|
||||
inline glm::mat4 getMatrix() const { return glm::perspective(fov, aspect, nearZ, farZ); }
|
||||
|
||||
float fov = glm::radians(50.0f), aspect = 16 / 9, nearZ = 0.1f, farZ = 1000;
|
||||
};
|
||||
|
||||
}
|
36
Deer/Include/DeerRender/Events/ApplicationEvent.h
Executable file
36
Deer/Include/DeerRender/Events/ApplicationEvent.h
Executable file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include "DeerRender/Events/Event.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace Deer {
|
||||
class WindowResizeEvent : public Event {
|
||||
public:
|
||||
WindowResizeEvent(unsigned int width, unsigned int height)
|
||||
: m_Width(width), m_Height(height) {}
|
||||
|
||||
inline unsigned int getWidth() const { return m_Width; }
|
||||
inline unsigned int getHeight() const { return m_Height; }
|
||||
|
||||
std::string toString() const override {
|
||||
std::stringstream ss;
|
||||
ss << "WindowResizeEvent: " << m_Width << ", " << m_Height;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(WindowResize)
|
||||
EVENT_CLASS_CATEGORY(EventCategoryApplication)
|
||||
private:
|
||||
unsigned int m_Width, m_Height;
|
||||
};
|
||||
|
||||
class WindowCloseEvent : public Event {
|
||||
public:
|
||||
WindowCloseEvent() = default;
|
||||
std::string toString() const override {
|
||||
return "Window close";
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(WindowClose)
|
||||
EVENT_CLASS_CATEGORY(EventCategoryApplication)
|
||||
};
|
||||
}
|
68
Deer/Include/DeerRender/Events/Event.h
Executable file
68
Deer/Include/DeerRender/Events/Event.h
Executable file
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace Deer {
|
||||
enum class EventType
|
||||
{
|
||||
None = 0,
|
||||
WindowClose, WindowMinimize, WindowResize, WindowFocus, WindowLostFocus, WindowMoved,
|
||||
AppUpdate, AppRender,
|
||||
KeyPressed, KeyReleased, KeyTyped,
|
||||
MouseButtonPressed, MouseButtonReleased, MouseButtonDown, MouseMoved, MouseScrolled
|
||||
};
|
||||
|
||||
enum EventCategory {
|
||||
None = 0,
|
||||
EventCategoryApplication = 1 << 0,
|
||||
EventCategoryInput = 1 << 1,
|
||||
EventCategoryKeyboard = 1 << 2,
|
||||
EventCategoryMouse = 1 << 3,
|
||||
EventCategoryMouseButton = 1 << 4
|
||||
};
|
||||
|
||||
#define EVENT_CLASS_TYPE(type) static EventType getStaticType() { return EventType::type; }\
|
||||
virtual EventType getEventType() const override { return getStaticType(); }\
|
||||
virtual const char* getName() const override { return #type; }
|
||||
|
||||
#define EVENT_CLASS_CATEGORY(category) virtual int getCategoryFlags() const override { return category; }
|
||||
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
bool handled = false;
|
||||
|
||||
virtual ~Event() {}
|
||||
virtual EventType getEventType() const = 0;
|
||||
virtual const char* getName() const = 0;
|
||||
virtual int getCategoryFlags() const = 0;
|
||||
virtual std::string toString() const { return getName(); }
|
||||
|
||||
inline bool isInCategory(EventCategory category)
|
||||
{
|
||||
return getCategoryFlags() & category;
|
||||
}
|
||||
};
|
||||
|
||||
class EventDispatcher
|
||||
{
|
||||
template<typename T>
|
||||
using EventFn = std::function<bool(T&)>;
|
||||
public:
|
||||
EventDispatcher(Event& event)
|
||||
: m_event(event) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool dispatch(EventFn<T> func) {
|
||||
if (m_event.getEventType() == T::getStaticType() && !m_event.handled)
|
||||
{
|
||||
m_event.handled = func(*(T*)&m_event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
Event& m_event;
|
||||
};
|
||||
}
|
71
Deer/Include/DeerRender/Events/KeyEvent.h
Executable file
71
Deer/Include/DeerRender/Events/KeyEvent.h
Executable file
@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
#include "DeerRender/Events/Event.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace Deer {
|
||||
|
||||
class KeyEvent : public Event
|
||||
{
|
||||
public:
|
||||
inline unsigned short getKeyCode() const { return m_KeyCode; }
|
||||
|
||||
EVENT_CLASS_CATEGORY(EventCategoryKeyboard | EventCategoryInput)
|
||||
protected:
|
||||
KeyEvent(unsigned short keycode)
|
||||
: m_KeyCode(keycode) {}
|
||||
|
||||
unsigned short m_KeyCode;
|
||||
};
|
||||
|
||||
class KeyPressedEvent : public KeyEvent
|
||||
{
|
||||
public:
|
||||
KeyPressedEvent(unsigned int keycode, int repeatCount)
|
||||
: KeyEvent(keycode), m_RepeatCount(repeatCount) {}
|
||||
|
||||
inline int getRepeatCount() const { return m_RepeatCount; }
|
||||
|
||||
std::string toString() const override
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "KeyPressedEvent: " << m_KeyCode << " (" << m_RepeatCount << " repeats)";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(KeyPressed)
|
||||
private:
|
||||
int m_RepeatCount;
|
||||
};
|
||||
|
||||
class KeyReleasedEvent : public KeyEvent
|
||||
{
|
||||
public:
|
||||
KeyReleasedEvent(unsigned int keycode)
|
||||
: KeyEvent(keycode) {}
|
||||
|
||||
std::string toString() const override
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "KeyReleasedEvent: " << m_KeyCode;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(KeyReleased)
|
||||
};
|
||||
|
||||
class KeyTypedEvent : public KeyEvent
|
||||
{
|
||||
public:
|
||||
KeyTypedEvent(unsigned int keycode)
|
||||
: KeyEvent(keycode) {}
|
||||
|
||||
std::string toString() const override
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "KeyTypedEvent: " << m_KeyCode;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(KeyTyped)
|
||||
};
|
||||
}
|
108
Deer/Include/DeerRender/Events/MouseEvent.h
Executable file
108
Deer/Include/DeerRender/Events/MouseEvent.h
Executable file
@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
#include "DeerRender/Events/Event.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace Deer {
|
||||
class MouseMovedEvent : public Event
|
||||
{
|
||||
public:
|
||||
MouseMovedEvent(float x, float y)
|
||||
: m_MouseX(x), m_MouseY(y) {}
|
||||
|
||||
inline float getX() const { return m_MouseX; }
|
||||
inline float getY() const { return m_MouseY; }
|
||||
|
||||
std::string toString() const override
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "MouseMovedEvent: " << m_MouseX << ", " << m_MouseY;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(MouseMoved)
|
||||
EVENT_CLASS_CATEGORY(EventCategoryMouse | EventCategoryInput)
|
||||
private:
|
||||
float m_MouseX, m_MouseY;
|
||||
};
|
||||
|
||||
class MouseScrolledEvent : public Event
|
||||
{
|
||||
public:
|
||||
MouseScrolledEvent(float xOffset, float yOffset)
|
||||
: m_XOffset(xOffset), m_YOffset(yOffset) {}
|
||||
|
||||
inline float getXOffset() const { return m_XOffset; }
|
||||
inline float getYOffset() const { return m_YOffset; }
|
||||
|
||||
std::string toString() const override
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "MouseScrolledEvent: " << getXOffset() << ", " << getYOffset();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(MouseScrolled)
|
||||
EVENT_CLASS_CATEGORY(EventCategoryMouse | EventCategoryInput)
|
||||
private:
|
||||
float m_XOffset, m_YOffset;
|
||||
};
|
||||
|
||||
class MouseButtonEvent : public Event
|
||||
{
|
||||
public:
|
||||
inline int getMouseButton() const { return m_Button; }
|
||||
|
||||
EVENT_CLASS_CATEGORY(EventCategoryMouse | EventCategoryInput)
|
||||
protected:
|
||||
MouseButtonEvent(int button)
|
||||
: m_Button(button) {}
|
||||
|
||||
int m_Button;
|
||||
};
|
||||
|
||||
class MouseButtonPressedEvent : public MouseButtonEvent
|
||||
{
|
||||
public:
|
||||
MouseButtonPressedEvent(int button)
|
||||
: MouseButtonEvent(button) {}
|
||||
|
||||
std::string toString() const override {
|
||||
std::stringstream ss;
|
||||
ss << "MouseButtonPressedEvent: " << m_Button;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(MouseButtonPressed)
|
||||
};
|
||||
|
||||
class MouseButtonReleasedEvent : public MouseButtonEvent
|
||||
{
|
||||
public:
|
||||
MouseButtonReleasedEvent(int button)
|
||||
: MouseButtonEvent(button) {}
|
||||
|
||||
std::string toString() const override {
|
||||
std::stringstream ss;
|
||||
ss << "MouseButtonReleasedEvent: " << m_Button;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(MouseButtonReleased)
|
||||
};
|
||||
|
||||
class MouseButtonDownEvent : public MouseButtonEvent
|
||||
{
|
||||
public:
|
||||
MouseButtonDownEvent(int button)
|
||||
: MouseButtonEvent(button) {
|
||||
}
|
||||
|
||||
std::string toString() const override {
|
||||
std::stringstream ss;
|
||||
ss << "MouseButtonDownEvent: " << m_Button;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
EVENT_CLASS_TYPE(MouseButtonDown)
|
||||
};
|
||||
}
|
33
Deer/Include/DeerRender/GizmoRenderer.h
Executable file
33
Deer/Include/DeerRender/GizmoRenderer.h
Executable file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include "glm/glm.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
#define GIZMO_DEPTH 8
|
||||
|
||||
namespace Deer {
|
||||
struct SceneCamera;
|
||||
struct GizmoFace {
|
||||
glm::vec3 positions[4];
|
||||
uint16_t textureID;
|
||||
uint8_t face;
|
||||
};
|
||||
|
||||
class GizmoRenderer {
|
||||
public:
|
||||
void drawLine(glm::vec3 a, glm::vec3 b, glm::vec3 color = glm::vec3(1.0f, 1.0f, 1.0f));
|
||||
void drawVoxelLine(int x, int y, int z, glm::vec3 color = glm::vec3(1.0f, 1.0f, 1.0f));
|
||||
void drawVoxelLineFace(int x, int y, int z, uint8_t face, glm::vec3 color = glm::vec3(1.0f, 1.0f, 1.0f));
|
||||
|
||||
void drawVoxelFace(int x, int y, int z, uint16_t voxelID, uint8_t face, uint8_t priority = 0);
|
||||
void drawVoxelFaceInverted(int x, int y, int z, uint16_t voxelID, uint8_t face, uint8_t priority = 0);
|
||||
|
||||
void render(const SceneCamera& camera);
|
||||
void refresh();
|
||||
private:
|
||||
std::vector<std::array<glm::vec3, 3>> m_lines;
|
||||
std::array<std::vector<GizmoFace>, GIZMO_DEPTH> m_faces;
|
||||
};
|
||||
}
|
||||
|
12
Deer/Include/DeerRender/Input.h
Executable file
12
Deer/Include/DeerRender/Input.h
Executable file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "Deer/Application.h"
|
||||
#include "DeerRender/KeyCodes.h"
|
||||
|
||||
namespace Deer {
|
||||
class Input {
|
||||
public:
|
||||
static bool isKeyPressed(unsigned int key);
|
||||
static bool isMouseButtonPressed(int button);
|
||||
static void getMousePos(float& x, float& y);
|
||||
};
|
||||
}
|
138
Deer/Include/DeerRender/KeyCodes.h
Executable file
138
Deer/Include/DeerRender/KeyCodes.h
Executable file
@ -0,0 +1,138 @@
|
||||
#pragma once
|
||||
|
||||
// From GLFW
|
||||
#define DEER_KEY_SPACE 32
|
||||
#define DEER_KEY_APOSTROPHE 39 /* ' */
|
||||
#define DEER_KEY_COMMA 44 /* , */
|
||||
#define DEER_KEY_MINUS 45 /* - */
|
||||
#define DEER_KEY_PERIOD 46 /* . */
|
||||
#define DEER_KEY_SLASH 47 /* / */
|
||||
#define DEER_KEY_0 48
|
||||
#define DEER_KEY_1 49
|
||||
#define DEER_KEY_2 50
|
||||
#define DEER_KEY_3 51
|
||||
#define DEER_KEY_4 52
|
||||
#define DEER_KEY_5 53
|
||||
#define DEER_KEY_6 54
|
||||
#define DEER_KEY_7 55
|
||||
#define DEER_KEY_8 56
|
||||
#define DEER_KEY_9 57
|
||||
#define DEER_KEY_SEMICOLON 59 /* ; */
|
||||
#define DEER_KEY_EQUAL 61 /* = */
|
||||
#define DEER_KEY_A 65
|
||||
#define DEER_KEY_B 66
|
||||
#define DEER_KEY_C 67
|
||||
#define DEER_KEY_D 68
|
||||
#define DEER_KEY_E 69
|
||||
#define DEER_KEY_F 70
|
||||
#define DEER_KEY_G 71
|
||||
#define DEER_KEY_H 72
|
||||
#define DEER_KEY_I 73
|
||||
#define DEER_KEY_J 74
|
||||
#define DEER_KEY_K 75
|
||||
#define DEER_KEY_L 76
|
||||
#define DEER_KEY_M 77
|
||||
#define DEER_KEY_N 78
|
||||
#define DEER_KEY_O 79
|
||||
#define DEER_KEY_P 80
|
||||
#define DEER_KEY_Q 81
|
||||
#define DEER_KEY_R 82
|
||||
#define DEER_KEY_S 83
|
||||
#define DEER_KEY_T 84
|
||||
#define DEER_KEY_U 85
|
||||
#define DEER_KEY_V 86
|
||||
#define DEER_KEY_W 87
|
||||
#define DEER_KEY_X 88
|
||||
#define DEER_KEY_Y 89
|
||||
#define DEER_KEY_Z 90
|
||||
#define DEER_KEY_LEFT_BRACKET 91 /* [ */
|
||||
#define DEER_KEY_BACKSLASH 92 /* \ */
|
||||
#define DEER_KEY_RIGHT_BRACKET 93 /* ] */
|
||||
#define DEER_KEY_GRAVE_ACCENT 96 /* ` */
|
||||
#define DEER_KEY_WORLD_1 161 /* non-US #1 */
|
||||
#define DEER_KEY_WORLD_2 162 /* non-US #2 */
|
||||
|
||||
/* Function keys */
|
||||
#define DEER_KEY_ESCAPE 256
|
||||
#define DEER_KEY_ENTER 257
|
||||
#define DEER_KEY_TAB 258
|
||||
#define DEER_KEY_BACKSPACE 259
|
||||
#define DEER_KEY_INSERT 260
|
||||
#define DEER_KEY_DELETE 261
|
||||
#define DEER_KEY_RIGHT 262
|
||||
#define DEER_KEY_LEFT 263
|
||||
#define DEER_KEY_DOWN 264
|
||||
#define DEER_KEY_UP 265
|
||||
#define DEER_KEY_PAGE_UP 266
|
||||
#define DEER_KEY_PAGE_DOWN 267
|
||||
#define DEER_KEY_HOME 268
|
||||
#define DEER_KEY_END 269
|
||||
#define DEER_KEY_CAPS_LOCK 280
|
||||
#define DEER_KEY_SCROLL_LOCK 281
|
||||
#define DEER_KEY_NUM_LOCK 282
|
||||
#define DEER_KEY_PRINT_SCREEN 283
|
||||
#define DEER_KEY_PAUSE 284
|
||||
#define DEER_KEY_F1 290
|
||||
#define DEER_KEY_F2 291
|
||||
#define DEER_KEY_F3 292
|
||||
#define DEER_KEY_F4 293
|
||||
#define DEER_KEY_F5 294
|
||||
#define DEER_KEY_F6 295
|
||||
#define DEER_KEY_F7 296
|
||||
#define DEER_KEY_F8 297
|
||||
#define DEER_KEY_F9 298
|
||||
#define DEER_KEY_F10 299
|
||||
#define DEER_KEY_F11 300
|
||||
#define DEER_KEY_F12 301
|
||||
#define DEER_KEY_F13 302
|
||||
#define DEER_KEY_F14 303
|
||||
#define DEER_KEY_F15 304
|
||||
#define DEER_KEY_F16 305
|
||||
#define DEER_KEY_F17 306
|
||||
#define DEER_KEY_F18 307
|
||||
#define DEER_KEY_F19 308
|
||||
#define DEER_KEY_F20 309
|
||||
#define DEER_KEY_F21 310
|
||||
#define DEER_KEY_F22 311
|
||||
#define DEER_KEY_F23 312
|
||||
#define DEER_KEY_F24 313
|
||||
#define DEER_KEY_F25 314
|
||||
#define DEER_KEY_KP_0 320
|
||||
#define DEER_KEY_KP_1 321
|
||||
#define DEER_KEY_KP_2 322
|
||||
#define DEER_KEY_KP_3 323
|
||||
#define DEER_KEY_KP_4 324
|
||||
#define DEER_KEY_KP_5 325
|
||||
#define DEER_KEY_KP_6 326
|
||||
#define DEER_KEY_KP_7 327
|
||||
#define DEER_KEY_KP_8 328
|
||||
#define DEER_KEY_KP_9 329
|
||||
#define DEER_KEY_KP_DECIMAL 330
|
||||
#define DEER_KEY_KP_DIVIDE 331
|
||||
#define DEER_KEY_KP_MULTIPLY 332
|
||||
#define DEER_KEY_KP_SUBTRACT 333
|
||||
#define DEER_KEY_KP_ADD 334
|
||||
#define DEER_KEY_KP_ENTER 335
|
||||
#define DEER_KEY_KP_EQUAL 336
|
||||
#define DEER_KEY_LEFT_SHIFT 340
|
||||
#define DEER_KEY_LEFT_CONTROL 341
|
||||
#define DEER_KEY_LEFT_ALT 342
|
||||
#define DEER_KEY_LEFT_SUPER 343
|
||||
#define DEER_KEY_RIGHT_SHIFT 344
|
||||
#define DEER_KEY_RIGHT_CONTROL 345
|
||||
#define DEER_KEY_RIGHT_ALT 346
|
||||
#define DEER_KEY_RIGHT_SUPER 347
|
||||
#define DEER_KEY_MENU 348
|
||||
|
||||
#define DEER_MOUSE_BUTTON_1 0
|
||||
#define DEER_MOUSE_BUTTON_2 1
|
||||
#define DEER_MOUSE_BUTTON_3 2
|
||||
#define DEER_MOUSE_BUTTON_4 3
|
||||
#define DEER_MOUSE_BUTTON_5 4
|
||||
#define DEER_MOUSE_BUTTON_6 5
|
||||
#define DEER_MOUSE_BUTTON_7 6
|
||||
#define DEER_MOUSE_BUTTON_8 7
|
||||
#define DEER_MOUSE_BUTTON_LAST DEER_MOUSE_BUTTON_8
|
||||
#define DEER_MOUSE_BUTTON_LEFT DEER_MOUSE_BUTTON_1
|
||||
#define DEER_MOUSE_BUTTON_RIGHT DEER_MOUSE_BUTTON_2
|
||||
#define DEER_MOUSE_BUTTON_MIDDLE DEER_MOUSE_BUTTON_3
|
33
Deer/Include/DeerRender/LightVoxel.h
Executable file
33
Deer/Include/DeerRender/LightVoxel.h
Executable file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include "Deer/Voxel.h"
|
||||
|
||||
#define LIGHT_PROPAGATION_COMPLEX_DIRS 18
|
||||
#define LIGHT_PROPAGATION_COMPLEX_DIR(id, dir) lightPropagationComplexDir[id + dir * 2]
|
||||
#define LIGHT_PROPAGATION_SIMPLE_FALL 16
|
||||
#define LIGHT_PROPAGATION_COMPLEX_FALL 23
|
||||
|
||||
#define NORMAL_VERTEX_POS(axis, id, normal) normalFacePositions[axis + id * 3 + normal * 3 * 4]
|
||||
#define VERTEX_UV(axis, id) uvFace[axis + id * 2]
|
||||
#define AMBIENT_OCCLUSION_VERTEX(axis, id, vertex, normal) ambientOcclusionVertex[axis + id * 3 + vertex * 3 * 2 + normal * 3 * 2 * 4]
|
||||
#define LAYER_CHECK_DIRS(axis, id) layerCheckDirections[axis + id * 2]
|
||||
|
||||
namespace Deer {
|
||||
struct VoxelLight;
|
||||
extern VoxelLight lightVoxel;
|
||||
|
||||
extern int lightPropagationComplexDir[12 * 2];
|
||||
extern int normalFacePositions[3 * 4 * 6];
|
||||
extern int uvFace[2 * 4];
|
||||
// 6 Dirs * 4 vertices * 2 checks * 3 dirs
|
||||
extern int ambientOcclusionVertex[6 * 4 * 2 * 3];
|
||||
extern int layerCheckDirections[2 * 8];
|
||||
|
||||
struct VoxelLight {
|
||||
uint8_t r_light;
|
||||
uint8_t g_light;
|
||||
uint8_t b_light;
|
||||
uint8_t ambient_light;
|
||||
|
||||
VoxelLight(uint8_t _ambient_light = 0) : r_light(0), g_light(0), b_light(0), ambient_light(_ambient_light) { }
|
||||
};
|
||||
}
|
97
Deer/Include/DeerRender/Render/Buffer.h
Executable file
97
Deer/Include/DeerRender/Render/Buffer.h
Executable file
@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
#include "Deer/Memory.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace Deer {
|
||||
enum class ShaderDataType {
|
||||
None = 0,
|
||||
FloatingPoint,
|
||||
NormalizedFloatingPoint,
|
||||
Integer
|
||||
};
|
||||
|
||||
enum class DataType {
|
||||
None = 0,
|
||||
Half, Half2, Half3, Half4,
|
||||
Float, Float2, Float3, Float4,
|
||||
|
||||
Byte, Byte2, Byte3, Byte4,
|
||||
Short, Short2, Short3, Short4,
|
||||
Int, Int2, Int3, Int4,
|
||||
|
||||
Unsigned_Byte, Unsigned_Byte2, Unsigned_Byte3, Unsigned_Byte4,
|
||||
Unsigned_Short, Unsigned_Short2, Unsigned_Short3, Unsigned_Short4,
|
||||
Unsigned_Int, Unsigned_Int2, Unsigned_Int3, Unsigned_Int4
|
||||
};
|
||||
|
||||
enum class IndexDataType {
|
||||
None = 0,
|
||||
Unsigned_Byte,
|
||||
Unsigned_Short,
|
||||
Unsigned_Int,
|
||||
};
|
||||
|
||||
unsigned int dataTypeSize(DataType type);
|
||||
unsigned int dataTypeCount(DataType type);
|
||||
unsigned int indexDataTypeSize(IndexDataType type);
|
||||
|
||||
struct BufferElement {
|
||||
std::string name;
|
||||
DataType type;
|
||||
ShaderDataType shaderType;
|
||||
int offset;
|
||||
|
||||
BufferElement(std::string _name, DataType _type , ShaderDataType _shaderType = ShaderDataType::FloatingPoint,
|
||||
int _offset = -1)
|
||||
: name(_name), type(_type), shaderType(_shaderType), offset(_offset){
|
||||
}
|
||||
};
|
||||
|
||||
class BufferLayout {
|
||||
public:
|
||||
BufferLayout() { }
|
||||
BufferLayout(const std::initializer_list<BufferElement>& elements, int _stride = -1)
|
||||
: m_bufferElements(elements), m_stride(_stride) {
|
||||
calculateOffsetAndStride();
|
||||
}
|
||||
BufferLayout(const std::vector<BufferElement> elements)
|
||||
: m_bufferElements(elements) {
|
||||
calculateOffsetAndStride();
|
||||
}
|
||||
|
||||
inline std::vector<BufferElement>::iterator begin() { return m_bufferElements.begin(); }
|
||||
inline std::vector<BufferElement>::iterator end() { return m_bufferElements.end(); }
|
||||
inline std::vector<BufferElement> getElements() { return m_bufferElements; }
|
||||
inline int getStride() { return m_stride; }
|
||||
private:
|
||||
void calculateOffsetAndStride();
|
||||
|
||||
std::vector<BufferElement> m_bufferElements;
|
||||
int m_stride;
|
||||
};
|
||||
|
||||
class VertexBuffer {
|
||||
public:
|
||||
virtual ~VertexBuffer() = default;
|
||||
|
||||
virtual void bind() const = 0;
|
||||
virtual void setLayout(BufferLayout& layout) = 0;
|
||||
virtual BufferLayout& getLayout() = 0;
|
||||
|
||||
static Ref<VertexBuffer> create(void* data, unsigned int size);
|
||||
};
|
||||
|
||||
class IndexBuffer {
|
||||
public:
|
||||
virtual ~IndexBuffer() = default;
|
||||
|
||||
virtual void bind() const = 0;
|
||||
virtual unsigned int getCount() const = 0;
|
||||
virtual IndexDataType getIndexDataType() const = 0;
|
||||
|
||||
static Ref<IndexBuffer> create(void* data, unsigned int size, IndexDataType indexDataType);
|
||||
};
|
||||
}
|
||||
|
35
Deer/Include/DeerRender/Render/Camera.h
Executable file
35
Deer/Include/DeerRender/Render/Camera.h
Executable file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include "glm/glm.hpp"
|
||||
#include "glm/gtc/quaternion.hpp"
|
||||
|
||||
namespace Deer {
|
||||
class Camera {
|
||||
public:
|
||||
Camera(float aspect, float fov = 60, float nearZ = 0.1f, float farZ = 500);
|
||||
|
||||
void setPosition(const glm::vec3& position) { m_position = position; }
|
||||
const glm::vec3& getPosition() { return m_position; }
|
||||
|
||||
void setRotation(const glm::quat& rotation) { m_rotation = rotation; }
|
||||
const glm::quat& getRotation() { return m_rotation; }
|
||||
|
||||
void setAspect(float aspect) { m_aspect = aspect; }
|
||||
float getAspect() { return m_aspect; }
|
||||
|
||||
void setFov(float fov) { m_fov = fov; }
|
||||
float getFov() { return m_fov; }
|
||||
|
||||
void recalculateMatrices();
|
||||
const glm::mat4& getProjectionMatrix() { return m_projectionMatrix; }
|
||||
const glm::mat4& getViewMatrix() { return m_viewMatrix; }
|
||||
private:
|
||||
float m_fov, m_aspect, m_nearZ, m_farZ;
|
||||
glm::mat4 m_projectionMatrix;
|
||||
glm::mat4 m_viewMatrix;
|
||||
|
||||
glm::vec3 m_position;
|
||||
glm::quat m_rotation;
|
||||
};
|
||||
}
|
||||
|
44
Deer/Include/DeerRender/Render/FrameBuffer.h
Executable file
44
Deer/Include/DeerRender/Render/FrameBuffer.h
Executable file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "Deer/Log.h"
|
||||
|
||||
#include <vector>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace Deer {
|
||||
enum class TextureBufferType {
|
||||
RGBA8,
|
||||
RED_INTEGER
|
||||
};
|
||||
|
||||
struct FrameBufferSpecification {
|
||||
unsigned int width, height;
|
||||
unsigned int samples;
|
||||
std::vector<TextureBufferType> frameBufferTextures;
|
||||
|
||||
bool swapChainTarget = false;
|
||||
FrameBufferSpecification(unsigned int _width, unsigned int _height, std::initializer_list<TextureBufferType> _frameBufferTextures, unsigned int _samples = 1, bool _swapChainTarget = false)
|
||||
: width(_width), height(_height), samples(_samples), frameBufferTextures(_frameBufferTextures), swapChainTarget(_swapChainTarget) {
|
||||
}
|
||||
};
|
||||
|
||||
class FrameBuffer {
|
||||
public:
|
||||
virtual ~FrameBuffer() = default;
|
||||
virtual const FrameBufferSpecification& getSpecification() = 0;
|
||||
|
||||
virtual void bind() = 0;
|
||||
virtual void unbind() = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
virtual void resize(unsigned int width, unsigned int height) = 0;
|
||||
|
||||
virtual unsigned int getTextureBufferID(int id = 0) = 0;
|
||||
virtual void clearBuffer(unsigned int bufferId, void* data) = 0;
|
||||
|
||||
virtual int getTextureBufferPixel(int id, unsigned int x, unsigned int y) = 0;
|
||||
|
||||
static Ref<FrameBuffer> create(const FrameBufferSpecification& spec);
|
||||
};
|
||||
}
|
||||
|
26
Deer/Include/DeerRender/Render/Shader.h
Executable file
26
Deer/Include/DeerRender/Render/Shader.h
Executable file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "Deer/Memory.h"
|
||||
|
||||
#include "glm/glm.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Deer {
|
||||
class Shader {
|
||||
public:
|
||||
virtual void bind() const = 0;
|
||||
virtual ~Shader() = default;
|
||||
|
||||
virtual void uploadUniformFloat(const std::string& name, float value) = 0;
|
||||
virtual void uploadUniformFloat2(const std::string& name, const glm::vec2& value) = 0;
|
||||
virtual void uploadUniformFloat3(const std::string& name, const glm::vec3& value) = 0;
|
||||
virtual void uploadUniformFloat4(const std::string& name, const glm::vec4& value) = 0;
|
||||
|
||||
virtual void uploadUniformInt(const std::string& name, int value) = 0;
|
||||
virtual void uploadUniformMat4(const std::string& name, const glm::mat4 mat) = 0;
|
||||
|
||||
static Ref<Shader> create(const std::string& filePath);
|
||||
static Ref<Shader> create(uint8_t* data, uint32_t size);
|
||||
static Ref<Shader> create(const std::string& vertexSrc, const std::string& fragmentSrc);
|
||||
};
|
||||
}
|
26
Deer/Include/DeerRender/Render/Texture.h
Executable file
26
Deer/Include/DeerRender/Render/Texture.h
Executable file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "Deer/Memory.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Deer {
|
||||
class Texture {
|
||||
public:
|
||||
virtual ~Texture() = default;
|
||||
|
||||
virtual unsigned int getWidth() = 0;
|
||||
virtual unsigned int getHeight() = 0;
|
||||
virtual unsigned int getTextureID() = 0;
|
||||
|
||||
virtual void bind(unsigned int slot) = 0;
|
||||
virtual void unbind(unsigned int slot) = 0;
|
||||
};
|
||||
|
||||
class Texture2D : public Texture {
|
||||
public:
|
||||
static Ref<Texture2D> create(const std::string&);
|
||||
static Ref<Texture2D> create(uint8_t* data, uint32_t size);
|
||||
static Ref<Texture2D> create(uint8_t* data, uint32_t width, uint32_t height, int channels);
|
||||
};
|
||||
}
|
||||
|
27
Deer/Include/DeerRender/Render/VertexArray.h
Executable file
27
Deer/Include/DeerRender/Render/VertexArray.h
Executable file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include "DeerRender/Render/Buffer.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace Deer {
|
||||
class VertexArray;
|
||||
using Mesh = VertexArray;
|
||||
|
||||
class VertexArray {
|
||||
public:
|
||||
virtual ~VertexArray() = default;
|
||||
|
||||
virtual void bind() const = 0;
|
||||
virtual void unbind() const = 0;
|
||||
|
||||
virtual void addVertexBuffer(const Ref<VertexBuffer>& vertexBuffer) = 0;
|
||||
virtual void setIndexBuffer(const Ref<IndexBuffer>& indexBuffer) = 0;
|
||||
|
||||
virtual const Ref<IndexBuffer>& getIndexBuffer() = 0;
|
||||
|
||||
static Ref<VertexArray> create();
|
||||
static Ref<VertexArray> create(uint8_t* data, uint32_t size);
|
||||
};
|
||||
}
|
||||
|
12
Deer/Include/DeerRender/SceneCamera.h
Executable file
12
Deer/Include/DeerRender/SceneCamera.h
Executable file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "DeerRender/Components.h"
|
||||
|
||||
namespace Deer {
|
||||
struct SceneCamera {
|
||||
TransformComponent transform;
|
||||
CameraComponent camera;
|
||||
|
||||
SceneCamera() {}
|
||||
SceneCamera(TransformComponent _transform, CameraComponent _camera) : transform(_transform), camera(_camera) { }
|
||||
};
|
||||
}
|
54
Deer/Include/DeerRender/VoxelAspect.h
Normal file
54
Deer/Include/DeerRender/VoxelAspect.h
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @file VoxelAspect.h
|
||||
* @author chewico@frostdeer.com
|
||||
* @brief File to save the voxel aspect data
|
||||
*
|
||||
* @copyright Copyright (c) 2025
|
||||
*/
|
||||
#pragma once
|
||||
#include "Deer/Voxel.h"
|
||||
|
||||
// TEMP
|
||||
#define VOXEL_TEXTURE_SIZE_X 128
|
||||
#define VOXEL_TEXTURE_SIZE_Y 128
|
||||
|
||||
namespace Deer {
|
||||
struct VoxelTextureFaceDefinition {
|
||||
std::string textureFaces[6];
|
||||
|
||||
inline std::string& operator[](size_t index) {
|
||||
return textureFaces[index];
|
||||
}
|
||||
};
|
||||
|
||||
struct VoxelColorEmission {
|
||||
uint8_t r_value = 0;
|
||||
uint8_t g_value = 0;
|
||||
uint8_t b_value = 0;
|
||||
};
|
||||
|
||||
struct VoxelAspectDefinition {
|
||||
std::string voxelName;
|
||||
VoxelTextureFaceDefinition textureFaces;
|
||||
VoxelColorEmission colorEmission;
|
||||
|
||||
VoxelAspectDefinition() = default;
|
||||
};
|
||||
|
||||
struct VoxelAspect {
|
||||
VoxelAspectDefinition definition;
|
||||
uint16_t textureFacesIDs[6]{};
|
||||
|
||||
inline bool isLightSource() {
|
||||
return definition.colorEmission.r_value || definition.colorEmission.g_value || definition.colorEmission.b_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the texture id for the voxel face
|
||||
*
|
||||
* @param face face of the texture defined in the enum NormalDirection of Voxel.h
|
||||
* @return uint16_t texture id in the texture atlas
|
||||
*/
|
||||
inline uint16_t getTextureID(uint8_t face) { return textureFacesIDs[face]; }
|
||||
};
|
||||
}
|
46
Deer/Include/DeerRender/Window.h
Executable file
46
Deer/Include/DeerRender/Window.h
Executable file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include "DeerRender/Events/Event.h"
|
||||
#include "Deer/Path.h"
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace Deer {
|
||||
struct WindowProps {
|
||||
std::string title;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
|
||||
WindowProps(const std::string& _title = "Deer Engine",
|
||||
unsigned int _width = 1280,
|
||||
unsigned int _height = 720)
|
||||
: title(_title), width(_width), height(_height) {
|
||||
}
|
||||
};
|
||||
|
||||
class Window {
|
||||
public:
|
||||
virtual ~Window() = default;
|
||||
virtual void initWindow() = 0;
|
||||
|
||||
virtual void onRender() = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual void resolveEvents() = 0;
|
||||
|
||||
inline virtual int getWitdth() const = 0;
|
||||
inline virtual int getHeight() const = 0;
|
||||
|
||||
virtual void setEventCallback(std::function<void(Event&)>) = 0;
|
||||
virtual void setVSync(bool enabled) = 0;
|
||||
inline virtual bool isVSync() const = 0;
|
||||
|
||||
virtual bool getKeyPressed(unsigned int key) = 0;
|
||||
virtual bool getMouseButton(int button) = 0;
|
||||
virtual void getMousePos(float& x, float& y) = 0;
|
||||
virtual void initImGUI() = 0;
|
||||
|
||||
virtual Path folderDialog(const char*) = 0;
|
||||
|
||||
static Window* create(const WindowProps& props = WindowProps());
|
||||
};
|
||||
}
|
6
Deer/src/Deer/Asset/AssetManager.cpp
Executable file
6
Deer/src/Deer/Asset/AssetManager.cpp
Executable file
@ -0,0 +1,6 @@
|
||||
#include "Deer/Asset.h"
|
||||
|
||||
namespace Deer {
|
||||
std::vector<Asset<void>> AssetManager::assets;
|
||||
}
|
||||
|
140
Deer/src/Deer/Core/Application.cpp
Executable file
140
Deer/src/Deer/Core/Application.cpp
Executable file
@ -0,0 +1,140 @@
|
||||
#include "Deer/Application.h"
|
||||
#include "Deer/Log.h"
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
#include "DeerRender/Render/RenderCommand.h"
|
||||
#include "DeerRender/Render/Render.h"
|
||||
#include "DeerRender/Render/RenderUtils.h"
|
||||
#include "DeerRender/ImGui/ImGuiLayer.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#include <functional>
|
||||
#endif
|
||||
|
||||
namespace Deer {
|
||||
namespace Core {
|
||||
int argc;
|
||||
char **argv;
|
||||
}
|
||||
|
||||
Application* Application::s_application;
|
||||
|
||||
Application::Application() : m_running(false) {
|
||||
#ifdef DEER_RENDER
|
||||
m_window = Scope<Window>(Window::create(m_windowProps));
|
||||
m_imGuiLayer = MakeScope<ImGuiLayer>();
|
||||
#endif
|
||||
}
|
||||
|
||||
Application::~Application() { }
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
Application::Application(const WindowProps& props)
|
||||
: m_running(false), m_windowProps(props) {
|
||||
m_window = Scope<Window>(Window::create(m_windowProps));
|
||||
m_imGuiLayer = MakeScope<ImGuiLayer>();
|
||||
}
|
||||
|
||||
void Application::initializeWindow() {
|
||||
m_window->initWindow();
|
||||
m_window->setEventCallback(std::bind(&Application::onEventCallback, this, std::placeholders::_1));
|
||||
}
|
||||
#endif
|
||||
|
||||
int Application::run() {
|
||||
s_application = this;
|
||||
m_running = true;
|
||||
|
||||
const double targetUpdateTime = 1.0 / 60.0; // Fixed 60 FPS update
|
||||
double targetRenderTime = 1.0 / 120.0; // User-defined render FPS
|
||||
|
||||
auto previousTime = std::chrono::high_resolution_clock::now();
|
||||
double accumulatedUpdateTime = 0.0;
|
||||
double accumulatedRenderTime = 0.0;
|
||||
|
||||
int res = onPreInit();
|
||||
if (res != 0)
|
||||
return res;
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
initializeWindow();
|
||||
m_imGuiLayer->onAttach();
|
||||
RenderUtils::initializeRenderUtils();
|
||||
RenderCommand::init();
|
||||
#endif
|
||||
|
||||
res = onInit();
|
||||
if (res != 0){
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
m_imGuiLayer->onDetach();
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
while (m_running) {
|
||||
// Time handling
|
||||
auto currentTime = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> deltaTime = currentTime - previousTime;
|
||||
previousTime = currentTime;
|
||||
|
||||
accumulatedUpdateTime += deltaTime.count();
|
||||
accumulatedRenderTime += deltaTime.count();
|
||||
|
||||
// Fixed Update loop (60 FPS)
|
||||
while (accumulatedUpdateTime >= targetUpdateTime) {
|
||||
Timestep timestep = (float)targetUpdateTime;
|
||||
onUpdate(timestep);
|
||||
accumulatedUpdateTime -= targetUpdateTime;
|
||||
}
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
// Render loop (User-defined FPS)
|
||||
if (accumulatedRenderTime >= targetRenderTime) {
|
||||
RenderCommand::setClearColor({ 0.2f, 0.2f, 0.3f, 1.0f });
|
||||
RenderCommand::clear();
|
||||
|
||||
Render::beginExecution();
|
||||
onRender(Timestep((float)targetRenderTime));
|
||||
Render::endExecution();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DeltaTime = (float)targetRenderTime;
|
||||
m_imGuiLayer->begin();
|
||||
onImGUI();
|
||||
m_imGuiLayer->end();
|
||||
|
||||
accumulatedRenderTime -= targetRenderTime;
|
||||
|
||||
m_window->onRender();
|
||||
}
|
||||
|
||||
m_window->resolveEvents();
|
||||
#endif
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
m_imGuiLayer->onDetach();
|
||||
#endif
|
||||
onShutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
void Application::onEventCallback(Event& e) {
|
||||
onEvent(e);
|
||||
m_imGuiLayer->onEvent(e);
|
||||
|
||||
EventDispatcher dispatcher(e);
|
||||
dispatcher.dispatch<WindowCloseEvent>(std::bind(&Application::onWindowClose, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
bool Application::onWindowClose(WindowCloseEvent& e)
|
||||
{
|
||||
m_running = false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
33
Deer/src/Deer/Core/Log.cpp
Executable file
33
Deer/src/Deer/Core/Log.cpp
Executable file
@ -0,0 +1,33 @@
|
||||
#include "Deer/Log.h"
|
||||
|
||||
namespace Deer {
|
||||
std::shared_ptr<spdlog::logger> Log::coreLogger;
|
||||
std::shared_ptr<spdlog::logger> Log::clientLogger;
|
||||
std::shared_ptr<spdlog::logger> Log::scriptLogger;
|
||||
|
||||
void Log::init()
|
||||
{
|
||||
spdlog::set_pattern("%^[%T] %n: %v%$");
|
||||
|
||||
coreLogger = spdlog::stdout_color_mt("Core");
|
||||
clientLogger = spdlog::stdout_color_mt("Client");
|
||||
scriptLogger = spdlog::stdout_color_mt("Script");
|
||||
|
||||
coreLogger->set_level(spdlog::level::level_enum::trace);
|
||||
clientLogger->set_level(spdlog::level::level_enum::trace);
|
||||
scriptLogger->set_level(spdlog::level::level_enum::trace);
|
||||
}
|
||||
|
||||
void Log::shutdown() {
|
||||
coreLogger.reset();
|
||||
clientLogger.reset();
|
||||
scriptLogger.reset();
|
||||
|
||||
spdlog::drop_all();
|
||||
}
|
||||
|
||||
void Log::coreTrace(const char* msg)
|
||||
{
|
||||
//coreLogger->trace(msg);
|
||||
}
|
||||
}
|
113
Deer/src/Deer/DataStore/DataStore.cpp
Executable file
113
Deer/src/Deer/DataStore/DataStore.cpp
Executable file
@ -0,0 +1,113 @@
|
||||
#include "Deer/DataStore.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "Deer/Path.h"
|
||||
|
||||
#include "cereal/cereal.hpp"
|
||||
#include "cereal/types/unordered_map.hpp"
|
||||
#include "cereal/archives/portable_binary.hpp"
|
||||
|
||||
#include "Deer/DataStore/DataStructure.h"
|
||||
#include "Deer/DataStore/DataStructureSerialization.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
|
||||
namespace Deer {
|
||||
Path DataStore::rootPath;
|
||||
|
||||
void DataStore::deleteFile(const Path& path) {
|
||||
Path filePath = rootPath / toLowerCasePath(path);
|
||||
std::filesystem::remove(filePath);
|
||||
}
|
||||
|
||||
uint8_t* DataStore::readFile(const Path& path, uint32_t* size) {
|
||||
Path filePath = rootPath / toLowerCasePath(path);
|
||||
std::ifstream file(filePath, std::ios::in | std::ios::binary);
|
||||
|
||||
if (!file) {
|
||||
file.close();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
file.seekg(0, std::ios::end);
|
||||
*size = (size_t)file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
uint8_t* buffer = new uint8_t[*size];
|
||||
|
||||
if (!file.read(reinterpret_cast<char*>(buffer), *size)) {
|
||||
DEER_CORE_ERROR("Failed to read file: {0}", filePath.generic_string().c_str());
|
||||
delete[] buffer;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
file.close();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void DataStore::saveFile(const Path& path, uint8_t* data, uint32_t size) {
|
||||
Path filePath = rootPath / toLowerCasePath(path);
|
||||
std::filesystem::create_directories(filePath.parent_path());
|
||||
|
||||
std::ofstream file(filePath, std::ios::out | std::ios::binary);
|
||||
|
||||
DEER_CORE_ASSERT(file, "Error when writing file {0}", filePath.generic_string().c_str());
|
||||
|
||||
file.write(reinterpret_cast<const char*>(data), size);
|
||||
}
|
||||
|
||||
void DataStore::compressFiles(std::vector<Path> files, const Path& path) {
|
||||
std::unordered_map<Path, DataStructure> dataStructure;
|
||||
std::vector<uint8_t> combinedData;
|
||||
|
||||
for (const Path& inputPath : files) {
|
||||
uint32_t fileSize = 0;
|
||||
uint8_t* fileData = readFile(inputPath, &fileSize);
|
||||
|
||||
uint32_t start = combinedData.size();
|
||||
|
||||
combinedData.insert(combinedData.end(), fileData, fileData + fileSize);
|
||||
dataStructure[inputPath] = DataStructure{
|
||||
.dataPath = inputPath,
|
||||
.dataStart = start,
|
||||
.dataSize = fileSize
|
||||
};
|
||||
|
||||
delete[] fileData;
|
||||
}
|
||||
|
||||
Path compressedPath = path;
|
||||
compressedPath += ".deer";
|
||||
Path metaPath = path;
|
||||
metaPath += ".deer.meta";
|
||||
|
||||
std::stringstream buffer;
|
||||
{
|
||||
cereal::PortableBinaryOutputArchive archive(buffer);
|
||||
archive(dataStructure);
|
||||
}
|
||||
|
||||
saveFile(compressedPath, combinedData.data(), combinedData.size());
|
||||
saveFile(metaPath, (uint8_t*)buffer.str().c_str(), buffer.str().size());
|
||||
}
|
||||
|
||||
std::vector<Path> DataStore::getFiles(const Path& path, const std::string& extension) {
|
||||
std::vector<Path> files;
|
||||
Path lookPath = rootPath / path;
|
||||
|
||||
for (const auto& entry : std::filesystem::recursive_directory_iterator(lookPath)) {
|
||||
if (std::filesystem::is_regular_file(entry) && entry.path().extension() == extension) {
|
||||
files.push_back(entry.path().lexically_relative(rootPath));
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
void DataStore::createFolder(const Path& path) {
|
||||
std::filesystem::create_directories(path);
|
||||
}
|
||||
}
|
11
Deer/src/Deer/DataStore/DataStructure.h
Executable file
11
Deer/src/Deer/DataStore/DataStructure.h
Executable file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "Deer/Path.h"
|
||||
|
||||
namespace Deer {
|
||||
struct DataStructure {
|
||||
Path dataPath;
|
||||
uint32_t dataStart;
|
||||
uint32_t dataSize;
|
||||
};
|
||||
}
|
36
Deer/src/Deer/DataStore/DataStructureSerialization.h
Executable file
36
Deer/src/Deer/DataStore/DataStructureSerialization.h
Executable file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include "Deer/DataStore/DataStructure.h"
|
||||
#include "Deer/Path.h"
|
||||
|
||||
#include "cereal/cereal.hpp"
|
||||
#include "cereal/types/string.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace cereal {
|
||||
template<class Archive>
|
||||
void save(Archive& archive,
|
||||
std::filesystem::path const& path)
|
||||
{
|
||||
archive(path.generic_string());
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive& archive,
|
||||
std::filesystem::path& path)
|
||||
{
|
||||
std::string _path;
|
||||
archive(_path);
|
||||
path = std::filesystem::path(_path);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Deer {
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive,
|
||||
DataStructure& ds)
|
||||
{
|
||||
archive(ds.dataPath, ds.dataStart, ds.dataSize);
|
||||
}
|
||||
}
|
9
Deer/src/Deer/DataStore/Path.cpp
Normal file
9
Deer/src/Deer/DataStore/Path.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "Deer/Path.h"
|
||||
#include <algorithm>
|
||||
|
||||
Deer::Path Deer::toLowerCasePath(const Path& inputPath) {
|
||||
std::string pathStr = inputPath.generic_string();
|
||||
std::transform(pathStr.begin(), pathStr.end(), pathStr.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
return Path(pathStr);
|
||||
}
|
14
Deer/src/Deer/Scene/Components.cpp
Executable file
14
Deer/src/Deer/Scene/Components.cpp
Executable file
@ -0,0 +1,14 @@
|
||||
#include "Deer/Components.h"
|
||||
#include "glm/gtc/matrix_transform.hpp"
|
||||
#include "Deer/Log.h"
|
||||
|
||||
namespace Deer {
|
||||
glm::mat4 TransformComponent::getMatrix() const{
|
||||
glm::mat4 scaleMat = glm::scale(glm::mat4(1.0f), scale);
|
||||
glm::mat4 roatationMat = glm::mat4(rotation);
|
||||
glm::mat4 positionMat = glm::translate(glm::mat4(1.0f), position);
|
||||
|
||||
return positionMat * roatationMat * scaleMat;
|
||||
}
|
||||
|
||||
}
|
127
Deer/src/Deer/Scene/Entity.cpp
Executable file
127
Deer/src/Deer/Scene/Entity.cpp
Executable file
@ -0,0 +1,127 @@
|
||||
#include "Deer/Enviroment.h"
|
||||
#include "Deer/Components.h"
|
||||
|
||||
namespace Deer {
|
||||
Entity Entity::nullEntity = Entity();
|
||||
|
||||
Entity::Entity(entt::entity handle, Environment* scene)
|
||||
: m_entityHandle(handle), m_environment(scene) {
|
||||
}
|
||||
|
||||
bool Entity::removeChild(Entity& child) {
|
||||
DEER_CORE_ASSERT(child.m_environment == m_environment, "Can not remove childrens from diferent enviroments");
|
||||
|
||||
std::vector<uint32_t>& children = getChildren();
|
||||
|
||||
auto it = std::find(children.begin(), children.end(), child.m_entityUID);
|
||||
if (it != children.end())
|
||||
{
|
||||
children.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Entity::setParent(Entity& parent) {
|
||||
DEER_CORE_ASSERT(parent.m_environment == m_environment , "Can not set parent from diferent enviroments");
|
||||
DEER_CORE_ASSERT(!isRoot(), "Can not set parent to root");
|
||||
DEER_CORE_ASSERT(parent.isValid(), "Parent is not valid");
|
||||
|
||||
if (m_parentUID == parent.m_entityUID)
|
||||
return;
|
||||
|
||||
if (m_parentUID != 0){
|
||||
Entity& current_parent = getParent();
|
||||
if (parent.isDescendant(*this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
current_parent.removeChild(*this);
|
||||
}
|
||||
|
||||
m_parentUID = parent.m_entityUID;
|
||||
getComponent<RelationshipComponent>().parent_UID = parent.m_entityUID;
|
||||
parent.getChildren().push_back(m_entityUID);
|
||||
}
|
||||
|
||||
bool Entity::isDescendant(Entity& parent) {
|
||||
if (m_entityUID == parent.m_entityUID)
|
||||
return true;
|
||||
|
||||
if (isRoot())
|
||||
return false;
|
||||
|
||||
return getParent().isDescendant(parent);
|
||||
}
|
||||
|
||||
Entity& Entity::duplicate() {
|
||||
Entity& creation = m_environment->createEntity(getComponent<TagComponent>().tag + "(d)");
|
||||
|
||||
creation.getComponent<TransformComponent>() = getComponent<TransformComponent>();
|
||||
Entity& parent = m_environment->getEntity(m_parentUID);
|
||||
creation.setParent(parent);
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
if (m_environment->m_registry.any_of<MeshRenderComponent>(m_entityHandle))
|
||||
creation.addComponent<MeshRenderComponent>(getComponent<MeshRenderComponent>());
|
||||
|
||||
if (m_environment->m_registry.any_of<CameraComponent>(m_entityHandle))
|
||||
creation.addComponent<CameraComponent>(getComponent<CameraComponent>());
|
||||
|
||||
if (m_environment->m_registry.any_of<TextureBindingComponent>(m_entityHandle))
|
||||
creation.addComponent<TextureBindingComponent>(getComponent<TextureBindingComponent>());
|
||||
#endif
|
||||
return creation;
|
||||
}
|
||||
|
||||
void Entity::destroy() {
|
||||
DEER_CORE_ASSERT(!isRoot(), "Can not destroy the root");
|
||||
getParent().removeChild(*this);
|
||||
|
||||
if (m_environment->tryGetMainCamera() == m_entityUID)
|
||||
m_environment->setMainCamera(nullEntity);
|
||||
|
||||
for (auto entt : getChildren()) {
|
||||
m_environment->getEntity(entt).destroy();
|
||||
}
|
||||
|
||||
m_environment->m_registry.destroy(m_entityHandle);
|
||||
m_entityHandle = entt::null;
|
||||
m_environment = nullptr;
|
||||
m_entityUID = 0;
|
||||
}
|
||||
|
||||
Entity& Entity::getParent() {
|
||||
return m_environment->getEntity(m_parentUID);
|
||||
}
|
||||
|
||||
std::vector<uint32_t>& Entity::getChildren() {
|
||||
return getComponent<RelationshipComponent>().children;
|
||||
}
|
||||
|
||||
glm::mat4 Entity::getWorldMatrix() {
|
||||
if (isRoot())
|
||||
return glm::mat4(1.0f);
|
||||
|
||||
return getParent().getWorldMatrix() * getRelativeMatrix();
|
||||
}
|
||||
|
||||
glm::mat4 Entity::getRelativeMatrix() {
|
||||
return getComponent<TransformComponent>().getMatrix();
|
||||
}
|
||||
|
||||
void Entity::updateInternalVars() {
|
||||
TagComponent& tag = getComponent<TagComponent>();
|
||||
RelationshipComponent& relation = getComponent<RelationshipComponent>();
|
||||
|
||||
m_entityUID = tag.entityUID;
|
||||
m_parentUID = relation.parent_UID;
|
||||
m_isRoot = relation.parent_UID == 0;
|
||||
|
||||
if (m_isRoot)
|
||||
m_environment->m_rootEntity = tag.entityUID;
|
||||
m_environment->m_entities[tag.entityUID] = *this;
|
||||
}
|
||||
}
|
||||
|
88
Deer/src/Deer/Scene/Enviroment.cpp
Executable file
88
Deer/src/Deer/Scene/Enviroment.cpp
Executable file
@ -0,0 +1,88 @@
|
||||
#include "Deer/Enviroment.h"
|
||||
#include "Deer/Application.h"
|
||||
#include "Deer/Asset.h"
|
||||
|
||||
#include "Deer/Components.h"
|
||||
#include "DeerRender/Render/Render.h"
|
||||
#include "DeerRender/Render/RenderUtils.h"
|
||||
#include "DeerRender/Render/Texture.h"
|
||||
|
||||
#include "Deer/Log.h"
|
||||
|
||||
namespace Deer {
|
||||
Environment::Environment() {
|
||||
clear();
|
||||
}
|
||||
|
||||
Environment::~Environment() { }
|
||||
|
||||
void Environment::clear() {
|
||||
// Clear all existing entities and map
|
||||
m_registry.clear();
|
||||
m_entities.clear();
|
||||
|
||||
m_rootEntity = 0;
|
||||
m_mainCamera = 0;
|
||||
m_idCreationOffset = 0;
|
||||
|
||||
m_rootEntity = pullEntityID();
|
||||
|
||||
entt::entity rootEntity = m_registry.create();
|
||||
Entity entity = { rootEntity, this };
|
||||
|
||||
entity.addComponent<TagComponent>("root", m_rootEntity);
|
||||
entity.addComponent<RelationshipComponent>();
|
||||
entity.addComponent<TransformComponent>();
|
||||
|
||||
entity.m_isRoot = true;
|
||||
entity.m_entityUID = m_rootEntity;
|
||||
m_entities.insert({ m_rootEntity, entity });
|
||||
}
|
||||
|
||||
Entity& Environment::getEntity(uint32_t id) {
|
||||
DEER_CORE_ASSERT(m_entities.contains(id), "Entity id : {0} does not exist", id);
|
||||
return m_entities[id];
|
||||
}
|
||||
|
||||
Entity& Environment::createEntity(const std::string& name)
|
||||
{
|
||||
uint32_t id;
|
||||
do {
|
||||
id = pullEntityID();
|
||||
} while (m_entities.contains(id));
|
||||
|
||||
entt::entity entityID = m_registry.create();
|
||||
Entity entity = { entityID, this };
|
||||
entity.addComponent<TagComponent>(name, id);
|
||||
entity.addComponent<RelationshipComponent>();
|
||||
entity.addComponent<TransformComponent>();
|
||||
|
||||
entity.m_entityUID = id;
|
||||
entity.setParent(getRoot());
|
||||
|
||||
m_entities.insert({ id, entity });
|
||||
return m_entities[id];
|
||||
}
|
||||
|
||||
Entity Environment::createEmptyEntity() {
|
||||
entt::entity entityID = m_registry.create();
|
||||
Entity entity = { entityID, this };
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
uint32_t Environment::tryGetMainCamera() {
|
||||
return m_mainCamera;
|
||||
}
|
||||
|
||||
void Environment::setMainCamera(Entity& entity) {
|
||||
if (!entity.isValid())
|
||||
m_mainCamera = 0;
|
||||
|
||||
m_mainCamera = entity.m_entityUID;
|
||||
}
|
||||
|
||||
Entity& Environment::getRoot() {
|
||||
return m_entities[m_rootEntity];
|
||||
}
|
||||
}
|
77
Deer/src/Deer/Scene/Scene.cpp
Executable file
77
Deer/src/Deer/Scene/Scene.cpp
Executable file
@ -0,0 +1,77 @@
|
||||
#include "Deer/Scene.h"
|
||||
#include "Deer/Memory.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "Deer/VoxelWorld.h"
|
||||
#include "Deer/Enviroment.h"
|
||||
#include "Deer/Voxels/Chunk.h"
|
||||
#include "Deer/Voxels/Layer.h"
|
||||
|
||||
#include "Deer/ScriptEngine.h"
|
||||
#include "Deer/Components.h"
|
||||
#include "Deer/ComponentScript.h"
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
|
||||
#endif
|
||||
|
||||
namespace Deer {
|
||||
Scene::Scene() {
|
||||
m_enviroment = Ref<Environment>(new Environment());
|
||||
}
|
||||
|
||||
void Scene::beginExecution() {
|
||||
DEER_CORE_ASSERT(!m_isExecuting, "Deer scene is already executing");
|
||||
m_isExecuting = true;
|
||||
|
||||
DEER_CORE_INFO("Executing Scene...");
|
||||
ScriptEngine::beginExecutionContext(this);
|
||||
|
||||
// Instantiate all the scripts
|
||||
auto view = m_enviroment->m_registry.view<ScriptComponent, TagComponent>();
|
||||
for (auto& entID : view) {
|
||||
auto& tagComponent = view.get<TagComponent>(entID);
|
||||
auto& componentScript = view.get<ScriptComponent>(entID);
|
||||
|
||||
Entity& entity = m_enviroment->getEntity(tagComponent.entityUID);
|
||||
componentScript.roeInstance = ScriptEngine::createComponentScriptInstance(componentScript.scriptID, entity);
|
||||
|
||||
componentScript.roeInstance->start();
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::updateInternalVars() {
|
||||
// Update all scripts
|
||||
auto view = m_enviroment->m_registry.view<ScriptComponent>();
|
||||
for (auto& entID : view) {
|
||||
auto& componentScript = view.get<ScriptComponent>(entID);
|
||||
componentScript.roeInstance->updateInternalVars();
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::endExecution() {
|
||||
DEER_CORE_ASSERT(m_isExecuting, "Deer scene is not executing");
|
||||
m_isExecuting = false;
|
||||
|
||||
// Deatach all scripts
|
||||
auto view = m_enviroment->m_registry.view<ScriptComponent>();
|
||||
for (auto& entID : view) {
|
||||
auto& componentScript = view.get<ScriptComponent>(entID);
|
||||
componentScript.roeInstance.reset();
|
||||
}
|
||||
|
||||
DEER_CORE_INFO("Stoping Scene...");
|
||||
}
|
||||
|
||||
void Scene::createVoxelWorld(const VoxelWorldProps& props) {
|
||||
m_voxelWorld = Ref<VoxelWorld>(new VoxelWorld(props));
|
||||
}
|
||||
|
||||
void Scene::deleteVoxelWorld() {
|
||||
m_voxelWorld.reset();
|
||||
}
|
||||
|
||||
void Scene::clear() {
|
||||
m_enviroment->clear();
|
||||
m_voxelWorld.reset();
|
||||
}
|
||||
}
|
130
Deer/src/Deer/Scene/SceneDataStore.cpp
Executable file
130
Deer/src/Deer/Scene/SceneDataStore.cpp
Executable file
@ -0,0 +1,130 @@
|
||||
#include "Deer/Scene.h"
|
||||
#include "cereal/archives/json.hpp"
|
||||
#include "cereal/archives/portable_binary.hpp"
|
||||
|
||||
#include "Deer/Scene/Serialization/Serialization.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace Deer {
|
||||
Scene loadSceneJson(uint8_t* data, uint32_t size);
|
||||
Scene loadSceneBin(uint8_t* data, uint32_t size);
|
||||
|
||||
Scene SceneDataStore::loadScene(const Path& name) {
|
||||
Path realName;
|
||||
realName = Path(DEER_SCENE_PATH) / (name.string() + ".dscn");
|
||||
|
||||
uint32_t size;
|
||||
uint8_t* data = DataStore::readFile(realName, &size);
|
||||
|
||||
Scene scene_data;
|
||||
scene_data = loadSceneJson(data, size);
|
||||
|
||||
delete[] data;
|
||||
return scene_data;
|
||||
}
|
||||
|
||||
Scene loadSceneJson(uint8_t* data, uint32_t size) {
|
||||
std::string strData((char*)data, size);
|
||||
std::istringstream stream(strData);
|
||||
|
||||
Scene scene;
|
||||
{
|
||||
cereal::JSONInputArchive archive(stream);
|
||||
archive(cereal::make_nvp("scene", scene));
|
||||
}
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
Scene loadSceneBin(uint8_t* data, uint32_t size) {
|
||||
std::string strData((char*)data, size);
|
||||
std::istringstream stream(strData);
|
||||
|
||||
Scene scene;
|
||||
{
|
||||
cereal::PortableBinaryInputArchive archive(stream);
|
||||
archive(cereal::make_nvp("scene", scene));
|
||||
}
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
void SceneDataStore::deleteSceneJson(const Path& name) {
|
||||
DataStore::deleteFile((Path(DEER_SCENE_PATH) / (name.generic_string() + ".dscn")));
|
||||
}
|
||||
|
||||
void SceneDataStore::exportSceneJson(Scene& scene, const Path& name) {
|
||||
is_server_serialization = false;
|
||||
|
||||
std::stringstream output;
|
||||
{
|
||||
cereal::JSONOutputArchive archive(output);
|
||||
archive(cereal::make_nvp("scene", scene));
|
||||
}
|
||||
|
||||
Path savePath = Path(DEER_SCENE_PATH) / toLowerCasePath((name.generic_string() + ".dscn"));
|
||||
std::string_view view = output.view();
|
||||
|
||||
DataStore::saveFile(savePath, (uint8_t*)view.data(), view.size());
|
||||
}
|
||||
|
||||
void exportSceneBin(Scene& scene, const Path& name) {
|
||||
is_server_serialization = false;
|
||||
|
||||
std::stringstream output;
|
||||
{
|
||||
cereal::PortableBinaryOutputArchive archive(output);
|
||||
archive(cereal::make_nvp("scene", scene));
|
||||
}
|
||||
|
||||
Path savePath = Path(DEER_BIN_PATH) / Path(DEER_SCENE_PATH) / toLowerCasePath((name.generic_string() + ".dbscn"));
|
||||
std::string_view view = output.view();
|
||||
|
||||
DataStore::saveFile(savePath, (uint8_t*)view.data(), view.size());
|
||||
}
|
||||
|
||||
void SceneDataStore::exportScenesBin() {
|
||||
std::vector<Path> scenes = DataStore::getFiles(DEER_SCENE_PATH, ".dscn");
|
||||
|
||||
for (Path& scene_path : scenes) {
|
||||
uint32_t size;
|
||||
uint8_t* data = DataStore::readFile(scene_path, &size);
|
||||
|
||||
Scene scene_data = loadSceneJson(data, size);
|
||||
delete[] data;
|
||||
|
||||
Path name = scene_path.lexically_relative(DEER_SCENE_PATH);
|
||||
name = name.root_path() / name.stem();
|
||||
|
||||
exportSceneBin(scene_data, name);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneDataStore::exportRuntimeScene(Scene& scene) {
|
||||
std::stringstream output;
|
||||
{
|
||||
cereal::PortableBinaryOutputArchive archive(output);
|
||||
archive(cereal::make_nvp("scene", scene));
|
||||
}
|
||||
|
||||
Path savePath = Path(DEER_TEMP_PATH) / "scene_runtime.dbscn";
|
||||
std::string_view view = output.view();
|
||||
|
||||
DataStore::saveFile(savePath, (uint8_t*)view.data(), view.size());
|
||||
}
|
||||
|
||||
Scene SceneDataStore::importRuntimeScene() {
|
||||
Path loadPath = Path(DEER_TEMP_PATH) / "scene_runtime.dbscn";
|
||||
|
||||
uint32_t size;
|
||||
uint8_t* data = DataStore::readFile(loadPath, &size);
|
||||
|
||||
Scene scene_data = loadSceneBin(data, size);
|
||||
delete[] data;
|
||||
|
||||
return scene_data;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "Deer/Components.h"
|
||||
|
||||
namespace Deer {
|
||||
// RELATIONSHIP COMPONENT
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive,
|
||||
RelationshipComponent& relationship) {
|
||||
|
||||
archive(cereal::make_nvp("parentUID", relationship.parent_UID));
|
||||
archive(cereal::make_nvp("childrensUIDs", relationship.children));
|
||||
|
||||
}
|
||||
}
|
12
Deer/src/Deer/Scene/Serialization/Components/ScriptComponentSerialization.h
Executable file
12
Deer/src/Deer/Scene/Serialization/Components/ScriptComponentSerialization.h
Executable file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "Deer/Components.h"
|
||||
|
||||
namespace Deer {
|
||||
// SCRIPT COMPONENT
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive,
|
||||
ScriptComponent& scriptComponent) {
|
||||
|
||||
archive(cereal::make_nvp("scriptID", scriptComponent.scriptID));
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "Deer/Components.h"
|
||||
|
||||
namespace Deer {
|
||||
|
||||
// TRANSFORM COMPONENT
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive,
|
||||
TransformComponent& transform) {
|
||||
|
||||
archive(cereal::make_nvp("position", transform.position));
|
||||
archive(cereal::make_nvp("scale", transform.scale));
|
||||
archive(cereal::make_nvp("rotation", transform.rotation));
|
||||
}
|
||||
|
||||
}
|
83
Deer/src/Deer/Scene/Serialization/EntitySerialization.h
Executable file
83
Deer/src/Deer/Scene/Serialization/EntitySerialization.h
Executable file
@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include "Deer/Components.h"
|
||||
#include "Deer/Scene/Serialization/SerializationGlobalVars.h"
|
||||
|
||||
namespace Deer {
|
||||
template <class Archive, typename T>
|
||||
void saveComponent(Archive& archive, const std::string& componentName, Entity const& m_entity) {
|
||||
|
||||
bool hasComponent = m_entity.hasComponent<T>();
|
||||
archive(cereal::make_nvp(("has_" + componentName).c_str(), hasComponent));
|
||||
if (hasComponent) {
|
||||
T& component = m_entity.getComponent<T>();
|
||||
archive(cereal::make_nvp(componentName.c_str(), component));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, typename T>
|
||||
void loadComponent(Archive& archive, const std::string& componentName, Entity const& m_entity) {
|
||||
|
||||
bool hasComponent;
|
||||
archive(cereal::make_nvp(("has_" + componentName).c_str(), hasComponent));
|
||||
if (hasComponent) {
|
||||
T& component = m_entity.addComponent<T>();
|
||||
archive(cereal::make_nvp(componentName.c_str(), component));
|
||||
}
|
||||
}
|
||||
// ENTITY
|
||||
template<class Archive>
|
||||
void save(Archive& archive,
|
||||
Entity const& m_entity) {
|
||||
|
||||
uint32_t id = m_entity.getUID();
|
||||
|
||||
TagComponent& name = m_entity.getComponent<TagComponent>();
|
||||
archive(cereal::make_nvp("id", id));
|
||||
archive(cereal::make_nvp("name", name.tag));
|
||||
|
||||
TransformComponent& transform = m_entity.getComponent<TransformComponent>();
|
||||
archive(cereal::make_nvp("transform", transform));
|
||||
|
||||
RelationshipComponent& relation = m_entity.getComponent<RelationshipComponent>();
|
||||
archive(cereal::make_nvp("relationship", relation));
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
if (!is_server_serialization) {
|
||||
saveComponent<Archive, MeshRenderComponent>(archive, "meshRenderComponent", m_entity);
|
||||
saveComponent<Archive, CameraComponent>(archive, "cameraComponent", m_entity);
|
||||
saveComponent<Archive, TextureBindingComponent>(archive, "textureBindingComponent", m_entity);
|
||||
}
|
||||
#endif
|
||||
saveComponent<Archive, ScriptComponent>(archive, "scriptComponent", m_entity);
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive& archive,
|
||||
Entity& m_entity) {
|
||||
|
||||
uint32_t id;
|
||||
std::string name;
|
||||
archive(cereal::make_nvp("id", id));
|
||||
archive(cereal::make_nvp("name", name));
|
||||
m_entity.addComponent<TagComponent>() = TagComponent(name, id);
|
||||
|
||||
TransformComponent& transform = m_entity.addComponent<TransformComponent>();
|
||||
archive(cereal::make_nvp("transform", transform));
|
||||
|
||||
RelationshipComponent& relationship = m_entity.addComponent<RelationshipComponent>();
|
||||
archive(cereal::make_nvp("relationship", relationship));
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
if (!is_server_serialization) {
|
||||
loadComponent<Archive, MeshRenderComponent>(archive, "meshRenderComponent", m_entity);
|
||||
loadComponent<Archive, CameraComponent>(archive, "cameraComponent", m_entity);
|
||||
loadComponent<Archive, TextureBindingComponent>(archive, "textureBindingComponent", m_entity);
|
||||
}
|
||||
#endif
|
||||
loadComponent<Archive, ScriptComponent>(archive, "scriptComponent", m_entity);
|
||||
|
||||
m_entity.updateInternalVars();
|
||||
}
|
||||
|
||||
}
|
76
Deer/src/Deer/Scene/Serialization/EnvironmentSerialization.h
Executable file
76
Deer/src/Deer/Scene/Serialization/EnvironmentSerialization.h
Executable file
@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include "Deer/Enviroment.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Deer {
|
||||
struct EntityVector_Environment {
|
||||
std::vector<Entity> entities;
|
||||
const Ref<Environment>& environment;
|
||||
EntityVector_Environment(const Ref<Environment>& _environment)
|
||||
: environment(_environment) { }
|
||||
};
|
||||
|
||||
template<class Archive>
|
||||
void save(Archive& archive,
|
||||
Ref<Environment> const& m_environment) {
|
||||
EntityVector_Environment entityMap(m_environment);
|
||||
auto view = m_environment->m_registry.view<TagComponent>();
|
||||
|
||||
for (auto entity : view) {
|
||||
TagComponent& tag = view.get<TagComponent>(entity);
|
||||
entityMap.entities.push_back(m_environment->getEntity(tag.entityUID));
|
||||
}
|
||||
|
||||
// Sort to avoid conflicts
|
||||
std::sort(entityMap.entities.begin(), entityMap.entities.end(), [](Entity& a, Entity& b) {
|
||||
return a.getUID() < b.getUID();
|
||||
});
|
||||
|
||||
uint32_t mainCameraUID = m_environment->tryGetMainCamera();
|
||||
|
||||
archive(cereal::make_nvp("entities", entityMap));
|
||||
archive(cereal::make_nvp("mainCameraUID", mainCameraUID));
|
||||
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive& archive,
|
||||
Ref<Environment>& m_environment) {
|
||||
EntityVector_Environment entityMap(m_environment);
|
||||
|
||||
uint32_t mainCameraUID;
|
||||
|
||||
archive(cereal::make_nvp("entities", entityMap));
|
||||
archive(cereal::make_nvp("mainCameraUID", mainCameraUID));
|
||||
|
||||
if (mainCameraUID != 0)
|
||||
m_environment->setMainCamera(m_environment->getEntity(mainCameraUID));
|
||||
|
||||
}
|
||||
|
||||
// ENVIRONMENT
|
||||
template<class Archive>
|
||||
void save(Archive& archive,
|
||||
EntityVector_Environment const& m_entityVector) {
|
||||
|
||||
archive(cereal::make_size_tag(static_cast<cereal::size_type>(m_entityVector.entities.size()))); // number of elements
|
||||
for (auto&& v : m_entityVector.entities)
|
||||
archive(v);
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive& archive,
|
||||
EntityVector_Environment& m_entityVector) {
|
||||
|
||||
cereal::size_type size;
|
||||
archive(cereal::make_size_tag(size));
|
||||
|
||||
m_entityVector.entities.resize(static_cast<std::size_t>(size));
|
||||
for (auto& v : m_entityVector.entities) {
|
||||
v = m_entityVector.environment->createEmptyEntity();
|
||||
archive(v);
|
||||
}
|
||||
}
|
||||
}
|
16
Deer/src/Deer/Scene/Serialization/QuatSerialization.h
Executable file
16
Deer/src/Deer/Scene/Serialization/QuatSerialization.h
Executable file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include "glm/gtc/quaternion.hpp"
|
||||
|
||||
namespace cereal {
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive,
|
||||
glm::quat& rot) {
|
||||
|
||||
archive(cereal::make_nvp("x", rot.x));
|
||||
archive(cereal::make_nvp("y", rot.y));
|
||||
archive(cereal::make_nvp("z", rot.z));
|
||||
archive(cereal::make_nvp("w", rot.w));
|
||||
}
|
||||
}
|
12
Deer/src/Deer/Scene/Serialization/SceneSerialization.h
Executable file
12
Deer/src/Deer/Scene/Serialization/SceneSerialization.h
Executable file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Deer/Scene.h"
|
||||
|
||||
namespace Deer {
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive,
|
||||
Scene& m_scene) {
|
||||
|
||||
archive(cereal::make_nvp("main_environment", m_scene.getMainEnviroment()));
|
||||
}
|
||||
}
|
4
Deer/src/Deer/Scene/Serialization/Serialization.cpp
Executable file
4
Deer/src/Deer/Scene/Serialization/Serialization.cpp
Executable file
@ -0,0 +1,4 @@
|
||||
|
||||
namespace Deer {
|
||||
bool is_server_serialization = false;
|
||||
}
|
32
Deer/src/Deer/Scene/Serialization/Serialization.h
Executable file
32
Deer/src/Deer/Scene/Serialization/Serialization.h
Executable file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "Deer/Asset.h"
|
||||
|
||||
|
||||
#include "cereal/cereal.hpp"
|
||||
#include "cereal/types/vector.hpp"
|
||||
#include "cereal/types/string.hpp"
|
||||
|
||||
// Serialization Vars
|
||||
#include "Deer/Scene/Serialization/SerializationGlobalVars.h"
|
||||
|
||||
// GENERICS
|
||||
#include "Deer/Scene/Serialization/Vec3Serialization.h"
|
||||
#include "Deer/Scene/Serialization/QuatSerialization.h"
|
||||
|
||||
// SCENE SPECIFIC
|
||||
#include "Deer/Scene/Serialization/SceneSerialization.h"
|
||||
#include "Deer/Scene/Serialization/EnvironmentSerialization.h"
|
||||
#include "Deer/Scene/Serialization/EntitySerialization.h"
|
||||
|
||||
// COMPONENTS SPECIFIC
|
||||
#include "Deer/Scene/Serialization/Components/TransformComponentSerialization.h"
|
||||
#include "Deer/Scene/Serialization/Components/RelationshipComponentSerialization.h"
|
||||
#include "Deer/Scene/Serialization/Components/ScriptComponentSerialization.h"
|
||||
|
||||
// RENDER SPECIFIC
|
||||
#ifdef DEER_RENDER
|
||||
#include "DeerRender/Scene/Serialization/Components/CameraSerializationComponent.h"
|
||||
#include "DeerRender/Scene/Serialization/Components/MeshRenderComponentSerialization.h"
|
||||
#include "DeerRender/Scene/Serialization/Components/TextureBindingSerializationComponent.h"
|
||||
#endif
|
7
Deer/src/Deer/Scene/Serialization/SerializationGlobalVars.cpp
Executable file
7
Deer/src/Deer/Scene/Serialization/SerializationGlobalVars.cpp
Executable file
@ -0,0 +1,7 @@
|
||||
#include "SerializationGlobalVars.h"
|
||||
|
||||
namespace Deer {
|
||||
|
||||
bool is_server_serialization = false;
|
||||
|
||||
}
|
5
Deer/src/Deer/Scene/Serialization/SerializationGlobalVars.h
Executable file
5
Deer/src/Deer/Scene/Serialization/SerializationGlobalVars.h
Executable file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
namespace Deer {
|
||||
extern bool is_server_serialization;
|
||||
}
|
14
Deer/src/Deer/Scene/Serialization/Vec3Serialization.h
Executable file
14
Deer/src/Deer/Scene/Serialization/Vec3Serialization.h
Executable file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "glm/glm.hpp"
|
||||
|
||||
namespace cereal {
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive,
|
||||
glm::vec3& vec3) {
|
||||
|
||||
archive(
|
||||
cereal::make_nvp("x", vec3.x),
|
||||
cereal::make_nvp("y", vec3.y),
|
||||
cereal::make_nvp("z", vec3.z));
|
||||
}
|
||||
}
|
41
Deer/src/Deer/Scripting/ComponentScript.cpp
Executable file
41
Deer/src/Deer/Scripting/ComponentScript.cpp
Executable file
@ -0,0 +1,41 @@
|
||||
#include "Deer/ComponentScript.h"
|
||||
#include "angelscript.h"
|
||||
|
||||
#include "Deer/Log.h"
|
||||
#include "Deer/ScriptEngine.h"
|
||||
#include "angelscript.h"
|
||||
|
||||
namespace Deer {
|
||||
ComponentScript::ComponentScript(asITypeInfo* typeInfo)
|
||||
: m_typeInfo(typeInfo) {
|
||||
|
||||
m_scriptID = m_typeInfo->GetName();
|
||||
m_attributes = extractAttributes(typeInfo);
|
||||
}
|
||||
|
||||
ComponentScriptInstance::~ComponentScriptInstance() {
|
||||
m_object->Release();
|
||||
}
|
||||
|
||||
void ComponentScriptInstance::updateInternalVars() {
|
||||
if (!m_updateFunction)
|
||||
return;
|
||||
|
||||
asIScriptContext* context = ScriptEngine::getExecutionContext();
|
||||
|
||||
context->Prepare(m_updateFunction);
|
||||
context->SetObject(m_object);
|
||||
context->Execute();
|
||||
}
|
||||
|
||||
void ComponentScriptInstance::start() {
|
||||
if (!m_startFuction)
|
||||
return;
|
||||
|
||||
asIScriptContext* context = ScriptEngine::getExecutionContext();
|
||||
|
||||
context->Prepare(m_startFuction);
|
||||
context->SetObject(m_object);
|
||||
context->Execute();
|
||||
}
|
||||
}
|
24
Deer/src/Deer/Scripting/ScriptAttributes.cpp
Executable file
24
Deer/src/Deer/Scripting/ScriptAttributes.cpp
Executable file
@ -0,0 +1,24 @@
|
||||
#include "Deer/ComponentScript.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "angelscript.h"
|
||||
|
||||
namespace Deer {
|
||||
ScriptAttributeMap extractAttributes(asITypeInfo* typeInfo) {
|
||||
ScriptAttributeMap m_attributes;
|
||||
|
||||
int atributes = typeInfo->GetPropertyCount();
|
||||
for (int x = 0; x < atributes; x++) {
|
||||
const char* name;
|
||||
bool isPrivate;
|
||||
int typeID;
|
||||
int offset;
|
||||
|
||||
typeInfo->GetProperty(x, &name, &typeID, &isPrivate, nullptr, &offset);
|
||||
ScriptAttribute attribute(name, typeID, isPrivate, offset, x);
|
||||
|
||||
m_attributes.insert({ std::string(name), attribute});
|
||||
}
|
||||
|
||||
return m_attributes;
|
||||
}
|
||||
}
|
157
Deer/src/Deer/Scripting/ScriptEngine.cpp
Executable file
157
Deer/src/Deer/Scripting/ScriptEngine.cpp
Executable file
@ -0,0 +1,157 @@
|
||||
#include "Deer/ScriptEngine.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "Deer/Enviroment.h"
|
||||
|
||||
#include "angelscript.h"
|
||||
#include "scriptbuilder.h"
|
||||
#include "scriptstdstring.h"
|
||||
#include "scriptmath.h"
|
||||
|
||||
#include "ScriptEngineFunctions.h"
|
||||
|
||||
#include "Deer/ComponentScript.h"
|
||||
|
||||
#include "Deer/Scene.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace Deer {
|
||||
namespace ScriptEngine {
|
||||
asIScriptEngine* m_scriptEngine;
|
||||
asIScriptModule* m_scriptModule;
|
||||
Scene* m_scene;
|
||||
|
||||
bool m_isCompilationValid = false;
|
||||
|
||||
asIScriptContext* m_context;
|
||||
ComponentScriptMap m_componentScripts;
|
||||
|
||||
void loadModuleFolder(const std::filesystem::path& modulePath, const char* moduleName);
|
||||
void registerBaseComponents();
|
||||
}
|
||||
|
||||
void ScriptEngine::shutdownScriptEngine() {
|
||||
m_componentScripts.clear();
|
||||
}
|
||||
|
||||
void ScriptEngine::beginExecutionContext(Scene* executingScene) {
|
||||
m_scene = executingScene;
|
||||
m_context = m_scriptEngine->CreateContext();
|
||||
}
|
||||
|
||||
void ScriptEngine::endExecutionContext() {
|
||||
m_context->Release();
|
||||
}
|
||||
|
||||
void ScriptEngine::compileScriptEngine(const std::filesystem::path& modulePath) {
|
||||
m_scriptEngine = asCreateScriptEngine();
|
||||
m_isCompilationValid = true;
|
||||
|
||||
registerBaseComponents();
|
||||
loadModuleFolder(modulePath, "Deer");
|
||||
|
||||
m_scriptModule = m_scriptEngine->GetModule("Deer");
|
||||
asITypeInfo* m_deerScript = m_scriptModule->GetTypeInfoByName("ComponentScript");
|
||||
|
||||
int classCount = m_scriptModule->GetObjectTypeCount();
|
||||
for (int i = 0; i < classCount; i++) {
|
||||
asITypeInfo* type = m_scriptModule->GetObjectTypeByIndex(i);
|
||||
asITypeInfo* parent = type->GetBaseType();
|
||||
|
||||
std::string scriptID = type->GetName();
|
||||
|
||||
if (parent == m_deerScript) {
|
||||
ComponentScript componentScript(type);
|
||||
m_componentScripts.insert({ scriptID, componentScript });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ref<ComponentScriptInstance> ScriptEngine::createComponentScriptInstance(const std::string& scriptID, Entity& scriptEntity) {
|
||||
ComponentScript& script = getComponentScript(scriptID);
|
||||
asITypeInfo* type = script.getTypeInfo();
|
||||
|
||||
ComponentScriptInstance* instance = new ComponentScriptInstance();
|
||||
|
||||
std::string factoryString(script.getName());
|
||||
factoryString = factoryString + " @" + script.getName() + "()";
|
||||
|
||||
asIScriptFunction* function = type->GetFactoryByDecl(factoryString.c_str());
|
||||
if (!function) {
|
||||
DEER_SCRIPT_ERROR("Function constructor not found for class {0}", script.getName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int r = m_context->Prepare(function);
|
||||
if (r < 0) {
|
||||
DEER_SCRIPT_ERROR("Failed to prepare constructor context for class {0}", script.getName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
r = m_context->Execute();
|
||||
if (r < 0) {
|
||||
DEER_SCRIPT_ERROR("Failed to execute constructor for class {0}", script.getName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
asIScriptObject* obj = *(asIScriptObject**)m_context->GetAddressOfReturnValue();
|
||||
obj->AddRef();
|
||||
|
||||
int entityPosition = script.getAttribute("entity").internalID;
|
||||
unsigned int* entityValue = (unsigned int*)obj->GetAddressOfProperty(entityPosition);
|
||||
|
||||
*entityValue = scriptEntity.getUID();
|
||||
|
||||
asIScriptFunction* updateFunction = type->GetMethodByDecl("void update()");
|
||||
asIScriptFunction* startFunction = type->GetMethodByDecl("void start()");
|
||||
instance->m_updateFunction = updateFunction;
|
||||
instance->m_startFuction = startFunction;
|
||||
instance->m_object = obj;
|
||||
|
||||
return Ref<ComponentScriptInstance>(instance);
|
||||
}
|
||||
|
||||
void ScriptEngine::loadModuleFolder(const std::filesystem::path& modulePath, const char* moduleName) {
|
||||
CScriptBuilder builder;
|
||||
|
||||
int r = builder.StartNewModule(m_scriptEngine, moduleName);
|
||||
DEER_SCRIPT_ASSERT(r >= 0, "Unrecoverable error while starting a new module. {0}", moduleName);
|
||||
|
||||
try {
|
||||
DEER_CORE_INFO("=== Loading Scripts ===");
|
||||
for (const auto& entry : fs::recursive_directory_iterator(modulePath)) {
|
||||
if (fs::is_regular_file(entry) && entry.path().extension() == ".as") {
|
||||
|
||||
r = builder.AddSectionFromFile(entry.path().generic_string().c_str());
|
||||
DEER_SCRIPT_ASSERT(r >= 0, "Please correct the errors in the script and try again. {0}", entry.path().generic_string().c_str());
|
||||
|
||||
DEER_CORE_TRACE(" {0}", entry.path().filename().string().c_str());
|
||||
}
|
||||
}
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
DEER_CORE_ERROR("Error while loading scripts, error: {0}", e.what());
|
||||
}
|
||||
|
||||
r = builder.BuildModule();
|
||||
if (r < 0) {
|
||||
DEER_SCRIPT_INFO("Please correct the errors in the script and try again.");
|
||||
m_isCompilationValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::registerBaseComponents() {
|
||||
RegisterStdString(m_scriptEngine);
|
||||
RegisterScriptMath(m_scriptEngine);
|
||||
|
||||
// Regist data types
|
||||
registerEntity(m_scriptEngine);
|
||||
registerVec3(m_scriptEngine);
|
||||
|
||||
// Regist functions
|
||||
registerDeerFunctions(m_scriptEngine);
|
||||
registerInputFunctions(m_scriptEngine);
|
||||
registerEntityTransformFunctions(m_scriptEngine);
|
||||
}
|
||||
}
|
201
Deer/src/Deer/Scripting/ScriptEngineFunctions.cpp
Executable file
201
Deer/src/Deer/Scripting/ScriptEngineFunctions.cpp
Executable file
@ -0,0 +1,201 @@
|
||||
#include "ScriptEngineFunctions.h"
|
||||
|
||||
|
||||
#include "Deer/Scene.h"
|
||||
#include "Deer/Enviroment.h"
|
||||
#include "Deer/ScriptEngine.h"
|
||||
#include "angelscript.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "DeerRender/Input.h"
|
||||
|
||||
#include "glm/glm.hpp"
|
||||
|
||||
namespace Deer {
|
||||
void messageCallback(const asSMessageInfo* msg, void* param) {
|
||||
if (msg->type == asMSGTYPE_WARNING) {
|
||||
DEER_SCRIPT_WARN("({0} {1}) : {2} {3}", msg->row, msg->col, msg->message, msg->section);
|
||||
}
|
||||
else if (msg->type == asMSGTYPE_ERROR) {
|
||||
DEER_SCRIPT_ERROR("({0} {1}) : {2} {3}", msg->row, msg->col, msg->message, msg->section);
|
||||
}
|
||||
else if (msg->type == asMSGTYPE_INFORMATION) {
|
||||
DEER_SCRIPT_INFO("({0} {1}) : {2} {3}", msg->row, msg->col, msg->message, msg->section);
|
||||
}
|
||||
else {
|
||||
DEER_SCRIPT_WARN("({0} {1}) : {2} {3}", msg->row, msg->col, msg->message, msg->section);
|
||||
}
|
||||
}
|
||||
|
||||
void print(std::string& msg) {
|
||||
DEER_SCRIPT_INFO(msg.c_str());
|
||||
}
|
||||
|
||||
glm::vec3 getEntityPosition(uint32_t& entityUID) {
|
||||
if (entityUID == 0 || entityUID == 1) {
|
||||
DEER_SCRIPT_ERROR("Entity is not invalid");
|
||||
return glm::vec3();
|
||||
}
|
||||
|
||||
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment();
|
||||
Entity& entt = m_environment->getEntity(entityUID);
|
||||
|
||||
return entt.getComponent<TransformComponent>().position;
|
||||
}
|
||||
|
||||
void setEntityPosition(glm::vec3 position, uint32_t& entityUID) {
|
||||
if (entityUID == 0 || entityUID == 1) {
|
||||
DEER_SCRIPT_ERROR("Entity is not invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment();
|
||||
Entity& entt = m_environment->getEntity(entityUID);
|
||||
|
||||
entt.getComponent<TransformComponent>().position = position;
|
||||
}
|
||||
|
||||
glm::vec3 getEntityScale(uint32_t& entityUID) {
|
||||
if (entityUID == 0 || entityUID == 1) {
|
||||
DEER_SCRIPT_ERROR("Entity is not invalid");
|
||||
return glm::vec3();
|
||||
}
|
||||
|
||||
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment();
|
||||
Entity& entt = m_environment->getEntity(entityUID);
|
||||
|
||||
return entt.getComponent<TransformComponent>().scale;
|
||||
}
|
||||
|
||||
void setEntityScale(glm::vec3 scale, uint32_t& entityUID) {
|
||||
if (entityUID == 0 || entityUID == 1) {
|
||||
DEER_SCRIPT_ERROR("Entity is not invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment();
|
||||
Entity& entt = m_environment->getEntity(entityUID);
|
||||
|
||||
entt.getComponent<TransformComponent>().scale = scale;
|
||||
}
|
||||
|
||||
uint32_t getEntityParent(uint32_t& entityUID) {
|
||||
if (entityUID == 0 || entityUID == 1) {
|
||||
DEER_SCRIPT_ERROR("Entity is not invalid");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment();
|
||||
Entity& entt = m_environment->getEntity(entityUID);
|
||||
|
||||
return entt.getParentUID();
|
||||
}
|
||||
|
||||
bool isEntityValid(uint32_t& entityUID) {
|
||||
if (entityUID == 0 || entityUID == 1)
|
||||
return false;
|
||||
|
||||
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment();
|
||||
Entity& entt = m_environment->getEntity(entityUID);
|
||||
|
||||
return entt.isValid();
|
||||
}
|
||||
|
||||
void registerVec3(asIScriptEngine* engine) {
|
||||
engine->RegisterObjectType("Vec3", sizeof(glm::vec3), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<glm::vec3>() | asOBJ_APP_CLASS_ALLFLOATS);
|
||||
|
||||
engine->RegisterObjectBehaviour("Vec3", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR([](void* memory) {
|
||||
new (memory) glm::vec3();
|
||||
}, (void*), void), asCALL_CDECL_OBJLAST);
|
||||
engine->RegisterObjectBehaviour("Vec3", asBEHAVE_CONSTRUCT, "void f(float, float = 0, float = 0)", asFUNCTIONPR([](float x, float y, float z, void* memory) {
|
||||
new (memory) glm::vec3(x, y, z);
|
||||
}, (float, float, float, void*), void), asCALL_CDECL_OBJLAST);
|
||||
engine->RegisterObjectProperty("Vec3", "float x", asOFFSET(glm::vec3, x));
|
||||
engine->RegisterObjectProperty("Vec3", "float y", asOFFSET(glm::vec3, y));
|
||||
engine->RegisterObjectProperty("Vec3", "float z", asOFFSET(glm::vec3, z));
|
||||
|
||||
engine->RegisterObjectMethod("Vec3", "Vec3 opAdd(const Vec3 &in) const",
|
||||
asFUNCTIONPR([](const glm::vec3& a, const glm::vec3& b) -> glm::vec3 {
|
||||
return a + b;
|
||||
}, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJFIRST);
|
||||
|
||||
engine->RegisterObjectMethod("Vec3", "Vec3 opSub(const Vec3 &in) const",
|
||||
asFUNCTIONPR([](const glm::vec3& a, const glm::vec3& b) {
|
||||
return a - b;
|
||||
}, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJFIRST);
|
||||
|
||||
engine->RegisterObjectMethod("Vec3", "Vec3 opMul(float) const",
|
||||
asFUNCTIONPR([](const glm::vec3& a, float scalar) {
|
||||
return a * scalar;
|
||||
}, (const glm::vec3&, float), glm::vec3), asCALL_CDECL_OBJFIRST);
|
||||
|
||||
engine->RegisterObjectMethod("Vec3", "Vec3 opDiv(float) const",
|
||||
asFUNCTIONPR([](const glm::vec3& a, float scalar) {
|
||||
return a / scalar;
|
||||
}, (const glm::vec3&, float), glm::vec3), asCALL_CDECL_OBJFIRST);
|
||||
|
||||
engine->RegisterObjectMethod("Vec3", "Vec3 normalize() const",
|
||||
asFUNCTIONPR(glm::normalize, (const glm::vec3&), glm::vec3), asCALL_CDECL_OBJFIRST);
|
||||
|
||||
engine->RegisterObjectMethod("Vec3", "float getMagnitude() const",
|
||||
asFUNCTIONPR(glm::length, (const glm::vec3&), float), asCALL_CDECL_OBJFIRST);
|
||||
|
||||
engine->RegisterObjectMethod("Vec3", "Vec3 opNeg() const",
|
||||
asFUNCTIONPR([](const glm::vec3& a) {
|
||||
return -a;
|
||||
}, (const glm::vec3&), glm::vec3), asCALL_CDECL_OBJFIRST);
|
||||
|
||||
engine->RegisterObjectMethod("Vec3", "bool opEquals(const Vec3 &in) const",
|
||||
asFUNCTIONPR([](const glm::vec3& a, const glm::vec3& b) {
|
||||
return a == b;
|
||||
}, (const glm::vec3&, const glm::vec3&), bool), asCALL_CDECL_OBJFIRST);
|
||||
|
||||
engine->RegisterObjectMethod("Vec3", "string opImplConv() const",
|
||||
asFUNCTIONPR([](const glm::vec3& a) {
|
||||
// Example string conversion using glm (you may need to format it)
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "(%.2f, %.2f, %.2f)", a.x, a.y, a.z);
|
||||
return std::string(buffer);
|
||||
}, (const glm::vec3&), std::string), asCALL_CDECL_OBJFIRST);
|
||||
}
|
||||
|
||||
void registerEntity(asIScriptEngine* engine) {
|
||||
engine->RegisterObjectType("Entity", sizeof(unsigned int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE);
|
||||
engine->RegisterObjectProperty("Entity", "uint uint32_t", 0);
|
||||
|
||||
engine->RegisterObjectMethod("Entity", "Entity getParent()", asFUNCTION(Deer::getEntityParent), asCALL_CDECL_OBJLAST);
|
||||
engine->RegisterObjectMethod("Entity", "bool isValid()", asFUNCTION(Deer::isEntityValid), asCALL_CDECL_OBJLAST);
|
||||
|
||||
engine->RegisterGlobalFunction("Entity getEntity(uint)", asFUNCTIONPR([](uint32_t id) {
|
||||
return id;
|
||||
}, (uint32_t), uint32_t), asCALL_CDECL);
|
||||
|
||||
}
|
||||
|
||||
void registerDeerFunctions(asIScriptEngine* scriptEngine) {
|
||||
int r = scriptEngine->SetMessageCallback(asFUNCTION(Deer::messageCallback), 0, asCALL_CDECL);
|
||||
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up angel script");
|
||||
|
||||
r = scriptEngine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(Deer::print), asCALL_CDECL);
|
||||
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up void print(const string &in)");
|
||||
}
|
||||
|
||||
void registerInputFunctions(asIScriptEngine* scriptEngine) {
|
||||
int r = scriptEngine->RegisterGlobalFunction("bool isKeyPressed(int)", asFUNCTION(Deer::Input::isKeyPressed), asCALL_CDECL);
|
||||
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up bool isKeyPressed(int)");
|
||||
}
|
||||
|
||||
void registerEntityTransformFunctions(asIScriptEngine* scriptEngine) {
|
||||
int r = scriptEngine->RegisterObjectMethod("Entity", "Vec3 getPosition()", asFUNCTION(Deer::getEntityPosition), asCALL_CDECL_OBJLAST);
|
||||
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up Vec3 getPosition()");
|
||||
|
||||
scriptEngine->RegisterObjectMethod("Entity", "void setPosition(Vec3)", asFUNCTION(Deer::setEntityPosition), asCALL_CDECL_OBJLAST);
|
||||
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up void setPosition(Vec3)");
|
||||
|
||||
r = scriptEngine->RegisterObjectMethod("Entity", "Vec3 getScale()", asFUNCTION(Deer::getEntityScale), asCALL_CDECL_OBJLAST);
|
||||
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up Vec3 getScale()");
|
||||
|
||||
scriptEngine->RegisterObjectMethod("Entity", "void setScale(Vec3)", asFUNCTION(Deer::setEntityScale), asCALL_CDECL_OBJLAST);
|
||||
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up void setScale(Vec3)");
|
||||
}
|
||||
|
||||
}
|
32
Deer/src/Deer/Scripting/ScriptEngineFunctions.h
Executable file
32
Deer/src/Deer/Scripting/ScriptEngineFunctions.h
Executable file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <string>
|
||||
#include "glm/glm.hpp"
|
||||
|
||||
struct asSMessageInfo;
|
||||
class asIScriptEngine;
|
||||
|
||||
namespace Deer {
|
||||
void messageCallback(const asSMessageInfo* msg, void* param);
|
||||
void print(std::string& msg);
|
||||
|
||||
// Entity Transformations -------------
|
||||
glm::vec3 getEntityPosition(uint32_t& entityUID);
|
||||
void setEntityPosition(glm::vec3 position, uint32_t& entityUID);
|
||||
glm::vec3 getEntityScale(uint32_t& entityUID);
|
||||
void setEntityScale(glm::vec3 scale, uint32_t& entityUID);
|
||||
// Entity Transformations -------------
|
||||
|
||||
// Entity Relationship ------------
|
||||
uint32_t getEntityParent(uint32_t& entityUID);
|
||||
bool isEntityValid(uint32_t& entityUID);
|
||||
// Entity Relationship ------------
|
||||
|
||||
void registerVec3(asIScriptEngine* engine);
|
||||
void registerEntity(asIScriptEngine* engine);
|
||||
|
||||
void registerDeerFunctions(asIScriptEngine* scriptEngine);
|
||||
void registerInputFunctions(asIScriptEngine* scriptEngine);
|
||||
void registerEntityTransformFunctions(asIScriptEngine* scriptEngine);
|
||||
}
|
21
Deer/src/Deer/Voxels/Chunk.cpp
Executable file
21
Deer/src/Deer/Voxels/Chunk.cpp
Executable file
@ -0,0 +1,21 @@
|
||||
#include "Chunk.h"
|
||||
|
||||
namespace Deer {
|
||||
Chunk::~Chunk() {
|
||||
if (m_voxels) {
|
||||
delete[] m_voxels;
|
||||
#ifdef DEER_RENDER
|
||||
delete[] m_lightInfo;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Chunk::loadVoxels() {
|
||||
if (!m_voxels) {
|
||||
m_voxels = new Voxel[CHUNK_VOXELS]();
|
||||
#ifdef DEER_RENDER
|
||||
m_lightInfo = new VoxelLight[CHUNK_VOXELS]();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
136
Deer/src/Deer/Voxels/Chunk.h
Executable file
136
Deer/src/Deer/Voxels/Chunk.h
Executable file
@ -0,0 +1,136 @@
|
||||
#pragma once
|
||||
#include "Deer/Voxel.h"
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
#include "DeerRender/LightVoxel.h"
|
||||
#include "DeerRender/VoxelAspect.h"
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace Deer {
|
||||
class Chunk {
|
||||
public:
|
||||
Chunk() = default;
|
||||
~Chunk();
|
||||
|
||||
inline Voxel readVoxel(ChunkVoxelID id) {
|
||||
if (m_voxels)
|
||||
return m_voxels[VOXEL_POSITION(id)];
|
||||
return emptyVoxel;
|
||||
}
|
||||
|
||||
inline Voxel& modVoxel(ChunkVoxelID id) {
|
||||
if (!m_voxels)
|
||||
loadVoxels();
|
||||
return m_voxels[VOXEL_POSITION(id)];
|
||||
}
|
||||
|
||||
inline void fillVoxels(ChunkVoxelID min, ChunkVoxelID max, Voxel info) {
|
||||
if (!m_voxels)
|
||||
loadVoxels();
|
||||
|
||||
ChunkVoxelID voxelID;
|
||||
for (voxelID.x = min.x; voxelID.x <= max.x; voxelID.x++) {
|
||||
for (voxelID.y = min.y; voxelID.y <= max.y; voxelID.y++) {
|
||||
for (voxelID.z = min.z; voxelID.z <= max.x; voxelID.z++) {
|
||||
m_voxels[VOXEL_POSITION(voxelID)] = info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void remplaceVoxels(ChunkVoxelID min, ChunkVoxelID max, Voxel ref, Voxel value) {
|
||||
if (!m_voxels)
|
||||
loadVoxels();
|
||||
|
||||
ChunkVoxelID voxelID;
|
||||
for (voxelID.x = min.x; voxelID.x <= max.x; voxelID.x++) {
|
||||
for (voxelID.y = min.y; voxelID.y <= max.y; voxelID.y++) {
|
||||
for (voxelID.z = min.z; voxelID.z <= max.z; voxelID.z++) {
|
||||
Voxel& currentVoxel = m_voxels[VOXEL_POSITION(voxelID)];
|
||||
|
||||
if (currentVoxel.id == ref.id)
|
||||
currentVoxel = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline uint8_t calculateLayerVoxelHeight(LayerVoxelID layerVoxelID) {
|
||||
if (!m_voxels)
|
||||
return 0;
|
||||
|
||||
ChunkVoxelID voxelID(layerVoxelID.x, CHUNK_SIZE_Y - 1, layerVoxelID.z);
|
||||
for (int y = CHUNK_SIZE_Y - 1; y >= 0; y--) {
|
||||
voxelID.y = y;
|
||||
|
||||
if (m_voxels[VOXEL_POSITION(voxelID)].id != 0)
|
||||
return voxelID.y + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
private:
|
||||
Voxel* m_voxels = nullptr;
|
||||
|
||||
void loadVoxels();
|
||||
#ifdef DEER_RENDER
|
||||
public:
|
||||
inline VoxelLight readLight(ChunkVoxelID id) {
|
||||
if (m_voxels)
|
||||
return m_lightInfo[VOXEL_POSITION(id)];
|
||||
return VoxelLight();
|
||||
}
|
||||
|
||||
inline VoxelLight& modLight(ChunkVoxelID id) {
|
||||
if (!m_voxels)
|
||||
loadVoxels();
|
||||
return m_lightInfo[VOXEL_POSITION(id)];
|
||||
}
|
||||
|
||||
inline void clearVoxelLight(ChunkVoxelID min, ChunkVoxelID max) {
|
||||
ChunkVoxelID voxelID;
|
||||
for (voxelID.x = min.x; voxelID.x <= max.x; voxelID.x++){
|
||||
for (voxelID.y = min.y; voxelID.y <= max.y; voxelID.y++){
|
||||
for (voxelID.z = min.z; voxelID.z <= max.z; voxelID.z++){
|
||||
m_lightInfo[VOXEL_POSITION(voxelID)].b_light = 0;
|
||||
m_lightInfo[VOXEL_POSITION(voxelID)].r_light = 0;
|
||||
m_lightInfo[VOXEL_POSITION(voxelID)].g_light = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function is the same as clear Voxel Light but it also checks if there is a source of light
|
||||
inline void clearVoxelLightAndSaveSources(ChunkVoxelID min, ChunkVoxelID max, ChunkID chunkID, std::vector<VoxelCordinates>& sources) {
|
||||
if (!m_voxels)
|
||||
return;
|
||||
|
||||
ChunkVoxelID voxelID;
|
||||
for (voxelID.x = min.x; voxelID.x <= max.x; voxelID.x++){
|
||||
for (voxelID.y = min.y; voxelID.y <= max.y; voxelID.y++){
|
||||
for (voxelID.z = min.z; voxelID.z <= max.z; voxelID.z++){
|
||||
Voxel voxel = m_voxels[VOXEL_POSITION(voxelID)];
|
||||
VoxelAspect& voxelAspect = VoxelData::voxelsAspect[voxel.id];
|
||||
if (voxelAspect.isLightSource()) {
|
||||
sources.push_back(VoxelCordinates(
|
||||
voxelID.x + chunkID.x * CHUNK_SIZE_X,
|
||||
voxelID.y + chunkID.y * CHUNK_SIZE_Y,
|
||||
voxelID.z + chunkID.z * CHUNK_SIZE_Z
|
||||
));
|
||||
}
|
||||
|
||||
m_lightInfo[VOXEL_POSITION(voxelID)].b_light = 0;
|
||||
m_lightInfo[VOXEL_POSITION(voxelID)].r_light = 0;
|
||||
m_lightInfo[VOXEL_POSITION(voxelID)].g_light = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
VoxelLight* m_lightInfo = nullptr;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
12
Deer/src/Deer/Voxels/Layer.cpp
Executable file
12
Deer/src/Deer/Voxels/Layer.cpp
Executable file
@ -0,0 +1,12 @@
|
||||
#include "Layer.h"
|
||||
|
||||
namespace Deer {
|
||||
Layer::~Layer() {
|
||||
if (m_layerInfo)
|
||||
delete[] m_layerInfo;
|
||||
}
|
||||
|
||||
void Layer::loadData() {
|
||||
m_layerInfo = new LayerVoxel[LAYER_VOXELS]();
|
||||
}
|
||||
}
|
40
Deer/src/Deer/Voxels/Layer.h
Executable file
40
Deer/src/Deer/Voxels/Layer.h
Executable file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#include "Deer/Voxel.h"
|
||||
|
||||
namespace Deer {
|
||||
class Layer {
|
||||
public:
|
||||
Layer() = default;
|
||||
~Layer();
|
||||
|
||||
inline LayerVoxel readLayerVoxel(LayerVoxelID id) {
|
||||
if (!m_layerInfo)
|
||||
return LayerVoxel();
|
||||
return m_layerInfo[LAYER_VOXEL_POSITION(id)];
|
||||
}
|
||||
|
||||
inline LayerVoxel& modLayerVoxel(LayerVoxelID id) {
|
||||
if (!m_layerInfo)
|
||||
loadData();
|
||||
return m_layerInfo[LAYER_VOXEL_POSITION(id)];
|
||||
}
|
||||
|
||||
inline void fillVoxelLayerMaxHeight(LayerVoxelID min, LayerVoxelID max, uint8_t maxHeight) {
|
||||
if (!m_layerInfo)
|
||||
loadData();
|
||||
|
||||
LayerVoxelID layerVoxelID;
|
||||
for (layerVoxelID.x = min.x; layerVoxelID.x <= max.x; layerVoxelID.x++) {
|
||||
for (layerVoxelID.z = min.x; layerVoxelID.z <= max.z; layerVoxelID.z++) {
|
||||
int id = LAYER_VOXEL_POSITION(layerVoxelID);
|
||||
if (m_layerInfo[id].height <= maxHeight)
|
||||
m_layerInfo[id].height = maxHeight + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
void loadData();
|
||||
|
||||
LayerVoxel* m_layerInfo = nullptr;
|
||||
};
|
||||
}
|
56
Deer/src/Deer/Voxels/Serialization/VoxelInfoSerialization.h
Normal file
56
Deer/src/Deer/Voxels/Serialization/VoxelInfoSerialization.h
Normal file
@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
#include "Deer/Voxel.h"
|
||||
#include "Deer/Log.h"
|
||||
|
||||
#include "cereal/cereal.hpp"
|
||||
#include "cereal/types/string.hpp"
|
||||
|
||||
namespace Deer{
|
||||
template<class Archive>
|
||||
void save(Archive & archive, VoxelInfo const & block) {
|
||||
archive(cereal::make_nvp("name", block.name));
|
||||
|
||||
// To avoid breaking things we set it up to Air
|
||||
const char* blockTypeChar = VOXEL_INFO_TYPE_AIR;
|
||||
switch (block.type)
|
||||
{
|
||||
case VoxelInfoType::Air :
|
||||
blockTypeChar = VOXEL_INFO_TYPE_AIR;
|
||||
break;
|
||||
case VoxelInfoType::Voxel :
|
||||
blockTypeChar = VOXEL_INFO_TYPE_VOXEL;
|
||||
break;
|
||||
case VoxelInfoType::TransparentVoxel :
|
||||
blockTypeChar = VOXEL_INFO_TYPE_TRANSPARENT_VOXEL;
|
||||
break;
|
||||
case VoxelInfoType::Custom :
|
||||
blockTypeChar = VOXEL_INFO_TYPE_CUSTOM;
|
||||
break;
|
||||
}
|
||||
|
||||
std::string blockTypeString(blockTypeChar);
|
||||
archive(cereal::make_nvp("type", blockTypeString));
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive & archive, VoxelInfo & block) {archive(cereal::make_nvp("name", block.name));
|
||||
std::string blockTypeString;
|
||||
|
||||
archive(cereal::make_nvp("name", block.name));
|
||||
archive(cereal::make_nvp("type", blockTypeString));
|
||||
|
||||
if (blockTypeString == VOXEL_INFO_TYPE_AIR)
|
||||
block.type = VoxelInfoType::Air;
|
||||
else if (blockTypeString == VOXEL_INFO_TYPE_VOXEL)
|
||||
block.type = VoxelInfoType::Voxel;
|
||||
else if (blockTypeString == VOXEL_INFO_TYPE_TRANSPARENT_VOXEL)
|
||||
block.type = VoxelInfoType::TransparentVoxel;
|
||||
else if (blockTypeString == VOXEL_INFO_TYPE_CUSTOM)
|
||||
block.type = VoxelInfoType::Custom;
|
||||
else {
|
||||
block.type = VoxelInfoType::Air;
|
||||
DEER_CORE_ERROR("Failed to resolve voxel type for {0}, unknown type : {1}",
|
||||
block.name.c_str(), blockTypeString.c_str());
|
||||
}
|
||||
}
|
||||
}
|
19
Deer/src/Deer/Voxels/Voxel.cpp
Executable file
19
Deer/src/Deer/Voxels/Voxel.cpp
Executable file
@ -0,0 +1,19 @@
|
||||
#include "Deer/Voxel.h"
|
||||
|
||||
namespace Deer {
|
||||
// This means the voxel is null
|
||||
Voxel nullVoxel(65535);
|
||||
Voxel emptyVoxel;
|
||||
|
||||
LayerVoxel nullLayerVoxel(65535);
|
||||
|
||||
int normalDirs[3 * 6] = {
|
||||
-1, 0, 0,
|
||||
1, 0, 0,
|
||||
0, -1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, -1,
|
||||
0, 0, 1
|
||||
};
|
||||
|
||||
}
|
89
Deer/src/Deer/Voxels/VoxelData.cpp
Normal file
89
Deer/src/Deer/Voxels/VoxelData.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Deer/DataStore.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "Deer/Voxel.h"
|
||||
#include "Deer/Voxels/Serialization/VoxelInfoSerialization.h"
|
||||
#include "cereal/archives/json.hpp"
|
||||
|
||||
namespace Deer {
|
||||
namespace VoxelData {
|
||||
std::vector<VoxelInfo> voxelsInfo;
|
||||
std::unordered_map<std::string, uint32_t> blockIDMap;
|
||||
} // namespace VoxelData
|
||||
|
||||
int32_t VoxelData::getVoxelID(const std::string& name) {
|
||||
if (blockIDMap.contains(name)) return blockIDMap[name];
|
||||
DEER_CORE_WARN("Voxel Info {0} Not Found!", name.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
void VoxelData::loadVoxelsData() {
|
||||
voxelsInfo.clear();
|
||||
blockIDMap.clear();
|
||||
|
||||
VoxelInfo airVoxelInfo;
|
||||
airVoxelInfo.name = VOXEL_INFO_TYPE_AIR;
|
||||
|
||||
voxelsInfo.push_back(airVoxelInfo);
|
||||
blockIDMap[VOXEL_INFO_TYPE_AIR] = 0;
|
||||
|
||||
std::vector<Path> voxelsData;
|
||||
voxelsData = DataStore::getFiles(DEER_VOXEL_DATA_PATH, ".voxel");
|
||||
|
||||
DEER_CORE_INFO("=== Loading voxels ===");
|
||||
DEER_CORE_TRACE(" default - air");
|
||||
for (Path& voxel : voxelsData) {
|
||||
VoxelInfo voxelData;
|
||||
|
||||
uint32_t dataSize;
|
||||
uint8_t* data = DataStore::readFile(voxel, &dataSize);
|
||||
|
||||
std::string dataString((char*)data, dataSize);
|
||||
std::istringstream dataInputStream(dataString);
|
||||
{
|
||||
cereal::JSONInputArchive archive(dataInputStream);
|
||||
archive(cereal::make_nvp("voxel", voxelData));
|
||||
}
|
||||
|
||||
if (voxelData.name.empty()) {
|
||||
DEER_CORE_ERROR("{0} has an empty name",
|
||||
voxel.generic_string().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (blockIDMap.contains(voxelData.name)) {
|
||||
DEER_CORE_ERROR("{0} with name {1} has dupplicated name id",
|
||||
voxel.generic_string().c_str(),
|
||||
voxelData.name.c_str());
|
||||
continue;
|
||||
}
|
||||
DEER_CORE_TRACE(" {0} - {1}",
|
||||
voxel.filename().generic_string().c_str(),
|
||||
voxelData.name);
|
||||
|
||||
uint32_t id = voxelsInfo.size();
|
||||
|
||||
voxelsInfo.push_back(voxelData);
|
||||
blockIDMap[voxelData.name] = id;
|
||||
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelData::createExampleVoxelData() {
|
||||
VoxelInfo block;
|
||||
|
||||
std::stringstream data;
|
||||
{
|
||||
cereal::JSONOutputArchive archive(data);
|
||||
archive(cereal::make_nvp("voxel", block));
|
||||
}
|
||||
|
||||
DataStore::saveFile(Path(DEER_VOXEL_PATH) / "voxel.example",
|
||||
(uint8_t*)(data.str().c_str()), data.str().size());
|
||||
}
|
||||
} // namespace Deer
|
43
Deer/src/Deer/Voxels/VoxelWorld.cpp
Executable file
43
Deer/src/Deer/Voxels/VoxelWorld.cpp
Executable file
@ -0,0 +1,43 @@
|
||||
#include "Deer/VoxelWorld.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "Deer/Voxels/Chunk.h"
|
||||
#include "Deer/Voxels/Layer.h"
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
namespace Deer {
|
||||
VoxelWorld::VoxelWorld(const VoxelWorldProps& props)
|
||||
: m_worldProps(props) {
|
||||
m_chunks = MakeScope<Chunk[]>(m_worldProps.getChunkCount());
|
||||
m_layers = MakeScope<Layer[]>(m_worldProps.getLayerCount());
|
||||
#ifdef DEER_RENDER
|
||||
m_renderData = MakeScope<VoxelWorldRenderData>(m_worldProps.getChunkCount());
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t VoxelWorld::calculateLayerVoxelHeight(int x, int z) {
|
||||
LayerVoxelID layerVoxelID;
|
||||
LayerID layerID;
|
||||
|
||||
extractLayerCordinates(x, z, layerID, layerVoxelID);
|
||||
ChunkID chunkID(layerID.x, 0, layerID.z);
|
||||
|
||||
for (int y = m_worldProps.chunkSizeY - 1; y >= 0; y--) {
|
||||
chunkID.y = y;
|
||||
|
||||
Chunk& chunk = m_chunks[m_worldProps.getWorldChunkID(chunkID)];
|
||||
uint8_t chunkVoxelHeight = chunk.calculateLayerVoxelHeight(layerVoxelID);
|
||||
|
||||
if (chunkVoxelHeight != 0) {
|
||||
return chunkVoxelHeight + chunkID.y * CHUNK_SIZE_Y;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
154
Deer/src/Deer/Voxels/VoxelWorld_Raycast.cpp
Normal file
154
Deer/src/Deer/Voxels/VoxelWorld_Raycast.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
#include "Deer/VoxelWorld.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "Deer/Voxels/Chunk.h"
|
||||
#include "Deer/Voxels/Layer.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
namespace Deer {
|
||||
VoxelRayResult VoxelWorld::rayCast(glm::vec3 position, glm::vec3 dir, float maxDistance) {
|
||||
VoxelRayResult result;
|
||||
|
||||
result.hitPos.x = (int32_t)std::floor(position.x);
|
||||
result.hitPos.y = (int32_t)std::floor(position.y);
|
||||
result.hitPos.z = (int32_t)std::floor(position.z);
|
||||
|
||||
result.distance = 0;
|
||||
|
||||
if (dir.x == 0 && dir.y == 0 && dir.z == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
dir = glm::normalize(dir);
|
||||
|
||||
glm::vec3 stepAxis = glm::vec3(maxDistance, maxDistance, maxDistance);
|
||||
glm::vec3 distanceAxis = glm::vec3(maxDistance, maxDistance, maxDistance);
|
||||
|
||||
int8_t directionAxis[3] = { 1, 1, 1 };
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (dir[i] < 0) {
|
||||
stepAxis[i] = -1.0f / dir[i];
|
||||
directionAxis[i] = -1;
|
||||
distanceAxis[i] = stepAxis[i] * ((float)position[i] - (float)(&result.hitPos.x)[i]);
|
||||
}
|
||||
else if (dir[i] > 0) {
|
||||
stepAxis[i] = 1.0f / dir[i];
|
||||
distanceAxis[i] = stepAxis[i] * (1 - (float)position[i] + (float)(&result.hitPos.x)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
while (result.distance < maxDistance) {
|
||||
float minDistance = distanceAxis[0];
|
||||
for (int i = 1; i < 3; i++) {
|
||||
if (distanceAxis[i] < minDistance)
|
||||
minDistance = distanceAxis[i];
|
||||
}
|
||||
|
||||
result.distance = minDistance;
|
||||
if (result.distance > maxDistance)
|
||||
break;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (minDistance == distanceAxis[i]) {
|
||||
result.hitPos[i] += directionAxis[i];
|
||||
distanceAxis[i] = minDistance + stepAxis[i];
|
||||
|
||||
Voxel hitVoxel = readVoxel(result.hitPos);
|
||||
|
||||
if (hitVoxel == nullVoxel)
|
||||
continue;
|
||||
|
||||
if (hitVoxel != 0) {
|
||||
result.face = i * 2;
|
||||
|
||||
if (directionAxis[i] == -1)
|
||||
result.face++;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.distance = maxDistance;
|
||||
return result;
|
||||
}
|
||||
|
||||
VoxelRayResult VoxelWorld::rayCast_editor(glm::vec3 position, glm::vec3 dir, float maxDistance) {
|
||||
VoxelRayResult result;
|
||||
|
||||
result.hitPos.x = (int32_t)std::floor(position.x);
|
||||
result.hitPos.y = (int32_t)std::floor(position.y);
|
||||
result.hitPos.z = (int32_t)std::floor(position.z);
|
||||
|
||||
result.distance = 0;
|
||||
|
||||
if (dir.x == 0 && dir.y == 0 && dir.z == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
dir = glm::normalize(dir);
|
||||
|
||||
glm::vec3 stepAxis = glm::vec3(maxDistance, maxDistance, maxDistance);
|
||||
glm::vec3 distanceAxis = glm::vec3(maxDistance, maxDistance, maxDistance);
|
||||
|
||||
int8_t directionAxis[3] = { 1, 1, 1 };
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (dir[i] < 0) {
|
||||
stepAxis[i] = -1.0f / dir[i];
|
||||
directionAxis[i] = -1;
|
||||
distanceAxis[i] = stepAxis[i] * ((float)position[i] - (float)result.hitPos[i]);
|
||||
}
|
||||
else if (dir[i] > 0) {
|
||||
stepAxis[i] = 1.0f / dir[i];
|
||||
distanceAxis[i] = stepAxis[i] * (1 - (float)position[i] + (float)result.hitPos[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Voxel hitVoxel = readVoxel(result.hitPos);
|
||||
bool has_exit_inner_walls = hitVoxel.id == 0;
|
||||
while (result.distance < maxDistance) {
|
||||
float minDistance = distanceAxis[0];
|
||||
for (int i = 1; i < 3; i++) {
|
||||
if (distanceAxis[i] < minDistance)
|
||||
minDistance = distanceAxis[i];
|
||||
}
|
||||
|
||||
result.distance = minDistance;
|
||||
if (result.distance > maxDistance)
|
||||
break;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (minDistance == distanceAxis[i]) {
|
||||
result.hitPos[i] += directionAxis[i];
|
||||
distanceAxis[i] = minDistance + stepAxis[i];
|
||||
|
||||
Voxel hitVoxel = readVoxel(result.hitPos);
|
||||
|
||||
if (hitVoxel.id == 0) {
|
||||
if (has_exit_inner_walls && result.hitPos.y == -1 && directionAxis[1] == -1 && i == 1) {
|
||||
result.face = NORMAL_UP;
|
||||
return result;
|
||||
}
|
||||
|
||||
has_exit_inner_walls = true;
|
||||
} else if (hitVoxel.id != 0 && has_exit_inner_walls) {
|
||||
result.face = i * 2;
|
||||
|
||||
if (directionAxis[i] == -1)
|
||||
result.face++;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.distance = maxDistance;
|
||||
return result;
|
||||
}
|
||||
}
|
246
Deer/src/Deer/Voxels/VoxelWorld_VoxelManipultation.cpp
Normal file
246
Deer/src/Deer/Voxels/VoxelWorld_VoxelManipultation.cpp
Normal file
@ -0,0 +1,246 @@
|
||||
#include "Deer/Log.h"
|
||||
#include "Deer/VoxelWorld.h"
|
||||
#include "Deer/Voxels/Chunk.h"
|
||||
#include "Deer/Voxels/Layer.h"
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
namespace Deer {
|
||||
Voxel VoxelWorld::readVoxel(VoxelCordinates coords) {
|
||||
ChunkID chunkID;
|
||||
ChunkVoxelID chunkVoxelID;
|
||||
|
||||
extractChunkCordinates(coords, chunkID, chunkVoxelID);
|
||||
if (!m_worldProps.isValid(chunkID)) return emptyVoxel;
|
||||
|
||||
Chunk& chunk = m_chunks[m_worldProps.getWorldChunkID(chunkID)];
|
||||
return chunk.readVoxel(chunkVoxelID);
|
||||
}
|
||||
|
||||
void VoxelWorld::setVoxel(VoxelCordinates coords, Voxel info) {
|
||||
ChunkID chunkID;
|
||||
ChunkVoxelID chunkVoxelID;
|
||||
|
||||
extractChunkCordinates(coords, chunkID, chunkVoxelID);
|
||||
if (!m_worldProps.isValid(chunkID)) return;
|
||||
|
||||
Chunk& chunk = m_chunks[m_worldProps.getWorldChunkID(chunkID)];
|
||||
chunk.modVoxel(chunkVoxelID) = info;
|
||||
|
||||
LayerID layerID;
|
||||
LayerVoxelID layerVoxelID;
|
||||
|
||||
extractLayerCordinates(coords.x, coords.z, layerID, layerVoxelID);
|
||||
|
||||
Layer& layer = m_layers[m_worldProps.getWorldLayerID(layerID)];
|
||||
LayerVoxel& layerVoxel = layer.modLayerVoxel(layerVoxelID);
|
||||
|
||||
if (!info.isVoxelType())
|
||||
layerVoxel.height = calculateLayerVoxelHeight(coords.x, coords.z);
|
||||
else if (coords.y >= layerVoxel.height)
|
||||
layerVoxel.height = coords.y + 1;
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
m_renderData->chunkQueue.addChunk(chunkID);
|
||||
// For every axis, X & Y & Z
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (chunkVoxelID[i] == 0 && chunkID[i] != 0) {
|
||||
ChunkID nextChunk = chunkID;
|
||||
nextChunk[i]--;
|
||||
m_renderData->chunkQueue.addChunk(nextChunk);
|
||||
}
|
||||
|
||||
if (chunkVoxelID[i] == CHUNK_SIZE(i) &&
|
||||
chunkID[i] != m_worldProps[i] - 1) {
|
||||
ChunkID nextChunk = chunkID;
|
||||
nextChunk[i]++;
|
||||
m_renderData->chunkQueue.addChunk(nextChunk);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we should update the lighting
|
||||
bakeAmbientLightFromPoint(coords.x, coords.z);
|
||||
bakeVoxelLightFromPoint(coords);
|
||||
#endif
|
||||
}
|
||||
|
||||
void VoxelWorld::fillVoxels(VoxelCordinates min, VoxelCordinates max,
|
||||
Voxel info) {
|
||||
ChunkID minChunkID;
|
||||
ChunkID maxChunkID;
|
||||
ChunkVoxelID minChunkVoxelID;
|
||||
ChunkVoxelID maxChunkVoxelID;
|
||||
|
||||
m_worldProps.clampAndSetMinMax(min, max);
|
||||
|
||||
extractChunkCordinates(min, minChunkID, minChunkVoxelID);
|
||||
extractChunkCordinates(max, maxChunkID, maxChunkVoxelID);
|
||||
for (int chunkX = minChunkID.x; chunkX <= maxChunkID.x; chunkX++) {
|
||||
for (int chunkY = minChunkID.y; chunkY <= maxChunkID.y; chunkY++) {
|
||||
for (int chunkZ = minChunkID.z; chunkZ <= maxChunkID.z;
|
||||
chunkZ++) {
|
||||
ChunkID workingChunkID(chunkX, chunkY, chunkZ);
|
||||
LayerID workingLayerID(chunkX, chunkZ);
|
||||
Chunk& workingChunk =
|
||||
m_chunks[m_worldProps.getWorldChunkID(workingChunkID)];
|
||||
Layer& workingLayer =
|
||||
m_layers[m_worldProps.getWorldLayerID(workingLayerID)];
|
||||
|
||||
ChunkVoxelID workingMin(0, 0, 0);
|
||||
ChunkVoxelID workingMax(CHUNK_SIZE_X - 1, CHUNK_SIZE_Y - 1,
|
||||
CHUNK_SIZE_Z - 1);
|
||||
|
||||
if (chunkX == minChunkID.x)
|
||||
workingMin.x = minChunkVoxelID.x;
|
||||
if (chunkY == minChunkID.y)
|
||||
workingMin.y = minChunkVoxelID.y;
|
||||
if (chunkZ == minChunkID.z)
|
||||
workingMin.z = minChunkVoxelID.z;
|
||||
|
||||
if (chunkX == maxChunkID.x)
|
||||
workingMax.x = maxChunkVoxelID.x;
|
||||
if (chunkY == maxChunkID.y)
|
||||
workingMax.y = maxChunkVoxelID.y;
|
||||
if (chunkZ == maxChunkID.z)
|
||||
workingMax.z = maxChunkVoxelID.z;
|
||||
|
||||
LayerVoxelID workingMinLayer(workingMin.x, workingMin.z);
|
||||
LayerVoxelID workingMaxLayer(workingMax.x, workingMax.z);
|
||||
|
||||
workingChunk.fillVoxels(workingMin, workingMax, info);
|
||||
workingLayer.fillVoxelLayerMaxHeight(
|
||||
workingMinLayer, workingMaxLayer, max.y);
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
m_renderData->chunkQueue.addChunk(workingChunkID);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
VoxelCordinates minLightModification = min;
|
||||
VoxelCordinates maxLightModification = max;
|
||||
// We want to add a 16 layer border
|
||||
for (int i = 0; i < 3; i++) {
|
||||
minLightModification[i] -= 16;
|
||||
maxLightModification[i] += 16;
|
||||
}
|
||||
|
||||
m_worldProps.clampCordinates(minLightModification);
|
||||
m_worldProps.clampCordinates(maxLightModification);
|
||||
|
||||
bakeAmbientLight(minLightModification.x, maxLightModification.x,
|
||||
minLightModification.z, maxLightModification.z);
|
||||
bakeVoxelLight(minLightModification, maxLightModification);
|
||||
#endif
|
||||
}
|
||||
|
||||
void VoxelWorld::remplaceVoxels(VoxelCordinates min, VoxelCordinates max,
|
||||
Voxel ref, Voxel value) {
|
||||
ChunkID minChunkID;
|
||||
ChunkID maxChunkID;
|
||||
ChunkVoxelID minChunkVoxelID;
|
||||
ChunkVoxelID maxChunkVoxelID;
|
||||
|
||||
m_worldProps.clampAndSetMinMax(min, max);
|
||||
|
||||
extractChunkCordinates(min, minChunkID, minChunkVoxelID);
|
||||
extractChunkCordinates(max, maxChunkID, maxChunkVoxelID);
|
||||
for (int chunkX = minChunkID.x; chunkX <= maxChunkID.x; chunkX++) {
|
||||
for (int chunkY = minChunkID.y; chunkY <= maxChunkID.y; chunkY++) {
|
||||
for (int chunkZ = minChunkID.z; chunkZ <= maxChunkID.z;
|
||||
chunkZ++) {
|
||||
ChunkID workingChunkID(chunkX, chunkY, chunkZ);
|
||||
Chunk& workingChunk =
|
||||
m_chunks[m_worldProps.getWorldChunkID(workingChunkID)];
|
||||
|
||||
ChunkVoxelID workingMin(0, 0, 0);
|
||||
ChunkVoxelID workingMax(CHUNK_SIZE_X - 1, CHUNK_SIZE_Y - 1,
|
||||
CHUNK_SIZE_Z - 1);
|
||||
|
||||
if (chunkX == minChunkID.x)
|
||||
workingMin.x = minChunkVoxelID.x;
|
||||
if (chunkY == minChunkID.y)
|
||||
workingMin.y = minChunkVoxelID.y;
|
||||
if (chunkZ == minChunkID.z)
|
||||
workingMin.z = minChunkVoxelID.z;
|
||||
|
||||
if (chunkX == maxChunkID.x)
|
||||
workingMax.x = maxChunkVoxelID.x;
|
||||
if (chunkY == maxChunkID.y)
|
||||
workingMax.y = maxChunkVoxelID.y;
|
||||
if (chunkZ == maxChunkID.z)
|
||||
workingMax.z = maxChunkVoxelID.z;
|
||||
|
||||
workingChunk.remplaceVoxels(workingMin, workingMax, ref,
|
||||
value);
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
m_renderData->chunkQueue.addChunk(workingChunkID);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int xPos = min.x; xPos <= max.x; xPos++) {
|
||||
for (int zPos = min.z; zPos <= max.z; zPos++) {
|
||||
LayerID layerID;
|
||||
LayerVoxelID layerVoxelID;
|
||||
|
||||
extractLayerCordinates(xPos, zPos, layerID, layerVoxelID);
|
||||
int worldLayerID = m_worldProps.getWorldLayerID(layerID);
|
||||
|
||||
m_layers[worldLayerID].modLayerVoxel(layerVoxelID).height =
|
||||
calculateLayerVoxelHeight(xPos, zPos);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
VoxelCordinates minLightModification = min;
|
||||
VoxelCordinates maxLightModification = max;
|
||||
// We want to add a 16 layer border
|
||||
for (int i = 0; i < 3; i++) {
|
||||
minLightModification[i] -= 16;
|
||||
maxLightModification[i] += 16;
|
||||
}
|
||||
|
||||
m_worldProps.clampCordinates(minLightModification);
|
||||
m_worldProps.clampCordinates(maxLightModification);
|
||||
|
||||
bakeAmbientLight(minLightModification.x, maxLightModification.x,
|
||||
minLightModification.z, maxLightModification.z);
|
||||
bakeVoxelLight(minLightModification, maxLightModification);
|
||||
#endif
|
||||
}
|
||||
|
||||
LayerVoxel VoxelWorld::readLayerVoxel(int x, int z) {
|
||||
LayerID layerID;
|
||||
LayerVoxelID layerVoxelID;
|
||||
|
||||
extractLayerCordinates(x, z, layerID, layerVoxelID);
|
||||
if (!m_worldProps.isValid(layerID)) return LayerVoxel();
|
||||
|
||||
Layer& layer = m_layers[m_worldProps.getWorldLayerID(layerID)];
|
||||
return layer.readLayerVoxel(layerVoxelID);
|
||||
}
|
||||
|
||||
LayerVoxel& VoxelWorld::modLayerVoxel(int x, int z) {
|
||||
LayerID layerID;
|
||||
LayerVoxelID layerVoxelID;
|
||||
|
||||
extractLayerCordinates(x, z, layerID, layerVoxelID);
|
||||
if (!m_worldProps.isValid(layerID)) return nullLayerVoxel;
|
||||
|
||||
Layer& layer = m_layers[m_worldProps.getWorldLayerID(layerID)];
|
||||
return layer.modLayerVoxel(layerVoxelID);
|
||||
}
|
||||
|
||||
} // namespace Deer
|
29
Deer/src/DeerRender/Core/Input/Input.cpp
Executable file
29
Deer/src/DeerRender/Core/Input/Input.cpp
Executable file
@ -0,0 +1,29 @@
|
||||
#include "DeerRender/Input.h"
|
||||
|
||||
namespace Deer {
|
||||
#ifdef DEER_RENDER
|
||||
bool Input::isKeyPressed(unsigned int key) {
|
||||
return Application::s_application->m_window->getKeyPressed(key);
|
||||
}
|
||||
|
||||
bool Input::isMouseButtonPressed(int button) {
|
||||
return Application::s_application->m_window->getMouseButton(button);
|
||||
}
|
||||
|
||||
void Input::getMousePos(float& x, float& y) {
|
||||
return Application::s_application->m_window->getMousePos(x, y);
|
||||
}
|
||||
#else
|
||||
bool Input::isKeyPressed(unsigned int key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Input::isMouseButtonPressed(int button) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Input::getMousePos(float& x, float& y) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
29
Deer/src/DeerRender/ImGui/ImGuiLayer.h
Executable file
29
Deer/src/DeerRender/ImGui/ImGuiLayer.h
Executable file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include "DeerRender/Events/ApplicationEvent.h"
|
||||
#include "DeerRender/Events/KeyEvent.h"
|
||||
#include "DeerRender/Events/MouseEvent.h"
|
||||
|
||||
namespace Deer {
|
||||
class ImGuiLayer {
|
||||
public:
|
||||
~ImGuiLayer() = default;
|
||||
|
||||
void onAttach();
|
||||
void onDetach();
|
||||
|
||||
void begin();
|
||||
void end();
|
||||
|
||||
void onEvent(Event& event);
|
||||
private:
|
||||
bool onMouseButtonPressedEvent(MouseButtonPressedEvent& e);
|
||||
bool onMouseButtonReleasedEvent(MouseButtonReleasedEvent& e);
|
||||
bool onMouseMovedEvent(MouseMovedEvent& e);
|
||||
bool onMouseScrollEvent(MouseScrolledEvent& e);
|
||||
bool onKeyPressedEvent(KeyPressedEvent& e);
|
||||
bool onKeyReleasedEvent(KeyReleasedEvent& e);
|
||||
bool onKeyTypedEvent(KeyTypedEvent& e);
|
||||
bool onWindowResizeEvent(WindowResizeEvent& e);
|
||||
};
|
||||
}
|
||||
|
129
Deer/src/DeerRender/Render/Buffer.cpp
Executable file
129
Deer/src/DeerRender/Render/Buffer.cpp
Executable file
@ -0,0 +1,129 @@
|
||||
#include "DeerRender/Render/Buffer.h"
|
||||
|
||||
#include "Deer/Log.h"
|
||||
#include "DeerRender/Render/Render.h"
|
||||
|
||||
namespace Deer {
|
||||
unsigned int dataTypeSize(DataType type) {
|
||||
switch (type) {
|
||||
case DataType::None: DEER_CORE_ERROR("Unkown shader data type"); return 0;
|
||||
// Halfs : 2
|
||||
case DataType::Half: return 2;
|
||||
case DataType::Half2: return 2 * 2;
|
||||
case DataType::Half3: return 2 * 3;
|
||||
case DataType::Half4: return 2 * 4;;
|
||||
// Floats : 4
|
||||
case DataType::Float: return 4;
|
||||
case DataType::Float2: return 4 * 2;
|
||||
case DataType::Float3: return 4 * 3;
|
||||
case DataType::Float4: return 4 * 4;
|
||||
// Byte : 1
|
||||
case DataType::Byte: return 1;
|
||||
case DataType::Byte2: return 1 * 2;
|
||||
case DataType::Byte3: return 1 * 3;
|
||||
case DataType::Byte4: return 1 * 4;
|
||||
// Short : 2
|
||||
case DataType::Short: return 2;
|
||||
case DataType::Short2: return 2 * 2;
|
||||
case DataType::Short3: return 2 * 3;
|
||||
case DataType::Short4: return 2 * 4;
|
||||
// Ints : 4
|
||||
case DataType::Int: return 4;
|
||||
case DataType::Int2: return 4 * 2;
|
||||
case DataType::Int3: return 4 * 3;
|
||||
case DataType::Int4: return 4 * 4;
|
||||
// Byte : 1
|
||||
case DataType::Unsigned_Byte: return 1;
|
||||
case DataType::Unsigned_Byte2: return 1 * 2;
|
||||
case DataType::Unsigned_Byte3: return 1 * 3;
|
||||
case DataType::Unsigned_Byte4: return 1 * 4;
|
||||
// Short : 2
|
||||
case DataType::Unsigned_Short: return 2;
|
||||
case DataType::Unsigned_Short2: return 2 * 2;
|
||||
case DataType::Unsigned_Short3: return 2 * 3;
|
||||
case DataType::Unsigned_Short4: return 2 * 4;
|
||||
// Ints : 4
|
||||
case DataType::Unsigned_Int: return 4;
|
||||
case DataType::Unsigned_Int2: return 4 * 2;
|
||||
case DataType::Unsigned_Int3: return 4 * 3;
|
||||
case DataType::Unsigned_Int4: return 4 * 4;
|
||||
}
|
||||
|
||||
DEER_CORE_ERROR("Unkown shader data type");
|
||||
}
|
||||
|
||||
unsigned int dataTypeCount(DataType type) {
|
||||
switch (type) {
|
||||
case DataType::None: DEER_CORE_ERROR("Unkown shader data type"); return 0;
|
||||
// Halfs : 2
|
||||
case DataType::Half: return 1;
|
||||
case DataType::Half2: return 2;
|
||||
case DataType::Half3: return 3;
|
||||
case DataType::Half4: return 4;
|
||||
// Floats : 4
|
||||
case DataType::Float: return 1;
|
||||
case DataType::Float2: return 2;
|
||||
case DataType::Float3: return 3;
|
||||
case DataType::Float4: return 4;
|
||||
// Byte : 1
|
||||
case DataType::Byte: return 1;
|
||||
case DataType::Byte2: return 2;
|
||||
case DataType::Byte3: return 3;
|
||||
case DataType::Byte4: return 4;
|
||||
// Short : 2
|
||||
case DataType::Short: return 1;
|
||||
case DataType::Short2: return 2;
|
||||
case DataType::Short3: return 3;
|
||||
case DataType::Short4: return 4;
|
||||
// Ints : 4
|
||||
case DataType::Int: return 1;
|
||||
case DataType::Int2: return 2;
|
||||
case DataType::Int3: return 3;
|
||||
case DataType::Int4: return 4;
|
||||
// Byte : 1
|
||||
case DataType::Unsigned_Byte: return 1;
|
||||
case DataType::Unsigned_Byte2: return 2;
|
||||
case DataType::Unsigned_Byte3: return 3;
|
||||
case DataType::Unsigned_Byte4: return 4;
|
||||
// Short : 2
|
||||
case DataType::Unsigned_Short: return 1;
|
||||
case DataType::Unsigned_Short2: return 2;
|
||||
case DataType::Unsigned_Short3: return 3;
|
||||
case DataType::Unsigned_Short4: return 4;
|
||||
// Ints : 4
|
||||
case DataType::Unsigned_Int: return 1;
|
||||
case DataType::Unsigned_Int2: return 2;
|
||||
case DataType::Unsigned_Int3: return 3;
|
||||
case DataType::Unsigned_Int4: return 4;
|
||||
}
|
||||
|
||||
DEER_CORE_ERROR("Unkown shader data type");
|
||||
}
|
||||
|
||||
unsigned int indexDataTypeSize(IndexDataType type)
|
||||
{
|
||||
switch (type) {
|
||||
case IndexDataType::None: DEER_CORE_ERROR("Unkown shader data type"); return 0;
|
||||
|
||||
case IndexDataType::Unsigned_Byte: return 1;
|
||||
case IndexDataType::Unsigned_Short: return 2;
|
||||
case IndexDataType::Unsigned_Int: return 4;
|
||||
}
|
||||
|
||||
DEER_CORE_ERROR("Unkown shader data type");
|
||||
}
|
||||
|
||||
void BufferLayout::calculateOffsetAndStride() {
|
||||
unsigned int offset = 0;
|
||||
int calc_stride = 0;
|
||||
for (auto& element : m_bufferElements) {
|
||||
if (element.offset == -1)
|
||||
element.offset = offset;
|
||||
offset += dataTypeSize(element.type);
|
||||
calc_stride += dataTypeSize(element.type);
|
||||
}
|
||||
|
||||
if (m_stride == -1)
|
||||
m_stride = calc_stride;
|
||||
}
|
||||
}
|
22
Deer/src/DeerRender/Render/Camera.cpp
Executable file
22
Deer/src/DeerRender/Render/Camera.cpp
Executable file
@ -0,0 +1,22 @@
|
||||
#include "DeerRender/Render/Camera.h"
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include "glm/gtc/matrix_transform.hpp"
|
||||
|
||||
namespace Deer {
|
||||
Camera::Camera(float aspect, float fov, float nearZ, float farZ)
|
||||
: m_aspect(aspect), m_fov(fov), m_nearZ(nearZ), m_farZ(farZ), m_position(glm::vec3(0)), m_rotation(glm::quat()){
|
||||
recalculateMatrices();
|
||||
}
|
||||
|
||||
void Camera::recalculateMatrices() {
|
||||
m_viewMatrix = glm::perspective(glm::radians(m_fov), m_aspect, m_nearZ, m_farZ);
|
||||
//m_viewMatrix = glm::inverse(m_viewMatrix);
|
||||
|
||||
glm::mat4 zInvertedMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(1.0f, 1.0f, -1.0f));
|
||||
m_projectionMatrix = glm::translate(glm::mat4(1.0f), m_position);
|
||||
m_projectionMatrix = m_projectionMatrix * glm::toMat4(m_rotation);
|
||||
m_projectionMatrix = zInvertedMatrix * glm::inverse(m_projectionMatrix);
|
||||
}
|
||||
}
|
21
Deer/src/DeerRender/Render/MeshUtils.cpp
Executable file
21
Deer/src/DeerRender/Render/MeshUtils.cpp
Executable file
@ -0,0 +1,21 @@
|
||||
#include "MeshUtils.h"
|
||||
#include "DeerRender/Render/Buffer.h"
|
||||
#include "DeerRender/Render/VertexArray.h"
|
||||
|
||||
namespace Deer {
|
||||
Ref<VertexArray> MeshUtils::createMesh(int vertexCount, float* vertices, int indexCount, unsigned int* m_indices) {
|
||||
Ref<VertexBuffer> vBuffer = VertexBuffer::create(vertices, vertexCount * sizeof(float));
|
||||
Ref<IndexBuffer> iBuffer = IndexBuffer::create(m_indices, indexCount * sizeof(unsigned int), IndexDataType::Unsigned_Int);
|
||||
|
||||
BufferLayout layout({
|
||||
{"a_Position", DataType::Float3, ShaderDataType::FloatingPoint}
|
||||
});
|
||||
vBuffer->setLayout(layout);
|
||||
|
||||
Ref<VertexArray> vertexArray = VertexArray::create();
|
||||
vertexArray->addVertexBuffer(vBuffer);
|
||||
vertexArray->setIndexBuffer(iBuffer);
|
||||
|
||||
return vertexArray;
|
||||
}
|
||||
}
|
12
Deer/src/DeerRender/Render/MeshUtils.h
Executable file
12
Deer/src/DeerRender/Render/MeshUtils.h
Executable file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "Deer/Memory.h"
|
||||
|
||||
namespace Deer {
|
||||
class VertexArray;
|
||||
|
||||
class MeshUtils {
|
||||
public:
|
||||
static Ref<VertexArray> createMesh(int vertexCount, float* vertices, int indexCount, unsigned int* m_indices);
|
||||
};
|
||||
}
|
||||
|
25
Deer/src/DeerRender/Render/Render.cpp
Executable file
25
Deer/src/DeerRender/Render/Render.cpp
Executable file
@ -0,0 +1,25 @@
|
||||
#include "Render.h"
|
||||
#include "DeerRender/Render/RenderCommand.h"
|
||||
#include "DeerRender/Render/VertexArray.h"
|
||||
#include "DeerRender/Render/RenderAPI.h"
|
||||
|
||||
namespace Deer {
|
||||
void Render::beginExecution() {
|
||||
|
||||
}
|
||||
|
||||
void Render::endExecution() {
|
||||
|
||||
}
|
||||
|
||||
void Render::submit(const Ref<VertexArray>& vertexArray) {
|
||||
vertexArray->bind();
|
||||
RenderCommand::drawIndex(vertexArray);
|
||||
}
|
||||
|
||||
void Render::submitLine(const Ref<VertexArray>& vertexArray) {
|
||||
vertexArray->bind();
|
||||
RenderCommand::drawLines(vertexArray);
|
||||
}
|
||||
|
||||
}
|
16
Deer/src/DeerRender/Render/Render.h
Executable file
16
Deer/src/DeerRender/Render/Render.h
Executable file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "DeerRender/Render/RenderAPI.h"
|
||||
|
||||
namespace Deer {
|
||||
class VertexArray;
|
||||
|
||||
class Render {
|
||||
public:
|
||||
static void beginExecution();
|
||||
static void endExecution();
|
||||
|
||||
static void submit(const Ref<VertexArray>& vertexArray);
|
||||
static void submitLine(const Ref<VertexArray>& vertexArray);
|
||||
static RenderAPI::API getAPI() { return RenderAPI::getAPI(); }
|
||||
};
|
||||
}
|
10
Deer/src/DeerRender/Render/RenderAPI.cpp
Executable file
10
Deer/src/DeerRender/Render/RenderAPI.cpp
Executable file
@ -0,0 +1,10 @@
|
||||
#include "RenderAPI.h"
|
||||
#include "DeerRender/Render/VertexArray.h"
|
||||
|
||||
namespace Deer {
|
||||
#ifdef DEER_RENDER
|
||||
RenderAPI::API RenderAPI::s_API = RenderAPI::API::OpenGL;
|
||||
#else // !DEER_SERVICE
|
||||
RenderAPI::API RenderAPI::s_API = RenderAPI::API::None;
|
||||
#endif
|
||||
}
|
30
Deer/src/DeerRender/Render/RenderAPI.h
Executable file
30
Deer/src/DeerRender/Render/RenderAPI.h
Executable file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include "Deer/Memory.h"
|
||||
#include "glm/glm.hpp"
|
||||
|
||||
namespace Deer {
|
||||
class VertexArray;
|
||||
|
||||
class RenderAPI {
|
||||
public:
|
||||
enum class API {
|
||||
None = 0,
|
||||
OpenGL = 1
|
||||
};
|
||||
public:
|
||||
virtual ~RenderAPI() = default;
|
||||
|
||||
virtual void init() = 0;
|
||||
virtual void clearColor(const glm::vec4& color) = 0;
|
||||
virtual void setDepthBuffer(bool enable) = 0;
|
||||
virtual void setBackfaceCulling(bool enable) = 0;
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual void drawIndex(const Ref<VertexArray>& vertexArray) = 0;
|
||||
virtual void drawLines(const Ref<VertexArray>& vertexArray) = 0;
|
||||
|
||||
inline static API getAPI() { return s_API; }
|
||||
private:
|
||||
static API s_API;
|
||||
};
|
||||
}
|
44
Deer/src/DeerRender/Render/RenderCommand.h
Executable file
44
Deer/src/DeerRender/Render/RenderCommand.h
Executable file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include "Deer/Memory.h"
|
||||
#include "DeerRender/Render/RenderAPI.h"
|
||||
|
||||
#include "glm/glm.hpp"
|
||||
|
||||
namespace Deer {
|
||||
class VertexArray;
|
||||
class RenderAPI;
|
||||
|
||||
class RenderCommand {
|
||||
public:
|
||||
static inline void setClearColor(const glm::vec4& color) {
|
||||
s_renderAPI->clearColor(color);
|
||||
}
|
||||
|
||||
static inline void clear() {
|
||||
s_renderAPI->clear();
|
||||
}
|
||||
|
||||
static inline void drawIndex(const Ref<VertexArray>& vertexArray) {
|
||||
s_renderAPI->drawIndex(vertexArray);
|
||||
}
|
||||
|
||||
static inline void drawLines(const Ref<VertexArray>& vertexArray) {
|
||||
s_renderAPI->drawLines(vertexArray);
|
||||
}
|
||||
|
||||
static inline void setDepthBuffer(bool state) {
|
||||
s_renderAPI->setDepthBuffer(state);
|
||||
}
|
||||
|
||||
static inline void setBackfaceCulling(bool state) {
|
||||
s_renderAPI->setBackfaceCulling(state);
|
||||
}
|
||||
|
||||
static inline void init() {
|
||||
s_renderAPI->init();
|
||||
}
|
||||
|
||||
private:
|
||||
static Scope<RenderAPI> s_renderAPI;
|
||||
};
|
||||
}
|
9
Deer/src/DeerRender/Render/RenderContext.h
Executable file
9
Deer/src/DeerRender/Render/RenderContext.h
Executable file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
namespace Deer {
|
||||
class RenderContext {
|
||||
public:
|
||||
virtual void init() = 0;
|
||||
virtual void swapBuffers() = 0;
|
||||
};
|
||||
}
|
||||
|
182
Deer/src/DeerRender/Render/RenderUtils.cpp
Executable file
182
Deer/src/DeerRender/Render/RenderUtils.cpp
Executable file
@ -0,0 +1,182 @@
|
||||
#include "RenderUtils.h"
|
||||
#include "DeerRender/Render/VertexArray.h"
|
||||
#include "DeerRender/Render/Buffer.h"
|
||||
#include "DeerRender/Render/Shader.h"
|
||||
|
||||
#ifdef DEER_RENDER
|
||||
|
||||
namespace Deer {
|
||||
namespace RenderUtils {
|
||||
Ref<VertexArray> m_lineVertexArray;
|
||||
Ref<VertexArray> m_faceVertexArray;
|
||||
Ref<Shader> m_lineShader;
|
||||
Ref<Shader> m_faceShader;
|
||||
|
||||
Ref<VertexArray> genLineVertexArray();
|
||||
Ref<VertexArray> genFaceVertexArray();
|
||||
Ref<Shader> getLineShader();
|
||||
Ref<Shader> getFaceShader();
|
||||
}
|
||||
|
||||
void RenderUtils::initializeRenderUtils() {
|
||||
m_lineVertexArray = genLineVertexArray();
|
||||
m_lineShader = getLineShader();
|
||||
m_faceVertexArray = genFaceVertexArray();
|
||||
m_faceShader = getFaceShader();
|
||||
}
|
||||
|
||||
Ref<VertexArray> RenderUtils::genLineVertexArray() {
|
||||
unsigned int vertices[2] = { 0, 1 };
|
||||
|
||||
Ref<VertexArray> vertexArray = VertexArray::create();
|
||||
vertexArray->bind();
|
||||
|
||||
Ref<VertexBuffer> vertexBuffer = VertexBuffer::create(vertices, sizeof(vertices));
|
||||
Ref<IndexBuffer> indexBuffer = IndexBuffer::create(vertices, sizeof(vertices), IndexDataType::Unsigned_Int);
|
||||
|
||||
BufferLayout layout({
|
||||
{"a_vertexID", DataType::Unsigned_Int, ShaderDataType::Integer}
|
||||
});
|
||||
|
||||
vertexBuffer->setLayout(layout);
|
||||
vertexArray->addVertexBuffer(vertexBuffer);
|
||||
vertexArray->setIndexBuffer(indexBuffer);
|
||||
|
||||
return vertexArray;
|
||||
}
|
||||
|
||||
Ref<Shader> RenderUtils::getLineShader() {
|
||||
std::string vertexSrc = R"(
|
||||
#version 410 core
|
||||
|
||||
layout(location = 0) in int a_vertexID;
|
||||
|
||||
uniform mat4 u_viewMatrix;
|
||||
uniform vec3 u_posA;
|
||||
uniform vec3 u_posB;
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
vec3 pos;
|
||||
if (a_vertexID == 0) {
|
||||
pos = u_posA;
|
||||
} else {
|
||||
pos = u_posB;
|
||||
}
|
||||
|
||||
gl_Position = u_viewMatrix * vec4(pos,1.0);
|
||||
})";
|
||||
|
||||
std::string fragmentSrc = R"(
|
||||
#version 410 core
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out int objectID;
|
||||
|
||||
uniform vec3 u_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
objectID = -1;
|
||||
fragColor = vec4(u_color, 1.0);
|
||||
})";
|
||||
|
||||
return Shader::create(vertexSrc, fragmentSrc);
|
||||
}
|
||||
|
||||
Ref<VertexArray> RenderUtils::genFaceVertexArray() {
|
||||
unsigned int vertices[4] = {
|
||||
0, 1, 2, 3
|
||||
};
|
||||
unsigned int indices[6] = {
|
||||
0, 2, 1, 1, 2, 3
|
||||
};
|
||||
|
||||
Ref<VertexArray> vertexArray = VertexArray::create();
|
||||
vertexArray->bind();
|
||||
|
||||
Ref<VertexBuffer> vertexBuffer = VertexBuffer::create(vertices, sizeof(vertices));
|
||||
Ref<IndexBuffer> indexBuffer = IndexBuffer::create(indices, sizeof(indices), IndexDataType::Unsigned_Int);
|
||||
|
||||
BufferLayout layout({
|
||||
{"a_vertexID", DataType::Unsigned_Int, ShaderDataType::Integer}
|
||||
});
|
||||
|
||||
vertexBuffer->setLayout(layout);
|
||||
vertexArray->addVertexBuffer(vertexBuffer);
|
||||
vertexArray->setIndexBuffer(indexBuffer);
|
||||
|
||||
return vertexArray;
|
||||
}
|
||||
|
||||
Ref<Shader> RenderUtils::getFaceShader() {
|
||||
std::string vertexSrc = R"(
|
||||
#version 410 core
|
||||
|
||||
layout(location = 0) in int a_vertexID;
|
||||
|
||||
uniform mat4 u_viewMatrix;
|
||||
uniform vec3 u_posA;
|
||||
uniform vec3 u_posB;
|
||||
uniform vec3 u_posC;
|
||||
uniform vec3 u_posD;
|
||||
|
||||
uniform int u_textureSize;
|
||||
uniform int u_textureID;
|
||||
|
||||
out vec2 uv;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 pos;
|
||||
vec2 a_uv;
|
||||
if (a_vertexID == 0) {
|
||||
pos = u_posA;
|
||||
a_uv = vec2(0, 0);
|
||||
} else if (a_vertexID == 1) {
|
||||
pos = u_posB;
|
||||
a_uv = vec2(1, 0);
|
||||
} else if (a_vertexID == 2) {
|
||||
pos = u_posC;
|
||||
a_uv = vec2(0, 1);
|
||||
} else {
|
||||
pos = u_posD;
|
||||
a_uv = vec2(1, 1);
|
||||
}
|
||||
|
||||
int posY = u_textureID / u_textureSize;
|
||||
int posX = u_textureID - posY * u_textureSize;
|
||||
|
||||
uv = vec2((a_uv.x + float(posX)) / float(u_textureSize), (a_uv.y + float(posY)) / float(u_textureSize));
|
||||
|
||||
gl_Position = u_viewMatrix * vec4(pos,1.0);
|
||||
})";
|
||||
|
||||
std::string fragmentSrc = R"(
|
||||
#version 410 core
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out int objectID;
|
||||
|
||||
in vec2 uv;
|
||||
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture(u_texture, uv);
|
||||
if (color.a == 0){
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
objectID = -1;
|
||||
fragColor = color;
|
||||
})";
|
||||
|
||||
return Shader::create(vertexSrc, fragmentSrc);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
17
Deer/src/DeerRender/Render/RenderUtils.h
Executable file
17
Deer/src/DeerRender/Render/RenderUtils.h
Executable file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "Deer/Memory.h"
|
||||
|
||||
namespace Deer {
|
||||
class VertexArray;
|
||||
class Shader;
|
||||
|
||||
namespace RenderUtils {
|
||||
extern Ref<VertexArray> m_lineVertexArray;
|
||||
extern Ref<VertexArray> m_faceVertexArray;
|
||||
extern Ref<Shader> m_lineShader;
|
||||
extern Ref<Shader> m_faceShader;
|
||||
|
||||
void initializeRenderUtils();
|
||||
}
|
||||
}
|
||||
|
156
Deer/src/DeerRender/Scene/Environment.cpp
Executable file
156
Deer/src/DeerRender/Scene/Environment.cpp
Executable file
@ -0,0 +1,156 @@
|
||||
#include "Deer/Enviroment.h"
|
||||
|
||||
#include "Deer/Application.h"
|
||||
#include "Deer/Asset.h"
|
||||
|
||||
#include "Deer/Components.h"
|
||||
#include "Deer/Voxel.h"
|
||||
|
||||
#include "DeerRender/Render/Render.h"
|
||||
#include "DeerRender/Render/RenderUtils.h"
|
||||
#include "DeerRender/Render/Texture.h"
|
||||
|
||||
#include "Deer/Log.h"
|
||||
|
||||
namespace Deer {
|
||||
void Environment::render(SceneCamera& camera) {
|
||||
glm::mat4 camMatrix = glm::inverse(camera.transform.getMatrix());
|
||||
glm::mat4 projectionMatrix = camera.camera.getMatrix();
|
||||
glm::mat4 invertZ = glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, -1));
|
||||
|
||||
// Lets invert the z axis for engine convenience
|
||||
glm::mat4 cameraProjectionMatrix = projectionMatrix * invertZ * camMatrix;
|
||||
{
|
||||
auto view = m_registry.view<MeshRenderComponent, TagComponent>();
|
||||
for (auto entityId : view) {
|
||||
auto& meshRender = view.get<MeshRenderComponent>(entityId);
|
||||
if (meshRender.shaderAssetID == 0)
|
||||
continue;
|
||||
|
||||
if (meshRender.meshAssetID == 0)
|
||||
continue;
|
||||
|
||||
auto& tag = view.get<TagComponent>(entityId);
|
||||
Entity& entity = getEntity(tag.entityUID);
|
||||
|
||||
if (entity.hasComponent<TextureBindingComponent>()) {
|
||||
TextureBindingComponent& textureBinding = entity.getComponent<TextureBindingComponent>();
|
||||
|
||||
for (int x = 0; x < MAX_TEXTURE_BINDINGS; x++) {
|
||||
if (textureBinding.textureAssetID[x] == 0)
|
||||
continue;
|
||||
|
||||
Asset<Texture2D>& textureAsset = AssetManager::getAsset<Texture2D>(textureBinding.textureAssetID[x]);
|
||||
textureAsset.value->bind(textureBinding.textureBindID[x]);
|
||||
}
|
||||
}
|
||||
|
||||
glm::mat4 matrix = entity.getWorldMatrix();
|
||||
Asset<Shader>& shaderAsset = AssetManager::getAsset<Shader>(meshRender.shaderAssetID);
|
||||
shaderAsset.value->bind();
|
||||
shaderAsset.value->uploadUniformMat4("u_viewMatrix", cameraProjectionMatrix);
|
||||
shaderAsset.value->uploadUniformMat4("u_worldMatrix", matrix);
|
||||
shaderAsset.value->uploadUniformInt("u_objectID", tag.entityUID);
|
||||
|
||||
Asset<Mesh>& meshAsset = AssetManager::getAsset<Mesh>(meshRender.meshAssetID);
|
||||
meshAsset.value->bind();
|
||||
|
||||
Render::submit(meshAsset.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw Grid Gizmo
|
||||
{
|
||||
RenderUtils::m_lineShader->bind();
|
||||
RenderUtils::m_lineShader->uploadUniformMat4("u_viewMatrix", cameraProjectionMatrix);
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_color", glm::vec3(.5f, .5f, .5f));
|
||||
for (int x = 0; x < CHUNK_SIZE_X + 1; x++) {
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posA", glm::vec3(x, 0, 0));
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posB", glm::vec3(x, 0, CHUNK_SIZE_Z));
|
||||
|
||||
Render::submitLine(RenderUtils::m_lineVertexArray);
|
||||
}
|
||||
for (int z = 0; z < CHUNK_SIZE_Z + 1; z++) {
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posA", glm::vec3(0, 0, z));
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posB", glm::vec3(CHUNK_SIZE_X, 0, z));
|
||||
|
||||
Render::submitLine(RenderUtils::m_lineVertexArray);
|
||||
}
|
||||
}
|
||||
|
||||
// Rendering Camera Gizmo
|
||||
{
|
||||
RenderUtils::m_lineShader->bind();
|
||||
RenderUtils::m_lineShader->uploadUniformMat4("u_viewMatrix", cameraProjectionMatrix);
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_color", glm::vec3(.7f, .85f, 1));
|
||||
|
||||
auto view = m_registry.view<CameraComponent, TagComponent>();
|
||||
for (auto entityId : view) {
|
||||
CameraComponent cameraComponent = view.get<CameraComponent>(entityId);
|
||||
cameraComponent.nearZ = .5f;
|
||||
cameraComponent.farZ = 2;
|
||||
TagComponent& tag = view.get<TagComponent>(entityId);
|
||||
|
||||
Entity& entity = getEntity(tag.entityUID);
|
||||
|
||||
glm::mat4 matrix = entity.getWorldMatrix();
|
||||
glm::mat4 camPrespective = glm::inverse(cameraComponent.getMatrix());
|
||||
|
||||
glm::mat4 cameraMatrix = camPrespective;
|
||||
glm::vec3 cameraAxisPoints[2 * 2 * 2];
|
||||
|
||||
// Generate 8 Points
|
||||
for (int x = 0; x < 2; x++) {
|
||||
for (int y = 0; y < 2; y++) {
|
||||
for (int z = 0; z < 2; z++) {
|
||||
glm::vec4 endPos = invertZ * camPrespective * glm::vec4(x * 2 - 1, y * 2 - 1, z, 1);
|
||||
endPos = endPos * endPos.w;
|
||||
endPos.w = 1;
|
||||
|
||||
cameraAxisPoints[z * 4 + y * 2 + x] = matrix * endPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the lines
|
||||
for (int x = 0; x < 2; x++) {
|
||||
for (int y = 0; y < 2; y++) {
|
||||
int posA = 0 * 4 + y * 2 + x;
|
||||
int posB = 1 * 4 + y * 2 + x;
|
||||
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posA", cameraAxisPoints[posA]);
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posB", cameraAxisPoints[posB]);
|
||||
|
||||
Render::submitLine(RenderUtils::m_lineVertexArray);
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x < 2; x++) {
|
||||
for (int z = 0; z < 2; z++) {
|
||||
int posA = z * 4 + 0 * 2 + x;
|
||||
int posB = z * 4 + 1 * 2 + x;
|
||||
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posA", cameraAxisPoints[posA]);
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posB", cameraAxisPoints[posB]);
|
||||
|
||||
Render::submitLine(RenderUtils::m_lineVertexArray);
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < 2; y++) {
|
||||
for (int z = 0; z < 2; z++) {
|
||||
int posA = z * 4 + y * 2 + 0;
|
||||
int posB = z * 4 + y * 2 + 1;
|
||||
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posA", cameraAxisPoints[posA]);
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posB", cameraAxisPoints[posB]);
|
||||
|
||||
Render::submitLine(RenderUtils::m_lineVertexArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
166
Deer/src/DeerRender/Scene/GizmoRenderer.cpp
Executable file
166
Deer/src/DeerRender/Scene/GizmoRenderer.cpp
Executable file
@ -0,0 +1,166 @@
|
||||
#include "DeerRender/GizmoRenderer.h"
|
||||
#include "DeerRender/Render/Render.h"
|
||||
#include "Deer/Voxel.h"
|
||||
#include "DeerRender/LightVoxel.h"
|
||||
#include "DeerRender/Render/RenderUtils.h"
|
||||
#include "DeerRender/SceneCamera.h"
|
||||
#include "Deer/Components.h"
|
||||
#include "DeerRender/Render/Texture.h"
|
||||
#include "DeerRender/Render/RenderCommand.h"
|
||||
|
||||
|
||||
namespace Deer {
|
||||
void GizmoRenderer::drawLine(glm::vec3 a, glm::vec3 b, glm::vec3 color) {
|
||||
m_lines.push_back({ a, b, color });
|
||||
}
|
||||
|
||||
void GizmoRenderer::drawVoxelLine(int _x, int _y, int _z, glm::vec3 color) {
|
||||
for (int x = 0; x < 2; x++) {
|
||||
for (int y = 0; y < 2; y++) {
|
||||
glm::vec3 a = glm::vec3(x + _x, y + _y, 0 + _z);
|
||||
glm::vec3 b = glm::vec3(x + _x, y + _y, 1 + _z);
|
||||
|
||||
drawLine(a, b, color);
|
||||
}
|
||||
}
|
||||
for (int z = 0; z < 2; z++) {
|
||||
for (int y = 0; y < 2; y++) {
|
||||
glm::vec3 a = glm::vec3(0 + _x, y + _y, z + _z);
|
||||
glm::vec3 b = glm::vec3(1 + _x, y + _y, z + _z);
|
||||
|
||||
drawLine(a, b, color);
|
||||
}
|
||||
}
|
||||
for (int x = 0; x < 2; x++) {
|
||||
for (int z = 0; z < 2; z++) {
|
||||
glm::vec3 a = glm::vec3(x + _x, 0 + _y, z + _z);
|
||||
glm::vec3 b = glm::vec3(x + _x, 1 + _y, z + _z);
|
||||
|
||||
drawLine(a, b, color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GizmoRenderer::drawVoxelLineFace(int x, int y, int z, uint8_t face, glm::vec3 color) {
|
||||
glm::vec3 points[4];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
points[i] = {
|
||||
x + NORMAL_VERTEX_POS(X_AXIS, i, face),
|
||||
y + NORMAL_VERTEX_POS(Y_AXIS, i, face),
|
||||
z + NORMAL_VERTEX_POS(Z_AXIS, i, face)
|
||||
};
|
||||
}
|
||||
|
||||
drawLine(points[0], points[1], color);
|
||||
drawLine(points[2], points[3], color);
|
||||
drawLine(points[0], points[2], color);
|
||||
drawLine(points[1], points[3], color);
|
||||
}
|
||||
|
||||
void GizmoRenderer::drawVoxelFace(int x, int y, int z, uint16_t voxelID, uint8_t faceID, uint8_t priority) {
|
||||
glm::vec3 points[4];
|
||||
VoxelAspect& aspect = VoxelData::voxelsAspect[voxelID];
|
||||
GizmoFace face;
|
||||
face.textureID = aspect.textureFacesIDs[faceID];
|
||||
face.face = faceID;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
face.positions[i] = {
|
||||
x + NORMAL_VERTEX_POS(X_AXIS, i, faceID),
|
||||
y + NORMAL_VERTEX_POS(Y_AXIS, i, faceID),
|
||||
z + NORMAL_VERTEX_POS(Z_AXIS, i, faceID)
|
||||
};
|
||||
}
|
||||
|
||||
m_faces[priority].push_back(face);
|
||||
}
|
||||
|
||||
void GizmoRenderer::drawVoxelFaceInverted(int x, int y, int z, uint16_t voxelID, uint8_t faceID, uint8_t priority) {
|
||||
glm::vec3 points[4];
|
||||
VoxelAspect& aspect = VoxelData::voxelsAspect[voxelID];
|
||||
GizmoFace face;
|
||||
face.textureID = aspect.textureFacesIDs[faceID];
|
||||
face.face = faceID;
|
||||
|
||||
face.positions[0] = {
|
||||
x + NORMAL_VERTEX_POS(X_AXIS, 0, faceID),
|
||||
y + NORMAL_VERTEX_POS(Y_AXIS, 0, faceID),
|
||||
z + NORMAL_VERTEX_POS(Z_AXIS, 0, faceID)
|
||||
};
|
||||
|
||||
face.positions[2] = {
|
||||
x + NORMAL_VERTEX_POS(X_AXIS, 1, faceID),
|
||||
y + NORMAL_VERTEX_POS(Y_AXIS, 1, faceID),
|
||||
z + NORMAL_VERTEX_POS(Z_AXIS, 1, faceID)
|
||||
};
|
||||
|
||||
face.positions[1] = {
|
||||
x + NORMAL_VERTEX_POS(X_AXIS, 2, faceID),
|
||||
y + NORMAL_VERTEX_POS(Y_AXIS, 2, faceID),
|
||||
z + NORMAL_VERTEX_POS(Z_AXIS, 2, faceID)
|
||||
};
|
||||
|
||||
face.positions[3] = {
|
||||
x + NORMAL_VERTEX_POS(X_AXIS, 3, faceID),
|
||||
y + NORMAL_VERTEX_POS(Y_AXIS, 3, faceID),
|
||||
z + NORMAL_VERTEX_POS(Z_AXIS, 3, faceID)
|
||||
};
|
||||
|
||||
m_faces[priority].push_back(face);
|
||||
}
|
||||
|
||||
void GizmoRenderer::render(const SceneCamera& camera) {
|
||||
|
||||
RenderCommand::setDepthBuffer(true);
|
||||
|
||||
// We make a exact camera but with less far clip to give priority in the depht test
|
||||
CameraComponent camera_lessDistance = camera.camera;
|
||||
camera_lessDistance.farZ *= 1.1f;
|
||||
|
||||
glm::mat4 camMatrix = glm::inverse(camera.transform.getMatrix());
|
||||
glm::mat4 projectionMatrix = camera_lessDistance.getMatrix();
|
||||
glm::mat4 invertZ = glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, -1));
|
||||
|
||||
glm::mat4 cameraProjectionMatrix = projectionMatrix * invertZ * camMatrix;
|
||||
|
||||
VoxelData::getVoxelColorTextureAtlas()->bind(0);
|
||||
RenderUtils::m_faceShader->bind();
|
||||
RenderUtils::m_faceShader->uploadUniformMat4("u_viewMatrix", cameraProjectionMatrix);
|
||||
RenderUtils::m_faceShader->uploadUniformInt("u_texture", 0);
|
||||
RenderUtils::m_faceShader->uploadUniformInt("u_textureSize", VoxelData::getVoxelTextureAtlasSize());
|
||||
|
||||
for (int i = 0; i < GIZMO_DEPTH; i++) {
|
||||
for (GizmoFace& face : m_faces[i]) {
|
||||
RenderUtils::m_faceShader->uploadUniformInt("u_textureID", face.textureID);
|
||||
|
||||
RenderUtils::m_faceShader->uploadUniformFloat3("u_posA", face.positions[0]);
|
||||
RenderUtils::m_faceShader->uploadUniformFloat3("u_posB", face.positions[1]);
|
||||
RenderUtils::m_faceShader->uploadUniformFloat3("u_posC", face.positions[2]);
|
||||
RenderUtils::m_faceShader->uploadUniformFloat3("u_posD", face.positions[3]);
|
||||
|
||||
Render::submit(RenderUtils::m_faceVertexArray);
|
||||
}
|
||||
}
|
||||
|
||||
RenderCommand::setDepthBuffer(false);
|
||||
|
||||
for (std::array<glm::vec3, 3>&line : m_lines) {
|
||||
RenderUtils::m_lineShader->bind();
|
||||
RenderUtils::m_lineShader->uploadUniformMat4("u_viewMatrix", cameraProjectionMatrix);
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_color", line[2]);
|
||||
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posA", line[0]);
|
||||
RenderUtils::m_lineShader->uploadUniformFloat3("u_posB", line[1]);
|
||||
|
||||
Render::submitLine(RenderUtils::m_lineVertexArray);
|
||||
}
|
||||
}
|
||||
|
||||
void GizmoRenderer::refresh() {
|
||||
m_lines.clear();
|
||||
for (int i = 0; i < GIZMO_DEPTH; i++)
|
||||
m_faces[i].clear();
|
||||
}
|
||||
}
|
31
Deer/src/DeerRender/Scene/Scene.cpp
Executable file
31
Deer/src/DeerRender/Scene/Scene.cpp
Executable file
@ -0,0 +1,31 @@
|
||||
#include "Deer/Scene.h"
|
||||
#include "Deer/Enviroment.h"
|
||||
#include "Deer/Components.h"
|
||||
#include "Deer/VoxelWorld.h"
|
||||
#include "DeerRender/Render/RenderCommand.h"
|
||||
#include "Deer/Enviroment.h"
|
||||
|
||||
namespace Deer {
|
||||
void Scene::render() {
|
||||
uint32_t mainCamera = m_enviroment->tryGetMainCamera();
|
||||
if (mainCamera == 0)
|
||||
return;
|
||||
|
||||
Entity& m_cameraEntity = m_enviroment->getEntity(mainCamera);
|
||||
SceneCamera sceneCamera;
|
||||
sceneCamera.camera = m_cameraEntity.getComponent<CameraComponent>();
|
||||
sceneCamera.transform = m_cameraEntity.getComponent<TransformComponent>();
|
||||
|
||||
Scene::render(sceneCamera);
|
||||
}
|
||||
|
||||
void Scene::render(SceneCamera sceneCamera) {
|
||||
RenderCommand::setDepthBuffer(true);
|
||||
m_enviroment->render(sceneCamera);
|
||||
if (m_voxelWorld)
|
||||
m_voxelWorld->render(sceneCamera);
|
||||
RenderCommand::setDepthBuffer(false);
|
||||
m_gizmoRenderer.render(sceneCamera);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "DeerRender/Components.h"
|
||||
|
||||
namespace Deer {
|
||||
// CAMERA COMPONENT
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive,
|
||||
CameraComponent& camera) {
|
||||
|
||||
archive(cereal::make_nvp("aspect", camera.aspect));
|
||||
archive(cereal::make_nvp("fov", camera.fov));
|
||||
archive(cereal::make_nvp("farZ", camera.farZ));
|
||||
archive(cereal::make_nvp("nearZ", camera.nearZ));
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "Deer/Components.h"
|
||||
#include "Deer/Asset.h"
|
||||
|
||||
namespace Deer{
|
||||
template<class Archive>
|
||||
void save(Archive& archive,
|
||||
MeshRenderComponent const& meshRender) {
|
||||
|
||||
std::string meshLocation = AssetManager::getAssetLocation(meshRender.meshAssetID).generic_string();
|
||||
archive(cereal::make_nvp("mesh", meshLocation));
|
||||
std::string shaderLocation = AssetManager::getAssetLocation(meshRender.shaderAssetID).generic_string();
|
||||
archive(cereal::make_nvp("shader", shaderLocation));
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive& archive,
|
||||
MeshRenderComponent& meshRender) {
|
||||
|
||||
std::string meshLocation;
|
||||
archive(cereal::make_nvp("mesh", meshLocation));
|
||||
std::string shaderLocation;
|
||||
archive(cereal::make_nvp("shader", shaderLocation));
|
||||
|
||||
meshRender.meshAssetID = AssetManager::loadAsset<Mesh>(std::filesystem::path(meshLocation));
|
||||
meshRender.shaderAssetID = AssetManager::loadAsset<Shader>(std::filesystem::path(shaderLocation));
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include "Deer/Components.h"
|
||||
#include "DeerRender/Render/Texture.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Deer {
|
||||
struct TextureBinding {
|
||||
std::string texturePath;
|
||||
unsigned char bindingID;
|
||||
|
||||
TextureBinding() = default;
|
||||
TextureBinding(std::string _texturePath, unsigned char _bindingID) : texturePath(_texturePath), bindingID(_bindingID) { }
|
||||
};
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive& archive,
|
||||
TextureBinding& textureBinding) {
|
||||
|
||||
archive(cereal::make_nvp("texturePath", textureBinding.texturePath));
|
||||
archive(cereal::make_nvp("bindingID", textureBinding.bindingID));
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive& archive,
|
||||
TextureBindingComponent& textureBinding) {
|
||||
std::vector<TextureBinding> bindings;
|
||||
|
||||
archive(cereal::make_nvp("bindings", bindings));
|
||||
|
||||
int id = 0;
|
||||
for (auto& binding : bindings) {
|
||||
if (id >= MAX_TEXTURE_BINDINGS)
|
||||
break;
|
||||
|
||||
textureBinding.textureAssetID[id] = AssetManager::loadAsset<Texture2D>(
|
||||
std::filesystem::path(binding.texturePath));
|
||||
textureBinding.textureBindID[id] = binding.bindingID;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void save(Archive& archive,
|
||||
TextureBindingComponent const& textureBinding) {
|
||||
std::vector<TextureBinding> bindings;
|
||||
|
||||
for (int x = 0; x < MAX_TEXTURE_BINDINGS; x++) {
|
||||
if (textureBinding.textureAssetID[x] != 0) {
|
||||
bindings.push_back(TextureBinding(
|
||||
AssetManager::getAssetLocation(textureBinding.textureAssetID[x]).generic_string(),
|
||||
textureBinding.textureBindID[x]
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(bindings.begin(), bindings.end(), [](TextureBinding& a, TextureBinding& b) {
|
||||
return a.bindingID < b.bindingID; });
|
||||
|
||||
archive(cereal::make_nvp("bindings", bindings));
|
||||
}
|
||||
}
|
22
Deer/src/DeerRender/Voxels/ChunkUpdateQueue.cpp
Executable file
22
Deer/src/DeerRender/Voxels/ChunkUpdateQueue.cpp
Executable file
@ -0,0 +1,22 @@
|
||||
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
|
||||
|
||||
namespace Deer {
|
||||
void ChunkUpdateQueue::addChunk(ChunkID chunkID) {
|
||||
if (m_containingChunks.contains(chunkID))
|
||||
return;
|
||||
|
||||
m_containingChunks.insert(chunkID);
|
||||
m_updateOrder.push(chunkID);
|
||||
}
|
||||
|
||||
ChunkID ChunkUpdateQueue::pullChunk() {
|
||||
ChunkID chunkID = m_updateOrder.front();
|
||||
m_updateOrder.pop();
|
||||
m_containingChunks.erase(chunkID);
|
||||
return chunkID;
|
||||
}
|
||||
|
||||
bool ChunkUpdateQueue::hasChunk() {
|
||||
return m_updateOrder.size() > 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include "DeerRender/VoxelAspect.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "Deer/Voxel.h"
|
||||
|
||||
#include "cereal/cereal.hpp"
|
||||
#include "cereal/types/string.hpp"
|
||||
|
||||
namespace Deer{
|
||||
template <class Archive>
|
||||
void serialize(Archive& archive, VoxelTextureFaceDefinition& textureFaceDefinitions) {
|
||||
archive(cereal::make_nvp("left", textureFaceDefinitions.textureFaces[NORMAL_LEFT]));
|
||||
archive(cereal::make_nvp("right", textureFaceDefinitions.textureFaces[NORMAL_RIGHT]));
|
||||
archive(cereal::make_nvp("down", textureFaceDefinitions.textureFaces[NORMAL_DOWN]));
|
||||
archive(cereal::make_nvp("up", textureFaceDefinitions.textureFaces[NORMAL_UP]));
|
||||
archive(cereal::make_nvp("front", textureFaceDefinitions.textureFaces[NORMAL_FRONT]));
|
||||
archive(cereal::make_nvp("back", textureFaceDefinitions.textureFaces[NORMAL_BACK]));
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& archive, VoxelColorEmission& voxelEmission) {
|
||||
archive(cereal::make_nvp("red", voxelEmission.r_value));
|
||||
archive(cereal::make_nvp("green", voxelEmission.g_value));
|
||||
archive(cereal::make_nvp("blue", voxelEmission.b_value));
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & archive, VoxelAspectDefinition& voxelAspectDefinition) {
|
||||
archive(cereal::make_nvp("name", voxelAspectDefinition.voxelName));
|
||||
archive(cereal::make_nvp("textureFaces", voxelAspectDefinition.textureFaces));
|
||||
archive(cereal::make_nvp("emission", voxelAspectDefinition.colorEmission));
|
||||
}
|
||||
}
|
155
Deer/src/DeerRender/Voxels/Voxel.cpp
Executable file
155
Deer/src/DeerRender/Voxels/Voxel.cpp
Executable file
@ -0,0 +1,155 @@
|
||||
#include "DeerRender/LightVoxel.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace Deer {
|
||||
VoxelLight lightVoxel(255);
|
||||
|
||||
int lightPropagationComplexDir[12 * 2] = {
|
||||
NORMAL_LEFT, NORMAL_DOWN,
|
||||
NORMAL_RIGHT, NORMAL_DOWN,
|
||||
NORMAL_LEFT, NORMAL_UP,
|
||||
NORMAL_RIGHT, NORMAL_UP,
|
||||
NORMAL_LEFT, NORMAL_BACK,
|
||||
NORMAL_RIGHT, NORMAL_BACK,
|
||||
NORMAL_LEFT, NORMAL_FRONT,
|
||||
NORMAL_RIGHT, NORMAL_FRONT,
|
||||
NORMAL_DOWN, NORMAL_BACK,
|
||||
NORMAL_UP, NORMAL_BACK,
|
||||
NORMAL_DOWN, NORMAL_FRONT,
|
||||
NORMAL_UP, NORMAL_FRONT
|
||||
};
|
||||
|
||||
int normalFacePositions[3 * 4 * 6] = {
|
||||
// Left
|
||||
0, 0, 1,
|
||||
0, 0, 0,
|
||||
0, 1, 1,
|
||||
0, 1, 0,
|
||||
// Right
|
||||
1, 0, 0,
|
||||
1, 0, 1,
|
||||
1, 1, 0,
|
||||
1, 1, 1,
|
||||
// Down
|
||||
0, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
1, 0, 0,
|
||||
// Up
|
||||
0, 1, 0,
|
||||
1, 1, 0,
|
||||
0, 1, 1,
|
||||
1, 1, 1,
|
||||
// Back
|
||||
0, 0, 0,
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
1, 1, 0,
|
||||
// Front
|
||||
1, 0, 1,
|
||||
0, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 1, 1
|
||||
};
|
||||
|
||||
int uvFace[2 * 4] = {
|
||||
0, 0,
|
||||
1, 0,
|
||||
0, 1,
|
||||
1, 1
|
||||
};
|
||||
|
||||
int ambientOcclusionVertex[6 * 2 * 4 * 3]{
|
||||
0, -1, 0, 0, 0, 1,
|
||||
0, -1, 0, 0, 0, -1,
|
||||
0, 1, 0, 0, 0, 1,
|
||||
0, 1, 0, 0, 0, -1,
|
||||
0, -1, 0, 0, 0, -1,
|
||||
0, -1, 0, 0, 0, 1,
|
||||
0, 1, 0, 0, 0, -1,
|
||||
0, 1, 0, 0, 0, 1,
|
||||
-1, 0, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 1,
|
||||
-1, 0, 0, 0, 0, -1,
|
||||
1, 0, 0, 0, 0, -1,
|
||||
-1, 0, 0, 0, 0, -1,
|
||||
1, 0, 0, 0, 0, -1,
|
||||
-1, 0, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 1,
|
||||
-1, 0, 0, 0, -1, 0,
|
||||
1, 0, 0, 0, -1, 0,
|
||||
-1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, -1, 0,
|
||||
-1, 0, 0, 0, -1, 0,
|
||||
1, 0, 0, 0, 1, 0,
|
||||
-1, 0, 0, 0, 1, 0
|
||||
};
|
||||
|
||||
int layerCheckDirections[2 * 8]{
|
||||
-1, 0,
|
||||
-1, 1,
|
||||
0, 1,
|
||||
1, 1,
|
||||
1, 0,
|
||||
1, -1,
|
||||
0, -1,
|
||||
-1, -1
|
||||
};
|
||||
|
||||
void calcFaces() {
|
||||
std::string out;
|
||||
|
||||
for (int f = 0; f < 6; f++) {
|
||||
int normalDirX = NORMAL_DIR(X_AXIS, f);
|
||||
int normalDirY = NORMAL_DIR(Y_AXIS, f);
|
||||
int normalDirZ = NORMAL_DIR(Z_AXIS, f);
|
||||
|
||||
for (int vertex = 0; vertex < 4; vertex++) {
|
||||
int xPos = NORMAL_VERTEX_POS(X_AXIS, vertex, f);
|
||||
int yPos = NORMAL_VERTEX_POS(Y_AXIS, vertex, f);
|
||||
int zPos = NORMAL_VERTEX_POS(Z_AXIS, vertex, f);
|
||||
|
||||
int sideX = (xPos == 1) ? 1 : -1;
|
||||
int sideY = (yPos == 1) ? 1 : -1;
|
||||
int sideZ = (zPos == 1) ? 1 : -1;
|
||||
|
||||
if (normalDirX == 1 || normalDirX == -1) {
|
||||
out += std::to_string(0) + ", ";
|
||||
out += std::to_string(sideY) + ", ";
|
||||
out += std::to_string(0) + ",\t";
|
||||
|
||||
out += std::to_string(0) + ", ";
|
||||
out += std::to_string(0) + ", ";
|
||||
out += std::to_string(sideZ) + ",\n";
|
||||
}
|
||||
|
||||
if (normalDirY == 1 || normalDirY == -1) {
|
||||
out += std::to_string(sideX) + ", ";
|
||||
out += std::to_string(0) + ", ";
|
||||
out += std::to_string(0) + ",\t";
|
||||
|
||||
out += std::to_string(0) + ", ";
|
||||
out += std::to_string(0) + ", ";
|
||||
out += std::to_string(sideZ) + ",\n";
|
||||
|
||||
}
|
||||
|
||||
if (normalDirZ == 1 || normalDirZ == -1) {
|
||||
out += std::to_string(sideX) + ", ";
|
||||
out += std::to_string(0) + ", ";
|
||||
out += std::to_string(0) + ",\t";
|
||||
|
||||
out += std::to_string(0) + ", ";
|
||||
out += std::to_string(sideY) + ", ";
|
||||
out += std::to_string(0) + ",\n";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << out;
|
||||
}/**/
|
||||
}
|
120
Deer/src/DeerRender/Voxels/VoxelData.cpp
Normal file
120
Deer/src/DeerRender/Voxels/VoxelData.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#include "Deer/Voxel.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "Deer/DataStore.h"
|
||||
#include "DeerRender/Render/Shader.h"
|
||||
#include "DeerRender/VoxelAspect.h"
|
||||
|
||||
#include "cereal/archives/json.hpp"
|
||||
#include "DeerRender/Voxels/Serialization/VoxelAspect_Serialization.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace Deer{
|
||||
namespace VoxelData {
|
||||
std::vector<VoxelAspect> voxelsAspect;
|
||||
std::unordered_map<std::string, uint16_t> texturesIDs;
|
||||
Ref<Shader> solidVoxelShader;
|
||||
}
|
||||
|
||||
void VoxelData::loadVoxelsAspect() {
|
||||
std::vector<Path> voxelsAspectPath = DataStore::getFiles(DEER_VOXEL_ASPECT_PATH, ".vaspect");
|
||||
voxelsAspect.clear();
|
||||
voxelsAspect.resize(voxelsInfo.size());
|
||||
|
||||
voxelsAspect[0].definition.voxelName = VOXEL_INFO_TYPE_AIR;
|
||||
|
||||
DEER_CORE_INFO("=== Loading voxel aspect ===");
|
||||
DEER_CORE_TRACE(" default - air");
|
||||
for (Path& voxelAspectPath: voxelsAspectPath) {
|
||||
uint32_t size;
|
||||
uint8_t* data = DataStore::readFile(voxelAspectPath, &size);
|
||||
|
||||
std::string dataString((char*)data, size);
|
||||
std::istringstream inputStream(dataString);
|
||||
|
||||
VoxelAspectDefinition aspectDefinition;
|
||||
{
|
||||
cereal::JSONInputArchive archive(inputStream);
|
||||
archive(cereal::make_nvp("voxelAspect", aspectDefinition));
|
||||
|
||||
}
|
||||
|
||||
if (aspectDefinition.voxelName.empty()) {
|
||||
DEER_CORE_ERROR("{0} has an empty name", voxelAspectPath.generic_string().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
int16_t voxelID = getVoxelID(aspectDefinition.voxelName);
|
||||
if (voxelID == -1) {
|
||||
DEER_CORE_ERROR("Voxel aspect {0} references {1} but it does not exist",
|
||||
voxelAspectPath.generic_string().c_str(), aspectDefinition.voxelName.c_str());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
DEER_CORE_TRACE(" {0} - {1}",
|
||||
voxelAspectPath.filename().generic_string().c_str(),
|
||||
aspectDefinition.voxelName.c_str());
|
||||
|
||||
voxelsAspect[voxelID].definition = aspectDefinition;
|
||||
}
|
||||
|
||||
DEER_CORE_INFO("=== Extracting textures ===");
|
||||
for (VoxelAspect& voxelAspect : voxelsAspect) {
|
||||
if (voxelsInfo[VoxelData::getVoxelID(voxelAspect.definition.voxelName)].type != VoxelInfoType::Voxel)
|
||||
continue;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
std::string& faceTextureString = voxelAspect.definition.textureFaces[i];
|
||||
|
||||
if (faceTextureString.empty()) {
|
||||
DEER_CORE_WARN("{0} has an empty texture at position {1} this could cause unwanted behaviour!",
|
||||
voxelAspect.definition.voxelName.c_str(), i);
|
||||
|
||||
voxelAspect.textureFacesIDs[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (texturesIDs.contains(faceTextureString))
|
||||
voxelAspect.textureFacesIDs[i] = texturesIDs[faceTextureString];
|
||||
else {
|
||||
uint16_t textureID = texturesIDs.size();
|
||||
|
||||
texturesIDs[faceTextureString] = textureID;
|
||||
voxelAspect.textureFacesIDs[i] = textureID;
|
||||
|
||||
DEER_CORE_TRACE(" texture {0} - id: {1}",
|
||||
faceTextureString.c_str(), textureID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelData::createExampleVoxelAspect() {
|
||||
VoxelAspectDefinition voxelAspectDefinition;
|
||||
|
||||
std::ostringstream outputStream;
|
||||
{
|
||||
cereal::JSONOutputArchive archive(outputStream);
|
||||
archive(cereal::make_nvp("voxelAspect", voxelAspectDefinition));
|
||||
}
|
||||
|
||||
std::string restultString = outputStream.str();
|
||||
DataStore::saveFile(Path(DEER_VOXEL_PATH) / "vaspect.example", (uint8_t*)restultString.c_str(), restultString.size());
|
||||
}
|
||||
|
||||
void VoxelData::loadVoxelsShaders() {
|
||||
uint32_t size;
|
||||
uint8_t* data = DataStore::readFile(Path(DEER_VOXEL_SHADER_PATH) / "solid_voxel.glsl", &size);
|
||||
|
||||
solidVoxelShader = Shader::create(data, size);
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
Ref<Shader>& VoxelData::getSolidVoxelShader() {
|
||||
return solidVoxelShader;
|
||||
}
|
||||
}
|
106
Deer/src/DeerRender/Voxels/VoxelData_TextureAtlas.cpp
Normal file
106
Deer/src/DeerRender/Voxels/VoxelData_TextureAtlas.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#include "Deer/Voxel.h"
|
||||
#include "Deer/Log.h"
|
||||
#include "DeerRender/VoxelAspect.h"
|
||||
|
||||
#include "stb_image.h"
|
||||
#include "stb_image_write.h"
|
||||
#include "Deer/DataStore.h"
|
||||
|
||||
#include "DeerRender/Render/Texture.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
namespace Deer {
|
||||
namespace VoxelData {
|
||||
extern std::unordered_map<std::string, uint16_t> texturesIDs;
|
||||
|
||||
int squareTextureSize = 0;
|
||||
uint8_t* voxelColorTextureAtlasData = nullptr;
|
||||
Ref<Texture2D> voxelColorTextureAtlas = nullptr;
|
||||
}
|
||||
|
||||
void VoxelData::generateTextureAtlas() {
|
||||
if (voxelColorTextureAtlasData != nullptr) {
|
||||
delete[] voxelColorTextureAtlasData;
|
||||
voxelColorTextureAtlasData = nullptr;
|
||||
}
|
||||
|
||||
squareTextureSize = 1;
|
||||
int textureCount = texturesIDs.size();
|
||||
while (squareTextureSize * squareTextureSize < textureCount)
|
||||
squareTextureSize++;
|
||||
|
||||
int textureAtlasSize = squareTextureSize * VOXEL_TEXTURE_SIZE_X * squareTextureSize * VOXEL_TEXTURE_SIZE_Y * 4;
|
||||
voxelColorTextureAtlasData = new uint8_t[textureAtlasSize]{};
|
||||
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
stbi_flip_vertically_on_write(true);
|
||||
|
||||
DEER_CORE_INFO("=== Creating Texture Atlas ===");
|
||||
for (auto& texture : texturesIDs) {
|
||||
|
||||
uint32_t size;
|
||||
uint8_t* fileData = DataStore::readFile(Path(DEER_VOXEL_TEXTURE_PATH) / (texture.first + ".png"), &size);
|
||||
|
||||
DEER_CORE_TRACE(" {0}.png - {1}", texture.first.c_str(), texture.second);
|
||||
if (fileData == nullptr) {
|
||||
DEER_CORE_ERROR("{0}.png does not exists",
|
||||
texture.first.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
int width, height, channels;
|
||||
uint8_t* textureData = stbi_load_from_memory(fileData, size, &width, &height, &channels, 4);
|
||||
|
||||
if (channels < 3) {
|
||||
DEER_CORE_ERROR("{0}.png has {1} channels and it must be bigger than {2}",
|
||||
texture.first.c_str(), channels, 3);
|
||||
} else if (width != VOXEL_TEXTURE_SIZE_X) {
|
||||
DEER_CORE_ERROR("{0}.png has a width of {1} and it must be {2}",
|
||||
texture.first.c_str(), width, VOXEL_TEXTURE_SIZE_X);
|
||||
} else if (height != VOXEL_TEXTURE_SIZE_Y) {
|
||||
DEER_CORE_ERROR("{0}.png has a height of {1} and it must be {2}",
|
||||
texture.first.c_str(), height, VOXEL_TEXTURE_SIZE_Y);
|
||||
} else {
|
||||
int yOffset = (int)(texture.second / squareTextureSize);
|
||||
int xOffset = texture.second - yOffset * squareTextureSize;
|
||||
|
||||
int yOffsetPixels = yOffset * VOXEL_TEXTURE_SIZE_Y;
|
||||
int xOffsetPixels = xOffset * VOXEL_TEXTURE_SIZE_X;
|
||||
|
||||
for (int y = 0; y < VOXEL_TEXTURE_SIZE_Y; y++) {
|
||||
for (int x = 0; x < VOXEL_TEXTURE_SIZE_X; x++) {
|
||||
int inputTextureIndex = (x + y * width) * 4;
|
||||
int outputTextureIndex = (x + xOffsetPixels + (y + yOffsetPixels) * VOXEL_TEXTURE_SIZE_X * squareTextureSize) * 4;
|
||||
|
||||
voxelColorTextureAtlasData[outputTextureIndex + 0] = textureData[inputTextureIndex + 0];
|
||||
voxelColorTextureAtlasData[outputTextureIndex + 1] = textureData[inputTextureIndex + 1];
|
||||
voxelColorTextureAtlasData[outputTextureIndex + 2] = textureData[inputTextureIndex + 2];
|
||||
voxelColorTextureAtlasData[outputTextureIndex + 3] = textureData[inputTextureIndex + 3];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
stbi_image_free(textureData);
|
||||
delete[] fileData;
|
||||
}
|
||||
|
||||
voxelColorTextureAtlas = Texture2D::create(voxelColorTextureAtlasData, squareTextureSize * VOXEL_TEXTURE_SIZE_X, squareTextureSize * VOXEL_TEXTURE_SIZE_Y, 4);
|
||||
|
||||
// temp
|
||||
Path savePath = DataStore::rootPath / DEER_TEMP_PATH / "voxel_texture_atlas.png";
|
||||
DataStore::createFolder(DataStore::rootPath / DEER_TEMP_PATH);
|
||||
stbi_write_png(savePath.generic_string().c_str(), squareTextureSize * VOXEL_TEXTURE_SIZE_X, squareTextureSize * VOXEL_TEXTURE_SIZE_Y, 4, voxelColorTextureAtlasData, squareTextureSize * VOXEL_TEXTURE_SIZE_X * 4);
|
||||
|
||||
}
|
||||
|
||||
int VoxelData::getVoxelTextureAtlasSize() {
|
||||
return squareTextureSize;
|
||||
}
|
||||
|
||||
Ref<Texture2D>& VoxelData::getVoxelColorTextureAtlas() {
|
||||
return voxelColorTextureAtlas;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user