Changed internal structure

This commit is contained in:
Chewico 2026-01-18 01:02:01 +01:00
parent 54f8156b6b
commit 67b316a70b
140 changed files with 9966 additions and 5376 deletions

View File

@ -19,8 +19,11 @@ project "DeerService"
"vendor/entt/include",
"vendor/cereal/include",
"vendor/angelScript/include",
"vendor/smallVector"
"vendor/smallVector",
"vendor/enet/include"
}
links {"enet"}
targetdir ("../bin/" .. OutputDir .. "/%{prj.name}")
objdir ("../bin/int/" .. OutputDir .. "/%{prj.name}")
@ -55,4 +58,4 @@ project "DeerService"
defines { "DIST" }
runtime "Release"
optimize "On"
symbols "Off"
symbols "Off"

View File

@ -6,8 +6,8 @@ project "Deer"
staticruntime "off"
files {
"src/Deer/**.h",
"src/Deer/**.cpp",
"src/DeerCore/**.h",
"src/DeerCore/**.cpp",
"src/DeerRender/**.h",
"src/DeerRender/**.cpp",
"src/Plattform/OpenGL/**.h",
@ -35,7 +35,8 @@ project "Deer"
"vendor/cereal/include",
"vendor/objload/include/objload",
"vendor/angelScript/include",
"vendor/smallVector"
"vendor/smallVector",
"vendor/enet/include"
}
targetdir ("../bin/" .. OutputDir .. "/%{prj.name}")
@ -81,7 +82,8 @@ project "Deer"
"gdk_pixbuf-2.0", -- GDK Pixbuf library
"gio-2.0", -- GIO library
"gobject-2.0", -- GObject library
"pthread" -- POSIX threads library
"pthread", -- POSIX threads library
"enet"
}
@ -109,4 +111,4 @@ project "Deer"
defines { "DIST" }
runtime "Release"
optimize "On"
symbols "Off"
symbols "Off"

View File

@ -1,296 +0,0 @@
// 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/Tools/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
// DataStore::voxelsInfo
struct VoxelInfo {
std::string name;
VoxelInfoType type = VoxelInfoType::Air;
};
// Namespace to load and manage voxel data
namespace DataStore {
// 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 DataStore
// 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 DataStore::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

View File

@ -1,209 +0,0 @@
// copyright Copyright (c) 2025 Deer
#pragma once
#include <array>
#include "Deer/Tools/Memory.h"
#include "Deer/Voxel.h"
#ifdef DEER_RENDER
#include "DeerRender/Voxel.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
namespace VoxelWorld {
void initialize(const VoxelWorldProps&);
void clear();
// 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);
bool isInitialized();
// 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
const VoxelWorldProps& getWorldProps();
#ifdef DEER_RENDER
// 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);
// 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
LayerVoxel& modLayerVoxel(int x, int z);
} // namespace VoxelWorld
} // namespace Deer

View File

