494 lines
20 KiB
C++
494 lines
20 KiB
C++
#include "behavior.h"
|
|
|
|
#include <uf/utils/renderer/renderer.h>
|
|
|
|
#include <uf/utils/math/transform.h>
|
|
#include <uf/utils/math/physics.h>
|
|
#include <uf/utils/camera/camera.h>
|
|
#include <uf/ext/gltf/gltf.h>
|
|
#include <uf/engine/asset/asset.h>
|
|
|
|
#include <uf/ext/xatlas/xatlas.h>
|
|
|
|
#include "../light/behavior.h"
|
|
#include "../scene/behavior.h"
|
|
|
|
UF_BEHAVIOR_REGISTER_CPP(ext::BakingBehavior)
|
|
#define this (&self)
|
|
void ext::BakingBehavior::initialize( uf::Object& self ) {
|
|
#if UF_USE_VULKAN
|
|
UF_MSG_DEBUG("Ping");
|
|
|
|
this->addHook( "entity:PostInitialization.%UID%", [&]( ext::json::Value& ){
|
|
auto& metadataJson = this->getComponent<uf::Serializer>();
|
|
auto& metadata = this->getComponent<ext::BakingBehavior::Metadata>();
|
|
|
|
metadata.names.model = this->grabURI( metadataJson["baking"]["model"].as<uf::stl::string>(), metadataJson["system"]["root"].as<uf::stl::string>() );
|
|
if ( metadataJson["baking"]["output"]["model"].is<uf::stl::string>() )
|
|
metadata.names.output.model = this->grabURI( metadataJson["baking"]["output"]["model"].as<uf::stl::string>(), metadataJson["system"]["root"].as<uf::stl::string>() );
|
|
metadata.names.output.map = this->grabURI( metadataJson["baking"]["output"]["map"].as<uf::stl::string>(), metadataJson["system"]["root"].as<uf::stl::string>() );
|
|
metadata.names.renderMode = "B:" + std::to_string((int) this->getUid());
|
|
metadata.trigger.mode = metadataJson["baking"]["trigger"]["mode"].as<uf::stl::string>();
|
|
metadata.trigger.value = metadataJson["baking"]["trigger"]["value"].as<uf::stl::string>();
|
|
if ( metadataJson["baking"]["resolution"].is<size_t>() )
|
|
metadata.size = { metadataJson["baking"]["resolution"].as<size_t>(), metadataJson["baking"]["resolution"].as<size_t>() };
|
|
metadata.shadows = metadataJson["baking"]["shadows"].as<bool>();
|
|
|
|
{
|
|
auto& scene = uf::scene::getCurrentScene();
|
|
auto& sceneMetadata = scene.getComponent<ext::ExtSceneBehavior::Metadata>();
|
|
|
|
metadata.previous.max = sceneMetadata.shadow.max;
|
|
metadata.previous.update = sceneMetadata.shadow.update;
|
|
|
|
sceneMetadata.shadow.max = 1024;
|
|
sceneMetadata.shadow.update = 1024;
|
|
|
|
UF_MSG_DEBUG("Temporarily altering shadow limits...");
|
|
}
|
|
|
|
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
|
|
uf::renderer::addRenderMode( &renderMode, metadata.names.renderMode );
|
|
|
|
renderMode.metadata.type = "single";
|
|
renderMode.metadata.samples = 1;
|
|
|
|
renderMode.width = metadata.size.x;
|
|
renderMode.height = metadata.size.y;
|
|
renderMode.blitter.process = false;
|
|
|
|
UF_MSG_DEBUG("Loading " << metadata.names.model );
|
|
|
|
auto& graph = this->getComponent<pod::Graph>();
|
|
graph = uf::graph::load( metadata.names.model, uf::graph::LoadMode::ATLAS );
|
|
graph.metadata["export"] = metadataJson["baking"]["export"];
|
|
|
|
if ( ext::json::isNull(graph.metadata["wrapped"]) ) {
|
|
UF_MSG_DEBUG("Unwrapping...");
|
|
auto size = ext::xatlas::unwrap( graph );
|
|
if ( size.x == 0 && size.y == 0 ) return;
|
|
if ( metadata.size.x == 0 && metadata.size.y == 0 ) metadata.size = size;
|
|
if ( metadata.names.output.model != "" ) {
|
|
UF_MSG_DEBUG("Saving to " << metadata.names.output.model);
|
|
uf::graph::save( graph, metadata.names.output.model );
|
|
}
|
|
}
|
|
|
|
auto& graphic = this->getComponent<uf::Graphic>();
|
|
graphic.process = false;
|
|
graphic.descriptor.cullMode = uf::renderer::enums::CullMode::NONE;
|
|
graphic.device = &ext::vulkan::device;
|
|
graphic.material.device = graphic.device;
|
|
|
|
if ( graph.atlas.generated() ) {
|
|
for ( auto& texture : graph.textures ) {
|
|
++texture.storage.index;
|
|
}
|
|
auto& image = *graph.images.emplace(graph.images.begin(), graph.atlas.getAtlas());
|
|
auto& texture = *graph.textures.emplace(graph.textures.begin());
|
|
texture.name = "atlas";
|
|
texture.bind = true;
|
|
texture.storage.index = 0;
|
|
texture.storage.sampler = 0;
|
|
texture.storage.remap = 0;
|
|
texture.storage.blend = 0;
|
|
|
|
if ( graph.metadata["filter"].is<uf::stl::string>() ) {
|
|
uf::stl::string filter = graph.metadata["filter"].as<uf::stl::string>();
|
|
if ( filter == "NEAREST" ) {
|
|
texture.texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::NEAREST;
|
|
texture.texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::NEAREST;
|
|
} else if ( filter == "LINEAR" ) {
|
|
texture.texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::LINEAR;
|
|
texture.texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::LINEAR;
|
|
}
|
|
}
|
|
for ( auto& material : graph.materials ) {
|
|
if ( 0 <= material.storage.indexAlbedo ) ++material.storage.indexAlbedo;
|
|
if ( 0 <= material.storage.indexNormal ) ++material.storage.indexNormal;
|
|
if ( 0 <= material.storage.indexEmissive ) ++material.storage.indexEmissive;
|
|
if ( 0 <= material.storage.indexOcclusion ) ++material.storage.indexOcclusion;
|
|
if ( 0 <= material.storage.indexMetallicRoughness ) ++material.storage.indexMetallicRoughness;
|
|
material.storage.indexAtlas = texture.storage.index;
|
|
if ( 0 <= material.storage.indexLightmap ) ++material.storage.indexLightmap;
|
|
}
|
|
texture.texture.loadFromImage( image );
|
|
} else {
|
|
for ( size_t i = 0; i < graph.textures.size() && i < graph.images.size(); ++i ) {
|
|
auto& image = graph.images[i];
|
|
auto& texture = graph.textures[i];
|
|
texture.bind = true;
|
|
texture.storage.index = i;
|
|
if ( graph.metadata["filter"].is<uf::stl::string>() ) {
|
|
uf::stl::string filter = graph.metadata["filter"].as<uf::stl::string>();
|
|
if ( filter == "NEAREST" ) {
|
|
texture.texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::NEAREST;
|
|
texture.texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::NEAREST;
|
|
} else if ( filter == "LINEAR" ) {
|
|
texture.texture.sampler.descriptor.filter.min = uf::renderer::enums::Filter::LINEAR;
|
|
texture.texture.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::LINEAR;
|
|
}
|
|
}
|
|
texture.texture.loadFromImage( image );
|
|
}
|
|
}
|
|
{
|
|
size_t textureSlot = 0;
|
|
for ( auto& texture : graph.textures ) {
|
|
texture.storage.index = -1;
|
|
if ( !texture.bind ) continue;
|
|
texture.storage.index = textureSlot++;
|
|
}
|
|
}
|
|
for ( auto& texture : graph.textures ) {
|
|
if ( !texture.bind ) continue;
|
|
graphic.material.textures.emplace_back().aliasTexture(texture.texture);
|
|
}
|
|
|
|
auto& mesh = this->getComponent<uf::graph::mesh_t>();
|
|
for ( auto& m : graph.meshes ) mesh.insert(m);
|
|
|
|
// Models storage buffer
|
|
uf::stl::vector<pod::Matrix4f> instances;
|
|
instances.reserve( graph.nodes.size() );
|
|
for ( auto& node : graph.nodes ) {
|
|
instances.emplace_back( uf::transform::model( node.transform ) );
|
|
}
|
|
metadata.buffers.instance = graphic.initializeBuffer(
|
|
(void*) instances.data(),
|
|
instances.size() * sizeof(pod::Matrix4f),
|
|
uf::renderer::enums::Buffer::STORAGE
|
|
);
|
|
// Materials storage buffer
|
|
uf::stl::vector<pod::Material::Storage> materials( graph.materials.size() );
|
|
for ( size_t i = 0; i < graph.materials.size(); ++i ) {
|
|
materials[i] = graph.materials[i].storage;
|
|
}
|
|
metadata.buffers.material = graphic.initializeBuffer(
|
|
(void*) materials.data(),
|
|
materials.size() * sizeof(pod::Material::Storage),
|
|
uf::renderer::enums::Buffer::STORAGE
|
|
);
|
|
// Texture storage buffer
|
|
uf::stl::vector<pod::Texture::Storage> textures( graph.textures.size() );
|
|
for ( size_t i = 0; i < graph.textures.size(); ++i ) {
|
|
textures[i] = graph.textures[i].storage;
|
|
}
|
|
metadata.buffers.texture = graphic.initializeBuffer(
|
|
(void*) textures.data(),
|
|
textures.size() * sizeof(pod::Texture::Storage),
|
|
uf::renderer::enums::Buffer::STORAGE
|
|
);
|
|
UF_MSG_DEBUG("Unwrapped model");
|
|
});
|
|
|
|
this->queueHook( "entity:PostInitialization.%UID%", ext::json::null(), 2.0f );
|
|
#endif
|
|
}
|
|
void ext::BakingBehavior::tick( uf::Object& self ) {
|
|
#if UF_USE_VULKAN
|
|
if ( !this->hasComponent<uf::renderer::RenderTargetRenderMode>() ) return;
|
|
auto& metadata = this->getComponent<ext::BakingBehavior::Metadata>();
|
|
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
|
|
if ( renderMode.executed && !metadata.initialized.renderMode ) goto PREPARE;
|
|
else if ( renderMode.executed && !metadata.initialized.map ) {
|
|
TIMER(1.0, (metadata.trigger.mode == "rendered" || (metadata.trigger.mode == "key" && uf::Window::isKeyPressed(metadata.trigger.value))) && ) {
|
|
goto SAVE;
|
|
}
|
|
}
|
|
return;
|
|
PREPARE: {
|
|
UF_MSG_DEBUG("Preparing graphics to bake...");
|
|
|
|
auto& scene = uf::scene::getCurrentScene();
|
|
auto& controller = scene.getController();
|
|
auto& controllerTransform = controller.getComponent<pod::Transform<>>();;
|
|
|
|
auto& mesh = this->getComponent<uf::graph::mesh_t>();
|
|
auto& graphic = this->getComponent<uf::Graphic>();
|
|
|
|
graphic.initialize( metadata.names.renderMode );
|
|
graphic.initializeMesh( mesh );
|
|
|
|
uf::stl::vector<uf::renderer::Texture> textures2D;
|
|
textures2D.reserve( metadata.max.textures2D );
|
|
|
|
uf::stl::vector<uf::renderer::Texture> textures3D;
|
|
textures3D.reserve( metadata.max.textures3D );
|
|
|
|
uf::stl::vector<uf::renderer::Texture> texturesCube;
|
|
texturesCube.reserve( metadata.max.texturesCube );
|
|
|
|
// attach lighting info
|
|
{
|
|
auto& graph = scene.getGraph();
|
|
|
|
struct LightInfo {
|
|
uf::Entity* entity = NULL;
|
|
pod::Vector4f color = {0,0,0,0};
|
|
pod::Vector3f position = {0,0,0};
|
|
float distance = 0;
|
|
float bias = 0;
|
|
int32_t type = 0;
|
|
bool shadows = false;
|
|
};
|
|
uf::stl::vector<LightInfo> entities;
|
|
entities.reserve(graph.size() / 2);
|
|
|
|
uf::stl::vector<pod::Light::Storage> lights;
|
|
lights.reserve(1024);
|
|
|
|
int32_t shadowUpdateThreshold = metadata.max.shadows; // how many shadow maps we should update, based on range
|
|
int32_t shadowCount = metadata.max.shadows; // how many shadow maps we should pass, based on range
|
|
if ( shadowCount <= 0 ) shadowCount = std::numeric_limits<int32_t>::max();
|
|
int32_t experimentalMode = 1;
|
|
|
|
for ( auto entity : graph ) {
|
|
// ignore this scene, our controller, and anything that isn't actually a light
|
|
if ( entity == this || entity == &controller || !entity->hasComponent<ext::LightBehavior::Metadata>() ) continue;
|
|
auto& metadata = entity->getComponent<ext::LightBehavior::Metadata>();
|
|
// disables shadow mappers that activate when in range
|
|
bool hasRT = entity->hasComponent<uf::renderer::RenderTargetRenderMode>();
|
|
if ( hasRT ) {
|
|
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
|
|
if ( metadata.renderer.mode == "in-range" ) renderMode.execute = false;
|
|
}
|
|
if ( metadata.power <= 0 ) continue;
|
|
auto flatten = uf::transform::flatten( entity->getComponent<pod::Transform<>>() );
|
|
LightInfo& info = entities.emplace_back(LightInfo{
|
|
.entity = entity,
|
|
.color = pod::Vector4f{ metadata.color.x, metadata.color.y, metadata.color.z, metadata.power },
|
|
.position = flatten.position,
|
|
.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) ),
|
|
.bias = metadata.bias,
|
|
.type = metadata.type,
|
|
.shadows = metadata.shadows && hasRT,
|
|
});
|
|
}
|
|
std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){
|
|
return l.distance < r.distance;
|
|
});
|
|
// bind lighting and requested shadow maps
|
|
for ( uint32_t i = 0; i < entities.size() && lights.size() < metadata.max.lights; ++i ) {
|
|
auto& info = entities[i];
|
|
uf::Entity* entity = info.entity;
|
|
|
|
if ( !info.shadows ) {
|
|
lights.emplace_back(pod::Light::Storage{
|
|
.position = info.position,
|
|
.color = info.color,
|
|
.type = info.type,
|
|
.typeMap = 0,
|
|
.indexMap = -1,
|
|
.depthBias = info.bias,
|
|
.view = uf::matrix::identity(),
|
|
.projection = uf::matrix::identity(),
|
|
});
|
|
} else {
|
|
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
|
|
auto& lightCamera = entity->getComponent<uf::Camera>();
|
|
auto& lightMetadata = entity->getComponent<ext::LightBehavior::Metadata>();
|
|
lightMetadata.renderer.rendered = true;
|
|
// activate our shadow mapper if it's range-basedd
|
|
if ( lightMetadata.renderer.mode == "in-range" && shadowUpdateThreshold-- > 0 ) renderMode.execute = true;
|
|
// if point light, and combining is requested
|
|
if ( experimentalMode > 0 && renderMode.renderTarget.views == 6 ) {
|
|
int32_t index = -1;
|
|
// separated texture2Ds
|
|
if ( experimentalMode == 2 ) {
|
|
index = textures2D.size();
|
|
for ( auto& attachment : renderMode.renderTarget.attachments ) {
|
|
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
|
|
for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) {
|
|
textures2D.emplace_back().aliasAttachment(attachment, view);
|
|
}
|
|
break;
|
|
}
|
|
// cubemapped
|
|
} else {
|
|
index = texturesCube.size();
|
|
for ( auto& attachment : renderMode.renderTarget.attachments ) {
|
|
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
|
|
texturesCube.emplace_back().aliasAttachment(attachment);
|
|
break;
|
|
}
|
|
}
|
|
lights.emplace_back(pod::Light::Storage{
|
|
.position = info.position,
|
|
.color = info.color,
|
|
.type = info.type,
|
|
.typeMap = experimentalMode,
|
|
.indexMap = index,
|
|
.depthBias = info.bias,
|
|
.view = lightCamera.getView(0),
|
|
.projection = lightCamera.getProjection(0),
|
|
});
|
|
// any other shadowing light, even point lights, are split by shadow maps
|
|
} else {
|
|
for ( auto& attachment : renderMode.renderTarget.attachments ) {
|
|
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
|
|
if ( attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) continue;
|
|
for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) {
|
|
lights.emplace_back(pod::Light::Storage{
|
|
.position = info.position,
|
|
.color = info.color,
|
|
.type = info.type,
|
|
.typeMap = 0,
|
|
.indexMap = textures2D.size(),
|
|
.depthBias = info.bias,
|
|
.view = lightCamera.getView(view),
|
|
.projection = lightCamera.getProjection(view),
|
|
});
|
|
textures2D.emplace_back().aliasAttachment(attachment, view);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
graphic.initializeBuffer(
|
|
(void*) lights.data(),
|
|
lights.size() * sizeof(pod::Light::Storage),
|
|
uf::renderer::enums::Buffer::STORAGE
|
|
);
|
|
}
|
|
// attach shader
|
|
{
|
|
|
|
size_t texture2Ds = textures2D.size();
|
|
size_t texture3Ds = textures3D.size();
|
|
size_t textureCubes = texturesCube.size();
|
|
|
|
for ( auto& texture : graphic.material.textures ) {
|
|
if ( texture.width > 1 && texture.height > 1 && texture.depth == 1 && texture.layers == 1 ) ++texture2Ds;
|
|
else if ( texture.width > 1 && texture.height > 1 && texture.depth > 1 && texture.layers == 1 ) ++texture3Ds;
|
|
}
|
|
|
|
// attach textures
|
|
for ( auto& t : textures2D ) graphic.material.textures.emplace_back().aliasTexture(t);
|
|
for ( auto& t : texturesCube ) graphic.material.textures.emplace_back().aliasTexture(t);
|
|
for ( auto& t : textures3D ) graphic.material.textures.emplace_back().aliasTexture(t);
|
|
|
|
// standard pipeline
|
|
{
|
|
uf::stl::string vertexShaderFilename = "/gltf/baking/bake.vert.spv";
|
|
uf::stl::string geometryShaderFilename = "";
|
|
uf::stl::string fragmentShaderFilename = "/gltf/baking/bake.frag.spv";
|
|
if ( uf::renderer::settings::experimental::deferredSampling ) {
|
|
fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "deferredSampling.frag" );
|
|
}
|
|
{
|
|
vertexShaderFilename = uf::io::resolveURI( vertexShaderFilename );
|
|
graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX);
|
|
}
|
|
{
|
|
fragmentShaderFilename = uf::io::resolveURI( fragmentShaderFilename );
|
|
graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT);
|
|
}
|
|
if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) {
|
|
geometryShaderFilename = uf::io::resolveURI( geometryShaderFilename );
|
|
graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY);
|
|
}
|
|
{
|
|
uint32_t maxPasses = 6;
|
|
|
|
auto& shader = graphic.material.getShader("vertex");
|
|
uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants;
|
|
ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){
|
|
uf::stl::string name = sc["name"].as<uf::stl::string>();
|
|
if ( name == "PASSES" ) sc["value"] = (specializationConstants[i] = maxPasses);
|
|
});
|
|
}
|
|
{
|
|
uint32_t maxTextures2D = texture2Ds;
|
|
uint32_t maxTexturesCube = textureCubes;
|
|
uint32_t maxTextures3D = texture3Ds;
|
|
uint32_t maxCascades = 1;
|
|
|
|
auto& shader = graphic.material.getShader("fragment");
|
|
uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants;
|
|
ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){
|
|
uf::stl::string name = sc["name"].as<uf::stl::string>();
|
|
if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D);
|
|
else if ( name == "CUBEMAPS" ) sc["value"] = (specializationConstants[i] = maxTexturesCube);
|
|
else if ( name == "CASCADES" ) sc["value"] = (specializationConstants[i] = maxCascades);
|
|
});
|
|
ext::json::forEach( shader.metadata.json["definitions"]["textures"], [&]( ext::json::Value& t ){
|
|
size_t binding = t["binding"].as<size_t>();
|
|
uf::stl::string name = t["name"].as<uf::stl::string>();
|
|
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
|
|
if ( layout.binding != binding ) continue;
|
|
if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures2D;
|
|
else if ( name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube;
|
|
else if ( name == "voxelId" ) layout.descriptorCount = maxCascades;
|
|
else if ( name == "voxelUv" ) layout.descriptorCount = maxCascades;
|
|
else if ( name == "voxelNormal" ) layout.descriptorCount = maxCascades;
|
|
else if ( name == "voxelRadiance" ) layout.descriptorCount = maxCascades;
|
|
}
|
|
});
|
|
/*
|
|
uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants;
|
|
ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){
|
|
uf::stl::string name = sc["name"].as<uf::stl::string>();
|
|
if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTexture2Ds);
|
|
});
|
|
|
|
ext::json::forEach( shader.metadata.json["definitions"]["textures"], [&]( ext::json::Value& t ){
|
|
if ( t["name"].as<uf::stl::string>() != "samplerTextures" ) return;
|
|
size_t binding = t["binding"].as<size_t>();
|
|
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
|
|
if ( layout.binding == binding ) layout.descriptorCount = maxTextures;
|
|
}
|
|
});
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
graphic.process = true;
|
|
metadata.initialized.renderMode = true;
|
|
UF_MSG_DEBUG("Graphic configured, ready to bake");
|
|
return;
|
|
}
|
|
SAVE: {
|
|
renderMode.execute = false;
|
|
UF_MSG_DEBUG("Baking...");
|
|
auto image = renderMode.screenshot();
|
|
uf::stl::string filename = metadata.names.output.map;
|
|
bool status = image.save(filename);
|
|
UF_MSG_DEBUG("Writing to " << filename << ": " << status);
|
|
UF_MSG_DEBUG("Baked.");
|
|
metadata.initialized.map = true;
|
|
|
|
{
|
|
auto& scene = uf::scene::getCurrentScene();
|
|
auto& sceneMetadata = scene.getComponent<ext::ExtSceneBehavior::Metadata>();
|
|
|
|
sceneMetadata.shadow.max = metadata.previous.max;
|
|
sceneMetadata.shadow.update = metadata.previous.update;
|
|
|
|
UF_MSG_DEBUG("Reverted shadow limits");
|
|
}
|
|
|
|
uf::Serializer payload;
|
|
payload["uid"] = this->getUid();
|
|
uf::scene::getCurrentScene().queueHook("system:Destroy", payload);
|
|
return;
|
|
}
|
|
#endif
|
|
}
|
|
void ext::BakingBehavior::render( uf::Object& self ){}
|
|
void ext::BakingBehavior::destroy( uf::Object& self ){
|
|
if ( this->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {
|
|
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
|
|
uf::renderer::removeRenderMode( &renderMode, false );
|
|
this->deleteComponent<uf::renderer::RenderTargetRenderMode>();
|
|
}
|
|
if ( this->hasComponent<pod::Graph>() ) {
|
|
auto& graph = this->getComponent<pod::Graph>();
|
|
uf::graph::destroy( graph );
|
|
}
|
|
}
|
|
#undef this |