Commit for 2020.07.23.7z

This commit is contained in:
mrq 2020-07-23 00:00:00 -05:00
parent e1736f573a
commit 958b1697f6
126 changed files with 3378 additions and 2160 deletions

View File

@ -59,7 +59,7 @@ EXT_WIN64_LIB_DIR = $(ENGINE_LIB_DIR)/win64/
EXT_WIN64_INCS = -I$(ENGINE_INC_DIR) -I$(EXT_WIN64_INC_DIR) -I$(VULKAN_WIN64_SDK_PATH)/include
EXT_WIN64_LIBS = -L$(ENGINE_LIB_DIR) -L$(EXT_WIN64_LIB_DIR) -L$(VULKAN_WIN64_SDK_PATH)/Lib
SRCS_EXT_WIN64_DLL = $(wildcard $(EXT_SRC_DIR)/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*.cpp)
SRCS_EXT_WIN64_DLL = $(wildcard $(EXT_SRC_DIR)/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*/*.cpp)
OBJS_EXT_WIN64_DLL = $(patsubst %.cpp,%.win64.o,$(SRCS_EXT_WIN64_DLL))
BASE_EXT_WIN64_DLL = lib$(EXT_LIB_NAME)
EXT_IM_WIN64_DLL = $(ENGINE_LIB_DIR)/win64/$(BASE_EXT_WIN64_DLL).dll.a

View File

@ -0,0 +1,12 @@
#version 450
layout (binding = 1) uniform sampler2D samplerTexture;
layout (location = 0) in vec2 inUv;
layout (location = 0) out vec4 outFragColor;
void main() {
outFragColor = texture(samplerTexture, inUv);
// outFragColor.a = 1.0f;
// outFragColor = vec4( inUv, 0.0f, 1.0f );
}

View File

@ -0,0 +1,17 @@
#version 450
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inUv;
layout (location = 0) out vec2 outUv;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
outUv = inUv;
gl_Position = vec4(inPos.xy, 0.0, 1.0);
}

View File

@ -0,0 +1,29 @@
#version 450
layout (binding = 1) uniform sampler2D samplerColor;
struct Gui {
vec4 offset;
vec4 color;
int mode;
float depth;
};
layout (location = 0) in vec2 inUv;
layout (location = 1) in flat Gui inGui;
layout (location = 0) out vec4 outFragColor;
void main() {
if ( inUv.x < inGui.offset.x ) discard;
if ( inUv.y < inGui.offset.y ) discard;
if ( inUv.x > inGui.offset.z ) discard;
if ( inUv.y > inGui.offset.w ) discard;
outFragColor = texture(samplerColor, inUv);// vec4(inUv.s, inUv.t, 1.0, 1.0);
if ( outFragColor.a < 0.001 ) discard;
if ( inGui.mode == 1 ) {
outFragColor = inGui.color;
} else {
outFragColor *= inGui.color;
}
}

View File

@ -0,0 +1,49 @@
#version 450
layout (binding = 1) uniform sampler2D samplerColor;
struct Gui {
vec4 offset;
vec4 color;
int mode;
float depth;
int sdf;
int shadowbox;
vec4 stroke;
float weight;
int spread;
float scale;
};
layout (location = 0) in vec2 inUv;
layout (location = 1) in flat Gui inGui;
layout (location = 0) out vec4 outFragColor;
void main() {
if ( inUv.x < inGui.offset.x ) discard;
if ( inUv.y < inGui.offset.y ) discard;
if ( inUv.x > inGui.offset.z ) discard;
if ( inUv.y > inGui.offset.w ) discard;
if ( inGui.shadowbox == 1 ) {
outFragColor = inGui.color;
return;
}
float dist = texture(samplerColor, inUv).r;
// outFragColor = mix(vec4(inGui.color) * dist, vec4(1.0f, 0.0f, 1.0f, 0.5f), 0.9);
if ( inGui.sdf == 1 ) {
float smoothing = ( inGui.spread > 0 && inGui.scale > 0 ) ? 0.25 / (inGui.spread * inGui.scale) : 0.25 / (4 * 1.5);
float outlining = smoothstep(0.5 - smoothing, 0.5 + smoothing, dist);
float alpha = smoothstep(inGui.weight - smoothing, inGui.weight + smoothing, dist);
vec4 c = inGui.color;
outFragColor = mix(inGui.stroke, c, outlining);
outFragColor.a = inGui.color.a * alpha;
if ( alpha < 0.001 ) discard;
if ( alpha > 1 ) discard;
} else {
outFragColor = vec4(inGui.color) * dist;
if ( dist < 0.001 ) discard;
if ( dist > 1 ) discard;
}
}

View File

@ -0,0 +1,44 @@
#version 450
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inUv;
layout( push_constant ) uniform PushBlock {
uint pass;
} PushConstant;
struct Matrices {
mat4 model[2];
};
struct Gui {
vec4 offset;
vec4 color;
int mode;
float depth;
int sdf;
int shadowbox;
vec4 stroke;
float weight;
int spread;
float scale;
};
layout (binding = 0) uniform UBO {
Matrices matrices;
Gui gui;
} ubo;
layout (location = 0) out vec2 outUv;
layout (location = 1) out flat Gui outGui;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
outUv = inUv;
outGui = ubo.gui;
gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(inPos.xy, ubo.gui.depth, 1.0);
}

View File

@ -0,0 +1,38 @@
#version 450
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inUv;
layout( push_constant ) uniform PushBlock {
uint pass;
} PushConstant;
struct Matrices {
mat4 model[2];
};
struct Gui {
vec4 offset;
vec4 color;
int mode;
float depth;
};
layout (binding = 0) uniform UBO {
Matrices matrices;
Gui gui;
} ubo;
layout (location = 0) out vec2 outUv;
layout (location = 1) out flat Gui outGui;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
outUv = inUv;
outGui = ubo.gui;
gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(inPos.xy, ubo.gui.depth, 1.0);
}

View File

@ -6,7 +6,7 @@
#include <uf/utils/audio/audio.h>
#include <uf/spec/terminal/terminal.h>
#include <uf/utils/hook/hook.h>
#include <uf/utils/thread/thread.h>
#include <uf/ext/vulkan/vulkan.h>
bool client::ready = false;
@ -15,7 +15,6 @@ uf::Window client::window;
uf::Serializer client::config;
void client::initialize() {
// spec::Context::globalInit();
uf::IoStream::ncurses = true;
ext::vulkan::device.window = &client::window;
/* Initialize config */ {
@ -26,29 +25,6 @@ void client::initialize() {
/* Get configuration */ {
config.ext = ext::getConfig();
}
/* Initialize default configuration */ {
config.fallback["terminal"]["visible"] = true;
config.fallback["terminal"]["ncurses"] = true;
config.fallback["window"]["title"] = "[uf] Grimgram";
config.fallback["window"]["icon"] = "./cfg/icon.png";
config.fallback["window"]["size"]["x"] = 640;
config.fallback["window"]["size"]["y"] = 480;
config.fallback["window"]["visible"] = true;
config.fallback["window"]["fullscreen"] = false;
config.fallback["cursor"]["visible"] = true;
config.fallback["keyboard"]["repeat"] = true;
config.fallback["hook"]["mode"] = "Readable";
config.fallback["light"]["ambient"]["g"] = 0.0f;
config.fallback["light"]["ambient"]["b"] = 0.0f;
config.fallback["light"]["ambient"]["a"] = 1.0f;
config.fallback["context"]["depthBits"] = 24;
config.fallback["context"]["stencilBits"] = 4;
config.fallback["context"]["bitsPerPixel"] = 8;
config.fallback["context"]["antialiasingLevel"] = 0;
config.fallback["context"]["majorVersion"] = 3;
config.fallback["context"]["minorVersion"] = 0;
}
/* Merge */ {
client::config = config.ext;
client::config.merge( config.fallback, true );
@ -65,32 +41,24 @@ void client::initialize() {
title = client::config["window"]["title"].asString();
}
// Terminal window;
spec::terminal.setVisible( client::config["terminal"]["visible"].asBool() );
spec::terminal.setVisible( client::config["window"]["terminal"]["visible"].asBool() );
// Ncurses
uf::IoStream::ncurses = client::config["terminal"]["ncurses"].asBool();
uf::IoStream::ncurses = client::config["window"]["terminal"]["ncurses"].asBool();
// Window's context settings
spec::Context::Settings settings; {
settings.depthBits = client::config["context"]["depthBits"].asUInt();
settings.stencilBits = client::config["context"]["stencilBits"].asUInt();
settings.bitsPerPixel = client::config["context"]["bitsPerPixel"].asUInt();
settings.antialiasingLevel = client::config["context"]["antialiasingLevel"].asUInt();
settings.majorVersion = client::config["context"]["majorVersion"].asUInt();
settings.minorVersion = client::config["context"]["minorVersion"].asUInt();
}
ext::vulkan::width = size.x;
ext::vulkan::height = size.y;
client::window.create( size, title, settings );
client::window.create( size, title );
// Miscellaneous
client::window.setVisible(client::config["window"]["visible"].asBool());
client::window.setCursorVisible(client::config["cursor"]["visible"].asBool());
client::window.setKeyRepeatEnabled(client::config["keyboard"]["repeat"].asBool());
client::window.setCursorVisible(client::config["window"]["cursor"]["visible"].asBool());
client::window.setKeyRepeatEnabled(client::config["window"]["keyboard"]["repeat"].asBool());
// client::window.centerWindow();
// client::window.setPosition({0, 0});
// client::window.setMouseGrabbed(true);
/* Set Icon */ {
/* Set Icon */ if ( client::config["window"]["icon"].isString() ) {
uf::Image icon;
icon.open(client::config["window"]["icon"].asString());
client::window.setIcon({(int) icon.getDimensions().x, (int) icon.getDimensions().y}, ((uint8_t*)icon.getPixelsPtr()));
@ -104,23 +72,7 @@ void client::initialize() {
uf::hooks.call( hook, json );
}
uf::hooks.shouldPreferReadable();
if ( client::config["hook"]["mode"] == "Readable" ) {}
}
/* Initialize OpenGL */ {
/*
if ( !ext::gl.initialize() ) {
std::cerr << "[ERROR] GL failed to initialize!" << std::endl;
std::exit(EXIT_SUCCESS);
return;
}
pod::Vector4f ambient;
ambient.x = client::config["light"]["ambient"]["r"].asDouble();
ambient.y = client::config["light"]["ambient"]["g"].asDouble();
ambient.z = client::config["light"]["ambient"]["b"].asDouble();
ambient.w = client::config["light"]["ambient"]["a"].asDouble();
glClearColor(ambient.x, ambient.y, ambient.z, ambient.w);
*/
if ( client::config["engine"]["hook"]["mode"] == "Readable" ) {}
}
/* Initialize OpenAL */ {
@ -132,12 +84,13 @@ void client::initialize() {
}
/* Initialize hooks */ {
if ( client::config["hook"]["mode"] == "Both" || client::config["hook"]["mode"] == "Readable" ) {
if ( client::config["engine"]["hook"]["mode"] == "Both" || client::config["engine"]["hook"]["mode"] == "Readable" ) {
uf::hooks.addHook( "window:Mouse.CursorVisibility", [&](const std::string& event)->std::string{
uf::Serializer json = event;
client::window.setCursorVisible(json["state"].asBool());
client::window.setMouseGrabbed(!json["state"].asBool());
client::config["mouse"]["visible"] = json["state"].asBool();
client::config["window"]["mouse"]["center"] = !json["state"].asBool();
return "true";
});
uf::hooks.addHook( "window:Mouse.Lock", [&](const std::string& event)->std::string{
@ -170,17 +123,13 @@ void client::initialize() {
client::window.setSize(size);
}
// Update viewport
// glViewport( 0, 0, size.x, size.y );
// client::window.centerWindow();
ext::vulkan::width = size.x;
ext::vulkan::height = size.y;
ext::vulkan::swapchain.rebuild = true;
return "true";
} );
} else if ( client::config["hook"]["mode"] == "Both" || client::config["hook"]["mode"] == "Optimal" ) {
} else if ( client::config["engine"]["hook"]["mode"] == "Both" || client::config["engine"]["hook"]["mode"] == "Optimal" ) {
uf::hooks.addHook( "window:Closed", [&](const uf::OptimalHook::argument_t& userdata)->uf::OptimalHook::return_t{
client::ready = false;
std::exit(EXIT_SUCCESS);
@ -218,7 +167,6 @@ void client::initialize() {
client::window.setSize(hook.window.size);
}
// Update viewport
// glViewport( 0, 0, hook.window.size.x, hook.window.size.y );
return NULL;
} );
}
@ -231,11 +179,11 @@ void client::tick() {
client::window.pollEvents();
// call mouse move
// query lock
if ( client::window.hasFocus() && !client::config["mouse"]["visible"].asBool() ) {
if ( client::window.hasFocus() && client::config["window"]["mouse"]["center"].asBool() ) {
auto previous = client::window.getMousePosition();
client::window.setMousePosition(client::window.getSize()/2);
auto current = client::window.getMousePosition();
// std::cout << "Delta: (" << current.x - previous.x << ", " << current.y - previous.y << ")" << std::endl;
auto size = client::window.getSize();
uf::Serializer payload;
payload["invoker"] = "client";
@ -280,7 +228,6 @@ void client::render() {
client::window.display();
}
#include <uf/utils/thread/thread.h>
void client::terminate() {
/* Close Threads */ {
uf::thread::terminate();
@ -291,7 +238,6 @@ void client::terminate() {
}
client::window.terminate();
// spec::Context::globalCleanup();
if ( !ext::oal.terminate() ) {
std::cerr << "[ERROR] AL failed to terminate!" << std::endl;

View File

@ -3,11 +3,6 @@
#include <uf/utils/io/iostream.h>
#include <uf/utils/time/time.h>
#include <uf/utils/math/quaternion.h>
// #include <uf/utils/math/glm.h>
#include <uf/engine/entity/entity.h>
int main(int argc, char** argv){
std::atexit([]{
uf::iostream << "Termination via std::atexit()!" << "\n";

View File

@ -7,8 +7,8 @@
#include <unordered_map>
#include <functional>
namespace ext {
class Asset : public uf::Entity {
namespace uf {
class UF_API Asset : public uf::Entity {
protected:
static uf::Entity masterAssetLoader;
public:

View File

@ -1,15 +1,15 @@
#pragma once
#include "./asset.h"
#include <uf/engine/asset/asset.h>
namespace ext {
class MasterData {
namespace uf {
class UF_API MasterData {
protected:
std::string m_table;
std::string m_key;
uf::Serializer m_data;
static ext::Asset assetLoader;
static uf::Asset assetLoader;
static std::string root;
public:
uf::Serializer load( const std::string&, size_t );

View File

@ -4,6 +4,7 @@
#include <uf/utils/component/component.h>
#include <uf/utils/serialize/serializer.h>
#include <vector>
#include <functional>
namespace uf {
class UF_API Entity : public uf::Component {
@ -53,6 +54,10 @@ namespace uf {
uf::Entity* findByUid( std::size_t id );
const uf::Entity* findByName( const std::string& name ) const;
const uf::Entity* findByUid( std::size_t id ) const;
void process( std::function<void(uf::Entity*)> );
void process( std::function<void(uf::Entity*, int)>, int depth = 0 );
// void process( std::function<void(const uf::Entity*)> ) const ;
// void process( std::function<void(const uf::Entity*, int)>, int depth = 0 ) const;
static uf::Entity* globalFindByName( const std::string& name );
};

View File

@ -0,0 +1,52 @@
#pragma once
#include <uf/config.h>
#include <uf/engine/entity/entity.h>
#include <uf/utils/singletons/pre_main.h>
#include <unordered_map>
#include <typeindex>
#include <functional>
#define NAMESPACE_CONCAT
#define UF_OBJECT_REGISTER_CPP( OBJ ) \
namespace {\
static uf::StaticInitialization REGISTER_UF_ ## OBJ( []{\
uf::instantiator::add<uf::OBJ>( #OBJ );\
});\
}
#define EXT_OBJECT_REGISTER_CPP( OBJ ) \
namespace {\
static uf::StaticInitialization REGISTER_EXT_ ## OBJ( []{\
uf::instantiator::add<ext::OBJ>( #OBJ );\
});\
}
namespace uf {
namespace instantiator {
typedef std::function<uf::Entity*()> function_t;
extern UF_API std::unordered_map<std::type_index, std::string>* names;
extern UF_API std::unordered_map<std::string, function_t>* map;
template<typename T>
void add( const std::string& name ) {
if ( !names ) names = new std::unordered_map<std::type_index, std::string>;
if ( !map ) map = new std::unordered_map<std::string, function_t>;
auto& names = *uf::instantiator::names;
auto& map = *uf::instantiator::map;
names[std::type_index(typeid(T))] = name;
map[name] = [](){
return new T;
};
std::cout << "Registered instantiation for " << name << std::endl;
}
uf::Entity* UF_API instantiate( const std::string& );
template<typename T>
T& instantiate() {
auto& names = *uf::instantiator::names;
return *((T*) uf::instantiator::instantiate( names[std::type_index(typeid(T))] ));
}
};
}

View File

@ -1,19 +1,13 @@
#pragma once
#include <uf/config.h>
#include <uf/ext/ext.h>
#include <uf/engine/entity/entity.h>
#include <uf/utils/camera/camera.h>
#include <uf/utils/math/transform.h>
#include <uf/utils/math/physics.h>
#include <uf/utils/math/collision.h>
#include <uf/utils/thread/thread.h>
#include <uf/engine/instantiator/instantiator.h>
#include <uf/utils/hook/hook.h>
#include <typeindex>
#include <functional>
namespace ext {
class EXT_API Object : public uf::Entity {
namespace uf {
class UF_API Object : public uf::Entity {
public:
virtual void initialize();
virtual void destroy();

View File

@ -0,0 +1,36 @@
#pragma once
#include <uf/engine/object/object.h>
namespace uf {
class UF_API Scene : public uf::Object {
protected:
// void* m_graphics;
public:
virtual void initialize();
virtual void tick();
virtual void render();
virtual void destroy();
virtual uf::Entity* getController();
virtual const uf::Entity* getController() const;
template<typename T> T& getController() {
return *((T*) this->getController());
}
template<typename T> const T& getController() const {
return *((const T*) this->getController());
}
};
namespace scene {
extern UF_API std::vector<uf::Scene*> scenes;
Scene& UF_API getCurrentScene();
Scene& UF_API loadScene( const std::string& name, const std::string data = "" );
void UF_API unloadScene();
void UF_API tick();
void UF_API render();
void UF_API destroy();
}
}

View File

@ -1,21 +0,0 @@
#pragma once
#include <uf/ext/vulkan/device.h>
namespace ext {
namespace vulkan {
struct UF_API Command {
uint32_t width, height;
// RAII
virtual const std::string& getName() const;
virtual size_t subpasses() const;
virtual void initialize( Device& device );
virtual void createCommandBuffers();
virtual void createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes );
virtual void render();
virtual void destroy();
virtual VkRenderPass& getRenderPass();
};
}
}

View File

@ -1,22 +0,0 @@
#pragma once
#include <uf/ext/vulkan/device.h>
#include <uf/ext/vulkan/rendertarget.h>
namespace ext {
namespace vulkan {
struct UF_API MultiviewCommand : public ext::vulkan::Command {
struct {
ext::vulkan::RenderTarget left;
ext::vulkan::RenderTarget right;
} framebuffers;
// RAII
virtual const std::string& getName() const;
virtual void createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes );
virtual void render();
virtual void initialize( Device& device );
virtual void destroy();
};
}
}

View File

@ -19,6 +19,8 @@ namespace ext {
VkPhysicalDeviceFeatures enabledFeatures;
VkPhysicalDeviceMemoryProperties memoryProperties;
VkPipelineCache pipelineCache;
std::vector<VkQueueFamilyProperties> queueFamilyProperties;
std::vector<const char*> supportedExtensions;
@ -28,6 +30,12 @@ namespace ext {
uf::Window* window;
struct {
VkFormat depth;
VkFormat color;
VkColorSpaceKHR space;
} formats;
struct QueueFamilyIndices {
uint32_t graphics;
uint32_t present;

View File

@ -4,9 +4,11 @@
#include <uf/ext/vulkan/swapchain.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/ext/vulkan/texture.h>
#include <uf/ext/vulkan/rendermodes/base.h>
namespace ext {
namespace vulkan {
struct RenderMode;
struct UF_API Graphic {
VkPipeline pipeline;
VkPipelineLayout pipelineLayout;
@ -21,7 +23,7 @@ namespace ext {
std::vector<Buffer> buffers;
Device* device = VK_NULL_HANDLE;
Swapchain* swapchain = VK_NULL_HANDLE;
RenderMode* renderMode = VK_NULL_HANDLE;
bool autoAssigned = false;
bool initialized = false;
@ -65,7 +67,8 @@ namespace ext {
void initializeDescriptorSet( const std::vector<VkWriteDescriptorSet>& writeDescriptorSets );
// RAII
virtual void initialize( Device& device, Swapchain& swapchain );
virtual void initialize( const std::string& = "" );
virtual void initialize( Device& device, RenderMode& renderMode );
virtual void destroy();
virtual void autoAssign();
virtual bool autoAssignable() const;

View File

@ -53,7 +53,8 @@ namespace ext {
virtual bool autoAssignable() const;
virtual std::string name() const;
// RAII
virtual void initialize( Device& device, Swapchain& swapchain );
virtual void initialize( const std::string& = "" );
virtual void initialize( Device& device, RenderMode& renderMode );
virtual void destroy();
};
}

View File

@ -50,7 +50,7 @@ namespace ext {
virtual void createCommandBuffer( VkCommandBuffer );
virtual std::string name() const;
// RAII
void initialize( Device& device, Swapchain& swapchain, uint32_t width = 0, uint32_t height = 0 );
void initialize( Device& device, RenderMode& renderMode, uint32_t width = 0, uint32_t height = 0 );
virtual void destroy();
};
}
@ -70,7 +70,8 @@ namespace ext {
virtual bool autoAssignable() const;
virtual std::string name() const;
// RAII
virtual void initialize( Device& device, Swapchain& swapchain );
virtual void initialize( const std::string& = "" );
virtual void initialize( Device& device, RenderMode& renderMode );
virtual void render();
virtual void destroy();
};

View File

@ -29,7 +29,8 @@ namespace ext {
virtual bool autoAssignable() const;
virtual std::string name() const;
// RAII
virtual void initialize( Device& device, Swapchain& swapchain );
virtual void initialize( const std::string& = "" );
virtual void initialize( Device& device, RenderMode& renderMode );
virtual void destroy();
};
}

View File

@ -38,7 +38,8 @@ namespace ext {
virtual bool autoAssignable() const;
virtual std::string name() const;
// RAII
virtual void initialize( Device& device, Swapchain& swapchain );
virtual void initialize( const std::string& = "" );
virtual void initialize( Device& device, RenderMode& renderMode );
virtual void destroy();
};
}

View File

@ -32,7 +32,8 @@ namespace ext {
virtual bool autoAssignable() const;
virtual std::string name() const;
// RAII
virtual void initialize( Device& device, Swapchain& swapchain );
virtual void initialize( const std::string& = "" );
virtual void initialize( Device& device, RenderMode& renderMode );
virtual void destroy();
};
}

View File

@ -0,0 +1,37 @@
#pragma once
#include <uf/ext/vulkan/device.h>
#include <uf/ext/vulkan/swapchain.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/ext/vulkan/graphic.h>
#include <uf/ext/vulkan/texture.h>
#include <uf/ext/vulkan/rendertarget.h>
#include <uf/utils/math/matrix.h>
namespace ext {
namespace vulkan {
struct UF_API RenderTargetGraphic : public Graphic {
struct Vertex {
alignas(16) pod::Vector2f position;
alignas(16) pod::Vector2f uv;
};
struct {
alignas(16) pod::Vector2f screenSize;
} uniforms;
uint32_t indices = 0;
VkSampler sampler;
ext::vulkan::RenderTarget* framebuffer;
virtual void createCommandBuffer( VkCommandBuffer );
virtual bool autoAssignable() const;
virtual std::string name() const;
// RAII
virtual void initialize( const std::string& = "" );
virtual void initialize( Device& device, RenderMode& renderMode );
virtual void destroy();
};
}
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <uf/ext/vulkan/device.h>
namespace ext {
namespace vulkan {
struct Graphic;
struct UF_API RenderMode {
uint32_t width = 0, height = 0;
std::string name = "";
Device* device = VK_NULL_HANDLE;
// virtual ~RenderMode();
// RAII
virtual std::string getType() const;
const std::string& getName() const;
virtual size_t subpasses() const;
virtual void initialize( Device& device );
virtual void createCommandBuffers();
virtual void createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics, const std::vector<std::string>& passes );
virtual void render();
virtual void destroy();
virtual VkRenderPass& getRenderPass();
virtual ext::vulkan::RenderTarget& getRenderTarget();
};
}
}

View File

@ -6,19 +6,20 @@
namespace ext {
namespace vulkan {
struct UF_API DeferredCommand : public ext::vulkan::Command {
ext::vulkan::RenderTarget framebuffer;
struct UF_API DeferredRenderMode : public ext::vulkan::RenderMode {
ext::vulkan::RenderTarget renderTarget;
ext::vulkan::FramebufferGraphic blitter;
// RAII
virtual const std::string& getName() const;
virtual std::string getType() const;
virtual size_t subpasses() const;
virtual void createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes );
virtual void render();
virtual void createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics, const std::vector<std::string>& passes );
virtual void initialize( Device& device );
virtual void destroy();
virtual VkRenderPass& getRenderPass();
virtual ext::vulkan::RenderTarget& getRenderTarget();
};
}
}

View File

@ -6,22 +6,23 @@
namespace ext {
namespace vulkan {
struct UF_API MultiviewCommand : public ext::vulkan::Command {
struct UF_API MultiviewRenderMode : public ext::vulkan::RenderMode {
struct {
ext::vulkan::RenderTarget left;
ext::vulkan::RenderTarget right;
} framebuffers;
} renderTargets;
ext::vulkan::FramebufferGraphic blitter;
// RAII
virtual const std::string& getName() const;
virtual std::string getType() const;
virtual size_t subpasses() const;
virtual void createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes );
virtual void render();
virtual void createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics, const std::vector<std::string>& passes );
virtual void initialize( Device& device );
virtual void destroy();
virtual VkRenderPass& getRenderPass();
virtual ext::vulkan::RenderTarget& getRenderTarget();
};
}
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <uf/ext/vulkan/device.h>
#include <uf/ext/vulkan/rendertarget.h>
#include <uf/ext/vulkan/graphics/rendertarget.h>
namespace ext {
namespace vulkan {
struct UF_API RenderTargetRenderMode : public ext::vulkan::RenderMode {
ext::vulkan::RenderTarget renderTarget;
ext::vulkan::RenderTargetGraphic blitter;
VkFence fence;
VkCommandBuffer commandBuffer;
// RAII
virtual std::string getType() const;
virtual size_t subpasses() const;
virtual void createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics, const std::vector<std::string>& passes );
virtual void initialize( Device& device );
virtual void destroy();
virtual void render();
virtual VkRenderPass& getRenderPass();
virtual ext::vulkan::RenderTarget& getRenderTarget();
};
}
}

View File

@ -25,10 +25,10 @@ namespace ext {
} Subpass;
std::vector<Subpass> passes;
Device* device = nullptr;
VkRenderPass renderPass;
bool initialized = false;
Device* device = VK_NULL_HANDLE;
VkRenderPass renderPass = VK_NULL_HANDLE;
std::vector<VkFramebuffer> framebuffers;
bool commandBufferSet;
// RAII
void initialize( Device& device );
void destroy();

View File

@ -1,27 +1,15 @@
#pragma once
#include <uf/ext/vulkan/device.h>
#include <uf/ext/vulkan/rendertarget.h>
namespace ext {
namespace vulkan {
struct UF_API Swapchain {
typedef struct {
VkImage image;
VkImageView view;
} SwapChainBuffer;
Device* device = nullptr;
VkSurfaceKHR surface;
VkFormat colorFormat;
VkColorSpaceKHR colorSpace;
/** @brief Handle to the current swap chain, required for recreation */
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
uint32_t imageCount;
std::vector<VkImage> images;
std::vector<SwapChainBuffer> buffers;
/** @brief Queue family index of the detected graphics and presenting device queue */
uint32_t queueNodeIndex = UINT32_MAX;
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
VkSemaphore presentCompleteSemaphore;
VkSemaphore renderCompleteSemaphore;
@ -29,21 +17,9 @@ namespace ext {
bool commandBufferSet = false;
std::vector<VkCommandBuffer> drawCommandBuffers;
VkSubmitInfo submitInfo;
VkRenderPass renderPass;
VkPipelineCache pipelineCache;
VkFormat depthFormat;
struct {
VkImage image;
VkDeviceMemory mem;
VkImageView view;
} depthStencil;
std::vector<VkFramebuffer> frameBuffers;
bool rebuild = false;
bool vsync = true;
uint32_t buffers;
// helpers
VkResult acquireNextImage( uint32_t *imageIndex );

View File

@ -19,7 +19,8 @@ namespace ext {
uint32_t mips;
uint32_t layers;
VkDescriptorImageInfo descriptor;
VkSampler sampler; // optional
VkSampler sampler;
VkFilter filter = VK_FILTER_NEAREST;
// RAII
void initialize( Device& device, size_t width, size_t height );
void updateDescriptors();
@ -44,6 +45,13 @@ namespace ext {
);
};
struct UF_API Texture2D : public Texture {
void loadFromFile(
std::string filename,
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
bool forceLinear = false
);
void loadFromFile(
std::string filename,
Device& device,
@ -62,6 +70,13 @@ namespace ext {
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
bool forceLinear = false
);
void loadFromImage(
uf::Image& image,
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
bool forceLinear = false
);
void fromBuffers(
void* buffer,
VkDeviceSize bufferSize,

View File

@ -4,7 +4,9 @@
#include <uf/ext/vulkan/device.h>
#include <uf/ext/vulkan/swapchain.h>
#include <uf/ext/vulkan/graphic.h>
#include <uf/ext/vulkan/commands/base.h>
#include <uf/ext/vulkan/rendermodes/base.h>
#include <uf/engine/scene/scene.h>
namespace ext {
namespace vulkan {
@ -33,26 +35,28 @@ namespace ext {
uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties);
typedef VmaAllocator Allocator;
extern UF_API Allocator allocator;
extern UF_API Device device;
extern UF_API Swapchain swapchain;
// extern UF_API std::vector<Graphic*> graphics;
extern UF_API std::vector<Graphic*>* graphics;
extern UF_API std::vector<std::string> passes;
extern UF_API std::string currentPass;
extern UF_API bool resizedFramebuffer;
extern UF_API uint32_t width;
extern UF_API uint32_t height;
extern UF_API bool validation;
extern UF_API bool openvr;
extern UF_API std::mutex mutex;
extern UF_API uint32_t currentBuffer;
extern UF_API Command* command;
void createCommandBuffers();
void createCommandBuffers( const std::vector<void*>&, const std::vector<uint32_t>& );
extern UF_API bool validation;
extern UF_API Device device;
typedef VmaAllocator Allocator;
extern UF_API Allocator allocator;
extern UF_API Swapchain swapchain;
extern UF_API std::mutex mutex;
extern UF_API bool resizedFramebuffer;
extern UF_API uint32_t currentBuffer;
extern UF_API std::string currentPass;
extern UF_API std::vector<std::string> passes;
// extern UF_API std::vector<Graphic*>* graphics;
extern UF_API std::vector<RenderMode*> renderModes;
extern UF_API std::vector<uf::Scene*> scenes;
RenderMode& UF_API addRenderMode( RenderMode*, const std::string& = "" );
RenderMode& UF_API getRenderMode( const std::string& );
void UF_API initialize( uint8_t = 0 );
void UF_API tick();

View File

@ -11,6 +11,7 @@ namespace pod {
struct UF_API Component {
typedef std::size_t id_t;
typedef std::unordered_map<pod::Component::id_t, pod::Component> container_t;
typedef std::unordered_map<pod::Component::id_t, pod::Component::id_t> alias_t;
pod::Component::id_t id;
pod::Userdata* userdata;
@ -26,9 +27,12 @@ namespace uf {
protected:
static const bool m_addOn404 = true;
pod::Component::container_t m_container;
pod::Component::alias_t m_aliases;
public:
~Component();
template<typename T> bool hasAlias() const;
template<typename T, typename U> bool addAlias();
template<typename T> pod::Component::id_t getType() const;
template<typename T> bool hasComponent() const;

View File

@ -6,9 +6,20 @@ template<typename T> bool uf::component::is( const pod::Component& component ) {
}
//
//
//
// GuiMesh -> MeshBase
template<typename T>
bool uf::Component::hasAlias() const {
return this->m_aliases.count(uf::component::type<T>()) != 0;
}
template<typename T, typename U>
bool uf::Component::addAlias() {
if ( this->hasAlias<T>() ) return false;
this->m_aliases[uf::component::type<T>()] = this->getType<U>();
return true;
}
template<typename T>
pod::Component::id_t uf::Component::getType() const {
if ( this->hasAlias<T>() ) return this->m_aliases.at(uf::component::type<T>());
return uf::component::type<T>();
}

View File

@ -106,7 +106,7 @@ namespace uf {
const pod::Transform<T>* pointer = &transform;
while ( pointer ) {
// if ( invert ) combined.position -= pointer->position; else combined.position += pointer->position;
combined.position += pointer->position;
combined.position = combined.position + pointer->position;
combined.orientation = invert ? uf::quaternion::multiply( pointer->orientation, combined.orientation ) : uf::quaternion::multiply( combined.orientation, pointer->orientation );
pointer = pointer->reference;
}

View File

@ -86,22 +86,48 @@ namespace std {
}
};
}
namespace uf {
struct UF_API MeshBase {
public:
ext::vulkan::BaseGraphic graphic;
bool generated = false;
};
template<typename T>
struct UF_API BaseMesh {
class UF_API BaseMesh : public MeshBase {
public:
typedef T vertex_t;
ext::vulkan::BaseGraphic graphic;
std::vector<vertex_t> vertices;
std::vector<uint32_t> indices;
bool generated = false;
~BaseMesh();
void initialize( bool compress = true );
void destroy( bool clear = true );
~BaseMesh();
};
}
/*
namespace uf {
class UF_API Graphic {
public:
ext::vulkan::BaseGraphic graphic;
bool generated = false;
virtual ~Graphic();
virtual void initialize( bool compress = true ) = 0;
virtual void destroy( bool clear = true ) = 0;
};
template<typename T>
class UF_API BaseMesh : public Graphic {
public:
typedef T vertex_t;
std::vector<vertex_t> vertices;
std::vector<uint32_t> indices;
virtual void initialize( bool compress = true );
virtual void destroy( bool clear = true );
};
}
*/
#include "mesh.inl"
namespace uf {

View File

@ -3,6 +3,9 @@
#include <uf/config.h>
#include <json/json.h>
#include <string>
#include <type_traits>
#include <uf/utils/userdata/userdata.h>
namespace uf {
class UF_API Serializer : public Json::Value {
@ -17,6 +20,39 @@ namespace uf {
Serializer::output_t serialize() const;
void deserialize( const std::string& );
// serializeable
template<typename T>
static bool serializeable() {
return std::is_pod<T>::value;
}
template<typename T>
static bool serializeable( const T& input ) {
return serializeable<T>();
}
// serialize to base64
template<typename T>
static uf::Serializer toBase64( const T& input ) {
// ensure this is a safe type to serialize
if ( !serializeable(input) ) return "";
pod::Userdata* userdata = uf::userdata::create(input);
uf::Serializer res;
res["base64"] = uf::userdata::toBase64( userdata );
uf::userdata::destroy( userdata );
return res;
}
// convert from base64 to POD
template<typename T>
static T fromBase64( const uf::Serializer& input ) {
// ensure this is a safe type to serialize
if ( !serializeable(input) ) return T();
// ensure it's "proper"
if ( !input["base64"].isString() ) return T();
pod::Userdata* userdata = uf::userdata::fromBase64(input["base64"].asString());
T res = uf::userdata::get<T>( userdata );
uf::userdata::destroy( userdata );
return res;
}
bool readFromFile( const std::string& from );
bool writeToFile( const std::string& to ) const;

View File

@ -0,0 +1,11 @@
#pragma once
#include <uf/config.h>
#include <functional>
namespace uf {
struct UF_API StaticInitialization {
public:
StaticInitialization(std::function<void()>);
};
}

View File

@ -3,6 +3,7 @@
#include <uf/config.h>
#include <stdint.h>
#include <cstddef>
#include <string>
#include <algorithm>
namespace pod {
@ -21,6 +22,9 @@ namespace uf {
template<typename T> T& get( pod::Userdata* userdata, bool validate = true);
template<typename T> const T& get(const pod::Userdata* userdata);
std::string UF_API toBase64( pod::Userdata* userdata );
pod::Userdata* UF_API fromBase64( const std::string& base64 );
// void move( pod::Userdata& to, pod::Userdata&& from );
// void copy( pod::Userdata& to, const pod::Userdata& from );
}

View File

@ -1,4 +1,4 @@
#include "asset.h"
#include <uf/engine/asset/asset.h>
#include <regex>
#include <functional>
#include <iomanip>
@ -76,9 +76,9 @@ namespace {
*/
}
uf::Entity ext::Asset::masterAssetLoader;
uf::Entity uf::Asset::masterAssetLoader;
void ext::Asset::processQueue() {
void uf::Asset::processQueue() {
mutex.lock();
while ( !jobs.empty() ) {
auto job = jobs.front();
@ -98,7 +98,7 @@ void ext::Asset::processQueue() {
}
mutex.unlock();
}
void ext::Asset::cache( const std::string& uri, const std::string& callback ) {
void uf::Asset::cache( const std::string& uri, const std::string& callback ) {
mutex.lock();
jobs.push({ uri, callback, "cache" });
mutex.unlock();
@ -122,7 +122,7 @@ void ext::Asset::cache( const std::string& uri, const std::string& callback ) {
return 0;}, true );
*/
}
void ext::Asset::load( const std::string& uri, const std::string& callback ) {
void uf::Asset::load( const std::string& uri, const std::string& callback ) {
mutex.lock();
jobs.push({ uri, callback, "load" });
mutex.unlock();
@ -144,7 +144,7 @@ void ext::Asset::load( const std::string& uri, const std::string& callback ) {
return 0;}, true );
*/
}
std::string ext::Asset::cache( const std::string& uri ) {
std::string uf::Asset::cache( const std::string& uri ) {
std::string filename = uri;
std::string extension = uf::string::extension( uri );
if ( uri.substr(0,5) == "https" ) {
@ -162,7 +162,7 @@ std::string ext::Asset::cache( const std::string& uri ) {
}
return filename;
}
std::string ext::Asset::load( const std::string& uri ) {
std::string uf::Asset::load( const std::string& uri ) {
std::string filename = uri;
std::string extension = uf::string::extension( uri );
if ( uri.substr(0,5) == "https" ) {
@ -219,7 +219,7 @@ std::string ext::Asset::load( const std::string& uri ) {
}
return filename;
}
std::string ext::Asset::getOriginal( const std::string& uri ) {
std::string uf::Asset::getOriginal( const std::string& uri ) {
std::string extension = uf::string::extension( uri );
auto& map = masterAssetLoader.getComponent<uf::Serializer>();
if ( map[extension][uri].isNull() ) return uri;

View File

@ -0,0 +1,31 @@
#include <uf/engine/asset/masterdata.h>
#include <iostream>
//std::string uf::MasterData::root = "https://el..xyz/mastertable/get/%TABLE%/%KEY%?.json";
std::string uf::MasterData::root = "./data/master/%TABLE%.json";
uf::Asset uf::MasterData::assetLoader;
uf::Serializer uf::MasterData::load( const std::string& table, size_t key ) {
return this->load( table, std::to_string(key) );
}
uf::Serializer uf::MasterData::load( const std::string& table, const std::string& key ) {
this->m_table = table;
this->m_key = key;
std::string url = uf::string::replace( root, "%TABLE%", table );
url = uf::string::replace( url, "%KEY%", key );
std::string filename = assetLoader.cache(url);
if ( filename != "" ) this->m_data.readFromFile(filename);
return this->get();
}
uf::Serializer uf::MasterData::get( const std::string& key ) const {
std::string k = (key == "" ? this->m_key : key);
if ( k != "" ) return this->m_data[k];
return this->m_data;
}
const std::string& uf::MasterData::tableName() const {
return this->m_table;
}
const std::string& uf::MasterData::keyName() const {
return this->m_key;
}

View File

@ -68,10 +68,14 @@ void uf::Entity::destroy(){
}
this->m_children.clear();
auto it = std::find( uf::Entity::entities.begin(), uf::Entity::entities.end(), this );
if ( it != uf::Entity::entities.end() ) {
*it = NULL;
{
auto it = std::find(uf::Entity::entities.begin(), uf::Entity::entities.end(), this);
if ( it != uf::Entity::entities.end() ) {
uf::Entity::entities.erase(it);
// *it = NULL;
}
}
this->m_uid = 0;
}
void uf::Entity::tick(){
@ -123,6 +127,36 @@ const uf::Entity* uf::Entity::findByUid( std::size_t id ) const {
return (const uf::Entity*) NULL;
};
void uf::Entity::process( std::function<void(uf::Entity*)> fn ) {
fn(this);
for ( uf::Entity* entity : this->getChildren() ) {
if ( !entity ) continue;
entity->process(fn);
}
}
void uf::Entity::process( std::function<void(uf::Entity*, int)> fn, int depth ) {
fn(this, depth);
for ( uf::Entity* entity : this->getChildren() ) {
if ( !entity ) continue;
entity->process(fn, depth + 1);
}
}
/*
void uf::Entity::process( std::function<void(const uf::Entity*)> fn ) const {
fn(this);
for ( uf::Entity* entity : this->getChildren() ) {
if ( !entity ) continue;
entity->process(fn);
}
}
void uf::Entity::process( std::function<void(const uf::Entity*, int)> fn, int depth ) const {
fn(this, depth);
for ( uf::Entity* entity : this->getChildren() ) {
if ( !entity ) continue;
entity->process(fn, depth + 1);
}
}
*/
uf::Entity* uf::Entity::globalFindByName( const std::string& name ) {
for ( uf::Entity* e : uf::Entity::entities ) {
if ( !e ) continue;

View File

@ -0,0 +1,13 @@
#include <uf/engine/instantiator/instantiator.h>
#include <assert.h>
std::unordered_map<std::type_index, std::string>* uf::instantiator::names = NULL;
std::unordered_map<std::string, uf::instantiator::function_t>* uf::instantiator::map = NULL;
uf::Entity* uf::instantiator::instantiate( const std::string& name ) {
auto& map = *uf::instantiator::map;
// assert it's already in map
assert( map.count(name) > 0 );
std::cout << "Instantiating " << name << std::endl;
return map[name]();
}

View File

@ -0,0 +1,421 @@
#include <uf/engine/object/object.h>
#include <uf/engine/asset/asset.h>
#include <uf/engine/scene/scene.h>
#include <uf/utils/time/time.h>
#include <uf/utils/math/transform.h>
namespace {
uf::Timer<long long> timer(false);
}
UF_OBJECT_REGISTER_CPP(Object)
void uf::Object::initialize() {
uf::Entity::initialize();
}
void uf::Object::destroy() {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
for( Json::Value::iterator it = metadata["system"]["hooks"]["alloc"].begin() ; it != metadata["system"]["hooks"]["alloc"].end() ; ++it ) {
std::string name = it.key().asString();
for ( size_t i = 0; i < metadata["system"]["hooks"]["alloc"][name].size(); ++i ) {
size_t id = metadata["system"]["hooks"]["alloc"][name][(int) i].asUInt();
uf::hooks.removeHook(name, id);
}
}
uf::Entity::destroy();
}
void uf::Object::tick() {
uf::Entity::tick();
// Call queued hooks
{
if ( !timer.running() ) timer.start();
float curTime = timer.elapsed().asDouble();
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
uf::Serializer newQueue = Json::Value(Json::arrayValue);
for ( auto& member : metadata["system"]["hooks"]["queue"] ) {
uf::Serializer payload = member["payload"];
std::string name = member["name"].asString();
float timeout = member["timeout"].asFloat();
if ( timeout < curTime ) {
this->callHook( name, payload );
} else {
newQueue.append(member);
}
}
if ( metadata.isObject() ) metadata["system"]["hooks"]["queue"] = newQueue;
}
}
void uf::Object::render() {
uf::Entity::render();
}
void uf::Object::queueHook( const std::string& name, const std::string& payload, double timeout ) {
if ( !timer.running() ) timer.start();
float start = timer.elapsed().asDouble();
uf::Serializer queue;
queue["name"] = name;
queue["payload"] = uf::Serializer{payload};
queue["timeout"] = start + timeout;
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
metadata["system"]["hooks"]["queue"].append(queue);
}
std::vector<std::string> uf::Object::callHook( const std::string& n, const std::string& payload ) {
std::string name = uf::string::replace( n, "%UID%", std::to_string(this->getUid()) );
return uf::hooks.call( name, payload );
}
std::size_t uf::Object::addHook( const std::string& name, const uf::HookHandler::Readable::function_t& callback ) {
std::string parsed = uf::string::replace( name, "%UID%", std::to_string(this->getUid()) );
std::size_t id = uf::hooks.addHook( parsed, callback );
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
metadata["system"]["hooks"]["alloc"][parsed].append(id);
return id;
}
bool uf::Object::load( const std::string& filename ) {
uf::Serializer json;
std::string root = "./data/" + uf::string::directory(filename);
if ( !json.readFromFile(root + uf::string::filename(filename)) ) {
uf::iostream << "Error: failed to open `" + root + uf::string::filename(filename) + "`" << "\n";
return false;
}
json["root"] = root;
return this->load(json);
}
std::size_t uf::Object::loadChild( const std::string& filename, bool initialize ) {
uf::Serializer json;
std::string root = "./data/" + uf::string::directory(filename);
if ( !json.readFromFile(root + uf::string::filename(filename)) ) {
uf::iostream << "Error: failed to open `" + root + uf::string::filename(filename) + "`" << "\n";
return -1;
}
json["root"] = root;
return this->loadChild(json, initialize);
}
bool uf::Object::load( const uf::Serializer& json ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
// Basic entity information
{
// Set name
this->m_name = json["name"].asString();
// Set transform
bool load = json["transform"].isObject();
if ( this->hasComponent<pod::Transform<>>() ) load = false;
pod::Transform<>& transform = this->getComponent<pod::Transform<>>();
if ( transform.position.x == 0 && transform.position.y == 0 && transform.position.z == 0 ) {
load = true;
}
if ( load ) {
float x = json["transform"]["position"][0].asFloat();
float y = json["transform"]["position"][1].asFloat();
float z = json["transform"]["position"][2].asFloat();
transform.position = { x, y, z };
transform.orientation = uf::quaternion::identity();
if ( json["transform"]["rotation"]["angle"].asFloat() != 0 ) {
transform.orientation = uf::quaternion::axisAngle( {
json["transform"]["rotation"]["axis"][0].asFloat(),
json["transform"]["rotation"]["axis"][1].asFloat(),
json["transform"]["rotation"]["axis"][2].asFloat()
},
json["transform"]["rotation"]["angle"].asFloat()
);
}
transform.scale = uf::vector::create( json["transform"]["scale"][0].asFloat(),json["transform"]["scale"][1].asFloat(),json["transform"]["scale"][2].asFloat() );
transform = uf::transform::reorient( transform );
}
}
uf::Scene& world = this->getRootParent<uf::Scene>();
uf::Asset& assetLoader = world.getComponent<uf::Asset>();
// initialize base entity, needed for asset hooks
// Audio (singular)
{
// find first valid texture in asset list
uf::Serializer target;
if ( metadata["system"]["assets"].isArray() ) {
target = metadata["system"]["assets"];
} else if ( json["assets"].isArray() ) {
target = json["assets"];
} else if ( json["assets"].isObject() && !json["assets"]["audio"].isNull() ) {
target = json["assets"]["audio"];
}
for ( uint i = 0; i < target.size(); ++i ) {
std::string filename = target[i].asString();
if ( uf::string::extension(filename) != "ogg" ) continue;
std::string canonical = "";
if ( (canonical = assetLoader.load( filename )) != "" ) {
uf::Serializer queue;
queue["name"] = "asset:Load.%UID%";
queue["payload"]["filename"] = canonical;
metadata["system"]["hooks"]["queue"].append(queue);
}
}
}
// Texture (singular)
{
// find first valid texture in asset list
uf::Serializer target;
if ( metadata["system"]["assets"].isArray() ) {
target = metadata["system"]["assets"];
} else if ( json["assets"].isArray() ) {
target = json["assets"];
} else if ( json["assets"].isObject() && !json["assets"]["textures"].isNull() ) {
target = json["assets"]["textures"];
}
for ( uint i = 0; i < target.size(); ++i ) {
std::string filename = target[i].asString();
if ( uf::string::extension(filename) != "png" ) continue;
std::string canonical = "";
if ( (canonical = assetLoader.load( filename )) != "" ) {
uf::Serializer queue;
queue["name"] = "asset:Load.%UID%";
queue["payload"]["filename"] = canonical;
metadata["system"]["hooks"]["queue"].append(queue);
// uf::Serializer payload;
// payload["filename"] = canonical;
// this->callHook( "asset:Load.%UID%", payload );
}
}
}
uf::Serializer queue = metadata["system"]["hooks"]["queue"];
// Metadata
if ( json["metadata"] != Json::nullValue ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( json["metadata"].type() == Json::stringValue ) {
std::string filename = json["root"].asString() + "/" + json["metadata"].asString();
if ( !metadata.readFromFile(filename) ) {
uf::iostream << "Error: failed to open `" + filename + "`" << "\n";
return false;
}
} else {
metadata = json["metadata"];
}
}
metadata["_config"] = json;
metadata["_config"].removeMember("metadata");
metadata["system"]["hooks"]["queue"] = queue;
// check for children
{
uf::Serializer target;
if ( metadata["system"]["assets"].isArray() ) {
target = metadata["system"]["assets"];
} else if ( metadata["_config"]["assets"].isArray() ) {
target = metadata["_config"]["assets"];
} else if ( metadata["_config"]["assets"].isObject() && !metadata["_config"]["assets"]["entities"].isNull() ) {
target = metadata["_config"]["assets"]["entities"];
}
for ( uint i = 0; i < target.size(); ++i ) {
std::string filename = target[i].asString();
if ( uf::string::extension(filename) != "json" ) continue;
std::string root = "./data/entities/" + uf::string::directory(filename);
filename = root + uf::string::filename(filename);
if ( (filename = assetLoader.load(filename) ) == "" ) return false;
uf::Serializer json;
if ( !json.readFromFile(filename) ) {
uf::iostream << "Error: failed to open `" + filename + "`" << "\n";
return false;
}
json["root"] = root;
if ( this->loadChild(json) == -1 ) return false;
}
}
return true;
}
std::size_t uf::Object::loadChild( const uf::Serializer& json, bool initialize ) {
uf::Entity* entity;
std::string type = json["type"].asString();
if ( json["ignore"].asBool() ) return 0;
entity = uf::instantiator::instantiate(type);
this->addChild(*entity);
if ( !((uf::Object*) entity)->load(json) ) {
uf::iostream << "Error loading `" << json << "!" << "\n";
this->removeChild(*entity);
delete entity;
return -1;
}
if ( initialize ) entity->initialize();
return entity->getUid();
}
/*
bool uf::Object::load( const uf::Serializer& json ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
uf::Object& root = this->getRootParent<uf::Object>();
uf::Asset& assetLoader = root.getComponent<uf::Asset>();
// Load metadata
{
// name
this->m_name = json["name"].asString();
// transform
pod::Transform<>& transform = this->getComponent<pod::Transform<>>();
}
return true;
}
std::size_t uf::Object::loadChild( const uf::Serializer& json, bool initialize ) {
return 0;
}
*/
/*
bool uf::Object::load( const uf::Serializer& json ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
// Basic entity information
{
// Set name
this->m_name = json["name"].asString();
// Set transform
bool load = json["transform"].isObject();
if ( this->hasComponent<pod::Transform<>>() ) load = false;
pod::Transform<>& transform = this->getComponent<pod::Transform<>>();
if ( transform.position.x == 0 && transform.position.y == 0 && transform.position.z == 0 ) {
load = true;
}
if ( load ) {
transform.position = uf::vector::create( json["transform"]["position"][0].asFloat(),json["transform"]["position"][1].asFloat(),json["transform"]["position"][2].asFloat() );
transform.orientation = uf::quaternion::identity();
if ( json["transform"]["rotation"]["angle"].asFloat() != 0 ) {
transform.orientation = uf::quaternion::axisAngle( {
json["transform"]["rotation"]["axis"][0].asFloat(),
json["transform"]["rotation"]["axis"][1].asFloat(),
json["transform"]["rotation"]["axis"][2].asFloat()
},
json["transform"]["rotation"]["angle"].asFloat()
);
}
transform.scale = uf::vector::create( json["transform"]["scale"][0].asFloat(),json["transform"]["scale"][1].asFloat(),json["transform"]["scale"][2].asFloat() );
transform = uf::transform::reorient( transform );
}
}
uf::Scene& world = this->getRootParent<uf::Scene>();
uf::Asset& assetLoader = world.getComponent<uf::Asset>();
// initialize base entity, needed for asset hooks
// Audio (singular)
{
// find first valid texture in asset list
uf::Serializer target;
if ( metadata["system"]["assets"].isArray() ) {
target = metadata["system"]["assets"];
} else if ( json["assets"].isArray() ) {
target = json["assets"];
} else if ( json["assets"].isObject() && !json["assets"]["audio"].isNull() ) {
target = json["assets"]["audio"];
}
for ( uint i = 0; i < target.size(); ++i ) {
std::string filename = target[i].asString();
if ( uf::string::extension(filename) != "ogg" ) continue;
std::string canonical = "";
if ( (canonical = assetLoader.load( filename )) != "" ) {
uf::Serializer queue;
queue["name"] = "asset:Load.%UID%";
queue["payload"]["filename"] = canonical;
metadata["system"]["hooks"]["queue"].append(queue);
}
}
}
// Texture (singular)
{
// find first valid texture in asset list
uf::Serializer target;
if ( metadata["system"]["assets"].isArray() ) {
target = metadata["system"]["assets"];
} else if ( json["assets"].isArray() ) {
target = json["assets"];
} else if ( json["assets"].isObject() && !json["assets"]["textures"].isNull() ) {
target = json["assets"]["textures"];
}
for ( uint i = 0; i < target.size(); ++i ) {
std::string filename = target[i].asString();
if ( uf::string::extension(filename) != "png" ) continue;
std::string canonical = "";
if ( (canonical = assetLoader.load( filename )) != "" ) {
uf::Serializer queue;
queue["name"] = "asset:Load.%UID%";
queue["payload"]["filename"] = canonical;
metadata["system"]["hooks"]["queue"].append(queue);
}
}
}
uf::Serializer queue = metadata["system"]["hooks"]["queue"];
// Metadata
if ( json["metadata"] != Json::nullValue ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( json["metadata"].type() == Json::stringValue ) {
std::string filename = json["root"].asString() + "/" + json["metadata"].asString();
if ( !metadata.readFromFile(filename) ) {
uf::iostream << "Error: failed to open `" + filename + "`" << "\n";
return false;
}
} else {
metadata = json["metadata"];
}
}
metadata["_config"] = json;
metadata["_config"].removeMember("metadata");
metadata["system"]["hooks"]["queue"] = queue;
// check for children
{
uf::Serializer target;
if ( metadata["system"]["assets"].isArray() ) {
target = metadata["system"]["assets"];
} else if ( metadata["_config"]["assets"].isArray() ) {
target = metadata["_config"]["assets"];
} else if ( metadata["_config"]["assets"].isObject() && !metadata["_config"]["assets"]["entities"].isNull() ) {
target = metadata["_config"]["assets"]["entities"];
}
for ( uint i = 0; i < target.size(); ++i ) {
std::string filename = target[i].asString();
if ( uf::string::extension(filename) != "json" ) continue;
std::string root = "./data/entities/" + uf::string::directory(filename);
filename = root + uf::string::filename(filename);
if ( (filename = assetLoader.load(filename) ) == "" ) return false;
uf::Serializer json;
if ( !json.readFromFile(filename) ) {
uf::iostream << "Error: failed to open `" + filename + "`" << "\n";
return false;
}
json["root"] = root;
if ( this->loadChild(json) == -1 ) return false;
}
}
return true;
}
std::size_t uf::Object::loadChild( const uf::Serializer& json, bool initialize ) {
uf::Entity* entity;
std::string type = json["type"].asString();
if ( json["ignore"].asBool() ) return 0;
if ( type == "Terrain" ) entity = new ext::Terrain;
else if ( type == "Player" ) entity = new ext::Player;
else if ( type == "Craeture" ) entity = new ext::Craeture;
else if ( type == "Housamo" ) entity = new ext::HousamoSprite;
else if ( type == "Gui" ) entity = new ext::Gui;
else {
uf::iostream << "Unimplemented entity: " << type << "\n";
entity = new uf::Object;
}
// uf::iostream << entity << ": " << type << "\n";
this->addChild(*entity);
if ( !((uf::Object*) entity)->load(json) ) {
uf::iostream << "Error loading `" << json << "!" << "\n";
this->removeChild(*entity);
delete entity;
return -1;
}
if ( initialize ) entity->initialize();
return entity->getUid();
}
*/

View File

@ -0,0 +1,94 @@
#include <uf/engine/scene/scene.h>
#include <uf/ext/vulkan/vulkan.h>
UF_OBJECT_REGISTER_CPP(Scene)
void uf::Scene::initialize() {
// this->m_graphics = new std::vector<ext::vulkan::Graphic*>();
// ext::vulkan::graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
ext::vulkan::scenes.push_back(this);
ext::vulkan::swapchain.rebuild = true;
uf::Object::initialize();
}
void uf::Scene::tick() {
// ext::vulkan::graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
uf::Object::tick();
}
void uf::Scene::render() {
// ext::vulkan::graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
uf::Object::render();
}
void uf::Scene::destroy() {
uf::Object::destroy();
{
auto it = std::find(ext::vulkan::scenes.begin(), ext::vulkan::scenes.end(), this);
if ( it != ext::vulkan::scenes.end() ) {
ext::vulkan::scenes.erase(it);
}
}
/*
ext::vulkan::scenes.erase(
std::remove(ext::vulkan::scenes.begin(), ext::vulkan::scenes.end(), this),
ext::vulkan::scenes.end()
);
*/
ext::vulkan::swapchain.rebuild = true;
/*
std::vector<ext::vulkan::Graphic*>* graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
for ( auto* graphic : *graphics ) {
graphic->destroy();
}
delete graphics;
ext::vulkan::graphics = NULL;
*/
}
uf::Entity* uf::Scene::getController() {
return this->findByName("Player");
}
const uf::Entity* uf::Scene::getController() const {
return this->findByName("Player");
}
std::vector<uf::Scene*> uf::scene::scenes;
uf::Scene& uf::scene::loadScene( const std::string& name, const std::string data ) {
uf::Scene* scene = (uf::Scene*) uf::instantiator::instantiate( name );
uf::scene::scenes.push_back(scene);
if ( data != "" ) scene->load(data);
else scene->initialize();
return *scene;
}
void uf::scene::unloadScene() {
uf::Scene* current = uf::scene::scenes.back();
current->destroy();
uf::scene::scenes.pop_back();
delete current;
}
uf::Scene& uf::scene::getCurrentScene() {
return *uf::scene::scenes.back();
}
void uf::scene::tick() {
// uf::scene::getCurrentScene().tick();
for ( auto scene : scenes ) scene->tick();
}
void uf::scene::render() {
// uf::scene::getCurrentScene().render();
for ( auto scene : scenes ) scene->render();
}
void uf::scene::destroy() {
while ( !scenes.empty() ) {
unloadScene();
}
}
/*
uf::Camera& uf::Scene::getCamera() {
if ( !::camera ) ::camera = this->getPlayer().getComponentPointer<uf::Camera>();
return *::camera;
}
uf::Player& uf::Scene::getPlayer() {
return *((uf::Player*) this->findByName("Player"));
}
const uf::Player& uf::Scene::getPlayer() const {
return *((const uf::Player*) this->findByName("Player"));
}
*/

View File

@ -16,12 +16,10 @@ ext::freetype::Glyph::~Glyph() {
UF_API bool ext::freetype::initialize() {
int error = 0;
std::cout << "FreeType initializing" << std::endl;
if ( (error = FT_Init_FreeType( &ext::freetype::library.library ) )) {
std::cout << "Error #" << ext::freetype::getError(error) << ": FreeType failed to initialize" << std::endl;
return false;
}
std::cout << "FreeType initialized" << std::endl;
ext::freetype::library.loaded = true;
return true;
}

View File

@ -1,6 +1,9 @@
#include <uf/ext/openvr/openvr.h>
#include <uf/utils/io/iostream.h>
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/rendermodes/multiview.h>
vr::IVRSystem* ext::openvr::context;
ext::openvr::Driver ext::openvr::driver;
uint8_t ext::openvr::renderPass = 0;
@ -212,11 +215,10 @@ void ext::openvr::tick() {
}
}
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/commands/multiview.h>
void ext::openvr::submit() {
float width = ext::vulkan::command->width > 0 ? ext::vulkan::command->width : ext::vulkan::width;
float height = ext::vulkan::command->height > 0 ? ext::vulkan::command->height : ext::vulkan::height;
ext::vulkan::MultiviewRenderMode* renderMode = (ext::vulkan::MultiviewRenderMode*) ext::vulkan::renderModes[0];
float width = renderMode->width > 0 ? renderMode->width : ext::vulkan::width;
float height = renderMode->height > 0 ? renderMode->height : ext::vulkan::height;
// Submit to SteamVR
vr::VRTextureBounds_t bounds;
bounds.uMin = 0.0f;
@ -239,10 +241,10 @@ void ext::openvr::submit() {
vr::Texture_t texture = { &vulkanData, vr::TextureType_Vulkan, vr::ColorSpace_Auto };
vulkanData.m_nImage = (uint64_t) (VkImage) ((ext::vulkan::MultiviewCommand*) ext::vulkan::command)->framebuffers.left.attachments[0].image;
vulkanData.m_nImage = (uint64_t) (VkImage) renderMode->framebuffers.left.attachments[0].image;
vr::VRCompositor()->Submit( vr::Eye_Left, &texture, &bounds );
vulkanData.m_nImage = (uint64_t) (VkImage) ((ext::vulkan::MultiviewCommand*) ext::vulkan::command)->framebuffers.right.attachments[0].image;
vulkanData.m_nImage = (uint64_t) (VkImage) renderMode->framebuffers.right.attachments[0].image;
vr::VRCompositor()->Submit( vr::Eye_Right, &texture, &bounds );
vr::VRCompositor()->PostPresentHandoff();

View File

@ -1,146 +0,0 @@
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/commands/base.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/utils/window/window.h>
#include <uf/ext/vulkan/rendertarget.h>
const std::string& ext::vulkan::Command::getName() const {
return "Base";
}
size_t ext::vulkan::Command::subpasses() const {
return 1;
}
VkRenderPass& ext::vulkan::Command::getRenderPass() {
return swapchain.renderPass;
}
void ext::vulkan::Command::createCommandBuffers() {
std::vector<void*> graphics;
if ( ext::vulkan::graphics ) {
graphics.reserve( ext::vulkan::graphics->size() );
for ( Graphic* graphic : *ext::vulkan::graphics ) {
if ( !graphic || !graphic->process ) continue;
graphics.push_back( (void*) graphic);
}
}
createCommandBuffers( graphics, ext::vulkan::passes );
}
void ext::vulkan::Command::createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes ) {
// destroy if exists
if ( swapchain.commandBufferSet ) {
auto* device = swapchain.device;
bool vsync = swapchain.vsync;
swapchain.destroy();
swapchain.initialize( *device, 0, 0, vsync );
}
float width = width > 0 ? this->width : ext::vulkan::width;
float height = height > 0 ? this->height : ext::vulkan::height;
swapchain.commandBufferSet = true;
VkCommandBufferBeginInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.pNext = nullptr;
// Set clear values for all framebuffer attachments with loadOp set to clear
// We use two attachments (color and depth) that are cleared at the start of the subpass and as such we need to set clear values for both
VkClearValue clearValues[2];
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderPass = swapchain.renderPass;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = width;
renderPassBeginInfo.clearValueCount = 2;
renderPassBeginInfo.pClearValues = clearValues;
for (int32_t i = 0; i < swapchain.drawCommandBuffers.size(); ++i) {
// Set target frame buffer
renderPassBeginInfo.framebuffer = swapchain.frameBuffers[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(swapchain.drawCommandBuffers[i], &cmdBufInfo));
for ( auto& pGraphic : graphics ) {
Graphic& graphic = *((Graphic*) pGraphic);
graphic.createImageMemoryBarrier(swapchain.drawCommandBuffers[i]);
}
// Start the first sub pass specified in our default render pass setup by the base class
// This will clear the color and depth attachment
vkCmdBeginRenderPass(swapchain.drawCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
// Update dynamic viewport state
VkViewport viewport = {};
viewport.height = (float) height;
viewport.width = (float) width;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
vkCmdSetViewport(swapchain.drawCommandBuffers[i], 0, 1, &viewport);
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
vkCmdSetScissor(swapchain.drawCommandBuffers[i], 0, 1, &scissor);
for ( auto pass : passes ) {
ext::vulkan::currentPass = pass;
for ( auto& pGraphic : graphics ) {
Graphic& graphic = *((Graphic*) pGraphic);
graphic.createCommandBuffer(swapchain.drawCommandBuffers[i] );
}
}
vkCmdEndRenderPass(swapchain.drawCommandBuffers[i]);
// Ending the render pass will add an implicit barrier transitioning the frame buffer color attachment to
// VK_IMAGE_LAYOUT_PRESENT_SRC_KHR for presenting it to the windowing system
VK_CHECK_RESULT(vkEndCommandBuffer(swapchain.drawCommandBuffers[i]));
}
}
void ext::vulkan::Command::render() {
// Get next image in the swap chain (back/front buffer)
VK_CHECK_RESULT(swapchain.acquireNextImage(&currentBuffer));
// Use a fence to wait until the command buffer has finished execution before using it again
VK_CHECK_RESULT(vkWaitForFences(device, 1, &swapchain.waitFences[currentBuffer], VK_TRUE, UINT64_MAX));
VK_CHECK_RESULT(vkResetFences(device, 1, &swapchain.waitFences[currentBuffer]));
// Pipeline stage at which the queue submission will wait (via pWaitSemaphores)
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
// The submit info structure specifices a command buffer queue submission batch
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = &waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
submitInfo.pSignalSemaphores = &swapchain.renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
submitInfo.pCommandBuffers = &swapchain.drawCommandBuffers[currentBuffer]; // Command buffers(s) to execute in this batch (submission)
submitInfo.commandBufferCount = 1;
// Submit to the graphics queue passing a wait fence
VK_CHECK_RESULT(vkQueueSubmit(device.graphicsQueue, 1, &submitInfo, swapchain.waitFences[currentBuffer]));
// Present the current buffer to the swap chain
// Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation
// This ensures that the image is not presented to the windowing system until all commands have been submitted
VK_CHECK_RESULT(swapchain.queuePresent(device.presentQueue, currentBuffer, swapchain.renderCompleteSemaphore));
VK_CHECK_RESULT(vkQueueWaitIdle(device.presentQueue));
}
void ext::vulkan::Command::initialize( Device& device ) {
this->width = 0;
this->height = 0;
}
void ext::vulkan::Command::destroy() {
}

View File

@ -1,217 +0,0 @@
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/commands/deferred.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/utils/window/window.h>
#include <uf/utils/mesh/mesh.h>
namespace {
// 0 left 1 right
uint8_t DOMINANT_EYE = 1;
}
const std::string& ext::vulkan::DeferredCommand::getName() const {
return "Defered";
}
size_t ext::vulkan::DeferredCommand::subpasses() const {
return framebuffer.passes.size();
}
VkRenderPass& ext::vulkan::DeferredCommand::getRenderPass() {
return framebuffer.renderPass;
}
void ext::vulkan::DeferredCommand::initialize( Device& device ) {
{
framebuffer.device = &device;
// attach targets
struct {
size_t albedo, normals, depth, output;
} attachments;
attachments.albedo = framebuffer.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ); // albedo
attachments.normals = framebuffer.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ); // normals
attachments.depth = framebuffer.attach( swapchain.depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ); // depth
// Attach swapchain's image as output
{
attachments.output = framebuffer.attachments.size();
framebuffer.attachments.push_back({ swapchain.colorFormat, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, });
}
// First pass: fill the G-Buffer
{
framebuffer.addPass(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
{ attachments.albedo, attachments.normals, },
{},
attachments.depth
);
}
// Second pass: write to output
{
framebuffer.addPass(
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT,
{ attachments.output, },
{ attachments.albedo, attachments.normals },
attachments.depth
);
}
}
framebuffer.initialize( device );
blitter.framebuffer = &framebuffer;
blitter.initializeShaders({
{"./data/shaders/display.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{"./data/shaders/display.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
blitter.initialize( device, ext::vulkan::swapchain );
}
void ext::vulkan::DeferredCommand::destroy() {
framebuffer.destroy();
}
void ext::vulkan::DeferredCommand::createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes ) {
// destroy if exists
if ( swapchain.rebuild ) {
if ( swapchain.commandBufferSet ) {
auto* device = swapchain.device;
bool vsync = swapchain.vsync;
swapchain.destroy();
swapchain.initialize( *device, 0, 0, vsync );
}
swapchain.commandBufferSet = true;
// destroy if exist
if ( framebuffer.commandBufferSet ) {
auto* device = framebuffer.device;
framebuffer.initialize( *device );
}
framebuffer.commandBufferSet = true;
// update descriptor set
if ( blitter.initialized ) {
VkDescriptorImageInfo textDescriptorAlbedo = ext::vulkan::initializers::descriptorImageInfo(
framebuffer.attachments[0].view,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
// Binding 0 : Projection/View matrix uniform buffer
ext::vulkan::initializers::writeDescriptorSet(
blitter.descriptorSet,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&(blitter.buffers.at(0).descriptor)
),
// Binding 1 : Albedo input attachment
ext::vulkan::initializers::writeDescriptorSet(
blitter.descriptorSet,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
1,
&textDescriptorAlbedo
),
};
vkUpdateDescriptorSets( device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr );
}
}
float width = this->width > 0 ? this->width : ext::vulkan::width;
float height = this->height > 0 ? this->height : ext::vulkan::height;
blitter.uniforms.screenSize = { width, height };
VkCommandBufferBeginInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.pNext = nullptr;
for (int32_t i = 0; i < swapchain.drawCommandBuffers.size(); ++i) {
VK_CHECK_RESULT(vkBeginCommandBuffer(swapchain.drawCommandBuffers[i], &cmdBufInfo));
// Fill GBuffer
{
std::vector<VkClearValue> clearValues; clearValues.resize(4);
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[2].depthStencil = { 1.0f, 0 };
clearValues[3].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = &clearValues[0];
renderPassBeginInfo.renderPass = framebuffer.renderPass;
renderPassBeginInfo.framebuffer = framebuffer.framebuffers[i];
for ( auto& pGraphic : graphics ) {
Graphic& graphic = *((Graphic*) pGraphic);
graphic.createImageMemoryBarrier(swapchain.drawCommandBuffers[i]);
}
// Update dynamic viewport state
VkViewport viewport = {};
viewport.width = (float) width;
viewport.height = (float) height;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
vkCmdBeginRenderPass(swapchain.drawCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(swapchain.drawCommandBuffers[i], 0, 1, &viewport);
vkCmdSetScissor(swapchain.drawCommandBuffers[i], 0, 1, &scissor);
for ( auto pass : passes ) {
ext::vulkan::currentPass = pass + ";DEFERRED";
for ( auto& pGraphic : graphics ) {
Graphic& graphic = *((Graphic*) pGraphic);
graphic.createCommandBuffer(swapchain.drawCommandBuffers[i] );
}
}
vkCmdNextSubpass(swapchain.drawCommandBuffers[i], VK_SUBPASS_CONTENTS_INLINE);
blitter.createCommandBuffer(swapchain.drawCommandBuffers[i]);
vkCmdEndRenderPass(swapchain.drawCommandBuffers[i]);
}
VK_CHECK_RESULT(vkEndCommandBuffer(swapchain.drawCommandBuffers[i]));
}
}
void ext::vulkan::DeferredCommand::render() {
//auto& device = ext::vulkan::device;
//auto& swapchain = ext::vulkan::swapchain;
//auto& currentBuffer = ext::vulkan::currentBuffer;
// Get next image in the swap chain (back/front buffer)
VK_CHECK_RESULT(swapchain.acquireNextImage(&currentBuffer));
// Use a fence to wait until the command buffer has finished execution before using it again
VK_CHECK_RESULT(vkWaitForFences(device, 1, &swapchain.waitFences[currentBuffer], VK_TRUE, UINT64_MAX));
VK_CHECK_RESULT(vkResetFences(device, 1, &swapchain.waitFences[currentBuffer]));
// Pipeline stage at which the queue submission will wait (via pWaitSemaphores)
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
// The submit info structure specifices a command buffer queue submission batch
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = &waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
submitInfo.pSignalSemaphores = &swapchain.renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
submitInfo.pCommandBuffers = &swapchain.drawCommandBuffers[currentBuffer]; // Command buffers(s) to execute in this batch (submission)
submitInfo.commandBufferCount = 1;
// Submit to the graphics queue passing a wait fence
VK_CHECK_RESULT(vkQueueSubmit(device.graphicsQueue, 1, &submitInfo, swapchain.waitFences[currentBuffer]));
// Present the current buffer to the swap chain
// Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation
// This ensures that the image is not presented to the windowing system until all commands have been submitted
VK_CHECK_RESULT(swapchain.queuePresent(device.presentQueue, currentBuffer, swapchain.renderCompleteSemaphore));
VK_CHECK_RESULT(vkQueueWaitIdle(device.presentQueue));
}

View File

@ -231,7 +231,7 @@ VkResult ext::vulkan::Device::createBuffer(
void ext::vulkan::Device::initialize() {
const std::vector<const char*> validationLayers = {
"VK_LAYER_LUNARG_standard_validation"
"VK_LAYER_KHRONOS_validation"
};
// Assert validation layers
if ( ext::vulkan::validation ) {
@ -255,7 +255,8 @@ void ext::vulkan::Device::initialize() {
// Get extensions
// OpenVR Support
supportedExtensions = window->getExtensions( ext::vulkan::validation );
if ( ext::vulkan::openvr && vr::VRCompositor() ) {
if ( ext::openvr::context && vr::VRCompositor() ) {
uint32_t nBufferSize = vr::VRCompositor()->GetVulkanInstanceExtensionsRequired( nullptr, 0 );
if ( nBufferSize > 0 ) {
char pExtensionStr[nBufferSize];
@ -292,7 +293,7 @@ void ext::vulkan::Device::initialize() {
}
}
}
// for ( auto ext : supportedExtensions ) std::cout << "Extension: " << ext << std::endl;
for ( auto ext : supportedExtensions ) std::cout << "Extension: " << ext << std::endl;
// Create instance
{
@ -375,7 +376,7 @@ void ext::vulkan::Device::initialize() {
std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
/* OpenVR support */ if ( ext::vulkan::openvr && vr::VRCompositor() ) {
/* OpenVR support */ if ( ext::openvr::context && vr::VRCompositor() ) {
uint32_t nBufferSize = vr::VRCompositor()->GetVulkanDeviceExtensionsRequired( ( VkPhysicalDevice_T * ) this->physicalDevice, nullptr, 0 );
if ( nBufferSize > 0 ) {
char pExtensionStr[nBufferSize];
@ -513,7 +514,7 @@ void ext::vulkan::Device::initialize() {
transferQueueNodeIndex = i;
VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR( device.physicalDevice, i, surface, &presentSupport );
vkGetPhysicalDeviceSurfaceSupportKHR( this->physicalDevice, i, surface, &presentSupport );
if ( queueFamily.queueCount > 0 && presentSupport )
presentQueueNodeIndex = i;
@ -528,9 +529,71 @@ void ext::vulkan::Device::initialize() {
vkGetDeviceQueue( device, device.queueFamilyIndices.present, 0, &presentQueue );
vkGetDeviceQueue( device, device.queueFamilyIndices.compute, 0, &computeQueue );
}
// Set formats
{
std::vector<VkSurfaceFormatKHR> formats;
uint32_t formatCount; vkGetPhysicalDeviceSurfaceFormatsKHR( this->physicalDevice, device.surface, &formatCount, nullptr);
formats.resize( formatCount );
vkGetPhysicalDeviceSurfaceFormatsKHR( this->physicalDevice, device.surface, &formatCount, formats.data() );
// If the surface format list only includes one entry with VK_FORMAT_UNDEFINED,
// there is no preferered format, so we assume VK_FORMAT_B8G8R8A8_UNORM
if ( (formatCount == 1) && (formats[0].format == VK_FORMAT_UNDEFINED) ) {
formats.color = VK_FORMAT_B8G8R8A8_UNORM;
formats.space = formats[0].colorSpace;
} else {
// iterate over the list of available surface format and
// check for the presence of VK_FORMAT_B8G8R8A8_UNORM
bool found_B8G8R8A8_UNORM = false;
for ( auto&& surfaceFormat : formats ) {
if ( surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM ) {
formats.color = surfaceFormat.format;
formats.space = surfaceFormat.colorSpace;
found_B8G8R8A8_UNORM = true;
break;
}
}
// in case VK_FORMAT_B8G8R8A8_UNORM is not available
// select the first available color format
if ( !found_B8G8R8A8_UNORM ) {
formats.color = formats[0].format;
formats.space = formats[0].colorSpace;
}
}
}
// Grab depth/stencil format
{
// Since all depth formats may be optional, we need to find a suitable depth format to use
// Start with the highest precision packed format
std::vector<VkFormat> depthFormats = {
VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_D32_SFLOAT,
VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_D16_UNORM_S8_UINT,
VK_FORMAT_D16_UNORM
};
for ( auto& format : depthFormats ) {
VkFormatProperties formatProps;
vkGetPhysicalDeviceFormatProperties( this->physicalDevice, format, &formatProps );
// Format must support depth stencil attachment for optimal tiling
if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
formats.depth = format;
}
}
}
// create pipeline cache
{
VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {};
pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
VK_CHECK_RESULT(vkCreatePipelineCache( device, &pipelineCacheCreateInfo, nullptr, &this->pipelineCache));
}
}
void ext::vulkan::Device::destroy() {
if ( this->pipelineCache ) {
vkDestroyPipelineCache( this->logicalDevice, this->pipelineCache, nullptr );
this->pipelineCache = nullptr;
}
if ( this->commandPool ) {
vkDestroyCommandPool( this->logicalDevice, this->commandPool, nullptr );
this->commandPool = nullptr;

View File

@ -121,115 +121,10 @@ void ext::vulkan::Graphic::initializeDescriptorLayout( const std::vector<VkDescr
}
// Create pipeline
void ext::vulkan::Graphic::initializePipeline( VkGraphicsPipelineCreateInfo pipelineCreateInfo ) {
/*
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = ext::vulkan::initializers::pipelineInputAssemblyStateCreateInfo(
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
0,
VK_FALSE
);
VkPipelineRasterizationStateCreateInfo rasterizationState = ext::vulkan::initializers::pipelineRasterizationStateCreateInfo(
VK_POLYGON_MODE_FILL,
VK_CULL_MODE_NONE,
VK_FRONT_FACE_COUNTER_CLOCKWISE,
0
);
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
0xf,
VK_FALSE
);
VkPipelineColorBlendStateCreateInfo colorBlendState = ext::vulkan::initializers::pipelineColorBlendStateCreateInfo(
1,
&blendAttachmentState
);
VkPipelineDepthStencilStateCreateInfo depthStencilState = ext::vulkan::initializers::pipelineDepthStencilStateCreateInfo(
VK_TRUE,
VK_TRUE,
VK_COMPARE_OP_LESS_OR_EQUAL
);
VkPipelineViewportStateCreateInfo viewportState = ext::vulkan::initializers::pipelineViewportStateCreateInfo(
1, 1, 0
);
VkPipelineMultisampleStateCreateInfo multisampleState = ext::vulkan::initializers::pipelineMultisampleStateCreateInfo(
VK_SAMPLE_COUNT_1_BIT,
0
);
std::vector<VkDynamicState> dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
};
VkPipelineDynamicStateCreateInfo dynamicState = ext::vulkan::initializers::pipelineDynamicStateCreateInfo(
dynamicStateEnables.data(),
static_cast<uint32_t>(dynamicStateEnables.size()),
0
);
// Binding description
vertices.bindingDescriptions.resize(1);
vertices.bindingDescriptions[0] = ext::vulkan::initializers::vertexInputBindingDescription(
VERTEX_BUFFER_BIND_ID,
sizeof(Vertex),
VK_VERTEX_INPUT_RATE_VERTEX
);
// Attribute descriptions
// Describes memory layout and shader positions
vertices.attributeDescriptions.resize(3);
// Location 0 : Position
vertices.attributeDescriptions[0] = ext::vulkan::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
0,
VK_FORMAT_R32G32B32_SFLOAT,
offsetof(Vertex, position)
);
// Location 1 : Texture coordinates
vertices.attributeDescriptions[1] = ext::vulkan::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
1,
VK_FORMAT_R32G32_SFLOAT,
offsetof(Vertex, uv)
);
// Location 1 : Vertex normal
vertices.attributeDescriptions[2] = ext::vulkan::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
2,
VK_FORMAT_R32G32B32_SFLOAT,
offsetof(Vertex, normal)
);
vertices.inputState = ext::vulkan::initializers::pipelineVertexInputStateCreateInfo();
vertices.inputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertices.bindingDescriptions.size());
vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data();
vertices.inputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertices.attributeDescriptions.size());
vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data();
// Load shaders
std::vector<VkPipelineShaderStageCreateInfo> shaderStages = this->loadShaders();
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
swapchain.renderPass,
0
);
pipelineCreateInfo.pVertexInputState = &vertices.inputState;
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
pipelineCreateInfo.pRasterizationState = &rasterizationState;
pipelineCreateInfo.pColorBlendState = &colorBlendState;
pipelineCreateInfo.pMultisampleState = &multisampleState;
pipelineCreateInfo.pViewportState = &viewportState;
pipelineCreateInfo.pDepthStencilState = &depthStencilState;
pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.stageCount = static_cast<uint32_t>(shaderStages.size());
pipelineCreateInfo.pStages = shaderStages.data();
*/
ext::vulkan::mutex.lock();
VK_CHECK_RESULT(vkCreateGraphicsPipelines(*device, swapchain->pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline));
VK_CHECK_RESULT(vkCreateGraphicsPipelines(*device, device->pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline));
ext::vulkan::mutex.unlock();
}
// Set descriptor pool
@ -266,8 +161,10 @@ bool ext::vulkan::Graphic::autoAssignable() const {
}
void ext::vulkan::Graphic::autoAssign() {
if ( !autoAssigned ) {
if ( this->swapchain ) this->swapchain->rebuild = true;
swapchain.rebuild = true;
/*
ext::vulkan::graphics->push_back(this);
*/
}
autoAssigned = true;
}
@ -275,9 +172,12 @@ std::string ext::vulkan::Graphic::name() const {
return "Graphic";
}
void ext::vulkan::Graphic::initialize( Device& device, Swapchain& swapchain ) {
void ext::vulkan::Graphic::initialize( const std::string& renderMode ) {
return initialize(this->device ? *device : ext::vulkan::device, ext::vulkan::getRenderMode(renderMode));
}
void ext::vulkan::Graphic::initialize( Device& device, RenderMode& renderMode ) {
this->device = &device;
this->swapchain = &swapchain;
this->renderMode = &renderMode;
this->initialized = true;
if ( autoAssignable() ) autoAssign();
}
@ -289,12 +189,14 @@ void ext::vulkan::Graphic::destroy() {
buffer.destroy();
}
if ( autoAssigned ) {
/*
ext::vulkan::graphics->erase(
std::remove(ext::vulkan::graphics->begin(), ext::vulkan::graphics->end(), this),
ext::vulkan::graphics->end()
);
if ( this->swapchain ) this->swapchain->rebuild = true;
*/
autoAssigned = false;
swapchain.rebuild = true;
}
initialized = false;
if ( !device || device == VK_NULL_HANDLE ) return;

View File

@ -43,11 +43,14 @@ void ext::vulkan::BaseGraphic::createCommandBuffer( VkCommandBuffer commandBuffe
void ext::vulkan::BaseGraphic::describeVertex( const std::vector<VertexDescriptor>& descriptor ) {
description.attributes = descriptor;
}
void ext::vulkan::BaseGraphic::initialize( Device& device, Swapchain& swapchain ) {
void ext::vulkan::BaseGraphic::initialize( const std::string& renderMode ) {
return initialize(this->device ? *device : ext::vulkan::device, ext::vulkan::getRenderMode(renderMode));
}
void ext::vulkan::BaseGraphic::initialize( Device& device, RenderMode& renderMode ) {
// updateUniforms = [&]() {};
// asset correct buffer sizes
assert( buffers.size() >= 2 );
ext::vulkan::Graphic::initialize( device, swapchain );
ext::vulkan::Graphic::initialize( device, renderMode );
// create default push constant
if ( !description.pushConstants.initialized() ) {
@ -116,16 +119,14 @@ void ext::vulkan::BaseGraphic::initialize( Device& device, Swapchain& swapchain
VK_FRONT_FACE_CLOCKWISE,
0
);
/*
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
0xf,
VK_FALSE
);
VkPipelineColorBlendStateCreateInfo colorBlendState = ext::vulkan::initializers::pipelineColorBlendStateCreateInfo(
1,
&blendAttachmentState
);
*/
/*
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
VK_FALSE
@ -137,15 +138,24 @@ void ext::vulkan::BaseGraphic::initialize( Device& device, Swapchain& swapchain
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
*/
std::vector<VkPipelineColorBlendAttachmentState> blendAttachmentStates;
for ( auto& attachment : renderMode.getFramebuffer().attachments ) {
if ( attachment.layout == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) {
blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
0xf,
VK_FALSE
);
blendAttachmentStates.push_back(blendAttachmentState);
}
}
VkPipelineColorBlendStateCreateInfo colorBlendState = ext::vulkan::initializers::pipelineColorBlendStateCreateInfo(
1,
&blendAttachmentState
blendAttachmentStates.size(),
blendAttachmentStates.data()
);
colorBlendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendState.logicOpEnable = VK_FALSE;
colorBlendState.logicOp = VK_LOGIC_OP_COPY;
colorBlendState.attachmentCount = 1;
colorBlendState.pAttachments = &blendAttachmentState;
colorBlendState.blendConstants[0] = 0.0f;
colorBlendState.blendConstants[1] = 0.0f;
colorBlendState.blendConstants[2] = 0.0f;
@ -201,9 +211,10 @@ void ext::vulkan::BaseGraphic::initialize( Device& device, Swapchain& swapchain
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
ext::vulkan::command ? ext::vulkan::command->getRenderPass() : swapchain.renderPass,
renderMode.getRenderPass(),
0
);
pipelineCreateInfo.pVertexInputState = &vertexInputState;
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
pipelineCreateInfo.pRasterizationState = &rasterizationState;

View File

@ -2,6 +2,7 @@
#include <uf/ext/vulkan/initializers.h>
#include <uf/ext/vulkan/vulkan.h>
#include <algorithm>
std::string ext::vulkan::ComputeGraphic::name() const {
return "ComputeGraphic";
}
@ -78,9 +79,9 @@ void ext::vulkan::ComputeGraphic::updateStorageBuffers( Device& device, std::vec
);
}
}
void ext::vulkan::ComputeGraphic::initialize( Device& device, Swapchain& swapchain, uint32_t width, uint32_t height ) {
void ext::vulkan::ComputeGraphic::initialize( Device& device, RenderMode& renderMode, uint32_t width, uint32_t height ) {
assert( buffers.size() >= 3 );
ext::vulkan::Graphic::initialize( device, swapchain );
ext::vulkan::Graphic::initialize( device, renderMode );
// Set queue
{
VkDeviceQueueCreateInfo queueCreateInfo = {};
@ -210,7 +211,7 @@ void ext::vulkan::ComputeGraphic::initialize( Device& device, Swapchain& swapcha
0
);
computePipelineCreateInfo.stage = shader.stages.at(0);
VK_CHECK_RESULT(vkCreateComputePipelines(device, swapchain.pipelineCache, 1, &computePipelineCreateInfo, nullptr, &pipeline));
VK_CHECK_RESULT(vkCreateComputePipelines(device, device.pipelineCache, 1, &computePipelineCreateInfo, nullptr, &pipeline));
}
// Create command pool
{
@ -283,9 +284,12 @@ std::string ext::vulkan::RTGraphic::name() const {
void ext::vulkan::RTGraphic::updateUniformBuffer() {
compute.updateUniformBuffer();
}
void ext::vulkan::RTGraphic::initialize( Device& device, Swapchain& swapchain ) {
ext::vulkan::Graphic::initialize( device, swapchain );
compute.initialize( device, swapchain, this->width, this->height );
void ext::vulkan::RTGraphic::initialize( const std::string& renderMode ) {
return initialize(this->device ? *device : ext::vulkan::device, ext::vulkan::getRenderMode(renderMode));
}
void ext::vulkan::RTGraphic::initialize( Device& device, RenderMode& renderMode ) {
ext::vulkan::Graphic::initialize( device, renderMode );
compute.initialize( device, renderMode, this->width, this->height );
// Set Descriptor Layout
initializeDescriptorLayout({
ext::vulkan::initializers::descriptorSetLayoutBinding(
@ -352,7 +356,7 @@ void ext::vulkan::RTGraphic::initialize( Device& device, Swapchain& swapchain )
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
swapchain.renderPass,
renderMode.getRenderPass(),
0
);
VkPipelineVertexInputStateCreateInfo emptyInputState = {};

View File

@ -7,7 +7,6 @@
namespace {
uint32_t VERTEX_BUFFER_BIND_ID = 0;
ext::vulkan::Texture2D texture;
}
bool ext::vulkan::FramebufferGraphic::autoAssignable() const {
return false;
@ -32,11 +31,12 @@ void ext::vulkan::FramebufferGraphic::createCommandBuffer( VkCommandBuffer comma
// Draw indexed triangle
vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(indices), 1, 0, 0, 1);
}
void ext::vulkan::FramebufferGraphic::initialize( Device& device, Swapchain& swapchain ) {
void ext::vulkan::FramebufferGraphic::initialize( const std::string& renderMode ) {
return initialize(this->device ? *device : ext::vulkan::device, ext::vulkan::getRenderMode(renderMode));
}
void ext::vulkan::FramebufferGraphic::initialize( Device& device, RenderMode& renderMode ) {
this->device = &device;
texture.loadFromFile( "./data/textures/texture.png", ext::vulkan::device, ext::vulkan::device.graphicsQueue );
std::vector<Vertex> vertices = {
{ {-1.0f, 1.0f}, {0.0f, 0.0f}, },
@ -77,7 +77,7 @@ void ext::vulkan::FramebufferGraphic::initialize( Device& device, Swapchain& swa
this->indices = indices.size();
// asset correct buffer sizes
assert( buffers.size() >= 2 );
ext::vulkan::Graphic::initialize( device, swapchain );
ext::vulkan::Graphic::initialize( device, renderMode );
// set descriptor layout
initializeDescriptorLayout({
// Vertex shader
@ -210,7 +210,7 @@ void ext::vulkan::FramebufferGraphic::initialize( Device& device, Swapchain& swa
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
ext::vulkan::command ? ext::vulkan::command->getRenderPass() : swapchain.renderPass,
renderMode.getRenderPass(),
0
);
pipelineCreateInfo.pVertexInputState = &vertexInputState;

View File

@ -31,11 +31,13 @@ void ext::vulkan::GuiGraphic::createCommandBuffer( VkCommandBuffer commandBuffer
// Draw indexed triangle
vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(indices), 1, 0, 0, 1);
}
void ext::vulkan::GuiGraphic::initialize( Device& device, Swapchain& swapchain ) {
void ext::vulkan::GuiGraphic::initialize( const std::string& renderMode ) {
return initialize(this->device ? *device : ext::vulkan::device, ext::vulkan::getRenderMode(renderMode));
}
void ext::vulkan::GuiGraphic::initialize( Device& device, RenderMode& renderMode ) {
// asset correct buffer sizes
assert( buffers.size() >= 2 );
ext::vulkan::Graphic::initialize( device, swapchain );
ext::vulkan::Graphic::initialize( device, renderMode );
// set descriptor layout
initializeDescriptorLayout({
// Vertex shader
@ -161,7 +163,7 @@ void ext::vulkan::GuiGraphic::initialize( Device& device, Swapchain& swapchain )
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
ext::vulkan::command ? ext::vulkan::command->getRenderPass() : swapchain.renderPass,
renderMode.getRenderPass(),
0
);
pipelineCreateInfo.pVertexInputState = &vertexInputState;

View File

@ -28,11 +28,13 @@ void ext::vulkan::MeshGraphic::createCommandBuffer( VkCommandBuffer commandBuffe
// Draw indexed triangle
vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(indices), 1, 0, 0, 1);
}
void ext::vulkan::MeshGraphic::initialize( Device& device, Swapchain& swapchain ) {
void ext::vulkan::MeshGraphic::initialize( const std::string& renderMode ) {
return initialize(this->device ? *device : ext::vulkan::device, ext::vulkan::getRenderMode(renderMode));
}
void ext::vulkan::MeshGraphic::initialize( Device& device, RenderMode& renderMode ) {
// asset correct buffer sizes
assert( buffers.size() >= 2 );
ext::vulkan::Graphic::initialize( device, swapchain );
ext::vulkan::Graphic::initialize( device, renderMode );
// set descriptor layout
initializeDescriptorLayout({
// Vertex shader
@ -167,7 +169,7 @@ void ext::vulkan::MeshGraphic::initialize( Device& device, Swapchain& swapchain
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
ext::vulkan::command ? ext::vulkan::command->getRenderPass() : swapchain.renderPass,
renderMode.getRenderPass(),
0
);
pipelineCreateInfo.pVertexInputState = &vertexInputState;

View File

@ -0,0 +1,311 @@
#include <uf/ext/vulkan/initializers.h>
#include <uf/ext/vulkan/graphics/rendertarget.h>
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/texture.h>
#include <uf/utils/mesh/mesh.h>
namespace {
uint32_t VERTEX_BUFFER_BIND_ID = 0;
}
bool ext::vulkan::RenderTargetGraphic::autoAssignable() const {
return false;
}
std::string ext::vulkan::RenderTargetGraphic::name() const {
return "RenderTargetGraphic";
}
void ext::vulkan::RenderTargetGraphic::createCommandBuffer( VkCommandBuffer commandBuffer ) {
assert( buffers.size() >= 2 );
Buffer& vertexBuffer = buffers.at(1);
Buffer& indexBuffer = buffers.at(2);
// Bind descriptor sets describing shader binding points
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
// Bind the rendering pipeline
// The pipeline (state object) contains all states of the rendering pipeline, binding it will set all the states specified at pipeline creation time
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
// Bind triangle vertex buffer (contains position and colors)
VkDeviceSize offsets[1] = { 0 };
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer.buffer, offsets);
// Bind triangle index buffer
vkCmdBindIndexBuffer(commandBuffer, indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
// Draw indexed triangle
vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(indices), 1, 0, 0, 1);
}
void ext::vulkan::RenderTargetGraphic::initialize( const std::string& renderMode ) {
return initialize(this->device ? *device : ext::vulkan::device, ext::vulkan::getRenderMode(renderMode));
}
void ext::vulkan::RenderTargetGraphic::initialize( Device& device, RenderMode& renderMode ) {
this->device = &device;
std::vector<Vertex> vertices = {
{ {-1.0f, 1.0f}, {0.0f, 1.0f}, },
{ {-1.0f, -1.0f}, {0.0f, 0.0f}, },
{ {1.0f, -1.0f}, {1.0f, 0.0f}, },
{ {1.0f, 1.0f}, {1.0f, 1.0f}, }
/*
{ {-1.0f, 1.0f}, {0.0f, 0.0f}, },
{ {-1.0f, -1.0f}, {0.0f, 1.0f}, },
{ {1.0f, -1.0f}, {1.0f, 1.0f}, },
{ {-1.0f, 1.0f}, {0.0f, 0.0f}, },
{ {1.0f, -1.0f}, {1.0f, 1.0f}, },
{ {1.0f, 1.0f}, {1.0f, 0.0f}, }
*/
};
std::vector<uint32_t> indices = {
0, 1, 2, 0, 2, 3
// 0, 1, 2, 3, 4, 5
};
initializeBuffer(
(void*) vertices.data(),
vertices.size() * sizeof(Vertex),
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, //VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
false
);
initializeBuffer(
(void*) indices.data(),
indices.size() * sizeof(uint32_t),
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, //VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
false
);
this->indices = indices.size();
// asset correct buffer sizes
assert( buffers.size() >= 2 );
ext::vulkan::Graphic::initialize( device, renderMode );
// set descriptor layout
initializeDescriptorLayout({
// Vertex shader
ext::vulkan::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
VK_SHADER_STAGE_VERTEX_BIT,
0
),
// Fragment shader
ext::vulkan::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_SHADER_STAGE_FRAGMENT_BIT,
1
)
});
// Create sampler
{
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.magFilter = VK_FILTER_NEAREST;
samplerInfo.minFilter = VK_FILTER_NEAREST;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeV = samplerInfo.addressModeU;
samplerInfo.addressModeW = samplerInfo.addressModeU;
samplerInfo.mipLodBias = 0.0f;
samplerInfo.maxAnisotropy = 1.0f;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 1.0f;
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
VK_CHECK_RESULT(vkCreateSampler(device, &samplerInfo, nullptr, &sampler));
}
// Create uniform buffer
initializeBuffer(
(void*) &uniforms,
sizeof(uniforms),
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
false
);
// Swap buffers
buffers = {
std::move(buffers.at(2)),
std::move(buffers.at(0)),
std::move(buffers.at(1)),
};
// set pipeline
{
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = ext::vulkan::initializers::pipelineInputAssemblyStateCreateInfo(
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
0,
VK_FALSE
);
VkPipelineRasterizationStateCreateInfo rasterizationState = ext::vulkan::initializers::pipelineRasterizationStateCreateInfo(
VK_POLYGON_MODE_FILL,
VK_CULL_MODE_NONE,
VK_FRONT_FACE_COUNTER_CLOCKWISE,
0
);
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
0xf,
VK_FALSE
);
/*
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
// VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
0xf,
VK_FALSE
);
blendAttachmentState.blendEnable = VK_TRUE;
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
VkPipelineColorBlendStateCreateInfo colorBlendState = ext::vulkan::initializers::pipelineColorBlendStateCreateInfo(
1,
&blendAttachmentState
);
*/
std::vector<VkPipelineColorBlendAttachmentState> blendAttachmentStates;
for ( auto& attachment : renderMode.framebuffer->attachments ) {
if ( attachment.layout == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) {
blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
0xf,
VK_FALSE
);
blendAttachmentStates.push_back(blendAttachmentState);
}
}
VkPipelineColorBlendStateCreateInfo colorBlendState = ext::vulkan::initializers::pipelineColorBlendStateCreateInfo(
blendAttachmentStates.size(),
blendAttachmentStates.data()
);
colorBlendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendState.logicOpEnable = VK_FALSE;
colorBlendState.logicOp = VK_LOGIC_OP_COPY;
colorBlendState.blendConstants[0] = 0.0f;
colorBlendState.blendConstants[1] = 0.0f;
colorBlendState.blendConstants[2] = 0.0f;
colorBlendState.blendConstants[3] = 0.0f;
VkPipelineDepthStencilStateCreateInfo depthStencilState = ext::vulkan::initializers::pipelineDepthStencilStateCreateInfo(
VK_TRUE,
VK_TRUE,
VK_COMPARE_OP_LESS_OR_EQUAL
);
VkPipelineViewportStateCreateInfo viewportState = ext::vulkan::initializers::pipelineViewportStateCreateInfo(
1, 1, 0
);
VkPipelineMultisampleStateCreateInfo multisampleState = ext::vulkan::initializers::pipelineMultisampleStateCreateInfo(
VK_SAMPLE_COUNT_1_BIT,
0
);
std::vector<VkDynamicState> dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
};
VkPipelineDynamicStateCreateInfo dynamicState = ext::vulkan::initializers::pipelineDynamicStateCreateInfo(
dynamicStateEnables.data(),
static_cast<uint32_t>(dynamicStateEnables.size()),
0
);
// Binding description
std::vector<VkVertexInputBindingDescription> vertexBindingDescriptions = {
ext::vulkan::initializers::vertexInputBindingDescription(
VERTEX_BUFFER_BIND_ID,
sizeof(Vertex),
VK_VERTEX_INPUT_RATE_VERTEX
)
};
// Attribute descriptions
// Describes memory layout and shader positions
std::vector<VkVertexInputAttributeDescription> vertexAttributeDescriptions = {
// Location 0 : Position
ext::vulkan::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
0,
VK_FORMAT_R32G32_SFLOAT,
offsetof(Vertex, position)
),
// Location 1 : Texture coordinates
ext::vulkan::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
1,
VK_FORMAT_R32G32_SFLOAT,
offsetof(Vertex, uv)
)
};
VkPipelineVertexInputStateCreateInfo vertexInputState = ext::vulkan::initializers::pipelineVertexInputStateCreateInfo();
vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexBindingDescriptions.size());
vertexInputState.pVertexBindingDescriptions = vertexBindingDescriptions.data();
vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexAttributeDescriptions.size());
vertexInputState.pVertexAttributeDescriptions = vertexAttributeDescriptions.data();
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
renderMode.getRenderPass(),
0
);
pipelineCreateInfo.pVertexInputState = &vertexInputState;
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
pipelineCreateInfo.pRasterizationState = &rasterizationState;
pipelineCreateInfo.pColorBlendState = &colorBlendState;
pipelineCreateInfo.pMultisampleState = &multisampleState;
pipelineCreateInfo.pViewportState = &viewportState;
pipelineCreateInfo.pDepthStencilState = &depthStencilState;
pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.stageCount = static_cast<uint32_t>(shader.stages.size());
pipelineCreateInfo.pStages = shader.stages.data();
pipelineCreateInfo.subpass = 1;
initializePipeline(pipelineCreateInfo);
}
// Set descriptor pool
initializeDescriptorPool({
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1),
}, 2);
// Set descriptor set
{
VkDescriptorImageInfo renderTargetDescriptor = ext::vulkan::initializers::descriptorImageInfo(
framebuffer->attachments[0].view,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
sampler
);
initializeDescriptorSet({
// Binding 0 : Projection/View matrix uniform buffer
ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&(buffers.at(0).descriptor)
),
// Binding 1 : Fragment shader texture sampler
// Fragment shader: layout (binding = 1) uniform sampler2D samplerColor;
ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1,
&renderTargetDescriptor
)
});
}
/*
for (int32_t i = 0; i < swapchain.drawCommandBuffers.size(); ++i) {
VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageMemoryBarrier.image = swapchain.buffers[i].image;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.srcQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
imageMemoryBarrier.dstQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
vkCmdPipelineBarrier( swapchain.drawCommandBuffers[i], VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
}
*/
}
void ext::vulkan::RenderTargetGraphic::destroy() {
vkDestroySampler( *device, sampler, nullptr );
ext::vulkan::Graphic::destroy();
}

View File

@ -0,0 +1,206 @@
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/rendermode.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/utils/window/window.h>
#include <uf/ext/vulkan/rendertarget.h>
#include <uf/utils/mesh/mesh.h>
/*
ext::vulkan::RenderMode::~RenderMode() {
this->destroy();
}
*/
std::string ext::vulkan::RenderMode::getType() const {
return "";
}
const std::string& ext::vulkan::RenderMode::getName() const {
return this->name;
}
size_t ext::vulkan::RenderMode::subpasses() const {
return 1;
}
VkRenderPass& ext::vulkan::RenderMode::getRenderPass() {
return swapchain.renderPass;
}
void ext::vulkan::RenderMode::createCommandBuffers() {
std::vector<ext::vulkan::Graphic*> graphics;
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Mesh>() ) return;
uf::MeshBase& mesh = entity->getComponent<uf::Mesh>();
if ( !mesh.generated ) return;
ext::vulkan::Graphic& graphic = mesh.graphic;
if ( !graphic.initialized ) return;
if ( !graphic.renderMode ) return;
graphics.push_back(&graphic);
};
for ( uf::Scene* scene : ext::vulkan::scenes ) {
if ( !scene ) continue;
scene->process(filter);
}
createCommandBuffers( graphics, ext::vulkan::passes );
}
void ext::vulkan::RenderMode::createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics, const std::vector<std::string>& passes ) {
// destroy if exists
if ( swapchain.initialized ) {
auto* device = swapchain.device;
bool vsync = swapchain.vsync;
swapchain.destroy();
swapchain.initialize( *device );
}
float width = width > 0 ? this->width : ext::vulkan::width;
float height = height > 0 ? this->height : ext::vulkan::height;
VkCommandBufferBeginInfo commandBufferInfo = {};
commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
commandBufferInfo.pNext = nullptr;
// Set clear values for all framebuffer attachments with loadOp set to clear
// We use two attachments (color and depth) that are cleared at the start of the subpass and as such we need to set clear values for both
VkClearValue clearValues[2];
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderPass = renderTarget.renderPass;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = width;
renderPassBeginInfo.clearValueCount = 2;
renderPassBeginInfo.pClearValues = clearValues;
for (size_t i = 0; i < commands.size(); ++i) {
// Set target frame buffer
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &commandBufferInfo));
for ( auto graphic : graphics ) {
graphic->createImageMemoryBarrier(commands[i]);
}
// Start the first sub pass specified in our default render pass setup by the base class
// This will clear the color and depth attachment
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
// Update dynamic viewport state
VkViewport viewport = {};
viewport.height = (float) height;
viewport.width = (float) width;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
vkCmdSetViewport(commands[i], 0, 1, &viewport);
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
vkCmdSetScissor(commands[i], 0, 1, &scissor);
for ( auto pass : passes ) {
ext::vulkan::currentPass = pass;
for ( auto graphic : graphics ) {
graphic->createCommandBuffer(commands[i] );
}
}
vkCmdEndRenderPass(commands[i]);
// Ending the render pass will add an implicit barrier transitioning the frame buffer color attachment to
// VK_IMAGE_LAYOUT_PRESENT_SRC_KHR for presenting it to the windowing system
VK_CHECK_RESULT(vkEndCommandBuffer(commands[i]));
}
}
void ext::vulkan::RenderMode::render() {
// Get next image in the swap chain (back/front buffer)
VK_CHECK_RESULT(swapchain.acquireNextImage(&currentBuffer));
// Use a fence to wait until the command buffer has finished execution before using it again
VK_CHECK_RESULT(vkWaitForFences(*device, 1, &waitFences[currentBuffer], VK_TRUE, UINT64_MAX));
VK_CHECK_RESULT(vkResetFences(*device, 1, &waitFences[currentBuffer]));
// Pipeline stage at which the queue submission will wait (via pWaitSemaphores)
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
// The submit info structure specifices a command buffer queue submission batch
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = &waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
submitInfo.pWaitSemaphores = &presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
submitInfo.pSignalSemaphores = &renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
submitInfo.pCommandBuffers = &commands[currentBuffer]; // Command buffers(s) to execute in this batch (submission)
submitInfo.commandBufferCount = 1;
// Submit to the graphics queue passing a wait fence
VK_CHECK_RESULT(vkQueueSubmit(device->graphicsQueue, 1, &submitInfo, waitFences[currentBuffer]));
// Present the current buffer to the swap chain
// Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation
// This ensures that the image is not presented to the windowing system until all commands have been submitted
VK_CHECK_RESULT(swapchain.queuePresent(device->presentQueue, currentBuffer, renderCompleteSemaphore));
VK_CHECK_RESULT(vkQueueWaitIdle(device->presentQueue));
}
void ext::vulkan::RenderMode::initialize( Device& device ) {
this->device = &device;
this->width = ext::vulkan::width;
this->height = ext::vulkan::height;
// Create command buffers
{
drawCommandBuffers.resize( buffers );
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo(
device.commandPool,
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
static_cast<uint32_t>(drawCommandBuffers.size())
);
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, drawCommandBuffers.data()));
}
// Set sync objects
{
// Semaphores (Used for correct command ordering)
VkSemaphoreCreateInfo semaphoreCreateInfo = {};
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphoreCreateInfo.pNext = nullptr;
// Semaphore used to ensures that image presentation is complete before starting to submit again
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &presentCompleteSemaphore));
// Semaphore used to ensures that all commands submitted have been finished before submitting the image to the queue
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderCompleteSemaphore));
// Fences (Used to check draw command buffer completion)
VkFenceCreateInfo fenceCreateInfo = {};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
// Create in signaled state so we don't wait on first render of each command buffer
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
waitFences.resize( buffers );
for ( auto& fence : waitFences ) {
VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
}
VkPipelineStageFlags submitPipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
}
void ext::vulkan::RenderMode::destroy() {
if ( commands.size() > 0 ) {
vkFreeCommandBuffers( *device, device->commandPool, static_cast<uint32_t>(commands.size()), commands.data());
}
if ( presentCompleteSemaphore != VK_NULL_HANDLE ) {
vkDestroySemaphore( *device, presentCompleteSemaphore, nullptr);
}
if ( renderCompleteSemaphore != VK_NULL_HANDLE ) {
vkDestroySemaphore( *device, renderCompleteSemaphore, nullptr);
}
}

View File

@ -0,0 +1,228 @@
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/rendermodes/base.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/utils/window/window.h>
#include <uf/ext/vulkan/rendertarget.h>
#include <uf/utils/mesh/mesh.h>
/*
ext::vulkan::BaseRenderMode::~BaseRenderMode() {
this->destroy();
}
*/
std::string ext::vulkan::BaseRenderMode::getType() const {
return "Base";
}
const std::string& ext::vulkan::BaseRenderMode::getName() const {
return this->name;
}
size_t ext::vulkan::BaseRenderMode::subpasses() const {
return 1;
}
VkRenderPass& ext::vulkan::BaseRenderMode::getRenderPass() {
return swapchain.renderPass;
}
void ext::vulkan::BaseRenderMode::createCommandBuffers() {
std::vector<ext::vulkan::Graphic*> graphics;
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Mesh>() ) return;
uf::MeshBase& mesh = entity->getComponent<uf::Mesh>();
if ( !mesh.generated ) return;
ext::vulkan::Graphic& graphic = mesh.graphic;
if ( !graphic.initialized ) return;
if ( !graphic.renderMode ) return;
graphics.push_back(&graphic);
};
for ( uf::Scene* scene : ext::vulkan::scenes ) {
if ( !scene ) continue;
scene->process(filter);
}
createCommandBuffers( graphics, ext::vulkan::passes );
}
void ext::vulkan::BaseRenderMode::createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics, const std::vector<std::string>& passes ) {
// destroy if exists
if ( swapchain.initialized ) {
auto* device = swapchain.device;
bool vsync = swapchain.vsync;
swapchain.destroy();
swapchain.initialize( *device );
}
float width = width > 0 ? this->width : ext::vulkan::width;
float height = height > 0 ? this->height : ext::vulkan::height;
VkCommandBufferBeginInfo commandBufferInfo = {};
commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
commandBufferInfo.pNext = nullptr;
// Set clear values for all framebuffer attachments with loadOp set to clear
// We use two attachments (color and depth) that are cleared at the start of the subpass and as such we need to set clear values for both
VkClearValue clearValues[2];
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderPass = renderTarget.renderPass;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = width;
renderPassBeginInfo.clearValueCount = 2;
renderPassBeginInfo.pClearValues = clearValues;
for (size_t i = 0; i < commands.size(); ++i) {
// Set target frame buffer
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &commandBufferInfo));
for ( auto graphic : graphics ) {
graphic->createImageMemoryBarrier(commands[i]);
}
// Start the first sub pass specified in our default render pass setup by the base class
// This will clear the color and depth attachment
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
// Update dynamic viewport state
VkViewport viewport = {};
viewport.height = (float) height;
viewport.width = (float) width;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
vkCmdSetViewport(commands[i], 0, 1, &viewport);
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
vkCmdSetScissor(commands[i], 0, 1, &scissor);
for ( auto pass : passes ) {
ext::vulkan::currentPass = pass;
for ( auto graphic : graphics ) {
graphic->createCommandBuffer(commands[i] );
}
}
vkCmdEndRenderPass(commands[i]);
// Ending the render pass will add an implicit barrier transitioning the frame buffer color attachment to
// VK_IMAGE_LAYOUT_PRESENT_SRC_KHR for presenting it to the windowing system
VK_CHECK_RESULT(vkEndCommandBuffer(commands[i]));
}
}
void ext::vulkan::BaseRenderMode::render() {
// Get next image in the swap chain (back/front buffer)
VK_CHECK_RESULT(swapchain.acquireNextImage(&currentBuffer));
// Use a fence to wait until the command buffer has finished execution before using it again
VK_CHECK_RESULT(vkWaitForFences(*device, 1, &waitFences[currentBuffer], VK_TRUE, UINT64_MAX));
VK_CHECK_RESULT(vkResetFences(*device, 1, &waitFences[currentBuffer]));
// Pipeline stage at which the queue submission will wait (via pWaitSemaphores)
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
// The submit info structure specifices a command buffer queue submission batch
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = &waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
submitInfo.pWaitSemaphores = &presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
submitInfo.pSignalSemaphores = &renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
submitInfo.pCommandBuffers = &commands[currentBuffer]; // Command buffers(s) to execute in this batch (submission)
submitInfo.commandBufferCount = 1;
// Submit to the graphics queue passing a wait fence
VK_CHECK_RESULT(vkQueueSubmit(device->graphicsQueue, 1, &submitInfo, waitFences[currentBuffer]));
// Present the current buffer to the swap chain
// Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation
// This ensures that the image is not presented to the windowing system until all commands have been submitted
VK_CHECK_RESULT(swapchain.queuePresent(device->presentQueue, currentBuffer, renderCompleteSemaphore));
VK_CHECK_RESULT(vkQueueWaitIdle(device->presentQueue));
}
void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
this->device = &device;
this->width = ext::vulkan::width;
this->height = ext::vulkan::height;
{
renderTarget.device = &device;
// attach targets
struct {
size_t color, depth;
} attachments;
attachments.color = renderTarget.attach( device.formats.color, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ); // color
attachments.depth = renderTarget.attach( device.formats.depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ); // depth
// First pass: fill the G-Buffer
{
renderTarget.addPass(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
{ attachments.color },
{},
attachments.depth
);
}
}
renderTarget.initialize( device );
// Create command buffers
{
commands.resize( buffers );
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo(
device.commandPool,
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
static_cast<uint32_t>(commands.size())
);
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, commands.data()));
}
// Set sync objects
{
// Semaphores (Used for correct command ordering)
VkSemaphoreCreateInfo semaphoreCreateInfo = {};
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphoreCreateInfo.pNext = nullptr;
// Semaphore used to ensures that image presentation is complete before starting to submit again
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &presentCompleteSemaphore));
// Semaphore used to ensures that all commands submitted have been finished before submitting the image to the queue
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderCompleteSemaphore));
// Fences (Used to check draw command buffer completion)
VkFenceCreateInfo fenceCreateInfo = {};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
// Create in signaled state so we don't wait on first render of each command buffer
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
waitFences.resize( buffers );
for ( auto& fence : waitFences ) {
VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
}
VkPipelineStageFlags submitPipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
}
void ext::vulkan::BaseRenderMode::destroy() {
if ( commands.size() > 0 ) {
vkFreeCommandBuffers( *device, device->commandPool, static_cast<uint32_t>(commands.size()), commands.data());
}
if ( presentCompleteSemaphore != VK_NULL_HANDLE ) {
vkDestroySemaphore( *device, presentCompleteSemaphore, nullptr);
}
if ( renderCompleteSemaphore != VK_NULL_HANDLE ) {
vkDestroySemaphore( *device, renderCompleteSemaphore, nullptr);
}
}

View File

@ -0,0 +1,190 @@
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/rendermodes/deferred.h>
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/utils/window/window.h>
#include <uf/utils/mesh/mesh.h>
namespace {
// 0 left 1 right
uint8_t DOMINANT_EYE = 1;
}
std::string ext::vulkan::DeferredRenderMode::getType() const {
return "Defered";
}
size_t ext::vulkan::DeferredRenderMode::subpasses() const {
return renderTarget.passes.size();
}
VkRenderPass& ext::vulkan::DeferredRenderMode::getRenderPass() {
return renderTarget.renderPass;
}
void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
ext::vulkan::RenderMode::initialize( device );
{
renderTarget.device = &device;
// attach targets
struct {
size_t albedo, normals, depth, output;
} attachments;
attachments.albedo = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ); // albedo
attachments.normals = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ); // normals
attachments.depth = renderTarget.attach( swapchain.depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ); // depth
// Attach swapchain's image as output
{
attachments.output = renderTarget.attachments.size();
renderTarget.attachments.push_back({ device.formats.color, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, });
}
// First pass: fill the G-Buffer
{
renderTarget.addPass(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
{ attachments.albedo, attachments.normals, },
{},
attachments.depth
);
}
// Second pass: write to output
{
renderTarget.addPass(
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT,
{ attachments.output, },
{ attachments.albedo, attachments.normals },
attachments.depth
);
}
}
renderTarget.initialize( device );
blitter.framebuffer = &framebuffer;
blitter.initializeShaders({
{"./data/shaders/display.subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{"./data/shaders/display.subpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
blitter.initialize( device, *this );
}
void ext::vulkan::DeferredRenderMode::destroy() {
renderTarget.destroy();
}
void ext::vulkan::DeferredRenderMode::createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics, const std::vector<std::string>& passes ) {
// destroy if exists
// ext::vulkan::RenderMode& swapchain =
if ( ext::vulkan::rebuild ) {
if ( swapchain.initialized ) {
auto* device = swapchain.device;
swapchain.destroy();
swapchain.initialize( *device );
}
swapchain.initialized = true;
// destroy if exist
if ( renderTarget.initialized ) {
auto* device = renderTarget.device;
renderTarget.initialize( *device );
}
renderTarget.initialized = true;
// update descriptor set
if ( blitter.initialized ) {
VkDescriptorImageInfo textDescriptorAlbedo = ext::vulkan::initializers::descriptorImageInfo(
renderTarget.attachments[0].view,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
// Binding 0 : Projection/View matrix uniform buffer
ext::vulkan::initializers::writeDescriptorSet(
blitter.descriptorSet,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&(blitter.buffers.at(0).descriptor)
),
// Binding 1 : Albedo input attachment
ext::vulkan::initializers::writeDescriptorSet(
blitter.descriptorSet,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
1,
&textDescriptorAlbedo
),
};
vkUpdateDescriptorSets( *device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr );
}
}
float width = this->width > 0 ? this->width : ext::vulkan::width;
float height = this->height > 0 ? this->height : ext::vulkan::height;
blitter.uniforms.screenSize = { width, height };
VkCommandBufferBeginInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.pNext = nullptr;
for (int32_t i = 0; i < swapchain.commands.size(); ++i) {
VK_CHECK_RESULT(vkBeginCommandBuffer(swapchain.commands[i], &cmdBufInfo));
// Fill GBuffer
{
std::vector<VkClearValue> clearValues; clearValues.resize(4);
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[2].depthStencil = { 1.0f, 0 };
clearValues[3].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = &clearValues[0];
renderPassBeginInfo.renderPass = renderTarget.renderPass;
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[i];
for ( auto graphic : graphics ) {
graphic->createImageMemoryBarrier(swapchain.commands[i]);
}
// Update dynamic viewport state
VkViewport viewport = {};
viewport.width = (float) width;
viewport.height = (float) height;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
vkCmdBeginRenderPass(swapchain.commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(swapchain.commands[i], 0, 1, &viewport);
vkCmdSetScissor(swapchain.commands[i], 0, 1, &scissor);
for ( auto pass : passes ) {
ext::vulkan::currentPass = pass + ";DEFERRED";
for ( auto graphic : graphics ) {
// only draw graphics that are assigned to this type of render mode
if ( graphic->renderMode->getName() != this->getName() ) continue;
graphic->createCommandBuffer(swapchain.commands[i] );
}
}
vkCmdNextSubpass(swapchain.commands[i], VK_SUBPASS_CONTENTS_INLINE);
blitter.createCommandBuffer(swapchain.commands[i]);
// render gui layer
{
RenderMode* layer = &ext::vulkan::getRenderMode("Gui");
if ( layer->getName() == "Gui" ) {
RenderTargetRenderMode* guiLayer = (RenderTargetRenderMode*) layer;
guiLayer->blitter.createCommandBuffer(swapchain.commands[i]);
}
}
vkCmdEndRenderPass(swapchain.commands[i]);
}
VK_CHECK_RESULT(vkEndCommandBuffer(swapchain.commands[i]));
}
}

View File

@ -1,5 +1,5 @@
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/commands/multiview.h>
#include <uf/ext/vulkan/rendermodes/multiview.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/utils/window/window.h>
#include <uf/utils/mesh/mesh.h>
@ -10,21 +10,21 @@ namespace {
uint8_t DOMINANT_EYE = 1;
}
const std::string& ext::vulkan::MultiviewCommand::getName() const {
std::string ext::vulkan::MultiviewRenderMode::getType() const {
return "Multiview";
}
size_t ext::vulkan::MultiviewCommand::subpasses() const {
return framebuffers.left.passes.size();
size_t ext::vulkan::MultiviewRenderMode::subpasses() const {
return rendertargets.left.passes.size();
}
VkRenderPass& ext::vulkan::MultiviewCommand::getRenderPass() {
return framebuffers.left.renderPass;
VkRenderPass& ext::vulkan::MultiviewRenderMode::getRenderPass() {
return rendertargets.left.renderPass;
}
void ext::vulkan::MultiviewCommand::initialize( Device& device ) {
framebuffers.left.initialize( device );
framebuffers.right.initialize( device );
void ext::vulkan::MultiviewRenderMode::initialize( Device& device ) {
rendertargets.left.initialize( device );
rendertargets.right.initialize( device );
/*
blitter.framebuffer = DOMINANT_EYE == 0 ? &framebuffers.left : &framebuffers.right;
blitter.framebuffer = DOMINANT_EYE == 0 ? &rendertargets.left : &rendertargets.right;
blitter.initializeShaders({
{"./data/shaders/display.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{"./data/shaders/display.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
@ -32,11 +32,11 @@ void ext::vulkan::MultiviewCommand::initialize( Device& device ) {
blitter.initialize( device, ext::vulkan::swapchain );
*/
}
void ext::vulkan::MultiviewCommand::destroy() {
framebuffers.left.destroy();
framebuffers.right.destroy();
void ext::vulkan::MultiviewRenderMode::destroy() {
rendertargets.left.destroy();
rendertargets.right.destroy();
}
void ext::vulkan::MultiviewCommand::createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes ) {
void ext::vulkan::MultiviewRenderMode::createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics, const std::vector<std::string>& passes ) {
//auto& device = ext::vulkan::device;
//auto& swapchain = ext::vulkan::swapchain;
//auto& currentBuffer = ext::vulkan::currentBuffer;
@ -52,17 +52,17 @@ void ext::vulkan::MultiviewCommand::createCommandBuffers( const std::vector<void
swapchain.commandBufferSet = true;
// destroy if exist
if ( framebuffers.left.commandBufferSet ) {
auto* device = framebuffers.left.device;
framebuffers.left.initialize( *device );
if ( rendertargets.left.commandBufferSet ) {
auto* device = rendertargets.left.device;
rendertargets.left.initialize( *device );
}
framebuffers.left.commandBufferSet = true;
rendertargets.left.commandBufferSet = true;
// destroy if exist
if ( framebuffers.right.commandBufferSet ) {
auto* device = framebuffers.right.device;
framebuffers.right.initialize( *device );
if ( rendertargets.right.commandBufferSet ) {
auto* device = rendertargets.right.device;
rendertargets.right.initialize( *device );
}
framebuffers.right.commandBufferSet = true;
rendertargets.right.commandBufferSet = true;
}
// blitter.uniforms.screenSize = { width, height };
@ -129,20 +129,20 @@ void ext::vulkan::MultiviewCommand::createCommandBuffers( const std::vector<void
/*
{
// Transition eye image to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL for write
imageMemoryBarrier.image = framebuffers.left.attachments[0].image;
imageMemoryBarrier.image = rendertargets.left.attachments[0].image;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = framebuffers.left.attachments[0].layout;
imageMemoryBarrier.oldLayout = rendertargets.left.attachments[0].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
vkCmdPipelineBarrier( swapchain.drawCommandBuffers[i], VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
framebuffers.left.attachments[0].layout = imageMemoryBarrier.newLayout;
rendertargets.left.attachments[0].layout = imageMemoryBarrier.newLayout;
}
*/
// Start the first sub pass specified in our default render pass setup by the base class
// This will clear the color and depth attachment
renderPassBeginInfo.renderPass = framebuffers.left.renderPass;
renderPassBeginInfo.framebuffer = framebuffers.left.framebuffers[i];
renderPassBeginInfo.renderPass = rendertargets.left.renderPass;
renderPassBeginInfo.framebuffer = rendertargets.left.rendertargets[i];
vkCmdBeginRenderPass(swapchain.drawCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(swapchain.drawCommandBuffers[i], 0, 1, &viewport);
@ -157,8 +157,8 @@ void ext::vulkan::MultiviewCommand::createCommandBuffers( const std::vector<void
}
vkCmdEndRenderPass(swapchain.drawCommandBuffers[i]);
renderPassBeginInfo.renderPass = framebuffers.right.renderPass;
renderPassBeginInfo.framebuffer = framebuffers.right.framebuffers[i];
renderPassBeginInfo.renderPass = rendertargets.right.renderPass;
renderPassBeginInfo.framebuffer = rendertargets.right.rendertargets[i];
vkCmdBeginRenderPass(swapchain.drawCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(swapchain.drawCommandBuffers[i], 0, 1, &viewport);
vkCmdSetScissor(swapchain.drawCommandBuffers[i], 0, 1, &scissor);
@ -175,14 +175,14 @@ void ext::vulkan::MultiviewCommand::createCommandBuffers( const std::vector<void
// Transition eye image to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL for display on the companion window
/*
{
imageMemoryBarrier.image = framebuffers.left.attachments[0].image;
imageMemoryBarrier.image = rendertargets.left.attachments[0].image;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.oldLayout = framebuffers.left.attachments[0].layout;
imageMemoryBarrier.oldLayout = rendertargets.left.attachments[0].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
vkCmdPipelineBarrier( swapchain.drawCommandBuffers[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
framebuffers.left.attachments[0].layout = imageMemoryBarrier.newLayout;
rendertargets.left.attachments[0].layout = imageMemoryBarrier.newLayout;
}
*/
/*
@ -217,7 +217,7 @@ void ext::vulkan::MultiviewCommand::createCommandBuffers( const std::vector<void
vkCmdBlitImage(
swapchain.drawCommandBuffers[i],
framebuffers.left.attachments[0].image,
rendertargets.left.attachments[0].image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
swapchain.buffers[i].image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
@ -230,13 +230,13 @@ void ext::vulkan::MultiviewCommand::createCommandBuffers( const std::vector<void
// Transition eye image for SteamVR which requires this layout for submit
/*
{
imageMemoryBarrier.image = framebuffers.left.attachments[0].image;
imageMemoryBarrier.image = rendertargets.left.attachments[0].image;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.oldLayout = framebuffers.left.attachments[0].layout;
imageMemoryBarrier.oldLayout = rendertargets.left.attachments[0].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
vkCmdPipelineBarrier( swapchain.drawCommandBuffers[i], VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
framebuffers.left.attachments[0].layout = imageMemoryBarrier.newLayout;
rendertargets.left.attachments[0].layout = imageMemoryBarrier.newLayout;
}
*/
@ -244,39 +244,4 @@ void ext::vulkan::MultiviewCommand::createCommandBuffers( const std::vector<void
// VK_IMAGE_LAYOUT_PRESENT_SRC_KHR for presenting it to the windowing system
VK_CHECK_RESULT(vkEndCommandBuffer(swapchain.drawCommandBuffers[i]));
}
}
void ext::vulkan::MultiviewCommand::render() {
//auto& device = ext::vulkan::device;
//auto& swapchain = ext::vulkan::swapchain;
//auto& currentBuffer = ext::vulkan::currentBuffer;
// Get next image in the swap chain (back/front buffer)
VK_CHECK_RESULT(swapchain.acquireNextImage(&currentBuffer));
// Use a fence to wait until the command buffer has finished execution before using it again
VK_CHECK_RESULT(vkWaitForFences(device, 1, &swapchain.waitFences[currentBuffer], VK_TRUE, UINT64_MAX));
VK_CHECK_RESULT(vkResetFences(device, 1, &swapchain.waitFences[currentBuffer]));
// Pipeline stage at which the queue submission will wait (via pWaitSemaphores)
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
// The submit info structure specifices a command buffer queue submission batch
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = &waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
submitInfo.pSignalSemaphores = &swapchain.renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
submitInfo.pCommandBuffers = &swapchain.drawCommandBuffers[currentBuffer]; // Command buffers(s) to execute in this batch (submission)
submitInfo.commandBufferCount = 1;
// Submit to the graphics queue passing a wait fence
VK_CHECK_RESULT(vkQueueSubmit(device.graphicsQueue, 1, &submitInfo, swapchain.waitFences[currentBuffer]));
// Present the current buffer to the swap chain
// Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation
// This ensures that the image is not presented to the windowing system until all commands have been submitted
VK_CHECK_RESULT(swapchain.queuePresent(device.presentQueue, currentBuffer, swapchain.renderCompleteSemaphore));
VK_CHECK_RESULT(vkQueueWaitIdle(device.presentQueue));
}

View File

@ -0,0 +1,178 @@
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/utils/window/window.h>
#include <uf/utils/mesh/mesh.h>
std::string ext::vulkan::RenderTargetRenderMode::getType() const {
return "RenderTarget";
}
size_t ext::vulkan::RenderTargetRenderMode::subpasses() const {
return renderTarget.passes.size();
}
VkRenderPass& ext::vulkan::RenderTargetRenderMode::getRenderPass() {
return renderTarget.renderPass;
}
void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
ext::vulkan::RenderMode::initialize( device );
{
renderTarget.device = &device;
// attach targets
struct {
size_t color, depth;
} attachments;
attachments.color = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ); // albedo
attachments.depth = renderTarget.attach( swapchain.depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ); // depth
// First pass: write to target
{
renderTarget.addPass(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
{ attachments.color },
{},
attachments.depth
);
}
}
renderTarget.initialize( device );
blitter.framebuffer = &framebuffer;
blitter.initializeShaders({
{"./data/shaders/display.rendertarget.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{"./data/shaders/display.rendertarget.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
blitter.initialize();
// Create command buffers
{
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo(
device.commandPool,
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1
);
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &commandBuffer));
}
// Set sync objects
{
// Fence for syncs
VkFenceCreateInfo fenceCreateInfo = ext::vulkan::initializers::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT);
VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
}
}
void ext::vulkan::RenderTargetRenderMode::destroy() {
renderTarget.destroy();
if ( fence != VK_NULL_HANDLE ) {
vkDestroyFence(*device, fence, nullptr);
fence = VK_NULL_HANDLE;
}
}
void ext::vulkan::RenderTargetRenderMode::render() {
// Submit commands
// Use a fence to ensure that command buffer has finished executing before using it again
vkWaitForFences( *device, 1, &fence, VK_TRUE, UINT64_MAX );
vkResetFences( *device, 1, &fence );
VkSubmitInfo renderSubmitInfo = ext::vulkan::initializers::submitInfo();
renderSubmitInfo.commandBufferCount = 1;
renderSubmitInfo.pCommandBuffers = &commandBuffer;
VK_CHECK_RESULT(vkQueueSubmit(device->graphicsQueue, 1, &renderSubmitInfo, fence));
}
void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics, const std::vector<std::string>& passes ) {
// destroy if exists
if ( swapchain.rebuild ) {
// destroy if exist
if ( renderTarget.commandBufferSet ) {
auto* device = renderTarget.device;
renderTarget.initialize( *device );
}
renderTarget.commandBufferSet = true;
// update descriptor set
if ( blitter.initialized ) {
VkDescriptorImageInfo renderTargetDescription = ext::vulkan::initializers::descriptorImageInfo(
renderTarget.attachments[0].view,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
blitter.sampler
);
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
// Binding 0 : Projection/View matrix uniform buffer
ext::vulkan::initializers::writeDescriptorSet(
blitter.descriptorSet,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&(blitter.buffers.at(0).descriptor)
),
// Binding 1 : Albedo input attachment
ext::vulkan::initializers::writeDescriptorSet(
blitter.descriptorSet,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1,
&renderTargetDescription
),
};
vkUpdateDescriptorSets( *device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr );
}
}
float width = this->width > 0 ? this->width : ext::vulkan::width;
float height = this->height > 0 ? this->height : ext::vulkan::height;
VkCommandBufferBeginInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.pNext = nullptr;
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo));
{
std::vector<VkClearValue> clearValues; clearValues.resize(2);
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = &clearValues[0];
renderPassBeginInfo.renderPass = renderTarget.renderPass;
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[0];
for ( auto graphic : graphics ) {
graphic.createImageMemoryBarrier(commandBuffer);
}
// Update dynamic viewport state
VkViewport viewport = {};
viewport.width = (float) width;
viewport.height = (float) height;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
for ( auto pass : passes ) {
ext::vulkan::currentPass = pass + ";TOTEXTURE";
for ( auto graphic : graphics ) {
if ( graphic->renderMode && graphic->renderMode->getName() != this->getName() ) continue;
graphic->createCommandBuffer(commandBuffer );
}
}
vkCmdEndRenderPass(commandBuffer);
}
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
}

View File

@ -13,7 +13,7 @@ void ext::vulkan::RenderTarget::addPass( VkPipelineStageFlags stage, VkAccessFla
pass.access = access;
for ( auto& i : colors ) pass.colors.push_back( { i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL } );
for ( auto& i : inputs ) pass.inputs.push_back( { i, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } );
pass.depth = { depth, attachments[depth].layout };
if ( depth < attachments.size() ) pass.depth = { depth, attachments[depth].layout };
passes.push_back(pass);
}
size_t ext::vulkan::RenderTarget::attach( VkFormat format, VkImageUsageFlags usage, Attachment* attachment ) {
@ -91,7 +91,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
if ( height == 0 ) height = ext::vulkan::height;
}
// resize attachments if necessary
if ( commandBufferSet ) {
if ( initialized ) {
for ( auto& attachment: this->attachments ) {
if ( attachment.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) continue;
attach( attachment.format, attachment.usage, &attachment );
@ -113,6 +113,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
description.finalLayout = attachment.layout;
description.flags = 0;
attachments.push_back(description);
}
@ -144,6 +145,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
description.preserveAttachmentCount = 0;
description.pPreserveAttachments = nullptr;
description.pResolveAttachments = nullptr;
description.flags = 0;
descriptions.push_back(description);
// transition dependency between subpasses
@ -166,7 +168,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
dependencies.push_back(dependency);
}
/*
std::cout << this << std::endl;
for ( auto& dependency : dependencies ) {
std::cout << "Subpass: " << std::hex << dependency.srcSubpass << " -> " << std::hex << dependency.dstSubpass << std::endl;;
@ -174,7 +176,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
std::cout << "AccessMask: " << std::hex << dependency.srcAccessMask << " -> " << std::hex << dependency.dstAccessMask << std::endl;;
std::cout << std::endl;
}
*/
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
@ -190,8 +192,12 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
}
// Create framebuffer
bool boundToSwapchain = false;
for ( auto& attachment : this->attachments ) {
if ( attachment.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) boundToSwapchain = true;
}
{
framebuffers.resize(swapchain.imageCount);
framebuffers.resize(boundToSwapchain ? swapchain.imageCount : 1);
for ( size_t i = 0; i < framebuffers.size(); ++i ) {
std::vector<VkImageView> attachments;
for ( auto& attachment : this->attachments ) {

View File

@ -24,56 +24,23 @@ VkResult ext::vulkan::Swapchain::queuePresent( VkQueue queue, uint32_t imageInde
return vkQueuePresentKHR(queue, &presentInfo);
}
void ext::vulkan::Swapchain::initialize( Device& device, size_t width, size_t height, bool vsync ) {
void ext::vulkan::Swapchain::initialize( Device& device ) {
// Bind
{
this->device = &device;
this->surface = device.surface;
this->vsync = vsync;
if ( width == 0 ) width = ext::vulkan::width;
if ( height == 0 ) height = ext::vulkan::height;
}
// Set formats
{
std::vector<VkSurfaceFormatKHR> formats;
uint32_t formatCount; vkGetPhysicalDeviceSurfaceFormatsKHR( device.physicalDevice, surface, &formatCount, nullptr);
formats.resize( formatCount );
vkGetPhysicalDeviceSurfaceFormatsKHR( device.physicalDevice, surface, &formatCount, formats.data() );
// If the surface format list only includes one entry with VK_FORMAT_UNDEFINED,
// there is no preferered format, so we assume VK_FORMAT_B8G8R8A8_UNORM
if ( (formatCount == 1) && (formats[0].format == VK_FORMAT_UNDEFINED) ) {
colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
colorSpace = formats[0].colorSpace;
} else {
// iterate over the list of available surface format and
// check for the presence of VK_FORMAT_B8G8R8A8_UNORM
bool found_B8G8R8A8_UNORM = false;
for ( auto&& surfaceFormat : formats ) {
if ( surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM ) {
colorFormat = surfaceFormat.format;
colorSpace = surfaceFormat.colorSpace;
found_B8G8R8A8_UNORM = true;
break;
}
}
// in case VK_FORMAT_B8G8R8A8_UNORM is not available
// select the first available color format
if ( !found_B8G8R8A8_UNORM ) {
colorFormat = formats[0].format;
colorSpace = formats[0].colorSpace;
}
}
}
// Set present
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
{
// Get available present modes
uint32_t presentModeCount;
VK_CHECK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(device.physicalDevice, surface, &presentModeCount, NULL));
VK_CHECK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(device.physicalDevice, device.surface, &presentModeCount, NULL));
assert(presentModeCount > 0);
std::vector<VkPresentModeKHR> presentModes(presentModeCount);
VK_CHECK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(device.physicalDevice, surface, &presentModeCount, presentModes.data()));
VK_CHECK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(device.physicalDevice, device.surface, &presentModeCount, presentModes.data()));
// Select a present mode for the swapchain
@ -97,14 +64,10 @@ void ext::vulkan::Swapchain::initialize( Device& device, size_t width, size_t he
VkExtent2D swapchainExtent = {};
{
VkSurfaceCapabilitiesKHR capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR( device.physicalDevice, surface, &capabilities );
vkGetPhysicalDeviceSurfaceCapabilitiesKHR( device.physicalDevice, device.surface, &capabilities );
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
swapchainExtent = capabilities.currentExtent;
} else {
/*
int width, height;
glfwGetFramebufferSize(uf::window, &width, &height);
*/
auto size = device.window->getSize();
VkExtent2D swapchainExtent = {
static_cast<uint32_t>(size[0]),
@ -121,7 +84,7 @@ void ext::vulkan::Swapchain::initialize( Device& device, size_t width, size_t he
// Get physical device surface properties and formats
VkSurfaceCapabilitiesKHR surfCaps;
VK_CHECK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device.physicalDevice, surface, &surfCaps));
VK_CHECK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device.physicalDevice, device.surface, &surfCaps));
// Determine the number of images
uint32_t desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1;
@ -156,10 +119,10 @@ void ext::vulkan::Swapchain::initialize( Device& device, size_t width, size_t he
VkSwapchainCreateInfoKHR swapchainCI = {};
swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchainCI.pNext = NULL;
swapchainCI.surface = surface;
swapchainCI.surface = device.surface;
swapchainCI.minImageCount = desiredNumberOfSwapchainImages;
swapchainCI.imageFormat = colorFormat;
swapchainCI.imageColorSpace = colorSpace;
swapchainCI.imageFormat = device->formats.color;
swapchainCI.imageColorSpace = device->formats.space;
swapchainCI.imageExtent = { swapchainExtent.width, swapchainExtent.height };
swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
swapchainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform;
@ -187,317 +150,25 @@ void ext::vulkan::Swapchain::initialize( Device& device, size_t width, size_t he
// If an existing swap chain is re-created, destroy the old swap chain
// This also cleans up all the presentable images
if (oldSwapchain != VK_NULL_HANDLE) {
for (uint32_t i = 0; i < imageCount; i++) {
vkDestroyImageView( device.logicalDevice, buffers[i].view, nullptr);
}
vkDestroySwapchainKHR( device.logicalDevice, oldSwapchain, nullptr);
}
VK_CHECK_RESULT(vkGetSwapchainImagesKHR( device.logicalDevice, swapChain, &imageCount, NULL));
// Get the swap chain images
images.resize(imageCount);
VK_CHECK_RESULT(vkGetSwapchainImagesKHR( device.logicalDevice, swapChain, &imageCount, images.data()));
// Get the swap chain buffers containing the image and imageview
buffers.resize(imageCount);
for ( uint32_t i = 0; i < imageCount; i++ ) {
VkImageViewCreateInfo colorAttachmentView = {};
colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
colorAttachmentView.pNext = NULL;
colorAttachmentView.format = colorFormat;
colorAttachmentView.components = {
VK_COMPONENT_SWIZZLE_R,
VK_COMPONENT_SWIZZLE_G,
VK_COMPONENT_SWIZZLE_B,
VK_COMPONENT_SWIZZLE_A
};
colorAttachmentView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
colorAttachmentView.subresourceRange.baseMipLevel = 0;
colorAttachmentView.subresourceRange.levelCount = 1;
colorAttachmentView.subresourceRange.baseArrayLayer = 0;
colorAttachmentView.subresourceRange.layerCount = 1;
colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
colorAttachmentView.flags = 0;
buffers[i].image = images[i];
colorAttachmentView.image = buffers[i].image;
VK_CHECK_RESULT(vkCreateImageView( device.logicalDevice, &colorAttachmentView, nullptr, &buffers[i].view));
}
}
// Create command buffers
{
drawCommandBuffers.resize( imageCount );
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo(
device.commandPool,
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
static_cast<uint32_t>(drawCommandBuffers.size())
);
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, drawCommandBuffers.data()));
}
// Set sync objects
{
// Semaphores (Used for correct command ordering)
VkSemaphoreCreateInfo semaphoreCreateInfo = {};
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphoreCreateInfo.pNext = nullptr;
// Semaphore used to ensures that image presentation is complete before starting to submit again
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &presentCompleteSemaphore));
// Semaphore used to ensures that all commands submitted have been finished before submitting the image to the queue
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderCompleteSemaphore));
// Fences (Used to check draw command buffer completion)
VkFenceCreateInfo fenceCreateInfo = {};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
// Create in signaled state so we don't wait on first render of each command buffer
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
waitFences.resize( imageCount );
for ( auto& fence : waitFences ) {
VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
}
VkPipelineStageFlags submitPipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
/*
submitInfo = ext::vulkan::initializers::submitInfo();
submitInfo.pWaitDstStageMask = &submitPipelineStages;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &presentCompleteSemaphore;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &renderCompleteSemaphore;
*/
}
// Grab depth/stencil format
{
// Since all depth formats may be optional, we need to find a suitable depth format to use
// Start with the highest precision packed format
std::vector<VkFormat> depthFormats = {
VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_D32_SFLOAT,
VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_D16_UNORM_S8_UINT,
VK_FORMAT_D16_UNORM
};
for ( auto& format : depthFormats ) {
VkFormatProperties formatProps;
vkGetPhysicalDeviceFormatProperties( device.physicalDevice, format, &formatProps );
// Format must support depth stencil attachment for optimal tiling
if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
depthFormat = format;
}
}
}
// Create depth/stencil buffer
{
// Create an optimal image used as the depth stencil attachment
VkImageCreateInfo image = {};
image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image.imageType = VK_IMAGE_TYPE_2D;
image.format = depthFormat;
// Use example's height and width
image.extent = { width, height, 1 };
image.mipLevels = 1;
image.arrayLayers = 1;
image.samples = VK_SAMPLE_COUNT_1_BIT;
image.tiling = VK_IMAGE_TILING_OPTIMAL;
image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthStencil.image));
// Allocate memory for the image (device local) and bind it to our image
VkMemoryAllocateInfo memAlloc = {};
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device, depthStencil.image, &memReqs);
memAlloc.allocationSize = memReqs.size;
memAlloc.memoryTypeIndex = getMemoryTypeIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &depthStencil.mem));
VK_CHECK_RESULT(vkBindImageMemory(device, depthStencil.image, depthStencil.mem, 0));
// Create a view for the depth stencil image
// Images aren't directly accessed in Vulkan, but rather through views described by a subresource range
// This allows for multiple views of one image with differing ranges (e.g. for different layers)
VkImageViewCreateInfo depthStencilView = {};
depthStencilView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthStencilView.format = depthFormat;
depthStencilView.subresourceRange = {};
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
depthStencilView.subresourceRange.baseMipLevel = 0;
depthStencilView.subresourceRange.levelCount = 1;
depthStencilView.subresourceRange.baseArrayLayer = 0;
depthStencilView.subresourceRange.layerCount = 1;
depthStencilView.image = depthStencil.image;
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthStencil.view));
}
// Create render pass
{
// This example will use a single render pass with one subpass
// Descriptors for the attachments used by this renderpass
std::array<VkAttachmentDescription, 2> attachments = {};
// Color attachment
attachments[0].format = swapchain.colorFormat; // Use the color format selected by the swapchain
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; // We don't use multi sampling in this example
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // Clear this attachment at the start of the render pass
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // Keep it's contents after the render pass is finished (for displaying it)
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // We don't use stencil, so don't care for load
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // Same for store
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Layout at render pass start. Initial doesn't matter, so we use undefined
attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; // Layout to which the attachment is transitioned when the render pass is finished
// As we want to present the color buffer to the swapchain, we transition to PRESENT_KHR
// Depth attachment
attachments[1].format = depthFormat; // A proper depth format is selected in the example base
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // Clear depth at start of first subpass
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // We don't need depth after render pass has finished (DONT_CARE may result in better performance)
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // No stencil
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // No Stencil
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Layout at render pass start. Initial doesn't matter, so we use undefined
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // Transition to depth/stencil attachment
// Setup attachment references
VkAttachmentReference colorReference = {};
colorReference.attachment = 0; // Attachment 0 is color
colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // Attachment layout used as color during the subpass
VkAttachmentReference depthReference = {};
depthReference.attachment = 1; // Attachment 1 is color
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // Attachment used as depth/stemcil used during the subpass
// Setup a single subpass reference
VkSubpassDescription subpassDescription = {};
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDescription.colorAttachmentCount = 1; // Subpass uses one color attachment
subpassDescription.pColorAttachments = &colorReference; // Reference to the color attachment in slot 0
subpassDescription.pDepthStencilAttachment = &depthReference; // Reference to the depth attachment in slot 1
subpassDescription.inputAttachmentCount = 0; // Input attachments can be used to sample from contents of a previous subpass
subpassDescription.pInputAttachments = nullptr; // (Input attachments not used by this example)
subpassDescription.preserveAttachmentCount = 0; // Preserved attachments can be used to loop (and preserve) attachments through subpasses
subpassDescription.pPreserveAttachments = nullptr; // (Preserve attachments not used by this example)
subpassDescription.pResolveAttachments = nullptr; // Resolve attachments are resolved at the end of a sub pass and can be used for e.g. multi sampling
// Setup subpass dependencies
// These will add the implicit ttachment layout transitionss specified by the attachment descriptions
// The actual usage layout is preserved through the layout specified in the attachment reference
// Each subpass dependency will introduce a memory and execution dependency between the source and dest subpass described by
// srcStageMask, dstStageMask, srcAccessMask, dstAccessMask (and dependencyFlags is set)
// Note: VK_SUBPASS_EXTERNAL is a special constant that refers to all commands executed outside of the actual renderpass)
std::array<VkSubpassDependency, 2> dependencies;
// First dependency at the start of the renderpass
// Does the transition from final to initial layout
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; // Producer of the dependency
dependencies[0].dstSubpass = 0; // Consumer is our single subpass that will wait for the execution depdendency
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
// Second dependency at the end the renderpass
// Does the transition from the initial to the final layout
dependencies[1].srcSubpass = 0; // Producer of the dependency is our single subpass
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; // Consumer are all commands outside of the renderpass
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
// Create the actual renderpass
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size()); // Number of attachments used by this render pass
renderPassInfo.pAttachments = attachments.data(); // Descriptions of the attachments used by the render pass
renderPassInfo.subpassCount = 1; // We only use one subpass in this example
renderPassInfo.pSubpasses = &subpassDescription; // Description of that subpass
renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size()); // Number of subpass dependencies
renderPassInfo.pDependencies = dependencies.data(); // Subpass dependencies used by the render pass
VK_CHECK_RESULT(vkCreateRenderPass( device, &renderPassInfo, nullptr, &renderPass));
}
// Create pipeline cache
{
VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {};
pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
VK_CHECK_RESULT(vkCreatePipelineCache( device, &pipelineCacheCreateInfo, nullptr, &pipelineCache));
}
// Create framebuffer
{
// Create a frame buffer for every image in the swapchain
frameBuffers.resize(swapchain.imageCount);
for (size_t i = 0; i < frameBuffers.size(); i++)
{
std::array<VkImageView, 2> attachments;
attachments[0] = swapchain.buffers[i].view; // Color attachment is the view of the swapchain image
attachments[1] = depthStencil.view; // Depth/Stencil attachment is the same for all frame buffers
VkFramebufferCreateInfo frameBufferCreateInfo = {};
frameBufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
// All frame buffers use the same renderpass setup
frameBufferCreateInfo.renderPass = renderPass;
frameBufferCreateInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
frameBufferCreateInfo.pAttachments = attachments.data();
frameBufferCreateInfo.width = width;
frameBufferCreateInfo.height = height;
frameBufferCreateInfo.layers = 1;
// Create the framebuffer
VK_CHECK_RESULT(vkCreateFramebuffer( device, &frameBufferCreateInfo, nullptr, &frameBuffers[i]));
}
if (oldSwapchain != VK_NULL_HANDLE) vkDestroySwapchainKHR( device.logicalDevice, oldSwapchain, nullptr);
VK_CHECK_RESULT(vkGetSwapchainImagesKHR( device.logicalDevice, swapChain, &buffers, NULL));
}
}
void ext::vulkan::Swapchain::destroy() {
if ( !device ) return;
vkDestroyRenderPass( *device, renderPass, nullptr );
for (uint32_t i = 0; i < swapchain.frameBuffers.size(); i++) {
vkDestroyFramebuffer( *device, swapchain.frameBuffers[i], nullptr );
}
{
vkDestroyImageView( *device, depthStencil.view, nullptr );
vkDestroyImage( *device, depthStencil.image, nullptr );
vkFreeMemory( *device, depthStencil.mem, nullptr );
}
vkDestroyPipelineCache( *device, pipelineCache, nullptr );
if ( drawCommandBuffers.size() > 0 ) {
vkFreeCommandBuffers( *device, device->commandPool, static_cast<uint32_t>(drawCommandBuffers.size()), drawCommandBuffers.data());
}
if ( swapChain != VK_NULL_HANDLE ) {
for ( uint32_t i = 0; i < imageCount; i++ ) {
vkDestroyImageView( *device, buffers[i].view, nullptr);
}
vkDestroySwapchainKHR( *device, swapChain, nullptr);
}
if ( presentCompleteSemaphore != VK_NULL_HANDLE ) {
vkDestroySemaphore( *device, presentCompleteSemaphore, nullptr);
}
if ( renderCompleteSemaphore != VK_NULL_HANDLE ) {
vkDestroySemaphore( *device, renderCompleteSemaphore, nullptr);
}
for ( auto& fence : waitFences ) {
vkDestroyFence( *device, fence, nullptr);
fence = VK_NULL_HANDLE;
}
renderPass = VK_NULL_HANDLE;
pipelineCache = VK_NULL_HANDLE;
presentCompleteSemaphore = VK_NULL_HANDLE;
renderCompleteSemaphore = VK_NULL_HANDLE;
swapChain = VK_NULL_HANDLE;
surface = VK_NULL_HANDLE;
device = VK_NULL_HANDLE;
}

View File

@ -158,6 +158,15 @@ void ext::vulkan::Texture::setImageLayout(
subresourceRange.layerCount = 1;
setImageLayout(cmdbuffer, image, oldImageLayout, newImageLayout, subresourceRange, srcStageMask, dstStageMask);
}
void ext::vulkan::Texture2D::loadFromFile(
std::string filename,
VkFormat format,
VkImageUsageFlags imageUsageFlags,
VkImageLayout imageLayout,
bool forceLinear
) {
return loadFromFile( filename, ext::vulkan::device, ext::vulkan::device.graphicsQueue, format, imageUsageFlags, imageLayout, forceLinear );
}
void ext::vulkan::Texture2D::loadFromFile(
std::string filename,
Device& device,
@ -223,7 +232,7 @@ void ext::vulkan::Texture2D::loadFromFile(
*/
// convert to power of two
image.padToPowerOfTwo();
//image.padToPowerOfTwo();
this->fromBuffers(
(void*) image.getPixelsPtr(),
@ -233,11 +242,20 @@ void ext::vulkan::Texture2D::loadFromFile(
image.getDimensions()[1],
device,
copyQueue,
VK_FILTER_LINEAR,
filter,
imageUsageFlags,
imageLayout
);
}
void ext::vulkan::Texture2D::loadFromImage(
uf::Image& image,
VkFormat format,
VkImageUsageFlags imageUsageFlags,
VkImageLayout imageLayout,
bool forceLinear
) {
return loadFromImage( image, ext::vulkan::device, ext::vulkan::device.graphicsQueue, format, imageUsageFlags, imageLayout, forceLinear );
}
void ext::vulkan::Texture2D::loadFromImage(
uf::Image& image,
Device& device,
@ -287,7 +305,7 @@ void ext::vulkan::Texture2D::loadFromImage(
}
// convert to power of two
image.padToPowerOfTwo();
//image.padToPowerOfTwo();
this->fromBuffers(
(void*) image.getPixelsPtr(),

View File

@ -1,25 +1,31 @@
#include <uf/ext/glfw/glfw.h>
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/ext/vulkan/commands/deferred.h>
#include <uf/ext/vulkan/rendermodes/multiview.h>
#include <uf/ext/vulkan/rendermodes/deferred.h>
#include <uf/utils/mesh/mesh.h>
#include <ostream>
#include <fstream>
uint32_t ext::vulkan::width = 800;
uint32_t ext::vulkan::height = 600;
uint32_t ext::vulkan::currentBuffer = 600;
ext::vulkan::Device ext::vulkan::device;
ext::vulkan::Swapchain ext::vulkan::swapchain;
ext::vulkan::Allocator ext::vulkan::allocator;
// std::vector<ext::vulkan::Graphic*> ext::vulkan::graphics;
std::vector<ext::vulkan::Graphic*>* ext::vulkan::graphics = NULL;
std::vector<std::string> ext::vulkan::passes = { "BASE" };
std::string ext::vulkan::currentPass = "BASE";
bool ext::vulkan::resizedFramebuffer = false;
bool ext::vulkan::validation = true;
bool ext::vulkan::openvr = false;
ext::vulkan::Device ext::vulkan::device;
ext::vulkan::Allocator ext::vulkan::allocator;
ext::vulkan::Swapchain ext::vulkan::swapchain;
std::mutex ext::vulkan::mutex;
ext::vulkan::Command* ext::vulkan::command = NULL;
bool ext::vulkan::resizedFramebuffer = false;
uint32_t ext::vulkan::currentBuffer = 600;
// std::vector<ext::vulkan::Graphic*> ext::vulkan::graphics;
std::vector<std::string> ext::vulkan::passes = { "BASE" };
//std::vector<ext::vulkan::Graphic*>* ext::vulkan::graphics = NULL;
std::vector<uf::Scene*> ext::vulkan::scenes;
std::string ext::vulkan::currentPass = "BASE";
std::vector<ext::vulkan::RenderMode*> ext::vulkan::renderModes;
VkResult ext::vulkan::CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) {
auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
@ -144,8 +150,21 @@ void ext::vulkan::alignedFree(void* data) {
free(data);
#endif
}
#include <uf/ext/vulkan/commands/multiview.h>
ext::vulkan::RenderMode& ext::vulkan::addRenderMode( ext::vulkan::RenderMode* mode, const std::string& name ) {
mode->name = name;
renderModes.push_back(mode);
return *mode;
}
ext::vulkan::RenderMode& ext::vulkan::getRenderMode( const std::string& name ) {
RenderMode* target = renderModes[ renderModes.size()-1 ];
for ( auto& renderMode: renderModes ) {
if ( renderMode->getName() == name ) {
target = renderMode;
break;
}
}
return *target;
}
void ext::vulkan::initialize( uint8_t stage ) {
switch ( stage ) {
@ -158,31 +177,69 @@ void ext::vulkan::initialize( uint8_t stage ) {
allocatorInfo.device = device.logicalDevice;
vmaCreateAllocator(&allocatorInfo, &allocator);
}
if ( !ext::vulkan::command ) {
// ext::vulkan::command = ext::vulkan::openvr ? new ext::vulkan::MultiviewCommand() : new ext::vulkan::Command();
// would ternary but yields "conditional expression between distinct pointer types ext::vulkan::MultiviewCommand* and ext::vulkan::DeferredCommand* lacks a cast"
if ( ext::vulkan::openvr ) ext::vulkan::command = new ext::vulkan::MultiviewCommand();
else ext::vulkan::command = new ext::vulkan::DeferredCommand();
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
renderMode->initialize(device);
}
/* resort */ {
/*
for ( auto it = renderModes.begin(); it != renderModes.end(); ++it ) {
if ( (*it)->getName() == "" ) {
// std::rotate( renderModes.begin(), it, renderModes.end() );
RenderMode* target = *it;
renderModes.erase(it);
renderModes.push_back(target);
break;
}
}
std::cout << "Render order: ";
for ( auto it = renderModes.begin(); it != renderModes.end(); ++it ) {
std::cout << "`" << (*it)->getName() << "` -> ";
}
std::cout << std::endl;
*/
}
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
renderMode->createCommandBuffers();
}
ext::vulkan::command->initialize(device);
ext::vulkan::command->createCommandBuffers();
} break;
/*
case 1: if ( ext::vulkan::graphics ) {
auto& graphics = *ext::vulkan::graphics;
for ( Graphic* graphic : graphics ) {
graphic->initialize( device, swapchain );
if ( !graphic->initialized ) {
graphic->initialize();
}
}
} break;
*/
case 1: {
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Mesh>() ) return;
uf::MeshBase& mesh = entity->getComponent<uf::Mesh>();
ext::vulkan::Graphic& graphic = mesh.graphic;
if ( !mesh.generated ) return;
if ( graphic.initialized ) return;
graphic.initialize();
swapchain.rebuild = true;
};
for ( uf::Scene* scene : ext::vulkan::scenes ) {
if ( !scene ) continue;
scene->process(filter);
}
}
case 2: {
ext::vulkan::command->createCommandBuffers();
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
renderMode->createCommandBuffers();
}
} break;
default: {
throw std::runtime_error("invalid stage id");
} break;
}
}
#include <ostream>
std::ostream& operator<<(std::ostream& os, const ext::vulkan::Graphic& graphic) {
os << graphic.name() << ": " << &graphic;
return os;
@ -190,49 +247,101 @@ std::ostream& operator<<(std::ostream& os, const ext::vulkan::Graphic& graphic)
void ext::vulkan::tick() {
// check for changes in swapchain
// ext::vulkan::mutex.lock();
/*
if ( ext::vulkan::graphics ) {
auto& graphics = *ext::vulkan::graphics;
for ( Graphic* graphic : graphics ) {
if ( !graphic->initialized ) {
swapchain.rebuild = true;
graphic->initialize( device, swapchain );
graphic->initialize();
}
}
}
*/
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Mesh>() ) return;
uf::MeshBase& mesh = entity->getComponent<uf::Mesh>();
ext::vulkan::Graphic& graphic = mesh.graphic;
// if ( !graphic->process ) return;
if ( !mesh.generated ) return;
if ( graphic.initialized ) return;
swapchain.rebuild = true;
graphic.initialize();
};
for ( uf::Scene* scene : ext::vulkan::scenes ) {
if ( !scene ) continue;
scene->process(filter);
}
if ( swapchain.rebuild ) {
ext::vulkan::command->createCommandBuffers();
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
renderMode->createCommandBuffers();
}
swapchain.rebuild = false;
}
// ext::vulkan::mutex.unlock();
}
void ext::vulkan::render() {
ext::vulkan::command->render();
// Handle resizes
if ( resizedFramebuffer ) {
resizedFramebuffer = false;
/*
if ( ext::vulkan::graphics ) {
auto& graphics = *ext::vulkan::graphics;
for ( Graphic* graphic : graphics ) {
if ( !graphic || !graphic->process ) continue;
graphic->render();
}
}
*/
/*
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Mesh>() ) return;
uf::MeshBase& mesh = entity->getComponent<uf::Mesh>();
ext::vulkan::Graphic& graphic = mesh.graphic;
// if ( !graphic.process ) return;
if ( !graphic.initialized ) return;
graphic.render();
};
for ( uf::Scene* scene : ext::vulkan::scenes ) {
if ( !scene ) continue;
scene->process(filter);
}
*/
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
renderMode->render();
}
if ( !ext::vulkan::graphics ) return;
auto& graphics = *ext::vulkan::graphics;
for ( Graphic* graphic : graphics ) {
if ( !graphic || !graphic->process ) continue;
graphic->render();
}
// Handle resizes
if ( resizedFramebuffer ) resizedFramebuffer = false;
}
void ext::vulkan::destroy() {
vkDeviceWaitIdle( device );
ext::vulkan::command->destroy();
delete ext::vulkan::command;
ext::vulkan::command = NULL;
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Mesh>() ) return;
uf::MeshBase& mesh = entity->getComponent<uf::Mesh>();
ext::vulkan::Graphic& graphic = mesh.graphic;
if ( !graphic.initialized ) return;
graphic.destroy();
};
for ( uf::Scene* scene : ext::vulkan::scenes ) {
if ( !scene ) continue;
scene->process(filter);
}
/*
if ( ext::vulkan::graphics ) {
auto& graphics = *ext::vulkan::graphics;
for ( Graphic* graphic : graphics ) {
graphic->destroy();
}
}
*/
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
renderMode->destroy();
delete renderMode;
renderMode = NULL;
}
vmaDestroyAllocator( allocator );
swapchain.destroy();
device.destroy();

View File

@ -5,4 +5,11 @@ uf::Component::~Component() {
pod::Component& component = kv.second;
uf::userdata::destroy(component.userdata);
}
}
#include <uf/utils/serialize/serializer.h>
// override serializers
template<>
uf::Serializer uf::Serializer::toBase64( const pod::Component& input ) {
}

View File

@ -1,5 +1,11 @@
#include <uf/utils/mesh/mesh.h>
/*
uf::Graphic::~Graphic() {
this->destroy();
}
void uf::Graphic::destroy( bool clear ) {
}
*/
// Used for terrain
std::vector<ext::vulkan::VertexDescriptor> pod::Vertex_3F2F3F32B::descriptor = {
{

View File

@ -0,0 +1,5 @@
#include <uf/utils/singletons/pre_main.h>
uf::StaticInitialization::StaticInitialization( std::function<void()> fun ) {
fun();
}

View File

@ -18,10 +18,10 @@ uint8_t* uf::Glyph::generate( ext::freetype::Glyph& glyph, unsigned long c, uint
}
// this->m_sdf = false;
// this->setSize( { static_cast<int>(glyph.face->glyph->metrics.width / 64), static_cast<int>(glyph.face->glyph->metrics.height / 64) } );
// this->setSize( { static_cast<int>(glyph.face->glyph->metrics.width) >> 6, static_cast<int>(glyph.face->glyph->metrics.height) >> 6 } );
this->setSize( { static_cast<int>(glyph.face->glyph->bitmap.width), static_cast<int>(glyph.face->glyph->bitmap.rows) } );
this->setBearing( { glyph.face->glyph->bitmap_left, glyph.face->glyph->bitmap_top } );
this->setAdvance( {static_cast<int>(glyph.face->glyph->advance.x / 64), static_cast<int>(glyph.face->glyph->advance.y / 64)} );
this->setAdvance( {static_cast<int>(glyph.face->glyph->advance.x) >> 6, static_cast<int>(glyph.face->glyph->advance.y) >> 6} );
// this->setPadding( {4, 4} );
uint8_t* bitmap = glyph.face->glyph->bitmap.buffer;
@ -70,10 +70,10 @@ uint8_t* uf::Glyph::generate( ext::freetype::Glyph& glyph, const uf::String& c,
delete[] this->m_buffer;
}
// this->setSize( { static_cast<int>(glyph.face->glyph->metrics.width / 64), static_cast<int>(glyph.face->glyph->metrics.height / 64) } );
// this->setSize( { static_cast<int>(glyph.face->glyph->metrics.width) >> 6, static_cast<int>(glyph.face->glyph->metrics.height) >> 6 } );
this->setSize( { static_cast<int>(glyph.face->glyph->bitmap.width), static_cast<int>(glyph.face->glyph->bitmap.rows) } );
this->setBearing( { glyph.face->glyph->bitmap_left, glyph.face->glyph->bitmap_top } );
this->setAdvance( {static_cast<int>(glyph.face->glyph->advance.x / 64), static_cast<int>(glyph.face->glyph->advance.y / 64)} );
this->setAdvance( {static_cast<int>(glyph.face->glyph->advance.x) >> 6, static_cast<int>(glyph.face->glyph->advance.y) >> 6} );
uint8_t* bitmap = glyph.face->glyph->bitmap.buffer;
std::size_t len = this->m_size.x * this->m_size.y;

View File

@ -1,4 +1,5 @@
#include <uf/utils/userdata/userdata.h> // userdata
#include <uf/utils/string/base64.h> // base64
#include <cstdlib> // malloc, free
#include <cstring> // memcpy
@ -22,6 +23,13 @@ void UF_API uf::userdata::destroy( pod::Userdata* userdata ) {
// free(userdata);
delete[] userdata;
}
std::string UF_API uf::userdata::toBase64( pod::Userdata* userdata ) {
return uf::base64::encode( userdata->data, userdata->len );
}
pod::Userdata* UF_API uf::userdata::fromBase64( const std::string& base64 ) {
std::vector<uint8_t> decoded = uf::base64::decode( base64 );
return uf::userdata::create( decoded.size(), decoded.data() );
}
// C-tor
// Initializes POD

View File

@ -1,32 +0,0 @@
#include "./masterdata.h"
#include <iostream>
//std::string ext::MasterData::root = "https://el..xyz/mastertable/get/%TABLE%/%KEY%?.json";
std::string ext::MasterData::root = "./data/master/%TABLE%.json";
ext::Asset ext::MasterData::assetLoader;
uf::Serializer ext::MasterData::load( const std::string& table, size_t key ) {
return this->load( table, std::to_string(key) );
}
uf::Serializer ext::MasterData::load( const std::string& table, const std::string& key ) {
this->m_table = table;
this->m_key = key;
std::string url = uf::string::replace( root, "%TABLE%", table );
url = uf::string::replace( url, "%KEY%", key );
std::string filename = assetLoader.cache(url);
if ( filename != "" ) this->m_data.readFromFile(filename);
return this->get();
}
uf::Serializer ext::MasterData::get( const std::string& key ) const {
std::string k = (key == "" ? this->m_key : key);
if ( k != "" ) return this->m_data[k];
return this->m_data;
}
const std::string& ext::MasterData::tableName() const {
return this->m_table;
}
const std::string& ext::MasterData::keyName() const {
return this->m_key;
}

View File

@ -10,8 +10,8 @@
#include <uf/utils/string/ext.h>
#include <uf/utils/text/glyph.h>
#include "../world/world.h"
#include "../asset/asset.h"
#include <uf/engine/asset/asset.h>
#include <uf/engine/scene/scene.h>
#include <unordered_map>
#include <locale>
@ -25,11 +25,10 @@
#include <sys/stat.h>
#include <fstream>
#include "menu.h"
#include "battle.h"
#include <regex>
EXT_OBJECT_REGISTER_CPP(Gui)
namespace {
struct {
ext::freetype::Glyph glyph;
@ -42,18 +41,18 @@ namespace {
ext::vulkan::height,
};
pod::Vector2ui reference = {
ext::vulkan::width,
ext::vulkan::height,
1280,
720,
};
} size;
/*
std::mutex mutex;
uint64_t uid = 0;
struct Job {
uint64_t uid;
};
std::queue<Job> jobs;
*/
struct GlyphDescriptor {
struct {
alignas(16) pod::Matrix4f model[2];
@ -82,10 +81,6 @@ namespace {
pod::Matrix4 matrix;
float area(int x1, int y1, int x2, int y2, int x3, int y3) {
return abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2.0);
}
std::vector<::GlyphBox> generateGlyphs( ext::Gui& gui, std::string string = "" ) {
uf::Serializer& metadata = gui.getComponent<uf::Serializer>();
std::string font = "./data/fonts/" + metadata["text settings"]["font"].asString();
@ -95,7 +90,6 @@ namespace {
if ( string == "" ) {
string = metadata["text settings"]["string"].asString();
}
// uf::Glyph& glyph = this->getComponent<uf::Glyph>();
pod::Transform<>& transform = gui.getComponent<pod::Transform<>>();
std::vector<::GlyphBox> gs;
struct {
@ -131,14 +125,6 @@ namespace {
} stat;
float scale = metadata["text settings"]["scale"].asFloat();
float scaleX = 2.0f / (float) ::size.reference.x;
float scaleY = 2.0f / (float) ::size.reference.y;
if ( ::size.current.x != 0 && ::size.current.y != 0 ) {
// scaleX = 2.0f / (float) ::size.current.x;
// scaleY = 2.0f / (float) ::size.current.y;
}
scaleX *= scale;
scaleY *= scale;
{
pod::Vector3f color = {
@ -209,10 +195,10 @@ namespace {
glyph.generate( ::glyphs.glyph, c, metadata["text settings"]["size"].asInt() );
}
stat.biggest.x = std::max( (float) stat.biggest.x, glyph.getSize().x * scaleX);
stat.biggest.y = std::max( (float) stat.biggest.y, glyph.getSize().y * scaleY);
stat.biggest.x = std::max( (float) stat.biggest.x, (float) glyph.getSize().x);
stat.biggest.y = std::max( (float) stat.biggest.y, (float) glyph.getSize().y);
stat.average.sum += glyph.getSize().x * scaleX;
stat.average.sum += glyph.getSize().x;
++stat.average.len;
}
stat.average.proc = stat.average.sum / stat.average.len;
@ -252,29 +238,13 @@ namespace {
uf::Glyph& glyph = ::glyphs.cache[font][key];
::GlyphBox g;
g.box.w = glyph.getSize().x;
g.box.h = glyph.getSize().y;
g.box.x = stat.cursor.x + glyph.getBearing().x;
g.box.y = stat.cursor.y - glyph.getBearing().y; // - (glyph.getSize().y - glyph.getBearing().y);
g.box.w = glyph.getSize().x * scaleX;
g.box.h = glyph.getSize().y * scaleY;
// stat.cursor.x -= glyph.getPadding().x * scaleX;
g.box.x = (stat.cursor.x + stat.origin.x) + (glyph.getBearing().x * scaleX);
if ( metadata["text settings"]["wrap"].asBool() && g.box.x + g.box.w >= 2 ) {
stat.cursor.y += stat.biggest.y;
g.box.x -= stat.cursor.x; stat.cursor.x = 0;
}
// g.box.y = (stat.cursor.y + stat.origin.y) - (glyph.getBearing().y * scaleY);
// g.box.y = (stat.cursor.y + stat.origin.y);
g.box.y = (stat.cursor.y + stat.origin.y) - (glyph.getBearing().y * scaleY) + (glyph.getSize().y * scaleY);
// g.box.y = (stat.cursor.y + stat.origin.y) - (glyph.getSize().y - glyph.getBearing().y * scaleY);
stat.cursor.x += (glyph.getAdvance().x) * scaleX;
stat.cursor.x += metadata["text settings"]["kerning"].asFloat() * scaleX;
// stat.cursor.x += glyph.getPadding().x * scaleX;
// stat.cursor.y -= (glyph.getAdvance().y) * scaleY;
// stat.cursor.y -= glyph.getPadding().y * scaleY;
stat.box.w = std::max( (float) stat.box.w, (float) (stat.cursor.x + g.box.w) );
stat.box.h = std::max( (float) stat.box.h, (float) (stat.cursor.y + g.box.h) );
stat.cursor.x += (glyph.getAdvance().x);
}
stat.origin.x = ( !metadata["text settings"]["world"].asBool() && transform.position.x != (int) transform.position.x ) ? transform.position.x * ::size.current.x : transform.position.x;
@ -289,23 +259,14 @@ namespace {
if ( metadata["text settings"]["align"] == "right" ) stat.origin.x = ::size.current.x - stat.origin.x - stat.box.w;// else stat.origin.x = stat.origin.x;
else if ( metadata["text settings"]["align"] == "center" )
stat.origin.x -= stat.box.w * 0.5f;
/*
std::cout << "String: " << metadata["text settings"]["string"].asString()
<< "\n\tWidth: " << stat.box.w << " | " << (stat.origin.x -= stat.box.w * 0.5f)
<< std::endl;
*/
}
stat.biggest.x *= 2;
stat.biggest.y *= 2;
// Render Glyphs
stat.cursor.x = 0;
stat.cursor.y = 0;
stat.cursor.y = stat.biggest.y;
for ( auto it = str.begin(); it != str.end(); ++it ) {
unsigned long c = *it; if ( c == '\n' ) {
if ( metadata["text settings"]["direction"] == "down" ) stat.cursor.y += stat.biggest.y; else stat.cursor.y -= stat.biggest.y;
if ( metadata["text settings"]["direction"] == "down" ) stat.cursor.y -= stat.biggest.y; else stat.cursor.y += stat.biggest.y;
stat.cursor.x = 0;
continue;
} else if ( c == '\t' ) {
@ -313,11 +274,11 @@ namespace {
if ( false ) {
stat.cursor.x += stat.average.tab;
} else {
stat.cursor.x = ((stat.cursor.x / stat.average.tab) + (1 * scaleX)) * stat.average.tab;
stat.cursor.x = ((stat.cursor.x / stat.average.tab) + 1) * stat.average.tab;
}
continue;
} else if ( c == ' ' ) {
stat.cursor.x += stat.average.tab / 2.0f;
stat.cursor.x += stat.average.tab / 4.0f;
continue;
} else if ( c == COLORCONTROL ) {
++stat.colors.index;
@ -337,18 +298,13 @@ namespace {
::GlyphBox g;
g.code = c;
g.box.w = glyph.getSize().x * scaleX;
g.box.h = glyph.getSize().y * scaleY;
g.box.x = (stat.cursor.x + stat.origin.x) + (glyph.getBearing().x * scaleX);
if ( metadata["text settings"]["wrap"].asBool() && g.box.x + g.box.w >= 2 ) {
if ( metadata["text settings"]["direction"] == "down" ) stat.cursor.y += stat.biggest.y; else stat.cursor.y -= stat.biggest.y;
g.box.x -= stat.cursor.x; stat.cursor.x = 0;
}
// g.box.y = (stat.cursor.y + stat.origin.y) - (glyph.getBearing().y * scaleY);
g.box.y = (stat.cursor.y + stat.origin.y) - (glyph.getBearing().y * scaleY) + (glyph.getSize().y * scaleY);
// g.box.y = (stat.cursor.y + stat.origin.y) - ((glyph.getSize().y - glyph.getBearing().y) * scaleY);
// std::cout << "Glyph: " << (char) c << " " << glyph.getBearing().y << ", " << glyph.getSize().y << ", " << g.box.y << std::endl;
// g.box.y = (stat.cursor.y + stat.origin.y) - (glyph.getSize().y - glyph.getBearing().y * scaleY);
g.box.w = glyph.getSize().x;
g.box.h = glyph.getSize().y;
g.box.x = stat.cursor.x + (glyph.getBearing().x);
g.box.y = stat.cursor.y - glyph.getBearing().y; // - (glyph.getSize().y - glyph.getBearing().y);
stat.cursor.x += (glyph.getAdvance().x);
try {
g.color = stat.colors.container.at(stat.colors.index);
@ -361,11 +317,6 @@ namespace {
};
}
stat.cursor.x += (glyph.getAdvance().x) * scaleX;
stat.cursor.x += metadata["text settings"]["kerning"].asFloat() * scaleX;
// stat.cursor.y -= (glyph.getAdvance().y) * scaleY;
// stat.cursor.y -= glyph.getPadding().y * scaleY;
gs.push_back(g);
}
return gs;
@ -374,16 +325,21 @@ namespace {
void loadGui( ext::Gui& gui, uf::Image& image ) {
uf::Serializer& metadata = gui.getComponent<uf::Serializer>();
metadata["render"] = true;
{
// this->addAlias<uf::GuiMesh, uf::MeshBase>();
gui.addAlias<uf::GuiMesh, uf::Mesh>();
}
uf::GuiMesh& mesh = gui.getComponent<uf::GuiMesh>();
/* get original image size (before padding) */ {
metadata["original size"]["x"] = image.getDimensions().x;
metadata["original size"]["y"] = image.getDimensions().y;
image.padToPowerOfTwo();
// image.padToPowerOfTwo();
metadata["current size"]["x"] = image.getDimensions().x;
metadata["current size"]["y"] = image.getDimensions().y;
}
/*
pod::Vector2f correction = {
(metadata["current size"]["x"].asInt() - metadata["original size"]["x"].asInt()) / (metadata["current size"]["x"].asFloat()),
(metadata["current size"]["y"].asInt() - metadata["original size"]["y"].asInt()) / (metadata["current size"]["y"].asFloat())
@ -397,15 +353,33 @@ namespace {
{ {1.0f, -1.0f}, {1.0f-correction.x, 1.0f-correction.y}, },
{ {1.0f, 1.0f}, {1.0f-correction.x, 0.0f}, }
};
mesh.initialize(true);
*/
std::string suffix = ""; {
std::string _ = gui.getRootParent<ext::World>().getComponent<uf::Serializer>()["shaders"]["gui"]["suffix"].asString();
std::string _ = gui.getRootParent<uf::Scene>().getComponent<uf::Serializer>()["shaders"]["gui"]["suffix"].asString();
if ( _ != "" ) suffix = _ + ".";
}
if ( gui.getName() == "Gui: Text" ) {
::GlyphBox g;
g.box.x = metadata["text settings"]["box"][0].asFloat();
g.box.y = metadata["text settings"]["box"][1].asFloat();
g.box.w = metadata["text settings"]["box"][2].asFloat();
g.box.h = metadata["text settings"]["box"][3].asFloat();
mesh.vertices = {
{{ g.box.x, g.box.y + g.box.h }, { 0.0f, 0.0f }},
{{ g.box.x, g.box.y }, { 0.0f, 1.0f }},
{{ g.box.x + g.box.w, g.box.y }, { 1.0f, 1.0f }},
{{ g.box.x, g.box.y + g.box.h }, { 0.0f, 0.0f }},
{{ g.box.x + g.box.w, g.box.y }, { 1.0f, 1.0f }},
{{ g.box.x + g.box.w, g.box.y + g.box.h }, { 1.0f, 0.0f }},
};
for ( auto& vertex : mesh.vertices ) {
vertex.position.x /= ::size.reference.x;
vertex.position.y /= ::size.reference.y;
}
mesh.initialize(true);
mesh.graphic.bindUniform<::GlyphDescriptor>();
struct {
std::string vertex = "./data/shaders/gui.text.stereo.vert.spv";
std::string vertex = "./data/shaders/gui.text.vert.spv";
std::string fragment = "./data/shaders/gui.text.frag.spv";
} filenames;
if ( metadata["shaders"]["vertex"].isString() ) filenames.vertex = metadata["shaders"]["vertex"].asString();
@ -416,9 +390,20 @@ namespace {
{filenames.fragment, VK_SHADER_STAGE_FRAGMENT_BIT}
});
} else {
mesh.vertices = {
{ {-1.0f, 1.0f}, {0.0f, 0.0f}, },
{ {-1.0f, -1.0f}, {0.0f, 1.0f}, },
{ {1.0f, -1.0f}, {1.0f, 1.0f}, },
{ {-1.0f, 1.0f}, {0.0f, 0.0f}, },
{ {1.0f, -1.0f}, {1.0f, 1.0f}, },
{ {1.0f, 1.0f}, {1.0f, 0.0f}, }
};
mesh.initialize(true);
mesh.graphic.bindUniform<uf::StereoGuiMeshDescriptor>();
struct {
std::string vertex = "./data/shaders/gui.stereo.vert.spv";
std::string vertex = "./data/shaders/gui.vert.spv";
std::string fragment = "./data/shaders/gui.frag.spv";
} filenames;
if ( metadata["shaders"]["vertex"].isString() ) filenames.vertex = metadata["shaders"]["vertex"].asString();
@ -430,13 +415,9 @@ namespace {
});
}
mesh.graphic.texture.loadFromImage(
image,
ext::vulkan::device,
ext::vulkan::device.graphicsQueue
);
mesh.graphic.texture.loadFromImage( image );
mesh.graphic.initialize( ext::vulkan::device, ext::vulkan::swapchain );
mesh.graphic.initialize( "Gui" );
mesh.graphic.autoAssign();
{
@ -460,11 +441,16 @@ namespace {
void ext::Gui::initialize() {
ext::Object::initialize();
uf::Object::initialize();
// alias Mesh types
{
const ext::World& world = this->getRootParent<ext::World>();
// this->addAlias<uf::GuiMesh, uf::MeshBase>();
this->addAlias<uf::GuiMesh, uf::Mesh>();
}
{
const uf::Scene& world = this->getRootParent<uf::Scene>();
const uf::Serializer& _metadata = world.getComponent<uf::Serializer>();
::size.current = {
_metadata["window"]["size"]["x"].asFloat(),
@ -473,7 +459,7 @@ void ext::Gui::initialize() {
}
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
ext::Asset& assetLoader = this->getComponent<ext::Asset>();
uf::Asset& assetLoader = this->getComponent<uf::Asset>();
// master gui manager
@ -486,7 +472,9 @@ void ext::Gui::initialize() {
size.y = json["window"]["size"]["y"].asUInt64();
}
::matrix = uf::matrix::ortho( 0.0f, (float) size.x, 0.0f, (float) size.y );
// ::matrix = uf::matrix::ortho( 0.0f, (float) size.x, 0.0f, (float) size.y );
// ::matrix = uf::matrix::ortho( size.x * -0.5f, size.x * 0.5f, size.y * -0.5f, size.y * 0.5f );
// ::matrix = uf::matrix::ortho( size.x * -1.0f, size.x * 1.0f, size.y * -1.0f, size.y * 1.0f );
::size.current = size;
// ::size.reference = size;
@ -527,8 +515,8 @@ void ext::Gui::initialize() {
if ( uf::string::extension(filename) != "png" ) return "false";
ext::World& world = this->getRootParent<ext::World>();
ext::Asset& assetLoader = world.getComponent<ext::Asset>();
uf::Scene& world = this->getRootParent<uf::Scene>();
uf::Asset& assetLoader = world.getComponent<uf::Asset>();
const uf::Image* imagePointer = NULL;
try { imagePointer = &assetLoader.get<uf::Image>(filename); } catch ( ... ) {}
if ( !imagePointer ) return "false";
@ -606,11 +594,18 @@ void ext::Gui::initialize() {
if (intersect) clicked = !clicked;
}
}
/*
if ( clicked ) std::cout << "Clicked on " << this->m_name << std::endl;
else {
std::cout << click.x << ", " << click.y << " " << this->m_name << metadata["box"] << std::endl;
}
*/
}
metadata["clicked"] = clicked;
if ( metadata["clicked"].asBool() && clickTimer.elapsed().asDouble() >= 1 ) {
clickTimer.reset();
std::cout << "Calling hook" << std::endl;
this->callHook("gui:Clicked.%UID%");
}
return "true";
@ -651,12 +646,6 @@ void ext::Gui::initialize() {
} );
}
if ( metadata["text settings"]["string"].isString() ) {
/*
mutex.lock();
jobs.push({ this->getUid() });
mutex.unlock();
*/
uf::Serializer defaultSettings;
defaultSettings.readFromFile("./data/entities/gui/text/string.json");
@ -670,34 +659,39 @@ void ext::Gui::initialize() {
if ( metadata["text settings"]["font"].isNull() ) metadata["text settings"]["font"] = defaultSettings["metadata"]["text settings"]["font"];
float delay = 0.0f;
float scale = metadata["text settings"]["scale"].asFloat();
std::vector<::GlyphBox> glyphs = generateGlyphs(*this);
for ( auto& glyph : glyphs ) {
// append new child
ext::Gui* glyphElement = new ext::Gui;
this->addChild(*glyphElement);
glyphElement->load("./entities/gui/text/letter.json");
// ext::Gui* glyphElement = new ext::Gui;
// this->addChild(*glyphElement);
// glyphElement->load("./entities/gui/text/letter.json");
size_t uid = this->loadChild("./entities/gui/text/letter.json");
ext::Gui* glyphElement = (ext::Gui*) this->findByUid( uid );
uf::Serializer& pMetadata = glyphElement->getComponent<uf::Serializer>();
pMetadata["events"] = metadata["events"];
pMetadata["text settings"] = metadata["text settings"];
pMetadata["text settings"].removeMember("string");
pMetadata["text settings"]["letter"] = (wchar_t) glyph.code;
pMetadata["text settings"]["color"][0] = glyph.color[0];
pMetadata["text settings"]["color"][1] = glyph.color[1];
pMetadata["text settings"]["color"][2] = glyph.color[2];
pMetadata["text settings"]["box"][0] = glyph.box.x;
pMetadata["text settings"]["box"][1] = glyph.box.y;
pMetadata["text settings"]["box"][2] = glyph.box.w;
pMetadata["text settings"]["box"][3] = glyph.box.h;
pMetadata["_config"]["hoverable"] = metadata["_config"]["hoverable"];
pMetadata["_config"]["clickable"] = metadata["_config"]["clickable"];
glyphElement->initialize();
pod::Transform<>& pTransform = glyphElement->getComponent<pod::Transform<>>();
pTransform.position.x = glyph.box.x;
pTransform.position.y = glyph.box.y;
pTransform.scale.x = glyph.box.w;
pTransform.scale.y = glyph.box.h;
pTransform.scale.x = scale;
pTransform.scale.y = scale;
pTransform.reference = this->getComponentPointer<pod::Transform<>>();
uf::Serializer payload;
@ -712,58 +706,7 @@ void ext::Gui::initialize() {
}
}
void ext::Gui::tick() {
ext::Object::tick();
/*
if ( this->m_name == "Gui Manager" ) {
mutex.lock();
while ( !jobs.empty() ) {
auto job = jobs.front();
uint64_t uid = job.uid;
ext::Gui* element = (ext::Gui*) this->findByUid( uid );
jobs.pop();
if ( !element ) continue;
if ( element->getUid() != uid ) continue;
std::vector<::GlyphBox> glyphs = generateGlyphs(*element);
uf::Serializer& metadata = element->getComponent<uf::Serializer>();
for ( auto& glyph : glyphs ) {
// append new child
ext::Gui* glyphElement = new ext::Gui;
element->addChild(*glyphElement);
glyphElement->load("./entities/gui/text/letter.json");
uf::Serializer& pMetadata = glyphElement->getComponent<uf::Serializer>();
pMetadata["text settings"] = metadata["text settings"];
pMetadata["text settings"].removeMember("string");
pMetadata["text settings"]["color"][0] = glyph.color[0];
pMetadata["text settings"]["color"][1] = glyph.color[1];
pMetadata["text settings"]["color"][2] = glyph.color[2];
pMetadata["_config"]["hoverable"] = metadata["_config"]["hoverable"];
pMetadata["_config"]["clickable"] = metadata["_config"]["clickable"];
glyphElement->initialize();
pod::Transform<>& pTransform = glyphElement->getComponent<pod::Transform<>>();
pTransform.position.x = glyph.box.x;
pTransform.position.y = glyph.box.y;
pTransform.scale.x = glyph.box.w;
pTransform.scale.y = glyph.box.h;
pTransform.reference = element->getComponentPointer<pod::Transform<>>();
uf::Serializer payload;
payload["glyph"] = (uint64_t) glyph.code;
glyphElement->callHook("glyph:Load.%UID%", payload);
}
}
mutex.unlock();
}
*/
uf::Object::tick();
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( metadata["text settings"]["fade in speed"].isNumeric() && !metadata["system"]["faded in"].asBool() ) {
@ -782,11 +725,11 @@ void ext::Gui::tick() {
}
}
void ext::Gui::render() {
ext::Object::render();
uf::Object::render();
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
/* Update uniforms */ if ( this->hasComponent<uf::GuiMesh>() ) {
auto& scene = this->getRootParent<ext::World>();
auto& scene = this->getRootParent<uf::Scene>();
auto& mesh = this->getComponent<uf::GuiMesh>();
auto& camera = scene.getController()->getComponent<uf::Camera>();
auto& transform = this->getComponent<pod::Transform<>>();
@ -860,7 +803,7 @@ void ext::Gui::render() {
for ( std::size_t i = 0; i < 2; ++i ) {
if ( metadata["text settings"]["world"].asBool() ) {
auto& scene = this->getRootParent<ext::Scene>();
auto& scene = this->getRootParent<uf::Scene>();
auto& camera = scene.getController()->getComponent<uf::Camera>();
pod::Transform<> flatten = uf::transform::flatten( this->getComponent<pod::Transform<>>() );
@ -868,14 +811,19 @@ void ext::Gui::render() {
auto view = camera.getView(i);
auto projection = camera.getProjection(i);
uniforms.matrices.model[i] = projection * view * model;
} else {
} else {
uf::Matrix4 translation, rotation, scale;
pod::Transform<> flatten = uf::transform::flatten(transform, false);
// make our own flattened position, for some reason this causes z to be 6.6E+28
flatten.position = transform.position + transform.reference->position;
flatten.orientation.w *= -1;
rotation = uf::quaternion::matrix(flatten.orientation);
scale = uf::matrix::scale( scale, transform.scale );
// pod::Vector3f offsetSize = { ::size.current.x, ::size.current.y, 1 };
// translation = uf::matrix::translate( uf::matrix::identity(), flatten.position * offsetSize );
translation = uf::matrix::translate( uf::matrix::identity(), flatten.position );
uniforms.matrices.model[i] = translation * scale * rotation;
scale = uf::matrix::scale( scale, transform.scale );
// uniforms.matrices.model[i] = ::matrix * translation * rotation * scale;
uniforms.matrices.model[i] = translation * rotation * scale;
}
}
mesh.graphic.updateBuffer( uniforms, 0, false );
@ -923,7 +871,7 @@ void ext::Gui::render() {
pod::Matrix4 rotation = uf::quaternion::matrix( uf::vector::multiply( { 1, 1, 1, -1 }, flatten.orientation) );
uniforms.matrices.model[i] = ::matrix * rotation;
*/
auto& scene = this->getRootParent<ext::Scene>();
auto& scene = this->getRootParent<uf::Scene>();
auto& camera = scene.getController()->getComponent<uf::Camera>();
pod::Transform<> flatten = uf::transform::flatten( this->getComponent<pod::Transform<>>() );
@ -975,8 +923,8 @@ void ext::Gui::render() {
if ( metadata["debug"]["moveable"].asBool() ) {
pod::Transform<>& transform = this->getComponent<pod::Transform<>>();
pod::Vector2f step = {
1 / 1280.0f,
1 / 720.0f,
4 / ::size.current.x,
4 / ::size.current.y,
};
if ( uf::Window::isKeyPressed("U") ) {
step.x = (step.y = uf::physics::time::delta * 0.5f);
@ -1031,5 +979,13 @@ void ext::Gui::destroy() {
mesh.graphic.destroy();
mesh.destroy();
}
ext::Object::destroy();
/*
std::cout << "Destroying " << this->m_name;
if ( this->m_name == "Gui: Text" ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
std::cout << ", " << metadata["text settings"]["letter"].asString();
}
std::cout << std::endl;
*/
uf::Object::destroy();
}

View File

@ -7,10 +7,10 @@
#include <uf/utils/math/transform.h>
#include <uf/utils/math/physics.h>
#include "../object/object.h"
#include <uf/engine/object/object.h>
namespace ext {
class EXT_API Gui : public ext::Object {
class EXT_API Gui : public uf::Object {
public:
virtual void initialize();
virtual void tick();

View File

@ -1,9 +1,9 @@
#pragma once
/* Read persistent data */ {
/* Read persistent data */ if ( false ) {
struct {
bool exists = false;
std::string filename = "cfg/persistent.json";
std::string filename = "./data/persistent.json";
} file;
struct {
uf::Serializer file;
@ -15,22 +15,6 @@
persistent.window.title = config.file["window"]["title"].asString();
}
{
double limit = config.file["engine"]["frame limit"].asDouble();
if ( limit != 0 )
uf::thread::limiter = 1.0 / config.file["engine"]["frame limit"].asDouble();
else uf::thread::limiter = 0;
}
{
double limit = config.file["engine"]["delta limit"].asDouble();
if ( limit != 0 )
uf::physics::time::clamp = 1.0 / config.file["engine"]["delta limit"].asDouble();
else uf::physics::time::clamp = 0;
}
uf::thread::workers = config.file["engine"]["workers"].asUInt64();
ext::vulkan::validation = config.file["engine"]["validation"].asBool();
/* Update window size */ {
uf::Serializer json;
std::string hook = "window:Resized";

View File

@ -32,14 +32,13 @@
#include <iostream>
#include "ext.h"
#include "scene/scene.h"
#include "mainmenu/menu.h"
#include "world/world.h"
#include "asset/asset.h"
#include <uf/ext/vulkan/graphics/compute.h>
#include <uf/ext/vulkan/graphics/mesh.h>
#include <uf/ext/vulkan/commands/multiview.h>
#include <uf/engine/scene/scene.h>
#include <uf/engine/asset/asset.h>
#include <uf/ext/vulkan/rendermodes/deferred.h>
#include <uf/ext/vulkan/rendermodes/multiview.h>
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
#include <uf/ext/discord/discord.h>
#include <uf/ext/openvr/openvr.h>
@ -53,25 +52,6 @@ namespace {
} filenames;
} io;
struct {
struct {
pod::Vector2ui size;
uf::String title;
} window;
struct {
uint state = 0;
} opengl;
struct {
std::string mode = "Readable";
} hook;
} persistent;
struct {
struct {
pod::Vector4f ambient = {};
} light;
} gl;
struct {
spec::Time::time_t epoch;
uf::Timer<> sys = uf::Timer<>(false);
@ -80,14 +60,8 @@ namespace {
double curTime = 0;
double deltaTime = 0;
} times;
/*
struct {
ext::World master;
} world;
*/
uf::Serializer config;
}
bool ext::ready = false;
@ -107,19 +81,37 @@ void EXT_API ext::initialize() {
times.curTime = times.sys.elapsed().asDouble();
}
/* Read persistent data */ {
#include "./inits/persistence.inl"
// #include "./inits/persistence.inl"
}
::config = ext::getConfig();
/* Parse config */ {
/* Frame limiter */ {
double limit = ::config["engine"]["frame limit"].asDouble();
if ( limit != 0 )
uf::thread::limiter = 1.0 / ::config["engine"]["frame limit"].asDouble();
else uf::thread::limiter = 0;
}
/* Max delta time */{
double limit = ::config["engine"]["delta limit"].asDouble();
if ( limit != 0 )
uf::physics::time::clamp = 1.0 / ::config["engine"]["delta limit"].asDouble();
else uf::physics::time::clamp = 0;
}
// Set worker threads
uf::thread::workers = ::config["engine"]["worker threads"].asUInt64();
// Enable valiation layer
ext::vulkan::validation = ::config["engine"]["ext"]["vulkan"]["validation"].asBool();
}
/* Initialize Vulkan */ {
ext::vulkan::width = ::config["window"]["size"]["x"].asInt();
ext::vulkan::height = ::config["window"]["size"]["y"].asInt();
ext::vulkan::openvr = ::config["vr"]["enable"].asBool();
// setup multiview command mode
//ext::vulkan::command = new ext::vulkan::Command();
//ext::vulkan::command = new ext::vulkan::MultiviewCommand();
// setup render mode
ext::vulkan::addRenderMode( new ext::vulkan::DeferredRenderMode, "" );
// ext::vulkan::addRenderMode( new ext::vulkan::RenderTargetRenderMode, "Gui" );
ext::vulkan::initialize();
}
/* */ {
@ -128,34 +120,19 @@ void EXT_API ext::initialize() {
pod::Thread& threadPhysics = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false );
}
/* Discord */ if ( ::config["window"]["discord"].asBool() ) {
/* Discord */ if ( ::config["engine"]["ex"]["discord"]["enabled"].asBool() ) {
ext::discord::initialize();
}
/* Initialize root scene*/ {
ext::Scene::current = new ext::MainMenu();
ext::Scene::current->initialize();
uf::scene::loadScene( ::config["engine"]["scenes"]["start"].asString() );
}
/* Add hooks */ {
uf::hooks.addHook( "game:LoadScene", [&](const std::string& event)->std::string{
uf::Serializer json = event;
ext::Scene* scene = NULL;
if ( json["scene"].asString() == "mainmenu" ) {
scene = new ext::MainMenu();
} else if ( json["scene"].asString() == "world" ) {
scene = new ext::World();
}
if ( scene ) {
scene->initialize();
ext::Scene::current->destroy();
delete ext::Scene::current;
ext::Scene::current = scene;
}
uf::scene::unloadScene();
uf::scene::loadScene( json["scene"].asString() );
return "true";
});
@ -171,14 +148,13 @@ void EXT_API ext::initialize() {
{
uf::thread::add( uf::thread::fetchWorker(), [&]() -> int {
// ext::Asset& assetLoader = ::world.master.getComponent<ext::Asset>();
ext::Asset& assetLoader = ext::Scene::current->getComponent<ext::Asset>();
uf::Asset& assetLoader = uf::scene::getCurrentScene().getComponent<uf::Asset>();
assetLoader.processQueue();
return 0;}, false );
}
{
uf::thread::add( uf::thread::fetchWorker(), [&]() -> int {
/* OpenVR */ if ( ::config["vr"]["enable"].asBool() ) {
/* OpenVR */ if ( ::config["engine"]["ext"]["vr"]["enable"].asBool() ) {
ext::openvr::initialize();
uint32_t width, height;
ext::openvr::recommendedResolution( width, height );
@ -193,8 +169,8 @@ void EXT_API ext::initialize() {
std::cout << width << ", " << height << std::endl;
ext::vulkan::swapchain.rebuild = true;
*/
if ( ::config["vr"]["resize"].asBool() )
ext::Scene::current->callHook("window:Resized", payload);
if ( ::config["engine"]["ext"]["vr"]["resize"].asBool() )
uf::hooks.call("window:Resized", payload);
}
return 0;}, true );
}
@ -208,11 +184,39 @@ void EXT_API ext::tick() {
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
/* Print World Tree */ {
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
if ( uf::Window::isKeyPressed("U") && timer.elapsed().asDouble() >= 1 ) { timer.reset();
std::function<void(uf::Entity*, int)> filter = []( uf::Entity* entity, int indent ) {
for ( int i = 0; i < indent; ++i ) uf::iostream << "\t";
uf::iostream << entity->getName() << ": " << entity->getUid();
if ( entity->hasComponent<pod::Transform<>>() ) {
pod::Transform<> t = uf::transform::flatten(entity->getComponent<pod::Transform<>>());
uf::iostream << " (" << t.position.x << ", " << t.position.y << ", " << t.position.z << ")";
}
uf::iostream << "\n";
};
for ( uf::Scene* scene : ext::vulkan::scenes ) {
if ( !scene ) continue;
std::cout << "Scene: " << scene->getName() << ": " << scene << std::endl;
scene->process(filter, 1);
}
}
}
/* Print Entity Information */ {
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
if ( uf::Window::isKeyPressed("P") && timer.elapsed().asDouble() >= 1 ) { timer.reset();
uf::iostream << ext::vulkan::allocatorStats() << "\n";
}
}
/* Update physics timer */ {
uf::physics::tick();
}
/* Update entities */ if ( ext::Scene::current ) {
ext::Scene::current->tick();
/* Update entities */ {
uf::scene::tick();
}
/* Tick Main Thread Queue */ {
@ -223,10 +227,10 @@ void EXT_API ext::tick() {
/* Update vulkan */ {
ext::vulkan::tick();
}
/* Discord */ if ( ::config["window"]["discord"].asBool() ) {
/* Discord */ if ( ::config["engine"]["ext"]["discord"]["enable"].asBool() ) {
ext::discord::tick();
}
/* OpenVR */ if ( ::config["vr"]["enable"].asBool() ) {
/* OpenVR */ if ( ext::openvr::context ) {
ext::openvr::tick();
}
@ -240,17 +244,20 @@ void EXT_API ext::tick() {
}
}
void EXT_API ext::render() {
if ( ext::Scene::current ) {
ext::Scene::current->render();
}
uf::scene::render();
ext::vulkan::render();
/* OpenVR */ if ( ::config["vr"]["enable"].asBool() ) {
/* OpenVR */ if ( ext::openvr::context ) {
ext::openvr::submit();
}
}
void EXT_API ext::terminate() {
/* OpenVR */ if ( ::config["vr"]["enable"].asBool() ) {
/* Kill threads */ {
uf::thread::terminate();
}
/* OpenVR */ if ( ext::openvr::context ) {
ext::openvr::terminate();
}
@ -261,15 +268,12 @@ void EXT_API ext::terminate() {
io.output.close();
}
// ::world.master.destroy();
if ( ext::Scene::current ) {
ext::Scene::current->destroy();
}
uf::scene::destroy();
/* Write persistent data */ {
/* Write persistent data */ if ( false ) {
struct {
bool exists = false;
std::string filename = "cfg/persistent.json";
std::string filename = "./data/persistent.json";
} file;
struct {
uf::Serializer file;
@ -277,18 +281,8 @@ void EXT_API ext::terminate() {
/* Read from file */ {
file.exists = config.file.readFromFile(file.filename);
}
// config.file["window"]["size"]["x"] = persistent.window.size.x;
// config.file["window"]["size"]["y"] = persistent.window.size.y;
// config.file["window"]["title"] = std::string(persistent.window.title);
// config.file["OpenGL"]["state"] = persistent.opengl.state;
config.file["meta"]["version"] = "2018.04.09";
config.file["meta"]["time"]["initialized"] = times.sys.getStarting().asDouble();
config.file["meta"]["time"]["terminated"] = times.sys.getEnding().asDouble();
config.file["meta"]["time"]["elapsed"] = times.sys.elapsed().asDouble();
/* Write persistent data */ {
// config.file.writeToFile(file.filename);
config.file.writeToFile(file.filename);
}
}
}
@ -304,36 +298,29 @@ std::string EXT_API ext::getConfig() {
struct {
bool exists = false;
std::string filename = "cfg/ext.json";
std::string filename = "./data/config.json";
} file;
/* Read from file */ {
file.exists = config.file.readFromFile(file.filename);
}
/* Initialize fallback */ {
config.fallback["terminal"]["visible"] = true;
config.fallback["terminal"]["ncurses"] = true;
config.fallback["window"]["title"] = "[uf] Grimgram - Extended";
config.fallback["window"]["size"]["x"] = 640;
config.fallback["window"]["size"]["y"] = 480;
/* Initialize default configuration */ {
config.fallback["window"]["terminal"]["ncurses"] = true;
config.fallback["window"]["terminal"]["visible"] = true;
config.fallback["window"]["title"] = "Grimgram";
config.fallback["window"]["icon"] = "";
config.fallback["window"]["size"]["x"] = 1280;
config.fallback["window"]["size"]["y"] = 720;
config.fallback["window"]["visible"] = true;
config.fallback["cursor"]["visible"] = true;
config.fallback["keyboard"]["repeat"] = true;
config.fallback["window"]["fullscreen"] = false;
config.fallback["window"]["cursor"]["visible"] = true;
config.fallback["window"]["cursor"]["center"] = false;
config.fallback["window"]["keyboard"]["repeat"] = true;
config.fallback["hook"]["mode"] = "Readable";
config.fallback["light"]["ambient"]["r"] = ::gl.light.ambient.x = 0.0f;
config.fallback["light"]["ambient"]["g"] = ::gl.light.ambient.y = 0.0f;
config.fallback["light"]["ambient"]["b"] = ::gl.light.ambient.z = 0.0f;
config.fallback["light"]["ambient"]["a"] = ::gl.light.ambient.w = 1.0f;
config.fallback["context"]["depthBits"] = 24;
config.fallback["context"]["stencilBits"] = 4;
config.fallback["context"]["bitsPerPixel"] = 8;
config.fallback["context"]["antialiasingLevel"] = 0;
config.fallback["context"]["majorVersion"] = 3;
config.fallback["context"]["minorVersion"] = 0;
config.fallback["engine"]["scenes"]["start"] = "StartMenu";
config.fallback["engine"]["hook"]["mode"] = "Readable";
config.fallback["engine"]["frame limit"] = 60;
config.fallback["engine"]["delta limit"] = 120;
config.fallback["engine"]["worker threads"] = 1;
}
/* Merge */ if ( file.exists ){
config.merged = config.file;
@ -341,21 +328,9 @@ std::string EXT_API ext::getConfig() {
} else {
config.merged = config.fallback;
}
/* Write default to file */ {
/* Write default to file */ if ( false ) {
config.merged.writeToFile(file.filename);
}
/* Update title */ {
persistent.window.title = config.merged["window"]["title"].asString();
}
/* Update hook mode */ {
persistent.hook.mode = config.merged["hook"]["mode"].asString();
}
/* Update ambient color */ {
::gl.light.ambient.x = config.merged["light"]["ambient"]["r"].asDouble();
::gl.light.ambient.y = config.merged["light"]["ambient"]["g"].asDouble();
::gl.light.ambient.z = config.merged["light"]["ambient"]["b"].asDouble();
::gl.light.ambient.w = config.merged["light"]["ambient"]["a"].asDouble();
}
config.initialized = true;
return config.merged;

View File

@ -1,245 +0,0 @@
#include "object.h"
#include "../ext.h"
#include <uf/ext/assimp/assimp.h>
#include <uf/utils/window/window.h>
#include "../gui/gui.h"
#include "../world//sprite.h"
#include "../asset/asset.h"
#include "../world/world.h"
#include "../world/player/player.h"
#include "../world/terrain/terrain.h"
namespace {
uf::Timer<long long> timer(false);
}
void ext::Object::initialize() {
uf::Entity::initialize();
}
void ext::Object::queueHook( const std::string& name, const std::string& payload, double timeout ) {
if ( !timer.running() ) timer.start();
float start = timer.elapsed().asDouble();
uf::Serializer queue;
queue["name"] = name;
queue["payload"] = uf::Serializer{payload};
queue["timeout"] = start + timeout;
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
metadata["system"]["hooks"]["queue"].append(queue);
}
std::vector<std::string> ext::Object::callHook( const std::string& n, const std::string& payload ) {
std::string name = uf::string::replace( n, "%UID%", std::to_string(this->getUid()) );
return uf::hooks.call( name, payload );
}
std::size_t ext::Object::addHook( const std::string& name, const uf::HookHandler::Readable::function_t& callback ) {
std::string parsed = uf::string::replace( name, "%UID%", std::to_string(this->getUid()) );
std::size_t id = uf::hooks.addHook( parsed, callback );
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
metadata["system"]["hooks"]["alloc"][parsed].append(id);
return id;
}
void ext::Object::destroy() {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
for( Json::Value::iterator it = metadata["system"]["hooks"]["alloc"].begin() ; it != metadata["system"]["hooks"]["alloc"].end() ; ++it ) {
std::string name = it.key().asString();
for ( uint i = 0; i < metadata["system"]["hooks"]["alloc"][name].size(); ++i ) {
uint id = metadata["system"]["hooks"]["alloc"][name][i].asUInt();
uf::hooks.removeHook(name, id);
}
}
uf::Entity::destroy();
}
void ext::Object::tick() {
uf::Entity::tick();
/* Call queued hooks */ {
if ( !timer.running() ) timer.start();
float curTime = timer.elapsed().asDouble();
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
uf::Serializer newQueue = Json::Value(Json::arrayValue);
for ( auto& member : metadata["system"]["hooks"]["queue"] ) {
uf::Serializer payload = member["payload"];
std::string name = member["name"].asString();
float timeout = member["timeout"].asFloat();
if ( timeout < curTime ) {
this->callHook( name, payload );
} else {
newQueue.append(member);
}
}
if ( metadata.isObject() ) metadata["system"]["hooks"]["queue"] = newQueue;
}
}
void ext::Object::render() {
uf::Entity::render();
}
bool ext::Object::load( const std::string& filename ) {
uf::Serializer json;
std::string root = "./data/" + uf::string::directory(filename);
if ( !json.readFromFile(root + uf::string::filename(filename)) ) {
uf::iostream << "Error: failed to open `" + root + uf::string::filename(filename) + "`" << "\n";
return false;
}
json["root"] = root;
return this->load(json);
}
bool ext::Object::load( const uf::Serializer& json ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
/* Basic entity information */ {
// Set name
this->m_name = json["name"].asString();
// Set transform
bool load = json["transform"].isObject();
if ( this->hasComponent<pod::Transform<>>() ) load = false;
pod::Transform<>& transform = this->getComponent<pod::Transform<>>();
if ( transform.position.x == 0 && transform.position.y == 0 && transform.position.z == 0 ) {
load = true;
}
if ( load ) {
transform.position = uf::vector::create( json["transform"]["position"][0].asFloat(),json["transform"]["position"][1].asFloat(),json["transform"]["position"][2].asFloat() );
transform.orientation = uf::quaternion::identity();
if ( json["transform"]["rotation"]["angle"].asFloat() != 0 ) {
transform.orientation = uf::quaternion::axisAngle( {
json["transform"]["rotation"]["axis"][0].asFloat(),
json["transform"]["rotation"]["axis"][1].asFloat(),
json["transform"]["rotation"]["axis"][2].asFloat()
},
json["transform"]["rotation"]["angle"].asFloat()
);
}
transform.scale = uf::vector::create( json["transform"]["scale"][0].asFloat(),json["transform"]["scale"][1].asFloat(),json["transform"]["scale"][2].asFloat() );
transform = uf::transform::reorient( transform );
}
}
ext::World& world = this->getRootParent<ext::World>();
ext::Asset& assetLoader = world.getComponent<ext::Asset>();
// initialize base entity, needed for asset hooks
/* Audio (singular) */ {
// find first valid texture in asset list
uf::Serializer target;
if ( metadata["system"]["assets"].isArray() ) {
target = metadata["system"]["assets"];
} else if ( json["assets"].isArray() ) {
target = json["assets"];
} else if ( json["assets"].isObject() && !json["assets"]["audio"].isNull() ) {
target = json["assets"]["audio"];
}
for ( uint i = 0; i < target.size(); ++i ) {
std::string filename = target[i].asString();
if ( uf::string::extension(filename) != "ogg" ) continue;
std::string canonical = "";
if ( (canonical = assetLoader.load( filename )) != "" ) {
uf::Serializer queue;
queue["name"] = "asset:Load.%UID%";
queue["payload"]["filename"] = canonical;
metadata["system"]["hooks"]["queue"].append(queue);
}
}
}
/* Texture (singular) */ {
// find first valid texture in asset list
uf::Serializer target;
if ( metadata["system"]["assets"].isArray() ) {
target = metadata["system"]["assets"];
} else if ( json["assets"].isArray() ) {
target = json["assets"];
} else if ( json["assets"].isObject() && !json["assets"]["textures"].isNull() ) {
target = json["assets"]["textures"];
}
for ( uint i = 0; i < target.size(); ++i ) {
std::string filename = target[i].asString();
if ( uf::string::extension(filename) != "png" ) continue;
std::string canonical = "";
if ( (canonical = assetLoader.load( filename )) != "" ) {
uf::Serializer queue;
queue["name"] = "asset:Load.%UID%";
queue["payload"]["filename"] = canonical;
metadata["system"]["hooks"]["queue"].append(queue);
}
}
}
uf::Serializer queue = metadata["system"]["hooks"]["queue"];
/* Metadata */ if ( json["metadata"] != Json::nullValue ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( json["metadata"].type() == Json::stringValue ) {
std::string filename = json["root"].asString() + "/" + json["metadata"].asString();
if ( !metadata.readFromFile(filename) ) {
uf::iostream << "Error: failed to open `" + filename + "`" << "\n";
return false;
}
} else {
metadata = json["metadata"];
}
}
metadata["_config"] = json;
metadata["_config"].removeMember("metadata");
metadata["system"]["hooks"]["queue"] = queue;
/* check for children */ {
uf::Serializer target;
if ( metadata["system"]["assets"].isArray() ) {
target = metadata["system"]["assets"];
} else if ( metadata["_config"]["assets"].isArray() ) {
target = metadata["_config"]["assets"];
} else if ( metadata["_config"]["assets"].isObject() && !metadata["_config"]["assets"]["entities"].isNull() ) {
target = metadata["_config"]["assets"]["entities"];
}
for ( uint i = 0; i < target.size(); ++i ) {
std::string filename = target[i].asString();
if ( uf::string::extension(filename) != "json" ) continue;
std::string root = "./data/entities/" + uf::string::directory(filename);
filename = root + uf::string::filename(filename);
if ( (filename = assetLoader.load(filename) ) == "" ) return false;
uf::Serializer json;
if ( !json.readFromFile(filename) ) {
uf::iostream << "Error: failed to open `" + filename + "`" << "\n";
return false;
}
json["root"] = root;
if ( this->loadChild(json) == -1 ) return false;
}
}
return true;
}
std::size_t ext::Object::loadChild( const std::string& filename, bool initialize ) {
uf::Serializer json;
std::string root = "./data/" + uf::string::directory(filename);
if ( !json.readFromFile(root + uf::string::filename(filename)) ) {
uf::iostream << "Error: failed to open `" + root + uf::string::filename(filename) + "`" << "\n";
return -1;
}
json["root"] = root;
return this->loadChild(json, initialize);
}
std::size_t ext::Object::loadChild( const uf::Serializer& json, bool initialize ) {
uf::Entity* entity;
std::string type = json["type"].asString();
if ( json["ignore"].asBool() ) return 0;
if ( type == "Terrain" ) entity = new ext::Terrain;
else if ( type == "Player" ) entity = new ext::Player;
else if ( type == "Craeture" ) entity = new ext::Craeture;
else if ( type == "Housamo" ) entity = new ext::HousamoSprite;
else if ( type == "Gui" ) entity = new ext::Gui;
else {
uf::iostream << "Unimplemented entity: " << type << "\n";
entity = new ext::Object;
}
uf::iostream << entity << ": " << type << "\n";
this->addChild(*entity);
if ( !((ext::Object*) entity)->load(json) ) {
uf::iostream << "Error loading `" << json << "!" << "\n";
this->removeChild(*entity);
delete entity;
return -1;
}
if ( initialize ) entity->initialize();
return entity->getUid();
}

View File

@ -1,49 +0,0 @@
#include "scene.h"
#include <uf/ext/vulkan/vulkan.h>
ext::Scene* ext::Scene::current = NULL;
void ext::Scene::initialize() {
this->m_graphics = new std::vector<ext::vulkan::Graphic*>();
ext::vulkan::graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
ext::Object::initialize();
}
void ext::Scene::tick() {
ext::vulkan::graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
ext::Object::tick();
}
void ext::Scene::render() {
ext::vulkan::graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
ext::Object::render();
}
void ext::Scene::destroy() {
ext::Object::destroy();
std::vector<ext::vulkan::Graphic*>* graphics = (std::vector<ext::vulkan::Graphic*>*) this->m_graphics;
for ( auto* graphic : *graphics ) {
graphic->destroy();
}
delete graphics;
ext::vulkan::graphics = NULL;
}
uf::Entity* ext::Scene::getController() {
return this->findByName("Player");
}
const uf::Entity* ext::Scene::getController() const {
return this->findByName("Player");
}
/*
uf::Camera& ext::Scene::getCamera() {
if ( !::camera ) ::camera = this->getPlayer().getComponentPointer<uf::Camera>();
return *::camera;
}
ext::Player& ext::Scene::getPlayer() {
return *((ext::Player*) this->findByName("Player"));
}
const ext::Player& ext::Scene::getPlayer() const {
return *((const ext::Player*) this->findByName("Player"));
}
*/

View File

@ -1,34 +0,0 @@
#pragma once
#include <uf/config.h>
#include <uf/ext/ext.h>
#include <uf/engine/entity/entity.h>
#include "../object/object.h"
namespace ext {
class EXT_API Scene : public ext::Object {
protected:
void* m_graphics;
template<typename T> T& getGraphics() {
return *((T*) this->m_graphics);
}
public:
static ext::Scene* current;
virtual void initialize();
virtual void tick();
virtual void render();
virtual void destroy();
virtual uf::Entity* getController();
virtual const uf::Entity* getController() const;
template<typename T> T& getController() {
return *((T*) this->getController());
}
template<typename T> const T& getController() const {
return *((const T*) this->getController());
}
};
}

View File

@ -8,40 +8,39 @@
#include <uf/utils/audio/audio.h>
#include <uf/utils/thread/thread.h>
#include "../ext.h"
#include "../asset/asset.h"
#include "../asset/masterdata.h"
#include "../gui/menu.h"
#include "../gui/battle.h"
#include "../gui/dialogue.h"
#include <uf/engine/asset/asset.h>
#include <uf/engine/asset/masterdata.h>
#include <uf/ext/vulkan/vulkan.h>
#include "../../ext.h"
#include "../../gui/gui.h"
namespace {
ext::Object controller;
uf::Object controller;
ext::Gui* gui;
ext::Gui* circleIn;
ext::Gui* circleOut;
}
uf::Entity* ext::MainMenu::getController() {
uf::Entity* ext::StartMenu::getController() {
return (uf::Entity*) &controller;
}
const uf::Entity* ext::MainMenu::getController() const {
const uf::Entity* ext::StartMenu::getController() const {
return (uf::Entity*) &controller;
}
void ext::MainMenu::initialize() {
ext::Scene::initialize();
EXT_OBJECT_REGISTER_CPP(StartMenu)
void ext::StartMenu::initialize() {
uf::Scene::initialize();
this->m_name = "Main Menu";
this->load("./entities/mainmenu.json");
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
ext::Asset& assetLoader = this->getComponent<ext::Asset>();
uf::Asset& assetLoader = this->getComponent<uf::Asset>();
this->addHook( "system:Quit.%UID%", [&](const std::string& event)->std::string{
std::cout << event << std::endl;
@ -154,11 +153,11 @@ void ext::MainMenu::initialize() {
}
}
void ext::MainMenu::tick() {
ext::Scene::tick();
void ext::StartMenu::tick() {
uf::Scene::tick();
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
ext::Asset& assetLoader = this->getComponent<ext::Asset>();
uf::Asset& assetLoader = this->getComponent<uf::Asset>();
/* check if audio needs to loop */ try {
uf::Audio& bgm = this->getComponent<uf::Audio>();
@ -225,6 +224,6 @@ void ext::MainMenu::tick() {
}
}
void ext::MainMenu::render() {
ext::Scene::render();
void ext::StartMenu::render() {
uf::Scene::render();
}

View File

@ -4,10 +4,10 @@
#include <uf/ext/ext.h>
#include <uf/engine/entity/entity.h>
#include "../scene/scene.h"
#include <uf/engine/scene/scene.h>
namespace ext {
class EXT_API MainMenu : public ext::Scene {
class EXT_API StartMenu : public uf::Scene {
public:
virtual void initialize();
virtual void tick();

View File

@ -9,15 +9,19 @@
#include <uf/utils/thread/thread.h>
#include <uf/utils/string/ext.h>
#include <uf/utils/audio/audio.h>
#include <uf/utils/math/transform.h>
#include <uf/utils/math/collision.h>
#include "..//battle.h"
#include "../terrain/generator.h"
#include "../world.h"
#include "../../asset/asset.h"
#include <uf/engine/asset/asset.h>
EXT_OBJECT_REGISTER_CPP(Craeture)
void ext::Craeture::initialize() {
ext::Object::initialize();
uf::Object::initialize();
pod::Transform<>& transform = this->getComponent<pod::Transform<>>();
transform = uf::transform::initialize(transform); {
@ -32,12 +36,14 @@ void ext::Craeture::initialize() {
physics.rotational.acceleration = {0,0,0,0};
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
/*
if ( metadata["animation"] != Json::nullValue ) {
for( auto it = metadata["animation"]["names"].begin() ; it != metadata["animation"]["names"].end() ; ++it ) {
const std::string& name = it->asString();
if ( this->m_animation.transforms.find(name) == this->m_animation.transforms.end() ) this->m_animation.transforms[name];
}
}
*/
/* Gravity */ {
if ( metadata["collision"]["gravity"] != Json::nullValue ) {
physics.linear.acceleration.x = metadata["collision"]["gravity"][0].asFloat();
@ -101,7 +107,7 @@ void ext::Craeture::initialize() {
metadata["timers"]["hurt"] = timer.elapsed().asDouble() + 1.0f;
ext::World& world = this->getRootParent<ext::World>();
ext::Asset& assetLoader = world.getComponent<ext::Asset>();
uf::Asset& assetLoader = world.getComponent<uf::Asset>();
assetLoader.cache("./data/audio/battle/hurt.ogg", "asset:Cache.Sound." + std::to_string(this->getUid()));
}
@ -127,7 +133,7 @@ void ext::Craeture::initialize() {
}
void ext::Craeture::tick() {
ext::Object::tick();
uf::Object::tick();
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
ext::World& world = this->getRootParent<ext::World>();
@ -423,5 +429,5 @@ void ext::Craeture::tick() {
}
}
void ext::Craeture::render() {
ext::Object::render();
uf::Object::render();
}

View File

@ -3,16 +3,17 @@
#include <uf/config.h>
#include <uf/ext/ext.h>
#include <uf/engine/entity/entity.h>
#include "../../object/object.h"
#include <uf/engine/object/object.h>
namespace ext {
class EXT_API Craeture : public ext::Object {
class EXT_API Craeture : public uf::Object {
public:
/*
struct Animation {
std::map<std::string, pod::Transform<>> transforms;
std::string state = "null";
} m_animation;
*/
void initialize();
void tick();
void render();

View File

@ -1,7 +1,5 @@
#include "battle.h"
#include "gui.h"
#include <uf/utils/hook/hook.h>
#include <uf/utils/time/time.h>
#include <uf/utils/serialize/serializer.h>
@ -11,9 +9,9 @@
#include <uf/utils/mesh/mesh.h>
#include <uf/utils/string/ext.h>
// #include <uf/gl/glyph/glyph.h>
#include "../world/world.h"
#include "../world//battle.h"
#include "../asset/asset.h"
#include "../world.h"
#include "..//battle.h"
#include <uf/engine/asset/asset.h>
#include <unordered_map>
@ -82,7 +80,7 @@ namespace {
url = "./data/smtsamo/voice/voice_" + name + "_" + key + ".ogg";
}
ext::Asset& assetLoader = world->getComponent<ext::Asset>();
uf::Asset& assetLoader = world->getComponent<uf::Asset>();
assetLoader.cache(url, "asset:Cache.Voice." + std::to_string(entity.getUid()));
}
void playSound( ext::GuiBattle& entity, std::size_t uid, const std::string& key ) {
@ -105,13 +103,13 @@ namespace {
std::string url = "./data/audio/ui/" + key + ".ogg";
ext::Asset& assetLoader = world->getComponent<ext::Asset>();
uf::Asset& assetLoader = world->getComponent<uf::Asset>();
assetLoader.cache(url, "asset:Cache.SFX." + std::to_string(entity.getUid()));
}
void playMusic( ext::GuiBattle& entity, const std::string& filename ) {
if ( !world ) world = (ext::World*) uf::Entity::globalFindByName("World");
if ( !world ) return;
ext::Asset& assetLoader = world->getComponent<ext::Asset>();
uf::Asset& assetLoader = world->getComponent<uf::Asset>();
uf::Serializer& masterdata = world->getComponent<uf::Serializer>();
assetLoader.load(filename, "asset:Load." + std::to_string(world->getUid()));
@ -929,7 +927,7 @@ void ext::GuiBattle::tick() {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( metadata["system"]["closing"].asBool() ) {
if ( alpha >= 1.0f ) {
ext::Asset assetLoader;
uf::Asset assetLoader;
std::string canonical = assetLoader.load("./data/audio/ui/menu close.ogg");
uf::Audio& sfx = assetLoader.get<uf::Audio>(canonical);
sfx.setVolume(masterdata["volumes"]["sfx"].asFloat());
@ -942,7 +940,7 @@ void ext::GuiBattle::tick() {
} else alpha -= uf::physics::time::delta;
metadata["color"][3] = alpha;
} else if ( metadata["system"]["closed"].asBool() ) {
ext::Object& parent = this->getParent<ext::Object>();
uf::Object& parent = this->getParent<uf::Object>();
parent.getComponent<uf::Serializer>()["system"]["closed"] = true;
this->destroy();
parent.removeChild(*this);

View File

@ -1,6 +1,6 @@
#pragma once
#include "gui.h"
#include "../../../gui/gui.h"
namespace ext {
class EXT_API GuiBattle : public ext::Gui {

Some files were not shown because too many files have changed in this diff Show More