Chronos 0.0
A advanced 2D rendering and animation system
Loading...
Searching...
No Matches
text.cpp
Go to the documentation of this file.
1/*
2Copyright (c) 2024 Rahul Satish Vadhyar
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20SOFTWARE.
21*/
22
23#include "text.hpp"
24#include "helper.hpp"
25#include "shaders/textVert.hpp"
26#include "shaders/textFrag.hpp"
27
29 VkCommandPool commandPool, Chronos::Engine::SwapChain* swapChain,
30 VkSampler textureSampler, VkRenderPass* renderPass,
32{
33
34 // set the fontstyle
35 this->fontStyle = fontStyle;
36
37 // initalize the font
38 uint32_t fontWidth = fontStyle.fontWidth;
39 uint32_t fontHeight = fontStyle.fontHeight;
41
42 // unsigned char fontpixels[fontHeight][256];
43 // this causes a memory leak... too bad, MSVC is fucked
44 // MSVC can't take variable multi dimensional arrays, else the above
45 // commented line would have worked.
46 fontpixels = new unsigned char[fontHeight][256];
48
49 // create the font texture from the raw data
50 /*
51 freetype-devel, use this instead and refer
52 https://github.com/RahulVadhyar/StreetChase/blob/main/TextClass.hpp to
53 render and freetype font.
54 */
56 static_cast<size_t>(fontWidth), static_cast<size_t>(fontHeight),
57 static_cast<VkDeviceSize>(fontWidth * fontHeight), VK_FORMAT_R8_UNORM,
58 "Text Texture");
59
60 // create the vertex buffer
61 VkDeviceSize bufferSize = maxTextLength * sizeof(glm::vec4);
63 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
64 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
65 | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, // want to be visible to
66 // host and device
68
69 // create the uniform buffers for color changing
71 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
72 colorBuffers[i].create(*device);
73 }
76 textVert_spv, textVert_spv_len,
77 textFrag_spv, textFrag_spv_len);
78}
79
80std::vector<VkDescriptorType> Chronos::Engine::Text::getDescriptorTypes()
81{
82 return std::vector<VkDescriptorType> {
83 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
84 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
85 };
86}
87
88std::vector<VkShaderStageFlagBits> Chronos::Engine::Text::getDescriptorStages()
89{
90 return std::vector<VkShaderStageFlagBits> { VK_SHADER_STAGE_FRAGMENT_BIT,
91 VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT };
92}
93
95{
96 std::vector<VkDescriptorSetLayout> layouts(
97 MAX_FRAMES_IN_FLIGHT, descriptorSetLayout);
98 VkDescriptorSetAllocateInfo allocInfo {};
99 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
100 allocInfo.descriptorPool = descriptorPool;
101 allocInfo.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
102 allocInfo.pSetLayouts = layouts.data();
103 descriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
104 if (vkAllocateDescriptorSets(
105 device->device, &allocInfo, descriptorSets.data())
106 != VK_SUCCESS) {
107 throw std::runtime_error("failed to allocate descriptor sets!");
108 }
109 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
110
111 VkDescriptorImageInfo imageInfo {};
112 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
113 imageInfo.imageView = fontTexture.textureImageView;
114 imageInfo.sampler = textureSampler;
115
116 VkDescriptorBufferInfo bufferInfo {};
117 bufferInfo.buffer = uniformBuffers[i].buffer;
118 bufferInfo.offset = 0;
119 bufferInfo.range = sizeof(UniformBufferObject);
120
121 VkDescriptorBufferInfo bufferInfo2 {};
122 bufferInfo2.buffer = colorBuffers[i].buffer;
123 bufferInfo2.offset = 0;
124 bufferInfo2.range = sizeof(UniformColorBufferObject);
125
126 std::array<VkWriteDescriptorSet, 3> descriptorWrites {};
127
128 descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
129 descriptorWrites[0].dstSet = descriptorSets[i];
130 descriptorWrites[0].dstBinding = 0;
131 descriptorWrites[0].dstArrayElement = 0;
132 descriptorWrites[0].descriptorType
133 = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
134 descriptorWrites[0].descriptorCount = 1;
135 descriptorWrites[0].pImageInfo = &imageInfo;
136
137 descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
138 descriptorWrites[1].dstSet = descriptorSets[i];
139 descriptorWrites[1].dstBinding = 1;
140 descriptorWrites[1].dstArrayElement = 0;
141 descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
142 descriptorWrites[1].descriptorCount = 1;
143 descriptorWrites[1].pBufferInfo = &bufferInfo;
144
145 descriptorWrites[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
146 descriptorWrites[2].dstSet = descriptorSets[i];
147 descriptorWrites[2].dstBinding = 2;
148 descriptorWrites[2].dstArrayElement = 0;
149 descriptorWrites[2].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
150 descriptorWrites[2].descriptorCount = 1;
151 descriptorWrites[2].pBufferInfo = &bufferInfo2;
152
153 vkUpdateDescriptorSets(device->device,
154 static_cast<uint32_t>(descriptorWrites.size()),
155 descriptorWrites.data(), 0, nullptr);
156 }
157};
158
161{
162 PipelineAttributes pipelineAttributes;
163 pipelineAttributes.bindingDescriptions
164 = std::vector<VkVertexInputBindingDescription> { 2 };
165 pipelineAttributes.bindingDescriptions[0].binding = 0;
166 pipelineAttributes.bindingDescriptions[0].stride = sizeof(glm::vec4);
167 pipelineAttributes.bindingDescriptions[0].inputRate
168 = VK_VERTEX_INPUT_RATE_VERTEX;
169
170 pipelineAttributes.bindingDescriptions[1].binding = 1;
171 pipelineAttributes.bindingDescriptions[1].stride = sizeof(glm::vec4);
172 pipelineAttributes.bindingDescriptions[1].inputRate
173 = VK_VERTEX_INPUT_RATE_VERTEX;
174
175 pipelineAttributes.attributeDescriptions
176 = std::vector<VkVertexInputAttributeDescription> { 2 };
177 pipelineAttributes.attributeDescriptions[0].binding = 0;
178 pipelineAttributes.attributeDescriptions[0].location = 0;
179 pipelineAttributes.attributeDescriptions[0].format
180 = VK_FORMAT_R32G32_SFLOAT;
181 pipelineAttributes.attributeDescriptions[0].offset = 0;
182
183 pipelineAttributes.attributeDescriptions[1].binding = 1;
184 pipelineAttributes.attributeDescriptions[1].location = 1;
185 pipelineAttributes.attributeDescriptions[1].format
186 = VK_FORMAT_R32G32_SFLOAT;
187 pipelineAttributes.attributeDescriptions[1].offset = sizeof(glm::vec2);
188
189 pipelineAttributes.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
190 pipelineAttributes.frontFace = VK_FRONT_FACE_CLOCKWISE;
191
192 pipelineAttributes.colorBlendAttachment.blendEnable = VK_TRUE;
193 pipelineAttributes.colorBlendAttachment.colorWriteMask
194 = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
195 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
196 pipelineAttributes.colorBlendAttachment.srcColorBlendFactor
197 = VK_BLEND_FACTOR_SRC_ALPHA;
198 pipelineAttributes.colorBlendAttachment.dstColorBlendFactor
199 = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
200 pipelineAttributes.colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
201 pipelineAttributes.colorBlendAttachment.srcAlphaBlendFactor
202 = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
203 pipelineAttributes.colorBlendAttachment.dstAlphaBlendFactor
204 = VK_BLEND_FACTOR_ZERO;
205 pipelineAttributes.colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
206
207 return pipelineAttributes;
208}
209
211{
213 vkDestroyBuffer(device->device, vertexBuffer, nullptr);
214 vkFreeMemory(device->device, vertexBufferMemory, nullptr);
215 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
216 colorBuffers[i].destroy();
217 }
218 fontTexture.destroy();
219 delete[] fontpixels;
220}
221
223{
224 // update the vertex buffer with new text on update
225 if (vkMapMemory(device->device, vertexBufferMemory, 0, VK_WHOLE_SIZE, 0,
226 (void**)&mappedMemory)
227 != VK_SUCCESS) {
228 throw std::runtime_error("failed to map memory!");
229 }
230
231 numLetters = 0;
232
233 assert(mappedMemory != nullptr);
234
235 const float charW = 1.5f * params.scale / swapChain->swapChainExtent.width;
236 const float charH = 1.5f * params.scale / swapChain->swapChainExtent.height;
237
238 float fbW = (float)swapChain->swapChainExtent.width;
239 float fbH = (float)swapChain->swapChainExtent.height;
240 float x = (0 / fbW * 2.0f);
241 float y = (0 / fbH * 2.0f);
242
243 // Calculate text width
244 float textWidth = 0;
245 for (auto letter : params.text) {
246 stb_fontchar* charData = &stbFontData[(uint32_t)letter - firstChar];
247 textWidth += charData->advance * charW;
248 }
249 // switch (alignment) {
250 // case Right:
251 // x -= textWidth;
252 // break;
253 // case Center:
254 x -= textWidth / 2.0f;
255 // break;
256 // case Left:
257 // break;
258 // }
259
260 // Generate a uv mapped quad per char in the new text
261 for (auto letter : params.text) {
262 stb_fontchar* charData = &stbFontData[(uint32_t)letter - firstChar];
263
264 mappedMemory->x = (x + (float)charData->x0 * charW);
265 mappedMemory->y = (y + (float)charData->y0 * charH);
266 mappedMemory->z = charData->s0;
267 mappedMemory->w = charData->t0;
268 mappedMemory++;
269
270 mappedMemory->x = (x + (float)charData->x1 * charW);
271 mappedMemory->y = (y + (float)charData->y0 * charH);
272 mappedMemory->z = charData->s1;
273 mappedMemory->w = charData->t0;
274 mappedMemory++;
275
276 mappedMemory->x = (x + (float)charData->x0 * charW);
277 mappedMemory->y = (y + (float)charData->y1 * charH);
278 mappedMemory->z = charData->s0;
279 mappedMemory->w = charData->t1;
280 mappedMemory++;
281
282 mappedMemory->x = (x + (float)charData->x1 * charW);
283 mappedMemory->y = (y + (float)charData->y1 * charH);
284 mappedMemory->z = charData->s1;
285 mappedMemory->w = charData->t1;
286 mappedMemory++;
287
288 x += charData->advance * charW;
289 numLetters++;
290 }
291
292 vkUnmapMemory(device->device, vertexBufferMemory);
293 mappedMemory = nullptr;
294}
295
297{
298 if (vkMapMemory(device->device, vertexBufferMemory, 0, VK_WHOLE_SIZE, 0,
299 (void**)&mappedMemory)
300 != VK_SUCCESS) {
301 throw std::runtime_error("failed to map memory!");
302 }
303 numLetters = 0;
304 mappedMemory = nullptr;
305
306 vkUnmapMemory(device->device, vertexBufferMemory);
307 mappedMemory = nullptr;
308}
309
310void Chronos::Engine::Text::update(uint32_t currentFrame)
311{
312 updateBuffer();
313 uniformBuffers[currentFrame].update(swapChain->swapChainExtent, params.x,
314 params.y, params.rotation + 90, 1.0f, -1.0f);
315 colorBuffers[currentFrame].update(
316 { params.color[0], params.color[1], params.color[2] });
317}
318
319void Chronos::Engine::Text::render(uint32_t currentFrame, uint32_t imageIndex,
320 float bgColor[3], VkViewport& viewport, VkRect2D& scissor,
321 std::vector<VkCommandBuffer>& commandBuffers)
322{
323 vkCmdBindPipeline(commandBuffers[currentFrame],
324 VK_PIPELINE_BIND_POINT_GRAPHICS, this->graphicsPipeline);
325 vkCmdSetViewport(commandBuffers[currentFrame], 0, 1, &viewport);
326 vkCmdSetScissor(commandBuffers[currentFrame], 0, 1, &scissor);
327 VkBuffer vertexBuffers[] = { this->vertexBuffer };
328 VkDeviceSize offsets[] = { 0 };
329 vkCmdBindVertexBuffers(
330 commandBuffers[currentFrame], 0, 1, vertexBuffers, offsets);
331 vkCmdBindVertexBuffers(
332 commandBuffers[currentFrame], 1, 1, vertexBuffers, offsets);
333 vkCmdBindDescriptorSets(commandBuffers[currentFrame],
334 VK_PIPELINE_BIND_POINT_GRAPHICS, this->pipelineLayout, 0, 1,
335 &this->descriptorSets[currentFrame], 0, nullptr);
336 for (uint32_t j = 0; j < this->numLetters; j++) {
337 vkCmdDraw(commandBuffers[currentFrame], 4, 1, j * 4, 0);
338 }
339}
This initializes, manages and destroys the logical and physical devices(GPU).
Definition device.hpp:47
virtual void destroy()=0
Destroys the object and releases associated resources.
Definition object.cpp:235
VkCommandPool commandPool
Definition object.hpp:143
Chronos::Engine::SwapChain * swapChain
Definition object.hpp:141
Chronos::Engine::Device * device
Definition object.hpp:140
void init(Chronos::Engine::Device *device, VkCommandPool commandPool, SwapChain *swapChain, VkSampler textureSampler, VkRenderPass *renderPass, ObjectType objectType, unsigned char *vertShaderCode, int vertShaderCodeSize, unsigned char *fragShaderCode, int fragShaderCodeSize)
Initializes the object.
Definition object.cpp:53
VkRenderPass * renderPass
Definition object.hpp:147
void destroy() override
Destroys the font object and frees the memory.
Definition text.cpp:210
Chronos::Engine::Texture fontTexture
Definition text.hpp:169
std::vector< VkShaderStageFlagBits > getDescriptorStages() override
Gets the descriptor stages in which the descriptor sets are used.
Definition text.cpp:88
uint32_t maxTextLength
Maximum number of characters that can be rendered.
Definition text.hpp:161
std::vector< VkDescriptorType > getDescriptorTypes() override
Gets the descriptor types needed for rendering the text.
Definition text.cpp:80
VkDeviceMemory vertexBufferMemory
The vertex buffer memory.
Definition text.hpp:165
std::vector< Chronos::Engine::ColorBuffer > colorBuffers
Definition text.hpp:171
void clear()
Clears the text stored in the font object.
Definition text.cpp:296
void update(uint32_t currentFrame) override
Updates the attributes(like position, color, etc) of the text.
Definition text.cpp:310
void init(Chronos::Engine::Device *device, VkCommandPool commandPool, Chronos::Engine::SwapChain *swapChain, VkSampler textureSampler, VkRenderPass *renderPass, Chronos::Engine::FontTypes fontStyle)
Initializes the font object and creates the necessary objects.
Definition text.cpp:28
stb_fontchar stbFontData[STB_FONT_consolas_24_latin1_NUM_CHARS]
Definition text.hpp:157
void createDescriptorSets() override
Creates the descriptor sets needed for rendering the text.
Definition text.cpp:94
unsigned char(* fontpixels)[256]
Definition text.hpp:212
PipelineAttributes getPipelineAttributes() override
Returns the pipeline attributes that are set for the graphics pipeline.
Definition text.cpp:160
VkBuffer vertexBuffer
The vertices of each character used for rendering.
Definition text.hpp:144
FontTypes fontStyle
Definition text.hpp:175
void render(uint32_t currentFrame, uint32_t imageIndex, float bgColor[3], VkViewport &viewport, VkRect2D &scissor, std::vector< VkCommandBuffer > &commandBuffers) override
Records the commands needed for rendering the text .
Definition text.cpp:319
void updateBuffer()
Updates the buffer with the new text.
Definition text.cpp:222
void create(Chronos::Engine::Device device, VkCommandPool commandPool, std::string texturePath, std::string textureName)
Create the texture by loading the texture from the given path. Only supports jpg and png images.
Definition texture.cpp:83
Contains various common functions used by other classes in the Engine namespace.
void createBuffer(Chronos::Engine::Device device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer *buffer, VkDeviceMemory *bufferMemory)
Creates a buffer of a given size, usage and properties.
Definition helper.cpp:78
The parameters needed for the font style.
Definition text.hpp:58
void(* getFontData)(stb_fontchar *, unsigned char[][256], int)
Definition text.hpp:61
Structure defining attributes required for creating a graphics pipeline.
Definition object.hpp:43
VkPrimitiveTopology topology
Definition object.hpp:49
VkPipelineColorBlendAttachmentState colorBlendAttachment
Definition object.hpp:53
std::vector< VkVertexInputBindingDescription > bindingDescriptions
Definition object.hpp:45
std::vector< VkVertexInputAttributeDescription > attributeDescriptions
Definition object.hpp:47
Uniform struct passed to shader.
Uniform struct for color passed to shader.
#define MAX_FRAMES_IN_FLIGHT
The number of frames in flight.