@ -1,5 +1,5 @@
#pragma once
#include "Deer/Tools/Memory.h"
#include "DeerCore/Tools/Memory.h"
namespace Deer {
class ImGuiLayer;

View File

@ -1,6 +1,6 @@
#pragma once
#include "Deer/Tools/Memory.h"
#include "Deer/Tools/SmallVector.h"
#include "DeerCore/Tools/Memory.h"
#include "DeerCore/Tools/SmallVector.h"
#define GLM_ENABLE_EXPERIMENTAL
#include <stdint.h>
@ -9,7 +9,7 @@
#include <string>
#include <vector>
#include "Deer/Log.h"
#include "DeerCore/Log.h"
#include "glm/glm.hpp"
#include "glm/gtc/quaternion.hpp"

View File

@ -1,6 +1,6 @@
#pragma once
#include "Deer/Tools/Memory.h"
#include "Deer/Tools/TypeDefs.h"
#include "DeerCore/Tools/Memory.h"
#include "DeerCore/Tools/TypeDefs.h"
#include <string>
#include <unordered_map>

View File

@ -3,7 +3,7 @@
#include <string>
#include <vector>
#include "Deer/Tools/Path.h"
#include "DeerCore/Tools/Path.h"
#define DEER_RESOURCE_PATH "Assets"

View File

@ -1,8 +1,8 @@
#pragma once
#include "Deer/Components.h"
#include "Deer/Log.h"
#include "Deer/Tools/Memory.h"
#include "Deer/Resource.h"
#include "DeerCore/Components.h"
#include "DeerCore/Log.h"
#include "DeerCore/Resource.h"
#include "DeerCore/Tools/Memory.h"
#include "entt/entt.hpp"
@ -63,7 +63,7 @@ namespace Deer {
// Obtains the entity that is on the root of the environment
inline Entity& getRoot() { return getEntity(0); }
#ifdef DEER_RENDER
void render(SceneCamera& camera);
void render(const SceneCamera& camera);
#endif
Scope<entt::registry> m_registry;

View File

@ -1,5 +1,5 @@
#pragma once
#include "Deer/Tools/Memory.h"
#include "DeerCore/Tools/Memory.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"

View File

@ -0,0 +1,35 @@
#pragma once
#include "DeerCore/Tools/Memory.h"
#include "DeerCore/Tools/TypeDefs.h"
typedef struct _ENetPeer ENetPeer;
namespace Deer {
namespace Network {
struct ServerSettings;
struct DeerClient;
void initServer(const ServerSettings&);
void shutdownServer();
void flushServerEvents();
enum class DeerClientState : int {
NotConnected = 0,
Connected = 1
};
struct DeerClient {
DeerClientState clientState = DeerClientState::NotConnected;
ENetPeer* internalPeer = nullptr;
};
struct ServerSettings {
uint32_t port = 500;
uint32_t maxClients = 32;
uint32_t maxOutgoingBand = 0;
uint32_t maxIncomingBand = 0;
};
} // namespace Network
} // namespace Deer

View File

@ -1,9 +1,9 @@
#pragma once
#include "Deer/DataManagment.h"
#include "Deer/Log.h"
#include "Deer/Tools/Memory.h"
#include "Deer/Tools/Path.h"
#include "Deer/Tools/TypeDefs.h"
#include "DeerCore/DataManagment.h"
#include "DeerCore/Log.h"
#include "DeerCore/Tools/Memory.h"
#include "DeerCore/Tools/Path.h"
#include "DeerCore/Tools/TypeDefs.h"
#include <cxxabi.h>
#include <unordered_map>
@ -94,7 +94,7 @@ namespace Deer {
static Resource<T> loadResourceFromData(const typename ResourceBuilder<T>::BaseDataType& resourceData, const std::string& storageId) {
if (resourceCache.contains(storageId))
return resourceCache[storageId];
Scope<T> data = ResourceBuilder<T>::buildResource(resourceData);
Resource<T> resource = Resource<T>::unsafeFromId(resources.size());

View File

@ -1,19 +1,9 @@
#pragma once
#include "Deer/DataStore.h"
#include "Deer/Tools/Memory.h"
#include "Deer/Tools/Path.h"
#ifdef DEER_RENDER
#include "DeerRender/GizmoRenderer.h"
#endif
#include <array>
#include <stdint.h>
#include <string>
#include <vector>
#include "DeerCore/Tools/TypeDefs.h"
namespace Deer {
class Environment;
class SceneCamera;
class GizmoRenderer;
// A scene is a 3d simulation with its environment and voxel world in case
@ -33,19 +23,10 @@ namespace Deer {
#ifdef DEER_RENDER
// This function renders with the default camera in the environment
void render();
void render(SceneCamera);
void render(const SceneCamera&);
extern GizmoRenderer gizmoRenderer;
#endif
extern Environment environment;
} // namespace Scene
// Namespace to manage scenes in memory
namespace DataStore {
void loadScene(const Path& name);
void exportScene(const Path& name);
void exportRuntimeScene();
void importRuntimeScene();
} // namespace DataStore
} // namespace Deer

View File

@ -1,4 +1,4 @@
#include "Deer/Application.h"
#include "DeerCore/Application.h"
#ifdef DEER_RENDER
#include "DeerRender/Events/ApplicationEvent.h"
@ -7,8 +7,8 @@
#endif
namespace Deer {
namespace Application {
using EventFunction = void(*)(Event&);
namespace Application {
using EventFunction = void (*)(Event&);
void initWindow();
void shutdownWindow();
@ -17,5 +17,5 @@ namespace Deer {
void setEventCallback(EventFunction);
Window& getWindow();
}
}
} // namespace Application
} // namespace Deer

View File

@ -1,5 +1,5 @@
#pragma once
#include "Deer/Components.h"
#include "DeerCore/Components.h"
#include "DeerRender/Mesh.h"
#include "DeerRender/Shader.h"

View File

@ -1,2 +1,2 @@
#pragma once
#include "Deer/DataManagment.h"
#include "DeerCore/DataManagment.h"

View File

@ -1,2 +1,2 @@
#pragma once
#include "Deer/DataStore.h"
#include "DeerCore/DataStore.h"

View File

@ -1,2 +1,2 @@
#pragma once
#include "Deer/Enviroment.h"
#include "DeerCore/Enviroment.h"

View File

@ -1,33 +0,0 @@
#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;
};
}

View File

@ -1,14 +1,14 @@
#pragma once
#include "Deer/Application.h"
#include "DeerCore/Application.h"
namespace Deer {
class Input {
public:
public:
static bool isKeyPressed(unsigned int key);
static bool isMouseButtonPressed(int button);
static void getMousePos(float& x, float& y);
};
} // namespace Deer
} // namespace Deer
// From GLFW
#define DEER_KEY_SPACE 32

View File

@ -1,2 +1,2 @@
#pragma once
#include "Deer/Log.h"
#include "DeerCore/Log.h"

View File

@ -1,5 +1,5 @@
#pragma once
#include "Deer/Tools/Memory.h"
#include "DeerCore/Tools/Memory.h"
#include <string>
#include <vector>

View File

@ -1,9 +1,9 @@
#pragma once
#include "Deer/Log.h"
#include "DeerCore/Log.h"
#include <vector>
#include <initializer_list>
#include <vector>
namespace Deer {
enum class TextureBufferType {
@ -15,15 +15,15 @@ namespace Deer {
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) {
: width(_width), height(_height), samples(_samples), frameBufferTextures(_frameBufferTextures), swapChainTarget(_swapChainTarget) {
}
};
class FrameBuffer {
public:
public:
virtual ~FrameBuffer() = default;
virtual const FrameBufferSpecification& getSpecification() = 0;
@ -32,7 +32,7 @@ namespace Deer {
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;
@ -40,5 +40,4 @@ namespace Deer {
static FrameBuffer* create(const FrameBufferSpecification& spec);
};
}
} // namespace Deer

View File

@ -1,5 +1,5 @@
#pragma once
#include "Deer/Tools/Memory.h"
#include "DeerCore/Tools/Memory.h"
#include "glm/glm.hpp"

View File

@ -1,5 +1,5 @@
#pragma once
#include "Deer/Tools/Memory.h"
#include "DeerCore/Tools/Memory.h"
#include <string>

View File

@ -1,2 +1,2 @@
#pragma once
#include "Deer/Resource.h"
#include "DeerCore/Resource.h"

View File

@ -1,5 +1,5 @@
#pragma once
#include "Deer/Scene.h"
#include "DeerCore/Scene.h"
#include "DeerRender/Components.h"
namespace Deer {

View File

@ -1,5 +1,5 @@
#pragma once
#include "Deer/Tools/Path.h"
#include "DeerCore/Tools/Path.h"
#include "DeerRender/Render/Shader.h"
#include "DeerRender/Resource.h"
@ -22,6 +22,11 @@ namespace Deer {
}
};
namespace RenderUtils {
void initializeRenderUtils();
void deinitializeRenderUtils();
} // namespace RenderUtils
template <>
class ResourceBuilder<Shader> {
public:

View File

@ -1,2 +1,2 @@
#pragma once
#include "Deer/Tools/Memory.h"
#include "DeerCore/Tools/Memory.h"

View File

@ -1,2 +1,2 @@
#pragma once
#include "Deer/Tools/Path.h"
#include "DeerCore/Tools/Path.h"

View File

@ -1,2 +1,2 @@
#pragma once
#include "Deer/Tools/SmallVector.h"
#include "DeerCore/Tools/SmallVector.h"

View File

@ -1,2 +1,2 @@
#pragma once
#include "Deer/Tools/TypeDefs.h"
#include "DeerCore/Tools/TypeDefs.h"

View File

@ -1,33 +0,0 @@
#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) {}
};
} // namespace Deer

View File

@ -1,54 +0,0 @@
/**
* @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]; }
};
}

View File

@ -1,2 +0,0 @@
#pragma once
#include "Deer/VoxelWorld.h"

View File

@ -1,5 +1,5 @@
#pragma once
#include "Deer/Tools/Path.h"
#include "DeerCore/Tools/Path.h"
#include "DeerRender/Events/Event.h"
#include <functional>

View File

@ -1,61 +0,0 @@
#include "Deer/Application.h"
#include <functional>
#include <thread>
namespace Deer {
namespace Application {
// Implemented in DeerRender/Application
void runRender(float deltaTime);
void resolveEvents();
Function tickCallback;
bool running;
const double targetUpdateTime = 1.0 / 60.0; // Fixed 60 FPS update
double targetRenderTime = 1.0 / 160.0; // User-defined render FPS
void setTickCallback(Function _tick) {
tickCallback = _tick;
}
void run() {
running = true;
auto previousTime = std::chrono::high_resolution_clock::now();
double accumulatedUpdateTime = 0.0;
double accumulatedRenderTime = 0.0;
while (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;
accumulatedUpdateTime -= targetUpdateTime;
if (tickCallback)
tickCallback();
}
#ifdef DEER_RENDER
if (accumulatedRenderTime >= targetRenderTime) {
runRender((float)targetRenderTime);
accumulatedRenderTime -= targetRenderTime;
}
resolveEvents();
#endif
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
void shutdown() {
running = false;
}
}
}

View File

@ -1,14 +0,0 @@
#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;
}
}

View File

@ -1,8 +0,0 @@
#include "Deer/Enviroment.h"
namespace Deer {
Scope<Environment> ResourceBuilder<Environment>::buildResource(const BaseDataType& baseData) {
Scope<Environment> env = MakeScope<Environment>();
return env;
}
}

View File

@ -1,18 +0,0 @@
#include "Deer/Enviroment.h"
#include "Deer/Tools/Memory.h"
#ifdef DEER_RENDER
#include "DeerRender/GizmoRenderer.h"
#endif
namespace Deer {
namespace Scene {
Environment environment;
bool isExecuting = false;
#ifdef DEER_RENDER
GizmoRenderer gizmoRenderer;
#endif
} // namespace Scene
} // namespace Deer

View File

@ -1,16 +0,0 @@
#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));
}
}

View File

@ -1,21 +0,0 @@
#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
}
}
}

View File

@ -1,143 +0,0 @@
#pragma once
#include "Deer/Voxel.h"
#ifdef DEER_RENDER
#include <vector>
#include "DeerRender/Voxel.h"
#include "DeerRender/VoxelAspect.h"
#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 =
DataStore::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
};
} // namespace Deer

View File

@ -1,12 +0,0 @@
#include "Layer.h"
namespace Deer {
Layer::~Layer() {
if (m_layerInfo)
delete[] m_layerInfo;
}
void Layer::loadData() {
m_layerInfo = new LayerVoxel[LAYER_VOXELS]();
}
}

View File

@ -1,40 +0,0 @@
#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;
};
}

View File

@ -1,56 +0,0 @@
#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());
}
}
}

View File

@ -1,19 +0,0 @@
#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
};
}

View File

@ -1,86 +0,0 @@
#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 DataStore {
std::vector<VoxelInfo> voxelsInfo;
std::unordered_map<std::string, uint32_t> blockIDMap;
} // namespace DataStore
int32_t DataStore::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 DataStore::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_TRACE("Loading voxels");
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;
}
uint32_t id = voxelsInfo.size();
voxelsInfo.push_back(voxelData);
blockIDMap[voxelData.name] = id;
delete data;
}
}
void DataStore::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

View File

@ -1,68 +0,0 @@
#include "Deer/VoxelWorld.h"
#include "Deer/Voxels/VoxelWorldData.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 {
void VoxelWorld::initialize(const VoxelWorldProps& props) {
clear();
worldProps = props;
chunks = MakeScope<Chunk[]>(worldProps.getChunkCount());
layers = MakeScope<Layer[]>(worldProps.getLayerCount());
#ifdef DEER_RENDER
initializeRenderVars(props);
#endif
initialized = true;
}
void VoxelWorld::clear() {
chunks.reset();
layers.reset();
initialized = false;
#ifdef DEER_RENDER
clearRenderVars();
#endif
}
const VoxelWorldProps& VoxelWorld::getWorldProps() {
return worldProps;
}
uint16_t VoxelWorld::calculateLayerVoxelHeight(int x, int z) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
LayerVoxelID layerVoxelID;
LayerID layerID;
extractLayerCordinates(x, z, layerID, layerVoxelID);
ChunkID chunkID(layerID.x, 0, layerID.z);
for (int y = worldProps.chunkSizeY - 1; y >= 0; y--) {
chunkID.y = y;
Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
uint8_t chunkVoxelHeight =
chunk.calculateLayerVoxelHeight(layerVoxelID);
if (chunkVoxelHeight != 0) {
return chunkVoxelHeight + chunkID.y * CHUNK_SIZE_Y;
}
}
return 0;
}
} // namespace Deer

View File

@ -1,18 +0,0 @@
#include "Deer/Voxels/VoxelWorldData.h"
#include "Deer/Voxels/Chunk.h"
#include "Deer/Voxels/Layer.h"
namespace Deer {
namespace VoxelWorld {
VoxelWorldProps worldProps;
Scope<Chunk[]> chunks;
Scope<Layer[]> layers;
bool initialized;
}
bool VoxelWorld::isInitialized() {
return initialized;
}
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "Deer/Tools/Memory.h"
#include "Deer/VoxelWorld.h"
namespace Deer {
namespace VoxelWorld {
extern VoxelWorldProps worldProps;
extern Scope<Chunk[]> chunks;
extern Scope<Layer[]> layers;
extern bool initialized;
} // namespace VoxelWorld
} // namespace Deer

View File

@ -1,159 +0,0 @@
#include "Deer/VoxelWorld.h"
#include "Deer/Log.h"
#include "Deer/Voxels/Chunk.h"
#include "Deer/Voxels/Layer.h"
#include "Deer/Voxels/VoxelWorldData.h"
#include <math.h>
#include <cmath>
#include <vector>
namespace Deer {
VoxelRayResult VoxelWorld::rayCast(glm::vec3 position, glm::vec3 dir, float maxDistance) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
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) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
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;
}
}

View File

@ -1,255 +0,0 @@
#include "Deer/Log.h"
#include "Deer/VoxelWorld.h"
#include "Deer/Voxels/Chunk.h"
#include "Deer/Voxels/Layer.h"
#include "Deer/Voxels/VoxelWorldData.h"
#ifdef DEER_RENDER
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
#endif
#include <math.h>
#include <cmath>
#include <vector>
namespace Deer {
Voxel VoxelWorld::readVoxel(VoxelCordinates coords) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
ChunkID chunkID;
ChunkVoxelID chunkVoxelID;
extractChunkCordinates(coords, chunkID, chunkVoxelID);
if (!worldProps.isValid(chunkID)) return emptyVoxel;
Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
return chunk.readVoxel(chunkVoxelID);
}
void VoxelWorld::setVoxel(VoxelCordinates coords, Voxel info) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
ChunkID chunkID;
ChunkVoxelID chunkVoxelID;
extractChunkCordinates(coords, chunkID, chunkVoxelID);
if (!worldProps.isValid(chunkID)) return;
Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
chunk.modVoxel(chunkVoxelID) = info;
LayerID layerID;
LayerVoxelID layerVoxelID;
extractLayerCordinates(coords.x, coords.z, layerID, layerVoxelID);
Layer& layer = layers[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
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]--;
chunkQueue.addChunk(nextChunk);
}
if (chunkVoxelID[i] == CHUNK_SIZE(i) &&
chunkID[i] != worldProps[i] - 1) {
ChunkID nextChunk = chunkID;
nextChunk[i]++;
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) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
ChunkID minChunkID;
ChunkID maxChunkID;
ChunkVoxelID minChunkVoxelID;
ChunkVoxelID maxChunkVoxelID;
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 =
chunks[worldProps.getWorldChunkID(workingChunkID)];
Layer& workingLayer =
layers[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
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;
}
worldProps.clampCordinates(minLightModification);
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) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
ChunkID minChunkID;
ChunkID maxChunkID;
ChunkVoxelID minChunkVoxelID;
ChunkVoxelID maxChunkVoxelID;
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 =
chunks[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
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 = worldProps.getWorldLayerID(layerID);
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;
}
worldProps.clampCordinates(minLightModification);
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 (!worldProps.isValid(layerID)) return LayerVoxel();
Layer& layer = layers[worldProps.getWorldLayerID(layerID)];
return layer.readLayerVoxel(layerVoxelID);
}
LayerVoxel& VoxelWorld::modLayerVoxel(int x, int z) {
LayerID layerID;
LayerVoxelID layerVoxelID;
extractLayerCordinates(x, z, layerID, layerVoxelID);
if (!worldProps.isValid(layerID)) return nullLayerVoxel;
Layer& layer = layers[worldProps.getWorldLayerID(layerID)];
return layer.modLayerVoxel(layerVoxelID);
}
} // namespace Deer

View File

@ -0,0 +1,59 @@
#include "DeerCore/Application.h"
#include <functional>
#include <thread>
namespace Deer {
namespace Application {
// Implemented in DeerRender/Application
void runRender(float deltaTime);
void resolveEvents();
Function tickCallback;
bool running;
const double targetUpdateTime = 1.0 / 60.0; // Fixed 60 FPS update
double targetRenderTime = 1.0 / 160.0; // User-defined render FPS
void setTickCallback(Function _tick) {
tickCallback = _tick;
}
void run() {
running = true;
auto previousTime = std::chrono::high_resolution_clock::now();
double accumulatedUpdateTime = 0.0;
double accumulatedRenderTime = 0.0;
while (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;
accumulatedUpdateTime -= targetUpdateTime;
if (tickCallback)
tickCallback();
}
#ifdef DEER_RENDER
if (accumulatedRenderTime >= targetRenderTime) {
runRender((float)targetRenderTime);
accumulatedRenderTime -= targetRenderTime;
}
resolveEvents();
#endif
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
void shutdown() {
running = false;
}
} // namespace Application
} // namespace Deer

View File

@ -1,4 +1,4 @@
#include "Deer/Log.h"
#include "DeerCore/Log.h"
namespace Deer {
std::shared_ptr<spdlog::logger> Log::coreLogger;

View File

@ -1,13 +1,13 @@
#include "Deer/DataStore.h"
#include "Deer/Log.h"
#include "Deer/Tools/Path.h"
#include "DeerCore/DataStore.h"
#include "DeerCore/Log.h"
#include "DeerCore/Tools/Path.h"
#include "cereal/archives/portable_binary.hpp"
#include "cereal/cereal.hpp"
#include "cereal/types/unordered_map.hpp"
#include "Deer/DataStore/DataStructure.h"
#include "Deer/DataStore/DataStructureSerialization.h"
#include "DeerCore/DataStore/DataStructure.h"
#include "DeerCore/DataStore/DataStructureSerialization.h"
#include <fstream>
#include <ostream>

View File

@ -1,6 +1,6 @@
#pragma once
#include "Deer/Tools/Path.h"
#include "DeerCore/Tools/Path.h"
namespace Deer {
struct DataStructure {

View File

@ -1,6 +1,6 @@
#pragma once
#include "Deer/DataStore/DataStructure.h"
#include "Deer/Tools/Path.h"
#include "DeerCore/DataStore/DataStructure.h"
#include "DeerCore/Tools/Path.h"
#include "cereal/cereal.hpp"
#include "cereal/types/string.hpp"

View File

@ -1,4 +1,4 @@
#include "Deer/Tools/Path.h"
#include "DeerCore/Tools/Path.h"
#include <algorithm>
Deer::Path Deer::toLowerCasePath(const Path& inputPath) {

View File

@ -0,0 +1,96 @@
#include "DeerCore/Log.h"
#include "DeerCore/Network.h"
#include "enet/enet.h"
#include <unordered_map>
#include <vector>
namespace Deer {
namespace Network {
ServerSettings serverSettings;
ENetHost* enetServer;
void clientConnect(ENetPeer* refPeer);
void clientDisconnect(ENetPeer* refPeer);
void clientData(ENetPeer* peer, ENetPacket* packet);
// Fixed array of clients, defined by max player count
Scope<DeerClient[]> clients;
} // namespace Network
void Network::initServer(const ServerSettings& config) {
serverSettings = config;
if (enet_initialize() != 0) {
DEER_CORE_ERROR("An error ocurred while initing enet");
return;
}
ENetAddress serverAddress;
serverAddress.host = ENET_HOST_ANY;
serverAddress.port = config.port;
enetServer = enet_host_create(&serverAddress, config.maxClients, 2, config.maxOutgoingBand, config.maxIncomingBand);
if (!enetServer) {
DEER_CORE_ERROR("An error ocurred while initing server");
return;
}
clients = MakeScope<DeerClient[]>(serverSettings.maxClients);
}
void Network::shutdownServer() {
enet_deinitialize();
}
void Network::flushServerEvents() {
ENetEvent event;
while (enet_host_service(enetServer, &event, 0) > 0) {
switch (event.type) {
case ENET_EVENT_TYPE_CONNECT:
clientConnect(event.peer);
break;
case ENET_EVENT_TYPE_RECEIVE:
clientData(event.peer, event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
clientDisconnect(event.peer);
break;
case ENET_EVENT_TYPE_NONE:
break;
}
}
}
void Network::clientConnect(ENetPeer* peer) {
DeerClient* client = nullptr;
int clientId = -1;
for (int i = 0; i < serverSettings.maxClients; i++) {
if (clients[i].clientState == DeerClientState::NotConnected) {
client = &client[i];
clientId = i;
break;
}
}
if (!client) {
DEER_CORE_ERROR("Server full, critical error");
enet_peer_disconnect(peer, 0);
return;
}
client->clientState = DeerClientState::Connected;
client->internalPeer = peer;
peer->data = client;
}
void Network::clientDisconnect(ENetPeer* peer) {
DeerClient& client = *(DeerClient*)peer->data;
client.clientState = DeerClientState::NotConnected;
client.internalPeer = nullptr;
}
void Network::clientData(ENetPeer* peer, ENetPacket* packetData) {
}
} // namespace Deer

View File

@ -0,0 +1,14 @@
#include "DeerCore/Components.h"
#include "DeerCore/Log.h"
#include "glm/gtc/matrix_transform.hpp"
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;
}
} // namespace Deer

View File

@ -1,6 +1,6 @@
#include "Deer/Components.h"
#include "Deer/Enviroment.h"
#include "Deer/Log.h"
#include "DeerCore/Components.h"
#include "DeerCore/Enviroment.h"
#include "DeerCore/Log.h"
namespace Deer {
Entity::Entity(entt::entity handle, Environment* scene, uint16_t entityID)

View File

@ -1,10 +1,9 @@
#include "Deer/Enviroment.h"
#include "DeerCore/Enviroment.h"
#include "Deer/Application.h"
#include "Deer/Components.h"
#include "Deer/Log.h"
#include "DeerCore/Application.h"
#include "DeerCore/Components.h"
#include "DeerCore/Log.h"
#include "DeerRender/Render/Render.h"
#include "DeerRender/Render/RenderUtils.h"
#include "DeerRender/Render/Texture.h"
namespace Deer {

View File

@ -0,0 +1,8 @@
#include "DeerCore/Enviroment.h"
namespace Deer {
Scope<Environment> ResourceBuilder<Environment>::buildResource(const BaseDataType& baseData) {
Scope<Environment> env = MakeScope<Environment>();
return env;
}
} // namespace Deer

View File

@ -1,28 +1,20 @@
#include "Deer/Scene.h"
#include "DeerCore/Scene.h"
#include "Deer/Components.h"
#include "Deer/Enviroment.h"
#include "Deer/Log.h"
#include "Deer/Tools/Memory.h"
#include "Deer/VoxelWorld.h"
#include "Deer/Voxels/Chunk.h"
#include "Deer/Voxels/Layer.h"
#include "Deer/Voxels/VoxelWorldData.h"
#include "Deer/Enviroment.h"
#include "Deer/Scene/SceneData.h"
#include "DeerCore/Components.h"
#include "DeerCore/Enviroment.h"
#include "DeerCore/Log.h"
#include "DeerCore/Scene/SceneData.h"
#include "DeerCore/Tools/Memory.h"
#ifdef DEER_RENDER
#include "DeerRender/FrameBuffer.h"
#include "DeerRender/Mesh.h"
#include "DeerRender/Shader.h"
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
#endif
namespace Deer {
void Scene::clear() {
environment.clear();
VoxelWorld::clear();
#ifdef DEER_RENDER
ResourceManager<Shader>::unloadResources();

View File

@ -0,0 +1,10 @@
#include "DeerCore/Enviroment.h"
#include "DeerCore/Tools/Memory.h"
namespace Deer {
namespace Scene {
Environment environment;
bool isExecuting = false;
} // namespace Scene
} // namespace Deer

View File

@ -1,9 +1,5 @@
#pragma once
#include "Deer/Tools/Memory.h"
#ifdef DEER_RENDER
#include "DeerRender/GizmoRenderer.h"
#endif
#include "DeerCore/Tools/Memory.h"
namespace Deer {
class Environment;
@ -11,10 +7,6 @@ namespace Deer {
namespace Scene {
extern Environment environment;
extern bool isExecuting;
#ifdef DEER_RENDER
extern GizmoRenderer gizmoRenderer;
#endif
} // namespace Scene
} // namespace Deer

View File

@ -1,5 +1,5 @@
#pragma once
#include "Deer/Components.h"
#include "DeerCore/Components.h"
namespace Deer {
// RELATIONSHIP COMPONENT

View File

@ -0,0 +1,16 @@
#pragma once
#include "DeerCore/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));
}
} // namespace Deer

View File

@ -1,8 +1,8 @@
#pragma once
#include "Deer/Components.h"
#include "Deer/Enviroment.h"
#include "Deer/Scene/Serialization/SerializationGlobalVars.h"
#include "DeerCore/Components.h"
#include "DeerCore/Enviroment.h"
#include "DeerCore/Scene/Serialization/SerializationGlobalVars.h"
#include "EntitySerializationStruct.h"
namespace Deer {

View File

@ -2,7 +2,7 @@
#include <cstdint>
#include <vector>
#include "Deer/Enviroment.h"
#include "DeerCore/Enviroment.h"
#include "EntitySerializationStruct.h"
namespace Deer {
@ -54,4 +54,4 @@ namespace Deer {
archive(serializationStruct);
}
}
} // namespace Deer
} // namespace Deer

View File

@ -5,19 +5,19 @@
#include "cereal/types/vector.hpp"
// Serialization Vars
#include "Deer/Scene/Serialization/SerializationGlobalVars.h"
#include "DeerCore/Scene/Serialization/SerializationGlobalVars.h"
// GENERICS
#include "Deer/Scene/Serialization/QuatSerialization.h"
#include "Deer/Scene/Serialization/Vec3Serialization.h"
#include "DeerCore/Scene/Serialization/QuatSerialization.h"
#include "DeerCore/Scene/Serialization/Vec3Serialization.h"
// SCENE SPECIFIC
#include "Deer/Scene/Serialization/EntitySerialization.h"
#include "Deer/Scene/Serialization/EnvironmentSerialization.h"
#include "DeerCore/Scene/Serialization/EntitySerialization.h"
#include "DeerCore/Scene/Serialization/EnvironmentSerialization.h"
// COMPONENTS SPECIFIC
#include "Deer/Scene/Serialization/Components/RelationshipComponentSerialization.h"
#include "Deer/Scene/Serialization/Components/TransformComponentSerialization.h"
#include "DeerCore/Scene/Serialization/Components/RelationshipComponentSerialization.h"
#include "DeerCore/Scene/Serialization/Components/TransformComponentSerialization.h"
// RENDER SPECIFIC
#ifdef DEER_RENDER

View File

@ -4,7 +4,6 @@
#include "DeerRender/Render/Render.h"
#include "DeerRender/Render/RenderCommand.h"
#include "DeerRender/Render/RenderUtils.h"
#include "DeerRender/Log.h"
@ -46,7 +45,6 @@ namespace Deer {
imGuiLayer = MakeScope<ImGuiLayer>();
imGuiLayer->onAttach();
RenderUtils::initializeRenderUtils();
RenderCommand::init();
}

View File

@ -1,7 +1,7 @@
#include "RenderUtils.h"
#include "DeerRender/Render/VertexArray.h"
#include "DeerRender/Render/Buffer.h"
#include "DeerRender/Render/Shader.h"
#include "DeerRender/Render/VertexArray.h"
#ifdef DEER_RENDER
@ -16,7 +16,7 @@ namespace Deer {
Scope<VertexArray> genFaceVertexArray();
Scope<Shader> getLineShader();
Scope<Shader> getFaceShader();
}
} // namespace RenderUtils
void RenderUtils::initializeRenderUtils() {
m_lineVertexArray = genLineVertexArray();
@ -25,18 +25,23 @@ namespace Deer {
m_faceShader = getFaceShader();
}
void RenderUtils::deinitializeRenderUtils() {
m_lineVertexArray.reset();
m_lineShader.reset();
m_faceVertexArray.reset();
m_faceShader.reset();
}
Scope<VertexArray> RenderUtils::genLineVertexArray() {
unsigned int vertices[2] = { 0, 1 };
unsigned int vertices[2] = {0, 1};
Scope<VertexArray> vertexArray = Scope<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}
});
BufferLayout layout({{"a_vertexID", DataType::Unsigned_Int, ShaderDataType::Integer}});
vertexBuffer->setLayout(layout);
vertexArray->addVertexBuffer(vertexBuffer);
@ -87,11 +92,9 @@ void main()
Scope<VertexArray> RenderUtils::genFaceVertexArray() {
unsigned int vertices[4] = {
0, 1, 2, 3
};
0, 1, 2, 3};
unsigned int indices[6] = {
0, 2, 1, 1, 2, 3
};
0, 2, 1, 1, 2, 3};
Scope<VertexArray> vertexArray = Scope<VertexArray>(VertexArray::create());
vertexArray->bind();
@ -99,9 +102,7 @@ void main()
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}
});
BufferLayout layout({{"a_vertexID", DataType::Unsigned_Int, ShaderDataType::Integer}});
vertexBuffer->setLayout(layout);
vertexArray->addVertexBuffer(vertexBuffer);
@ -178,5 +179,5 @@ void main()
return Scope<Shader>(Shader::create(vertexSrc, fragmentSrc));
}
}
#endif
} // namespace Deer
#endif

View File

@ -12,5 +12,6 @@ namespace Deer {
extern Scope<Shader> m_faceShader;
void initializeRenderUtils();
void deinitializeRenderUtils();
} // namespace RenderUtils
} // namespace Deer

View File

@ -3,7 +3,6 @@
#include "DeerRender/Application.h"
#include "DeerRender/Components.h"
#include "DeerRender/Voxel.h"
#include "DeerRender/Mesh.h"
#include "DeerRender/Render/Render.h"
@ -14,7 +13,7 @@
#include "DeerRender/Log.h"
namespace Deer {
void Environment::render(SceneCamera& camera) {
void Environment::render(const 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));

View File

@ -1,163 +0,0 @@
#include "DeerRender/GizmoRenderer.h"
#include "DeerRender/Components.h"
#include "DeerRender/Render/Render.h"
#include "DeerRender/Render/RenderCommand.h"
#include "DeerRender/Render/RenderUtils.h"
#include "DeerRender/Render/Texture.h"
#include "DeerRender/Scene.h"
#include "DeerRender/Voxel.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 = DataStore::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 = DataStore::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;
// DataStore::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", DataStore::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();
}
} // namespace Deer

View File

@ -3,7 +3,7 @@
#include "DeerRender/Components.h"
#include "DeerRender/Enviroment.h"
#include "DeerRender/Render/RenderCommand.h"
#include "DeerRender/VoxelWorld.h"
#include "DeerRender/Scene.h"
namespace Deer {
void Scene::render() {
@ -19,15 +19,11 @@ namespace Deer {
Scene::render(sceneCamera);
}
void Scene::render(SceneCamera sceneCamera) {
void Scene::render(const SceneCamera& sceneCamera) {
RenderCommand::setDepthBuffer(true);
environment.render(sceneCamera);
if (VoxelWorld::isInitialized())
VoxelWorld::render(sceneCamera);
RenderCommand::setDepthBuffer(false);
gizmoRenderer.render(sceneCamera);
}
} // namespace Deer

View File

@ -1,30 +0,0 @@
#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;
}
void ChunkUpdateQueue::reset() {
while (!m_updateOrder.empty()) {
m_updateOrder.pop();
}
m_containingChunks.clear();
}
bool ChunkUpdateQueue::hasChunk() {
return m_updateOrder.size() > 0;
}
}

View File

@ -1,33 +0,0 @@
#pragma once
#include "DeerRender/Log.h"
#include "DeerRender/Voxel.h"
#include "DeerRender/VoxelAspect.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));
}
} // namespace Deer

View File

@ -1,148 +0,0 @@
#include "DeerRender/Voxel.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;
} /**/
} // namespace Deer

View File

@ -1,122 +0,0 @@
#include <sstream>
#include <string>
#include <unordered_map>
#include "DeerRender/DataStore.h"
#include "DeerRender/Log.h"
#include "DeerRender/Render/Shader.h"
#include "DeerRender/Voxel.h"
#include "DeerRender/VoxelAspect.h"
#include "DeerRender/Voxels/Serialization/VoxelAspect_Serialization.h"
#include "cereal/archives/json.hpp"
namespace Deer {
namespace DataStore {
std::vector<VoxelAspect> voxelsAspect;
std::unordered_map<std::string, uint16_t> texturesIDs;
Ref<Shader> solidVoxelShader;
} // namespace DataStore
void DataStore::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_TRACE("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;
}
voxelsAspect[voxelID].definition = aspectDefinition;
}
DEER_CORE_TRACE("Extracting textures ");
for (VoxelAspect& voxelAspect : voxelsAspect) {
if (voxelsInfo[DataStore::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;
}
}
}
}
void DataStore::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 DataStore::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>& DataStore::getSolidVoxelShader() { return solidVoxelShader; }
} // namespace Deer

