WIP adding directory structure

This commit is contained in:
2024-08-17 23:12:20 -07:00
parent 862ffeeaa0
commit 7e4fc361d4
34 changed files with 46 additions and 46 deletions

1693
kraken/resources/mesh/KRMesh.cpp Executable file

File diff suppressed because it is too large Load Diff

307
kraken/resources/mesh/KRMesh.h Executable file
View File

@@ -0,0 +1,307 @@
//
// KRMesh.h
// Kraken Engine
//
// Copyright 2024 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#pragma once
#include "KREngine-common.h"
#include "KRContext.h"
#include "KRBone.h"
#include "KRMeshManager.h"
#include "KREngine-common.h"
#include "hydra.h"
using namespace kraken;
#define MAX_VBO_SIZE 65535
#define KRENGINE_MAX_BONE_WEIGHTS_PER_VERTEX 4
#define KRENGINE_MAX_NAME_LENGTH 256
// MAX_VBO_SIZE must be divisible by 3 so triangles aren't split across VBO objects...
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
#include "resources/material/KRMaterialManager.h"
#include "KRCamera.h"
#include "KRViewport.h"
class KRMaterial;
class KRNode;
class KRRenderPass;
enum class ModelFormat : __uint8_t
{
KRENGINE_MODEL_FORMAT_TRIANGLES = 0,
KRENGINE_MODEL_FORMAT_STRIP,
KRENGINE_MODEL_FORMAT_INDEXED_TRIANGLES,
KRENGINE_MODEL_FORMAT_INDEXED_STRIP
};
class KRMesh : public KRResource
{
public:
static void parseName(const std::string& name, std::string& lodBaseName, int& lodCoverage);
KRMesh(KRContext& context, std::string name, mimir::Block* data);
KRMesh(KRContext& context, std::string name);
virtual ~KRMesh();
kraken_stream_level getStreamLevel();
void preStream(float lodCoverage);
bool hasTransparency();
typedef enum
{
KRENGINE_ATTRIB_VERTEX = 0,
KRENGINE_ATTRIB_NORMAL,
KRENGINE_ATTRIB_TANGENT,
KRENGINE_ATTRIB_TEXUVA,
KRENGINE_ATTRIB_TEXUVB,
KRENGINE_ATTRIB_BONEINDEXES,
KRENGINE_ATTRIB_BONEWEIGHTS,
KRENGINE_ATTRIB_VERTEX_SHORT,
KRENGINE_ATTRIB_NORMAL_SHORT,
KRENGINE_ATTRIB_TANGENT_SHORT,
KRENGINE_ATTRIB_TEXUVA_SHORT,
KRENGINE_ATTRIB_TEXUVB_SHORT,
KRENGINE_NUM_ATTRIBUTES
} vertex_attrib_t;
typedef struct
{
ModelFormat format;
std::vector<hydra::Vector3> vertices;
std::vector<__uint16_t> vertex_indexes;
std::vector<std::pair<int, int> > vertex_index_bases;
std::vector<hydra::Vector2> uva;
std::vector<hydra::Vector2> uvb;
std::vector<hydra::Vector3> normals;
std::vector<hydra::Vector3> tangents;
std::vector<int> submesh_starts;
std::vector<int> submesh_lengths;
std::vector<std::string> material_names;
std::vector<std::string> bone_names;
std::vector<std::vector<int> > bone_indexes;
std::vector<hydra::Matrix4> bone_bind_poses;
std::vector<std::vector<float> > bone_weights;
} mesh_info;
void render(const KRNode::RenderInfo& ri, const std::string& object_name, const hydra::Matrix4& matModel, KRTexture* pLightMap, const std::vector<KRBone*>& bones, const hydra::Vector3& rim_color, float rim_power, float lod_coverage = 0.0f);
std::string m_lodBaseName;
virtual std::string getExtension();
virtual bool save(const std::string& path);
virtual bool save(mimir::Block& data);
void LoadData(const mesh_info& mi, bool calculate_normals, bool calculate_tangents);
void loadPack(mimir::Block* data);
void convertToIndexed();
void optimize();
void optimizeIndexes();
void renderNoMaterials(VkCommandBuffer& commandBuffer, const KRRenderPass* renderPass, const std::string& object_name, const std::string& material_name, float lodCoverage);
bool isReady() const;
float getMaxDimension();
hydra::Vector3 getMinPoint() const;
hydra::Vector3 getMaxPoint() const;
class Submesh
{
public:
Submesh()
{};
~Submesh()
{
vbo_data_blocks.clear();
for (auto itr = vertex_data_blocks.begin(); itr != vertex_data_blocks.end(); itr++) {
delete (*itr);
}
for (auto itr = index_data_blocks.begin(); itr != index_data_blocks.end(); itr++) {
delete (*itr);
}
};
int start_vertex;
int vertex_count;
char szMaterialName[KRENGINE_MAX_NAME_LENGTH];
vector<mimir::Block*> vertex_data_blocks;
vector<mimir::Block*> index_data_blocks;
// KRMeshManager depends on the address of KRVBOData's being constant
// after allocation, enforced by deleted copy constructors.
// As std::vector requires copy constuctors, we wrap these in shared_ptr.
vector<shared_ptr<KRMeshManager::KRVBOData>> vbo_data_blocks;
};
typedef struct
{
union
{
struct
{ // For Indexed triangles / strips
uint16_t index_group;
uint16_t index_group_offset;
};
int32_t start_vertex; // For non-indexed trigangles / strips
};
int32_t vertex_count;
char szName[KRENGINE_MAX_NAME_LENGTH];
} pack_material;
typedef struct
{
char szName[KRENGINE_MAX_NAME_LENGTH];
float bind_pose[16];
} pack_bone;
int getLODCoverage() const;
std::string getLODBaseName() const;
static bool lod_sort_predicate(const KRMesh* m1, const KRMesh* m2);
bool has_vertex_attribute(vertex_attrib_t attribute_type) const;
static bool has_vertex_attribute(int vertex_attrib_flags, vertex_attrib_t attribute_type);
int getSubmeshCount() const;
int getVertexCount(int submesh) const;
__uint32_t getVertexAttributes() const;
int getTriangleVertexIndex(int submesh, int index) const;
hydra::Vector3 getVertexPosition(int index) const;
hydra::Vector3 getVertexNormal(int index) const;
hydra::Vector3 getVertexTangent(int index) const;
hydra::Vector2 getVertexUVA(int index) const;
hydra::Vector2 getVertexUVB(int index) const;
int getBoneIndex(int index, int weight_index) const;
float getBoneWeight(int index, int weight_index) const;
void setVertexPosition(int index, const hydra::Vector3& v);
void setVertexNormal(int index, const hydra::Vector3& v);
void setVertexTangent(int index, const hydra::Vector3& v);
void setVertexUVA(int index, const hydra::Vector2& v);
void setVertexUVB(int index, const hydra::Vector2& v);
void setBoneIndex(int index, int weight_index, int bone_index);
void setBoneWeight(int index, int weight_index, float bone_weight);
static size_t VertexSizeForAttributes(__int32_t vertex_attrib_flags);
static size_t AttributeOffset(__int32_t vertex_attrib, __int32_t vertex_attrib_flags);
static VkFormat AttributeVulkanFormat(__int32_t vertex_attrib);
int getBoneCount();
char* getBoneName(int bone_index);
hydra::Matrix4 getBoneBindPose(int bone_index);
ModelFormat getModelFormat() const;
bool lineCast(const hydra::Vector3& v0, const hydra::Vector3& v1, hydra::HitInfo& hitinfo) const;
bool rayCast(const hydra::Vector3& v0, const hydra::Vector3& dir, hydra::HitInfo& hitinfo) const;
bool sphereCast(const hydra::Matrix4& model_to_world, const hydra::Vector3& v0, const hydra::Vector3& v1, float radius, hydra::HitInfo& hitinfo) const;
static int GetLODCoverage(const std::string& name);
protected:
bool m_constant; // TRUE if this should be always loaded and should not be passed through the streamer
private:
mimir::Block* m_pData;
mimir::Block* m_pMetaData;
mimir::Block* m_pIndexBaseData;
void getSubmeshes();
void getMaterials();
void renderSubmesh(VkCommandBuffer& commandBuffer, int iSubmesh, const KRRenderPass* renderPass, const std::string& object_name, const std::string& material_name, float lodCoverage);
static bool rayCast(const hydra::Vector3& start, const hydra::Vector3& dir, const hydra::Triangle3& tri, const hydra::Vector3& tri_n0, const hydra::Vector3& tri_n1, const hydra::Vector3& tri_n2, hydra::HitInfo& hitinfo);
static bool sphereCast(const hydra::Matrix4& model_to_world, const hydra::Vector3& v0, const hydra::Vector3& v1, float radius, const hydra::Triangle3& tri, hydra::HitInfo& hitinfo);
int m_lodCoverage; // This LOD level is activated when the bounding box of the model will cover less than this percent of the screen (100 = highest detail model)
vector<KRMaterial*> m_materials;
set<KRMaterial*> m_uniqueMaterials;
bool m_hasTransparency;
hydra::Vector3 m_minPoint, m_maxPoint;
typedef struct
{
char szTag[16];
int32_t model_format; // 0 == Triangle list, 1 == Triangle strips, 2 == Indexed triangle list, 3 == Indexed triangle strips, rest are reserved (model_format_t enum)
int32_t vertex_attrib_flags;
int32_t vertex_count;
int32_t submesh_count;
int32_t bone_count;
float minx, miny, minz, maxx, maxy, maxz; // Axis aligned bounding box, in model's coordinate space
int32_t index_count;
int32_t index_base_count;
unsigned char reserved[444]; // Pad out to 512 bytes
} pack_header;
vector<Submesh> m_submeshes;
int m_vertex_attribute_offset[KRENGINE_NUM_ATTRIBUTES];
int m_vertex_size;
void updateAttributeOffsets();
void setName(const std::string name);
pack_material* getSubmesh(int mesh_index) const;
unsigned char* getVertexData() const;
size_t getVertexDataOffset() const;
unsigned char* getVertexData(int index) const;
__uint16_t* getIndexData() const;
size_t getIndexDataOffset() const;
__uint32_t* getIndexBaseData() const;
pack_header* getHeader() const;
pack_bone* getBone(int index);
void getIndexedRange(int index_group, int& start_index_offset, int& start_vertex_offset, int& index_count, int& vertex_count) const;
void releaseData();
void createDataBlocks(KRMeshManager::KRVBOData::vbo_type t);
};

