summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--assets/shaders/glyph.frag24
-rw-r--r--assets/shaders/glyph.vert32
-rw-r--r--assets/shaders/present.vert8
-rw-r--r--assets/shaders/vertex.vert22
-rw-r--r--config.mk2
-rw-r--r--editor/editor.cpp156
-rw-r--r--src/asset-manager.cpp4
-rw-r--r--src/asset-manager.hpp2
-rw-r--r--src/components.hpp5
-rw-r--r--src/ecs.cpp2
-rw-r--r--src/entities.cpp72
-rw-r--r--src/font.cpp638
-rw-r--r--src/font.hpp74
-rw-r--r--src/static-plane.cpp21
-rw-r--r--src/static-plane.hpp15
-rw-r--r--src/window.cpp97
-rw-r--r--src/window.hpp24
18 files changed, 1098 insertions, 110 deletions
diff --git a/Makefile b/Makefile
index f35e108..402d699 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ define cxx-dbg-command
endef
FLG_PKE = -Isub/imgui -Isub/stb -Isub/cgltf -Isub/bullet3/src
-FLG_EDT = $(FLG_PKE) -Isrc
+FLG_EDT = $(FLG_PKE) -Isrc -I/home/pikum/build/msdfgen -I/home/pikum/build/msdf-atlas-gen
FLG_MPL = $(FLG_PKE) -Isrc
FLG_RUN = $(FLG_PKE) -Isrc
@@ -34,6 +34,7 @@ SRC = \
src/ecs.cpp \
src/entities.cpp \
src/event.cpp \
+ src/font.cpp \
src/game.cpp \
src/game-settings.cpp \
src/helpers.cpp \
@@ -48,6 +49,7 @@ SRC = \
src/project.cpp \
src/project-settings.cpp \
src/static-cube.cpp \
+ src/static-plane.cpp \
src/thread-pool.cpp \
src/vendor-cgltf-include.cpp \
src/vendor-stb-image-include.c \
@@ -59,6 +61,8 @@ DST_SHADERS = \
$(DIR_OBJ)/shaders/present.vert.spv \
$(DIR_OBJ)/shaders/texture.frag.spv \
$(DIR_OBJ)/shaders/present.frag.spv \
+ $(DIR_OBJ)/shaders/glyph.vert.spv \
+ $(DIR_OBJ)/shaders/glyph.frag.spv \
SRC_C = $(filter %.c,$(SRC))
SRC_CXX = $(filter %.cpp,$(SRC))
@@ -208,12 +212,12 @@ $(DIR_DBG)/libpke-example.a: $(DIR_OBJ)/example.so
$(DIR_BIN)/pke-editor: $(DIR_BIN)/libpke.a $(DIR_BIN)/libImgui.a $(DIR_BIN)/libBullet3.a
$(DIR_BIN)/pke-editor: $(DIR_OBJ)/editor-main.o $(DIR_OBJ)/editor.o
- $(CXX) -v -std=c++23 $(INCS) $^ $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@
+ $(CXX) -v -std=c++23 $(INCS) /home/pikum/build/msdfgen/dbg/msdfgen.a /home/pikum/build/msdf-atlas-gen/dbg/msdf-atlas-gen.a $^ $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@
$(DIR_DBG)/pke-editor: $(DIR_DBG)/libpke.a $(DIR_DBG)/libImgui.a $(DIR_DBG)/libBullet3.a
$(DIR_DBG)/pke-editor: $(DIR_OBJ)/editor-main.so $(DIR_OBJ)/editor.so
@echo $^
- $(CXX) -v -std=c++23 $(INCS) $^ $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@
+ $(CXX) -v -std=c++23 $(INCS) $^ /home/pikum/build/msdf-atlas-gen/dbg/msdf-atlas-gen.a /home/pikum/build/msdfgen/dbg/msdfgen.a $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@
$(DIR_BIN)/pke-runtime: $(DIR_BIN)/libpke.a $(DIR_BIN)/libImgui.a $(DIR_BIN)/libBullet3.a
$(DIR_BIN)/pke-runtime: $(DIR_OBJ)/runtime.o
diff --git a/assets/shaders/glyph.frag b/assets/shaders/glyph.frag
new file mode 100644
index 0000000..90186a3
--- /dev/null
+++ b/assets/shaders/glyph.frag
@@ -0,0 +1,24 @@
+# version 450
+
+layout(location = 0) in vec4 in_fg_color;
+layout(location = 1) in vec4 in_bg_color;
+layout(location = 2) in vec4 in_sprite_region;
+layout(location = 3) in vec2 in_uv;
+layout(location = 4) in float in_width;
+
+layout(location = 0) out vec4 out_color;
+
+layout(binding = 1) uniform sampler2D mtsdfSampler;
+
+float median(float r, float g, float b) {
+ return max(min(r, g), min(max(r, g), b));
+}
+
+void main() {
+ vec2 atlas_coord = (in_uv - in_sprite_region.xy) / in_sprite_region.zw;
+ vec4 msd = texture(mtsdfSampler, atlas_coord);
+ float sd = median(msd.r, msd.g, msd.b);
+ float screenPxDistance = in_width * (sd - 0.5);
+ float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
+ out_color = mix(in_bg_color, in_fg_color, opacity);
+}
diff --git a/assets/shaders/glyph.vert b/assets/shaders/glyph.vert
new file mode 100644
index 0000000..52981c2
--- /dev/null
+++ b/assets/shaders/glyph.vert
@@ -0,0 +1,32 @@
+#version 450
+
+// vertex
+layout(location = 0) in vec2 in_position;
+layout(location = 1) in vec2 in_uv;
+
+// instance
+layout(location = 2) in vec4 in_fg_color;
+layout(location = 3) in vec4 in_bg_color;
+layout(location = 4) in vec4 in_sprite_region;
+layout(location = 5) in float in_width;
+
+layout(location = 0) out vec4 out_fg_color;
+layout(location = 1) out vec4 out_bg_color;
+layout(location = 2) out vec4 out_sprite_region;
+layout(location = 3) out vec2 out_uv;
+layout(location = 4) out float out_width;
+
+out gl_PerVertex
+{
+ vec4 gl_Position;
+};
+
+void main()
+{
+ gl_Position = vec4(in_position, 0.0, 1.0);
+ out_fg_color = in_fg_color;
+ out_bg_color = in_bg_color;
+ out_sprite_region = in_sprite_region;
+ out_uv = in_uv;
+ out_width = in_width;
+}
diff --git a/assets/shaders/present.vert b/assets/shaders/present.vert
index 5423fcf..a5d60d0 100644
--- a/assets/shaders/present.vert
+++ b/assets/shaders/present.vert
@@ -4,11 +4,11 @@ layout (location = 0) out vec2 outUV;
out gl_PerVertex
{
- vec4 gl_Position;
+ vec4 gl_Position;
};
void main()
{
- outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
- gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f);
-} \ No newline at end of file
+ outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
+ gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f);
+}
diff --git a/assets/shaders/vertex.vert b/assets/shaders/vertex.vert
index 57fa219..8b2c133 100644
--- a/assets/shaders/vertex.vert
+++ b/assets/shaders/vertex.vert
@@ -1,9 +1,9 @@
#version 450
layout(binding = 0) uniform UniformBufferObject {
- mat4 model;
- mat4 view;
- mat4 proj;
+ mat4 model;
+ mat4 view;
+ mat4 proj;
} ubo;
// vertex
@@ -20,12 +20,12 @@ layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec3 fragTexCoord;
void main() {
- gl_Position =
- ubo.proj *
- ubo.view *
- ubo.model *
- instPosRotScale *
- vec4(inPosition, 1.0);
- fragColor = vec4(0.0, 0.0, 0.0, 0.0);
- fragTexCoord = vec3(inUV, 0);
+ gl_Position =
+ ubo.proj *
+ ubo.view *
+ ubo.model *
+ instPosRotScale *
+ vec4(inPosition, 1.0);
+ fragColor = vec4(0.0, 0.0, 0.0, 0.0);
+ fragTexCoord = vec3(inUV, 0);
}
diff --git a/config.mk b/config.mk
index a2b93ce..87c5b22 100644
--- a/config.mk
+++ b/config.mk
@@ -15,6 +15,8 @@ USED_LIBS = \
vulkan \
glfw3 \
glm \
+ freetype2 \
+ libpng \
INCS = `$(PKG_CONFIG) --cflags $(USED_LIBS)`
diff --git a/editor/editor.cpp b/editor/editor.cpp
index a15c838..9f6b492 100644
--- a/editor/editor.cpp
+++ b/editor/editor.cpp
@@ -3,14 +3,20 @@
#include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h"
#include "array.hpp"
+#include "asset-manager.hpp"
#include "camera.hpp"
#include "ecs.hpp"
#include "entities.hpp"
+#include "font.hpp"
#include "game-settings.hpp"
#include "game.hpp"
#include "imgui.h"
#include "level.hpp"
#include "math-helpers.hpp"
+#include "msdf-atlas-gen/GlyphGeometry.h"
+#include "msdf-atlas-gen/glyph-generators.h"
+#include "msdf-atlas-gen/image-save.h"
+#include "msdf-atlas-gen/types.h"
#include "player-input.hpp"
#include "plugins.hpp"
#include "project.hpp"
@@ -19,11 +25,14 @@
#include "vendor-tinyfiledialogs.h"
#include "window.hpp"
#include "pk.h"
+#include "msdf-atlas-gen/msdf-atlas-gen.h"
#include <GLFW/glfw3.h>
#include <compare>
+#include <cstdio>
#include <filesystem>
#include <future>
+#include <glm/fwd.hpp>
#include <regex>
#ifdef WIN32
@@ -230,7 +239,7 @@ void PkeEditor_Tick(double delta) {
if (focusedInst != nullptr) {
const auto *grBinds = ECS_GetGrBinds(focusedInst->grBindsHandle);
if (grBinds != nullptr) {
- pkeDebugHitbox.instanceBuffer = grBinds->instanceBuffer;
+ pkeDebugHitbox.instanceBuffer = grBinds->instanceBD.buffer;
pkeDebugHitbox.instanceStartingIndex = focusedInst->index;
found = true;
}
@@ -706,6 +715,140 @@ void RecordImGuiEntityTypes() {
ImGui::End();
}
+void GenerateMTSDF(const Asset *a) {
+ std::error_code e;
+ std::filesystem::create_directory("./cache", e);
+ if (msdfgen::FreetypeHandle *ft = msdfgen::initializeFreetype()) {
+ // Load font file
+ if (msdfgen::FontHandle *font = msdfgen::loadFont(ft, a->basePath)) {
+ // Storage for glyph geometry and their coordinates in the atlas
+ std::vector<msdf_atlas::GlyphGeometry> glyphs;
+ // FontGeometry is a helper class that loads a set of glyphs from a single font.
+ // It can also be used to get additional font metrics, kerning information, etc.
+ msdf_atlas::FontGeometry fontGeometry(&glyphs);
+ // Load a set of character glyphs:
+ // The second argument can be ignored unless you mix different font sizes in one atlas.
+ // In the last argument, you can specify a charset other than ASCII.
+ // To load specific glyph indices, use loadGlyphs instead.
+ fontGeometry.loadCharset(font, 1.0, msdf_atlas::Charset::ASCII);
+ // Apply MSDF edge coloring. See edge-coloring.h for other coloring strategies.
+ const double maxCornerAngle = 3.0;
+ for (msdf_atlas::GlyphGeometry &glyph : glyphs)
+ glyph.edgeColoring(&msdfgen::edgeColoringInkTrap, maxCornerAngle, 0);
+ // TightAtlasPacker class computes the layout of the atlas.
+ msdf_atlas::TightAtlasPacker packer;
+ // Set atlas parameters:
+ // setDimensions or setDimensionsConstraint to find the best value
+ packer.setDimensionsConstraint(msdf_atlas::DimensionsConstraint::SQUARE);
+ // setScale for a fixed size or setMinimumScale to use the largest that fits
+ packer.setMinimumScale(24.0);
+ // setPixelRange or setUnitRange
+ packer.setPixelRange(2.0);
+ packer.setMiterLimit(1.0);
+ // Compute atlas layout - pack glyphs
+ packer.pack(glyphs.data(), glyphs.size());
+ // Get final atlas dimensions
+ int width = 0, height = 0;
+ packer.getDimensions(width, height);
+ // The ImmediateAtlasGenerator class facilitates the generation of the atlas bitmap.
+ msdf_atlas::ImmediateAtlasGenerator<
+ float, // pixel type of buffer for individual glyphs depends on generator function
+ 4, // number of atlas color channels
+ &msdf_atlas::mtsdfGenerator, // function to generate bitmaps for individual glyphs
+ msdf_atlas::BitmapAtlasStorage<float, 4> // class that stores the atlas bitmap
+ // For example, a custom atlas storage class that stores it in VRAM can be used.
+ > generator(width, height);
+ // GeneratorAttributes can be modified to change the generator's default settings.
+ msdf_atlas::GeneratorAttributes attributes;
+ generator.setAttributes(attributes);
+ // generator.setThreadCount(4);
+ // Generate atlas bitmap
+ generator.generate(glyphs.data(), glyphs.size());
+ // The atlas bitmap can now be retrieved via atlasStorage as a BitmapConstRef.
+ // The glyphs array (or fontGeometry) contains positioning data for typesetting text.
+ msdf_atlas::BitmapAtlasStorage<float, 4> storage = generator.atlasStorage();
+ msdf_atlas::saveImage<4>(storage, msdf_atlas::ImageFormat::PNG, "cache/test-font.png", msdf_atlas::YDirection::TOP_DOWN);
+
+ auto f = fopen("cache/test-font.glyphs", "w");
+ pk_arr arr_glyphs = {};
+ arr_glyphs.alignment = 8;
+ arr_glyphs.stride = sizeof(FontGlyphChar);
+ pk_arr_resize(&arr_glyphs, glyphs.size());
+ FontGlyphChar *arr = reinterpret_cast<FontGlyphChar *>(arr_glyphs.data);
+ for (uint64_t i = 0; i < glyphs.size(); ++i) {
+ arr[i].unicode = glyphs[i].getCodepoint();
+ glyphs[i].getBoxRect(arr[i].bounds.x, arr[i].bounds.y, arr[i].bounds.z, arr[i].bounds.a);
+ }
+
+ fwrite(glyphs.data(), sizeof(msdf_atlas::GlyphGeometry) * glyphs.size(), 1, f);
+ fclose(f);
+ // _ = myProject::submitAtlasBitmapAndLayout(generator.atlasStorage(), glyphs);
+ // Cleanup
+ msdfgen::destroyFont(font);
+ }
+ msdfgen::deinitializeFreetype(ft);
+ }
+}
+
+void RecordImGuiAssets() {
+ if (!ImGui::Begin("AssetList")) {
+ ImGui::End();
+ return;
+ }
+
+ static ImGuiTableFlags tableFlags{
+ ImGuiTableFlags_Borders |
+ ImGuiTableFlags_RowBg
+ };
+ if (ImGui::BeginTable("Assets", 7, tableFlags)) {
+ ImGui::TableSetupColumn("Controls");
+ ImGui::TableSetupColumn("Type");
+ ImGui::TableSetupColumn("Handle");
+ ImGui::TableSetupColumn("Key");
+ ImGui::TableSetupColumn("Data");
+ ImGui::TableSetupColumn("Size");
+ ImGui::TableSetupColumn("Ref Count");
+ ImGui::TableHeadersRow();
+
+ pk_handle_bucket_index_T asset_bucket_count = AM_GetBucketCount();
+ for (pk_handle_bucket_index_T b = 0; b < asset_bucket_count; ++b) {
+ pk_handle_item_index_T count;
+ auto *assets = AM_GetAssets(b, count);
+ ImGui::PushID(b);
+ for (pk_handle_item_index_T i = 0; i < count; ++i) {
+ const auto &asset = assets[i];
+ if (asset.handle == EntityHandle_MAX)
+ continue;
+ ImGui::PushID(i);
+ ImGui::TableNextRow();
+ ImGui::TableSetColumnIndex(0);
+ if ((asset.type & PKE_ASSET_TYPE_FONT) != PKE_ASSET_TYPE_UNSET) {
+ if (ImGui::Button("Create MTSDF")) {
+ GenerateMTSDF(&asset);
+ }
+ }
+ ImGui::TableSetColumnIndex(1);
+ ImGui::Text("%i", (uint8_t)asset.type);
+ ImGui::TableSetColumnIndex(2);
+ ImGui::Text("0x%08X 0x%08X", asset.handle.bucketIndex, asset.handle.itemIndex);
+ ImGui::TableSetColumnIndex(3);
+ ImGui::Text("%.16s", asset.key);
+ ImGui::TableSetColumnIndex(4);
+ ImGui::Text("%p", asset.ptr);
+ ImGui::TableSetColumnIndex(5);
+ ImGui::Text("%li", asset.size);
+ ImGui::TableSetColumnIndex(6);
+ ImGui::Text("%hhi", asset.referenceCount);
+ ImGui::PopID();
+ }
+ ImGui::PopID();
+ }
+ ImGui::EndTable();
+
+ }
+ ImGui::End();
+}
+
void RecordImGuiCameras() {
CompInstance *activeInst = nullptr;
// CompInstance *activeTargetInst = nullptr;
@@ -1044,11 +1187,11 @@ void RecordImGui_CompGrBinds(bool readonly, CompGrBinds *component) {
ImGui::InputScalar("IndexOffsets", ImGuiDataType_U64, &component->indexBD.offsets[0], nullptr, nullptr, nullptr, inputTextFlags);
ImGui::InputScalar("IndexCount", ImGuiDataType_U32, &component->indexCount, nullptr, nullptr, nullptr, inputTextFlags);
- if (component->instanceBuffer)
- ImGui::InputScalar("VkInstanceBuffer", ImGuiDataType_U64, &component->instanceBuffer, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly);
- ImGui::InputScalar("InstanceFirstBinding", ImGuiDataType_U32, &component->instanceFirstBinding, nullptr, nullptr, nullptr, inputTextFlags);
- ImGui::InputScalar("InstanceBindingCount", ImGuiDataType_U32, &component->instanceBindingCount, nullptr, nullptr, nullptr, inputTextFlags);
- ImGui::InputScalar("InstanceOffsets", ImGuiDataType_U64, &component->instanceOffsets, nullptr, nullptr, nullptr, inputTextFlags);
+ if (component->instanceBD.buffer)
+ ImGui::InputScalar("VkInstanceBuffer", ImGuiDataType_U64, &component->instanceBD.buffer, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly);
+ ImGui::InputScalar("InstanceFirstBinding", ImGuiDataType_U32, &component->instanceBD.firstBinding, nullptr, nullptr, nullptr, inputTextFlags);
+ ImGui::InputScalar("InstanceBindingCount", ImGuiDataType_U32, &component->instanceBD.bindingCount, nullptr, nullptr, nullptr, inputTextFlags);
+ ImGui::InputScalar("InstanceOffsets", ImGuiDataType_U64, &component->instanceBD.offsets[0], nullptr, nullptr, nullptr, inputTextFlags);
ImGui::InputScalar("InstanceBufferMaxCount", ImGuiDataType_U32, &component->instanceBufferMaxCount, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly);
ImGui::InputScalar("Instance Count", ImGuiDataType_U32, &component->instanceCounter, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly);
@@ -1366,6 +1509,7 @@ void PkeEditor_RecordImGui() {
RecordImGuiCameras();
RecordImGuiLevels();
RecordImGuiEntityTypes();
+ RecordImGuiAssets();
Game_RecordImGui();
}
}
diff --git a/src/asset-manager.cpp b/src/asset-manager.cpp
index b280361..d12d860 100644
--- a/src/asset-manager.cpp
+++ b/src/asset-manager.cpp
@@ -20,6 +20,8 @@ AssetKey EngineDefinedAssets[EngineDefinedAssetCount] = {
"pke_prsnt_frg\0\0",
"pke_txtr_vrt\0\0\0",
"pke_txtr_frg\0\0\0",
+ "pke_glyph_vrt\0\0",
+ "pke_glyph_frg\0\0",
};
void AM_Init() {
@@ -29,6 +31,8 @@ void AM_Init() {
AM_Register(EngineDefinedAssets[1], PKE_ASSET_TYPE_SHADER, "assets/shaders/present.frag.spv");
AM_Register(EngineDefinedAssets[2], PKE_ASSET_TYPE_SHADER, "assets/shaders/vertex.vert.spv");
AM_Register(EngineDefinedAssets[3], PKE_ASSET_TYPE_SHADER, "assets/shaders/texture.frag.spv");
+ AM_Register(EngineDefinedAssets[4], PKE_ASSET_TYPE_SHADER, "assets/shaders/glyph.vert.spv");
+ AM_Register(EngineDefinedAssets[5], PKE_ASSET_TYPE_SHADER, "assets/shaders/glyph.frag.spv");
}
void AM_Load_Task(Asset &asset) {
diff --git a/src/asset-manager.hpp b/src/asset-manager.hpp
index 0a7cd5c..fb922e9 100644
--- a/src/asset-manager.hpp
+++ b/src/asset-manager.hpp
@@ -29,7 +29,7 @@ const AssetType PKE_ASSET_TYPE_AUDIO = AssetType {0x08};
const AssetType PKE_ASSET_TYPE_FONT = AssetType {0x10};
const AssetType PKE_ASSET_TYPE_ALL = AssetType {0xFF};
-constexpr int64_t EngineDefinedAssetCount = 4;
+constexpr int64_t EngineDefinedAssetCount = 6;
extern AssetKey EngineDefinedAssets[EngineDefinedAssetCount];
struct Asset {
diff --git a/src/components.hpp b/src/components.hpp
index eb891a4..cf86099 100644
--- a/src/components.hpp
+++ b/src/components.hpp
@@ -42,17 +42,14 @@ struct CompGrBinds {
BufferBindingDetails normalsBD;
BufferBindingDetails uvBD;
BufferBindingDetails indexBD;
+ BufferBindingDetails instanceBD;
BufferBindingDetails physVertBD;
BufferBindingDetails physNormBD;
BufferBindingDetails physUvBD;
BufferBindingDetails physIndxBD;
- VkBuffer instanceBuffer = VK_NULL_HANDLE;
uint32_t indexCount;
- uint32_t instanceFirstBinding = 0;
- uint32_t instanceBindingCount = 0;
uint32_t instanceCounter = 0;
uint32_t instanceBufferMaxCount = 0;
- VkDeviceSize instanceOffsets = 0;
PkeCallback collisionCallback{};
};
diff --git a/src/ecs.cpp b/src/ecs.cpp
index 09eb725..c5f221a 100644
--- a/src/ecs.cpp
+++ b/src/ecs.cpp
@@ -336,7 +336,7 @@ void ECS_Tick_Late(double delta) {
vkBeginCommandBuffer(transferCommandBuffer, &cbbi);
for (long i = 0; i < ibc.chunks->Count(); ++i) {
- vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ibc.grBinds->instanceBuffer, 1, &(*ibc.chunks)[i].dstBufferCopy);
+ vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ibc.grBinds->instanceBD.buffer, 1, &(*ibc.chunks)[i].dstBufferCopy);
}
vkEndCommandBuffer(transferCommandBuffer);
diff --git a/src/entities.cpp b/src/entities.cpp
index 179ce4b..123c095 100644
--- a/src/entities.cpp
+++ b/src/entities.cpp
@@ -133,40 +133,6 @@ EntityType *EntityType_FindByEntityHandle(EntityHandle handle) {
return nullptr;
}
-void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memReqs, VkMemoryRequirements &combinedMemReqs) {
- combinedMemReqs.size = 0;
- combinedMemReqs.alignment = memReqs[0].alignment;
- combinedMemReqs.memoryTypeBits = memReqs[0].memoryTypeBits;
- for (uint64_t i = 1; i < memReqsCount; ++i) {
- combinedMemReqs.memoryTypeBits |= memReqs[i].memoryTypeBits;
- if (combinedMemReqs.alignment == memReqs[i].alignment) {
- continue;
- }
- VkDeviceSize larger, smaller;
- if (combinedMemReqs.alignment > memReqs[i].alignment) {
- larger = combinedMemReqs.alignment;
- smaller = memReqs[i].alignment;
- } else {
- larger = memReqs[i].alignment;
- smaller = combinedMemReqs.alignment;
- }
- if (larger % smaller == 0) {
- combinedMemReqs.alignment = larger;
- continue;
- }
- int combined = larger * smaller;
- while ((combined / 2) % 2 == 0 && (combined / 2) % larger == 0) {
- combined /= 2;
- }
- combinedMemReqs.alignment = combined;
- }
- for (uint64_t i = 0; i < memReqsCount; ++i) {
- uint32_t alignmentPadding = memReqs[i].size % combinedMemReqs.alignment;
- memReqs[i].size += (alignmentPadding == 0 ? 0 : combinedMemReqs.alignment - alignmentPadding);
- combinedMemReqs.size += memReqs[i].size;
- }
-}
-
struct EntityTypeDetails_LoadHelperStruct {
EntityTypeDetails *etd = nullptr;
AssetHandle textureAssetHandle = AssetHandle_MAX;
@@ -644,7 +610,7 @@ void EntityType_LoadTexture(EntityType_LoadHelperStruct &helper, const int64_t i
VkDescriptorSetLayout descriptorSets[MAX_FRAMES_IN_FLIGHT];
for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
- descriptorSets[i] = pkePipelines.vkDescriptorSetLayout_Texture;
+ descriptorSets[i] = pkePipelines.descr_layouts.named.texture;
}
VkDescriptorSetAllocateInfo vkDescriptorSetAllocateInfo;
vkDescriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
@@ -773,8 +739,8 @@ void EntityType_LoadMesh(EntityType_LoadHelperStruct &helper, const int64_t mesh
// 2023-09-27 - JCB
// I don't know where else to put this
- etdHelper.etd->grBinds->instanceFirstBinding = index;
- etdHelper.etd->grBinds->instanceBindingCount = 1;
+ etdHelper.etd->grBinds->instanceBD.firstBinding = index;
+ etdHelper.etd->grBinds->instanceBD.bindingCount = 1;
// no index += 1 because index just happens to be the right value here for
// the binding index, whereas binding the IndexBuffer doesn't need a binding index.
@@ -878,8 +844,8 @@ void EntityType_LoadMesh(EntityType_LoadHelperStruct &helper, const int64_t mesh
etdHelper.etd->grBinds->instanceBufferMaxCount = etdHelper.etd->grBinds->instanceBufferMaxCount < 1 ? 1 : etdHelper.etd->grBinds->instanceBufferMaxCount;
bufferCI.size = sizeof(glm::mat4) * etdHelper.etd->grBinds->instanceBufferMaxCount;
bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
- vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->instanceBuffer);
- vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->instanceBuffer, helper.et.deviceMemoryInst, 0);
+ vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->instanceBD.buffer);
+ vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->instanceBD.buffer, helper.et.deviceMemoryInst, 0);
// bullet
@@ -1094,8 +1060,8 @@ void EntityType_Load(EntityType &et) {
* I don't like that we're just copying this.
* This should be moved to window.cpp.
*/
- etdHelper.etd->grBinds->vkPipelineLayout = pkePipelines.vkPipelineLayout_Texture;
- etdHelper.etd->grBinds->graphicsPipeline = pkePipelines.pipelines.named.Texture;
+ etdHelper.etd->grBinds->vkPipelineLayout = pkePipelines.pipe_layouts.named.texture;
+ etdHelper.etd->grBinds->graphicsPipeline = pkePipelines.pipelines.named.texture;
// handle texture
EntityType_LoadTexture(helper, i);
@@ -1185,14 +1151,14 @@ void EntityType_Unload(EntityType &et, CompGrBinds *grBindsArr[1]) {
grBinds->physIndxBD.bindingCount = 0;
grBinds->physIndxBD.offsets[0] = 0;
- if (grBinds->instanceBuffer != VK_NULL_HANDLE)
- vkDestroyBuffer(vkDevice, grBinds->instanceBuffer, vkAllocator);
- grBinds->instanceBuffer = VK_NULL_HANDLE;
- grBinds->instanceFirstBinding = 0;
- grBinds->instanceBindingCount = 0;
+ if (grBinds->instanceBD.buffer != VK_NULL_HANDLE)
+ vkDestroyBuffer(vkDevice, grBinds->instanceBD.buffer, vkAllocator);
+ grBinds->instanceBD.buffer = VK_NULL_HANDLE;
+ grBinds->instanceBD.firstBinding = 0;
+ grBinds->instanceBD.bindingCount = 0;
grBinds->instanceCounter = 0;
grBinds->instanceBufferMaxCount = 0;
- grBinds->instanceOffsets = 0;
+ grBinds->instanceBD.offsets[0] = 0;
}
if (etd.textureImageView != VK_NULL_HANDLE)
@@ -1277,7 +1243,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) {
uint32_t oldSize = sizeof(glm::mat4) * oldCount;
VkDeviceMemory oldMemory(et.deviceMemoryInst);
- VkBuffer oldBuffer(grBinds.instanceBuffer);
+ VkBuffer oldBuffer(grBinds.instanceBD.buffer);
VkBufferCreateInfo vkBufferCreateInfo{};
vkBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
@@ -1288,10 +1254,10 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) {
vkBufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vkBufferCreateInfo.queueFamilyIndexCount = 1;
vkBufferCreateInfo.pQueueFamilyIndices = &graphicsFamilyIndex;
- vkCreateBuffer(vkDevice, &vkBufferCreateInfo, vkAllocator, &grBinds.instanceBuffer);
+ vkCreateBuffer(vkDevice, &vkBufferCreateInfo, vkAllocator, &grBinds.instanceBD.buffer);
VkMemoryRequirements vkMemoryRequirementsInst;
- vkGetBufferMemoryRequirements(vkDevice, grBinds.instanceBuffer, &vkMemoryRequirementsInst);
+ vkGetBufferMemoryRequirements(vkDevice, grBinds.instanceBD.buffer, &vkMemoryRequirementsInst);
VkMemoryAllocateInfo vkMemoryAllocateInfo;
vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
@@ -1300,7 +1266,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) {
vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(vkMemoryRequirementsInst.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &et.deviceMemoryInst);
- vkBindBufferMemory(vkDevice, grBinds.instanceBuffer, et.deviceMemoryInst, 0);
+ vkBindBufferMemory(vkDevice, grBinds.instanceBD.buffer, et.deviceMemoryInst, 0);
// copy data
{
@@ -1323,7 +1289,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) {
memBarriers[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
memBarriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
memBarriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- memBarriers[1].buffer = grBinds.instanceBuffer;
+ memBarriers[1].buffer = grBinds.instanceBD.buffer;
memBarriers[1].offset = 0;
memBarriers[1].size = vkMemoryRequirementsInst.size;
@@ -1341,7 +1307,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) {
vkBufferCopy.srcOffset = 0;
vkBufferCopy.dstOffset = 0;
vkBufferCopy.size = oldSize;
- vkCmdCopyBuffer(graphicsCommandBuffer, oldBuffer, grBinds.instanceBuffer, 1, &vkBufferCopy);
+ vkCmdCopyBuffer(graphicsCommandBuffer, oldBuffer, grBinds.instanceBD.buffer, 1, &vkBufferCopy);
vkEndCommandBuffer(graphicsCommandBuffer);
diff --git a/src/font.cpp b/src/font.cpp
new file mode 100644
index 0000000..d218430
--- /dev/null
+++ b/src/font.cpp
@@ -0,0 +1,638 @@
+
+#include "font.hpp"
+#include "asset-manager.hpp"
+#include "pk.h"
+#include "window.hpp"
+#include "static-plane.hpp"
+#include "vendor-stb-image-include.h"
+// #include "bucketed-array.hpp"
+
+// TODO threading
+
+TypeSafeInt_B(FontTypeIndex);
+TypeSafeInt_B(FontRenderIndex);
+
+struct FontTypeData {
+ FontType *arr_ft;
+ FontTypeIndex n_ft{0};
+ FontTypeIndex h_ft{0};
+} ftd;
+
+// BucketContainer<FontType, TextRenderHandle, 2> bktFont;
+
+void FontType_Init() {
+ ftd.h_ft = FontTypeIndex{5};
+ ftd.arr_ft = pk_new<FontType>(5);
+}
+
+void FontType_Teardown() {
+ FontTypeIndex i;
+ FontType *ft;
+ for (i = FontTypeIndex{0}; i < ftd.h_ft; ++i) {
+ FontType_Unload(i);
+ ft = &ftd.arr_ft[(FontTypeIndex_T)i];
+ pk_delete<FontRender>(ft->renders, (FontTypeIndex_T)ft->n_render);
+ }
+ pk_delete(ftd.arr_ft, (FontTypeIndex_T)ftd.n_ft);
+}
+
+FontType* FontType_GetFonts(FontTypeIndex &count)
+{
+ count = ftd.h_ft;
+ return ftd.arr_ft;
+}
+
+FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle, AssetHandle glyphsHandle) {
+ VkResult vkResult;
+ pk_arr arr_vert_mem_reqs;
+ memset(&arr_vert_mem_reqs, 0, sizeof(pk_arr));
+ arr_vert_mem_reqs.alignment = alignof(VkMemoryRequirements);
+ arr_vert_mem_reqs.stride = sizeof(VkMemoryRequirements);
+ pk_arr arr_inst_mem_reqs(arr_vert_mem_reqs);
+ pk_arr arr_texture_mem_reqs(arr_vert_mem_reqs);
+ VkDeviceSize index;
+ constexpr VkDeviceSize expectedBufferCount = 3;
+ constexpr VkDeviceSize startingGlyphCount = 4;
+
+ VkMemoryRequirements combined_vert_mem_reqs;
+ VkMemoryRequirements combined_inst_mem_reqs;
+ VkMemoryRequirements combined_texture_mem_reqs;
+
+ const Asset *fontTexture = AM_Get(fontTextureHandle);
+ const Asset *glyphs = AM_Get(glyphsHandle);
+ if (ftd.h_ft > ftd.n_ft) {
+ index = (VkDeviceSize)ftd.n_ft;
+ ftd.n_ft += FontTypeIndex{5};
+ FontType *arr = pk_new<FontType>((FontTypeIndex_T)ftd.n_ft);
+ memcpy(arr, ftd.arr_ft, sizeof(FontType) * index);
+ pk_delete<FontType>(ftd.arr_ft, index);
+ ftd.arr_ft = arr;
+ }
+
+ FontTypeIndex idx = ftd.h_ft++;
+ FontTypeIndex_T idx_t = (FontTypeIndex_T)idx;
+ FontType *ft = &ftd.arr_ft[idx_t];
+ ft->title = title;
+ ft->fontTextureAssetKey = fontTextureHandle;
+ ft->glyphDetailsAssetKey = glyphsHandle;
+ ft->renders = pk_new<FontRender>(startingGlyphCount);
+ ft->n_render = FontRenderIndex{startingGlyphCount};
+
+ int txtr_x, txtr_y, txtr_chan;
+ stbi_uc *txtr_bytes = stbi_load_from_memory((unsigned char*)fontTexture->ptr, fontTexture->size, &txtr_x, &txtr_y, &txtr_chan, 4);
+ assert(txtr_chan == 4);
+
+ /*
+ * vulkan setup
+ */
+ VkBuffer buffer;
+ VkBufferCreateInfo bufferCI;
+ bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ bufferCI.pNext = nullptr;
+ bufferCI.flags = {};
+ bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ bufferCI.queueFamilyIndexCount = 1;
+ bufferCI.pQueueFamilyIndices = &graphicsFamilyIndex;
+
+ /*
+ * Vulkan resource setup
+ */
+ // vertex
+ {
+ for (uint64_t index = 0; index < expectedBufferCount; ++index) {
+ if (index == 0) {
+ bufferCI.size = sizeof(glm::vec2) * 4;
+ } else if (index == 1) {
+ bufferCI.size = sizeof(glm::vec2) * 4;
+ } else if (index == 2) {
+ bufferCI.size = sizeof(uint16_t) * 6;
+ }
+ if (index == 2) {
+ bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+ } else {
+ bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ }
+ vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &buffer);
+ VkMemoryRequirements tmp;
+ vkGetBufferMemoryRequirements(vkDevice, buffer, &tmp);
+ pk_arr_append(&arr_vert_mem_reqs, &tmp);
+ vkDestroyBuffer(vkDevice, buffer, vkAllocator);
+ }
+ }
+ // instance
+ {
+ bufferCI.size = 0;
+ bufferCI.size += sizeof(glm::vec4); // fgColor
+ bufferCI.size += sizeof(glm::vec4); // bgColor
+ bufferCI.size += sizeof(glm::vec4); // sprite_region
+ bufferCI.size += sizeof(float); // width
+ bufferCI.size *= startingGlyphCount;
+ bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &buffer);
+ VkMemoryRequirements tmp;
+ vkGetBufferMemoryRequirements(vkDevice, buffer, &tmp);
+ pk_arr_append(&arr_inst_mem_reqs, &tmp);
+ vkDestroyBuffer(vkDevice, buffer, vkAllocator);
+ }
+ // texture
+ VkImageCreateInfo imageCreateInfo{};
+ VkImageSubresourceRange vkImageSubresourceRange;
+ {
+ imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ imageCreateInfo.pNext = nullptr;
+ imageCreateInfo.flags = 0;
+ imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
+ imageCreateInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
+ imageCreateInfo.extent.width = txtr_x;
+ imageCreateInfo.extent.height = txtr_y;
+ imageCreateInfo.extent.depth = 1;
+ imageCreateInfo.mipLevels = 1;
+ imageCreateInfo.arrayLayers = 1;
+ imageCreateInfo.samples = renderSampleCount;
+ imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+ imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ imageCreateInfo.queueFamilyIndexCount = 0;
+ imageCreateInfo.pQueueFamilyIndices = nullptr;
+ imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ vkImageSubresourceRange.aspectMask = VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT;
+ vkImageSubresourceRange.baseMipLevel = 0u;
+ vkImageSubresourceRange.levelCount = 1u;
+ vkImageSubresourceRange.baseArrayLayer = 0u;
+ vkImageSubresourceRange.layerCount = 1u;
+
+ VkImageViewCreateInfo vkImageViewCreateInfo;
+ vkImageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ vkImageViewCreateInfo.pNext = nullptr;
+ vkImageViewCreateInfo.flags = 0;
+ vkImageViewCreateInfo.image = ft->textureImage;
+ vkImageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ vkImageViewCreateInfo.format = imageCreateInfo.format;
+ vkImageViewCreateInfo.components = VkComponentMapping {
+ .r = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .g = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .b = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .a = VK_COMPONENT_SWIZZLE_IDENTITY,
+ };
+ vkImageViewCreateInfo.subresourceRange = vkImageSubresourceRange;
+
+ VkImage tmpImage;
+ vkResult = vkCreateImage(vkDevice, &imageCreateInfo, vkAllocator, &tmpImage);
+ assert(vkResult == VK_SUCCESS);
+
+ VkMemoryRequirements imageMemoryRequirements;
+ vkGetImageMemoryRequirements(vkDevice, tmpImage, &imageMemoryRequirements);
+
+ VkDeviceSize paddedImageSize = imageMemoryRequirements.size + (imageMemoryRequirements.alignment - (imageMemoryRequirements.size % imageMemoryRequirements.alignment));
+ assert(paddedImageSize % imageMemoryRequirements.alignment == 0);
+
+ vkDestroyImage(vkDevice, tmpImage, vkAllocator);
+
+ VkMemoryAllocateInfo vkMemoryAllocateInfo{};
+ vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ vkMemoryAllocateInfo.pNext = nullptr;
+ vkMemoryAllocateInfo.allocationSize = paddedImageSize * MAX_FRAMES_IN_FLIGHT;
+ vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(imageMemoryRequirements.memoryTypeBits,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ vkResult = vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryTexture);
+ assert(vkResult == VK_SUCCESS);
+
+ vkResult = vkCreateImage(vkDevice, &imageCreateInfo, vkAllocator, &ft->textureImage);
+ assert(vkResult == VK_SUCCESS);
+ vkResult = vkBindImageMemory(vkDevice, ft->textureImage, ft->deviceMemoryTexture, 0);
+ assert(vkResult == VK_SUCCESS);
+
+ vkImageViewCreateInfo.image = ft->textureImage;
+ vkResult = vkCreateImageView(vkDevice, &vkImageViewCreateInfo, vkAllocator, &ft->textureImageView);
+ assert(vkResult == VK_SUCCESS);
+ }
+
+ /*
+ * Vulkan memory allocation
+ */
+
+ VkMemoryAllocateInfo vkMemoryAllocateInfo;
+ vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ vkMemoryAllocateInfo.pNext = nullptr;
+
+ // verts
+ CalculateCombinedMemReqs(arr_vert_mem_reqs.next, (VkMemoryRequirements*)arr_vert_mem_reqs.data, combined_vert_mem_reqs);
+ vkMemoryAllocateInfo.allocationSize = combined_vert_mem_reqs.size;
+ vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_vert_mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryVert);
+
+ // inst
+ CalculateCombinedMemReqs(arr_inst_mem_reqs.next, (VkMemoryRequirements*)arr_inst_mem_reqs.data, combined_inst_mem_reqs);
+ vkMemoryAllocateInfo.allocationSize = combined_inst_mem_reqs.size;
+ vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_inst_mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryInst);
+
+ // texture
+ CalculateCombinedMemReqs(arr_texture_mem_reqs.next, (VkMemoryRequirements*)arr_texture_mem_reqs.data, combined_texture_mem_reqs);
+ vkMemoryAllocateInfo.allocationSize = combined_texture_mem_reqs.size;
+ vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_texture_mem_reqs.memoryTypeBits, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
+ if (vkMemoryAllocateInfo.memoryTypeIndex == 0) {
+ vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_texture_mem_reqs.memoryTypeBits, 0);
+ }
+ vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryTexture);
+
+ /*
+ * Vulkan data transfer
+ */
+ VkBuffer transferBuffer;
+ VkDeviceMemory transferMemory;
+ void *deviceData;
+ VkDeviceSize runningOffset, alignmentPadding;
+ // vert
+ BeginTransferBuffer(combined_vert_mem_reqs.size, transferBuffer, transferMemory, deviceData);
+ {
+ index = 0;
+ runningOffset = 0;
+
+ uint32_t offsetVert = runningOffset;
+ uint32_t sizeVert = sizeof(pkeIntrinsicsPlane.vert[0]) * 4;
+ ft->bindings.vertexBD.firstBinding = index;
+ ft->bindings.vertexBD.bindingCount = 1;
+ alignmentPadding = sizeVert % combined_vert_mem_reqs.alignment;
+ alignmentPadding = alignmentPadding == 0 ? 0 : combined_vert_mem_reqs.alignment - alignmentPadding;
+ sizeVert += alignmentPadding;
+ bufferCI.size = sizeVert;
+ bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.vertexBD.buffer);
+ vkBindBufferMemory(vkDevice, ft->bindings.vertexBD.buffer, ft->deviceMemoryVert, offsetVert);
+ runningOffset += sizeVert;
+ index += 1;
+
+ // uv
+ uint32_t offsetUV = runningOffset;
+ uint32_t sizeUV = sizeof(pkeIntrinsicsPlane.uv[0]) * 4;
+ ft->bindings.uvBD.firstBinding = index;
+ ft->bindings.uvBD.bindingCount = 1;
+ alignmentPadding = sizeUV % combined_vert_mem_reqs.alignment;
+ alignmentPadding = alignmentPadding == 0 ? 0 : combined_vert_mem_reqs.alignment - alignmentPadding;
+ sizeUV += alignmentPadding;
+ bufferCI.size = sizeUV;
+ vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.uvBD.buffer);
+ vkBindBufferMemory(vkDevice, ft->bindings.uvBD.buffer, ft->deviceMemoryVert, offsetUV);
+ runningOffset += sizeUV;
+ index += 1;
+
+ // 2023-09-27 - JCB
+ // I don't know where else to put this
+ ft->bindings.instanceBD.firstBinding = index;
+ ft->bindings.instanceBD.bindingCount = 1;
+ // no index += 1 because index just happens to be the right value here for
+ // the binding index, whereas binding the IndexBuffer doesn't need a binding index.
+
+ // index
+ uint32_t offsetIndex = runningOffset;
+ uint32_t sizeIndex = sizeof(pkeIntrinsicsPlane.index[0]) * 6;
+ ft->bindings.indexBD.bindingCount = 1;
+ ft->bindings.indexCount = 6;
+ alignmentPadding = sizeIndex % combined_vert_mem_reqs.alignment;
+ alignmentPadding = alignmentPadding == 0 ? 0 : combined_vert_mem_reqs.alignment - alignmentPadding;
+ sizeIndex += alignmentPadding;
+ bufferCI.size = sizeIndex;
+ bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+ vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.indexBD.buffer);
+ vkBindBufferMemory(vkDevice, ft->bindings.indexBD.buffer, ft->deviceMemoryVert, offsetIndex);
+ runningOffset += sizeIndex;
+ // index += 1;
+
+ assert(runningOffset == combined_vert_mem_reqs.size);
+
+
+ runningOffset = 0;
+
+ char *dstPtr = nullptr;
+ char *srcPtr = nullptr;
+
+ dstPtr = static_cast<char *>(deviceData) + runningOffset;
+ srcPtr = reinterpret_cast<char *>(pkeIntrinsicsPlane.vert);
+ memcpy(dstPtr, srcPtr, sizeVert);
+ runningOffset += sizeVert;
+
+ dstPtr = static_cast<char *>(deviceData) + runningOffset;
+ srcPtr = reinterpret_cast<char *>(pkeIntrinsicsPlane.uv);
+ memcpy(dstPtr, srcPtr, sizeUV);
+ runningOffset += sizeUV;
+
+ dstPtr = static_cast<char *>(deviceData) + runningOffset;
+ srcPtr = reinterpret_cast<char *>(pkeIntrinsicsPlane.index);
+ memcpy(dstPtr, srcPtr, sizeIndex);
+ // runningOffset += sizeIndex;
+
+ VkCommandBufferBeginInfo vkCommandBufferBeginInfo;
+ vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ vkCommandBufferBeginInfo.pNext = nullptr;
+ // TODO consider single-use?
+ vkCommandBufferBeginInfo.flags = 0;
+ vkCommandBufferBeginInfo.pInheritanceInfo = nullptr;
+ vkBeginCommandBuffer(transferCommandBuffer, &vkCommandBufferBeginInfo);
+ VkBufferCopy bufferCopys[expectedBufferCount];
+ for (VkDeviceSize i = 0; i < expectedBufferCount; ++i) {
+ bufferCopys[i].dstOffset = 0;
+ }
+ index = 0;
+ bufferCopys[index].srcOffset = offsetVert;
+ bufferCopys[index].size = sizeVert;
+ vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ft->bindings.vertexBD.buffer, 1, &bufferCopys[index]);
+ index+=1;
+
+ bufferCopys[index].srcOffset = offsetUV;
+ bufferCopys[index].size = sizeUV;
+ vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ft->bindings.uvBD.buffer, 1, &bufferCopys[index]);
+ index+=1;
+
+ bufferCopys[index].srcOffset = offsetIndex;
+ bufferCopys[index].size = sizeIndex;
+ vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ft->bindings.indexBD.buffer, 1, &bufferCopys[index]);
+ // index+=1;
+
+ vkEndCommandBuffer(transferCommandBuffer);
+
+ VkSubmitInfo submitInfo;
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.pNext = nullptr;
+ submitInfo.waitSemaphoreCount = 0;
+ submitInfo.pWaitSemaphores = nullptr;
+ submitInfo.pWaitDstStageMask = nullptr;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &transferCommandBuffer;
+ submitInfo.signalSemaphoreCount = 0;
+ submitInfo.pSignalSemaphores = nullptr;
+ vkQueueSubmit(transferQueue, 1, &submitInfo, nullptr);
+ vkQueueWaitIdle(transferQueue);
+ }
+ EndTransferBuffer(transferBuffer, transferMemory);
+ // set up instance buffer
+ {
+ ft->bindings.instanceBufferMaxCount = startingGlyphCount;
+ bufferCI.size = combined_inst_mem_reqs.size;
+ bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.instanceBD.buffer);
+ vkBindBufferMemory(vkDevice, ft->bindings.instanceBD.buffer, ft->deviceMemoryInst, 0);
+ }
+ // texture // transition image layout and copy to buffer
+ BeginTransferBuffer(combined_texture_mem_reqs.size, transferBuffer, transferMemory, deviceData);
+ memcpy(deviceData, txtr_bytes, combined_texture_mem_reqs.size);
+ {
+ VkImageMemoryBarrier vkImageMemoryBarrier;
+ vkImageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ vkImageMemoryBarrier.pNext = nullptr;
+ vkImageMemoryBarrier.srcAccessMask = {};
+ vkImageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ vkImageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ vkImageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ vkImageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ vkImageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ vkImageMemoryBarrier.image = ft->textureImage;
+ vkImageMemoryBarrier.subresourceRange = VkImageSubresourceRange {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ // TODO MipMap
+ .levelCount = 1,
+ .baseArrayLayer = 0,
+ .layerCount = 1,
+ };
+
+ VkCommandBufferBeginInfo vkCommandBufferBeginInfo;
+ vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ vkCommandBufferBeginInfo.pNext = nullptr;
+ vkCommandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+ vkCommandBufferBeginInfo.pInheritanceInfo = nullptr;
+
+ vkBeginCommandBuffer(transferCommandBuffer, &vkCommandBufferBeginInfo);
+
+ vkCmdPipelineBarrier(transferCommandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier);
+
+ VkBufferImageCopy vkBufferImageCopy;
+ vkBufferImageCopy.bufferOffset = 0;
+ vkBufferImageCopy.bufferRowLength = txtr_x;
+ vkBufferImageCopy.bufferImageHeight = txtr_y;
+ vkBufferImageCopy.imageSubresource = VkImageSubresourceLayers {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .baseArrayLayer = 0,
+ .layerCount = 1,
+ };
+ vkBufferImageCopy.imageOffset = VkOffset3D {
+ .x = 0,
+ .y = 0,
+ .z = 0,
+ };
+ vkBufferImageCopy.imageExtent = VkExtent3D {
+ .width = static_cast<uint32_t>(txtr_x),
+ .height = static_cast<uint32_t>(txtr_y),
+ .depth = 1,
+ };
+ vkCmdCopyBufferToImage(transferCommandBuffer, transferBuffer, ft->textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vkBufferImageCopy);
+
+ vkEndCommandBuffer(transferCommandBuffer);
+
+ VkSubmitInfo submitInfo;
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.pNext = nullptr;
+ submitInfo.waitSemaphoreCount = 0;
+ submitInfo.pWaitSemaphores = nullptr;
+ submitInfo.pWaitDstStageMask = nullptr;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &transferCommandBuffer;
+ submitInfo.signalSemaphoreCount = 0;
+ submitInfo.pSignalSemaphores = nullptr;
+ vkQueueSubmit(transferQueue, 1, &submitInfo, nullptr);
+ vkQueueWaitIdle(transferQueue);
+ vkResetCommandBuffer(transferCommandBuffer, 0);
+ }
+ EndTransferBuffer(transferBuffer, transferMemory);
+ {
+ VkImageMemoryBarrier vkImageMemoryBarrier;
+ vkImageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ vkImageMemoryBarrier.pNext = nullptr;
+ vkImageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ vkImageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ vkImageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ vkImageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ vkImageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ vkImageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ vkImageMemoryBarrier.image = ft->textureImage;
+ vkImageMemoryBarrier.subresourceRange = VkImageSubresourceRange {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ // TODO MipMap
+ .levelCount = 1,
+ .baseArrayLayer = 0,
+ .layerCount = 1,
+ };
+
+ VkCommandBufferBeginInfo vkCommandBufferBeginInfo;
+ vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ vkCommandBufferBeginInfo.pNext = nullptr;
+ vkCommandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+ vkCommandBufferBeginInfo.pInheritanceInfo = nullptr;
+
+ vkBeginCommandBuffer(graphicsCommandBuffer, &vkCommandBufferBeginInfo);
+
+ vkCmdPipelineBarrier(graphicsCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier);
+
+ vkEndCommandBuffer(graphicsCommandBuffer);
+
+ VkSubmitInfo submitInfo;
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.pNext = nullptr;
+ submitInfo.waitSemaphoreCount = 0;
+ submitInfo.pWaitSemaphores = nullptr;
+ submitInfo.pWaitDstStageMask = nullptr;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &graphicsCommandBuffer;
+ submitInfo.signalSemaphoreCount = 0;
+ submitInfo.pSignalSemaphores = nullptr;
+ vkQueueSubmit(graphicsQueue, 1, &submitInfo, nullptr);
+ vkQueueWaitIdle(graphicsQueue);
+ }
+
+ /*
+ * Vulkan descriptor sets
+ */
+ VkDescriptorPoolSize descriptorPoolSizes[1];
+ descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ descriptorPoolSizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT;
+
+ VkDescriptorPoolCreateInfo vkDescriptorPoolCreateInfo;
+ vkDescriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ vkDescriptorPoolCreateInfo.pNext = nullptr;
+ vkDescriptorPoolCreateInfo.flags = 0;
+ vkDescriptorPoolCreateInfo.maxSets = MAX_FRAMES_IN_FLIGHT;
+ vkDescriptorPoolCreateInfo.poolSizeCount = (uint32_t)1;
+ vkDescriptorPoolCreateInfo.pPoolSizes = descriptorPoolSizes;
+
+ // consider making me a global pool
+ vkResult = vkCreateDescriptorPool(vkDevice, &vkDescriptorPoolCreateInfo, vkAllocator, &ft->vkDescriptorPool);
+ assert(vkResult == VK_SUCCESS);
+
+ VkDescriptorSetLayout descriptorSets[MAX_FRAMES_IN_FLIGHT];
+ for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
+ descriptorSets[i] = pkePipelines.descr_layouts.named.glyph;
+ }
+ VkDescriptorSetAllocateInfo vkDescriptorSetAllocateInfo;
+ vkDescriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ vkDescriptorSetAllocateInfo.pNext = nullptr;
+ vkDescriptorSetAllocateInfo.descriptorPool = ft->vkDescriptorPool;
+ vkDescriptorSetAllocateInfo.descriptorSetCount = MAX_FRAMES_IN_FLIGHT;
+ vkDescriptorSetAllocateInfo.pSetLayouts = descriptorSets;
+
+ ft->vkDescriptorSets = pk_new<VkDescriptorSet>(MAX_FRAMES_IN_FLIGHT);
+ for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
+ ft->vkDescriptorSets[i] = VkDescriptorSet{};
+ }
+ vkResult = vkAllocateDescriptorSets(vkDevice, &vkDescriptorSetAllocateInfo, ft->vkDescriptorSets);
+ assert(vkResult == VK_SUCCESS);
+
+ VkWriteDescriptorSet writeDescriptorSets[1 * MAX_FRAMES_IN_FLIGHT];
+ for (long i = 0; i < 1 * MAX_FRAMES_IN_FLIGHT; ++i) {
+ writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ writeDescriptorSets[i].pNext = nullptr;
+ writeDescriptorSets[i].dstSet = nullptr;
+ writeDescriptorSets[i].dstBinding = i;
+ writeDescriptorSets[i].dstArrayElement = 0;
+ writeDescriptorSets[i].descriptorCount = 1;
+ writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ writeDescriptorSets[i].pImageInfo = nullptr;
+ writeDescriptorSets[i].pBufferInfo = nullptr;
+ writeDescriptorSets[i].pTexelBufferView = nullptr;
+ }
+
+ VkDescriptorImageInfo textureDescriptorInfo;
+ textureDescriptorInfo.sampler = pkePipelines.vkSampler_Texture;
+ textureDescriptorInfo.imageView = ft->textureImageView;
+ textureDescriptorInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ VkDescriptorBufferInfo vkDescriptorBufferInfo[MAX_FRAMES_IN_FLIGHT];
+
+ for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
+ vkDescriptorBufferInfo[i].buffer = UniformBuffers[i];
+ vkDescriptorBufferInfo[i].offset = 0;
+ vkDescriptorBufferInfo[i].range = sizeof(UniformBufferObject);
+
+ long uboIndex = i * 2;
+ long samplerIndex = uboIndex + 1;
+
+ writeDescriptorSets[uboIndex].pBufferInfo = &vkDescriptorBufferInfo[i];
+ writeDescriptorSets[uboIndex].dstSet = ft->vkDescriptorSets[i];
+
+ writeDescriptorSets[samplerIndex].pImageInfo = &textureDescriptorInfo;
+ writeDescriptorSets[samplerIndex].dstSet = ft->vkDescriptorSets[i];
+ }
+
+ vkUpdateDescriptorSets(vkDevice, 2 * MAX_FRAMES_IN_FLIGHT, writeDescriptorSets, 0, nullptr);
+
+ return idx;
+}
+
+void FontType_Unload(FontTypeIndex idx)
+{
+ FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)idx];
+
+ if (ft->vkDescriptorSets != VK_NULL_HANDLE && ft->vkDescriptorPool != VK_NULL_HANDLE) {
+ // 2023-09-27 - JCB (copied from entities.cpp)
+ // We are not setting the pool flag for allowing freeing descriptor sets
+ // so all we need to do is destroy the pool
+ // If we switch to a global pool, we will need to free here, and
+ // destroy the pool outside of this loop
+ vkDestroyDescriptorPool(vkDevice, ft->vkDescriptorPool, vkAllocator);
+ ft->vkDescriptorSets = CAFE_BABE(VkDescriptorSet);
+ ft->vkDescriptorPool = VK_NULL_HANDLE;
+ }
+
+ if (ft->bindings.vertexBD.buffer != VK_NULL_HANDLE)
+ vkDestroyBuffer(vkDevice, ft->bindings.vertexBD.buffer, vkAllocator);
+ ft->bindings.vertexBD.buffer = VK_NULL_HANDLE;
+ ft->bindings.vertexBD.firstBinding = 0;
+ ft->bindings.vertexBD.bindingCount = 0;
+ ft->bindings.vertexBD.offsets[0] = 0;
+
+ if (ft->bindings.uvBD.buffer != VK_NULL_HANDLE)
+ vkDestroyBuffer(vkDevice, ft->bindings.uvBD.buffer, vkAllocator);
+ ft->bindings.uvBD.buffer = VK_NULL_HANDLE;
+ ft->bindings.uvBD.firstBinding = 0;
+ ft->bindings.uvBD.bindingCount = 0;
+ ft->bindings.uvBD.offsets[0] = 0;
+
+ if (ft->bindings.indexBD.buffer != VK_NULL_HANDLE)
+ vkDestroyBuffer(vkDevice, ft->bindings.indexBD.buffer, vkAllocator);
+ ft->bindings.indexBD.buffer = VK_NULL_HANDLE;
+ ft->bindings.indexBD.bindingCount = 0;
+ ft->bindings.indexBD.offsets[0] = 0;
+ ft->bindings.indexCount = 0;
+
+ if (ft->bindings.instanceBD.buffer != VK_NULL_HANDLE)
+ vkDestroyBuffer(vkDevice, ft->bindings.instanceBD.buffer, vkAllocator);
+ ft->bindings.instanceBD.buffer = VK_NULL_HANDLE;
+ ft->bindings.instanceBD.firstBinding = 0;
+ ft->bindings.instanceBD.bindingCount = 0;
+ ft->bindings.instanceCounter = 0;
+ ft->bindings.instanceBufferMaxCount = 0;
+ ft->bindings.instanceBD.offsets[0] = 0;
+
+ if (ft->textureImageView != VK_NULL_HANDLE)
+ vkDestroyImageView(vkDevice, ft->textureImageView, vkAllocator);
+ ft->textureImageView = VK_NULL_HANDLE;
+
+ if (ft->textureImage != VK_NULL_HANDLE)
+ vkDestroyImage(vkDevice, ft->textureImage, vkAllocator);
+ ft->textureImage = VK_NULL_HANDLE;
+
+ if (ft->deviceMemoryInst != VK_NULL_HANDLE)
+ vkFreeMemory(vkDevice, ft->deviceMemoryInst, vkAllocator);
+ ft->deviceMemoryInst = VK_NULL_HANDLE;
+
+ if (ft->deviceMemoryVert != VK_NULL_HANDLE)
+ vkFreeMemory(vkDevice, ft->deviceMemoryVert, vkAllocator);
+ ft->deviceMemoryVert = VK_NULL_HANDLE;
+
+ if (ft->deviceMemoryTexture != VK_NULL_HANDLE)
+ vkFreeMemory(vkDevice, ft->deviceMemoryTexture, vkAllocator);
+ ft->deviceMemoryTexture = VK_NULL_HANDLE;
+}
diff --git a/src/font.hpp b/src/font.hpp
new file mode 100644
index 0000000..48a7b40
--- /dev/null
+++ b/src/font.hpp
@@ -0,0 +1,74 @@
+#ifndef PKE_FONT_TYPE_HPP
+#define PKE_FONT_TYPE_HPP
+
+#include "asset-manager.hpp"
+#include "components.hpp"
+#include "pk.h"
+
+#include <glm/vec4.hpp>
+
+/*
+Vert: (two triangles)
+vec2 vertex
+vec2 uv
+
+Inst:
+vec4 fg_color
+vec4 bg_color
+vec4 sprite_region
+float width
+
+Texture:
+the MTSDF
+*/
+
+TypeSafeInt_H(FontTypeIndex, uint16_t, 0xFFFF);
+TypeSafeInt_H(FontRenderIndex, uint16_t, 0xFFFF);
+
+struct FontGlyphChar {
+ uint32_t unicode;
+ glm::ivec4 bounds;
+};
+struct FontRender {
+ uint32_t len;
+ FontTypeIndex index_ft;
+ FontRenderIndex index_fr;
+};
+struct FontType : public Entity_Base {
+ pk_cstr title;
+ AssetHandle fontTextureAssetKey;
+ AssetHandle glyphDetailsAssetKey;
+ VkDeviceMemory deviceMemoryVert = VK_NULL_HANDLE;
+ VkDeviceMemory deviceMemoryTexture = VK_NULL_HANDLE;
+ VkDeviceMemory deviceMemoryInst = VK_NULL_HANDLE;
+ VkImage textureImage = VK_NULL_HANDLE;
+ VkImageView textureImageView = VK_NULL_HANDLE;
+ VkDescriptorPool vkDescriptorPool = VK_NULL_HANDLE;
+ VkDescriptorSet *vkDescriptorSets = nullptr;
+ FontRender *renders = nullptr;
+ FontRenderIndex n_render = FontRenderIndex{0};
+ FontRenderIndex h_render = FontRenderIndex{0};
+ FontTypeIndex index_ft = FontTypeIndex{0};
+ struct FontTypeBindings {
+ BufferBindingDetails vertexBD;
+ BufferBindingDetails uvBD;
+ BufferBindingDetails indexBD;
+ BufferBindingDetails instanceBD;
+ uint32_t indexCount;
+ uint32_t instanceCounter = 0;
+ uint32_t instanceBufferMaxCount = 0;
+ } bindings;
+};
+
+
+void FontType_Init();
+void FontType_Teardown();
+// void FontType_Serialize(FontType *ft); // TODO
+// void FontType_Deserialize(FontType **ft); // TODO
+FontType* FontType_GetFonts(FontTypeIndex &count);
+FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetKey fontTexture, AssetKey glyphs);
+void FontType_Unload(FontTypeIndex idx);
+FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr);
+void FontType_RemoveStringRender(FontRender fr);
+
+#endif /* PKE_FONT_TYPE_HPP */
diff --git a/src/static-plane.cpp b/src/static-plane.cpp
new file mode 100644
index 0000000..d504b24
--- /dev/null
+++ b/src/static-plane.cpp
@@ -0,0 +1,21 @@
+
+#include "static-plane.hpp"
+
+IntrinsicShapePlane pkeIntrinsicsPlane {
+ .vert = {
+ {-1, -1},
+ { 1, -1},
+ { 1, 1},
+ {-1, 1},
+ },
+ .uv = {
+ {0,0},
+ {1,0},
+ {1,1},
+ {0,1},
+ },
+ .index = {
+ 2, 1, 0,
+ 0, 3, 2,
+ },
+};
diff --git a/src/static-plane.hpp b/src/static-plane.hpp
new file mode 100644
index 0000000..097a779
--- /dev/null
+++ b/src/static-plane.hpp
@@ -0,0 +1,15 @@
+#ifndef PKE_STATIC_PLANE_HPP
+#define PKE_STATIC_PLANE_HPP
+
+#include <glm/ext/vector_float3.hpp>
+#include <glm/ext/vector_float2.hpp>
+
+struct IntrinsicShapePlane {
+ glm::vec2 vert[4];
+ glm::vec2 uv[4];
+ uint16_t index[6];
+};
+
+extern IntrinsicShapePlane pkeIntrinsicsPlane;
+
+#endif /* PKE_STATIC_PLANE_HPP */
diff --git a/src/window.cpp b/src/window.cpp
index b83ef9a..a06895c 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -1,3 +1,4 @@
+#include "font.hpp"
#define GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_VULKAN
@@ -1562,18 +1563,23 @@ void CreateGraphicsPipelines() {
.bindingCount = 2,
.pBindings = vkDescriptorSetLayoutBindings,
};
- vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &pkePipelines.vkDescriptorSetLayout_Texture);
+ vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &pkePipelines.descr_layouts.named.texture);
+
+ // no UBO on glyph
+ vkDescriptorSetLayoutBindings[0] = vkDescriptorSetLayoutBindings[1];
+ vkDescriptorSetLayoutCreateInfo.bindingCount = 1;
+ vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &pkePipelines.descr_layouts.named.glyph);
VkPipelineLayoutCreateInfo vkPipelineLayoutCreateInfo {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
- .setLayoutCount = 1,
- .pSetLayouts = &pkePipelines.vkDescriptorSetLayout_Texture,
+ .setLayoutCount = 2,
+ .pSetLayouts = pkePipelines.descr_layouts.arr,
.pushConstantRangeCount = 0,
.pPushConstantRanges = nullptr,
};
- vkCreatePipelineLayout(vkDevice, &vkPipelineLayoutCreateInfo, vkAllocator, &pkePipelines.vkPipelineLayout_Texture);
+ vkCreatePipelineLayout(vkDevice, &vkPipelineLayoutCreateInfo, vkAllocator, pkePipelines.pipe_layouts.arr);
VkSamplerCreateInfo vkSamplerCreateInfo;
vkSamplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
@@ -1814,7 +1820,7 @@ void CreateGraphicsPipelines() {
vkGraphicsPipelineCreateInfo[i].pDepthStencilState = &vkPipelineDepthStencilStateCreateInfo;
vkGraphicsPipelineCreateInfo[i].pColorBlendState = &vkPipelineColorBlendStateCreateInfo;
vkGraphicsPipelineCreateInfo[i].pDynamicState = &vkPipelineDynamicStateCreateInfo;
- vkGraphicsPipelineCreateInfo[i].layout = pkePipelines.vkPipelineLayout_Texture;
+ vkGraphicsPipelineCreateInfo[i].layout = pkePipelines.pipe_layouts.named.texture;
vkGraphicsPipelineCreateInfo[i].renderPass = renderRenderPass;
vkGraphicsPipelineCreateInfo[i].subpass = 0;
vkGraphicsPipelineCreateInfo[i].basePipelineHandle = VK_NULL_HANDLE;
@@ -2259,7 +2265,7 @@ void UpdateDebugGraphicsPipeline() {
VkDescriptorSetLayout descriptorSets[MAX_FRAMES_IN_FLIGHT];
for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
- descriptorSets[i] = pkePipelines.vkDescriptorSetLayout_Texture;
+ descriptorSets[i] = pkePipelines.descr_layouts.named.texture;
}
VkDescriptorSetAllocateInfo vkDescriptorSetAllocateInfo;
vkDescriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
@@ -2414,7 +2420,7 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
throw "failed to begin recording command buffer";
}
- // VkClearColorValue clearColorTransparent = {{0.0f, 0.0f, 0.0f, 0.0f}};
+ VkClearColorValue clearColorTransparent = {{0.0f, 0.0f, 0.0f, 0.0f}};
VkClearColorValue clearColorBlack = {{0.0f, 0.0f, 0.0f, 1.0f}};
VkClearDepthStencilValue clearDepth;
clearDepth.depth = 1.0;
@@ -2463,7 +2469,7 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
continue;
if (!binder->vkPipelineLayout)
continue;
- if (binder->instanceBindingCount < 1) {
+ if (binder->instanceBD.bindingCount < 1) {
continue;
}
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, binder->graphicsPipeline);
@@ -2474,13 +2480,13 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
vkCmdBindVertexBuffers(commandBuffer, binder->vertexBD.firstBinding, binder->vertexBD.bindingCount, &binder->vertexBD.buffer, binder->vertexBD.offsets);
vkCmdBindVertexBuffers(commandBuffer, binder->normalsBD.firstBinding, binder->normalsBD.bindingCount, &binder->normalsBD.buffer, binder->normalsBD.offsets);
vkCmdBindVertexBuffers(commandBuffer, binder->uvBD.firstBinding, binder->uvBD.bindingCount, &binder->uvBD.buffer, binder->uvBD.offsets);
- vkCmdBindVertexBuffers(commandBuffer, binder->instanceFirstBinding, binder->instanceBindingCount, &binder->instanceBuffer, &binder->instanceOffsets);
+ vkCmdBindVertexBuffers(commandBuffer, binder->instanceBD.firstBinding, binder->instanceBD.bindingCount, &binder->instanceBD.buffer, binder->instanceBD.offsets);
vkCmdDrawIndexed(commandBuffer, binder->indexCount, binder->instanceCounter, 0, 0, 0);
if (pkeSettings.isRenderingDebug) {
- vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.TextureWireframe);
- vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.vkPipelineLayout_Texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {});
+ vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.texture_wireframe);
+ vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipe_layouts.named.texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {});
vkCmdBindVertexBuffers(commandBuffer, binder->physVertBD.firstBinding, 1, &binder->physVertBD.buffer, binder->physVertBD.offsets);
vkCmdBindVertexBuffers(commandBuffer, binder->physNormBD.firstBinding, 1, &binder->physNormBD.buffer, binder->physVertBD.offsets);
@@ -2493,8 +2499,8 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
}
if (pkeDebugHitbox.instanceBuffer != VK_NULL_HANDLE) {
- vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.TextureWireframe);
- vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.vkPipelineLayout_Texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {});
+ vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.texture_wireframe);
+ vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipe_layouts.named.texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {});
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &UniformBuffers[imageIndex], offsets);
// TODO don't hardcode firstBinding
@@ -2509,8 +2515,8 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
vkCmdEndRenderPass(commandBuffer);
- /*
// 2d overlay pass
+ /*
renderPassInfo.renderPass = d2OverlayRenderPass;
renderPassInfo.framebuffer = d2OverlayImageFramebuffers[imageIndex];
renderPassInfo.clearValueCount = 1;
@@ -2521,10 +2527,23 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
// TODO 2d overlay grbinds
+ FontTypeIndex count;
+ FontType *fts = FontType_GetFonts(count);
+ for (FontTypeIndex i = FontTypeIndex{0}; i < count; ++i)
{
+ FontType *ft = &fts[(FontTypeIndex_T)i];
+ vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.glyph);
- }
+ vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipe_layouts.named.glyph, 0, 1, &ft->vkDescriptorSets[imageIndex], 0, {});
+ vkCmdBindVertexBuffers(commandBuffer, 0, 1, &UniformBuffers[imageIndex], offsets);
+ vkCmdBindIndexBuffer(commandBuffer, ft->bindings.indexBD.buffer, ft->bindings.indexBD.offsets[0], VK_INDEX_TYPE_UINT16);
+ vkCmdBindVertexBuffers(commandBuffer, ft->bindings.vertexBD.firstBinding, ft->bindings.vertexBD.bindingCount, &ft->bindings.vertexBD.buffer, ft->bindings.vertexBD.offsets);
+ vkCmdBindVertexBuffers(commandBuffer, ft->bindings.uvBD.firstBinding, ft->bindings.uvBD.bindingCount, &ft->bindings.uvBD.buffer, ft->bindings.uvBD.offsets);
+ vkCmdBindVertexBuffers(commandBuffer, ft->bindings.instanceBD.firstBinding, ft->bindings.instanceBD.bindingCount, &ft->bindings.instanceBD.buffer, ft->bindings.instanceBD.offsets);
+
+ vkCmdDrawIndexed(commandBuffer, ft->bindings.indexCount, ft->bindings.instanceCounter, 0, 0, 0);
+ }
vkCmdEndRenderPass(commandBuffer);
*/
@@ -2544,9 +2563,9 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
// ImGui
- const auto count = LoadedPkePlugins.Count();
+ const auto plugin_count = LoadedPkePlugins.Count();
bool any = false;
- for (long i = 0; i < count; ++i) {
+ for (long i = 0; i < plugin_count; ++i) {
if (LoadedPkePlugins[i].OnImGuiRender != nullptr) {
any = true;
break;
@@ -2556,7 +2575,7 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
- for (long i = 0; i < count; ++i) {
+ for (long i = 0; i < plugin_count; ++i) {
if (LoadedPkePlugins[i].OnImGuiRender != nullptr) {
LoadedPkePlugins[i].OnImGuiRender();
}
@@ -2746,10 +2765,10 @@ void DestroyWindow() {
if (pkePipelines.pipelines.arr[i] != VK_NULL_HANDLE)
vkDestroyPipeline(vkDevice, pkePipelines.pipelines.arr[i], vkAllocator);
}
- if (pkePipelines.vkPipelineLayout_Texture != VK_NULL_HANDLE)
- vkDestroyPipelineLayout(vkDevice, pkePipelines.vkPipelineLayout_Texture, vkAllocator);
- if (pkePipelines.vkDescriptorSetLayout_Texture != VK_NULL_HANDLE)
- vkDestroyDescriptorSetLayout(vkDevice, pkePipelines.vkDescriptorSetLayout_Texture, vkAllocator);
+ if (pkePipelines.pipe_layouts.named.texture != VK_NULL_HANDLE)
+ vkDestroyPipelineLayout(vkDevice, pkePipelines.pipe_layouts.named.texture, vkAllocator);
+ if (pkePipelines.descr_layouts.named.texture != VK_NULL_HANDLE)
+ vkDestroyDescriptorSetLayout(vkDevice, pkePipelines.descr_layouts.named.texture, vkAllocator);
for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
vkDestroyBuffer(vkDevice, UniformBuffers[i], vkAllocator);
@@ -2805,6 +2824,40 @@ VkShaderModule UploadShader(AssetHandle handle) {
return vkShaderModule;
}
+void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memReqs, VkMemoryRequirements &combinedMemReqs) {
+ combinedMemReqs.size = 0;
+ combinedMemReqs.alignment = memReqs[0].alignment;
+ combinedMemReqs.memoryTypeBits = memReqs[0].memoryTypeBits;
+ for (uint64_t i = 1; i < memReqsCount; ++i) {
+ combinedMemReqs.memoryTypeBits |= memReqs[i].memoryTypeBits;
+ if (combinedMemReqs.alignment == memReqs[i].alignment) {
+ continue;
+ }
+ VkDeviceSize larger, smaller;
+ if (combinedMemReqs.alignment > memReqs[i].alignment) {
+ larger = combinedMemReqs.alignment;
+ smaller = memReqs[i].alignment;
+ } else {
+ larger = memReqs[i].alignment;
+ smaller = combinedMemReqs.alignment;
+ }
+ if (larger % smaller == 0) {
+ combinedMemReqs.alignment = larger;
+ continue;
+ }
+ int combined = larger * smaller;
+ while ((combined / 2) % 2 == 0 && (combined / 2) % larger == 0) {
+ combined /= 2;
+ }
+ combinedMemReqs.alignment = combined;
+ }
+ for (uint64_t i = 0; i < memReqsCount; ++i) {
+ uint32_t alignmentPadding = memReqs[i].size % combinedMemReqs.alignment;
+ memReqs[i].size += (alignmentPadding == 0 ? 0 : combinedMemReqs.alignment - alignmentPadding);
+ combinedMemReqs.size += memReqs[i].size;
+ }
+}
+
void Render() {
vkWaitForFences(vkDevice, 1, &presentInFlightFences[CURRENT_FRAME], VK_TRUE, UINT64_MAX);
diff --git a/src/window.hpp b/src/window.hpp
index 35891c0..e6f422a 100644
--- a/src/window.hpp
+++ b/src/window.hpp
@@ -66,14 +66,27 @@ struct DebugHitbox {
};
extern DebugHitbox pkeDebugHitbox;
struct ImplementedPipelines {
- VkDescriptorSetLayout vkDescriptorSetLayout_Texture = VK_NULL_HANDLE;
- VkPipelineLayout vkPipelineLayout_Texture = VK_NULL_HANDLE;
VkSampler vkSampler_Texture = VK_NULL_HANDLE;
union {
- VkPipeline arr[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE };
+ VkDescriptorSetLayout arr[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE };
+ struct ImplementedPipelineLayoutsByName {
+ VkDescriptorSetLayout texture;
+ VkDescriptorSetLayout glyph;
+ } named;
+ } descr_layouts;
+ union {
+ VkPipelineLayout arr[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE };
+ struct ImplementedPipelineLayoutsByName {
+ VkPipelineLayout texture;
+ VkPipelineLayout glyph;
+ } named;
+ } pipe_layouts;
+ union {
+ VkPipeline arr[3] = { VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE };
struct ImplementedPipelinesByName {
- VkPipeline Texture;
- VkPipeline TextureWireframe;
+ VkPipeline texture;
+ VkPipeline texture_wireframe;
+ VkPipeline glyph;
} named;
} pipelines;
};
@@ -85,6 +98,7 @@ VkShaderModule UploadShader(AssetHandle handle);
void Render();
unsigned int FindMemoryTypeIndex(uint32_t typeFilter, VkMemoryPropertyFlags memPropertyFlags);
+void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memReqs, VkMemoryRequirements &combinedMemReqs);
void BeginTransferBuffer(VkDeviceSize requestedMemorySize, VkBuffer &buffer, VkDeviceMemory &deviceMemory, void *&deviceData);
void EndTransferBuffer(VkBuffer &buffer, VkDeviceMemory &deviceMemory);