View File

@ -1,115 +0,0 @@
/*
#include <string>
#include <unordered_map>
#include "DeerRender/DataStore.h"
#include "DeerRender/Log.h"
#include "DeerRender/Render/Texture.h"
#include "DeerRender/Voxel.h"
#include "DeerRender/VoxelAspect.h"
namespace Deer {
namespace DataStore {
extern std::unordered_map<std::string, uint16_t> texturesIDs;
int squareTextureSize = 0;
uint8_t* voxelColorTextureAtlasData = nullptr;
Ref<Texture2D> voxelColorTextureAtlas = nullptr;
} // namespace DataStore
void DataStore::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]{};
DEER_CORE_TRACE("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 DataStore::getVoxelTextureAtlasSize() { return squareTextureSize; }
Ref<Texture2D>& DataStore::getVoxelColorTextureAtlas() {
return voxelColorTextureAtlas;
}
} // namespace Deer
*/

View File

@ -1,88 +0,0 @@
#include "DeerRender/VoxelWorld.h"
#include "Deer/Voxels/Chunk.h"
#include "Deer/Voxels/VoxelWorldData.h"
#include "DeerRender/Application.h"
#include "DeerRender/Components.h"
#include "DeerRender/Log.h"
#include "DeerRender/Tools/Memory.h"
#include "DeerRender/Voxel.h"
#include "DeerRender/Render/Render.h"
#include "DeerRender/Render/RenderUtils.h"
#include "DeerRender/Render/Texture.h"
#include "DeerRender/Scene.h"
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_inverse.hpp"
#include "glm/gtc/matrix_transform.hpp"
namespace Deer {
VoxelLight VoxelWorld::readLight(VoxelCordinates coords) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
ChunkID chunkID;
ChunkVoxelID chunkVoxelID;
extractChunkCordinates(coords, chunkID, chunkVoxelID);
if (!worldProps.isValid(chunkID))
return lightVoxel;
Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
return chunk.readLight(chunkVoxelID);
}
VoxelLight& VoxelWorld::modLight(VoxelCordinates coords) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
ChunkID chunkID;
ChunkVoxelID chunkVoxelID;
extractChunkCordinates(coords, chunkID, chunkVoxelID);
if (!worldProps.isValid(chunkID))
return lightVoxel;
chunkQueue.addChunk(chunkID);
Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
return chunk.modLight(chunkVoxelID);
}
void VoxelWorld::render(const SceneCamera& camera) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
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;
// DataStore::getVoxelColorTextureAtlas()->bind(0);
// Ref<Shader>& shader = DataStore::getSolidVoxelShader();
// shader->bind();
// shader->uploadUniformMat4("u_viewMatrix", cameraProjectionMatrix);
// shader->uploadUniformMat4("u_worldMatrix", glm::mat4(1.0f));
// shader->uploadUniformInt("u_texture", 0);
// shader->uploadUniformInt("u_textureSize",
// DataStore::getVoxelTextureAtlasSize());
for (int x = 0; x < worldProps.getChunkCount(); x++) {
ChunkRender& chunkRender = chunksRender[x];
if (!chunkRender.hasData)
continue;
ChunkID chunkID = worldProps.getChunkID(x);
chunkRender.solidVoxel->bind();
// shader->uploadUniformInt("u_chunkID_x", chunkID.x);
// shader->uploadUniformInt("u_chunkID_y", chunkID.y);
// shader->uploadUniformInt("u_chunkID_z", chunkID.z);
Render::submit(*chunkRender.solidVoxel);
}
}
} // namespace Deer

