init
This commit is contained in:
@@ -0,0 +1,311 @@
|
||||
/* Copyright (c) 2018-2025, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <queue>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "scene_graph/components/material.h"
|
||||
#include "scene_graph/components/perspective_camera.h"
|
||||
#include "scene_graph/components/sub_mesh.h"
|
||||
#include "scene_graph/node.h"
|
||||
#include "scene_graph/script.h"
|
||||
#include "scene_graph/scripts/free_camera.h"
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
std::string get_extension(const std::string &uri)
|
||||
{
|
||||
auto dot_pos = uri.find_last_of('.');
|
||||
if (dot_pos == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error{"Uri has no extension"};
|
||||
}
|
||||
|
||||
return uri.substr(dot_pos + 1);
|
||||
}
|
||||
|
||||
void screenshot(RenderContext &render_context, const std::string &filename)
|
||||
{
|
||||
assert(render_context.get_format() == VK_FORMAT_R8G8B8A8_UNORM ||
|
||||
render_context.get_format() == VK_FORMAT_B8G8R8A8_UNORM ||
|
||||
render_context.get_format() == VK_FORMAT_R8G8B8A8_SRGB ||
|
||||
render_context.get_format() == VK_FORMAT_B8G8R8A8_SRGB);
|
||||
|
||||
// We want the last completed frame since we don't want to be reading from an incomplete framebuffer
|
||||
auto &frame = render_context.get_last_rendered_frame();
|
||||
assert(!frame.get_render_target().get_views().empty());
|
||||
auto &src_image_view = frame.get_render_target().get_views()[0];
|
||||
|
||||
auto width = render_context.get_surface_extent().width;
|
||||
auto height = render_context.get_surface_extent().height;
|
||||
auto dst_size = width * height * 4;
|
||||
|
||||
vkb::core::BufferC dst_buffer{render_context.get_device(),
|
||||
dst_size,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VMA_MEMORY_USAGE_GPU_TO_CPU,
|
||||
VMA_ALLOCATION_CREATE_MAPPED_BIT};
|
||||
|
||||
const auto &queue = render_context.get_device().get_queue_by_flags(VK_QUEUE_GRAPHICS_BIT, 0);
|
||||
|
||||
auto cmd_buf = render_context.get_device().get_command_pool().request_command_buffer();
|
||||
|
||||
cmd_buf->begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
|
||||
|
||||
// Enable destination buffer to be written to
|
||||
{
|
||||
BufferMemoryBarrier memory_barrier{};
|
||||
memory_barrier.src_access_mask = 0;
|
||||
memory_barrier.dst_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
|
||||
cmd_buf->buffer_memory_barrier(dst_buffer, 0, dst_size, memory_barrier);
|
||||
}
|
||||
|
||||
// Enable framebuffer image view to be read from
|
||||
{
|
||||
ImageMemoryBarrier memory_barrier{};
|
||||
memory_barrier.old_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
memory_barrier.new_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
|
||||
cmd_buf->image_memory_barrier(src_image_view, memory_barrier);
|
||||
}
|
||||
|
||||
// Check if framebuffer images are in a BGR format
|
||||
auto bgr_formats = {VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM};
|
||||
bool swizzle = std::ranges::find(bgr_formats, src_image_view.get_format()) != bgr_formats.end();
|
||||
|
||||
// Copy framebuffer image memory
|
||||
VkBufferImageCopy image_copy_region{};
|
||||
image_copy_region.bufferRowLength = width;
|
||||
image_copy_region.bufferImageHeight = height;
|
||||
image_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
image_copy_region.imageSubresource.layerCount = 1;
|
||||
image_copy_region.imageExtent.width = width;
|
||||
image_copy_region.imageExtent.height = height;
|
||||
image_copy_region.imageExtent.depth = 1;
|
||||
|
||||
cmd_buf->copy_image_to_buffer(src_image_view.get_image(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_buffer, {image_copy_region});
|
||||
|
||||
// Enable destination buffer to map memory
|
||||
{
|
||||
BufferMemoryBarrier memory_barrier{};
|
||||
memory_barrier.src_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
memory_barrier.dst_access_mask = VK_ACCESS_HOST_READ_BIT;
|
||||
memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_HOST_BIT;
|
||||
|
||||
cmd_buf->buffer_memory_barrier(dst_buffer, 0, dst_size, memory_barrier);
|
||||
}
|
||||
|
||||
// Revert back the framebuffer image view from transfer to present
|
||||
{
|
||||
ImageMemoryBarrier memory_barrier{};
|
||||
memory_barrier.old_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
memory_barrier.new_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
|
||||
cmd_buf->image_memory_barrier(src_image_view, memory_barrier);
|
||||
}
|
||||
|
||||
cmd_buf->end();
|
||||
|
||||
queue.submit(*cmd_buf, frame.get_fence_pool().request_fence());
|
||||
|
||||
queue.wait_idle();
|
||||
|
||||
auto raw_data = dst_buffer.map();
|
||||
|
||||
// Creates a pointer to the address of the first byte of the image data
|
||||
// Replace the A component with 255 (remove transparency)
|
||||
// If swapchain format is BGR, swapping the R and B components
|
||||
uint8_t *data = raw_data;
|
||||
if (swizzle)
|
||||
{
|
||||
for (size_t i = 0; i < height; ++i)
|
||||
{
|
||||
// Iterate over each pixel, swapping R and B components and writing the max value for alpha
|
||||
for (size_t j = 0; j < width; ++j)
|
||||
{
|
||||
auto temp = *(data + 2);
|
||||
*(data + 2) = *(data);
|
||||
*(data) = temp;
|
||||
*(data + 3) = 255;
|
||||
|
||||
// Get next pixel
|
||||
data += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < height; ++i)
|
||||
{
|
||||
// Iterate over each pixel, writing the max value for alpha
|
||||
for (size_t j = 0; j < width; ++j)
|
||||
{
|
||||
*(data + 3) = 255;
|
||||
|
||||
// Get next pixel
|
||||
data += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vkb::fs::write_image(raw_data,
|
||||
filename,
|
||||
width,
|
||||
height,
|
||||
4,
|
||||
width * 4);
|
||||
|
||||
dst_buffer.unmap();
|
||||
} // namespace vkb
|
||||
|
||||
std::string to_snake_case(const std::string &text)
|
||||
{
|
||||
std::stringstream result;
|
||||
|
||||
for (const auto ch : text)
|
||||
{
|
||||
if (std::isalpha(ch))
|
||||
{
|
||||
if (std::isspace(ch))
|
||||
{
|
||||
result << "_";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::isupper(ch))
|
||||
{
|
||||
result << "_";
|
||||
}
|
||||
|
||||
result << static_cast<char>(std::tolower(ch));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result << ch;
|
||||
}
|
||||
}
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
sg::Light &add_light(sg::Scene &scene, sg::LightType type, const glm::vec3 &position, const glm::quat &rotation, const sg::LightProperties &props, sg::Node *parent_node)
|
||||
{
|
||||
auto light_ptr = std::make_unique<sg::Light>("light");
|
||||
auto node = std::make_unique<sg::Node>(-1, "light node");
|
||||
|
||||
if (parent_node)
|
||||
{
|
||||
node->set_parent(*parent_node);
|
||||
}
|
||||
|
||||
light_ptr->set_node(*node);
|
||||
light_ptr->set_light_type(type);
|
||||
light_ptr->set_properties(props);
|
||||
|
||||
auto &t = node->get_transform();
|
||||
t.set_translation(position);
|
||||
t.set_rotation(rotation);
|
||||
|
||||
// Storing the light component because the unique_ptr will be moved to the scene
|
||||
auto &light = *light_ptr;
|
||||
|
||||
node->set_component(light);
|
||||
scene.add_child(*node);
|
||||
scene.add_component(std::move(light_ptr));
|
||||
scene.add_node(std::move(node));
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
sg::Light &add_point_light(sg::Scene &scene, const glm::vec3 &position, const sg::LightProperties &props, sg::Node *parent_node)
|
||||
{
|
||||
return add_light(scene, sg::LightType::Point, position, {}, props, parent_node);
|
||||
}
|
||||
|
||||
sg::Light &add_directional_light(sg::Scene &scene, const glm::quat &rotation, const sg::LightProperties &props, sg::Node *parent_node)
|
||||
{
|
||||
return add_light(scene, sg::LightType::Directional, {}, rotation, props, parent_node);
|
||||
}
|
||||
|
||||
sg::Light &add_spot_light(sg::Scene &scene, const glm::vec3 &position, const glm::quat &rotation, const sg::LightProperties &props, sg::Node *parent_node)
|
||||
{
|
||||
return add_light(scene, sg::LightType::Spot, position, rotation, props, parent_node);
|
||||
}
|
||||
|
||||
sg::Node &add_free_camera(sg::Scene &scene, const std::string &node_name, VkExtent2D extent)
|
||||
{
|
||||
auto camera_node = scene.find_node(node_name);
|
||||
|
||||
if (!camera_node)
|
||||
{
|
||||
LOGW("Camera node `{}` not found. Looking for `default_camera` node.", node_name.c_str());
|
||||
|
||||
camera_node = scene.find_node("default_camera");
|
||||
}
|
||||
|
||||
if (!camera_node)
|
||||
{
|
||||
throw std::runtime_error("Camera node with name `" + node_name + "` not found.");
|
||||
}
|
||||
|
||||
if (!camera_node->has_component<sg::Camera>())
|
||||
{
|
||||
throw std::runtime_error("No camera component found for `" + node_name + "` node.");
|
||||
}
|
||||
|
||||
auto free_camera_script = std::make_unique<sg::FreeCamera>(*camera_node);
|
||||
|
||||
free_camera_script->resize(extent.width, extent.height);
|
||||
|
||||
scene.add_component(std::move(free_camera_script), *camera_node);
|
||||
|
||||
return *camera_node;
|
||||
}
|
||||
|
||||
size_t calculate_hash(const std::vector<uint8_t> &data)
|
||||
{
|
||||
static_assert(sizeof(data[0]) == 1);
|
||||
constexpr size_t chunk_size = sizeof(size_t) / sizeof(data[0]);
|
||||
size_t data_hash = 0;
|
||||
size_t offset = 0;
|
||||
|
||||
for (; offset + chunk_size < data.size(); offset += chunk_size)
|
||||
{
|
||||
glm::detail::hash_combine(data_hash, *reinterpret_cast<size_t const *>(&data[offset]));
|
||||
}
|
||||
|
||||
if (offset < data.size())
|
||||
{
|
||||
size_t it = 0;
|
||||
std::memcpy(&it, &data[offset], data.size() - offset);
|
||||
glm::detail::hash_combine(data_hash, it);
|
||||
}
|
||||
return data_hash;
|
||||
}
|
||||
|
||||
} // namespace vkb
|
||||
Reference in New Issue
Block a user