Commit for 2020.10.18.7z

This commit is contained in:
mrq 2020-10-18 00:00:00 -05:00
parent 3fdc1820ea
commit 1393f1b77a
59 changed files with 2147 additions and 1416 deletions

View File

@ -21,20 +21,20 @@ layout (location = 1) out vec4 outNormal;
layout (location = 2) out vec4 outPosition;
void main() {
outAlbedoSpecular = texture(sampler2D(albedoTexture, samp), inUv);
if ( inCursor.radius.x <= 0 && inCursor.radius.y <= 0 ) {
vec2 uv = gl_FragCoord.xy / textureSize(albedoTexture, 0);
// uv.x = 1-uv.x;
outAlbedoSpecular = texture(sampler2D(albedoTexture, samp), uv);
outNormal = texture(sampler2D(normalTexture, samp), uv);
outPosition = texture(sampler2D(positionTexture, samp), uv);
if ( outAlbedoSpecular.a < 0.01f ) outAlbedoSpecular = vec4(0,0,0,1);
// if ( outAlbedoSpecular.a < 0.01f ) outAlbedoSpecular = vec4(0,0,0,1);
return;
}
outAlbedoSpecular = texture(sampler2D(albedoTexture, samp), inUv);
float dist = pow(inUv.x - inCursor.position.x, 2) / pow(inCursor.radius.x, 2) + pow(inUv.y - inCursor.position.y, 2) / pow(inCursor.radius.y, 2);
if ( dist <= 1 ) {
float attenuation = dist;
outAlbedoSpecular.rgb = mix( inCursor.color.rgb * inCursor.color.a, outAlbedoSpecular.rgb, attenuation );
}
if ( inAlpha < 1.0 ) outAlbedoSpecular.a = inAlpha;
}

View File