View File

@ -1,39 +0,0 @@
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
#include "Deer/Voxels/Chunk.h"
#include "DeerRender/VoxelWorld.h"
namespace Deer {
namespace VoxelWorld {
// Chunk render data
Scope<ChunkRender[]> chunksRender;
ChunkUpdateQueue chunkQueue;
// Voxel creation data
std::vector<uint32_t> indices;
std::vector<SolidVoxelVertexData> vertexData;
std::queue<VoxelCordinates> ambientLightPropagation;
std::queue<VoxelCordinates> voxelLightPropagation;
std::vector<VoxelCordinates> tmp_voxelLightSource;
} // namespace VoxelWorld
void VoxelWorld::clearRenderVars() {
chunksRender.reset();
chunkQueue.reset();
indices.clear();
vertexData.clear();
while (!ambientLightPropagation.empty()) {
ambientLightPropagation.pop();
}
while (!voxelLightPropagation.empty()) {
voxelLightPropagation.pop();
}
tmp_voxelLightSource.clear();
}
void VoxelWorld::initializeRenderVars(const VoxelWorldProps& props) {
chunksRender = MakeScope<ChunkRender[]>(props.getChunkCount());
}
} // namespace Deer

View File

@ -1,68 +0,0 @@
#pragma once
#include <queue>
#include <unordered_set>
#include <vector>
#include "DeerRender/Render/VertexArray.h"
#include "DeerRender/Tools/Memory.h"
#include "DeerRender/Voxel.h"
#include "DeerRender/VoxelWorld.h"
namespace Deer {
struct ChunkRender {
Scope<VertexArray> solidVoxel;
bool hasData = false;
};
struct SolidVoxelVertexData {
uint16_t textureID = 0;
uint8_t ambient_occlusion = 0;
uint8_t xPos = 0;
uint8_t yPos = 0;
uint8_t zPos = 0;
uint8_t a_light = 0;
uint8_t r_light = 0;
uint8_t g_light = 0;
uint8_t b_light = 0;
uint8_t normal = 0;
uint8_t u = 0;
uint8_t v = 0;
SolidVoxelVertexData() = default;
};
class ChunkUpdateQueue {
public:
// TODO: Add priority
void addChunk(ChunkID);
void reset();
ChunkID pullChunk();
bool hasChunk();
private:
std::queue<ChunkID> m_updateOrder;
std::unordered_set<ChunkID, ChunkIDHash> m_containingChunks;
};
namespace VoxelWorld {
// Chunk render data
extern Scope<ChunkRender[]> chunksRender;
extern ChunkUpdateQueue chunkQueue;
// Voxel creation data
extern std::vector<uint32_t> indices;
extern std::vector<SolidVoxelVertexData> vertexData;
// Voxel temp light variables
extern std::queue<VoxelCordinates> ambientLightPropagation;
extern std::queue<VoxelCordinates> voxelLightPropagation;
extern std::vector<VoxelCordinates> tmp_voxelLightSource;
void clearRenderVars();
void initializeRenderVars(const VoxelWorldProps& props);
} // namespace VoxelWorld
} // namespace Deer

