mirror of
https://github.com/love2d/love.git
synced 2026-08-14 10:13:46 +02:00
Implement drawing very basic textures
With this commit you can draw very simple textures.
The following code will showcase it:
```lua
function love.run()
local data = love.image.newImageData(40, 40)
for i = 0,39 do
for j=0,39 do
if i <= 20 then
if j <= 20 then
data:setPixel(i, j, 1, 0, 0, 1)
else
data:setPixel(i, j, 0, 1, 0, 1)
end
else
if j <= 20 then
data:setPixel(i, j, 0, 0, 1, 1)
else
data:setPixel(i, j, 1, 1, 1, 1)
end
end
end
end
local texture
texture = love.graphics.newTexture(data)
return function()
love.event.pump()
for name, a,b,c,d,e,f in love.event.poll() do
if name == "quit" then
if not love.quit or not love.quit() then
return a or 0
end
end
love.handlers[name](a,b,c,d,e,f)
end
love.graphics.origin()
love.graphics.clear()
love.graphics.draw(texture, 50, 500)
love.graphics.present()
end
end
```
This commit is contained in:
@@ -436,20 +436,25 @@ static const char vulkan_vert[] = R"(
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 inPosition;
|
||||
layout(location = 1) in vec2 iTexCoords;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out vec2 texCoords;
|
||||
|
||||
layout(binding = 0) uniform LoveUniforms {
|
||||
float windowWidth;
|
||||
float windowHeight;
|
||||
} loveUniforms;
|
||||
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(
|
||||
2 * inPosition.x / loveUniforms.windowWidth - 1,
|
||||
2 * inPosition.y / loveUniforms.windowHeight - 1,
|
||||
0.0, 1.0);
|
||||
|
||||
fragColor = vec4(1, 1, 1, 1);
|
||||
texCoords = iTexCoords;
|
||||
}
|
||||
)";
|
||||
|
||||
@@ -457,13 +462,14 @@ static const char vulkan_pixel[] = R"(
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec4 fragColor;
|
||||
layout(location = 1) in vec2 texCoords;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
layout(binding = 1) uniform sampler2D texSampler;
|
||||
|
||||
void main() {
|
||||
outColor = fragColor * texture(texSampler, vec2(0, 0));
|
||||
outColor = fragColor * texture(texSampler, texCoords);
|
||||
}
|
||||
)";
|
||||
|
||||
|
||||
@@ -205,7 +205,6 @@ namespace love {
|
||||
createUniformBuffers();
|
||||
createDefaultTexture();
|
||||
createDescriptorPool();
|
||||
createDescriptorSets();
|
||||
createSyncObjects();
|
||||
startRecordingGraphicsCommands();
|
||||
|
||||
@@ -282,11 +281,24 @@ namespace love {
|
||||
|
||||
std::vector<VkBuffer> buffers;
|
||||
std::vector<VkDeviceSize> offsets;
|
||||
|
||||
// vertices
|
||||
buffers.push_back((VkBuffer)cmd.buffers->info[0].buffer->getHandle());
|
||||
offsets.push_back((VkDeviceSize)0);
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets.at(currentFrame), 0, nullptr);
|
||||
vkCmdBindVertexBuffers(commandBuffers.at(imageIndex), 0, 1, buffers.data(), offsets.data());
|
||||
// tex coords
|
||||
buffers.push_back((VkBuffer)cmd.buffers->info[1].buffer->getHandle());
|
||||
offsets.push_back((VkDeviceSize)0);
|
||||
|
||||
if (cmd.texture == nullptr) {
|
||||
setTexture(standardTexture);
|
||||
}
|
||||
else {
|
||||
setTexture(cmd.texture);
|
||||
}
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, getDescriptorSet(currentFrame), 0, nullptr);
|
||||
vkCmdBindVertexBuffers(commandBuffers.at(imageIndex), 0, buffers.size(), buffers.data(), offsets.data());
|
||||
vkCmdBindIndexBuffer(commandBuffers.at(imageIndex), (VkBuffer)cmd.indexBuffer->getHandle(), 0, VK_INDEX_TYPE_UINT16);
|
||||
vkCmdDrawIndexed(commandBuffers.at(imageIndex), static_cast<uint32_t>(cmd.indexCount), 1, 0, 0, 0);
|
||||
}
|
||||
@@ -298,6 +310,15 @@ namespace love {
|
||||
|
||||
// END IMPLEMENTATION OVERRIDDEN FUNCTIONS
|
||||
|
||||
VkDescriptorSet* Graphics::getDescriptorSet(int currentFrame) {
|
||||
auto it = textureToDescriptorSetsMap.find(currentTexture);
|
||||
if (it == textureToDescriptorSetsMap.end()) {
|
||||
textureToDescriptorSetsMap[currentTexture] = createDescriptorSets(currentTexture);
|
||||
}
|
||||
|
||||
return &textureToDescriptorSetsMap.at(currentTexture)[currentFrame];
|
||||
}
|
||||
|
||||
VkCommandBuffer Graphics::beginSingleTimeCommands() {
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
@@ -876,7 +897,7 @@ namespace love {
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::createDescriptorSets() {
|
||||
std::vector<VkDescriptorSet> Graphics::createDescriptorSets(graphics::Texture* texture) {
|
||||
std::vector<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout);
|
||||
VkDescriptorSetAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
@@ -884,26 +905,28 @@ namespace love {
|
||||
allocInfo.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
||||
allocInfo.pSetLayouts = layouts.data();
|
||||
|
||||
descriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) {
|
||||
std::vector<VkDescriptorSet> newDescriptorSets;
|
||||
|
||||
newDescriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
if (vkAllocateDescriptorSets(device, &allocInfo, newDescriptorSets.data()) != VK_SUCCESS) {
|
||||
throw love::Exception("failed to allocate descriptor sets");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
VkDescriptorBufferInfo bufferInfo{};
|
||||
bufferInfo.buffer = (VkBuffer) uniformBuffers.at(i)->getHandle();
|
||||
bufferInfo.buffer = (VkBuffer)uniformBuffers.at(i)->getHandle();
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.range = sizeof(Shader::UniformBufferObject);
|
||||
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
Texture* vkTexture = (Texture*)standardTexture;
|
||||
Texture* vkTexture = (Texture*)texture;
|
||||
imageInfo.imageView = vkTexture->getImageView();
|
||||
imageInfo.sampler = vkTexture->getSampler();
|
||||
|
||||
std::array<VkWriteDescriptorSet, 2> descriptorWrite{};
|
||||
descriptorWrite[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrite[0].dstSet = descriptorSets[i];
|
||||
descriptorWrite[0].dstSet = newDescriptorSets[i];
|
||||
descriptorWrite[0].dstBinding = 0;
|
||||
descriptorWrite[0].dstArrayElement = 0;
|
||||
descriptorWrite[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
@@ -911,7 +934,7 @@ namespace love {
|
||||
descriptorWrite[0].pBufferInfo = &bufferInfo;
|
||||
|
||||
descriptorWrite[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrite[1].dstSet = descriptorSets[i];
|
||||
descriptorWrite[1].dstSet = newDescriptorSets[i];
|
||||
descriptorWrite[1].dstBinding = 1;
|
||||
descriptorWrite[1].dstArrayElement = 0;
|
||||
descriptorWrite[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
@@ -920,6 +943,8 @@ namespace love {
|
||||
|
||||
vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
return newDescriptorSets;
|
||||
}
|
||||
|
||||
void Graphics::createGraphicsPipeline() {
|
||||
@@ -934,17 +959,30 @@ namespace love {
|
||||
vertexBindingDescription.stride = 2 * sizeof(float); // just position for now
|
||||
vertexBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
// todo later
|
||||
VkVertexInputAttributeDescription positionInputAttributeDescription;
|
||||
positionInputAttributeDescription.binding = 0;
|
||||
positionInputAttributeDescription.location = 0;
|
||||
positionInputAttributeDescription.format = VK_FORMAT_R32G32_SFLOAT;
|
||||
positionInputAttributeDescription.offset = 0;
|
||||
|
||||
vertexInputInfo.vertexBindingDescriptionCount = 1;
|
||||
vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDescription;
|
||||
vertexInputInfo.vertexAttributeDescriptionCount = 1;
|
||||
vertexInputInfo.pVertexAttributeDescriptions = &positionInputAttributeDescription;
|
||||
VkVertexInputBindingDescription texCoordsBindingDescription;
|
||||
texCoordsBindingDescription.binding = 1;
|
||||
texCoordsBindingDescription.stride = 3 * sizeof(float); // 2 floats for texture coordinates, 1 float for color
|
||||
texCoordsBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
VkVertexInputAttributeDescription texCoordsInputAttributeDescription;
|
||||
texCoordsInputAttributeDescription.binding = 1;
|
||||
texCoordsInputAttributeDescription.location = 1;
|
||||
texCoordsInputAttributeDescription.format = VK_FORMAT_R32G32_SFLOAT;
|
||||
texCoordsInputAttributeDescription.offset = 0;
|
||||
|
||||
std::vector<VkVertexInputBindingDescription> bindingDescriptions = { vertexBindingDescription, texCoordsBindingDescription };
|
||||
std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions = { positionInputAttributeDescription, texCoordsInputAttributeDescription };
|
||||
|
||||
vertexInputInfo.vertexBindingDescriptionCount = bindingDescriptions.size();
|
||||
vertexInputInfo.pVertexBindingDescriptions = bindingDescriptions.data();
|
||||
vertexInputInfo.vertexAttributeDescriptionCount = vertexInputAttributeDescriptions.size();
|
||||
vertexInputInfo.pVertexAttributeDescriptions = vertexInputAttributeDescriptions.data();
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
|
||||
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
@@ -1119,6 +1157,7 @@ namespace love {
|
||||
void Graphics::cleanup() {
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
|
||||
cleanupSwapChain();
|
||||
|
||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
@@ -1149,6 +1188,7 @@ namespace love {
|
||||
}
|
||||
vkDestroySwapchainKHR(device, swapChain, nullptr);
|
||||
uniformBuffers.clear();
|
||||
textureToDescriptorSetsMap.clear();
|
||||
}
|
||||
|
||||
void Graphics::recreateSwapChain() {
|
||||
@@ -1163,7 +1203,6 @@ namespace love {
|
||||
createFramebuffers();
|
||||
createUniformBuffers();
|
||||
createDescriptorPool();
|
||||
createDescriptorSets();
|
||||
createCommandBuffers();
|
||||
startRecordingGraphicsCommands();
|
||||
}
|
||||
|
||||
@@ -96,6 +96,16 @@ namespace love {
|
||||
void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override { std::cout << "setRenderTargetsInternal "; }
|
||||
|
||||
private:
|
||||
graphics::Texture* currentTexture;
|
||||
|
||||
void setTexture(graphics::Texture* texture) {
|
||||
currentTexture = texture;
|
||||
}
|
||||
|
||||
VkDescriptorSet* getDescriptorSet(int currentFrame);
|
||||
|
||||
std::unordered_map<graphics::Texture*, std::vector<VkDescriptorSet>> textureToDescriptorSetsMap;
|
||||
|
||||
// vulkan specific member functions and variables
|
||||
|
||||
struct QueueFamilyIndices {
|
||||
@@ -133,7 +143,7 @@ namespace love {
|
||||
void createDescriptorSetLayout();
|
||||
void createUniformBuffers();
|
||||
void createDescriptorPool();
|
||||
void createDescriptorSets();
|
||||
std::vector<VkDescriptorSet> createDescriptorSets(graphics::Texture* texture);
|
||||
void createGraphicsPipeline();
|
||||
void createFramebuffers();
|
||||
void createCommandPool();
|
||||
@@ -170,7 +180,6 @@ namespace love {
|
||||
VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
|
||||
std::vector<std::unique_ptr<StreamBuffer>> uniformBuffers;
|
||||
VkDescriptorPool descriptorPool;
|
||||
std::vector<VkDescriptorSet> descriptorSets;
|
||||
std::vector<VkSemaphore> imageAvailableSemaphores;
|
||||
std::vector<VkSemaphore> renderFinishedSemaphores;
|
||||
std::vector<VkFence> inFlightFences;
|
||||
|
||||
@@ -22,12 +22,12 @@ namespace love {
|
||||
rect.w = sliceData->getWidth();
|
||||
rect.h = sliceData->getHeight();
|
||||
|
||||
uploadByteData(PIXELFORMAT_BGRA8_UNORM, dataPtr, size, 0, 0, rect);
|
||||
uploadByteData(PIXELFORMAT_RGBA8_UNORM, dataPtr, size, 0, 0, rect);
|
||||
}
|
||||
else {
|
||||
uint8 defaultPixel[] = { 255, 255, 255, 255 };
|
||||
Rect rect = { 0, 0, 1, 1 };
|
||||
uploadByteData(PIXELFORMAT_BGRA8_UNORM, defaultPixel, sizeof(defaultPixel), 0, 0, rect);
|
||||
uploadByteData(PIXELFORMAT_RGBA8_UNORM, defaultPixel, sizeof(defaultPixel), 0, 0, rect);
|
||||
}
|
||||
createTextureImageView();
|
||||
createTextureSampler();
|
||||
|
||||
Reference in New Issue
Block a user