@ -27,12 +27,14 @@ struct Matrices {
layout (binding = 0) uniform UBO {
Matrices matrices;
Cursor cursor;
vec2 alpha;
// float alpha;
// float padding;
} ubo;
void main() {
outUv = inUv;
outCursor = ubo.cursor;
outAlpha = 1;
gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(inPos.xy, 0.0, 1.0);
}

View File

@ -7,7 +7,11 @@ layout (input_attachment_index = 0, binding = 2) uniform subpassInput samplerNor
layout (input_attachment_index = 0, binding = 3) uniform subpassInput samplerPosition;
// layout (input_attachment_index = 0, binding = 4) uniform subpassInput samplerDepth;
layout (binding = 5) uniform sampler2D samplerShadows[LIGHTS];
/*
layout (std140, binding = 6) buffer Palette {
vec4 palette[];
};
*/
layout (location = 0) in vec2 inUv;
layout (location = 1) in flat uint inPushConstantPass;
@ -47,6 +51,7 @@ struct Light {
float power;
int type;
float depthBias;
vec2 padding;
mat4 view;
mat4 projection;
};
@ -62,13 +67,15 @@ struct Space {
} position, normal, view;
struct Fog {
vec2 range;
vec4 color;
vec2 range;
vec2 padding;
};
struct Mode {
uint type;
uint scalar;
vec2 padding;
vec4 parameters;
};
@ -188,7 +195,6 @@ vec3 hslToRgb(vec3 HSL) {
float C = (1 - abs(2 * HSL.z - 1)) * HSL.y;
return (RGB - 0.5) * C + HSL.z;
}
vec3 rgbToHsl(vec3 RGB) {
float Epsilon = 1e-10;
vec3 HCV; {
@ -209,7 +215,6 @@ float hueDistance(float h1, float h2) {
}
const float lightnessSteps = 4.0;
float lightnessStep(float l) {
/* Quantize the lightness to one of `lightnessSteps` values */
return floor((0.5 + l * lightnessSteps)) / lightnessSteps;
}
const int indexMatrix16x16[256] = int[](0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255,
@ -228,54 +233,11 @@ const int indexMatrix16x16[256] = int[](0,192, 48,240, 12,204, 60,252, 3,195, 5
138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117,
42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213,
170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85);
float indexValue16x16() {
int x = int(mod(gl_FragCoord.x, 16));
int y = int(mod(gl_FragCoord.y, 16));
float indexValue16x16( float scale ) {
int x = int(mod(gl_FragCoord.x * scale, 16));
int y = int(mod(gl_FragCoord.y * scale, 16));
return indexMatrix16x16[(x + y * 16)] / 256.0;
}
const int paletteSize = 40;
const vec3 palette16x16[paletteSize] = vec3[](
vec3( 0, 0, 0),
vec3( 0, 0, 0.502),
vec3( 0, 0, 0.753),
vec3( 0, 0, 1),
vec3( 0, 1, 0.251),
vec3( 0, 1, 0.50),
vec3( 24.0/360.0, 1, 0.251),
vec3( 24.0/360.0, 1, 0.5),
vec3( 24.0/360.0, 1, 0.625),
vec3( 24.0/360.0, 1, 0.751),
vec3( 30.0/360.0, 1, 0.251),
vec3( 60.0/360.0, 0.333, 0.376),
vec3( 60.0/360.0, 1, 0.251),
vec3( 60.0/360.0, 1, 0.5),
vec3( 60.0/360.0, 1, 0.751),
vec3(120.0/360.0, 1, 0.251),
vec3(120.0/360.0, 1, 0.5),
vec3(120.0/360.0, 1, 0.751),
vec3(150.0/360.0, 1, 0.251),
vec3(150.0/360.0, 1, 0.5),
vec3(150.0/360.0, 1, 0.751),
vec3(180.0/360.0, 1, 0.125),
vec3(180.0/360.0, 1, 0.251),
vec3(180.0/360.0, 1, 0.5),
vec3(180.0/360.0, 1, 0.751),
vec3(210.0/360.0, 1, 0.251),
vec3(210.0/360.0, 1, 0.5),
vec3(210.0/360.0, 1, 0.751),
vec3(240.0/360.0, 1, 0.251),
vec3(240.0/360.0, 1, 0.5),
vec3(240.0/360.0, 1, 0.751),
vec3(270.0/360.0, 1, 0.251),
vec3(270.0/360.0, 1, 0.5),
vec3(270.0/360.0, 1, 0.751),
vec3(300.0/360.0, 1, 0.251),
vec3(300.0/360.0, 1, 0.5),
vec3(300.0/360.0, 1, 0.751),
vec3(330.0/360.0, 1, 0.251),
vec3(330.0/360.0, 1, 0.5),
vec3(330.0/360.0, 1, 0.751)
);
const int indexMatrix8x8[64] = int[](0, 32, 8, 40, 2, 34, 10, 42,
48, 16, 56, 24, 50, 18, 58, 26,
12, 44, 4, 36, 14, 46, 6, 38,
@ -284,90 +246,28 @@ const int indexMatrix8x8[64] = int[](0, 32, 8, 40, 2, 34, 10, 42,
51, 19, 59, 27, 49, 17, 57, 25,
15, 47, 7, 39, 13, 45, 5, 37,
63, 31, 55, 23, 61, 29, 53, 21);
float indexValue8x8() {
int x = int(mod(gl_FragCoord.x, 8));
int y = int(mod(gl_FragCoord.y, 8));
float indexValue8x8( float scale ) {
int x = int(mod(gl_FragCoord.x * scale, 8));
int y = int(mod(gl_FragCoord.y * scale, 8));
return indexMatrix8x8[(x + y * 8)] / 64.0;
}
const int palette8x8Size = 28;
const vec3 palette8x8[28] = vec3[](
vec3(0, 0, 0),
vec3(0, 0, 1),
vec3(0, 0, 0.502),
vec3(0, 0, 0.753),
vec3(0, 1, 0.251),
vec3(0, 1, 0.50),
vec3(60.0/360.0, 1, 0.251),
vec3(60.0/360.0, 1, 0.5),
vec3(120.0/360.0, 1, 0.251),
vec3(120.0/360.0, 1, 0.5),
vec3(180.0/360.0, 1, 0.251),
vec3(180.0/360.0, 1, 0.5),
vec3(240.0/360.0, 1, 0.251),
vec3(240.0/360.0, 1, 0.5),
vec3(300.0/360.0, 1, 0.251),
vec3(300.0/360.0, 1, 0.5),
vec3(60.0/360.0, 0.333, 0.376),
vec3(60.0/360.0, 1, 0.751),
vec3(180.0/360.0, 1, 0.125),
vec3(150.0/360.0, 1, 0.5),
vec3(210.0/360.0, 1, 0.5),
vec3(180.0/360.0, 1, 0.751),
vec3(210.0/360.0, 1, 0.251),
vec3(240.0/360.0, 1, 0.751),
vec3(270.0/360.0, 1, 0.5),
vec3(330.0/360.0, 1, 0.5),
vec3(30.0/360.0, 1, 0.251),
vec3(24.0/360.0, 1, 0.625)
);
const int indexMatrix4x4[16] = int[](0, 8, 2, 10,
12, 4, 14, 6,
3, 11, 1, 9,
15, 7, 13, 5);
float indexValue4x4() {
int x = int(mod(gl_FragCoord.x, 4));
int y = int(mod(gl_FragCoord.y, 4));
float indexValue4x4( float scale ) {
int x = int(mod(gl_FragCoord.x * scale, 4));
int y = int(mod(gl_FragCoord.y * scale, 4));
return indexMatrix4x4[(x + y * 4)] / 16.0;
}
const int palette4x4Size = 28;
const vec3 palette4x4[28] = vec3[](
vec3(0, 0, 0),
vec3(0, 0, 1),
vec3(0, 0, 0.502),
vec3(0, 0, 0.753),
vec3(0, 1, 0.251),
vec3(0, 1, 0.50),
vec3(60.0/360.0, 1, 0.251),
vec3(60.0/360.0, 1, 0.5),
vec3(120.0/360.0, 1, 0.251),
vec3(120.0/360.0, 1, 0.5),
vec3(180.0/360.0, 1, 0.251),
vec3(180.0/360.0, 1, 0.5),
vec3(240.0/360.0, 1, 0.251),
vec3(240.0/360.0, 1, 0.5),
vec3(300.0/360.0, 1, 0.251),
vec3(300.0/360.0, 1, 0.5),
vec3(60.0/360.0, 0.333, 0.376),
vec3(60.0/360.0, 1, 0.751),
vec3(180.0/360.0, 1, 0.125),
vec3(150.0/360.0, 1, 0.5),
vec3(210.0/360.0, 1, 0.5),
vec3(180.0/360.0, 1, 0.751),
vec3(210.0/360.0, 1, 0.251),
vec3(240.0/360.0, 1, 0.751),
vec3(270.0/360.0, 1, 0.5),
vec3(330.0/360.0, 1, 0.5),
vec3(30.0/360.0, 1, 0.251),
vec3(24.0/360.0, 1, 0.625)
);
vec3[2] closestColors16x16(float hue) {
vec3[2] closestColors(float hue) {
vec3 ret[2];
vec3 closest = vec3(-2, 0, 0);
vec3 secondClosest = vec3(-2, 0, 0);
vec3 temp;
for (int i = 0; i < paletteSize; ++i) {
temp = rgbToHsl(palette16x16[i]);
/*
for (int i = 0; i < palette.length(); ++i) {
temp = rgbToHsl(palette[i].rgb);
float tempDistance = hueDistance(temp.x, hue);
if (tempDistance < hueDistance(closest.x, hue)) {
secondClosest = closest;
@ -378,123 +278,52 @@ vec3[2] closestColors16x16(float hue) {
}
}
}
*/
ret[0] = closest;
ret[1] = secondClosest;
return ret;
}
vec3 dither1_16x16(vec3 color) {
vec3 hsl = rgbToHsl(color);
vec3 cs[2] = closestColors16x16(hsl.x);
vec3 c1 = cs[0];
vec3 c2 = cs[1];
float d = indexValue16x16();
float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x);
float l1 = lightnessStep(max((hsl.z - 0.125), 0.0));
float l2 = lightnessStep(min((hsl.z + 0.124), 1.0));
float lightnessDiff = (hsl.z - l1) / (l2 - l1);
vec3 resultColor = (hueDiff < d) ? c1 : c2;
resultColor.z = (lightnessDiff < d) ? l1 : l2;
return hslToRgb(resultColor);
}
vec3[2] closestColors8x8(float hue) {
vec3 ret[2];
vec3 closest = vec3(-2, 0, 0);
vec3 secondClosest = vec3(-2, 0, 0);
vec3 temp;
for (int i = 0; i < palette8x8Size; ++i) {
temp = palette8x8[i];
float tempDistance = hueDistance(temp.x, hue);
if (tempDistance < hueDistance(closest.x, hue)) {
secondClosest = closest;
closest = temp;
} else {
if (tempDistance < hueDistance(secondClosest.x, hue)) {
secondClosest = temp;
}
}
}
ret[0] = closest;
ret[1] = secondClosest;
return ret;
}
vec3 dither1_8x8(vec3 color) {
vec3 hsl = rgbToHsl(color);
vec3 cs[2] = closestColors8x8(hsl.x);
vec3 c1 = cs[0];
vec3 c2 = cs[1];
float d = indexValue8x8();
float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x);
float l1 = lightnessStep(max((hsl.z - 0.125), 0.0));
float l2 = lightnessStep(min((hsl.z + 0.124), 1.0));
float lightnessDiff = (hsl.z - l1) / (l2 - l1);
vec3 resultColor = (hueDiff < d) ? c1 : c2;
//resultColor.z = (lightnessDiff < d) ? l1 : l2;
return hslToRgb(resultColor);
}
vec3[2] closestColors4x4(float hue) {
vec3 ret[2];
vec3 closest = vec3(-2, 0, 0);
vec3 secondClosest = vec3(-2, 0, 0);
vec3 temp;
for (int i = 0; i < palette4x4Size; ++i) {
temp = palette4x4[i];
float tempDistance = hueDistance(temp.x, hue);
if (tempDistance < hueDistance(closest.x, hue)) {
secondClosest = closest;
closest = temp;
} else {
if (tempDistance < hueDistance(secondClosest.x, hue)) {
secondClosest = temp;
}
}
}
ret[0] = closest;
ret[1] = secondClosest;
return ret;
}
vec3 dither1_4x4(vec3 color) {
vec3 hsl = rgbToHsl(color);
vec3 cs[2] = closestColors4x4(hsl.x);
vec3 c1 = cs[0];
vec3 c2 = cs[1];
float d = indexValue4x4();
float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x);
float l1 = lightnessStep(max((hsl.z - 0.125), 0.0));
float l2 = lightnessStep(min((hsl.z + 0.124), 1.0));
float lightnessDiff = (hsl.z - l1) / (l2 - l1);
vec3 resultColor = (hueDiff < d) ? c1 : c2;
//resultColor.z = (lightnessDiff < d) ? l1 : l2;
return hslToRgb(resultColor);
}
float dither(float color) {
float closestColor = (color < 0.5) ? 0 : 1;
float secondClosestColor = 1 - closestColor;
float d;
float d = 1; // -0.5 - fract(ubo.mode.parameters.w / 8.0);
if ( ubo.mode.scalar == 16 ) {
d = indexValue16x16();
d = indexValue16x16(1);
} else if ( ubo.mode.scalar == 8 ) {
d = indexValue8x8();
d = indexValue8x8(1);
} else if ( ubo.mode.scalar == 4 ) {
d = indexValue4x4();
d = indexValue4x4(1);
}
float distance = abs(closestColor - color);
return (distance < d) ? closestColor : secondClosestColor;
}
void dither(inout vec3 color) {
vec3 hsl = rgbToHsl(color);
hsl.y = dither(hsl.y);
hsl.x = dither(hsl.x);
color = hslToRgb(hsl);
}
void dither1(inout vec3 color) {
vec3 hsl = rgbToHsl(color);
float d = 0;
vec3 cs[2] = { hsl, hsl }; // closestColors(hsl.x);
float scale = 1;
if ( ubo.mode.scalar == 16 ) {
d = indexValue16x16(scale);
} else if ( ubo.mode.scalar == 8 ) {
d = indexValue8x8(scale);
} else if ( ubo.mode.scalar == 4 ) {
d = indexValue4x4(scale);
}
float hueDiff = hueDistance(hsl.x, cs[0].x) / hueDistance(cs[1].x, cs[0].x);
float l1 = lightnessStep(max((hsl.z - 0.125), 0.0));
float l2 = lightnessStep(min((hsl.z + 0.124), 1.0));
float lightnessDiff = (hsl.z - l1) / (l2 - l1);
vec3 resultColor = (hueDiff < d) ? cs[0] : cs[1];
resultColor.z = (lightnessDiff < d) ? l1 : l2;
color = hslToRgb(resultColor);
}
float rand2(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453);
@ -541,15 +370,12 @@ void main() {
fog(fragColor, litFactor);
if ( (ubo.mode.type & (0x1 >> 1)) == (0x1 >> 1) ) {
dither(fragColor);
if ( (ubo.mode.type & (0x1 << 0)) == (0x1 << 0) ) {
dither1(fragColor);
}
if ( (ubo.mode.type & (0x1 >> 2)) == (0x1 >> 2) ) {
if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) {
whitenoise(fragColor);
}
if ( (ubo.mode.type & (0x1 >> 3)) == (0x1 >> 3) ) {
dither(fragColor);
}
outFragColor = vec4(fragColor,1);
}

View File

@ -7,6 +7,7 @@ struct Gui {
vec4 color;
int mode;
float depth;
vec2 padding;
};
layout (location = 0) in vec2 inUv;
@ -19,7 +20,7 @@ void main() {
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);
outFragColor = texture(samplerColor, inUv);
if ( outFragColor.a < 0.001 ) discard;
if ( inGui.mode == 1 ) {
outFragColor = inGui.color;

View File

@ -1,38 +0,0 @@
#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;
}
float end = 0.25;
if ( inUv.x < end ) {
outFragColor.a = inUv.x / end;
} else if ( inUv.x + end >= 1 ) {
float offset = (1 - inUv.x);
outFragColor.a = offset / end;
}
}

View File

@ -15,6 +15,7 @@ struct Gui {
vec4 color;
int mode;
float depth;
vec2 padding;
};
layout (binding = 0) uniform UBO {

View File

@ -13,6 +13,7 @@ struct Gui {
float weight;
int spread;
float scale;
float padding;
};
layout (location = 0) in vec2 inUv;

View File

@ -21,6 +21,7 @@ struct Gui {
float weight;
int spread;
float scale;
float padding;
};
layout (binding = 0) uniform UBO {

View File

@ -21,6 +21,7 @@ struct Gui {
float weight;
int spread;
float scale;
float padding;
};
layout (binding = 0) uniform UBO {

View File

@ -15,6 +15,7 @@ struct Gui {
vec4 color;
int mode;
float depth;
vec2 padding;
};
layout (binding = 0) uniform UBO {

View File

@ -0,0 +1,39 @@
#version 450
layout (constant_id = 0) const uint TEXTURES = 87;
layout (binding = 1) uniform sampler2D samplerTextures[TEXTURES];
struct Map {
uint target;
float blend;
ivec2 padding;
};
layout (binding = 2) uniform UBO {
Map map[TEXTURES];
} ubo;
layout (location = 0) in vec2 inUv;
layout (location = 1) in vec4 inColor;
layout (location = 2) in vec3 inNormal;
layout (location = 3) in vec3 inPosition;
layout (location = 4) flat in uint inId;
layout (location = 0) out vec4 outAlbedoSpecular;
layout (location = 1) out vec4 outNormal;
layout (location = 2) out vec4 outPosition;
void main() {
uint offset = inId;
outAlbedoSpecular = texture(samplerTextures[offset], inUv.xy);
Map mapped = ubo.map[offset];
if ( offset != mapped.target ) {
outAlbedoSpecular = mix(texture(samplerTextures[offset], inUv.xy), texture(samplerTextures[mapped.target], inUv.xy), mapped.blend);
} else {
outAlbedoSpecular = texture(samplerTextures[offset], inUv.xy);
}
if ( outAlbedoSpecular.a < 0.001 ) discard;
outAlbedoSpecular.rgb *= inColor.rgb;
outAlbedoSpecular.a = 1;
outNormal = vec4(inNormal,1);
outPosition = vec4(inPosition,1);
}

View File

@ -6,6 +6,12 @@
#include <uf/utils/mempool/mempool.h>
int main(int argc, char** argv){
for ( size_t i = 0; i < argc; ++i ) {
char* c_str = argv[i];
std::string string(argv[i]);
ext::arguments.emplace_back(string);
}
std::atexit([]{
uf::iostream << "Termination via std::atexit()!" << "\n";
client::terminated = !(client::ready = ext::ready = false);
@ -42,13 +48,9 @@ int main(int argc, char** argv){
ext::render();
} catch ( std::runtime_error& e ) {
uf::iostream << "RUNTIME ERROR: " << e.what() << "\n";
std::abort();
raise(SIGSEGV);
throw e;
break;
} catch ( std::exception& e ) {
uf::iostream << "EXCEPTION ERROR: " << e.what() << "\n";
std::abort();
raise(SIGSEGV);
throw e;
} catch ( bool handled ) {
if (!handled) uf::iostream << "UNHANDLED ERROR: " << "???" << "\n";
@ -59,8 +61,8 @@ int main(int argc, char** argv){
if ( !client::terminated ) {
uf::iostream << "Natural termination!" << "\n";
ext::terminate();
client::terminate();
}
ext::terminate();
client::terminate();
return 0;
}

View File

@ -31,9 +31,12 @@ namespace uf {
template<typename T>
T loadChild( const std::string&, bool = true );
std::string formatHookName( const std::string& name );
void queueHook( const std::string&, const std::string& = "", double = 0 );
std::vector<std::string> callHook( const std::string&, const std::string& = "" );
std::size_t addHook( const std::string&, const uf::HookHandler::Readable::function_t& );
std::string grabURI( const std::string& filename, const std::string& root = "" );
};
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <uf/config.h>
#include <vector>
#if !defined(EXT_STATIC)
#if defined(UF_ENV_WINDOWS)
@ -38,6 +39,7 @@
#include <string>
namespace ext {
extern bool EXT_API ready;
extern std::vector<std::string> EXT_API arguments;
extern void EXT_API initialize();
extern bool EXT_API running();

View File

@ -11,7 +11,11 @@ namespace ext {
VkDevice device;
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkDescriptorBufferInfo descriptor;
VkDescriptorBufferInfo descriptor = {
VK_NULL_HANDLE,
0,
0
};
VkDeviceSize size = 0;
VkDeviceSize alignment = 0;
void* mapped = nullptr;

View File

@ -3,6 +3,7 @@
#include <uf/ext/vulkan.h>
#include <uf/ext/vulkan/buffer.h>
#include <uf/utils/window/window.h>
#include <uf/utils/thread/thread.h>
namespace ext {
namespace vulkan {
@ -13,9 +14,9 @@ namespace ext {
VkPhysicalDevice physicalDevice;
VkDevice logicalDevice;
struct {
VkCommandPool graphics = VK_NULL_HANDLE;
VkCommandPool compute = VK_NULL_HANDLE;
VkCommandPool transfer = VK_NULL_HANDLE;
std::unordered_map<std::thread::id, VkCommandPool> graphics;
std::unordered_map<std::thread::id, VkCommandPool> compute;
std::unordered_map<std::thread::id, VkCommandPool> transfer;
} commandPool;
VkPhysicalDeviceProperties properties;
@ -42,10 +43,10 @@ namespace ext {
std::vector<VkQueueFamilyProperties> queueFamilyProperties;
struct {
VkQueue graphics;
VkQueue present;
VkQueue compute;
VkQueue transfer;
std::unordered_map<std::thread::id,VkQueue> graphics;
std::unordered_map<std::thread::id,VkQueue> present;
std::unordered_map<std::thread::id,VkQueue> compute;
std::unordered_map<std::thread::id,VkQueue> transfer;
} queues;
uf::Window* window;
@ -88,6 +89,15 @@ namespace ext {
void *data = nullptr
);
enum QueueEnum {
GRAPHICS,
PRESENT,
COMPUTE,
TRANSFER,
};
VkQueue& getQueue( QueueEnum );
VkCommandPool& getCommandPool( QueueEnum );
// RAII
void initialize();
void destroy();

View File

@ -18,7 +18,7 @@ void ext::vulkan::Graphic::initializeGeometry( uf::BaseMesh<T, U>& mesh, bool st
updateBuffer(
(void*) mesh.indices.data(),
mesh.indices.size() * mesh.sizes.indices,
0,
1,
stage
);
return;

View File

@ -9,6 +9,7 @@ namespace ext {
VkFormat format;
VkImageLayout layout;
VkImageUsageFlags usage;
VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
bool aliased = false;
VkImage image;

View File

@ -15,21 +15,24 @@ namespace ext {
struct {
VkFilter min = VK_FILTER_LINEAR;
VkFilter mag = VK_FILTER_LINEAR;
VkBorderColor borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
} filter;
struct {
VkSamplerAddressMode u = VK_SAMPLER_ADDRESS_MODE_REPEAT, v = VK_SAMPLER_ADDRESS_MODE_REPEAT, w = VK_SAMPLER_ADDRESS_MODE_REPEAT;
VkBool32 unnormalizedCoordinates = VK_FALSE;
} addressMode;
struct {
VkBool32 compareEnable = VK_FALSE;
VkCompareOp compareOp = VK_COMPARE_OP_ALWAYS;
VkSamplerMipmapMode mode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
float lodBias = 0.0f;
} mip;
VkCompareOp compareOp = VK_COMPARE_OP_NEVER;
struct {
float min = 0.0f;
float max = 0.0f;
} lod;
float maxAnisotropy;
} mip;
struct {
VkBool32 enabled = VK_TRUE;
float max = 16.0f;
} anisotropy;
VkDescriptorImageInfo info;
} descriptor;
@ -41,9 +44,10 @@ namespace ext {
VkImage image;
VkImageView view;
VkImageLayout imageLayout;
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkDeviceMemory deviceMemory;
VkDescriptorImageInfo descriptor;
VkFormat format;
Sampler sampler;
@ -63,9 +67,7 @@ namespace ext {
VkImage image,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
VkImageSubresourceRange subresourceRange,
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
VkImageSubresourceRange subresourceRange
);
static void setImageLayout(
VkCommandBuffer cmdbuffer,
@ -73,8 +75,7 @@ namespace ext {
VkImageAspectFlags aspectMask,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
uint32_t mipLevels
);
};
struct UF_API Texture2D : public Texture {
@ -83,31 +84,27 @@ namespace ext {
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
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);
void loadFromFile(
std::string filename,
Device& device,
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
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);
void loadFromImage(
uf::Image& image,
Device& device,
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
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);
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
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);
void fromBuffers(
void* buffer,
@ -119,13 +116,14 @@ namespace ext {
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);
void asRenderTarget(
Device& device,
uint32_t texWidth,
uint32_t texHeight,
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM
);
void asRenderTarget( Device& device, uint32_t texWidth, uint32_t texHeight, VkFormat format = VK_FORMAT_R8G8B8A8_UNORM );
void aliasAttachment( const RenderTarget::Attachment& attachment, bool = true );
void update( uf::Image& image, VkImageLayout );
void update( void*, VkDeviceSize, VkImageLayout );
inline void update( uf::Image& image ) { return this->update(image, this->imageLayout) ; }
inline void update( void* data, VkDeviceSize size ) { return this->update(data, size, this->imageLayout) ; }
void generateMipmaps(VkCommandBuffer commandBuffer);
};
}
}

View File

@ -41,8 +41,11 @@ namespace ext {
extern UF_API uint32_t width;
extern UF_API uint32_t height;
extern UF_API uint8_t msaa;
extern UF_API bool validation;
extern UF_API bool rebuildOnTickStart;
extern UF_API bool waitOnRenderEnd;
extern UF_API std::vector<std::string> validationFilters;
extern UF_API std::vector<std::string> requestedDeviceFeatures;
extern UF_API std::vector<std::string> requestedDeviceExtensions;

View File

@ -248,26 +248,4 @@ namespace uf {
} matrices;
alignas(16) pod::Vector4f color = { 1, 1, 1, 0 };
};
struct GuiMeshDescriptor {
struct {
alignas(16) pod::Matrix4f model;
} matrices;
struct {
alignas(16) pod::Vector4f offset;
alignas(16) pod::Vector4f color;
alignas(4) int32_t mode = 0;
alignas(4) float depth = 0.0f;
} gui;
};
struct StereoGuiMeshDescriptor {
struct {
alignas(16) pod::Matrix4f model[2];
} matrices;
struct {
alignas(16) pod::Vector4f offset;
alignas(16) pod::Vector4f color;
alignas(4) int32_t mode = 0;
alignas(4) float depth = 0.0f;
} gui;
};
}

View File

@ -22,6 +22,7 @@ namespace uf {
void addImage( const uint8_t*, const pod::Vector2ui&, std::size_t, std::size_t, bool = false, bool = false );
void generate();
void clear();
pod::Vector2f mapUv( const pod::Vector2f&, size_t );
pod::Vector3f mapUv( const pod::Vector3f& );

View File

@ -12,5 +12,6 @@ namespace uf {
std::string UF_API lowercase( const std::string& );
std::string UF_API uppercase( const std::string& );
std::vector<std::string> UF_API split( const std::string&, const std::string& );
std::string UF_API si( double value, const std::string& unit, size_t precision = 3 );
}
}

View File

@ -11,12 +11,22 @@
#include <uf/utils/thread/thread.h>
#include <uf/utils/graphic/mesh.h>
#include <uf/ext/gltf/gltf.h>
#include <uf/utils/string/hash.h>
UF_BEHAVIOR_REGISTER_CPP(GltfBehavior)
#define this (&self)
void uf::GltfBehavior::initialize( uf::Object& self ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
metadata["textures"]["additional"] = Json::Value(Json::arrayValue);
// Default load: GLTF model
this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{
uf::Serializer json = event;
std::string filename = json["filename"].asString();
if ( uf::io::extension(filename) != "png" ) return "false";
auto& vector = metadata["textures"]["additional"];
vector[vector.size()] = filename;
return "true";
});
this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{
uf::Serializer json = event;
std::string filename = json["filename"].asString();
@ -28,16 +38,39 @@ void uf::GltfBehavior::initialize( uf::Object& self ) {
uf::Object* objectPointer = NULL;
try { objectPointer = assetLoader.get<uf::Object*>(filename); } catch ( ... ) {}
if ( !objectPointer ) return "false";
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
objectPointer->process([&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Graphic>() || !entity->hasComponent<ext::gltf::mesh_t>() ) return;
auto& graphic = entity->getComponent<uf::Graphic>();
auto& mesh = entity->getComponent<ext::gltf::mesh_t>();
graphic.initialize();
graphic.initializeGeometry( mesh );
graphic.material.attachShader("./data/shaders/gltf.stereo.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
graphic.material.attachShader("./data/shaders/gltf.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
{
std::string filename = "/gltf.stereo.vert.spv";
if ( metadata["system"]["renderer"]["shaders"]["vertex"].isString() )
filename = metadata["system"]["renderer"]["shaders"]["vertex"].asString();
filename = this->grabURI( filename, metadata["system"]["root"].asString() );
graphic.material.attachShader(filename, VK_SHADER_STAGE_VERTEX_BIT);
}
{
std::string filename = "/gltf.frag.spv";
if ( metadata["system"]["renderer"]["shaders"]["fragment"].isString() )
filename = metadata["system"]["renderer"]["shaders"]["fragment"].asString();
filename = this->grabURI( filename, metadata["system"]["root"].asString() );
graphic.material.attachShader(filename, VK_SHADER_STAGE_FRAGMENT_BIT);
}
for ( int i = 0; i < metadata["textures"]["additional"].size(); ++i ) {
std::string filename = metadata["textures"]["additional"][i].asString();
auto& scene = uf::scene::getCurrentScene();
auto& assetLoader = scene.getComponent<uf::Asset>();
const uf::Image* imagePointer = NULL;
try { imagePointer = &assetLoader.get<uf::Image>(filename); } catch ( ... ) {}
if ( !imagePointer ) continue;
uf::Image image = *imagePointer;
auto& texture = graphic.material.textures.emplace_back();
texture.loadFromImage( image );
}
graphic.process = true;
@ -52,12 +85,15 @@ void uf::GltfBehavior::initialize( uf::Object& self ) {
if ( binding.descriptorCount > 1 )
binding.descriptorCount = specializationConstants->textures;
}
};
objectPointer->process(filter);
});
this->addChild(objectPointer->as<uf::Entity>());
objectPointer->initialize();
objectPointer->process([&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Graphic>() || !entity->hasComponent<ext::gltf::mesh_t>() ) return;
auto& eMetadata = entity->getComponent<uf::Serializer>();
eMetadata["textures"]["map"] = metadata["textures"]["map"];
uf::instantiator::bind( "GltfBehavior", *entity );
});
return "true";
});
}
@ -65,7 +101,50 @@ void uf::GltfBehavior::destroy( uf::Object& self ) {
}
void uf::GltfBehavior::tick( uf::Object& self ) {
/* Update uniforms */ if ( this->hasComponent<uf::Graphic>() ) {
auto& metadata = this->getComponent<uf::Serializer>();
auto& graphic = this->getComponent<uf::Graphic>();
if ( !graphic.initialized ) return;
auto& shader = graphic.material.shaders.back();
if ( shader.uniforms.empty() ) return;
auto& userdata = shader.uniforms.front();
struct UniformDescriptor {
// alignas(4) uint32_t mappings;
struct Mapping {
alignas(4) uint32_t target;
alignas(4) float blend;
uint32_t padding[2];
} map;
};
size_t uniforms_len = userdata.data().len;
uint8_t* uniforms_buffer = (uint8_t*) (void*) userdata;
UniformDescriptor* uniforms = (UniformDescriptor*) uniforms_buffer;
UniformDescriptor::Mapping* mappings = (UniformDescriptor::Mapping*) &uniforms_buffer[sizeof(UniformDescriptor) - sizeof(UniformDescriptor::Mapping)];
size_t textures = graphic.material.textures.size();
// uniforms->mappings = textures;
for ( size_t i = 0; i < textures; ++i ) {
mappings[i].target = i;
mappings[i].blend = 0.0f;
}
for ( auto it = metadata["textures"]["map"].begin(); it != metadata["textures"]["map"].end(); ++it ) {
std::string key = it.key().asString();
uint32_t from = std::stoi(key);
uint32_t to = metadata["textures"]["map"][key][0].asUInt();
float blend = 1.0f;
if ( metadata["textures"]["map"][key][1].asString() == "sin(time)" ) {
blend = sin(uf::physics::time::current)*0.5f+0.5f;
} else if ( metadata["textures"]["map"][key][1].asString() == "cos(time)" ) {
blend = cos(uf::physics::time::current)*0.5f+0.5f;
} else if ( metadata["textures"]["map"][key][1].isNumeric() ) {
blend = metadata["textures"]["map"][key][1].asFloat();
}
if ( from >= textures || to >= textures ) continue;
mappings[from].target = to;
mappings[from].blend = blend;
}
shader.updateBuffer( (void*) uniforms_buffer, uniforms_len, 0, false );
};
}
void uf::GltfBehavior::render( uf::Object& self ) {

View File

@ -12,19 +12,6 @@
uf::Timer<long long> uf::Object::timer(false);
namespace {
uf::Object null;
std::string grabURI( std::string filename, std::string root = "" ) {
if ( filename.substr(0,8) == "https://" ) return filename;
std::string extension = uf::io::extension(filename);
if ( filename[0] == '/' || root == "" ) {
if ( filename.substr(0,9) == "/smtsamo/" ) root = "./data/";
else if ( extension == "json" ) root = "./data/entities/";
else if ( extension == "png" ) root = "./data/textures/";
else if ( extension == "glb" ) root = "./data/models/";
else if ( extension == "gltf" ) root = "./data/models/";
else if ( extension == "ogg" ) root = "./data/audio/";
}
return uf::io::sanitize(filename, root);
}
}
UF_OBJECT_REGISTER_BEGIN(Object)
@ -41,12 +28,22 @@ void uf::Object::queueHook( const std::string& name, const std::string& payload,
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::string uf::Object::formatHookName( const std::string& n ) {
std::unordered_map<std::string, std::string> formats = {
{"%UID%", std::to_string(this->getUid())},
{"%P-UID%", std::to_string(this->getParent().getUid())},
};
std::string name = n;
for ( auto& pair : formats ) {
name = uf::string::replace( name, pair.first, pair.second );
}
return name;
}
std::vector<std::string> uf::Object::callHook( const std::string& name, const std::string& payload ) {
return uf::hooks.call( this->formatHookName( 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::string parsed = this->formatHookName( name );
std::size_t id = uf::hooks.addHook( parsed, callback );
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
metadata["system"]["hooks"]["alloc"][parsed].append(id);
@ -76,6 +73,7 @@ bool uf::Object::reload( bool hard ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( !metadata["system"]["source"].isString() ) return false;
uf::Serializer json;
uf::Serializer payload;
std::string filename = metadata["system"]["source"].asString(); //grabURI( metadata["system"]["source"].asString(), metadata["system"]["root"].asString() ); // uf::io::sanitize(metadata["system"]["source"].asString(), metadata["system"]["root"].asString());
if ( !json.readFromFile( filename ) ) {
uf::iostream << "Error @ " << __FILE__ << ":" << __LINE__ << ": failed to open `" + filename + "`" << "\n";
@ -83,11 +81,15 @@ bool uf::Object::reload( bool hard ) {
return false;
}
if ( hard ) return this->load(filename);
payload["old"] = metadata;
for ( auto it = json["metadata"].begin(); it != json["metadata"].end(); ++it ) {
metadata[it.key().asString()] = json["metadata"][it.key().asString()];
}
payload["new"] = metadata;
std::cout << "Updated metadata for " << this->getName() << ": " << this->getUid() << std::endl;
this->queueHook("object:Reload.%UID%");
this->queueHook("object:Reload.%UID%", payload);
return true;
}
@ -306,6 +308,7 @@ bool uf::Object::load( const uf::Serializer& _json ) {
json["root"] = uf::io::directory(filename);
json["source"] = filename; // uf::io::filename(filename)
json["hot reload"]["mtime"] = uf::io::mtime( filename ) + 10;
if ( this->loadChildUid(json) == -1 ) continue;
}
}
@ -411,4 +414,20 @@ std::size_t uf::Object::loadChildUid( const std::string& f, bool initialize ) {
std::size_t uf::Object::loadChildUid( const uf::Serializer& json, bool initialize ) {
uf::Object* pointer = this->loadChildPointer(json, initialize);
return pointer ? pointer->getUid() : -1;
}
std::string uf::Object::grabURI( const std::string& filename, const std::string& _root ) {
std::string root = _root;
if ( filename.substr(0,8) == "https://" ) return filename;
std::string extension = uf::io::extension(filename);
if ( filename[0] == '/' || root == "" ) {
if ( filename.substr(0,9) == "/smtsamo/" ) root = "./data/";
else if ( extension == "json" ) root = "./data/entities/";
else if ( extension == "png" ) root = "./data/textures/";
else if ( extension == "glb" ) root = "./data/models/";
else if ( extension == "gltf" ) root = "./data/models/";
else if ( extension == "ogg" ) root = "./data/audio/";
else if ( extension == "spv" ) root = "./data/shaders/";
}
return uf::io::sanitize(filename, root);
}

View File

@ -12,6 +12,7 @@
#include <uf/utils/serialize/serializer.h>
#include <uf/utils/math/collision.h>
#include <uf/utils/image/atlas.h>
#include <uf/utils/string/hash.h>
namespace {
@ -224,6 +225,14 @@ void loadNode( uf::Object& entity, const tinygltf::Model& model, const tinygltf:
auto& im = model.images[t.source];
uf::Image& image = images.emplace_back();
image.loadFromBuffer( &im.image[0], {im.width, im.height}, 8, im.component, true );
/*
{
static int i = 0;
auto& pixels = image.getPixels();
std::string hash = uf::string::sha256( pixels );
image.save("./textures/" + std::to_string(i++) + "."+hash+".png");
}
*/
}
if ( mode & ext::gltf::LoadMode::SEPARATE_MESHES ) {
auto sampler = samplers.begin();

View File

@ -468,7 +468,7 @@ void ext::openvr::submit() { bool invert = swapEyes;
vulkanData.m_pDevice = ( VkDevice_T * ) ext::vulkan::device;
vulkanData.m_pPhysicalDevice = ( VkPhysicalDevice_T * ) ext::vulkan::device.physicalDevice;
vulkanData.m_pInstance = ( VkInstance_T *) ext::vulkan::device.instance;
vulkanData.m_pQueue = ( VkQueue_T * ) ext::vulkan::device.queues.present;
vulkanData.m_pQueue = ( VkQueue_T * ) ext::vulkan::device.getQueue( ext::vulkan::Device::QueueEnum::PRESENT );
vulkanData.m_nQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.present;
vulkanData.m_nWidth = width;

View File

@ -127,6 +127,15 @@ namespace {
CHECK_FEATURE(inheritedQueries);
}
#undef CHECK_FEATURE
#define CHECK_FEATURE2( NAME )\
if ( feature == #NAME ) {\
if ( device.features2.NAME == VK_TRUE ) {\
device.enabledFeatures2.NAME = true;\
if ( ext::vulkan::validation ) std::cout << "Enabled feature: " << feature << std::endl;\
} else if ( ext::vulkan::validation ) std::cout << "Failed to enable feature: " << feature << std::endl;\
}
#undef CHECK_FEATURE2
}
uf::Serializer retrieveDeviceFeatures( ext::vulkan::Device& device ) {
uf::Serializer json;
@ -192,6 +201,11 @@ namespace {
CHECK_FEATURE(inheritedQueries);
#undef CHECK_FEATURE
#define CHECK_FEATURE2( NAME )\
json[#NAME]["supported"] = device.features2.NAME;\
json[#NAME]["enabled"] = device.enabledFeatures2.NAME;
#undef CHECK_FEATURE2
return json;
}
}
@ -295,7 +309,7 @@ int ext::vulkan::Device::rate( VkPhysicalDevice device ) {
}
VkCommandBuffer ext::vulkan::Device::createCommandBuffer( VkCommandBufferLevel level, bool begin ){
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo( commandPool.transfer, level, 1 );
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo( getCommandPool(QueueEnum::TRANSFER), level, 1 );
VkCommandBuffer commandBuffer;
VK_CHECK_RESULT( vkAllocateCommandBuffers( logicalDevice, &cmdBufAllocateInfo, &commandBuffer ) );
@ -322,14 +336,14 @@ void ext::vulkan::Device::flushCommandBuffer( VkCommandBuffer commandBuffer, boo
VK_CHECK_RESULT(vkCreateFence(logicalDevice, &fenceInfo, nullptr, &fence));
// Submit to the queue
VK_CHECK_RESULT(vkQueueSubmit(device.queues.transfer, 1, &submitInfo, fence));
VK_CHECK_RESULT(vkQueueSubmit( getQueue( QueueEnum::TRANSFER ), 1, &submitInfo, fence));
// vkQueueSubmit(device.queues.transfer, 1, &submitInfo, fence);
// Wait for the fence to signal that command buffer has finished executing
VK_CHECK_RESULT(vkWaitForFences(logicalDevice, 1, &fence, VK_TRUE, DEFAULT_FENCE_TIMEOUT));
vkDestroyFence(logicalDevice, fence, nullptr);
if ( free ) vkFreeCommandBuffers(logicalDevice, commandPool.transfer, 1, &commandBuffer);
if ( free ) vkFreeCommandBuffers(logicalDevice, getCommandPool( QueueEnum::TRANSFER ), 1, &commandBuffer);
}
VkResult ext::vulkan::Device::createBuffer( VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer* buffer, VkDeviceMemory* memory, void *data ) {
@ -421,6 +435,71 @@ VkResult ext::vulkan::Device::createBuffer(
// Attach the memory to the buffer object
return buffer.bind();
}
VkCommandPool& ext::vulkan::Device::getCommandPool( ext::vulkan::Device::QueueEnum queueEnum ) {
uint32_t index = 0;
VkCommandPool* pool = NULL;
bool exists = false;
auto id = std::this_thread::get_id();
switch ( queueEnum ) {
case QueueEnum::GRAPHICS:
index = device.queueFamilyIndices.graphics;
if ( commandPool.graphics.count(id) > 0 ) exists = true;
pool = &commandPool.graphics[id];
break;
case QueueEnum::COMPUTE:
index = device.queueFamilyIndices.compute;
if ( commandPool.compute.count(id) > 0 ) exists = true;
pool = &commandPool.compute[id];
break;
case QueueEnum::TRANSFER:
index = device.queueFamilyIndices.transfer;
if ( commandPool.transfer.count(id) > 0 ) exists = true;
pool = &commandPool.transfer[id];
break;
}
if ( !exists ) {
VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
VkCommandPoolCreateInfo cmdPoolInfo = {};
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmdPoolInfo.queueFamilyIndex = index;
cmdPoolInfo.flags = createFlags;
if ( vkCreateCommandPool( this->logicalDevice, &cmdPoolInfo, nullptr, pool ) != VK_SUCCESS )
throw std::runtime_error("failed to create command pool for graphics!");
}
return *pool;
}
VkQueue& ext::vulkan::Device::getQueue( ext::vulkan::Device::QueueEnum queueEnum ) {
uint32_t index = 0;
VkQueue* queue = NULL;
bool exists = false;
auto id = std::this_thread::get_id();
switch ( queueEnum ) {
case QueueEnum::GRAPHICS:
index = device.queueFamilyIndices.graphics;
if ( queues.graphics.count(id) > 0 ) exists = true;
queue = &queues.graphics[id];
break;
case QueueEnum::PRESENT:
index = device.queueFamilyIndices.present;
if ( queues.present.count(id) > 0 ) exists = true;
queue = &queues.present[id];
break;
case QueueEnum::COMPUTE:
index = device.queueFamilyIndices.compute;
if ( queues.compute.count(id) > 0 ) exists = true;
queue = &queues.compute[id];
break;
case QueueEnum::TRANSFER:
index = device.queueFamilyIndices.transfer;
if ( queues.transfer.count(id) > 0 ) exists = true;
queue = &queues.transfer[id];
break;
}
if ( !exists ) {
vkGetDeviceQueue( device, index, 0, queue );
}
return *queue;
}
void ext::vulkan::Device::initialize() {
const std::vector<const char*> validationLayers = {
@ -540,7 +619,11 @@ void ext::vulkan::Device::initialize() {
// Memory properties are used regularly for creating all kinds of buffers
vkGetPhysicalDeviceMemoryProperties( this->physicalDevice, &memoryProperties );
}
if ( false ) {
{
properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
memoryProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
vkGetPhysicalDeviceProperties2( this->physicalDevice, &properties2 );
// Features should be checked by the examples before using them
vkGetPhysicalDeviceFeatures2( this->physicalDevice, &features2 );
@ -553,6 +636,17 @@ void ext::vulkan::Device::initialize() {
// assert(queueFamilyCount > 0);
queueFamilyProperties.resize(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties( this->physicalDevice, &queueFamilyCount, queueFamilyProperties.data() );
{
VkSampleCountFlags counts = properties.limits.framebufferColorSampleCounts & properties.limits.framebufferDepthSampleCounts;
uint8_t maxSamples = 1;
if (counts & VK_SAMPLE_COUNT_64_BIT) maxSamples = 64;
else if (counts & VK_SAMPLE_COUNT_32_BIT) maxSamples = 32;
else if (counts & VK_SAMPLE_COUNT_16_BIT) maxSamples = 16;
else if (counts & VK_SAMPLE_COUNT_8_BIT) maxSamples = 8;
else if (counts & VK_SAMPLE_COUNT_4_BIT) maxSamples = 4;
else if (counts & VK_SAMPLE_COUNT_2_BIT) maxSamples = 2;
ext::vulkan::msaa = std::min( maxSamples, ext::vulkan::msaa );
}
}
// Create logical device
{
@ -664,33 +758,9 @@ void ext::vulkan::Device::initialize() {
std::cout << retrieveDeviceFeatures( *this ) << std::endl;
}
// Create command pool
{
VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
VkCommandPoolCreateInfo cmdPoolInfo = {};
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmdPoolInfo.queueFamilyIndex = queueFamilyIndices.graphics;
cmdPoolInfo.flags = createFlags;
if ( vkCreateCommandPool( this->logicalDevice, &cmdPoolInfo, nullptr, &commandPool.graphics ) != VK_SUCCESS )
throw std::runtime_error("failed to create command pool for graphics!");
}
{
VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
VkCommandPoolCreateInfo cmdPoolInfo = {};
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmdPoolInfo.queueFamilyIndex = queueFamilyIndices.compute;
cmdPoolInfo.flags = createFlags;
if ( vkCreateCommandPool( this->logicalDevice, &cmdPoolInfo, nullptr, &commandPool.compute ) != VK_SUCCESS )
throw std::runtime_error("failed to create command pool for compute!");
}
{
VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
VkCommandPoolCreateInfo cmdPoolInfo = {};
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmdPoolInfo.queueFamilyIndex = queueFamilyIndices.transfer;
cmdPoolInfo.flags = createFlags;
if ( vkCreateCommandPool( this->logicalDevice, &cmdPoolInfo, nullptr, &commandPool.transfer ) != VK_SUCCESS )
throw std::runtime_error("failed to create command pool for transfer!");
}
getCommandPool( QueueEnum::GRAPHICS );
getCommandPool( QueueEnum::COMPUTE );
getCommandPool( QueueEnum::TRANSFER );
// Set queue
{
uint32_t graphicsQueueNodeIndex = UINT32_MAX;
@ -720,11 +790,16 @@ void ext::vulkan::Device::initialize() {
}
device.queueFamilyIndices.present = presentQueueNodeIndex;
vkGetDeviceQueue( device, device.queueFamilyIndices.graphics, 0, &queues.graphics );
vkGetDeviceQueue( device, device.queueFamilyIndices.present, 0, &queues.present );
vkGetDeviceQueue( device, device.queueFamilyIndices.compute, 0, &queues.compute );
vkGetDeviceQueue( device, device.queueFamilyIndices.transfer, 0, &queues.transfer );
getQueue( QueueEnum::GRAPHICS );
getQueue( QueueEnum::PRESENT );
getQueue( QueueEnum::COMPUTE );
getQueue( QueueEnum::TRANSFER );
/*
vkGetDeviceQueue( device, device.queueFamilyIndices.graphics, 0, &queues.graphics[std::this_thread::get_id()] );
vkGetDeviceQueue( device, device.queueFamilyIndices.present, 0, &queues.present[std::this_thread::get_id()] );
vkGetDeviceQueue( device, device.queueFamilyIndices.compute, 0, &queues.compute[std::this_thread::get_id()] );
vkGetDeviceQueue( device, device.queueFamilyIndices.transfer, 0, &queues.transfer[std::this_thread::get_id()] );
*/
}
// Set formats
{
@ -791,17 +866,17 @@ void ext::vulkan::Device::destroy() {
vkDestroyPipelineCache( this->logicalDevice, this->pipelineCache, nullptr );
this->pipelineCache = nullptr;
}
if ( this->commandPool.graphics ) {
vkDestroyCommandPool( this->logicalDevice, this->commandPool.graphics, nullptr );
this->commandPool.graphics = nullptr;
for ( auto& pair : this->commandPool.graphics ) {
vkDestroyCommandPool( this->logicalDevice, pair.second, nullptr );
pair.second = VK_NULL_HANDLE;
}
if ( this->commandPool.compute ) {
vkDestroyCommandPool( this->logicalDevice, this->commandPool.compute, nullptr );
this->commandPool.compute = nullptr;
for ( auto& pair : this->commandPool.compute ) {
vkDestroyCommandPool( this->logicalDevice, pair.second, nullptr );
pair.second = VK_NULL_HANDLE;
}
if ( this->commandPool.transfer ) {
vkDestroyCommandPool( this->logicalDevice, this->commandPool.transfer, nullptr );
this->commandPool.transfer = nullptr;
for ( auto& pair : this->commandPool.transfer ) {
vkDestroyCommandPool( this->logicalDevice, pair.second, nullptr );
pair.second = VK_NULL_HANDLE;
}
if ( this->logicalDevice ) {
vkDestroyDevice( this->logicalDevice, nullptr );

View File

@ -322,7 +322,7 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic ) {
blendAttachmentStates.push_back(renderTarget.attachments[color.attachment].blendState);
}
// require blending if independentBlend is not an enabled feature
if ( !device.enabledFeatures.independentBlend ) {
if ( device.enabledFeatures.independentBlend == VK_FALSE ) {
for ( size_t i = 1; i < blendAttachmentStates.size(); ++i ) {
blendAttachmentStates[i] = blendAttachmentStates[0];
}
@ -365,8 +365,18 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic ) {
VkPipelineViewportStateCreateInfo viewportState = ext::vulkan::initializers::pipelineViewportStateCreateInfo(
1, 1, 0
);
VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
switch ( ext::vulkan::msaa ) {
case 64: samples = VK_SAMPLE_COUNT_64_BIT; break;
case 32: samples = VK_SAMPLE_COUNT_32_BIT; break;
case 16: samples = VK_SAMPLE_COUNT_16_BIT; break;
case 8: samples = VK_SAMPLE_COUNT_8_BIT; break;
case 4: samples = VK_SAMPLE_COUNT_4_BIT; break;
case 2: samples = VK_SAMPLE_COUNT_2_BIT; break;
default: samples = VK_SAMPLE_COUNT_1_BIT; break;
}
VkPipelineMultisampleStateCreateInfo multisampleState = ext::vulkan::initializers::pipelineMultisampleStateCreateInfo(
VK_SAMPLE_COUNT_1_BIT,
samples,
0
);
std::vector<VkDynamicState> dynamicStateEnables = {
@ -460,7 +470,7 @@ void ext::vulkan::Pipeline::record( Graphic& graphic, VkCommandBuffer commandBuf
}
}
// Bind descriptor sets describing shader binding points
vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
vkCmdBindDescriptorSets(commandBuffer, bindPoint, 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, bindPoint, pipeline);
@ -493,11 +503,46 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
}
{
for ( auto& shader : graphic.material.shaders ) {
std::vector<VkDescriptorBufferInfo> buffersStorageVector;
std::vector<VkDescriptorBufferInfo> buffersUniformsVector;
for ( auto& buffer : shader.buffers ) {
if ( buffer.usageFlags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) {
auto& descriptor = buffersStorageVector.emplace_back(buffer.descriptor);
if ( descriptor.offset % device->properties.limits.minStorageBufferOffsetAlignment != 0 ) {
// std::cout << "Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.pBufferInfo->offset << std::endl;
descriptor.offset = 0;
}
}
if ( buffer.usageFlags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) {
auto& descriptor = buffersUniformsVector.emplace_back(buffer.descriptor);
if ( descriptor.offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) {
// std::cout << "Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.pBufferInfo->offset << std::endl;
descriptor.offset = 0;
}
}
}
for ( auto& buffer : graphic.buffers ) {
if ( buffer.usageFlags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) {
auto& descriptor = buffersStorageVector.emplace_back(buffer.descriptor);
if ( descriptor.offset % device->properties.limits.minStorageBufferOffsetAlignment != 0 ) {
std::cout << __LINE__ << ": Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.offset << std::endl;
descriptor.offset = 0;
}
}
if ( buffer.usageFlags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) {
auto& descriptor = buffersUniformsVector.emplace_back(buffer.descriptor);
if ( descriptor.offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) {
std::cout << __LINE__ << ": Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.offset << std::endl;
descriptor.offset = 0;
}
}
}
auto textures = graphic.material.textures.begin();
auto samplers = graphic.material.samplers.begin();
auto buffersUniforms = shader.buffers.begin();
auto buffersStorage = graphic.buffers.begin();
auto attachments = inputDescriptors.begin();
auto buffersStorage = buffersStorageVector.begin();
auto buffersUniforms = buffersUniformsVector.begin();
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
@ -509,9 +554,6 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
size_t imageInfosStart = imageInfos.size();
// assume we have a texture, and fill it in the slots as defaults
size_t target = layout.descriptorCount;
if ( target == 132 ) {
target = graphic.material.textures.size();
}
for ( size_t i = 0; i < target; ++i ) {
VkDescriptorImageInfo d = emptyTexture.descriptor;
if ( textures != graphic.material.textures.end() ) {
@ -558,27 +600,38 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
imageInfo = &((samplers++)->descriptor.info);
} break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
if ( buffersUniforms == shader.buffers.end() ) {
std::cout << "buffersUniforms == shader.buffers.end()" << std::endl;
if ( buffersUniforms == buffersUniformsVector.end() ) {
std::cout << "buffersUniforms == buffersUniformsVector.end()" << std::endl;
break;
}
auto* descriptor = &(*(buffersUniforms++));
if ( descriptor->offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) {
std::cout << __LINE__ << ": Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor->offset << std::endl;
descriptor->offset = 0;
}
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&((buffersUniforms++)->descriptor)
descriptor
));
} break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
if ( buffersStorage == graphic.buffers.end() ) {
std::cout << "buffersStorage == graphic.buffers.end()" << std::endl;
if ( buffersStorage == buffersStorageVector.end() ) {
std::cout << "buffersStorage == buffersStorageVector.end()" << std::endl;
break;
}
auto* descriptor = &(*(buffersStorage++));
if ( descriptor->offset % device->properties.limits.minStorageBufferOffsetAlignment != 0 ) {
std::cout << __LINE__ << ": Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor->offset << std::endl;
descriptor->offset = 0;
}
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&((buffersStorage++)->descriptor)
descriptor
));
} break;
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
@ -591,6 +644,16 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
}
if ( imageInfo ) {
if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || layout.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ) {
if ( imageInfo->imageView == VK_NULL_HANDLE ) {
imageInfo = &emptyTexture.descriptor;
}
}
if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || layout.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ) {
if ( imageInfo->sampler == VK_NULL_HANDLE ) {
imageInfo->sampler = emptyTexture.sampler.sampler;
}
}
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
@ -602,6 +665,22 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
}
}
for ( auto& descriptor : writeDescriptorSets ) {
if ( descriptor.pBufferInfo ) {
// std::cout << descriptor.pBufferInfo->offset << std::endl;
if ( descriptor.pBufferInfo->offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) {
// std::cout << "Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.pBufferInfo->offset << std::endl;
std::cout << "Invalid descriptor for buffer: " << descriptor.pBufferInfo->buffer << " " << descriptor.pBufferInfo->offset << " " << descriptor.pBufferInfo->range << ", invalidating..." << std::endl;
auto pointer = const_cast<VkDescriptorBufferInfo*>(descriptor.pBufferInfo);
pointer->offset = 0;
pointer->range = 0;
pointer->buffer = VK_NULL_HANDLE;
// const_cast<VkDescriptorBufferInfo*>(descriptor.pBufferInfo)->offset = 0;
}
}
}
vkUpdateDescriptorSets(
*device,
writeDescriptorSets.size(),
@ -667,10 +746,12 @@ void ext::vulkan::Graphic::initialize( const std::string& renderModeName ) {
RenderMode& renderMode = ext::vulkan::getRenderMode(renderModeName, true);
this->descriptor.renderMode = renderModeName;
auto* device = renderMode.device;
if ( !device ) device = &ext::vulkan::device;
material.initialize( *renderMode.device );
material.initialize( *device );
ext::vulkan::Buffers::initialize( *renderMode.device );
ext::vulkan::Buffers::initialize( *device );
}
void ext::vulkan::Graphic::initializePipeline() {
initializePipeline( this->descriptor, false );

View File

@ -80,14 +80,14 @@ void ext::vulkan::RenderMode::render() {
submitInfo.commandBufferCount = 1;
// Submit to the graphics queue passing a wait fence
VK_CHECK_RESULT(vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[currentBuffer]));
VK_CHECK_RESULT(vkQueueSubmit( device->getQueue( Device::QueueEnum::GRAPHICS ), 1, &submitInfo, fences[currentBuffer]));
//vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[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->queues.present, currentBuffer, renderCompleteSemaphore));
VK_CHECK_RESULT(vkQueueWaitIdle(device->queues.present));
VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( Device::QueueEnum::PRESENT ), currentBuffer, renderCompleteSemaphore));
VK_CHECK_RESULT(vkQueueWaitIdle(device->getQueue( Device::QueueEnum::PRESENT )));
}
void ext::vulkan::RenderMode::initialize( Device& device ) {
@ -105,7 +105,7 @@ void ext::vulkan::RenderMode::initialize( Device& device ) {
commands.resize( swapchain.buffers );
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo(
this->getType() == "Compute" ? device.commandPool.compute : device.commandPool.graphics,
this->getType() == "Compute" ? device.getCommandPool(Device::QueueEnum::COMPUTE) : device.getCommandPool(Device::QueueEnum::GRAPHICS),
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
static_cast<uint32_t>(commands.size())
);
@ -145,20 +145,23 @@ void ext::vulkan::RenderMode::destroy() {
renderTarget.destroy();
if ( commands.size() > 0 ) {
vkFreeCommandBuffers( *device, this->getType() == "Compute" ? device->commandPool.compute : device->commandPool.graphics, static_cast<uint32_t>(commands.size()), commands.data());
vkFreeCommandBuffers( *device, this->getType() == "Compute" ? device->getCommandPool(Device::QueueEnum::COMPUTE) : device->getCommandPool(Device::QueueEnum::GRAPHICS), static_cast<uint32_t>(commands.size()), commands.data());
}
commands.clear();
if ( renderCompleteSemaphore != VK_NULL_HANDLE ) {
vkDestroySemaphore( *device, renderCompleteSemaphore, nullptr);
renderCompleteSemaphore = VK_NULL_HANDLE;
}
for ( auto& fence : fences ) {
vkDestroyFence( *device, fence, nullptr);
fence = VK_NULL_HANDLE;
}
fences.clear();
}
void ext::vulkan::RenderMode::synchronize( uint64_t timeout ) {
if ( !device ) return;
if ( fences.empty() ) return;
VK_CHECK_RESULT(vkWaitForFences( *device, fences.size(), fences.data(), VK_TRUE, timeout ));
}
void ext::vulkan::RenderMode::pipelineBarrier( VkCommandBuffer command, uint8_t stage ) {

View File

@ -115,7 +115,7 @@ void ext::vulkan::ComputeRenderMode::render() {
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commands[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(device->queues.compute, 1, &submitInfo, fences[currentBuffer]));
VK_CHECK_RESULT(vkQueueSubmit(device->getQueue( Device::QueueEnum::COMPUTE ), 1, &submitInfo, fences[currentBuffer]));
//vkQueueSubmit(device->queues.compute, 1, &submitInfo, fences[currentBuffer]);
}
void ext::vulkan::ComputeRenderMode::tick() {

View File

@ -103,13 +103,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
{
auto& scene = uf::scene::getCurrentScene();
auto& metadata = scene.getComponent<uf::Serializer>();
/*
struct SpecializationConstant {
int32_t maxLights = 16;
};
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
specializationConstants.maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64();
*/
auto& shader = blitter.material.shaders.back();
struct SpecializationConstant {
uint32_t maxLights = 16;
@ -120,6 +114,41 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
if ( binding.descriptorCount > 1 )
binding.descriptorCount = specializationConstants->maxLights;
}
/*
std::vector<pod::Vector4f> palette;
// size of palette
if ( metadata["system"]["config"]["engine"]["scenes"]["palette"].isNumeric() ) {
size_t size = metadata["system"]["config"]["engine"]["scenes"]["palette"].asUInt64();
for ( size_t x = 0; x < size; ++x ) {
palette.push_back(pod::Vector4f{
(128.0f + 128.0f * sin(3.1415f * x / 16.0f)) / 256.0f,
(128.0f + 128.0f * sin(3.1415f * x / 32.0f)) / 256.0f,
(128.0f + 128.0f * sin(3.1415f * x / 64.0f)) / 256.0f,
1.0f,
});
}
// palette array
} else if ( metadata["system"]["config"]["engine"]["scenes"]["palette"].isArray() ) {
for ( int i = 0; i < metadata["system"]["config"]["engine"]["scenes"]["palette"].size(); ++i ) {
auto& color = palette.emplace_back();
palette.push_back(pod::Vector4f{
metadata["system"]["config"]["engine"]["scenes"]["palette"][i][0].asFloat(),
metadata["system"]["config"]["engine"]["scenes"]["palette"][i][1].asFloat(),
metadata["system"]["config"]["engine"]["scenes"]["palette"][i][2].asFloat(),
metadata["system"]["config"]["engine"]["scenes"]["palette"][i][3].asFloat(),
});
}
}
if ( !palette.empty() ) {
shader.initializeBuffer(
(void*) palette.data(),
palette.size() * sizeof(pod::Vector4f),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
true
);
}
*/
}
blitter.initializePipeline();
}
@ -133,6 +162,7 @@ void ext::vulkan::DeferredRenderMode::tick() {
if ( blitter.initialized ) {
auto& pipeline = blitter.getPipeline();
pipeline.update( blitter );
ext::vulkan::rebuild = true;
}
}
}

View File

@ -145,7 +145,7 @@ void ext::vulkan::RenderTargetRenderMode::render() {
submitInfo.pCommandBuffers = &commands[currentBuffer]; // Command buffers(s) to execute in this batch (submission)
submitInfo.commandBufferCount = 1;
VK_CHECK_RESULT(vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[currentBuffer]));
VK_CHECK_RESULT(vkQueueSubmit(device->getQueue( Device::QueueEnum::GRAPHICS ), 1, &submitInfo, fences[currentBuffer]));
//vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[currentBuffer]);
/*
VkSemaphoreWaitInfo waitInfo = {};

View File

@ -48,9 +48,21 @@ size_t ext::vulkan::RenderTarget::attach( VkFormat format, VkImageUsageFlags usa
aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}
VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
switch ( ext::vulkan::msaa ) {
case 64: samples = VK_SAMPLE_COUNT_64_BIT; break;
case 32: samples = VK_SAMPLE_COUNT_32_BIT; break;
case 16: samples = VK_SAMPLE_COUNT_16_BIT; break;
case 8: samples = VK_SAMPLE_COUNT_8_BIT; break;
case 4: samples = VK_SAMPLE_COUNT_4_BIT; break;
case 2: samples = VK_SAMPLE_COUNT_2_BIT; break;
default: samples = VK_SAMPLE_COUNT_1_BIT; break;
}
attachment->layout = layout;
attachment->format = format;
attachment->usage = usage;
attachment->samples = samples;
VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
@ -59,7 +71,7 @@ size_t ext::vulkan::RenderTarget::attach( VkFormat format, VkImageUsageFlags usa
imageCreateInfo.extent = { width, height, 1 };
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = USEVR ? 2 : 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.samples = samples;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = usage;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
@ -151,7 +163,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) {
for ( auto& attachment : this->attachments ) {
VkAttachmentDescription description;
description.format = attachment.format;
description.samples = VK_SAMPLE_COUNT_1_BIT;
description.samples = attachment.samples;
description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;

View File

@ -7,22 +7,29 @@ ext::vulkan::Texture2D ext::vulkan::Texture2D::empty;
void ext::vulkan::Sampler::initialize( Device& device ) {
this->device = &device;
if ( device.enabledFeatures.samplerAnisotropy == VK_FALSE ) {
descriptor.anisotropy.enabled = VK_FALSE;
}
{
VkSamplerCreateInfo samplerCreateInfo = {};
samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerCreateInfo.minFilter = descriptor.filter.min;
samplerCreateInfo.magFilter = descriptor.filter.mag;
samplerCreateInfo.borderColor = descriptor.filter.borderColor;
samplerCreateInfo.addressModeU = descriptor.addressMode.u;
samplerCreateInfo.addressModeV = descriptor.addressMode.v;
samplerCreateInfo.addressModeW = descriptor.addressMode.w;
samplerCreateInfo.unnormalizedCoordinates = descriptor.addressMode.unnormalizedCoordinates;
samplerCreateInfo.mipmapMode = descriptor.mip.mode;
samplerCreateInfo.mipLodBias = descriptor.mip.lodBias;
samplerCreateInfo.compareOp = descriptor.compareOp;
samplerCreateInfo.minLod = descriptor.lod.min;
samplerCreateInfo.maxLod = descriptor.lod.max;
samplerCreateInfo.maxAnisotropy = descriptor.maxAnisotropy;
samplerCreateInfo.compareEnable = descriptor.mip.compareEnable;
samplerCreateInfo.compareOp = descriptor.mip.compareOp;
samplerCreateInfo.minLod = descriptor.mip.min;
samplerCreateInfo.maxLod = descriptor.mip.max;
samplerCreateInfo.anisotropyEnable = descriptor.anisotropy.enabled;
samplerCreateInfo.maxAnisotropy = descriptor.anisotropy.max;
VK_CHECK_RESULT(vkCreateSampler(device.logicalDevice, &samplerCreateInfo, nullptr, &sampler));
}
{
@ -72,9 +79,7 @@ void ext::vulkan::Texture::setImageLayout(
VkImage image,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
VkImageSubresourceRange subresourceRange,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask
VkImageSubresourceRange subresourceRange
) {
// Create an image barrier object
VkImageMemoryBarrier imageMemoryBarrier = ext::vulkan::initializers::imageMemoryBarrier();
@ -83,6 +88,9 @@ void ext::vulkan::Texture::setImageLayout(
imageMemoryBarrier.image = image;
imageMemoryBarrier.subresourceRange = subresourceRange;
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
// Source layouts (old)
// Source access mask controls actions that have to be finished on the old layout
// before it will be transitioned to the new layout
@ -165,6 +173,20 @@ void ext::vulkan::Texture::setImageLayout(
break;
}
if ( oldImageLayout == VK_IMAGE_LAYOUT_UNDEFINED && newImageLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ) {
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
} else if ( oldImageLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
// Put barrier inside setup command buffer
vkCmdPipelineBarrier(
cmdbuffer,
@ -181,32 +203,29 @@ void ext::vulkan::Texture::setImageLayout(
VkImageAspectFlags aspectMask,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask
uint32_t mipLevels
) {
VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = aspectMask;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
subresourceRange.levelCount = mipLevels;
subresourceRange.layerCount = 1;
setImageLayout(cmdbuffer, image, oldImageLayout, newImageLayout, subresourceRange, srcStageMask, dstStageMask);
setImageLayout(cmdbuffer, image, oldImageLayout, newImageLayout, subresourceRange);
}
void ext::vulkan::Texture2D::loadFromFile(
std::string filename,
VkFormat format,
VkImageUsageFlags imageUsageFlags,
VkImageLayout imageLayout,
bool forceLinear
VkImageLayout imageLayout
) {
return loadFromFile( filename, ext::vulkan::device, format, imageUsageFlags, imageLayout, forceLinear );
return loadFromFile( filename, ext::vulkan::device, format, imageUsageFlags, imageLayout );
}
void ext::vulkan::Texture2D::loadFromFile(
std::string filename,
Device& device,
VkFormat format,
VkImageUsageFlags imageUsageFlags,
VkImageLayout imageLayout,
bool forceLinear
VkImageLayout imageLayout
) {
uf::Image image;
image.open( filename );
@ -281,18 +300,16 @@ void ext::vulkan::Texture2D::loadFromImage(
uf::Image& image,
VkFormat format,
VkImageUsageFlags imageUsageFlags,
VkImageLayout imageLayout,
bool forceLinear
VkImageLayout imageLayout
) {
return loadFromImage( image, ext::vulkan::device, format, imageUsageFlags, imageLayout, forceLinear );
return loadFromImage( image, ext::vulkan::device, format, imageUsageFlags, imageLayout );
}
void ext::vulkan::Texture2D::loadFromImage(
uf::Image& image,
Device& device,
VkFormat format,
VkImageUsageFlags imageUsageFlags,
VkImageLayout imageLayout,
bool forceLinear
VkImageLayout imageLayout
) {
switch ( image.getChannels() ) {
// R
@ -358,37 +375,12 @@ void ext::vulkan::Texture2D::fromBuffers(
VkImageLayout imageLayout
) {
this->initialize(device, texWidth, texHeight);
this->mips = 1;
// Use a separate command buffer for texture loading
VkCommandBuffer copyCmd = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
//
Buffer staging;
VK_CHECK_RESULT(device.createBuffer(
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
staging,
bufferSize,
data
));
VkBufferImageCopy bufferCopyRegion = {};
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
bufferCopyRegion.imageSubresource.mipLevel = 0;
bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
bufferCopyRegion.imageSubresource.layerCount = 1;
bufferCopyRegion.imageExtent.width = width;
bufferCopyRegion.imageExtent.height = height;
bufferCopyRegion.imageExtent.depth = 1;
bufferCopyRegion.bufferOffset = 0;
// Create optimal tiled target image
VkImageCreateInfo imageCreateInfo = ext::vulkan::initializers::imageCreateInfo();
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = format;
imageCreateInfo.mipLevels = this->mips;
imageCreateInfo.format = this->format = format;
imageCreateInfo.mipLevels = this->mips = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
@ -396,6 +388,10 @@ void ext::vulkan::Texture2D::fromBuffers(
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent = { width, height, 1 };
imageCreateInfo.usage = imageUsageFlags;
// Ensure that the TRANSFER_SRC bit is set for mip creation
if ( this->mips > 1 && !(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
// Ensure that the TRANSFER_DST bit is set for staging
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
@ -405,62 +401,19 @@ void ext::vulkan::Texture2D::fromBuffers(
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
VK_CHECK_RESULT(vmaCreateImage(allocator, &imageCreateInfo, &allocInfo, &image, &allocation, &allocationInfo));
deviceMemory = allocationInfo.deviceMemory;
/*
VK_CHECK_RESULT(vkCreateImage(device.logicalDevice, &imageCreateInfo, nullptr, &image));
VkMemoryAllocateInfo memAlloc = staging.memAlloc;
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device.logicalDevice, image, &memReqs);
memAlloc.allocationSize = staging.memReqs.size;
memAlloc.memoryTypeIndex = device.getMemoryType(staging.memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device.logicalDevice, &memAlloc, nullptr, &deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(device.logicalDevice, image, deviceMemory, 0));
*/
// Create sampler
sampler.descriptor.mip.min = 0;
sampler.descriptor.mip.max = static_cast<float>(this->mips);
sampler.initialize( device );
// Create image view
VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = this->mips;
subresourceRange.layerCount = 1;
// Image barrier for optimal image (target)
// Optimal image will be used as destination for the copy
setImageLayout(
copyCmd,
image,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
subresourceRange
);
// Copy mip levels from staging buffer
vkCmdCopyBufferToImage(
copyCmd,
staging.buffer,
image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&bufferCopyRegion
);
// Change texture image layout to shader read after all mip levels have been copied
this->imageLayout = imageLayout;
setImageLayout(
copyCmd,
image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
imageLayout,
subresourceRange
);
device.flushCommandBuffer(copyCmd);
// Clean up staging resources
/*
vkFreeMemory(device.logicalDevice, staging.memory, nullptr);
vkDestroyBuffer(device.logicalDevice, staging.buffer, nullptr);
*/
staging.destroy();
// Create sampler
sampler.initialize( device );
// Create image view
VkImageViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCreateInfo.pNext = NULL;
@ -471,7 +424,8 @@ void ext::vulkan::Texture2D::fromBuffers(
viewCreateInfo.subresourceRange.levelCount = 1;
viewCreateInfo.image = image;
VK_CHECK_RESULT(vkCreateImageView(device.logicalDevice, &viewCreateInfo, nullptr, &view));
// Update descriptor image info member that can be used for setting up descriptor sets
this->update( data, bufferSize, imageLayout );
this->updateDescriptors();
}
@ -505,14 +459,7 @@ void ext::vulkan::Texture2D::asRenderTarget( Device& device, uint32_t width, uin
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
VK_CHECK_RESULT(vmaCreateImage(allocator, &imageCreateInfo, &allocInfo, &image, &allocation, &allocationInfo));
deviceMemory = allocationInfo.deviceMemory;
/*
VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, &image));
vkGetImageMemoryRequirements(device, image, &memReqs);
memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = device.getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(device, image, deviceMemory, 0));
*/
VkCommandBuffer layoutCmd = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
imageLayout = VK_IMAGE_LAYOUT_GENERAL;
@ -521,7 +468,8 @@ void ext::vulkan::Texture2D::asRenderTarget( Device& device, uint32_t width, uin
image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
imageLayout
imageLayout,
this->mips
);
device.flushCommandBuffer(layoutCmd, true);
@ -551,4 +499,177 @@ void ext::vulkan::Texture2D::aliasAttachment( const RenderTarget::Attachment& at
if ( createSampler ) sampler.initialize( ext::vulkan::device );
this->updateDescriptors();
}
void ext::vulkan::Texture2D::update( uf::Image& image, VkImageLayout targetImageLayout ) {
if ( width != image.getDimensions()[0] || height != image.getDimensions()[1] )
return;
return this->update( (void*) image.getPixelsPtr(), image.getPixels().size() );
}
void ext::vulkan::Texture2D::update( void* data, VkDeviceSize bufferSize, VkImageLayout targetImageLayout ) {
// Update descriptor image info member that can be used for setting up descriptor sets
auto& device = *this->device;
if ( targetImageLayout == VK_IMAGE_LAYOUT_UNDEFINED ) {
targetImageLayout = this->imageLayout;
}
// Create image view
VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = this->mips;
subresourceRange.layerCount = 1;
VkBufferImageCopy bufferCopyRegion = {};
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
bufferCopyRegion.imageSubresource.mipLevel = 0;
bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
bufferCopyRegion.imageSubresource.layerCount = 1;
bufferCopyRegion.imageExtent.width = width;
bufferCopyRegion.imageExtent.height = height;
bufferCopyRegion.imageExtent.depth = 1;
bufferCopyRegion.bufferOffset = 0;
//
Buffer staging;
VK_CHECK_RESULT(device.createBuffer(
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
staging,
bufferSize,
data
));
// Use a separate command buffer for texture loading
VkCommandBuffer commandBuffer = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
// Image barrier for optimal image (target)
// Optimal image will be used as destination for the copy
setImageLayout(
commandBuffer,
image,
imageLayout,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
subresourceRange
);
// Copy mip levels from staging buffer
vkCmdCopyBufferToImage(
commandBuffer,
staging.buffer,
image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&bufferCopyRegion
);
this->generateMipmaps(commandBuffer);
setImageLayout(
commandBuffer,
image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
targetImageLayout,
subresourceRange
);
device.flushCommandBuffer(commandBuffer);
// Clean up staging resources
staging.destroy();
this->imageLayout = targetImageLayout;
this->updateDescriptors();
}
void ext::vulkan::Texture2D::generateMipmaps( VkCommandBuffer commandBuffer ) {
auto& device = *this->device;
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(device.physicalDevice, format, &formatProperties);
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
throw std::runtime_error("texture image format does not support linear blitting!");
}
// base layer barrier
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.image = image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.subresourceRange.levelCount = 1;
int32_t mipWidth = width;
int32_t mipHeight = height;
for ( size_t i = 1; i < this->mips; ++i ) {
// transition previous layer to read from it
barrier.subresourceRange.baseMipLevel = i - 1;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vkCmdPipelineBarrier(commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
0, nullptr,
0, nullptr,
1, &barrier
);
// blit to current mip layer
VkImageBlit blit{};
blit.srcOffsets[0] = { 0, 0, 0 };
blit.srcOffsets[1] = { mipWidth, mipHeight, 1 };
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.mipLevel = i - 1;
blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = 1;
blit.dstOffsets[0] = { 0, 0, 0 };
blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 };
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = i;
blit.dstSubresource.baseArrayLayer = 0;
blit.dstSubresource.layerCount = 1;
vkCmdBlitImage(
commandBuffer,
image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &blit,
VK_FILTER_LINEAR
);
// transition previous layer back
barrier.subresourceRange.baseMipLevel = i - 1;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vkCmdPipelineBarrier(commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
0, nullptr,
0, nullptr,
1, &barrier
);
if (mipWidth > 1) mipWidth /= 2;
if (mipHeight > 1) mipHeight /= 2;
}
/*
barrier.subresourceRange.baseMipLevel = this->mips - 1;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
0, nullptr,
0, nullptr,
1, &barrier
);
*/
}

View File

@ -10,8 +10,11 @@
uint32_t ext::vulkan::width = 1280;
uint32_t ext::vulkan::height = 720;
uint8_t ext::vulkan::msaa = 1;
bool ext::vulkan::validation = true;
bool ext::vulkan::rebuildOnTickStart = false;
bool ext::vulkan::waitOnRenderEnd = false;
std::vector<std::string> ext::vulkan::validationFilters;
std::vector<std::string> ext::vulkan::requestedDeviceFeatures;
std::vector<std::string> ext::vulkan::requestedDeviceExtensions;
@ -49,7 +52,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL ext::vulkan::debugCallback(
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData
) {
if ( messageSeverity <= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT ) return VK_FALSE;
// if ( messageSeverity <= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT ) return VK_FALSE;
std::string message = pCallbackData->pMessage;
for ( auto& filter : ext::vulkan::validationFilters ) {
if ( message.find(filter) != std::string::npos ) return VK_FALSE;
@ -276,15 +279,14 @@ void ext::vulkan::initialize( uint8_t stage ) {
}
void ext::vulkan::tick() {
ext::vulkan::mutex.lock();
if ( ext::vulkan::resized ) ext::vulkan::rebuild = true;
if ( ext::vulkan::resized || ext::vulkan::rebuildOnTickStart ) {
ext::vulkan::rebuild = true;
}
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Graphic>() ) return;
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
if ( graphic.initialized ) return;
if ( !graphic.process ) return;
if ( graphic.initialized ) return;
if ( graphic.initialized || !graphic.process || graphic.initialized ) return;
graphic.initializePipeline();
ext::vulkan::rebuild = true;
};
@ -310,7 +312,7 @@ void ext::vulkan::tick() {
ext::vulkan::mutex.unlock();
}
void ext::vulkan::render() {
// ext::vulkan::mutex.lock();
ext::vulkan::mutex.lock();
if ( hasRenderMode("Gui", true) ) {
RenderMode& primary = getRenderMode("Gui", true);
auto it = std::find( renderModes.begin(), renderModes.end(), &primary );
@ -331,7 +333,15 @@ void ext::vulkan::render() {
}
ext::vulkan::currentRenderMode = NULL;
// ext::vulkan::mutex.unlock();
if ( ext::vulkan::waitOnRenderEnd ) {
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
if ( !renderMode->execute ) continue;
renderMode->synchronize();
}
vkDeviceWaitIdle( device );
}
ext::vulkan::mutex.unlock();
}
void ext::vulkan::destroy() {
ext::vulkan::mutex.lock();

View File

@ -60,10 +60,10 @@ void uf::Atlas::generate() {
auto& dstBuffer = this->m_image.getPixels();
for ( size_t i = 0; i < size.x * size.y * 4; i+=4 ) {
dstBuffer[i+0] = 255;
dstBuffer[i+0] = 0;
dstBuffer[i+1] = 0;
dstBuffer[i+2] = 255;
dstBuffer[i+3] = 255;
dstBuffer[i+2] = 0;
dstBuffer[i+3] = 0;
}
for ( auto& it : stored.Get() ) {
@ -84,6 +84,11 @@ void uf::Atlas::generate() {
}
}
}
void uf::Atlas::clear() {
this->m_images.clear();
this->m_image.clear();
this->m_atlas = uf::Atlas::atlas_t{};
}
pod::Vector2f uf::Atlas::mapUv( const pod::Vector2f& uv, size_t index ) {
BinPack2D::ContentAccumulator<uf::Atlas::identifier_t> stored;
this->m_atlas.CollectContent( stored );

View File

@ -1,5 +1,9 @@
#include <uf/utils/string/ext.h>
#include <algorithm>
#include <bitset>
#include <iomanip>
#include <sstream>
#include <cmath>
std::string UF_API uf::string::lowercase( const std::string& str ) {
std::string lower = str;
@ -27,4 +31,73 @@ std::string UF_API uf::string::replace( const std::string& string, const std::st
if( start_pos == std::string::npos ) return result;
result.replace(start_pos, search.length(), replace);
return result;
}
std::string UF_API uf::string::si( double value, const std::string& unit, size_t precision ) {
int power = floor(std::log10( value ));
double base = value / std::pow( 10, power );
// std::cout << base << " x 10^" << power << " -> ";
size_t pValue = -1;
#define REDUCE(VAL)\
while ( pValue > power && power > VAL ) {\
--power;\
base *= 10;\
}\
pValue = VAL;
#define INCREASE(VAL)\
if ( pValue < power && power < VAL ) std::cout << " (increasing (" << pValue << ", " << VAL << ")) ";\
while ( pValue < power && power < VAL ) {\
++power;\
base /= 10;\
}\
pValue = VAL;
REDUCE(24)
REDUCE(21)
REDUCE(18)
REDUCE(15)
REDUCE(12)
REDUCE( 9)
REDUCE( 6)
REDUCE( 3)
// REDUCE( 2)
// REDUCE( 1)
REDUCE( 0)
/*
// INCREASE(-1)
INCREASE(-2)
INCREASE(-3)
INCREASE(-6)
INCREASE(-9)
INCREASE(-12)
*/
// std::cout << base << " x 10^" << power << std::endl;
std::stringstream ss;
ss << std::fixed << std::setprecision(precision) << base;
std::string string = ss.str();
switch ( power ) {
case 24: string += "Y"; break;
case 21: string += "Z"; break;
case 18: string += "E"; break;
case 15: string += "P"; break;
case 12: string += "T"; break;
case 9: string += "G"; break;
case 6: string += "M"; break;
case 3: string += "k"; break;
// case 2: string += "h"; break;
// case 1: string += "da"; break;
case 0: string += ""; break;
// case -1: string += "d"; break;
case -2: string += "c"; break;
case -3: string += "m"; break;
case -6: string += "μ"; break;
case -9: string += "n"; break;
case-12: string += "p"; break;
}
string += unit;
return string;
}

View File

@ -172,6 +172,7 @@ void ext::LightBehavior::destroy( uf::Object& self ){
if ( this->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
uf::renderer::removeRenderMode( &renderMode, false );
this->deleteComponent<uf::renderer::RenderTargetRenderMode>();
}
}
#undef this

View File

@ -158,5 +158,6 @@ void ext::PortalBehavior::render( uf::Object& self ){
void ext::PortalBehavior::destroy( uf::Object& self ){
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
uf::renderer::removeRenderMode( &renderMode, false );
this->deleteComponent<uf::renderer::RenderTargetRenderMode>();
}
#undef this

View File

@ -85,7 +85,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
timer.reset();
uf::Serializer json = event;
uf::Object* manager = (uf::Object*) this->findByName("Gui Manager");
uf::Object* manager = (uf::Object*) this->globalFindByName("Gui Manager");
if ( !manager ) return "false";
uf::Serializer payload;
// uf::Object* gui = (uf::Object*) manager->findByUid( (payload["uid"] = manager->loadChildUid("/scenes/worldscape/gui/pause/menu.json", false)).asUInt64() );
@ -109,8 +109,10 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
return "true";
});
/* store viewport size */ {
metadata["window"]["size"]["x"] = uf::renderer::width;
metadata["window"]["size"]["y"] = uf::renderer::height;
metadata["system"]["window"]["size"]["x"] = uf::renderer::width;
metadata["system"]["window"]["size"]["y"] = uf::renderer::height;
ext::gui::size.current.x = uf::renderer::width;
ext::gui::size.current.y = uf::renderer::height;
this->addHook( "window:Resized", [&](const std::string& event)->std::string{
uf::Serializer json = event;
@ -120,7 +122,8 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
size.y = json["window"]["size"]["y"].asUInt64();
}
metadata["window"] = json["window"];
metadata["system"]["window"] = json["system"]["window"];
ext::gui::size.current = size;
return "true";
});
@ -160,7 +163,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
}
/* Regain control if nothing requests it */ {
uf::Object* menu = (uf::Object*) this->findByName("Gui: Menu");
uf::Object* menu = (uf::Object*) this->globalFindByName("Gui: Menu");
if ( !menu ) {
uf::Serializer payload;
payload["state"] = false;
@ -245,17 +248,20 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
alignas(16) pod::Vector4f ambient;
struct Mode {
alignas(8) pod::Vector2ui type;
alignas(8) pod::Vector2ui padding;
alignas(16) pod::Vector4f parameters;
} mode;
struct {
alignas(8) pod::Vector2f range;
alignas(16) pod::Vector4f color;
alignas(8) pod::Vector2f range;
alignas(8) pod::Vector2f padding;
} fog;
struct Light {
alignas(16) pod::Vector4f position;
alignas(16) pod::Vector4f color;
alignas(4) uint32_t type;
alignas(4) float depthBias;
alignas(8) pod::Vector2f padding;
alignas(16) pod::Matrix4f view;
alignas(16) pod::Matrix4f projection;
} lights;

View File

@ -4,15 +4,15 @@
#include <uf/utils/audio/audio.h>
#include <uf/utils/math/transform.h>
#include <uf/utils/string/ext.h>
#include <uf/engine/asset/asset.h>
#include <mutex>
EXT_BEHAVIOR_REGISTER_CPP(StaticEmitterBehavior)
#define this ((uf::Scene*) &self)
#define this ((uf::Object*) &self)
void ext::StaticEmitterBehavior::initialize( uf::Object& self ) {
auto& metadata = this->getComponent<uf::Serializer>();
auto* hud = this->loadChildPointer("/hud.json", true);
metadata["hud"]["uid"] = hud->getUid();
}
void ext::StaticEmitterBehavior::tick( uf::Object& self ) {
auto& scene = uf::scene::getCurrentScene();
@ -37,9 +37,7 @@ void ext::StaticEmitterBehavior::tick( uf::Object& self ) {
float pieces = metadata["static"]["pieces"].isNumeric() ? metadata["static"]["pieces"].asFloat() : 1000;
uint32_t mode = sMetadata["system"]["renderer"]["shader"]["mode"].asUInt();
if ( !(mode & 0x2) ) {
mode = mode | 0x2;
}
mode |= (0x1 << 1);
sMetadata["system"]["renderer"]["shader"]["mode"] = mode;
sMetadata["system"]["renderer"]["shader"]["parameters"][0] = flicker;
@ -47,6 +45,22 @@ void ext::StaticEmitterBehavior::tick( uf::Object& self ) {
sMetadata["system"]["renderer"]["shader"]["parameters"][2] = staticBlend;
sMetadata["system"]["renderer"]["shader"]["parameters"][3] = "time";
}
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
if ( metadata["hud"]["uid"].isNumeric() && timer.elapsed().asDouble() > 0.125 ) {
timer.reset();
auto* hud = this->findByUid( metadata["hud"]["uid"].asUInt64() );
auto& hMetadata = hud->getComponent<uf::Serializer>();
double d = uf::vector::distance( cTransform.position, transform.position );
std::string string = uf::string::si( d, "m" );
hMetadata["text settings"]["alpha"] = 0.5f;
if ( hMetadata["text settings"]["string"].asString() != string ) {
uf::Serializer payload;
payload["string"] = string;
hud->as<uf::Object>().callHook("gui:UpdateString.%UID%", payload);
}
}
}
void ext::StaticEmitterBehavior::render( uf::Object& self ){}

File diff suppressed because it is too large Load Diff

View File

@ -4,14 +4,35 @@
#include <uf/ext/ext.h>
#include <uf/engine/entity/entity.h>
#include <uf/engine/scene/scene.h>
#include <uf/utils/math/vector.h>
#include <uf/utils/renderer/renderer.h>
#include "behavior.h"
namespace pod {
struct GlyphBox {
struct {
float x, y, w, h;
} box;
uint64_t code;
pod::Vector3f color;
};
}
namespace ext {
class EXT_API Gui : public uf::Object {
public:
Gui() {
this->addBehavior<ext::GuiBehavior>();
}
typedef uf::BaseMesh<pod::Vertex_3F2F3F> glyph_mesh_t;
Gui();
std::vector<pod::GlyphBox> generateGlyphs( const std::string& = "" );
void load( uf::Image& );
};
namespace gui {
struct Size {
pod::Vector2ui current = {};
pod::Vector2ui reference = {};
};
extern Size size;
}
}

View File

@ -0,0 +1,204 @@
#include "behavior.h"
#include "../gui.h"
#include <uf/utils/hook/hook.h>
#include <uf/utils/time/time.h>
#include <uf/utils/serialize/serializer.h>
#include <uf/utils/userdata/userdata.h>
#include <uf/utils/window/window.h>
#include <uf/utils/camera/camera.h>
#include <uf/utils/graphic/mesh.h>
#include <uf/utils/graphic/graphic.h>
#include <uf/utils/string/ext.h>
#include <uf/utils/math/physics.h>
#include <uf/utils/text/glyph.h>
#include <uf/engine/asset/asset.h>
#include <uf/engine/scene/scene.h>
#include <unordered_map>
#include <locale>
#include <codecvt>
#include <uf/utils/renderer/renderer.h>
#include <uf/ext/openvr/openvr.h>
#include <uf/utils/http/http.h>
#include <uf/utils/audio/audio.h>
#include <sys/stat.h>
#include <fstream>
#include <regex>
ext::gui::Size ext::gui::size = {
.current = {
uf::renderer::width,
uf::renderer::height,
},
.reference = {
1920,
1080
},
};
EXT_BEHAVIOR_REGISTER_CPP(GuiManagerBehavior)
EXT_BEHAVIOR_REGISTER_AS_OBJECT(GuiManagerBehavior, GuiManager)
#define this (&self)
void ext::GuiManagerBehavior::initialize( uf::Object& self ) {
{
ext::gui::size.current.x = uf::renderer::width;
ext::gui::size.current.y = uf::renderer::height;
}
// add gui render mode
if ( !uf::renderer::hasRenderMode( "Gui", true ) ) {
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
std::string name = "Gui";
uf::renderer::addRenderMode( &renderMode, name );
renderMode.blitter.descriptor.subpass = 1;
}
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
uf::Asset& assetLoader = this->getComponent<uf::Asset>();
this->addHook( "window:Resized", [&](const std::string& event)->std::string{
uf::Serializer json = event;
pod::Vector2ui size; {
size.x = json["window"]["size"]["x"].asUInt64();
size.y = json["window"]["size"]["y"].asUInt64();
}
ext::gui::size.current = size;
// ext::gui::size.reference = size;
return "true";
} );
this->addHook( "window:Mouse.Moved", [&](const std::string& event)->std::string{
uf::Serializer json = event;
bool down = json["mouse"]["state"].asString() == "Down";
bool clicked = false;
pod::Vector2ui position; {
position.x = json["mouse"]["position"]["x"].asInt() > 0 ? json["mouse"]["position"]["x"].asUInt() : 0;
position.y = json["mouse"]["position"]["y"].asInt() > 0 ? json["mouse"]["position"]["y"].asUInt() : 0;
}
pod::Vector2f click; {
click.x = (float) position.x / (float) ext::gui::size.current.x;
click.y = (float) position.y / (float) ext::gui::size.current.y;
click.x = (click.x * 2.0f) - 1.0f;
click.y = (click.y * 2.0f) - 1.0f;
float x = click.x;
float y = click.y;
}
{
auto& scene = uf::scene::getCurrentScene();
auto& controller = scene.getController();
auto& metadata = controller.getComponent<uf::Serializer>();
if ( metadata["overlay"]["cursor"]["type"].asString() == "mouse" ) {
metadata["overlay"]["cursor"]["position"][0] = click.x;
metadata["overlay"]["cursor"]["position"][1] = click.y;
}
}
return "true";
});
}
void ext::GuiManagerBehavior::tick( uf::Object& self ) {
}
void ext::GuiManagerBehavior::render( uf::Object& self ){
auto& scene = uf::scene::getCurrentScene();
auto& controller = scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
auto& metadata = controller.getComponent<uf::Serializer>();
uf::renderer::RenderTargetRenderMode* renderModePointer = NULL;
if ( this->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {
renderModePointer = this->getComponentPointer<uf::renderer::RenderTargetRenderMode>();
} else {
renderModePointer = (uf::renderer::RenderTargetRenderMode*) &uf::renderer::getRenderMode( "Gui", true );
}
auto& renderMode = *renderModePointer;
auto& blitter = renderMode.blitter;
struct UniformDescriptor {
struct {
alignas(16) pod::Matrix4f models[2];
} matrices;
struct {
alignas(8) pod::Vector2f position = { 0.5f, 0.5f };
alignas(8) pod::Vector2f radius = { 0.1f, 0.1f };
alignas(16) pod::Vector4f color = { 1, 1, 1, 1 };
} cursor;
// alignas(8) pod::Vector2f alpha;
};
auto& shader = blitter.material.shaders.front();
auto& uniforms = shader.uniforms.front().get<UniformDescriptor>();
for ( size_t i = 0; i < 2; ++i ) {
pod::Transform<> transform;
if ( metadata["overlay"]["position"].isArray() )
transform.position = {
metadata["overlay"]["position"][0].asFloat(),
metadata["overlay"]["position"][1].asFloat(),
metadata["overlay"]["position"][2].asFloat(),
};
if ( metadata["overlay"]["scale"].isArray() )
transform.scale = {
metadata["overlay"]["scale"][0].asFloat(),
metadata["overlay"]["scale"][1].asFloat(),
metadata["overlay"]["scale"][2].asFloat(),
};
if ( metadata["overlay"]["orientation"].isArray() )
transform.orientation = {
metadata["overlay"]["orientation"][0].asFloat(),
metadata["overlay"]["orientation"][1].asFloat(),
metadata["overlay"]["orientation"][2].asFloat(),
metadata["overlay"]["orientation"][3].asFloat(),
};
if ( ext::openvr::enabled && (metadata["overlay"]["enabled"].asBool() || uf::renderer::getRenderMode("Stereoscopic Deferred", true).getType() == "Stereoscopic Deferred" )) {
if ( metadata["overlay"]["floating"].asBool() ) {
pod::Matrix4f model = uf::transform::model( transform );
uniforms.matrices.models[i] = camera.getProjection(i) * ext::openvr::hmdEyePositionMatrix( i == 0 ? vr::Eye_Left : vr::Eye_Right ) * model;
} else {
auto translation = uf::matrix::translate( uf::matrix::identity(), camera.getTransform().position + controller.getComponent<pod::Transform<>>().position );
auto rotation = uf::quaternion::matrix( controller.getComponent<pod::Transform<>>().orientation * pod::Vector4f{1,1,1,-1} );
pod::Matrix4f model = translation * rotation * uf::transform::model( transform );
uniforms.matrices.models[i] = camera.getProjection(i) * camera.getView(i) * model;
}
} else {
pod::Matrix4t<> model = uf::matrix::translate( uf::matrix::identity(), { 0, 0, 1 } );
uniforms.matrices.models[i] = model;
}
// uniforms.alpha.x = metadata["overlay"]["alpha"].asFloat();
// uniforms.alpha.y = 0;
uniforms.cursor.position.x = (metadata["overlay"]["cursor"]["position"][0].asFloat() + 1.0f) * 0.5f; //(::mouse.position.x + 1.0f) * 0.5f;
uniforms.cursor.position.y = (metadata["overlay"]["cursor"]["position"][1].asFloat() + 1.0f) * 0.5f; //(::mouse.position.y + 1.0f) * 0.5f;
pod::Vector3f cursorSize;
cursorSize.x = metadata["overlay"]["cursor"]["radius"].asFloat();
cursorSize.y = metadata["overlay"]["cursor"]["radius"].asFloat();
cursorSize = uf::matrix::multiply<float>( uf::matrix::inverse( uf::matrix::scale( uf::matrix::identity() , transform.scale) ), cursorSize );
uniforms.cursor.radius.x = cursorSize.x;
uniforms.cursor.radius.y = cursorSize.y;
uniforms.cursor.color.x = metadata["overlay"]["cursor"]["color"][0].asFloat();
uniforms.cursor.color.y = metadata["overlay"]["cursor"]["color"][1].asFloat();
uniforms.cursor.color.z = metadata["overlay"]["cursor"]["color"][2].asFloat();
uniforms.cursor.color.w = metadata["overlay"]["cursor"]["color"][3].asFloat();
}
shader.updateBuffer( (void*) &uniforms, sizeof(uniforms), 0 );
}
void ext::GuiManagerBehavior::destroy( uf::Object& self ){
if ( this->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
uf::renderer::removeRenderMode( &renderMode, false );
this->deleteComponent<uf::renderer::RenderTargetRenderMode>();
}
}
#undef this

View File

@ -0,0 +1,17 @@
#pragma once
#include <uf/config.h>
#include <uf/ext/ext.h>
#include <uf/engine/entity/entity.h>
#include <uf/engine/scene/scene.h>
namespace ext {
class EXT_API GuiManagerBehavior {
public:
static void attach( uf::Object& );
static void initialize( uf::Object& );
static void tick( uf::Object& );
static void render( uf::Object& );
static void destroy( uf::Object& );
};
}

View File

@ -64,9 +64,38 @@ namespace {
uf::Serializer config;
}
bool ext::ready = false;
std::vector<std::string> ext::arguments;
void EXT_API ext::initialize() {
/**/ {
::config = ext::getConfig();
/* Arguments */ {
auto& arguments = ::config["arguments"];
for ( auto& arg : ext::arguments ) {
// store raw argument
int i = arguments.size();
arguments[i] = arg;
// parse --key=value
{
std::regex regex("^--(.+?)=(.+?)$");
std::smatch match;
if ( std::regex_search( arg, match, regex ) ) {
std::string keyString = match[1].str();
std::string valueString = match[2].str();
auto keys = uf::string::split(keyString, ".");
uf::Serializer value; value.deserialize(valueString);
Json::Value* traversal = &::config;
for ( auto& key : keys ) {
traversal = &((*traversal)[key]);
}
*traversal = value;
}
}
}
uf::iostream << "Arguments: " << uf::Serializer(arguments) << "\n";
uf::iostream << "New config: " << ::config << "\n";
}
/* Seed */ {
srand(time(NULL));
}
/* Open output file */ {
@ -84,7 +113,6 @@ void EXT_API ext::initialize() {
// #include "./inits/persistence.inl"
}
::config = ext::getConfig();
/* Parse config */ {
// Set memory pool sizes
{
@ -153,6 +181,11 @@ void EXT_API ext::initialize() {
uf::thread::workers = ::config["engine"]["threads"]["workers"].asUInt64();
// Enable valiation layer
uf::renderer::validation = ::config["engine"]["ext"]["vulkan"]["validation"]["enabled"].asBool();
if ( ::config["engine"]["ext"]["vulkan"]["validation"]["enabled"].isNumeric() )
uf::renderer::msaa = ::config["engine"]["ext"]["vulkan"]["msaa"].asUInt64();
uf::renderer::rebuildOnTickStart = ::config["engine"]["ext"]["vulkan"]["validation"]["rebuild on tick begin"].asBool();
uf::renderer::waitOnRenderEnd = ::config["engine"]["ext"]["vulkan"]["validation"]["wait on render end"].asBool();
for ( int i = 0; i < ::config["engine"]["ext"]["vulkan"]["validation"]["filters"].size(); ++i ) {
uf::renderer::validationFilters.push_back( ::config["engine"]["ext"]["vulkan"]["validation"]["filters"][i].asString() );
@ -196,7 +229,6 @@ void EXT_API ext::initialize() {
uf::renderer::addRenderMode( renderMode, "Gui" );
renderMode->blitter.descriptor.subpass = 1;
}
if ( ::config["engine"]["render modes"]["stereo deferred"].asBool() )
uf::renderer::addRenderMode( new uf::renderer::StereoscopicDeferredRenderMode, "" );
else if ( ::config["engine"]["render modes"]["deferred"].asBool() )
@ -240,6 +272,9 @@ void EXT_API ext::initialize() {
/* Add hooks */ {
uf::hooks.addHook( "game:LoadScene", [&](const std::string& event)->std::string{
uf::Serializer json = event;
std::cout << "SCENE CHANGE: " << event << std::endl;
uf::renderer::mutex.lock();
uf::renderer::mutex.unlock();
uf::scene::unloadScene();
auto& scene = uf::scene::loadScene( json["scene"].asString() );
auto& metadata = scene.getComponent<uf::Serializer>();

View File

@ -68,7 +68,7 @@ void ext::RayTracingSceneBehavior::initialize( uf::Object& self ) {
renderMode.compute.initializeBuffer(
(void*) shapes.data(),
shapes.size() * sizeof(Shape),
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
true
);

View File

@ -74,7 +74,7 @@ void ext::WorldScapeSceneBehavior::initialize( uf::Object& self ) {
this->addHook( "world:Battle.Start", [&](const std::string& event)->std::string{
if ( timer.elapsed().asDouble() < 1 ) return "false";
timer.reset();
uf::Object* guiManager = (uf::Object*) this->findByName("Gui Manager");
uf::Object* guiManager = (uf::Object*) this->globalFindByName("Gui Manager");
if ( !guiManager ) return "false";
uf::Serializer json = event;
@ -88,7 +88,7 @@ void ext::WorldScapeSceneBehavior::initialize( uf::Object& self ) {
});
this->addHook( "world:Battle.End", [&](const std::string& event)->std::string{
uf::Serializer json = event;
ext::HousamoBattle* battleManager = (ext::HousamoBattle*) this->findByName("Battle Manager");
ext::HousamoBattle* battleManager = (ext::HousamoBattle*) this->globalFindByName("Battle Manager");
if ( !battleManager ) return "false";
this->removeChild(*battleManager);
@ -100,7 +100,7 @@ void ext::WorldScapeSceneBehavior::initialize( uf::Object& self ) {
this->addHook( "menu:Dialogue.Start", [&](const std::string& event)->std::string{
if ( timer.elapsed().asDouble() < 1 ) return "false";
timer.reset();
uf::Object* guiManager = (uf::Object*) this->findByName("Gui Manager");
uf::Object* guiManager = (uf::Object*) this->globalFindByName("Gui Manager");
if ( !guiManager ) return "false";
uf::Serializer json = event;
@ -112,7 +112,7 @@ void ext::WorldScapeSceneBehavior::initialize( uf::Object& self ) {
});
this->addHook( "menu:Dialogue.End", [&](const std::string& event)->std::string{
uf::Serializer json = event;
ext::DialogueManager* dialogueManager = (ext::DialogueManager*) this->findByName("Dialogue Manager");
ext::DialogueManager* dialogueManager = (ext::DialogueManager*) this->globalFindByName("Dialogue Manager");
if ( !dialogueManager ) return "false";
this->removeChild(*dialogueManager);

View File

@ -206,37 +206,37 @@ void ext::GuiBattle::initialize() {
{
battleMessage = new ext::Gui;
this->addChild(*battleMessage);
battleMessage->load("./battle-text.json", true);
battleMessage->as<uf::Object>().load("./battle-text.json", true);
battleMessage->initialize();
}
/* Magic Circle Outter */ {
circleOut = new ext::Gui;
this->addChild(*circleOut);
circleOut->load("./circle-out.json", true);
circleOut->as<uf::Object>().load("./circle-out.json", true);
circleOut->initialize();
}
/* Magic Circle Inner */ {
circleIn = new ext::Gui;
this->addChild(*circleIn);
circleIn->load("./circle-in.json", true);
circleIn->as<uf::Object>().load("./circle-in.json", true);
circleIn->initialize();
}
/* Command Circle */ {
partyMemberCommandCircle = new ext::Gui;
this->addChild(*partyMemberCommandCircle);
partyMemberCommandCircle->load("./partyMemberCommandCircle.json", true);
partyMemberCommandCircle->as<uf::Object>().load("./partyMemberCommandCircle.json", true);
partyMemberCommandCircle->initialize();
}
/* Command Circle */ {
optionsBackground = new ext::Gui;
this->addChild(*optionsBackground);
optionsBackground->load("./optionsBackground.json", true);
optionsBackground->as<uf::Object>().load("./optionsBackground.json", true);
optionsBackground->initialize();
}
/* Turn Counter Container */ {
turnCounters = new ext::Gui;
this->addChild(*turnCounters);
turnCounters->load("./turnCounters.json", true);
turnCounters->as<uf::Object>().load("./turnCounters.json", true);
turnCounters->initialize();
}
@ -277,7 +277,7 @@ void ext::GuiBattle::initialize() {
ext::Gui* particle = new ext::Gui;
this->addChild(*particle);
uf::Serializer& pMetadata = particle->getComponent<uf::Serializer>();
particle->load("./damageText.json", true);
particle->as<uf::Object>().load("./damageText.json", true);
std::string color = json["color"].isString() ? json["color"].asString() : "FF0000";
pMetadata["text settings"]["string"] = "%#"+color+"%" + damage;
pod::Transform<>& transform = particle->getComponent<pod::Transform<>>();
@ -300,7 +300,7 @@ void ext::GuiBattle::initialize() {
battleMessage = new ext::Gui;
this->addChild(*battleMessage);
uf::Serializer& pMetadata = battleMessage->getComponent<uf::Serializer>();
battleMessage->load("./battle-text.json", true);
battleMessage->as<uf::Object>().load("./battle-text.json", true);
pMetadata["text settings"]["string"] = message;
battleMessage->initialize();
@ -340,7 +340,7 @@ void ext::GuiBattle::initialize() {
{
critCutInBackground = new ext::Gui;
this->addChild(*critCutInBackground);
critCutInBackground->load("./critCutInBackground.json", true);
critCutInBackground->as<uf::Object>().load("./critCutInBackground.json", true);
critCutInBackground->initialize();
}
{
@ -351,7 +351,7 @@ void ext::GuiBattle::initialize() {
uf::Serializer cardData = masterDataGet("Card", json["id"].asString());
pMetadata["system"]["assets"][0] = "/smtsamo/ci/ci_"+ cardData["filename"].asString() +".png";
if ( !uf::io::exists( pMetadata["system"]["assets"][0].asString() ) ) pMetadata["system"]["assets"][0] = Json::nullValue;
critCutIn->load("./critCutIn.json", true);
critCutIn->as<uf::Object>().load("./critCutIn.json", true);
critCutIn->initialize();
}
@ -373,7 +373,7 @@ void ext::GuiBattle::initialize() {
{
turnCounters = new ext::Gui;
this->addChild(*turnCounters);
turnCounters->load("./turnCounters.json", true);
turnCounters->as<uf::Object>().load("./turnCounters.json", true);
turnCounters->initialize();
}
// show full counters
@ -381,7 +381,7 @@ void ext::GuiBattle::initialize() {
while ( turns > 0 ) {
ext::Gui* counter = new ext::Gui;
turnCounters->addChild(*counter);
counter->load("./turnCounter.json", true);
counter->as<uf::Object>().load("./turnCounter.json", true);
counter->initialize();
pod::Transform<>& pTransform = counter->getComponent<pod::Transform<>>();
pTransform.position.x -= 0.142716f * (i++);
@ -465,7 +465,7 @@ void ext::GuiBattle::initialize() {
partyMemberText = new ext::Gui;
partyMemberButton->addChild(*partyMemberText);
uf::Serializer& pMetadata = partyMemberText->getComponent<uf::Serializer>();
partyMemberText->load("./partyMemberText.json", true);
partyMemberText->as<uf::Object>().load("./partyMemberText.json", true);
pMetadata["text settings"]["string"] = "" + colorString("00FF00") + "" + member["hp"].asString() + "\n" + colorString("0000FF") + "" + member["mp"].asString();
pMetadata[""] = member;
pod::Transform<>& transform = partyMemberText->getComponent<pod::Transform<>>();
@ -499,7 +499,7 @@ void ext::GuiBattle::initialize() {
{
partyMemberButton = new ext::Gui;
this->addChild(*partyMemberButton);
partyMemberButton->load("./partyMemberButton.json", true);
partyMemberButton->as<uf::Object>().load("./partyMemberButton.json", true);
pod::Transform<>& transform = partyMemberButton->getComponent<pod::Transform<>>();
transform.position.y += (i * 0.45);
@ -518,7 +518,7 @@ void ext::GuiBattle::initialize() {
partyMemberButton->addChild(*partyMemberIconShadow);
uf::Serializer& pMetadata = partyMemberIconShadow->getComponent<uf::Serializer>();
pMetadata["system"]["assets"][0] = filename;
partyMemberIconShadow->load("./partyMemberIconShadow.json", true);
partyMemberIconShadow->as<uf::Object>().load("./partyMemberIconShadow.json", true);
pMetadata[""] = member;
pod::Transform<>& transform = partyMemberIconShadow->getComponent<pod::Transform<>>();
transform.position = bTransform.position;
@ -532,7 +532,7 @@ void ext::GuiBattle::initialize() {
partyMemberButton->addChild(*partyMemberIcon);
uf::Serializer& pMetadata = partyMemberIcon->getComponent<uf::Serializer>();
pMetadata["system"]["assets"][0] = filename;
partyMemberIcon->load("./partyMemberIcon.json", true);
partyMemberIcon->as<uf::Object>().load("./partyMemberIcon.json", true);
pMetadata[""] = member;
pod::Transform<>& transform = partyMemberIcon->getComponent<pod::Transform<>>();
transform.position = bTransform.position;
@ -544,7 +544,7 @@ void ext::GuiBattle::initialize() {
partyMemberText = new ext::Gui;
partyMemberButton->addChild(*partyMemberText);
uf::Serializer& pMetadata = partyMemberText->getComponent<uf::Serializer>();
partyMemberText->load("./partyMemberText.json", true);
partyMemberText->as<uf::Object>().load("./partyMemberText.json", true);
pMetadata["text settings"]["string"] = "" + colorString("FF0000") + "" + member["hp"].asString() + "\n" + colorString("0000FF") + "" + member["mp"].asString();
pMetadata[""] = member;
pod::Transform<>& transform = partyMemberText->getComponent<pod::Transform<>>();
@ -555,7 +555,7 @@ void ext::GuiBattle::initialize() {
{
ext::Gui* partyMemberBar = new ext::Gui;
partyMemberButton->addChild(*partyMemberBar);
partyMemberBar->load("./partyMemberBars.json", true);
partyMemberBar->as<uf::Object>().load("./partyMemberBars.json", true);
pod::Transform<>& transform = partyMemberBar->getComponent<pod::Transform<>>();
transform.position = bTransform.position;
transform.position.x = 0.742573;
@ -565,7 +565,7 @@ void ext::GuiBattle::initialize() {
{
ext::Gui* partyMemberHP = new ext::Gui;
partyMemberButton->addChild(*partyMemberHP);
partyMemberHP->load("./partyMemberHP.json", true);
partyMemberHP->as<uf::Object>().load("./partyMemberHP.json", true);
pod::Transform<>& transform = partyMemberHP->getComponent<pod::Transform<>>();
transform.position = bTransform.position;
transform.position.x = 0.742573;
@ -583,7 +583,7 @@ void ext::GuiBattle::initialize() {
{
ext::Gui* partyMemberMP = new ext::Gui;
partyMemberButton->addChild(*partyMemberMP);
partyMemberMP->load("./partyMemberMP.json", true);
partyMemberMP->as<uf::Object>().load("./partyMemberMP.json", true);
pod::Transform<>& transform = partyMemberMP->getComponent<pod::Transform<>>();
transform.position = bTransform.position;
transform.position.x = 0.742573;
@ -740,7 +740,7 @@ void ext::GuiBattle::tick() {
battleOptions = new ext::Gui;
this->addChild(*battleOptions);
uf::Serializer& pMetadata = battleOptions->getComponent<uf::Serializer>();
battleOptions->load("./battle-option.json", true);
battleOptions->as<uf::Object>().load("./battle-option.json", true);
pMetadata["text settings"]["string"] = string;
pod::Transform<>& pTransform = battleOptions->getComponent<pod::Transform<>>();
battleOptions->initialize();
@ -793,7 +793,7 @@ void ext::GuiBattle::tick() {
commandOptions = new ext::Gui;
this->addChild(*commandOptions);
uf::Serializer& pMetadata = commandOptions->getComponent<uf::Serializer>();
commandOptions->load("./battle-option.json", true);
commandOptions->as<uf::Object>().load("./battle-option.json", true);
pMetadata["text settings"]["string"] = string;
pod::Transform<>& pTransform = commandOptions->getComponent<pod::Transform<>>();
commandOptions->initialize();
@ -845,7 +845,7 @@ void ext::GuiBattle::tick() {
targetOptions = new ext::Gui;
this->addChild(*targetOptions);
uf::Serializer& pMetadata = targetOptions->getComponent<uf::Serializer>();
targetOptions->load("./battle-option.json", true);
targetOptions->as<uf::Object>().load("./battle-option.json", true);
pMetadata["text settings"]["string"] = string;
pod::Transform<>& pTransform = targetOptions->getComponent<pod::Transform<>>();
targetOptions->initialize();

View File

@ -203,7 +203,7 @@ void ext::GuiDialogue::tick() {
dialogueMessage = new ext::Gui;
this->addChild(*dialogueMessage);
uf::Serializer& pMetadata = dialogueMessage->getComponent<uf::Serializer>();
dialogueMessage->load("./dialogue-text.json", true);
dialogueMessage->as<uf::Object>().load("./dialogue-text.json", true);
pMetadata["text settings"]["string"] = result["message"].asString();
dialogueMessage->initialize();
}
@ -251,7 +251,7 @@ void ext::GuiDialogue::tick() {
dialogueOptions = new ext::Gui;
this->addChild(*dialogueOptions);
uf::Serializer& pMetadata = dialogueOptions->getComponent<uf::Serializer>();
dialogueOptions->load("./dialogue-option.json", true);
dialogueOptions->as<uf::Object>().load("./dialogue-option.json", true);
pMetadata["text settings"]["string"] = string;
pod::Transform<>& pTransform = dialogueOptions->getComponent<pod::Transform<>>();
dialogueOptions->initialize();

View File

@ -127,6 +127,7 @@ void ext::GuiWorldPauseMenuBehavior::initialize( uf::Object& self ) {
uf::Serializer member = pMetadata[""]["transients"][id];
uf::Serializer cardData = masterDataGet("Card", id);
std::string name = cardData["filename"].asString();
if ( name == "" ) continue;
if ( member["skin"].isString() ) name += "_" + member["skin"].asString();
std::string filename = "https://cdn..xyz//unity/Android/fg/fg_" + name + ".png";
if ( cardData["internal"].asBool() ) {
@ -137,7 +138,7 @@ void ext::GuiWorldPauseMenuBehavior::initialize( uf::Object& self ) {
}
{
std::string portrait = metadata["portraits"]["list"][0].asString();
/* Transient shadow background */ {
/* Transient shadow background */ if ( portrait != "" ) {
transientSpriteShadow = new uf::Object;
uf::Asset& assetLoader = transientSpriteShadow->getComponent<uf::Asset>();
this->addChild(*transientSpriteShadow);
@ -148,7 +149,7 @@ void ext::GuiWorldPauseMenuBehavior::initialize( uf::Object& self ) {
transientSpriteShadow->initialize();
}
/* Transient transientSprite */ {
/* Transient transientSprite */ if ( portrait != "" ) {
transientSprite = new uf::Object;
uf::Asset& assetLoader = transientSprite->getComponent<uf::Asset>();
this->addChild(*transientSprite);
@ -229,7 +230,13 @@ void ext::GuiWorldPauseMenuBehavior::initialize( uf::Object& self ) {
delete this;
return "true";
*/
uf::Serializer json = event;
metadata["system"]["hooks"]["onClose"] = json["callback"];
metadata["system"]["closing"] = true;
playSound(*this, "menu close");
return "true";
});
}
@ -238,6 +245,7 @@ void ext::GuiWorldPauseMenuBehavior::tick( uf::Object& self ) {
uf::Serializer& masterdata = scene.getComponent<uf::Serializer>();
static uf::Timer<long long> timer(false);
static uf::Audio sfx;
// if ( !timer.running() ) timer.start( uf::Time<>(-1000000) );
if ( !timer.running() ) timer.start();
static float alpha = 0.0f;
@ -259,6 +267,21 @@ void ext::GuiWorldPauseMenuBehavior::tick( uf::Object& self ) {
} else if ( metadata["system"]["closed"].asBool() ) {
// kill
timer.stop();
uf::Serializer callback = metadata["system"]["hooks"]["onClose"];
uf::Serializer payload = callback["payload"];
uf::Object* target = this;
if ( callback["scope"].asString() == "parent" ) {
target = &this->getParent().as<uf::Object>();
} else if ( callback["scope"].asString() == "scene" ) {
target = &uf::scene::getCurrentScene();
}
if ( callback["delay"].isNumeric() ) {
target->queueHook( callback["name"].asString(), payload, callback["delay"].asFloat() );
} else {
target->callHook( callback["name"].asString(), payload );
}
this->destroy();
this->getParent().removeChild(*this);
delete this;
@ -495,13 +518,13 @@ void ext::GuiWorldPauseMenuBehavior::tick( uf::Object& self ) {
delta += uf::physics::time::delta * 1.5f;
transform.position = uf::vector::lerp( start, end, delta );
}
/*
if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= 1 ) {
timer.reset();
this->callHook("menu:Close.%UID%");
playSound(*this, "menu close");
}
*/
metadata["color"][3] = alpha;
for ( uf::Entity* pointer : closeOption->getChildren() ) {
@ -531,17 +554,13 @@ void ext::GuiWorldPauseMenuBehavior::tick( uf::Object& self ) {
delta += uf::physics::time::delta * 1.5f;
transform.position = uf::vector::lerp( start, end, delta );
}
/*
if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= 1 ) {
timer.reset();
this->callHook("menu:Close.%UID%");
playSound(*this, "menu close");
/*
uf::Scene& scene = this->getRootParent<uf::Scene>();
scene.queueHook("system:Quit.%UID%", "", 1.0f);
*/
}
*/
metadata["color"][3] = alpha;
for ( uf::Entity* pointer : quitOption->getChildren() ) {

View File

@ -105,7 +105,7 @@ namespace {
void ext::HousamoBattle::initialize() {
uf::Object::initialize();
gui = NULL;
::gui = NULL;
transients.clear();
uf::Scene& scene = uf::scene::getCurrentScene();
@ -283,17 +283,17 @@ void ext::HousamoBattle::initialize() {
return payload;
});
this->addHook( "world:Battle.Gui.%UID%", [&](const std::string& event)->std::string{
ext::Gui* guiManager = (ext::Gui*) this->getRootParent().findByName("Gui Manager");
ext::Gui* guiManager = (ext::Gui*) this->globalFindByName("Gui Manager");
ext::Gui* guiMenu = new ext::GuiBattle;
guiManager->addChild(*guiMenu);
guiMenu->load("./scenes/world/gui/battle/menu.json");
guiMenu->as<uf::Object>().load("./scenes/world/gui/battle/menu.json");
guiMenu->initialize();
uf::Serializer payload;
payload["battle"] = metadata["battle"];
guiMenu->queueHook("world:Battle.Start.%UID%", payload);
gui = guiMenu;
::gui = guiMenu;
return "true";
});
@ -403,10 +403,10 @@ void ext::HousamoBattle::initialize() {
// std::cout << metadata["battle"]["transients"] << std::endl;
}
if ( gui ) {
if ( ::gui ) {
uf::Serializer payload;
payload["battle"] = metadata["battle"];
gui->queueHook("world:Battle.Update.%UID%", payload);
::gui->queueHook("world:Battle.Update.%UID%", payload);
}
if ( hookName == "" ) return payload;
@ -657,10 +657,10 @@ void ext::HousamoBattle::initialize() {
turnState["counter"] = counter;
turnState["start of turn"] = true;
if ( gui ) {
if ( ::gui ) {
uf::Serializer payload;
payload["battle"] = metadata["battle"];
gui->queueHook("world:Battle.TurnStart.%UID%", payload);
::gui->queueHook("world:Battle.TurnStart.%UID%", payload);
}
} else {
turnState["start of turn"] = false;
@ -791,10 +791,10 @@ void ext::HousamoBattle::initialize() {
}
}
if ( gui ) {
if ( ::gui ) {
uf::Serializer payload;
payload["battle"] = metadata["battle"];
gui->queueHook("world:Battle.Update.%UID%", payload);
::gui->queueHook("world:Battle.Update.%UID%", payload);
}
if ( skipped ) payload["skipped"] = true;
@ -906,7 +906,7 @@ void ext::HousamoBattle::initialize() {
payload["color"] = json["color"];
payload["target"]["uid"] = json["uid"];
payload["target"]["damage"] = json["message"];
gui->queueHook("world:Battle.Damage.%UID%", payload, delays.damage);
::gui->queueHook("world:Battle.Damage.%UID%", payload, delays.damage);
delays.damage += 0.25f;
};
@ -1062,7 +1062,7 @@ void ext::HousamoBattle::initialize() {
uf::Serializer payload;
payload["target"]["uid"] = target["uid"];
payload["target"]["damage"] = "Miss";
gui->queueHook("world:Battle.Damage.%UID%", payload);
::gui->queueHook("world:Battle.Damage.%UID%", payload);
continue;
}
@ -1337,7 +1337,7 @@ void ext::HousamoBattle::initialize() {
uf::Serializer payload;
payload["uid"] = json["uid"];
payload["id"] = member["id"];
gui->queueHook("world:Battle.OnCrit.%UID%", payload, 0.1f);
::gui->queueHook("world:Battle.OnCrit.%UID%", payload, 0.1f);
}
}
@ -1435,7 +1435,7 @@ void ext::HousamoBattle::initialize() {
*/
uf::Scene& scene = uf::scene::getCurrentScene();
scene.callHook("world:Music.LoadPrevious.%UID%");
gui->callHook("menu:Close.%UID%");
::gui->callHook("menu:Close.%UID%");
// cleanup
for ( ext::Housamo* pointer : transients ) {

View File

@ -92,7 +92,7 @@ namespace {
void ext::DialogueManager::initialize() {
uf::Object::initialize();
gui = NULL;
::gui = NULL;
transients.clear();
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
@ -175,17 +175,17 @@ void ext::DialogueManager::initialize() {
return payload;
});
this->addHook( "menu:Dialogue.Gui.%UID%", [&](const std::string& event)->std::string{
ext::Gui* guiManager = (ext::Gui*) this->getRootParent().findByName("Gui Manager");
ext::Gui* guiManager = (ext::Gui*) this->globalFindByName("Gui Manager");
ext::Gui* guiMenu = new ext::GuiDialogue;
guiManager->addChild(*guiMenu);
guiMenu->load("./entities/gui/dialogue/menu.json");
guiMenu->as<uf::Object>().load("./entities/gui/dialogue/menu.json");
guiMenu->initialize();
uf::Serializer payload;
payload["dialogue"] = metadata["dialogue"];
guiMenu->queueHook("menu:Dialogue.Start.%UID%", payload);
gui = guiMenu;
::gui = guiMenu;
return "true";
});
@ -251,7 +251,7 @@ void ext::DialogueManager::initialize() {
// play music
uf::Scene& scene = uf::scene::getCurrentScene();
scene.callHook("world:Music.LoadPrevious.%UID%");
gui->callHook("menu:Close.%UID%");
::gui->callHook("menu:Close.%UID%");
this->callHook("menu:Dialogue.End");

View File

@ -8,6 +8,7 @@
#include <uf/utils/math/physics.h>
#include <uf/engine/object/object.h>
#include <uf/engine/asset/asset.h>
#include <uf/utils/window/window.h>
#include <uf/utils/graphic/mesh.h>
@ -77,7 +78,51 @@ void ext::TerrainBehavior::initialize( uf::Object& self ) {
uf::thread::limiter = metadata["system"]["limiter"].asFloat();
return "true";
});
this->addHook( "terrain:GenerateMesh.%UID%", [&](const std::string& event)->std::string{
uf::Serializer json = event;
auto& graphic = this->getComponent<uf::Graphic>();
auto& mesh = this->getComponent<ext::TerrainGenerator::mesh_t>();
graphic.initializeGeometry( mesh );
graphic.getPipeline().update( graphic );
graphic.process = true;
uf::renderer::rebuild = true;
return "true";
});
this->addHook( "terrain:Post-Initialize.%UID%", [&](const std::string& event)->std::string{
if ( metadata["terrain"]["unified"].asBool() ) {
std::string textureFilename = ""; {
uf::Asset assetLoader;
for ( uint i = 0; i < metadata["system"]["assets"].size(); ++i ) {
if ( textureFilename != "" ) break;
std::string filename = this->grabURI( metadata["system"]["assets"][i].asString(), metadata["system"]["root"].asString() );
textureFilename = assetLoader.cache( filename );
}
}
auto& graphic = this->getComponent<uf::Graphic>();
graphic.initialize();
graphic.process = false;
auto& texture = graphic.material.textures.emplace_back();
texture.sampler.descriptor.filter.min = VK_FILTER_NEAREST;
texture.sampler.descriptor.filter.mag = VK_FILTER_NEAREST;
texture.loadFromFile( textureFilename );
std::string suffix = ""; {
std::string _ = this->getRootParent<uf::Scene>().getComponent<uf::Serializer>()["shaders"]["region"]["suffix"].asString();
if ( _ != "" ) suffix = _ + ".";
}
graphic.material.initializeShaders({
{"./data/shaders/terrain.stereo.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{"./data/shaders/terrain."+suffix+"frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
uf::renderer::rebuildOnTickStart = false;
}
this->generate();
/*
auto& parent = this->getParent().as<uf::Object>();
@ -185,15 +230,34 @@ void ext::TerrainBehavior::tick( uf::Object& self ) {
}
// sort by closest to farthest
sortRegions(controller, regions);
if ( metadata["terrain"]["unified"].asBool() ) {
auto& graphic = this->getComponent<uf::Graphic>();
auto& mesh = this->getComponent<ext::TerrainGenerator::mesh_t>();
mesh.destroy();
for ( uf::Object* region : regions ) {
uf::Serializer& metadata = region->getComponent<uf::Serializer>();
if ( !metadata["region"]["initialized"].asBool() ) region->initialize();
if ( !metadata["region"]["generated"].asBool() ) region->callHook("region:Generate.%UID%", "");
if ( !metadata["region"]["rasterized"].asBool() ) {
region->queueHook("region:Finalize.%UID%", "");
region->queueHook("region:Populate.%UID%", "");
}
auto& generator = region->getComponent<ext::TerrainGenerator>();
generator.rasterize(mesh.vertices, *region, false);
}
this->queueHook("terrain:GenerateMesh.%UID%");
} else {
// initialize uninitialized regions
for ( uf::Object* region : regions ) {
// uf::thread::add( uf::thread::fetchWorker(), [&]() -> int {
uf::Serializer& metadata = region->getComponent<uf::Serializer>();
if ( !metadata["region"]["initialized"].asBool() ) region->initialize();
if ( !metadata["region"]["generated"].asBool() ) region->callHook("region:Generate.%UID%", "");
if ( !metadata["region"]["rasterized"].asBool() ) region->callHook("region:Rasterize.%UID%", "");
// return 0;}, true );
for ( uf::Object* region : regions ) {
// uf::thread::add( uf::thread::fetchWorker(), [&]() -> int {
uf::Serializer& metadata = region->getComponent<uf::Serializer>();
if ( !metadata["region"]["initialized"].asBool() ) region->initialize();
if ( !metadata["region"]["generated"].asBool() ) region->callHook("region:Generate.%UID%", "");
if ( !metadata["region"]["rasterized"].asBool() ) region->callHook("region:Rasterize.%UID%", "");
// return 0;}, true );
}
}
// move to next state:
transitionState(*this, "open", !regions.empty());
return 0;}, true );
@ -201,7 +265,25 @@ void ext::TerrainBehavior::tick( uf::Object& self ) {
// check if we need to relocate entities
this->relocateChildren();
}
void ext::TerrainBehavior::render( uf::Object& self ){}
void ext::TerrainBehavior::render( uf::Object& self ){
uf::Scene& scene = uf::scene::getCurrentScene();
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
if ( !metadata["terrain"]["unified"].asBool() ) return;
/* Update uniforms */ if ( this->hasComponent<uf::Graphic>() ) {
auto& scene = uf::scene::getCurrentScene();
auto& graphic = this->getComponent<uf::Graphic>();
auto& camera = scene.getController().getComponent<uf::Camera>();
if ( !graphic.initialized ) return;
auto& uniforms = graphic.material.shaders.front().uniforms.front().get<uf::StereoMeshDescriptor>();
uniforms.matrices.model = uf::matrix::identity();
for ( std::size_t i = 0; i < 2; ++i ) {
uniforms.matrices.view[i] = camera.getView( i );
uniforms.matrices.projection[i] = camera.getProjection( i );
}
graphic.material.shaders.front().updateBuffer( uniforms, 0, true );
}
}
void ext::TerrainBehavior::destroy( uf::Object& self ){}
#undef this
EXT_BEHAVIOR_ENTITY_CPP_END(Terrain)

View File

@ -1287,7 +1287,7 @@ void ext::TerrainGenerator::updateLight(){
// this->wrapLight();
// this->writeToFile();
}
void ext::TerrainGenerator::rasterize( std::vector<ext::TerrainGenerator::mesh_t::vertex_t>& vertices, const uf::Object& region ){
void ext::TerrainGenerator::rasterize( std::vector<ext::TerrainGenerator::mesh_t::vertex_t>& vertices, const uf::Object& region, bool applyTransform ){
if ( this->m_voxels.id.rle.empty() ) return;
this->writeToFile();
@ -1326,6 +1326,7 @@ void ext::TerrainGenerator::rasterize( std::vector<ext::TerrainGenerator::mesh_t
color.b *= tMetadata["region"]["light"]["ambient"][2].asFloat();
ambientLight = colorToUint16( color );
}
pod::Matrix4f modelMatrix = uf::transform::model( transform );
#define TERRAIN_SHOULD_RENDER_FACE(SIDE)\
should.SIDE = !neighbor.SIDE.opaque();\
if ( should.SIDE ) {\
@ -1359,6 +1360,10 @@ void ext::TerrainGenerator::rasterize( std::vector<ext::TerrainGenerator::mesh_t
p[2] = (p[2] << 4) | p[2];\
p[3] = (p[3] << 4) | p[3];\
}\
if ( applyTransform ) {\
pod::Vector3f& p = vertex.position;\
p += transform.position; /*p = uf::matrix::multiply<float>( modelMatrix, p );*/\
}\
vertices.push_back(vertex);\
}\
}

View File

@ -54,7 +54,7 @@ namespace ext {
void updateLight();
void generate( uf::Object& );
void rasterize( std::vector<TerrainGenerator::mesh_t::vertex_t>& vertices, const uf::Object& );
void rasterize( std::vector<TerrainGenerator::mesh_t::vertex_t>& vertices, const uf::Object&, bool = false );
// void vectorize( std::vector<uf::renderer::ComputeGraphic::Cube>&, const uf::Object& );
std::vector<ext::TerrainVoxel::uid_t> getRawVoxels();

View File

@ -12,22 +12,9 @@
#include <uf/utils/string/ext.h>
#include <mutex>
namespace {
std::string grabURI( std::string filename, std::string root = "" ) {
if ( filename.substr(0,8) == "https://" ) return filename;
std::string extension = uf::io::extension(filename);
if ( filename[0] == '/' || root == "" ) {
if ( extension == "json" ) root = "./data/entities/";
if ( extension == "png" ) root = "./data/textures/";
if ( extension == "ogg" ) root = "./data/audio/";
}
return uf::io::sanitize(filename, root);
}
}
EXT_BEHAVIOR_REGISTER_CPP(RegionBehavior)
EXT_BEHAVIOR_REGISTER_AS_OBJECT(RegionBehavior, Region)
#define this (&self)
#define this ((uf::Object*) &self)
void ext::RegionBehavior::initialize( uf::Object& self ) {
// alias Mesh types
{
@ -38,13 +25,13 @@ void ext::RegionBehavior::initialize( uf::Object& self ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
metadata["region"]["initialized"] = true;
{
if ( !metadata["terrain"]["unified"].asBool() ) {
std::string textureFilename = ""; {
uf::Serializer& metadata = this->getParent().getComponent<uf::Serializer>();
uf::Asset assetLoader;
for ( uint i = 0; i < metadata["system"]["assets"].size(); ++i ) {
if ( textureFilename != "" ) break;
std::string filename = grabURI( metadata["system"]["assets"][i].asString(), metadata["system"]["root"].asString() );
std::string filename = this->grabURI( metadata["system"]["assets"][i].asString(), metadata["system"]["root"].asString() );
textureFilename = assetLoader.cache( filename );
}
}
@ -141,10 +128,10 @@ void ext::RegionBehavior::initialize( uf::Object& self ) {
this->addHook( "region:Finalize.%UID%", [&](const std::string& event)->std::string{
uf::Serializer json = event;
ext::TerrainGenerator::mesh_t& mesh = this->getComponent<ext::TerrainGenerator::mesh_t>();
auto& graphic = this->getComponent<uf::Graphic>();
graphic.process = true;
if ( this->hasComponent<uf::Graphic>() ) {
auto& graphic = this->getComponent<uf::Graphic>();
graphic.process = true;
}
metadata["region"]["rasterized"] = true;
return "true";

View File

@ -1,5 +1,5 @@
#!/bin/bash
tskill program
cd bin
./program.bat
./program.bat $@
tskill program