View File

@ -1,177 +0,0 @@
#include "Deer/Voxels/Chunk.h"
#include "DeerRender/Application.h"
#include "DeerRender/VoxelWorld.h"
#include "Deer/Voxels/VoxelWorldData.h"
#include "DeerRender/Components.h"
#include "DeerRender/Render/Render.h"
#include "DeerRender/Render/RenderUtils.h"
#include "DeerRender/Render/Texture.h"
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
#include "DeerRender/Log.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_inverse.hpp"
#include "glm/gtc/matrix_transform.hpp"
namespace Deer {
void VoxelWorld::bakeAmbientLight(int minX, int maxX, int minZ, int maxZ) {
int xPos = minX;
for (; xPos <= maxX; xPos++) {
int zPos = minZ;
for (; zPos <= maxZ; zPos++) {
LayerVoxel layer = readLayerVoxel(xPos, zPos);
uint16_t maxHeight = layer.height;
uint16_t minHeight = layer.ambient_light_height;
if (minHeight > layer.height)
minHeight = layer.height;
uint16_t maxHeightSorroundings = maxHeight;
for (int i = 0; i < 8; i++) {
int checkX = xPos + LAYER_CHECK_DIRS(X_AXIS, i);
int checkZ = zPos + LAYER_CHECK_DIRS(Y_AXIS, i);
LayerVoxel layer = readLayerVoxel(checkX, checkZ);
if (layer.height > maxHeightSorroundings)
maxHeightSorroundings = layer.height;
}
maxHeightSorroundings++;
if (maxHeightSorroundings >= CHUNK_SIZE_Y * worldProps.chunkSizeY)
maxHeightSorroundings = CHUNK_SIZE_Y * worldProps.chunkSizeY - 1;
ChunkID chunkID;
ChunkVoxelID chunkVoxelID;
// Depending if it's an edge we will add to queue to propagate the light
bool isPositionEdge =
(xPos == minX) || (xPos == maxX) ||
(zPos == minZ) || (zPos == maxZ);
if (xPos == 0 || zPos == 0 || xPos == CHUNK_SIZE_X * worldProps.chunkSizeX - 1 || zPos == CHUNK_SIZE_Z * worldProps.chunkSizeZ - 1)
isPositionEdge = false;
// All light voxelsInfo under the max height must be put to 0 ambient light and above to 255
// I think this is optional
int yPos = minHeight;
if (!isPositionEdge) {
// Empty the ilumination
for (; yPos < maxHeight; yPos++) {
extractChunkCordinates(xPos, yPos, zPos, chunkID, chunkVoxelID);
Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
VoxelLight& voxelLight = chunk.modLight(chunkVoxelID);
voxelLight.ambient_light = 0;
}
} else {
// Add to queue
for (; yPos < maxHeight; yPos++) {
extractChunkCordinates(xPos, yPos, zPos, chunkID, chunkVoxelID);
Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
VoxelLight voxelLight = chunk.readLight(chunkVoxelID);
if (voxelLight.ambient_light > 0)
ambientLightPropagation.push(VoxelCordinates(xPos, yPos, zPos));
}
}
// Fill with light voxelsInfo and add queue to update light propagation
for (; yPos < maxHeightSorroundings; yPos++) {
extractChunkCordinates(xPos, yPos, zPos, chunkID, chunkVoxelID);
Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
VoxelLight& voxelLight = chunk.modLight(chunkVoxelID);
voxelLight.ambient_light = 255;
ambientLightPropagation.push(VoxelCordinates(xPos, yPos, zPos));
}
modLayerVoxel(xPos, zPos).ambient_light_height = CHUNK_SIZE_Y * worldProps.chunkSizeY;
}
}
// Resolve ambient light propagation
while (!ambientLightPropagation.empty()) {
resolveNextAmbientLightPropagation();
}
}
void VoxelWorld::bakeAmbientLightFromPoint(int x, int z) {
int minX = x - 16;
int maxX = x + 16;
int minZ = z - 16;
int maxZ = z + 16;
minX = (minX < 0) ? 0 : minX;
maxX = (maxX >= worldProps.chunkSizeX * CHUNK_SIZE_X) ? worldProps.chunkSizeX * CHUNK_SIZE_X - 1 : maxX;
minZ = (minZ < 0) ? 0 : minZ;
maxZ = (maxZ >= worldProps.chunkSizeZ * CHUNK_SIZE_Z) ? worldProps.chunkSizeZ * CHUNK_SIZE_Z - 1 : maxZ;
bakeAmbientLight(minX, maxX, minZ, maxZ);
}
void VoxelWorld::resolveNextAmbientLightPropagation() {
VoxelCordinates position = ambientLightPropagation.front();
ambientLightPropagation.pop();
LayerVoxel& layerVoxel = modLayerVoxel(position.x, position.z);
if (layerVoxel.ambient_light_height > position.y)
layerVoxel.ambient_light_height = position.y;
VoxelLight currentLight = readLight(position);
bool solidCheck[6] = {false};
// Check for every simple dir
for (int i = 0; i < 6; i++) {
VoxelCordinates next(
position.x + NORMAL_DIR(X_AXIS, i),
position.y + NORMAL_DIR(Y_AXIS, i),
position.z + NORMAL_DIR(Z_AXIS, i));
Voxel nextVoxel = readVoxel(next);
solidCheck[i] = nextVoxel.isVoxelType();
if (solidCheck[i])
continue;
VoxelLight& nextLight = modLight(next);
int nextLightMinValue = currentLight.ambient_light - LIGHT_PROPAGATION_SIMPLE_FALL;
if (nextLight.ambient_light < nextLightMinValue) {
nextLight.ambient_light = nextLightMinValue;
ambientLightPropagation.push(next);
}
}
return;
// TODO
// Check for every complex dir
for (int i = 0; i < 6; i++) {
int cDir0 = LIGHT_PROPAGATION_COMPLEX_DIR(0, i);
int cDir1 = LIGHT_PROPAGATION_COMPLEX_DIR(1, i);
if (solidCheck[cDir0] || solidCheck[cDir1])
continue;
VoxelCordinates next(
NORMAL_DIR(X_AXIS, cDir0) + NORMAL_DIR(X_AXIS, cDir1),
NORMAL_DIR(Y_AXIS, cDir0) + NORMAL_DIR(Y_AXIS, cDir1),
NORMAL_DIR(Z_AXIS, cDir0) + NORMAL_DIR(Z_AXIS, cDir1));
Voxel nextVoxel = readVoxel(next);
if (nextVoxel.isVoxelType())
continue;
VoxelLight& nextLight = modLight(next);
int nextLightMinValue = currentLight.ambient_light - LIGHT_PROPAGATION_COMPLEX_FALL;
if (nextLight.ambient_light < nextLightMinValue) {
nextLight.ambient_light = nextLightMinValue;
ambientLightPropagation.push(next);
}
}
}
} // namespace Deer

