Commit for 2020.07.23.7z
This commit is contained in:
parent
e1736f573a
commit
958b1697f6
2
Makefile
2
Makefile
@ -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
|
||||
|
||||
12
bin/data/shaders/display.rendertarget.frag.glsl
Normal file
12
bin/data/shaders/display.rendertarget.frag.glsl
Normal 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 );
|
||||
}
|
||||
17
bin/data/shaders/display.subpass.vert.glsl
Normal file
17
bin/data/shaders/display.subpass.vert.glsl
Normal 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);
|
||||
}
|
||||
29
bin/data/shaders/gui.frag.glsl
Normal file
29
bin/data/shaders/gui.frag.glsl
Normal 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;
|
||||
}
|
||||
}
|
||||
49
bin/data/shaders/gui.text.frag.glsl
Normal file
49
bin/data/shaders/gui.text.frag.glsl
Normal 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;
|
||||
}
|
||||
}
|
||||
44
bin/data/shaders/gui.text.vert.glsl
Normal file
44
bin/data/shaders/gui.text.vert.glsl
Normal 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);
|
||||
}
|
||||
38
bin/data/shaders/gui.vert.glsl
Normal file
38
bin/data/shaders/gui.vert.glsl
Normal 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);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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:
|
||||
@ -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 );
|
||||
@ -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 );
|
||||
};
|
||||
|
||||
52
engine/inc/uf/engine/instantiator/instantiator.h
Normal file
52
engine/inc/uf/engine/instantiator/instantiator.h
Normal 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))] ));
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -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();
|
||||
36
engine/inc/uf/engine/scene/scene.h
Normal file
36
engine/inc/uf/engine/scene/scene.h
Normal 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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
@ -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();
|
||||
};
|
||||
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
37
engine/inc/uf/ext/vulkan/graphics/rendertarget.h
Normal file
37
engine/inc/uf/ext/vulkan/graphics/rendertarget.h
Normal 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();
|
||||
};
|
||||
}
|
||||
}
|
||||
29
engine/inc/uf/ext/vulkan/rendermodes/base.h
Normal file
29
engine/inc/uf/ext/vulkan/rendermodes/base.h
Normal 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();
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
28
engine/inc/uf/ext/vulkan/rendermodes/rendertarget.h
Normal file
28
engine/inc/uf/ext/vulkan/rendermodes/rendertarget.h
Normal 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();
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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>();
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
11
engine/inc/uf/utils/singletons/pre_main.h
Normal file
11
engine/inc/uf/utils/singletons/pre_main.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <uf/config.h>
|
||||
#include <functional>
|
||||
|
||||
namespace uf {
|
||||
struct UF_API StaticInitialization {
|
||||
public:
|
||||
StaticInitialization(std::function<void()>);
|
||||
};
|
||||
}
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
@ -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;
|
||||
31
engine/src/engine/asset/masterdata.cpp
Normal file
31
engine/src/engine/asset/masterdata.cpp
Normal 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;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
13
engine/src/engine/instantiator/instantiator.cpp
Normal file
13
engine/src/engine/instantiator/instantiator.cpp
Normal 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]();
|
||||
}
|
||||
421
engine/src/engine/object/object.cpp
Normal file
421
engine/src/engine/object/object.cpp
Normal 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();
|
||||
}
|
||||
*/
|
||||
94
engine/src/engine/scene/scene.cpp
Normal file
94
engine/src/engine/scene/scene.cpp
Normal 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"));
|
||||
}
|
||||
*/
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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(¤tBuffer));
|
||||
|
||||
// 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() {
|
||||
|
||||
}
|
||||
@ -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(¤tBuffer));
|
||||
|
||||
// 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));
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 = {};
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
311
engine/src/ext/vulkan/graphics/rendertarget.cpp
Normal file
311
engine/src/ext/vulkan/graphics/rendertarget.cpp
Normal 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();
|
||||
}
|
||||
206
engine/src/ext/vulkan/rendermode.cpp
Normal file
206
engine/src/ext/vulkan/rendermode.cpp
Normal 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(¤tBuffer));
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
228
engine/src/ext/vulkan/rendermodes/base.cpp
Normal file
228
engine/src/ext/vulkan/rendermodes/base.cpp
Normal 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(¤tBuffer));
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
190
engine/src/ext/vulkan/rendermodes/deferred.cpp
Normal file
190
engine/src/ext/vulkan/rendermodes/deferred.cpp
Normal 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]));
|
||||
}
|
||||
}
|
||||
@ -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(¤tBuffer));
|
||||
|
||||
// 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));
|
||||
}
|
||||
178
engine/src/ext/vulkan/rendermodes/rendertarget.cpp
Normal file
178
engine/src/ext/vulkan/rendermodes/rendertarget.cpp
Normal 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));
|
||||
}
|
||||
@ -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 ) {
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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(),
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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 ) {
|
||||
|
||||
}
|
||||
@ -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 = {
|
||||
{
|
||||
|
||||
5
engine/src/utils/singletons/pre_main.cpp
Normal file
5
engine/src/utils/singletons/pre_main.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include <uf/utils/singletons/pre_main.h>
|
||||
|
||||
uf::StaticInitialization::StaticInitialization( std::function<void()> fun ) {
|
||||
fun();
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
300
ext/gui/gui.cpp
300
ext/gui/gui.cpp
@ -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();
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -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";
|
||||
|
||||
225
ext/main.cpp
225
ext/main.cpp
@ -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;
|
||||
|
||||
@ -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();
|
||||
}
|
||||
@ -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"));
|
||||
}
|
||||
*/
|
||||
@ -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());
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
@ -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();
|
||||
@ -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();
|
||||
}
|
||||
@ -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();
|
||||
@ -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);
|
||||
@ -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
Loading…
Reference in New Issue
Block a user