View File

@@ -0,0 +1,70 @@
//
// KRMeshCube.cpp
// Kraken Engine
//
// Copyright 2024 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#include "KRMeshCube.h"
using namespace hydra;
KRMeshCube::KRMeshCube(KRContext& context) : KRMesh(context, "__cube")
{
m_constant = true;
KRMesh::mesh_info mi;
mi.vertices.push_back(Vector3::Create(1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3::Create(-1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3::Create(1.0, -1.0, 1.0));
mi.vertices.push_back(Vector3::Create(-1.0, -1.0, 1.0));
mi.vertices.push_back(Vector3::Create(-1.0, -1.0, -1.0));
mi.vertices.push_back(Vector3::Create(-1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3::Create(-1.0, 1.0, -1.0));
mi.vertices.push_back(Vector3::Create(1.0, 1.0, 1.0));
mi.vertices.push_back(Vector3::Create(1.0, 1.0, -1.0));
mi.vertices.push_back(Vector3::Create(1.0, -1.0, 1.0));
mi.vertices.push_back(Vector3::Create(1.0, -1.0, -1.0));
mi.vertices.push_back(Vector3::Create(-1.0, -1.0, -1.0));
mi.vertices.push_back(Vector3::Create(1.0, 1.0, -1.0));
mi.vertices.push_back(Vector3::Create(-1.0, 1.0, -1.0));
mi.submesh_starts.push_back(0);
mi.submesh_lengths.push_back((int)mi.vertices.size());
mi.material_names.push_back("");
mi.format = ModelFormat::KRENGINE_MODEL_FORMAT_STRIP;
LoadData(mi, true, true);
}
KRMeshCube::~KRMeshCube()
{
}

View File

@@ -0,0 +1,43 @@
//
// KRMeshCube.h
// Kraken Engine
//
// Copyright 2024 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#pragma once
#include "KRMesh.h"
class KRMeshCube : public KRMesh
{
public:
KRMeshCube(KRContext& context);
virtual ~KRMeshCube();
private:
};

View File

@@ -0,0 +1,715 @@
//
// KRMeshManager.cpp
// Kraken Engine
//
// Copyright 2024 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#include "KREngine-common.h"
#include "KRMeshManager.h"
#include "KRMesh.h"
#include "KRMeshCube.h"
#include "KRMeshQuad.h"
#include "KRMeshSphere.h"
#include "KRRenderPass.h"
using namespace mimir;
KRMeshManager::KRMeshManager(KRContext& context)
: KRResourceManager(context)
, m_currentVBO(NULL)
, m_vboMemUsed(0)
, m_memoryTransferredThisFrame(0)
, m_streamerComplete(true)
, m_draw_call_logging_enabled(false)
, m_draw_call_log_used(false)
{
}
void KRMeshManager::init()
{
addModel(new KRMeshCube(*m_pContext));
addModel(new KRMeshQuad(*m_pContext));
addModel(new KRMeshSphere(*m_pContext));
// ---- Initialize stock models ----
static const float _KRENGINE_VBO_3D_CUBE_VERTEX_DATA[] = {
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
1.0,-1.0, 1.0,
-1.0,-1.0, 1.0,
-1.0,-1.0,-1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0,-1.0,
1.0, 1.0, 1.0,
1.0, 1.0,-1.0,
1.0,-1.0, 1.0,
1.0,-1.0,-1.0,
-1.0,-1.0,-1.0,
1.0, 1.0,-1.0,
-1.0, 1.0,-1.0
};
KRENGINE_VBO_3D_CUBE_ATTRIBS = (1 << KRMesh::KRENGINE_ATTRIB_VERTEX);
KRENGINE_VBO_3D_CUBE_VERTICES.expand(sizeof(float) * 3 * 14);
KRENGINE_VBO_3D_CUBE_VERTICES.lock();
memcpy(KRENGINE_VBO_3D_CUBE_VERTICES.getStart(), _KRENGINE_VBO_3D_CUBE_VERTEX_DATA, sizeof(float) * 3 * 14);
KRENGINE_VBO_3D_CUBE_VERTICES.unlock();
KRENGINE_VBO_DATA_3D_CUBE_VERTICES.init(this, &KRENGINE_VBO_3D_CUBE_VERTICES, nullptr, KRENGINE_VBO_3D_CUBE_ATTRIBS, false, KRVBOData::CONSTANT
#if KRENGINE_DEBUG_GPU_LABELS
, "Cube Mesh [built-in]"
#endif
);
initRandomParticles();
initVolumetricLightingVertexes();
static const float _KRENGINE_VBO_2D_SQUARE_VERTEX_DATA[] = {
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f
};
KRENGINE_VBO_2D_SQUARE_ATTRIBS = (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA);
KRENGINE_VBO_2D_SQUARE_VERTICES.expand(sizeof(float) * 5 * 4);
KRENGINE_VBO_2D_SQUARE_VERTICES.lock();
memcpy(KRENGINE_VBO_2D_SQUARE_VERTICES.getStart(), _KRENGINE_VBO_2D_SQUARE_VERTEX_DATA, sizeof(float) * 5 * 4);
KRENGINE_VBO_2D_SQUARE_VERTICES.unlock();
KRENGINE_VBO_DATA_2D_SQUARE_VERTICES.init(this, &KRENGINE_VBO_2D_SQUARE_VERTICES, nullptr, KRENGINE_VBO_2D_SQUARE_ATTRIBS, false, KRVBOData::CONSTANT
#if KRENGINE_DEBUG_GPU_LABELS
, "Square Mesh [built-in]"
#endif
);
}
KRMeshManager::~KRMeshManager()
{
for (unordered_multimap<std::string, KRMesh*>::iterator itr = m_models.begin(); itr != m_models.end(); ++itr) {
delete (*itr).second;
}
m_models.clear();
}
KRResource* KRMeshManager::loadResource(const std::string& name, const std::string& extension, Block* data)
{
if (extension.compare("krmesh") == 0) {
return loadModel(name.c_str(), data);
}
return nullptr;
}
KRResource* KRMeshManager::getResource(const std::string& name, const std::string& extension)
{
if (extension.compare("krmesh") == 0) {
std::string lodBaseName;
int lodCoverage;
KRMesh::parseName(name, lodBaseName, lodCoverage);
std::vector<KRMesh*> models = getModel(lodBaseName.c_str());
for (KRMesh* mesh : models) {
if (mesh->getLODCoverage() == lodCoverage) {
return mesh;
}
}
}
return nullptr;
}
KRMesh* KRMeshManager::loadModel(const char* szName, Block* pData)
{
KRMesh* pModel = new KRMesh(*m_pContext, szName, pData);
addModel(pModel);
return pModel;
}
void KRMeshManager::addModel(KRMesh* model)
{
std::string lowerName = model->getLODBaseName();
std::transform(lowerName.begin(), lowerName.end(),
lowerName.begin(), ::tolower);
m_models.insert(std::pair<std::string, KRMesh*>(lowerName, model));
}
KRMesh* KRMeshManager::getMaxLODModel(const char* szName)
{
std::vector<KRMesh*> models = getModel(szName);
// models are always in order of highest LOD first
if (models.size()) {
return models[0];
}
return nullptr;
}
std::vector<KRMesh*> KRMeshManager::getModel(const char* szName)
{
std::string lowerName = szName;
std::transform(lowerName.begin(), lowerName.end(),
lowerName.begin(), ::tolower);
std::vector<KRMesh*> matching_models;
std::pair<unordered_multimap<std::string, KRMesh*>::iterator, unordered_multimap<std::string, KRMesh*>::iterator> range = m_models.equal_range(lowerName);
for (unordered_multimap<std::string, KRMesh*>::iterator itr_match = range.first; itr_match != range.second; itr_match++) {
matching_models.push_back(itr_match->second);
}
std::sort(matching_models.begin(), matching_models.end(), KRMesh::lod_sort_predicate);
if (matching_models.size() == 0) {
KRContext::Log(KRContext::LOG_LEVEL_INFORMATION, "Model not found: %s", lowerName.c_str());
}
return matching_models;
}
unordered_multimap<std::string, KRMesh*>& KRMeshManager::getModels()
{
return m_models;
}
void KRMeshManager::bindVBO(VkCommandBuffer& commandBuffer, KRVBOData* vbo_data, float lodCoverage)
{
vbo_data->resetPoolExpiry(lodCoverage);
bool vbo_changed = false;
if (m_currentVBO == NULL) {
vbo_changed = true;
} else if (m_currentVBO->m_data != vbo_data->m_data) {
vbo_changed = true;
}
if (vbo_changed) {
if (m_vbosActive.find(vbo_data->m_data) != m_vbosActive.end()) {
m_currentVBO = m_vbosActive[vbo_data->m_data];
} else {
m_currentVBO = vbo_data;
m_vbosActive[vbo_data->m_data] = m_currentVBO;
}
m_currentVBO->bind(commandBuffer);
}
}
void KRMeshManager::startFrame(float deltaTime)
{
m_memoryTransferredThisFrame = 0;
if (m_draw_call_log_used) {
// Only log draw calls on the next frame if the draw call log was used on last frame
m_draw_call_log_used = false;
m_draw_call_logging_enabled = true;
}
m_draw_calls.clear();
// TODO - Implement proper double-buffering to reduce copy operations
m_streamerFenceMutex.lock();
if (m_streamerComplete) {
assert(m_activeVBOs_streamer_copy.size() == 0); // The streamer should have emptied this if it really did complete
const long KRENGINE_VBO_EXPIRY_FRAMES = 1;
std::set<KRVBOData*> expiredVBOs;
for (auto itr = m_vbosActive.begin(); itr != m_vbosActive.end(); itr++) {
KRVBOData* activeVBO = (*itr).second;
activeVBO->_swapHandles();
if (activeVBO->getType() == KRVBOData::CONSTANT) {
// Ensure that CONSTANT data is always loaded
float priority = std::numeric_limits<float>::max();
m_activeVBOs_streamer_copy.push_back(std::pair<float, KRVBOData*>(priority, activeVBO));
} else if (activeVBO->getLastFrameUsed() + KRENGINE_VBO_EXPIRY_FRAMES < getContext().getCurrentFrame()) {
// Expire VBO's that haven't been used in a long time
switch (activeVBO->getType()) {
case KRVBOData::STREAMING:
case KRVBOData::IMMEDIATE:
activeVBO->unload();
break;
case KRVBOData::CONSTANT:
// CONSTANT VBO's are not unloaded
break;
}
expiredVBOs.insert(activeVBO);
} else if (activeVBO->getType() == KRVBOData::STREAMING) {
float priority = activeVBO->getStreamPriority();
m_activeVBOs_streamer_copy.push_back(std::pair<float, KRVBOData*>(priority, activeVBO));
}
}
for (std::set<KRVBOData*>::iterator itr = expiredVBOs.begin(); itr != expiredVBOs.end(); itr++) {
m_vbosActive.erase((*itr)->m_data);
}
if (m_activeVBOs_streamer_copy.size() > 0) {
m_streamerComplete = false;
}
}
m_streamerFenceMutex.unlock();
}
void KRMeshManager::endFrame(float deltaTime)
{
m_currentVBO = nullptr;
}
void KRMeshManager::doStreaming(long& memoryRemaining, long& memoryRemainingThisFrame)
{
// TODO - Implement proper double-buffering to reduce copy operations
m_streamerFenceMutex.lock();
m_activeVBOs_streamer = std::move(m_activeVBOs_streamer_copy);
m_streamerFenceMutex.unlock();
if (m_activeVBOs_streamer.size() > 0) {
balanceVBOMemory(memoryRemaining, memoryRemainingThisFrame);
m_streamerFenceMutex.lock();
m_streamerComplete = true;
m_streamerFenceMutex.unlock();
} else {
memoryRemaining -= getMemUsed();
}
}
void KRMeshManager::balanceVBOMemory(long& memoryRemaining, long& memoryRemainingThisFrame)
{
std::sort(m_activeVBOs_streamer.begin(), m_activeVBOs_streamer.end(), std::greater<std::pair<float, KRVBOData*>>());
for (auto vbo_itr = m_activeVBOs_streamer.begin(); vbo_itr != m_activeVBOs_streamer.end(); vbo_itr++) {
KRVBOData* vbo_data = (*vbo_itr).second;
long vbo_size = vbo_data->getSize();
if (!vbo_data->isVBOLoaded()) {
if (memoryRemainingThisFrame > vbo_size) {
vbo_data->load();
memoryRemainingThisFrame -= vbo_size;
}
}
memoryRemaining -= vbo_size;
}
}
long KRMeshManager::getMemUsed()
{
return m_vboMemUsed;
}
long KRMeshManager::getMemActive()
{
long mem_active = 0;
for (unordered_map<Block*, KRVBOData*>::iterator itr = m_vbosActive.begin(); itr != m_vbosActive.end(); itr++) {
mem_active += (*itr).second->getSize();
}
return mem_active;
}
void KRMeshManager::initVolumetricLightingVertexes()
{
if (m_volumetricLightingVertexData.getSize() == 0) {
m_volumetricLightingVertexData.expand(sizeof(VolumetricLightingVertexData) * KRENGINE_MAX_VOLUMETRIC_PLANES * 6);
m_volumetricLightingVertexData.lock();
VolumetricLightingVertexData* vertex_data = (VolumetricLightingVertexData*)m_volumetricLightingVertexData.getStart();
int iVertex = 0;
for (int iPlane = 0; iPlane < KRENGINE_MAX_VOLUMETRIC_PLANES; iPlane++) {
vertex_data[iVertex].vertex.x = -1.0f;
vertex_data[iVertex].vertex.y = -1.0f;
vertex_data[iVertex].vertex.z = (float)iPlane;
iVertex++;
vertex_data[iVertex].vertex.x = 1.0f;
vertex_data[iVertex].vertex.y = -1.0f;
vertex_data[iVertex].vertex.z = (float)iPlane;
iVertex++;
vertex_data[iVertex].vertex.x = -1.0f;
vertex_data[iVertex].vertex.y = 1.0f;
vertex_data[iVertex].vertex.z = (float)iPlane;
iVertex++;
vertex_data[iVertex].vertex.x = -1.0f;
vertex_data[iVertex].vertex.y = 1.0f;
vertex_data[iVertex].vertex.z = (float)iPlane;
iVertex++;
vertex_data[iVertex].vertex.x = 1.0f;
vertex_data[iVertex].vertex.y = -1.0f;
vertex_data[iVertex].vertex.z = (float)iPlane;
iVertex++;
vertex_data[iVertex].vertex.x = 1.0f;
vertex_data[iVertex].vertex.y = 1.0f;
vertex_data[iVertex].vertex.z = (float)iPlane;
iVertex++;
}
KRENGINE_VBO_DATA_VOLUMETRIC_LIGHTING.init(this, &m_volumetricLightingVertexData, nullptr, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX), false, KRVBOData::CONSTANT
#if KRENGINE_DEBUG_GPU_LABELS
, "Volumetric Lighting Planes [built-in]"
#endif
);
m_volumetricLightingVertexData.unlock();
}
}
void KRMeshManager::initRandomParticles()
{
if (m_randomParticleVertexData.getSize() == 0) {
m_randomParticleVertexData.expand(sizeof(RandomParticleVertexData) * KRENGINE_MAX_RANDOM_PARTICLES * 3);
m_randomParticleVertexData.lock();
RandomParticleVertexData* vertex_data = (RandomParticleVertexData*)m_randomParticleVertexData.getStart();
// Generate vertices for randomly placed equilateral triangles with a side length of 1 and an origin point centered so that an inscribed circle can be efficiently rendered without wasting fill
float equilateral_triangle_height = sqrt(3.0f) * 0.5f;
float inscribed_circle_radius = 1.0f / (2.0f * sqrt(3.0f));
int iVertex = 0;
for (int iParticle = 0; iParticle < KRENGINE_MAX_RANDOM_PARTICLES; iParticle++) {
vertex_data[iVertex].vertex.x = (float)(rand() % 2000) / 1000.0f - 1000.0f;
vertex_data[iVertex].vertex.y = (float)(rand() % 2000) / 1000.0f - 1000.0f;
vertex_data[iVertex].vertex.z = (float)(rand() % 2000) / 1000.0f - 1000.0f;
vertex_data[iVertex].uva.x = -0.5f;
vertex_data[iVertex].uva.y = -inscribed_circle_radius;
iVertex++;
vertex_data[iVertex].vertex.x = vertex_data[iVertex - 1].vertex.x;
vertex_data[iVertex].vertex.y = vertex_data[iVertex - 1].vertex.y;
vertex_data[iVertex].vertex.z = vertex_data[iVertex - 1].vertex.z;
vertex_data[iVertex].uva.x = 0.5f;
vertex_data[iVertex].uva.y = -inscribed_circle_radius;
iVertex++;
vertex_data[iVertex].vertex.x = vertex_data[iVertex - 1].vertex.x;
vertex_data[iVertex].vertex.y = vertex_data[iVertex - 1].vertex.y;
vertex_data[iVertex].vertex.z = vertex_data[iVertex - 1].vertex.z;
vertex_data[iVertex].uva.x = 0.0f;
vertex_data[iVertex].uva.y = -inscribed_circle_radius + equilateral_triangle_height;
iVertex++;
}
KRENGINE_VBO_DATA_RANDOM_PARTICLES.init(this, &m_randomParticleVertexData, nullptr, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA), false, KRVBOData::CONSTANT
#if KRENGINE_DEBUG_GPU_LABELS
, "Random Particles [built-in]"
#endif
);
m_randomParticleVertexData.unlock();
}
}
long KRMeshManager::getMemoryTransferedThisFrame()
{
return m_memoryTransferredThisFrame;
}
size_t KRMeshManager::getActiveVBOCount()
{
return m_vbosActive.size();
}
void KRMeshManager::log_draw_call(RenderPassType pass, const std::string& object_name, const std::string& material_name, int vertex_count)
{
if (m_draw_call_logging_enabled) {
draw_call_info info;
info.pass = pass;
strncpy(info.object_name, object_name.c_str(), 256);
strncpy(info.material_name, material_name.c_str(), 256);
info.vertex_count = vertex_count;
m_draw_calls.push_back(info);
}
}
std::vector<KRMeshManager::draw_call_info> KRMeshManager::getDrawCalls()
{
m_draw_call_log_used = true;
return m_draw_calls;
}
KRMeshManager::KRVBOData::KRVBOData()
{
m_debugLabel[0] = '\0';
m_is_vbo_loaded = false;
m_is_vbo_ready = false;
m_manager = NULL;
m_type = STREAMING;
m_data = NULL;
m_index_data = NULL;
m_vertex_attrib_flags = 0;
m_size = 0;
m_last_frame_used = 0;
m_last_frame_max_lod_coverage = 0.0f;
memset(m_allocations, 0, sizeof(AllocationInfo) * KRENGINE_MAX_GPU_COUNT);
}
KRMeshManager::KRVBOData::KRVBOData(KRMeshManager* manager, Block* data, Block* index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t
#if KRENGINE_DEBUG_GPU_LABELS
, const char* debug_label
#endif
)
{
m_debugLabel[0] = '\0';
memset(m_allocations, 0, sizeof(AllocationInfo) * KRENGINE_MAX_GPU_COUNT);
m_is_vbo_loaded = false;
m_is_vbo_ready = false;
init(manager, data, index_data, vertex_attrib_flags, static_vbo, t
#if KRENGINE_DEBUG_GPU_LABELS
, debug_label
#endif
);
}
void KRMeshManager::KRVBOData::init(KRMeshManager* manager, Block* data, Block* index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t
#if KRENGINE_DEBUG_GPU_LABELS
, const char* debug_label
#endif
)
{
#if KRENGINE_DEBUG_GPU_LABELS
snprintf(m_debugLabel, KRENGINE_DEBUG_GPU_LABEL_MAX_LEN, debug_label);
#endif //KRENGINE_DEBUG_GPU_LABELS
m_manager = manager;
m_type = t;
m_static_vbo = static_vbo;
m_data = data;
m_index_data = index_data;
m_vertex_attrib_flags = vertex_attrib_flags;
m_size = m_data->getSize();
if (m_index_data != NULL) {
m_size += m_index_data->getSize();
}
if (t == KRVBOData::CONSTANT) {
m_manager->primeVBO(this);
}
}
KRMeshManager::KRVBOData::~KRVBOData()
{
// TODO - This needs to be done by the streamer thread, and asserted here...
unload();
}
void KRMeshManager::KRVBOData::load()
{
// TODO - This is a bit messy. Clean up after Vulkan refactor.
VkCommandBuffer noCommandBuffer = VK_NULL_HANDLE;
load(noCommandBuffer);
}
void KRMeshManager::KRVBOData::load(VkCommandBuffer& commandBuffer)
{
// TODO - We should load on each GPU only if there is a surface using the mesh
if (isVBOLoaded()) {
return;
}
KRDeviceManager* deviceManager = m_manager->getContext().getDeviceManager();
int iAllocation = 0;
for (auto deviceItr = deviceManager->getDevices().begin(); deviceItr != deviceManager->getDevices().end() && iAllocation < KRENGINE_MAX_GPU_COUNT; deviceItr++, iAllocation++) {
KRDevice& device = *(*deviceItr).second;
KrDeviceHandle deviceHandle = (*deviceItr).first;
VmaAllocator allocator = device.getAllocator();
AllocationInfo& allocation = m_allocations[iAllocation];
allocation.device = deviceHandle;
#if KRENGINE_DEBUG_GPU_LABELS
char debug_label[KRENGINE_DEBUG_GPU_LABEL_MAX_LEN];
const char* type_label = "";
switch (m_type) {
case vbo_type::STREAMING:
type_label = "Streaming";
break;
case vbo_type::CONSTANT:
type_label = "Constant";
break;
case vbo_type::IMMEDIATE:
type_label = "Immediate";
break;
default:
assert(false);
}
snprintf(debug_label, KRENGINE_DEBUG_GPU_LABEL_MAX_LEN, "%s Vertices: %s", type_label, m_debugLabel);
#endif // KRENGINE_DEBUG_GPU_LABELS
device.createBuffer(
m_data->getSize(),
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
&allocation.vertex_buffer,
&allocation.vertex_allocation
#if KRENGINE_DEBUG_GPU_LABELS
, debug_label
#endif // KRENGINE_DEBUG_GPU_LABELS
);
if (m_type == vbo_type::IMMEDIATE) {
device.graphicsUpload(commandBuffer, *m_data, allocation.vertex_buffer);
} else {
device.streamUpload(*m_data, allocation.vertex_buffer);
}
if (m_index_data && m_index_data->getSize() > 0) {
#if KRENGINE_DEBUG_GPU_LABELS
snprintf(debug_label, KRENGINE_DEBUG_GPU_LABEL_MAX_LEN, "%s Indexes: %s", type_label, m_debugLabel);
#endif // KRENGINE_DEBUG_GPU_LABELS
device.createBuffer(
m_index_data->getSize(),
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
&allocation.index_buffer,
&allocation.index_allocation
#if KRENGINE_DEBUG_GPU_LABELS
, debug_label
#endif
);
if (m_type == vbo_type::IMMEDIATE) {
device.graphicsUpload(commandBuffer, *m_index_data, allocation.index_buffer);
} else {
device.streamUpload(*m_index_data, allocation.index_buffer);
}
}
}
m_is_vbo_loaded = true;
m_manager->m_vboMemUsed += getSize();
m_manager->m_memoryTransferredThisFrame += getSize();
if (m_type != STREAMING) {
_swapHandles();
}
}
void KRMeshManager::KRVBOData::unload()
{
KRDeviceManager* deviceManager = m_manager->getContext().getDeviceManager();
for (int i = 0; i < KRENGINE_MAX_GPU_COUNT; i++) {
AllocationInfo& allocation = m_allocations[i];
if (allocation.device) {
std::unique_ptr<KRDevice>& device = deviceManager->getDevice(allocation.device);
if (device) {
VmaAllocator allocator = device->getAllocator();
vmaDestroyBuffer(allocator, allocation.vertex_buffer, allocation.vertex_allocation);
if (allocation.index_buffer) {
vmaDestroyBuffer(allocator, allocation.index_buffer, allocation.index_allocation);
}
}
}
memset(&allocation, 0, sizeof(AllocationInfo));
}
if (isVBOLoaded()) {
m_manager->m_vboMemUsed -= getSize();
}
m_is_vbo_loaded = false;
m_is_vbo_ready = false;
}
void KRMeshManager::KRVBOData::bind(VkCommandBuffer& commandBuffer)
{
VkBuffer vertexBuffers[] = { getVertexBuffer() };
VkDeviceSize offsets[] = { 0 };
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
if (m_index_data && m_index_data->getSize() > 0) {
// TODO - Support 32-bit index buffers
vkCmdBindIndexBuffer(commandBuffer, getIndexBuffer(), 0, VK_INDEX_TYPE_UINT16);
}
}
void KRMeshManager::KRVBOData::resetPoolExpiry(float lodCoverage)
{
long current_frame = m_manager->getContext().getCurrentFrame();
if (current_frame != m_last_frame_used) {
m_last_frame_used = current_frame;
m_last_frame_max_lod_coverage = 0.0f;
m_manager->primeVBO(this);
}
m_last_frame_max_lod_coverage = KRMAX(lodCoverage, m_last_frame_max_lod_coverage);
}
float KRMeshManager::KRVBOData::getStreamPriority()
{
long current_frame = m_manager->getContext().getCurrentFrame();
if (current_frame > m_last_frame_used + 5) {
return 1.0f - KRCLAMP((float)(current_frame - m_last_frame_used) / 60.0f, 0.0f, 1.0f);
} else {
return 10000.0f + m_last_frame_max_lod_coverage * 10.0f;
}
}
void KRMeshManager::KRVBOData::_swapHandles()
{
m_is_vbo_ready = m_is_vbo_loaded;
}
void KRMeshManager::primeVBO(KRVBOData* vbo_data)
{
if (m_vbosActive.find(vbo_data->m_data) == m_vbosActive.end()) {
m_vbosActive[vbo_data->m_data] = vbo_data;
}
}
VkBuffer& KRMeshManager::KRVBOData::getVertexBuffer()
{
assert(m_is_vbo_ready);
return m_allocations->vertex_buffer;
}
VkBuffer& KRMeshManager::KRVBOData::getIndexBuffer()
{
assert(m_is_vbo_ready);
return m_allocations->index_buffer;
}
uint32_t KRMeshManager::KRVBOData::getVertexAttributes()
{
return m_vertex_attrib_flags;
}

View File

@@ -0,0 +1,248 @@
//
// KRMeshManager.h
// Kraken Engine
//
// Copyright 2024 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#pragma once
#include "KREngine-common.h"
#include "resources/KRResourceManager.h"
#include "KRContextObject.h"
#include "block.h"
#include "KRNode.h"
class KRContext;
class KRMesh;
enum RenderPassType : uint8_t;
class KRMeshManager : public KRResourceManager
{
public:
static const int KRENGINE_MAX_VOLUMETRIC_PLANES = 500;
static const int KRENGINE_MAX_RANDOM_PARTICLES = 150000;
KRMeshManager(KRContext& context);
void init();
virtual ~KRMeshManager();
virtual KRResource* loadResource(const std::string& name, const std::string& extension, mimir::Block* data) override;
virtual KRResource* getResource(const std::string& name, const std::string& extension) override;
void startFrame(float deltaTime);
void endFrame(float deltaTime);
KRMesh* loadModel(const char* szName, mimir::Block* pData);
std::vector<KRMesh*> getModel(const char* szName);
KRMesh* getMaxLODModel(const char* szName);
void addModel(KRMesh* model);
std::vector<std::string> getModelNames();
unordered_multimap<std::string, KRMesh*>& getModels();
class KRVBOData
{
public:
typedef enum
{
STREAMING,
// STREAMING data is loaded asynchronously, with transfer queues in the streamer thread.
CONSTANT,
// CONSTANT data is loaded asyncrhronously, with transfer queues in the streamer thread, but is not unloaded.
IMMEDIATE
// IMMEDIATE data is loaded synchronously, with graphics queues in the presentation threads.
// IMMEDIATE data is available for use immediately on the same frame it is generated.
} vbo_type;
KRVBOData();
KRVBOData(KRMeshManager* manager, mimir::Block* data, mimir::Block* index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t
#if KRENGINE_DEBUG_GPU_LABELS
, const char* debug_label
#endif
);
void init(KRMeshManager* manager, mimir::Block* data, mimir::Block* index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t
#if KRENGINE_DEBUG_GPU_LABELS
, const char* debug_label
#endif
);
~KRVBOData();
mimir::Block* m_data;
mimir::Block* m_index_data;
bool isVBOLoaded()
{
return m_is_vbo_loaded;
}
bool isVBOReady() const
{
return m_is_vbo_ready;
}
void load();
void load(VkCommandBuffer& commandBuffer);
void unload();
void bind(VkCommandBuffer& commandBuffer);
// KRMeshManager depends on the address of KRVBOData's being constant
// after allocation. This is enforced by deleted copy constructors.
KRVBOData(const KRVBOData& o) = delete;
KRVBOData& operator=(const KRVBOData& o) = delete;
long getSize()
{
return (long)m_size;
}
void resetPoolExpiry(float lodCoverage);
long getLastFrameUsed()
{
return m_last_frame_used;
}
vbo_type getType()
{
return m_type;
}
float getStreamPriority();
void _swapHandles();
VkBuffer& getVertexBuffer();
VkBuffer& getIndexBuffer();
uint32_t getVertexAttributes();
private:
KRMeshManager* m_manager;
int m_vertex_attrib_flags;
long m_size;
long m_last_frame_used;
float m_last_frame_max_lod_coverage;
vbo_type m_type;
bool m_static_vbo;
bool m_is_vbo_loaded;
bool m_is_vbo_ready;
typedef struct
{
KrDeviceHandle device;
VkBuffer vertex_buffer;
VmaAllocation vertex_allocation;
VkBuffer index_buffer;
VmaAllocation index_allocation;
} AllocationInfo;
AllocationInfo m_allocations[KRENGINE_MAX_GPU_COUNT];
#if KRENGINE_DEBUG_GPU_LABELS
char m_debugLabel[KRENGINE_DEBUG_GPU_LABEL_MAX_LEN];
#endif
};
void bindVBO(VkCommandBuffer& commandBuffer, KRVBOData* vbo_data, float lodCoverage);
long getMemUsed();
long getMemActive();
typedef struct
{
hydra::Vector3 vertex;
hydra::Vector2 uva;
} RandomParticleVertexData;
typedef struct
{
hydra::Vector3 vertex;
} VolumetricLightingVertexData;
long getMemoryTransferedThisFrame();
size_t getActiveVBOCount();
struct draw_call_info
{
RenderPassType pass;
char object_name[256];
char material_name[256];
int vertex_count;
};
void log_draw_call(RenderPassType pass, const std::string& object_name, const std::string& material_name, int vertex_count);
std::vector<draw_call_info> getDrawCalls();
KRVBOData KRENGINE_VBO_DATA_3D_CUBE_VERTICES;
KRVBOData KRENGINE_VBO_DATA_2D_SQUARE_VERTICES;
KRVBOData KRENGINE_VBO_DATA_RANDOM_PARTICLES;
KRVBOData KRENGINE_VBO_DATA_VOLUMETRIC_LIGHTING;
void doStreaming(long& memoryRemaining, long& memoryRemainingThisFrame);
private:
mimir::Block KRENGINE_VBO_3D_CUBE_VERTICES;
__int32_t KRENGINE_VBO_3D_CUBE_ATTRIBS;
mimir::Block KRENGINE_VBO_2D_SQUARE_VERTICES;
__int32_t KRENGINE_VBO_2D_SQUARE_ATTRIBS;
unordered_multimap<std::string, KRMesh*> m_models; // Multiple models with the same name/key may be inserted, representing multiple LOD levels of the model
long m_vboMemUsed;
KRVBOData* m_currentVBO;
unordered_map<mimir::Block*, KRVBOData*> m_vbosActive;
std::vector<std::pair<float, KRVBOData*> > m_activeVBOs_streamer;
std::vector<std::pair<float, KRVBOData*> > m_activeVBOs_streamer_copy;
mimir::Block m_randomParticleVertexData;
mimir::Block m_volumetricLightingVertexData;
long m_memoryTransferredThisFrame;
std::vector<draw_call_info> m_draw_calls;
bool m_draw_call_logging_enabled;
bool m_draw_call_log_used;
std::mutex m_streamerFenceMutex;
bool m_streamerComplete;
void balanceVBOMemory(long& memoryRemaining, long& memoryRemainingThisFrame);
void primeVBO(KRVBOData* vbo_data);
void initRandomParticles();
void initVolumetricLightingVertexes();
};

View File

@@ -0,0 +1,64 @@
//
// KRMeshQuad.cpp
// Kraken Engine
//
// Copyright 2024 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#include "KRMeshQuad.h"
using namespace hydra;
KRMeshQuad::KRMeshQuad(KRContext& context) : KRMesh(context, "__quad")
{
m_constant = true;
KRMesh::mesh_info mi;
mi.vertices.push_back(Vector3::Create(-1.0f, -1.0f, 0.0f));
mi.vertices.push_back(Vector3::Create(1.0f, -1.0f, 0.0f));
mi.vertices.push_back(Vector3::Create(-1.0f, 1.0f, 0.0f));
mi.vertices.push_back(Vector3::Create(1.0f, 1.0f, 0.0f));
mi.uva.push_back(Vector2::Create(0.0f, 0.0f));
mi.uva.push_back(Vector2::Create(1.0f, 0.0f));
mi.uva.push_back(Vector2::Create(0.0f, 1.0f));
mi.uva.push_back(Vector2::Create(1.0f, 1.0f));
mi.submesh_starts.push_back(0);
mi.submesh_lengths.push_back((int)mi.vertices.size());
mi.material_names.push_back("");
mi.format = ModelFormat::KRENGINE_MODEL_FORMAT_STRIP;
LoadData(mi, true, true);
}
KRMeshQuad::~KRMeshQuad()
{
}

View File

@@ -0,0 +1,42 @@
//
// KRMeshQuad.h
// Kraken Engine
//
// Copyright 2024 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#pragma once
#include "KRMesh.h"
class KRMeshQuad : public KRMesh
{
public:
KRMeshQuad(KRContext& context);
virtual ~KRMeshQuad();
private:
};

View File

@@ -0,0 +1,129 @@
//
// KRMeshSphere.cpp
// Kraken Engine
//
// Copyright 2024 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#include "KRMeshSphere.h"
using namespace hydra;
KRMeshSphere::KRMeshSphere(KRContext& context) : KRMesh(context, "__sphere")
{
m_constant = true;
KRMesh::mesh_info mi;
// Create a triangular facet approximation to a sphere
// Based on algorithm from Paul Bourke: http://paulbourke.net/miscellaneous/sphere_cylinder/
int iterations = 3;
int facet_count = (int)(pow(4, iterations) * 8.0f);
std::vector<Triangle3> f = std::vector<Triangle3>(facet_count);
int i, it;
float a;
Vector3 p[6] = {
Vector3::Create(0,0,1),
Vector3::Create(0,0,-1),
Vector3::Create(-1,-1,0),
Vector3::Create(1,-1,0),
Vector3::Create(1,1,0),
Vector3::Create(-1,1,0)
};
Vector3 pa, pb, pc;
int nt = 0, ntold;
/* Create the level 0 object */
a = 1.0f / sqrtf(2.0f);
for (i = 0; i < 6; i++) {
p[i].x *= a;
p[i].y *= a;
}
f[0][0] = p[0]; f[0][1] = p[3]; f[0][2] = p[4];
f[1][0] = p[0]; f[1][1] = p[4]; f[1][2] = p[5];
f[2][0] = p[0]; f[2][1] = p[5]; f[2][2] = p[2];
f[3][0] = p[0]; f[3][1] = p[2]; f[3][2] = p[3];
f[4][0] = p[1]; f[4][1] = p[4]; f[4][2] = p[3];
f[5][0] = p[1]; f[5][1] = p[5]; f[5][2] = p[4];
f[6][0] = p[1]; f[6][1] = p[2]; f[6][2] = p[5];
f[7][0] = p[1]; f[7][1] = p[3]; f[7][2] = p[2];
nt = 8;
/* Bisect each edge and move to the surface of a unit sphere */
for (it = 0; it < iterations; it++) {
ntold = nt;
for (i = 0; i < ntold; i++) {
pa.x = (f[i][0].x + f[i][1].x) / 2;
pa.y = (f[i][0].y + f[i][1].y) / 2;
pa.z = (f[i][0].z + f[i][1].z) / 2;
pb.x = (f[i][1].x + f[i][2].x) / 2;
pb.y = (f[i][1].y + f[i][2].y) / 2;
pb.z = (f[i][1].z + f[i][2].z) / 2;
pc.x = (f[i][2].x + f[i][0].x) / 2;
pc.y = (f[i][2].y + f[i][0].y) / 2;
pc.z = (f[i][2].z + f[i][0].z) / 2;
pa.normalize();
pb.normalize();
pc.normalize();
f[nt][0] = f[i][0]; f[nt][1] = pa; f[nt][2] = pc; nt++;
f[nt][0] = pa; f[nt][1] = f[i][1]; f[nt][2] = pb; nt++;
f[nt][0] = pb; f[nt][1] = f[i][2]; f[nt][2] = pc; nt++;
f[i][0] = pa;
f[i][1] = pb;
f[i][2] = pc;
}
}
for (int facet_index = 0; facet_index < facet_count; facet_index++) {
mi.vertices.push_back(f[facet_index][0]);
mi.vertices.push_back(f[facet_index][1]);
mi.vertices.push_back(f[facet_index][2]);
}
mi.submesh_starts.push_back(0);
mi.submesh_lengths.push_back((int)mi.vertices.size());
mi.material_names.push_back("");
mi.format = ModelFormat::KRENGINE_MODEL_FORMAT_TRIANGLES;
// Generate normals pointing away from center of sphere.
for (int vertex_index = 0; vertex_index < mi.vertices.size(); vertex_index++) {
mi.normals.push_back(Vector3::Normalize(mi.vertices[vertex_index] - Vector3::Zero()));
}
LoadData(mi, true, true);
}
KRMeshSphere::~KRMeshSphere()
{
}

View File

@@ -0,0 +1,42 @@
//
// KRMeshSphere.h
// Kraken Engine
//
// Copyright 2024 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#pragma once
#include "KRMesh.h"
class KRMeshSphere : public KRMesh
{
public:
KRMeshSphere(KRContext& context);
virtual ~KRMeshSphere();
private:
};