View File

@ -1,263 +0,0 @@
#include "Deer/Voxels/Chunk.h"
#include "Deer/Voxels/VoxelWorldData.h"
#include "DeerRender/Application.h"
#include "DeerRender/Components.h"
#include "DeerRender/VoxelWorld.h"
#include "DeerRender/Render/Render.h"
#include "DeerRender/Render/RenderUtils.h"
#include "DeerRender/Render/Texture.h"
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_inverse.hpp"
#include "glm/gtc/matrix_transform.hpp"
namespace Deer {
void VoxelWorld::bakeNextChunk() {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
if (!chunkQueue.hasChunk())
return;
// Pull the next chunk to render
ChunkID nextChunk = chunkQueue.pullChunk();
vertexData.clear();
indices.clear();
// For each voxel
for (int x = 0; x < CHUNK_SIZE_X; x++) {
for (int y = 0; y < CHUNK_SIZE_Y; y++) {
for (int z = 0; z < CHUNK_SIZE_Z; z++) {
genSolidVoxel(nextChunk, ChunkVoxelID(x, y, z));
}
}
}
// Pass the data to the GPU
Scope<VertexArray> va = Scope<VertexArray>(VertexArray::create());
va->bind();
Ref<VertexBuffer> vb = VertexBuffer::create(
vertexData.data(),
vertexData.size() * sizeof(SolidVoxelVertexData));
Ref<IndexBuffer> ib =
IndexBuffer::create(indices.data(),
indices.size() * sizeof(uint32_t),
IndexDataType::Unsigned_Int);
BufferLayout layout(
{{"a_textureID", DataType::Unsigned_Short2, ShaderDataType::Integer,
offsetof(SolidVoxelVertexData, textureID)},
{"a_ambient_occlusion", DataType::Unsigned_Byte,
ShaderDataType::FloatingPoint,
offsetof(SolidVoxelVertexData, ambient_occlusion)},
{"a_xPos", DataType::Unsigned_Byte, ShaderDataType::FloatingPoint,
offsetof(SolidVoxelVertexData, xPos)},
{"a_yPos", DataType::Unsigned_Byte, ShaderDataType::FloatingPoint,
offsetof(SolidVoxelVertexData, yPos)},
{"a_zPos", DataType::Unsigned_Byte, ShaderDataType::FloatingPoint,
offsetof(SolidVoxelVertexData, zPos)},
{"a_a_light", DataType::Unsigned_Byte,
ShaderDataType::FloatingPoint,
offsetof(SolidVoxelVertexData, a_light)},
{"a_r_light", DataType::Unsigned_Byte,
ShaderDataType::FloatingPoint,
offsetof(SolidVoxelVertexData, r_light)},
{"a_g_light", DataType::Unsigned_Byte,
ShaderDataType::FloatingPoint,
offsetof(SolidVoxelVertexData, g_light)},
{"a_b_light", DataType::Unsigned_Byte,
ShaderDataType::FloatingPoint,
offsetof(SolidVoxelVertexData, b_light)},
{"a_normal", DataType::Unsigned_Byte, ShaderDataType::Integer,
offsetof(SolidVoxelVertexData, normal)},
{"a_u", DataType::Unsigned_Byte, ShaderDataType::FloatingPoint,
offsetof(SolidVoxelVertexData, u)},
{"a_v", DataType::Unsigned_Byte, ShaderDataType::FloatingPoint,
offsetof(SolidVoxelVertexData, v)}},
sizeof(SolidVoxelVertexData));
vb->setLayout(layout);
va->addVertexBuffer(vb);
va->setIndexBuffer(ib);
// Update the data to the chunk render
int id = worldProps.getWorldChunkID(nextChunk);
ChunkRender& chunkRender = chunksRender[id];
chunkRender.solidVoxel = std::move(va);
chunkRender.hasData = true;
}
void VoxelWorld::genSolidVoxel(ChunkID chunkID, ChunkVoxelID chunkVoxelID) {
Chunk& workingChunk = chunks[worldProps.getWorldChunkID(chunkID)];
Voxel voxel = workingChunk.readVoxel(chunkVoxelID);
if (!voxel.isVoxelType())
return;
for (int i = 0; i < 6; i++) {
// front means the front voxel of the face
VoxelCordinates frontID(NORMAL_DIR(X_AXIS, i) + chunkVoxelID.x +
CHUNK_SIZE_X * chunkID.x,
NORMAL_DIR(Y_AXIS, i) + chunkVoxelID.y +
CHUNK_SIZE_Y * chunkID.y,
NORMAL_DIR(Z_AXIS, i) + chunkVoxelID.z +
CHUNK_SIZE_Z * chunkID.z);
Voxel frontVoxel = readVoxel(frontID);
// If the face is inside 2 Voxels we will not render it
if (frontVoxel.isVoxelType())
continue;
VoxelLight frontVoxelLight = readLight(frontID);
// front2ID means the front voxel in 2 voxels apart
VoxelCordinates front2ID(
NORMAL_DIR(X_AXIS, i) * 2 + chunkVoxelID.x +
CHUNK_SIZE_X * chunkID.x,
NORMAL_DIR(Y_AXIS, i) * 2 + chunkVoxelID.y +
CHUNK_SIZE_Y * chunkID.y,
NORMAL_DIR(Z_AXIS, i) * 2 + chunkVoxelID.z +
CHUNK_SIZE_Z * chunkID.z);
Voxel front2Voxel = readVoxel(frontID);
VoxelLight front2VoxelLight = readLight(frontID);
// Face Shadow means that face is not in the direction of the light
bool isFaceShadow = frontVoxelLight.ambient_light != 255 &&
(frontVoxel.isVoxelType() ||
frontVoxelLight.ambient_light >
front2VoxelLight.ambient_light);
// Save the vertex id for later
int vertexID = vertexData.size();
int voxel_count[4];
// For every vertex
for (int v = 0; v < 4; v++) {
// This var takes the count of the voxels that where added in
// voxel_light
int sample_count = 1;
// Count the blocks to calculate the ambient occlusion, min
// value 0 max value 2
voxel_count[v] = 0;
// col 0 -> ambient oclusion
// col 1 -> red light
// col 2 -> green light
// col 3 -> blue light
int voxel_light[4];
voxel_light[0] = frontVoxelLight.ambient_light;
voxel_light[1] = frontVoxelLight.r_light;
voxel_light[2] = frontVoxelLight.g_light;
voxel_light[3] = frontVoxelLight.b_light;
// Checks if there is air on the blocks of the side
bool airEdge[2];
// Calculate ambient occlusion and light difusion
for (int a = 0; a < 2; a++) {
VoxelCordinates checkChordsID(
frontID.x + AMBIENT_OCCLUSION_VERTEX(X_AXIS, a, v, i),
frontID.y + AMBIENT_OCCLUSION_VERTEX(Y_AXIS, a, v, i),
frontID.z + AMBIENT_OCCLUSION_VERTEX(Z_AXIS, a, v, i));
Voxel checkChordsVoxel = readVoxel(checkChordsID);
VoxelLight checkChordsVoxelLight = readLight(checkChordsID);
// Check for the same chords but 2 voxels apart
airEdge[a] = !checkChordsVoxel.isVoxelType();
if (airEdge[a]) {
sample_count++;
voxel_light[0] += checkChordsVoxelLight.ambient_light;
voxel_light[1] += checkChordsVoxelLight.r_light;
voxel_light[2] += checkChordsVoxelLight.g_light;
voxel_light[3] += checkChordsVoxelLight.b_light;
} else {
voxel_count[v]++;
}
}
if (airEdge[0] || airEdge[1]) {
VoxelCordinates checkChordsID(
frontID.x + AMBIENT_OCCLUSION_VERTEX(X_AXIS, 0, v, i) +
AMBIENT_OCCLUSION_VERTEX(X_AXIS, 1, v, i),
frontID.y + AMBIENT_OCCLUSION_VERTEX(Y_AXIS, 0, v, i) +
AMBIENT_OCCLUSION_VERTEX(Y_AXIS, 1, v, i),
frontID.z + AMBIENT_OCCLUSION_VERTEX(Z_AXIS, 0, v, i) +
AMBIENT_OCCLUSION_VERTEX(Z_AXIS, 1, v, i));
Voxel checkChordsVoxel = readVoxel(checkChordsID);
VoxelLight checkChordsVoxelLight = readLight(checkChordsID);
if (!checkChordsVoxel.isVoxelType()) {
sample_count++;
voxel_light[0] += checkChordsVoxelLight.ambient_light;
voxel_light[1] += checkChordsVoxelLight.r_light;
voxel_light[2] += checkChordsVoxelLight.g_light;
voxel_light[3] += checkChordsVoxelLight.b_light;
} else {
voxel_count[v]++;
}
}
for (int xi = 0; xi < 4; xi++) {
voxel_light[xi] = (voxel_light[xi]) / sample_count;
voxel_light[xi] =
(voxel_light[xi] > 255) ? 255 : voxel_light[xi];
}
SolidVoxelVertexData vertex_data;
vertex_data.textureID =
DataStore::voxelsAspect[voxel.id].getTextureID(i);
vertex_data.ambient_occlusion = voxel_count[v];
vertex_data.xPos =
chunkVoxelID.x + NORMAL_VERTEX_POS(X_AXIS, v, i);
vertex_data.yPos =
chunkVoxelID.y + NORMAL_VERTEX_POS(Y_AXIS, v, i);
vertex_data.zPos =
chunkVoxelID.z + NORMAL_VERTEX_POS(Z_AXIS, v, i);
vertex_data.a_light = voxel_light[0];
vertex_data.r_light = voxel_light[1];
vertex_data.g_light = voxel_light[2];
vertex_data.b_light = voxel_light[3];
vertex_data.normal = i;
vertex_data.u = VERTEX_UV(X_AXIS, v);
vertex_data.v = VERTEX_UV(Y_AXIS, v);
vertexData.push_back(vertex_data);
}
if (voxel_count[0] + voxel_count[3] >
voxel_count[1] + voxel_count[2]) {
indices.push_back(vertexID);
indices.push_back(vertexID + 2);
indices.push_back(vertexID + 1);
indices.push_back(vertexID + 1);
indices.push_back(vertexID + 2);
indices.push_back(vertexID + 3);
} else {
indices.push_back(vertexID);
indices.push_back(vertexID + 3);
indices.push_back(vertexID + 1);
indices.push_back(vertexID + 2);
indices.push_back(vertexID + 3);
indices.push_back(vertexID);
}
}
}
} // namespace Deer

View File

@ -1,250 +0,0 @@
#include "Deer/Voxels/Chunk.h"
#include "Deer/Voxels/VoxelWorldData.h"
#include "DeerRender/Log.h"
#include "DeerRender/VoxelWorld.h"
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
namespace Deer {
void VoxelWorld::bakeVoxelLightFromPoint(VoxelCordinates coords) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
VoxelCordinates min = VoxelCordinates(coords.x - 16, coords.y - 16, coords.z - 16);
VoxelCordinates max = VoxelCordinates(coords.x + 16, coords.y + 16, coords.z + 16);
worldProps.clampCordinates(min);
worldProps.clampCordinates(max);
bakeVoxelLight(min, max);
}
void VoxelWorld::bakeVoxelLight(VoxelCordinates min, VoxelCordinates max) {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
// We want to make the box 1 layer smaller
// For every axis, X & Y & Z
for (int i = 0; i < 3; i++) {
min[i]++;
max[i]--;
}
ChunkID minChunkID;
ChunkID maxChunkID;
ChunkVoxelID minChunkVoxelID;
ChunkVoxelID maxChunkVoxelID;
extractChunkCordinates(min, minChunkID, minChunkVoxelID);
extractChunkCordinates(max, maxChunkID, maxChunkVoxelID);
tmp_voxelLightSource.clear();
// We want to empty the voxel light of the section first
ChunkID workingChunkID;
for (workingChunkID.x = minChunkID.x; workingChunkID.x <= maxChunkID.x;
workingChunkID.x++) {
for (workingChunkID.y = minChunkID.y;
workingChunkID.y <= maxChunkID.y; workingChunkID.y++) {
for (workingChunkID.z = minChunkID.z;
workingChunkID.z <= maxChunkID.z; workingChunkID.z++) {
ChunkVoxelID workingMinVoxelID(
(workingChunkID.x == minChunkID.x) ? minChunkVoxelID.x
: 0,
(workingChunkID.y == minChunkID.y) ? minChunkVoxelID.y
: 0,
(workingChunkID.z == minChunkID.z) ? minChunkVoxelID.z
: 0);
ChunkVoxelID workingMaxVoxelID(
(workingChunkID.x == maxChunkID.x) ? maxChunkVoxelID.x
: CHUNK_SIZE_X - 1,
(workingChunkID.y == maxChunkID.y) ? maxChunkVoxelID.y
: CHUNK_SIZE_Y - 1,
(workingChunkID.z == maxChunkID.z) ? maxChunkVoxelID.z
: CHUNK_SIZE_Z - 1);
Chunk& workingChunk =
chunks[worldProps.getWorldChunkID(workingChunkID)];
workingChunk.clearVoxelLightAndSaveSources(
workingMinVoxelID, workingMaxVoxelID, workingChunkID,
tmp_voxelLightSource);
}
}
}
// Cover all 6 edges with light propagation
for (int x = min.x; x <= max.x; x++) {
for (int y = min.y; y <= max.y; y++) {
VoxelCordinates minZEdge(x, y, min.z - 1);
VoxelCordinates maxZEdge(x, y, max.z + 1);
VoxelLight minZEdgeLight = readLight(minZEdge);
VoxelLight maxZEdgeLight = readLight(maxZEdge);
if (minZEdgeLight.b_light || minZEdgeLight.g_light ||
minZEdgeLight.b_light)
voxelLightPropagation.push(minZEdge);
if (maxZEdgeLight.b_light || maxZEdgeLight.g_light ||
maxZEdgeLight.b_light)
voxelLightPropagation.push(maxZEdge);
}
}
for (int x = min.x; x <= max.x; x++) {
for (int z = min.z; z <= max.z; z++) {
VoxelCordinates minYEdge(x, min.y - 1, z);
VoxelCordinates maxYEdge(x, max.y + 1, z);
VoxelLight minYEdgeLight = readLight(minYEdge);
VoxelLight maxYEdgeLight = readLight(maxYEdge);
if (minYEdgeLight.b_light || minYEdgeLight.g_light ||
minYEdgeLight.b_light)
voxelLightPropagation.push(minYEdge);
if (maxYEdgeLight.b_light || maxYEdgeLight.g_light ||
maxYEdgeLight.b_light)
voxelLightPropagation.push(maxYEdge);
}
}
for (int y = min.y; y <= max.y; y++) {
for (int z = min.z; z <= max.z; z++) {
VoxelCordinates minXEdge(min.x - 1, y, z);
VoxelCordinates maxXEdge(max.x + 1, y, z);
VoxelLight minXEdgeLight = readLight(minXEdge);
VoxelLight maxXEdgeLight = readLight(maxXEdge);
if (minXEdgeLight.b_light || minXEdgeLight.g_light ||
minXEdgeLight.b_light)
voxelLightPropagation.push(minXEdge);
if (maxXEdgeLight.b_light || maxXEdgeLight.g_light ||
maxXEdgeLight.b_light)
voxelLightPropagation.push(maxXEdge);
}
}
for (VoxelCordinates& cordinates : tmp_voxelLightSource) {
VoxelLight& voxelLight = modLight(cordinates);
Voxel voxel = readVoxel(cordinates);
VoxelAspect& voxelAspect = DataStore::voxelsAspect[voxel.id];
voxelLight.r_light = voxelAspect.definition.colorEmission.r_value;
voxelLight.g_light = voxelAspect.definition.colorEmission.g_value;
voxelLight.b_light = voxelAspect.definition.colorEmission.b_value;
voxelLightPropagation.push(cordinates);
}
while (!voxelLightPropagation.empty()) {
resolveNextVoxelLightPropagation();
}
}
void VoxelWorld::resolveNextVoxelLightPropagation() {
DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
VoxelCordinates position = voxelLightPropagation.front();
voxelLightPropagation.pop();
VoxelLight currentLight = readLight(position);
bool voxelCheck[6] = {false};
int highestRGBValue = currentLight.r_light;
if (highestRGBValue < currentLight.g_light)
highestRGBValue = currentLight.g_light;
if (highestRGBValue < currentLight.b_light)
highestRGBValue = currentLight.b_light;
int proportionalDecrease =
(LIGHT_PROPAGATION_SIMPLE_FALL * 100) / highestRGBValue;
int nextLightRedMinValue =
currentLight.r_light -
(proportionalDecrease * currentLight.r_light) / 100;
int nextLightGreenMinValue =
currentLight.g_light -
(proportionalDecrease * currentLight.g_light) / 100;
int nextLightBlueMinValue =
currentLight.b_light -
(proportionalDecrease * currentLight.b_light) / 100;
// Check for every simple dir
for (int i = 0; i < 6; i++) {
VoxelCordinates next(position.x + NORMAL_DIR(X_AXIS, i),
position.y + NORMAL_DIR(Y_AXIS, i),
position.z + NORMAL_DIR(Z_AXIS, i));
Voxel nextVoxel = readVoxel(next);
voxelCheck[i] = nextVoxel.isVoxelType();
if (voxelCheck[i])
continue;
VoxelLight& nextLight = modLight(next);
bool nextVoxelModified = false;
if (nextLight.r_light < nextLightRedMinValue) {
nextLight.r_light = nextLightRedMinValue;
nextVoxelModified = true;
}
if (nextLight.g_light < nextLightGreenMinValue) {
nextLight.g_light = nextLightGreenMinValue;
nextVoxelModified = true;
}
if (nextLight.b_light < nextLightBlueMinValue) {
nextLight.b_light = nextLightBlueMinValue;
nextVoxelModified = true;
}
if (nextVoxelModified)
voxelLightPropagation.push(next);
}
return;
// TODO
// Check for every complex dir
for (int i = 0; i < 6; i++) {
int cDir0 = LIGHT_PROPAGATION_COMPLEX_DIR(0, i);
int cDir1 = LIGHT_PROPAGATION_COMPLEX_DIR(1, i);
if (voxelCheck[cDir0] || voxelCheck[cDir1])
continue;
VoxelCordinates next(position.x + NORMAL_DIR(X_AXIS, cDir0) +
NORMAL_DIR(X_AXIS, cDir1),
position.y + NORMAL_DIR(Y_AXIS, cDir0) +
NORMAL_DIR(Y_AXIS, cDir1),
position.z + NORMAL_DIR(Z_AXIS, cDir0) +
NORMAL_DIR(Z_AXIS, cDir1));
Voxel nextVoxel = readVoxel(next);
if (nextVoxel.isVoxelType())
continue;
VoxelLight& nextLight = modLight(next);
int nextLightRedMinValue =
currentLight.r_light - LIGHT_PROPAGATION_COMPLEX_FALL;
int nextLightGreenMinValue =
currentLight.g_light - LIGHT_PROPAGATION_COMPLEX_FALL;
int nextLightBlueMinValue =
currentLight.b_light - LIGHT_PROPAGATION_COMPLEX_FALL;
bool nextVoxelModified = false;
if (nextLight.r_light < nextLightRedMinValue) {
nextLight.r_light = nextLightRedMinValue;
nextVoxelModified = true;
}
if (nextLight.g_light < nextLightGreenMinValue) {
nextLight.g_light = nextLightGreenMinValue;
nextVoxelModified = true;
}
if (nextLight.b_light < nextLightBlueMinValue) {
nextLight.b_light = nextLightBlueMinValue;
nextVoxelModified = true;
}
if (nextVoxelModified)
voxelLightPropagation.push(next);
}
}
} // namespace Deer

View File

@ -1,6 +1,6 @@
#include "LinuxWindow.h"
#include "Deer/Application.h"
#include "Deer/Log.h"
#include "DeerCore/Application.h"
#include "DeerCore/Log.h"
#include "glad/glad.h"

Some files were not shown because too many files have changed in this diff Show More