Commit for 2020.10.08.7z
This commit is contained in:
parent
0563fdfb4a
commit
3fdc1820ea
3
Makefile
3
Makefile
@ -25,7 +25,8 @@ EXT_LIB_NAME = ext
|
||||
#VULKAN_WIN64_SDK_PATH = /c/VulkanSDK/1.1.101.0/
|
||||
#VULKAN_WIN64_SDK_PATH = /c/VulkanSDK/1.1.108.0/
|
||||
#VULKAN_WIN64_SDK_PATH = /c/VulkanSDK/1.1.114.0/
|
||||
VULKAN_WIN64_SDK_PATH = /c/VulkanSDK/1.2.141.2/
|
||||
#VULKAN_WIN64_SDK_PATH = /c/VulkanSDK/1.2.141.2/
|
||||
VULKAN_WIN64_SDK_PATH = /c/VulkanSDK/1.2.154.0/
|
||||
WIN64_CC = g++
|
||||
WIN64_GLSL_VALIDATOR = $(VULKAN_WIN64_SDK_PATH)/Bin32/glslangValidator
|
||||
# Base Engine's DLL
|
||||
|
||||
@ -21,7 +21,6 @@ const vec2 poissonDisk[4] = vec2[](
|
||||
vec2( 0.34495938, 0.29387760 )
|
||||
);
|
||||
*/
|
||||
|
||||
vec2 poissonDisk[16] = vec2[](
|
||||
vec2( -0.94201624, -0.39906216 ),
|
||||
vec2( 0.94558609, -0.76890725 ),
|
||||
@ -67,10 +66,17 @@ struct Fog {
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
struct Mode {
|
||||
uint type;
|
||||
uint scalar;
|
||||
vec4 parameters;
|
||||
};
|
||||
|
||||
layout (binding = 0) uniform UBO {
|
||||
Matrices matrices;
|
||||
vec3 ambient;
|
||||
float kexp;
|
||||
Mode mode;
|
||||
Fog fog;
|
||||
Light lights[LIGHTS];
|
||||
} ubo;
|
||||
@ -171,63 +177,357 @@ float shadowFactor( Light light, uint shadowMap ) {
|
||||
}
|
||||
return factor;
|
||||
}
|
||||
vec3 hslToRgb(vec3 HSL) {
|
||||
vec3 RGB; {
|
||||
float H = HSL.x;
|
||||
float R = abs(H * 6 - 3) - 1;
|
||||
float G = 2 - abs(H * 6 - 2);
|
||||
float B = 2 - abs(H * 6 - 4);
|
||||
RGB = clamp(vec3(R,G,B), 0, 1);
|
||||
}
|
||||
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; {
|
||||
vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0);
|
||||
vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx);
|
||||
float C = Q.x - min(Q.w, Q.y);
|
||||
float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z);
|
||||
HCV = vec3(H, C, Q.x);
|
||||
}
|
||||
float L = HCV.z - HCV.y * 0.5;
|
||||
float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon);
|
||||
return vec3(HCV.x, S, L);
|
||||
}
|
||||
|
||||
float hueDistance(float h1, float h2) {
|
||||
float diff = abs((h1 - h2));
|
||||
return min(abs((1.0 - diff)), diff);
|
||||
}
|
||||
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,
|
||||
128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127,
|
||||
32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223,
|
||||
160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95,
|
||||
8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247,
|
||||
136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119,
|
||||
40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215,
|
||||
168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87,
|
||||
2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253,
|
||||
130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125,
|
||||
34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221,
|
||||
162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93,
|
||||
10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245,
|
||||
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));
|
||||
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,
|
||||
60, 28, 52, 20, 62, 30, 54, 22,
|
||||
3, 35, 11, 43, 1, 33, 9, 41,
|
||||
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));
|
||||
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));
|
||||
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 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]);
|
||||
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_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;
|
||||
if ( ubo.mode.scalar == 16 ) {
|
||||
d = indexValue16x16();
|
||||
} else if ( ubo.mode.scalar == 8 ) {
|
||||
d = indexValue8x8();
|
||||
} else if ( ubo.mode.scalar == 4 ) {
|
||||
d = indexValue4x4();
|
||||
}
|
||||
float distance = abs(closestColor - color);
|
||||
return (distance < d) ? closestColor : secondClosestColor;
|
||||
}
|
||||
void dither(inout vec3 color) {
|
||||
vec3 hsl = rgbToHsl(color);
|
||||
hsl.y = dither(hsl.y);
|
||||
color = hslToRgb(hsl);
|
||||
}
|
||||
|
||||
float rand2(vec2 co){
|
||||
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453);
|
||||
}
|
||||
float rand3(vec3 co){
|
||||
return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453);
|
||||
}
|
||||
void whitenoise(inout vec3 color) {
|
||||
float flicker = ubo.mode.parameters.x;
|
||||
float pieces = ubo.mode.parameters.y;
|
||||
float blend = ubo.mode.parameters.z;
|
||||
float time = ubo.mode.parameters.w;
|
||||
if ( blend < 0.0001 ) return;
|
||||
float freq = sin(pow(mod(time, flicker) + flicker, 1.9));
|
||||
// float whiteNoise = rand3( floor(position.world / pieces) + floor(time * 2) );
|
||||
float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) );
|
||||
color = mix( color, vec3(whiteNoise), blend );
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 albedoSpecular = subpassLoad(samplerAlbedo);
|
||||
vec3 fragColor = albedoSpecular.rgb * ubo.ambient.rgb;
|
||||
normal.eye = subpassLoad(samplerNormal).rgb;
|
||||
position.eye = subpassLoad(samplerPosition).rgb;
|
||||
|
||||
{
|
||||
position.eye = subpassLoad(samplerPosition).rgb; {
|
||||
mat4 iView = inverse( ubo.matrices.view[inPushConstantPass] );
|
||||
vec4 positionWorld = iView * vec4(position.eye, 1);
|
||||
position.world = positionWorld.xyz;
|
||||
}
|
||||
/*
|
||||
{
|
||||
for ( int i = 0; i < LIGHTS; ++i ) {
|
||||
outFragColor.rgb = texture(samplerShadows[i], inUv).rgb;
|
||||
}
|
||||
float depth = texture(samplerShadows[3], inUv).r;
|
||||
depth /= 0.00526;
|
||||
outFragColor.rgb = vec3(1 - depth);
|
||||
// outFragColor.rgb = texture(samplerShadows[0], inUv).rgb;
|
||||
outFragColor.a = 1;
|
||||
return;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
{
|
||||
mat4 iProj = inverse( ubo.matrices.projection[inPushConstantPass] );
|
||||
mat4 iView = inverse( ubo.matrices.view[inPushConstantPass] );
|
||||
|
||||
float depth = subpassLoad(samplerDepth).r;
|
||||
|
||||
if ( false ) {
|
||||
depth /= 0.00526;
|
||||
outFragColor.rgb = vec3( 1 - depth );
|
||||
outFragColor.a = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 positionClip = vec4(inUv * 2.0 - 1.0, depth, 1.0);
|
||||
vec4 positionEye = iProj * positionClip;
|
||||
positionEye /= positionEye.w;
|
||||
position.eye = positionEye.xyz;
|
||||
|
||||
vec4 positionWorld = iView * positionEye;
|
||||
position.world = positionWorld.xyz;
|
||||
}
|
||||
*/
|
||||
|
||||
vec3 fragColor = albedoSpecular.rgb * ubo.ambient.rgb;
|
||||
bool lit = false;
|
||||
uint shadowMap = 0;
|
||||
float litFactor = 1.0;
|
||||
for ( uint i = 0; i < LIGHTS; ++i ) {
|
||||
for ( uint i = 0, shadowMap = 0; i < LIGHTS; ++i ) {
|
||||
Light light = ubo.lights[i];
|
||||
|
||||
if ( light.power <= 0.001 ) continue;
|
||||
lit = true;
|
||||
|
||||
light.position.xyz = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1));
|
||||
if ( light.type > 0 ) {
|
||||
@ -238,8 +538,18 @@ void main() {
|
||||
}
|
||||
phong( light, albedoSpecular, fragColor );
|
||||
}
|
||||
// if ( !lit ) fragColor = albedoSpecular.rgb;
|
||||
|
||||
fog(fragColor, litFactor);
|
||||
// if ( length(position.eye) < 0.01 ) fragColor = vec3(1,0,1);
|
||||
|
||||
if ( (ubo.mode.type & (0x1 >> 1)) == (0x1 >> 1) ) {
|
||||
dither(fragColor);
|
||||
}
|
||||
if ( (ubo.mode.type & (0x1 >> 2)) == (0x1 >> 2) ) {
|
||||
whitenoise(fragColor);
|
||||
}
|
||||
if ( (ubo.mode.type & (0x1 >> 3)) == (0x1 >> 3) ) {
|
||||
dither(fragColor);
|
||||
}
|
||||
|
||||
outFragColor = vec4(fragColor,1);
|
||||
}
|
||||
25
bin/data/shaders/gltf.frag.glsl
Normal file
25
bin/data/shaders/gltf.frag.glsl
Normal file
@ -0,0 +1,25 @@
|
||||
#version 450
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 1;
|
||||
layout (binding = 1) uniform sampler2D samplerTextures[TEXTURES];
|
||||
|
||||
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);
|
||||
if ( outAlbedoSpecular.a < 0.001 ) discard;
|
||||
outAlbedoSpecular.rgb *= inColor.rgb;
|
||||
outAlbedoSpecular.a = 1;
|
||||
|
||||
outNormal = vec4(inNormal,1);
|
||||
outPosition = vec4(inPosition,1);
|
||||
}
|
||||
45
bin/data/shaders/gltf.stereo.vert.glsl
Normal file
45
bin/data/shaders/gltf.stereo.vert.glsl
Normal file
@ -0,0 +1,45 @@
|
||||
#version 450
|
||||
|
||||
layout (location = 0) in vec3 inPos;
|
||||
layout (location = 1) in vec2 inUv;
|
||||
layout (location = 2) in vec3 inNormal;
|
||||
layout (location = 3) in uint inId;
|
||||
|
||||
layout( push_constant ) uniform PushBlock {
|
||||
uint pass;
|
||||
} PushConstant;
|
||||
|
||||
struct Matrices {
|
||||
mat4 model;
|
||||
mat4 view[2];
|
||||
mat4 projection[2];
|
||||
};
|
||||
|
||||
layout (binding = 0) uniform UBO {
|
||||
Matrices matrices;
|
||||
vec4 color;
|
||||
} ubo;
|
||||
|
||||
layout (location = 0) out vec2 outUv;
|
||||
layout (location = 1) out vec4 outColor;
|
||||
layout (location = 2) out vec3 outNormal;
|
||||
layout (location = 3) out vec3 outPosition;
|
||||
layout (location = 4) flat out uint outId;
|
||||
|
||||
out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
|
||||
void main() {
|
||||
outUv = inUv;
|
||||
outColor = ubo.color;
|
||||
|
||||
outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
|
||||
outNormal = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0));
|
||||
outNormal = normalize(outNormal);
|
||||
|
||||
outId = inId;
|
||||
|
||||
gl_Position = ubo.matrices.projection[PushConstant.pass] * ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0);
|
||||
}
|
||||
595
engine/inc/binpack2d/binpack2d.hpp
Normal file
595
engine/inc/binpack2d/binpack2d.hpp
Normal file
@ -0,0 +1,595 @@
|
||||
/**
|
||||
* BinPack2D is a 2 dimensional, multi-bin, bin-packer. ( Texture Atlas Array! )
|
||||
* It supports an arbitrary number of bins, at arbitrary sizes.
|
||||
* rectangles can be added one at a time, chunks at a time, or all at once.
|
||||
* rectangles that dont fit are reported back.
|
||||
* Data can be associated to rectangles before processing via a template, and recalled after processing.
|
||||
*
|
||||
* There is no documentation, See ExampleProgram() below for a taste.
|
||||
*
|
||||
* Instead of tracking 'free rectangles' like other solutions I've found online,
|
||||
* this algorithm tracks free 'top lefts', keeps them sorted by closest to origin, and puts new rectangles into
|
||||
* the first free top left that doesnt collide. Consuming a top left creates 2 new top lefts (x+w,y) and (x,y+h).
|
||||
* If a rectangle doesnt fit into a bin, before condisering the next bin, the current bin is re-tried with the rectangle rotated.
|
||||
* This SOMTIMES helps... but not always.. i might disable this in future !?
|
||||
*
|
||||
* This Header was origonally part of my rh_texture_packer program.
|
||||
* A program I wrote to take advantage of my nexus-7's GL_EXT_texture_array extension.
|
||||
* I wanted to be able to render out whole scenes with a single glDraw*
|
||||
* blah blah blah...
|
||||
*/
|
||||
|
||||
|
||||
/** ***** EXAMPLE CODE **************************************
|
||||
|
||||
// Your data - whatever you want to associate with 'rectangle'
|
||||
class MyContent {
|
||||
public:
|
||||
std::string str;
|
||||
MyContent() : str("default string") {}
|
||||
MyContent(const std::string &str) : str(str) {}
|
||||
};
|
||||
|
||||
int ExampleProgram() {
|
||||
|
||||
srandom(0x69);
|
||||
|
||||
// Create some 'content' to work on.
|
||||
BinPack2D::ContentAccumulator<MyContent> inputContent;
|
||||
|
||||
for(int i=0;i<20;i++) {
|
||||
|
||||
// random size for this content
|
||||
int width = ((random() % 32)+1) * ((random() % 10)+1);
|
||||
int height = ((random() % 32)+1) * ((random() % 10)+1);
|
||||
|
||||
// whatever data you want to associate with this content
|
||||
std::stringstream ss;
|
||||
ss << "box " << i;
|
||||
MyContent mycontent( ss.str().c_str() );
|
||||
|
||||
// Add it
|
||||
inputContent += BinPack2D::Content<MyContent>(mycontent, BinPack2D::Coord(), BinPack2D::Size(width, height), false );
|
||||
}
|
||||
|
||||
// Sort the input content by size... usually packs better.
|
||||
inputContent.Sort();
|
||||
|
||||
// Create some bins! ( 2 bins, 128x128 in this example )
|
||||
BinPack2D::CanvasArray<MyContent> canvasArray =
|
||||
BinPack2D::UniformCanvasArrayBuilder<MyContent>(128,128,2).Build();
|
||||
|
||||
// A place to store content that didnt fit into the canvas array.
|
||||
BinPack2D::ContentAccumulator<MyContent> remainder;
|
||||
|
||||
// try to pack content into the bins.
|
||||
bool success = canvasArray.Place( inputContent, remainder );
|
||||
|
||||
// A place to store packed content.
|
||||
BinPack2D::ContentAccumulator<MyContent> outputContent;
|
||||
|
||||
// Read all placed content.
|
||||
canvasArray.CollectContent( outputContent );
|
||||
|
||||
// parse output.
|
||||
typedef BinPack2D::Content<MyContent>::Vector::iterator binpack2d_iterator;
|
||||
printf("PLACED:\n");
|
||||
for( binpack2d_iterator itor = outputContent.Get().begin(); itor != outputContent.Get().end(); itor++ ) {
|
||||
|
||||
const BinPack2D::Content<MyContent> &content = *itor;
|
||||
|
||||
// retreive your data.
|
||||
const MyContent &myContent = content.content;
|
||||
|
||||
printf("\t%9s of size %3dx%3d at position %3d,%3d,%2d rotated=%s\n",
|
||||
myContent.str.c_str(),
|
||||
content.size.w,
|
||||
content.size.h,
|
||||
content.coord.x,
|
||||
content.coord.y,
|
||||
content.coord.z,
|
||||
(content.rotated ? "yes":" no"));
|
||||
}
|
||||
|
||||
printf("NOT PLACED:\n");
|
||||
for( binpack2d_iterator itor = remainder.Get().begin(); itor != remainder.Get().end(); itor++ ) {
|
||||
|
||||
const BinPack2D::Content<MyContent> &content = *itor;
|
||||
|
||||
const MyContent &myContent = content.content;
|
||||
|
||||
printf("\t%9s of size %3dx%3d\n",
|
||||
myContent.str.c_str(),
|
||||
content.size.w,
|
||||
content.size.h);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include<vector>
|
||||
#include<map>
|
||||
#include<list>
|
||||
#include<algorithm>
|
||||
#include<math.h>
|
||||
#include<sstream>
|
||||
|
||||
namespace BinPack2D {
|
||||
|
||||
class Size {
|
||||
|
||||
public:
|
||||
|
||||
/*const*/ int w;
|
||||
/*const*/ int h;
|
||||
|
||||
Size(int w, int h)
|
||||
: w(w),
|
||||
h(h)
|
||||
{}
|
||||
|
||||
bool operator < ( const Size &that ) const {
|
||||
|
||||
if(this->w != that.w) return this->w < that.w;
|
||||
if(this->h != that.h) return this->h < that.h;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class Coord {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::vector<Coord> Vector;
|
||||
typedef std::list<Coord> List;
|
||||
|
||||
/*const*/ int x;
|
||||
/*const*/ int y;
|
||||
/*const*/ int z;
|
||||
|
||||
Coord()
|
||||
: x(0),
|
||||
y(0),
|
||||
z(0)
|
||||
{}
|
||||
|
||||
Coord(int x, int y)
|
||||
: x(x),
|
||||
y(y),
|
||||
z(0)
|
||||
{}
|
||||
|
||||
Coord(int x, int y, int z)
|
||||
: x(x),
|
||||
y(y),
|
||||
z(z)
|
||||
{}
|
||||
|
||||
bool operator < ( const Coord &that ) const {
|
||||
|
||||
if(this->x != that.x) return this->x < that.x;
|
||||
if(this->y != that.y) return this->y < that.y;
|
||||
if(this->z != that.z) return this->z < that.z;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _T> class Content {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::vector<Content<_T> > Vector;
|
||||
|
||||
/*const*/ bool rotated;
|
||||
/*const*/ Coord coord;
|
||||
/*const*/ Size size;
|
||||
/*const*/ _T content;
|
||||
|
||||
Content( const Content<_T> &src )
|
||||
: rotated(src.rotated),
|
||||
coord(src.coord),
|
||||
size(src.size),
|
||||
content(src.content)
|
||||
{}
|
||||
|
||||
Content( const _T &content, const Coord &coord, const Size &size, bool rotated )
|
||||
:
|
||||
content(content),
|
||||
coord(coord),
|
||||
size(size),
|
||||
rotated(rotated)
|
||||
{}
|
||||
|
||||
void Rotate() {
|
||||
|
||||
rotated = !rotated;
|
||||
size = Size( size.h, size.w );
|
||||
}
|
||||
|
||||
bool intersects(const Content<_T> &that) const {
|
||||
|
||||
if(this->coord.x >= (that.coord.x + that.size.w))
|
||||
return false;
|
||||
|
||||
if(this->coord.y >= (that.coord.y + that.size.h))
|
||||
return false;
|
||||
|
||||
if(that.coord.x >= (this->coord.x + this->size.w))
|
||||
return false;
|
||||
|
||||
if(that.coord.y >= (this->coord.y + this->size.h))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _T> class Canvas {
|
||||
|
||||
Coord::List topLefts;
|
||||
typename Content<_T>::Vector contentVector;
|
||||
|
||||
bool needToSort;
|
||||
|
||||
public:
|
||||
|
||||
typedef Canvas<_T> CanvasT;
|
||||
typedef typename std::vector<CanvasT> Vector;
|
||||
|
||||
static bool Place( Vector &canvasVector, const typename Content<_T>::Vector &contentVector, typename Content<_T>::Vector &remainder ) {
|
||||
|
||||
typename Content<_T>::Vector todo = contentVector;
|
||||
|
||||
for( typename Vector::iterator itor = canvasVector.begin(); itor != canvasVector.end(); itor++ ) {
|
||||
|
||||
Canvas <_T> &canvas = *itor;
|
||||
|
||||
remainder.clear();
|
||||
canvas.Place(todo, remainder);
|
||||
todo = remainder;
|
||||
}
|
||||
|
||||
if(remainder.size()==0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool Place( Vector &canvasVector, const typename Content<_T>::Vector &contentVector ) {
|
||||
|
||||
typename Content<_T>::Vector remainder;
|
||||
|
||||
return Place( canvasVector, contentVector, remainder );
|
||||
}
|
||||
|
||||
static bool Place( Vector &canvasVector, const Content<_T> &content ) {
|
||||
|
||||
typename Content<_T>::Vector contentVector(1, content);
|
||||
|
||||
return Place( canvasVector, contentVector );
|
||||
}
|
||||
|
||||
const int w;
|
||||
const int h;
|
||||
|
||||
Canvas(int w, int h)
|
||||
: needToSort(false),
|
||||
w(w),
|
||||
h(h)
|
||||
{
|
||||
topLefts.push_back( Coord(0,0) );
|
||||
}
|
||||
|
||||
bool HasContent() const {
|
||||
|
||||
return ( contentVector.size() > 0) ;
|
||||
}
|
||||
|
||||
const typename Content<_T>::Vector &GetContents( ) const {
|
||||
|
||||
return contentVector;
|
||||
}
|
||||
|
||||
bool operator < ( const Canvas &that ) const {
|
||||
|
||||
if(this->w != that.w) return this->w < that.w;
|
||||
if(this->h != that.h) return this->h < that.h;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Place(const typename Content<_T>::Vector &contentVector, typename Content<_T>::Vector &remainder) {
|
||||
|
||||
bool placedAll = true;
|
||||
|
||||
for( typename Content<_T>::Vector::const_iterator itor = contentVector.begin(); itor != contentVector.end(); itor++ ) {
|
||||
|
||||
const Content<_T> & content = *itor;
|
||||
|
||||
if( Place( content ) == false ) {
|
||||
|
||||
placedAll = false;
|
||||
remainder.push_back( content );
|
||||
}
|
||||
}
|
||||
|
||||
return placedAll;
|
||||
}
|
||||
|
||||
bool Place(Content<_T> content) {
|
||||
|
||||
Sort();
|
||||
|
||||
for( Coord::List::iterator itor = topLefts.begin(); itor != topLefts.end(); itor++ ) {
|
||||
|
||||
content.coord = *itor;
|
||||
|
||||
if( Fits( content ) ) {
|
||||
|
||||
Use( content );
|
||||
topLefts.erase( itor );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// EXPERIMENTAL - TRY ROTATED?
|
||||
content.Rotate();
|
||||
for( Coord::List::iterator itor = topLefts.begin(); itor != topLefts.end(); itor++ ) {
|
||||
|
||||
content.coord = *itor;
|
||||
|
||||
if( Fits( content ) ) {
|
||||
|
||||
Use( content );
|
||||
topLefts.erase( itor );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
////////////////////////////////
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool Fits( const Content<_T> &content ) const {
|
||||
|
||||
if( (content.coord.x + content.size.w) > w )
|
||||
return false;
|
||||
|
||||
if( (content.coord.y + content.size.h) > h )
|
||||
return false;
|
||||
|
||||
for( typename Content<_T>::Vector::const_iterator itor = contentVector.begin(); itor != contentVector.end(); itor++ )
|
||||
if( content.intersects( *itor ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Use(const Content<_T> &content) {
|
||||
|
||||
const Size &size = content.size;
|
||||
const Coord &coord = content.coord;
|
||||
|
||||
topLefts.push_front ( Coord( coord.x + size.w, coord.y ) );
|
||||
topLefts.push_back ( Coord( coord.x , coord.y + size.h ) );
|
||||
|
||||
contentVector.push_back( content );
|
||||
|
||||
needToSort = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct TopToBottomLeftToRightSort {
|
||||
|
||||
bool operator()(const Coord &a, const Coord &b) const {
|
||||
|
||||
return ( a.x * a.x + a.y * a.y ) < ( b.x * b.x + b.y * b.y );
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
void Sort() {
|
||||
|
||||
if(!needToSort)
|
||||
return;
|
||||
|
||||
topLefts.sort(TopToBottomLeftToRightSort());
|
||||
|
||||
needToSort = false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _T> class ContentAccumulator {
|
||||
|
||||
typename Content<_T>::Vector contentVector;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
ContentAccumulator()
|
||||
{}
|
||||
|
||||
const typename Content<_T>::Vector &Get() const {
|
||||
|
||||
return contentVector;
|
||||
}
|
||||
|
||||
typename Content<_T>::Vector &Get() {
|
||||
|
||||
return contentVector;
|
||||
}
|
||||
|
||||
ContentAccumulator<_T>& operator += ( const Content<_T> & content ) {
|
||||
|
||||
contentVector.push_back( content );
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ContentAccumulator<_T>& operator += ( const typename Content<_T>::Vector & content ) {
|
||||
|
||||
contentVector.insert( contentVector.end(), content.begin(), content.end() );
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ContentAccumulator<_T> operator + ( const Content<_T> & content ) {
|
||||
|
||||
ContentAccumulator<_T> temp = *this;
|
||||
|
||||
temp += content;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
ContentAccumulator<_T> operator + ( const typename Content<_T>::Vector & content ) {
|
||||
|
||||
ContentAccumulator<_T> temp = *this;
|
||||
|
||||
temp += content;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
struct GreatestWidthThenGreatestHeightSort {
|
||||
|
||||
bool operator()(const Content<_T> &a, const Content<_T> &b) const {
|
||||
|
||||
const Size &sa = a.size;
|
||||
const Size &sb = b.size;
|
||||
|
||||
// return( sa.w * sa.h > sb.w * sb.h );
|
||||
|
||||
if(sa.w != sb.w)
|
||||
return sa.w > sb.w;
|
||||
return sa.h > sb.h;
|
||||
}
|
||||
};
|
||||
|
||||
struct MakeHorizontal {
|
||||
|
||||
Content<_T> operator()( const Content<_T> &elem) {
|
||||
|
||||
if(elem.size.h > elem.size.w)
|
||||
{
|
||||
Content<_T> r = elem;
|
||||
|
||||
r.size.w = elem.size.h;
|
||||
r.size.h = elem.size.w;
|
||||
r.rotated = !elem.rotated;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
void Sort() {
|
||||
|
||||
// if(allow_rotation)
|
||||
// std::transform(contentVector.begin(), contentVector.end(), contentVector.begin(), MakeHorizontal());
|
||||
|
||||
std::sort( contentVector.begin(), contentVector.end(), GreatestWidthThenGreatestHeightSort() );
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _T> class UniformCanvasArrayBuilder {
|
||||
|
||||
int w;
|
||||
int h;
|
||||
int d;
|
||||
|
||||
public:
|
||||
|
||||
UniformCanvasArrayBuilder( int w, int h, int d )
|
||||
: w(w),
|
||||
h(h),
|
||||
d(d)
|
||||
{}
|
||||
|
||||
typename Canvas<_T>::Vector Build() {
|
||||
|
||||
return typename Canvas<_T>::Vector(d, Canvas<_T>(w, h) );
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _T> class CanvasArray {
|
||||
|
||||
typename Canvas<_T>::Vector canvasArray;
|
||||
|
||||
public:
|
||||
CanvasArray() {
|
||||
|
||||
}
|
||||
CanvasArray( const typename Canvas<_T>::Vector &canvasArray )
|
||||
: canvasArray( canvasArray )
|
||||
{}
|
||||
|
||||
bool Place(const typename Content<_T>::Vector &contentVector, typename Content<_T>::Vector &remainder) {
|
||||
|
||||
return Canvas<_T>::Place( canvasArray, contentVector, remainder );
|
||||
}
|
||||
|
||||
bool Place(const ContentAccumulator<_T> &content, ContentAccumulator<_T> &remainder) {
|
||||
|
||||
return Place( content.Get(), remainder.Get() );
|
||||
}
|
||||
|
||||
bool Place(const typename Content<_T>::Vector &contentVector) {
|
||||
|
||||
return Canvas<_T>::Place( canvasArray, contentVector );
|
||||
}
|
||||
|
||||
bool Place(const ContentAccumulator<_T> &content) {
|
||||
|
||||
return Place( content.Get() );
|
||||
}
|
||||
|
||||
bool CollectContent( typename Content<_T>::Vector &contentVector ) const {
|
||||
|
||||
int z = 0;
|
||||
|
||||
for( typename Canvas<_T>::Vector::const_iterator itor = canvasArray.begin(); itor != canvasArray.end(); itor++ ) {
|
||||
|
||||
const typename Content<_T>::Vector &contents = itor->GetContents();
|
||||
|
||||
for( typename Content<_T>::Vector::const_iterator itor = contents.begin(); itor != contents.end(); itor++ ) {
|
||||
|
||||
Content<_T> content = *itor;
|
||||
|
||||
content.coord.z = z;
|
||||
|
||||
contentVector.push_back( content );
|
||||
}
|
||||
z++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CollectContent( ContentAccumulator<_T> &content) const {
|
||||
|
||||
return CollectContent( content.Get() );
|
||||
}
|
||||
};
|
||||
|
||||
} /*** BinPack2D ***/
|
||||
@ -7,6 +7,8 @@
|
||||
#include <typeindex>
|
||||
#include <functional>
|
||||
|
||||
#define UF_INSTANTIATOR_ANNOUNCE 0
|
||||
|
||||
namespace pod {
|
||||
struct UF_API Instantiator {
|
||||
typedef std::function<uf::Entity*()> function_t;
|
||||
|
||||
@ -45,7 +45,7 @@ template<typename T> void uf::instantiator::registerObject( const std::string& n
|
||||
.function = _instantiate<T>
|
||||
});
|
||||
|
||||
std::cout << "Registered instantiation for " << name << std::endl;
|
||||
if ( UF_INSTANTIATOR_ANNOUNCE ) std::cout << "Registered instantiation for " << name << std::endl;
|
||||
}
|
||||
template<typename T> void uf::instantiator::registerBehavior( const std::string& name ) {
|
||||
if ( !behaviors ) behaviors = new pod::NamedTypes<pod::Behavior>;
|
||||
@ -58,7 +58,7 @@ template<typename T> void uf::instantiator::registerBehavior( const std::string&
|
||||
.destroy = T::destroy,
|
||||
});
|
||||
|
||||
std::cout << "Registered behavior for " << name << std::endl;
|
||||
if ( UF_INSTANTIATOR_ANNOUNCE ) std::cout << "Registered behavior for " << name << std::endl;
|
||||
}
|
||||
|
||||
template<typename T> void uf::instantiator::registerBinding( const std::string& name ) {
|
||||
@ -67,7 +67,7 @@ template<typename T> void uf::instantiator::registerBinding( const std::string&
|
||||
auto& instantiator = container.get<T>();
|
||||
instantiator.behaviors.emplace_back(name);
|
||||
|
||||
std::cout << "Registered binding for " << name << std::endl;
|
||||
if ( UF_INSTANTIATOR_ANNOUNCE ) std::cout << "Registered binding for " << name << std::endl;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <uf/engine/object/object.h>
|
||||
#include <uf/utils/graphic/mesh.h>
|
||||
|
||||
namespace ext {
|
||||
namespace gltf {
|
||||
typedef uf::BaseMesh<pod::Vertex_3F2F3F1UI, uint32_t> mesh_t;
|
||||
enum LoadMode {
|
||||
GENERATE_NORMALS = 0x1 << 0,
|
||||
APPLY_TRANSFORMS = 0x1 << 1,
|
||||
@ -11,7 +13,8 @@ namespace ext {
|
||||
RENDER = 0x1 << 3,
|
||||
COLLISION = 0x1 << 4,
|
||||
AABB = 0x1 << 5,
|
||||
THREADED = 0x1 << 6,
|
||||
DEFER_INIT = 0x1 << 6,
|
||||
USE_ATLAS = 0x1 << 7,
|
||||
};
|
||||
bool UF_API load( uf::Object&, const std::string&, uint8_t = LoadMode::GENERATE_NORMALS | LoadMode::RENDER );
|
||||
}
|
||||
|
||||
@ -24,7 +24,8 @@ namespace ext {
|
||||
|
||||
std::vector<uf::Userdata> pushConstants;
|
||||
// std::vector<uf::Userdata> specializationConstants;
|
||||
uf::Userdata specializationConstants;
|
||||
// uf::Userdata specializationConstants;
|
||||
std::vector<uint8_t> specializationConstants;
|
||||
std::vector<uf::Userdata> uniforms;
|
||||
|
||||
// ~Shader();
|
||||
@ -94,7 +95,7 @@ namespace ext {
|
||||
void destroy();
|
||||
|
||||
template<typename T, typename U>
|
||||
void initializeGeometry( uf::BaseMesh<T, U>& mesh );
|
||||
void initializeGeometry( uf::BaseMesh<T, U>& mesh, bool = false );
|
||||
|
||||
bool hasPipeline( Descriptor& descriptor );
|
||||
void initializePipeline();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
template<typename T, typename U>
|
||||
void ext::vulkan::Graphic::initializeGeometry( uf::BaseMesh<T, U>& mesh ) {
|
||||
void ext::vulkan::Graphic::initializeGeometry( uf::BaseMesh<T, U>& mesh, bool stage ) {
|
||||
if ( mesh.indices.empty() ) mesh.initialize();
|
||||
mesh.updateDescriptor();
|
||||
|
||||
@ -13,13 +13,13 @@ void ext::vulkan::Graphic::initializeGeometry( uf::BaseMesh<T, U>& mesh ) {
|
||||
(void*) mesh.vertices.data(),
|
||||
mesh.vertices.size() * mesh.sizes.vertex,
|
||||
0,
|
||||
false
|
||||
stage
|
||||
);
|
||||
updateBuffer(
|
||||
(void*) mesh.indices.data(),
|
||||
mesh.indices.size() * mesh.sizes.indices,
|
||||
0,
|
||||
false
|
||||
stage
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -38,13 +38,13 @@ void ext::vulkan::Graphic::initializeGeometry( uf::BaseMesh<T, U>& mesh ) {
|
||||
mesh.vertices.size() * mesh.sizes.vertex,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, //VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
false
|
||||
stage
|
||||
);
|
||||
initializeBuffer(
|
||||
(void*) mesh.indices.data(),
|
||||
mesh.indices.size() * mesh.sizes.indices,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, //VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
false
|
||||
stage
|
||||
);
|
||||
}
|
||||
@ -43,6 +43,10 @@ namespace uf {
|
||||
void setPitch( ALfloat );
|
||||
ALfloat getGain();
|
||||
void setGain( ALfloat );
|
||||
ALfloat getRolloffFactor();
|
||||
void setRolloffFactor( ALfloat );
|
||||
ALfloat getMaxDistance();
|
||||
void setMaxDistance( ALfloat );
|
||||
|
||||
float getVolume() const;
|
||||
const std::string& getFilename() const;
|
||||
|
||||
@ -24,6 +24,38 @@ namespace pod {
|
||||
}
|
||||
bool operator!=( const Vertex_3F2F3F32B& that ) const { return !(*this == that); }
|
||||
|
||||
};
|
||||
struct /*UF_API*/ Vertex_3F3F3F {
|
||||
alignas(16) pod::Vector3f position;
|
||||
alignas(16) pod::Vector3f uv;
|
||||
alignas(16) pod::Vector3f normal;
|
||||
|
||||
static UF_API std::vector<ext::vulkan::VertexDescriptor> descriptor;
|
||||
|
||||
bool operator==( const Vertex_3F3F3F& that ) const {
|
||||
return this->position == that.position &&
|
||||
this->normal == that.normal &&
|
||||
this->uv == that.uv;
|
||||
}
|
||||
bool operator!=( const Vertex_3F3F3F& that ) const { return !(*this == that); }
|
||||
|
||||
};
|
||||
struct /*UF_API*/ Vertex_3F2F3F1UI {
|
||||
alignas(16) pod::Vector3f position;
|
||||
alignas(8) pod::Vector2f uv;
|
||||
alignas(16) pod::Vector3f normal;
|
||||
alignas(4) uint32_t id;
|
||||
|
||||
static UF_API std::vector<ext::vulkan::VertexDescriptor> descriptor;
|
||||
|
||||
bool operator==( const Vertex_3F2F3F1UI& that ) const {
|
||||
return this->position == that.position &&
|
||||
this->normal == that.normal &&
|
||||
this->uv == that.uv &&
|
||||
this->id == that.id;
|
||||
}
|
||||
bool operator!=( const Vertex_3F2F3F1UI& that ) const { return !(*this == that); }
|
||||
|
||||
};
|
||||
struct /*UF_API*/ Vertex_3F2F3F {
|
||||
alignas(16) pod::Vector3f position;
|
||||
@ -87,6 +119,27 @@ namespace std {
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
template<> struct hash<pod::Vertex_3F2F3F1UI> {
|
||||
size_t operator()(pod::Vertex_3F2F3F1UI const& vertex) const {
|
||||
std::size_t seed = 3 + 2 + 3 + 1;
|
||||
std::hash<float> hasher;
|
||||
for ( size_t i = 0; i < 3; ++i ) seed ^= hasher( vertex.position[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
for ( size_t i = 0; i < 3; ++i ) seed ^= hasher( vertex.normal[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
for ( size_t i = 0; i < 2; ++i ) seed ^= hasher( vertex.uv[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
seed ^= hasher( (float) vertex.id ) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
template<> struct hash<pod::Vertex_3F3F3F> {
|
||||
size_t operator()(pod::Vertex_3F3F3F const& vertex) const {
|
||||
std::size_t seed = 3 + 3 + 3;
|
||||
std::hash<float> hasher;
|
||||
for ( size_t i = 0; i < 3; ++i ) seed ^= hasher( vertex.position[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
for ( size_t i = 0; i < 3; ++i ) seed ^= hasher( vertex.normal[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
for ( size_t i = 0; i < 3; ++i ) seed ^= hasher( vertex.uv[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
template<> struct hash<pod::Vertex_3F2F3F> {
|
||||
size_t operator()(pod::Vertex_3F2F3F const& vertex) const {
|
||||
std::size_t seed = 3 + 3 + 2;
|
||||
|
||||
33
engine/inc/uf/utils/image/atlas.h
Normal file
33
engine/inc/uf/utils/image/atlas.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <uf/utils/image/image.h>
|
||||
#include <binpack2d/binpack2d.hpp>
|
||||
|
||||
namespace uf {
|
||||
class UF_API Atlas {
|
||||
public:
|
||||
struct Identifier {
|
||||
size_t index;
|
||||
};
|
||||
typedef std::vector<uf::Image> images_t;
|
||||
typedef Identifier identifier_t;
|
||||
typedef BinPack2D::CanvasArray<identifier_t> atlas_t;
|
||||
protected:
|
||||
uf::Image m_image;
|
||||
images_t m_images;
|
||||
atlas_t m_atlas;
|
||||
public:
|
||||
void addImage( const uf::Image&, bool = false );
|
||||
void addImage( uf::Image&&, bool = false );
|
||||
void addImage( const uint8_t*, const pod::Vector2ui&, std::size_t, std::size_t, bool = false, bool = false );
|
||||
|
||||
void generate();
|
||||
|
||||
pod::Vector2f mapUv( const pod::Vector2f&, size_t );
|
||||
pod::Vector3f mapUv( const pod::Vector3f& );
|
||||
|
||||
uf::Image& getAtlas();
|
||||
images_t& getImages();
|
||||
const images_t& getImages() const;
|
||||
};
|
||||
}
|
||||
@ -50,6 +50,7 @@ namespace uf {
|
||||
std::size_t getChannels() const;
|
||||
Image::pixel_t at( const Image::vec2_t& at );
|
||||
// Modifiers
|
||||
void flip();
|
||||
void padToPowerOfTwo();
|
||||
bool save( const std::string& filename, bool flip = false ); // to file
|
||||
void save( std::ostream& stream ); // to stream
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include <uf/utils/serialize/serializer.h>
|
||||
#include <uf/utils/string/ext.h>
|
||||
#include <uf/utils/thread/thread.h>
|
||||
#include <uf/ext/gltf/gltf.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
@ -86,6 +87,7 @@ void uf::Asset::processQueue() {
|
||||
continue;
|
||||
}
|
||||
std::string filename = type == "cache" ? this->cache(uri) : this->load(uri);
|
||||
// uf::iostream << "Parsed `" + filename + "` (" + type + "). Callback: " + callback << "\n";
|
||||
if ( callback != "" ) {
|
||||
uf::Serializer payload;
|
||||
payload["filename"] = filename;
|
||||
@ -174,44 +176,51 @@ std::string uf::Asset::load( const std::string& uri ) {
|
||||
uf::iostream << "Failed to load `" + filename + "`: Does not exist" << "\n";
|
||||
return "";
|
||||
}
|
||||
#define UF_ASSET_REGISTER(type)\
|
||||
auto& container = this->getContainer<type>();\
|
||||
if ( !map[extension][uri].isNull() ) return filename;\
|
||||
if ( !map[extension][filename].isNull() ) return filename;\
|
||||
map[extension][uri] = container.size();\
|
||||
map[extension][filename] = container.size();\
|
||||
type& asset = container.emplace_back();
|
||||
|
||||
// deduce PNG, load as texture
|
||||
auto& map = masterAssetLoader.getComponent<uf::Serializer>();
|
||||
if ( extension == "png" ) {
|
||||
auto& container = this->getContainer<uf::Image>();
|
||||
|
||||
if ( !map[extension][uri].isNull() ) return filename;
|
||||
if ( !map[extension][filename].isNull() ) return filename;
|
||||
|
||||
map[extension][uri] = container.size();
|
||||
map[extension][filename] = container.size();
|
||||
|
||||
uf::Image& image = container.emplace_back();
|
||||
image.open(filename);
|
||||
UF_ASSET_REGISTER(uf::Image)
|
||||
asset.open(filename);
|
||||
} else if ( extension == "ogg" ) {
|
||||
auto& container = this->getContainer<uf::Audio>();
|
||||
|
||||
if ( !map[extension][uri].isNull() ) return filename;
|
||||
if ( !map[extension][filename].isNull() ) return filename;
|
||||
|
||||
map[extension][uri] = container.size();
|
||||
map[extension][filename] = container.size();
|
||||
|
||||
uf::Audio& audio = container.emplace_back();
|
||||
audio.load(filename);
|
||||
UF_ASSET_REGISTER(uf::Audio)
|
||||
asset.load(filename);
|
||||
} else if ( extension == "json" ) {
|
||||
auto& container = this->getContainer<uf::Serializer>();
|
||||
UF_ASSET_REGISTER(uf::Serializer)
|
||||
asset.readFromFile(filename);
|
||||
} else if ( extension == "gltf" || extension == "glb" ) {
|
||||
UF_ASSET_REGISTER(uf::Object*)
|
||||
uint8_t LOAD_FLAGS = 0;
|
||||
|
||||
if ( !map[extension][uri].isNull() ) return filename;
|
||||
if ( !map[extension][filename].isNull() ) return filename;
|
||||
asset = &uf::instantiator::instantiate<uf::Object>();
|
||||
|
||||
map[extension][uri] = container.size();
|
||||
map[extension][filename] = container.size();
|
||||
auto& metadata = this->getComponent<uf::Serializer>();
|
||||
|
||||
uf::Serializer& json = container.emplace_back();
|
||||
json.readFromFile(filename);
|
||||
#define LOAD_FLAG(name)\
|
||||
if ( metadata[uri]["flags"][#name].asBool() )\
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::name;
|
||||
|
||||
LOAD_FLAG(GENERATE_NORMALS); // 0x1 << 0;
|
||||
LOAD_FLAG(APPLY_TRANSFORMS); // 0x1 << 1;
|
||||
LOAD_FLAG(SEPARATE_MESHES); // 0x1 << 2;
|
||||
LOAD_FLAG(RENDER); // 0x1 << 3;
|
||||
LOAD_FLAG(COLLISION); // 0x1 << 4;
|
||||
LOAD_FLAG(AABB); // 0x1 << 5;
|
||||
LOAD_FLAG(DEFER_INIT); // 0x1 << 6;
|
||||
LOAD_FLAG(USE_ATLAS); // 0x1 << 7;
|
||||
|
||||
ext::gltf::load( *asset, filename, LOAD_FLAGS );
|
||||
} else {
|
||||
uf::iostream << "Failed to parse `" + filename + "`: Unimplemented extension: " + extension << "\n";
|
||||
}
|
||||
// uf::iostream << "Parsed URI: `" + uri + "` -> `" + filename + "`" << "\n";
|
||||
return filename;
|
||||
}
|
||||
std::string uf::Asset::getOriginal( const std::string& uri ) {
|
||||
|
||||
@ -46,7 +46,7 @@ void uf::instantiator::registerBinding( const std::string& object, const std::st
|
||||
auto& instantiator = uf::instantiator::objects->get( object );
|
||||
instantiator.behaviors.emplace_back( behavior );
|
||||
|
||||
std::cout << "Registered binding: " << object << " and " << behavior << ": " << instantiator.behaviors.size() << std::endl;
|
||||
if ( UF_INSTANTIATOR_ANNOUNCE ) std::cout << "Registered binding: " << object << " and " << behavior << ": " << instantiator.behaviors.size() << std::endl;
|
||||
}
|
||||
|
||||
uf::Entity& uf::instantiator::instantiate( const std::string& name ) {
|
||||
|
||||
@ -12,36 +12,53 @@
|
||||
|
||||
UF_BEHAVIOR_ENTITY_CPP_BEGIN(Object)
|
||||
#define this (&self)
|
||||
void uf::ObjectBehavior::initialize( uf::Object& self ) {
|
||||
/*
|
||||
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
|
||||
if ( metadata["system"]["type"].isNull() || metadata["system"]["defaults"]["asset load"].asBool() ) {
|
||||
// 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) != "glb" ) return "false";
|
||||
int8_t LOAD_FLAGS = 0;
|
||||
if ( metadata["model"]["flags"]["GENERATE_NORMALS"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::GENERATE_NORMALS; // 0x1 << 0;
|
||||
if ( metadata["model"]["flags"]["APPLY_TRANSFORMS"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::APPLY_TRANSFORMS; // 0x1 << 1;
|
||||
if ( metadata["model"]["flags"]["SEPARATE_MESHES"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::SEPARATE_MESHES; // 0x1 << 2;
|
||||
if ( metadata["model"]["flags"]["RENDER"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::RENDER; // 0x1 << 3;
|
||||
if ( metadata["model"]["flags"]["COLLISION"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::COLLISION; // 0x1 << 4;
|
||||
if ( metadata["model"]["flags"]["AABB"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::AABB; // 0x1 << 5;
|
||||
|
||||
ext::gltf::load( *this, filename, LOAD_FLAGS );
|
||||
std::cout << this->getName() << ": " << this->getUid() << " finished loading " << filename << std::endl;
|
||||
return "true";
|
||||
});
|
||||
void uf::ObjectBehavior::initialize( uf::Object& self ) {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& assetLoader = scene.getComponent<uf::Asset>();
|
||||
auto& metadata = this->getComponent<uf::Serializer>();
|
||||
/*
|
||||
size_t target = 0;
|
||||
for ( int i = 0; i < metadata["system"]["assets"].size(); ++i ) {
|
||||
std::string filename = metadata["system"]["assets"][i].isObject() ? metadata["system"]["assets"][i]["filename"].asString() : metadata["system"]["assets"][i].asString();
|
||||
if ( uf::io::extension(filename) != "json" ) ++target;
|
||||
}
|
||||
if ( target > 0 ) {
|
||||
metadata["system"]["load"]["progress"] = 0;
|
||||
metadata["system"]["load"]["total"] = target;
|
||||
}
|
||||
*/
|
||||
|
||||
//
|
||||
{
|
||||
size_t assets = metadata["system"]["assets"].size();
|
||||
metadata["system"]["load"]["progress"] = 0;
|
||||
metadata["system"]["load"]["total"] = assets;
|
||||
if ( assets == 0 ) {
|
||||
auto& parent = this->getParent().as<uf::Object>();
|
||||
uf::Serializer payload;
|
||||
payload["uid"] = this->getUid();
|
||||
parent.callHook("asset:Parsed.%UID%", payload);
|
||||
}
|
||||
}
|
||||
|
||||
this->addHook( "asset:QueueLoad.%UID%", [&](const std::string& event)->std::string{
|
||||
uf::Serializer json = event;
|
||||
std::string filename = json["filename"].asString();
|
||||
std::string callback = "asset:FinishedLoad." + std::to_string(this->getUid());
|
||||
if ( json["single threaded"].asBool() ) {
|
||||
assetLoader.load( filename );
|
||||
this->queueHook( callback, event );
|
||||
} else {
|
||||
assetLoader.load( filename, callback );
|
||||
}
|
||||
|
||||
return "true";
|
||||
});
|
||||
this->addHook( "asset:FinishedLoad.%UID%", [&](const std::string& event)->std::string{
|
||||
this->queueHook("asset:Load.%UID%", event);
|
||||
this->queueHook("asset:Parsed.%UID%", event);
|
||||
return "true";
|
||||
});
|
||||
this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{
|
||||
uf::Serializer json = event;
|
||||
std::string filename = json["filename"].asString();
|
||||
@ -59,6 +76,32 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
|
||||
|
||||
return "true";
|
||||
});
|
||||
this->addHook( "asset:Parsed.%UID%", [&](const std::string& event)->std::string{
|
||||
uf::Serializer json = event;
|
||||
int portion = 1;
|
||||
auto& total = metadata["system"]["load"]["total"];
|
||||
auto& progress = metadata["system"]["load"]["progress"];
|
||||
progress = progress.asInt() + portion;
|
||||
if ( progress.asInt() == total.asInt() ) {
|
||||
auto& parent = this->getParent().as<uf::Object>();
|
||||
|
||||
uf::Serializer payload;
|
||||
payload["uid"] = this->getUid();
|
||||
parent.callHook("asset:Parsed.%UID%", payload);
|
||||
}
|
||||
/*
|
||||
float portion = 1.0f / metadata["system"]["load"]["total"].asFloat();
|
||||
auto& progress = metadata["system"]["load"]["progress"];
|
||||
progress = progress.asFloat() + portion;
|
||||
*/
|
||||
/*
|
||||
if ( metadata["system"]["loaded"].asBool() ) return "false";
|
||||
if ( progress.asFloat() >= 1.0f ) {
|
||||
this->queueHook("system:Load.Finished.%UID%");
|
||||
}
|
||||
*/
|
||||
return "true";
|
||||
});
|
||||
}
|
||||
void uf::ObjectBehavior::destroy( uf::Object& self ) {
|
||||
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
|
||||
|
||||
@ -17,30 +17,47 @@ UF_BEHAVIOR_REGISTER_CPP(GltfBehavior)
|
||||
void uf::GltfBehavior::initialize( uf::Object& self ) {
|
||||
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
|
||||
// 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) != "gltf" && uf::io::extension(filename) != "glb" ) return "false";
|
||||
int8_t LOAD_FLAGS = 0;
|
||||
if ( metadata["model"]["flags"]["GENERATE_NORMALS"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::GENERATE_NORMALS; // 0x1 << 0;
|
||||
if ( metadata["model"]["flags"]["APPLY_TRANSFORMS"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::APPLY_TRANSFORMS; // 0x1 << 1;
|
||||
if ( metadata["model"]["flags"]["SEPARATE_MESHES"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::SEPARATE_MESHES; // 0x1 << 2;
|
||||
if ( metadata["model"]["flags"]["RENDER"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::RENDER; // 0x1 << 3;
|
||||
if ( metadata["model"]["flags"]["COLLISION"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::COLLISION; // 0x1 << 4;
|
||||
if ( metadata["model"]["flags"]["AABB"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::AABB; // 0x1 << 5;
|
||||
if ( metadata["model"]["flags"]["THREADED"].asBool() )
|
||||
LOAD_FLAGS |= ext::gltf::LoadMode::THREADED; // 0x1 << 6;
|
||||
|
||||
ext::gltf::load( *this, filename, LOAD_FLAGS );
|
||||
|
||||
uf::Scene& scene = uf::scene::getCurrentScene();
|
||||
uf::Asset& assetLoader = scene.getComponent<uf::Asset>();
|
||||
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 ) {
|
||||
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);
|
||||
|
||||
graphic.process = true;
|
||||
|
||||
auto& shader = graphic.material.shaders.back();
|
||||
struct SpecializationConstant {
|
||||
uint32_t textures = 1;
|
||||
};
|
||||
auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0];
|
||||
specializationConstants->textures = graphic.material.textures.size();
|
||||
|
||||
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
|
||||
if ( binding.descriptorCount > 1 )
|
||||
binding.descriptorCount = specializationConstants->textures;
|
||||
}
|
||||
};
|
||||
objectPointer->process(filter);
|
||||
|
||||
this->addChild(objectPointer->as<uf::Entity>());
|
||||
objectPointer->initialize();
|
||||
|
||||
return "true";
|
||||
});
|
||||
}
|
||||
|
||||
@ -14,22 +14,43 @@
|
||||
|
||||
UF_BEHAVIOR_REGISTER_CPP(LoadingBehavior)
|
||||
#define this (&self)
|
||||
void uf::LoadingBehavior::initialize( uf::Object& self ) {
|
||||
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
|
||||
|
||||
size_t target = 0;
|
||||
for ( int i = 0; i < metadata["system"]["assets"].size(); ++i ) {
|
||||
std::string filename = metadata["system"]["assets"][i].asString();
|
||||
if ( uf::io::extension(filename) != "json" ) ++target;
|
||||
}
|
||||
if ( target > 0 ) {
|
||||
metadata["system"]["load"]["progress"] = 0;
|
||||
metadata["system"]["load"]["total"] = target;
|
||||
}
|
||||
|
||||
void uf::LoadingBehavior::initialize( uf::Object& self ) {
|
||||
auto& metadata = this->getComponent<uf::Serializer>();
|
||||
/*
|
||||
this->addHook( "asset:Parsed.%UID%", [&](const std::string& event)->std::string{
|
||||
uf::Serializer json = event;
|
||||
int portion = 1;
|
||||
auto& total = metadata["system"]["load"]["total"];
|
||||
auto& progress = metadata["system"]["load"]["progress"];
|
||||
if ( json["uid"].isNull() ) return "false";
|
||||
// progress = progress.asInt() + portion;
|
||||
if ( progress.asInt() == total.asInt() ) {
|
||||
auto& parent = this->getParent().as<uf::Object>();
|
||||
parent.callHook("asset:Parsed.%UID%");
|
||||
}
|
||||
return "true";
|
||||
});
|
||||
*/
|
||||
/*
|
||||
this->addHook( "system:Load.Finished.%UID%", [&](const std::string& event)->std::string{
|
||||
std::cout << "FINISHED LOADING" << std::endl;
|
||||
uf::Serializer json = event;
|
||||
auto& parent = this->getParent();
|
||||
// unbind all children
|
||||
for ( auto* child : this->getChildren() ) {
|
||||
this->removeChild(*child);
|
||||
parent.addChild(*child);
|
||||
}
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
uf::Serializer payload;
|
||||
payload["uid"] = this->getUid();
|
||||
parent.removeChild(*this);
|
||||
scene.queueHook("system:Destroy", payload);
|
||||
return "true";
|
||||
});
|
||||
*/
|
||||
this->addHook( "system:Load.Finished.%UID%", [&](const std::string& event)->std::string{
|
||||
uf::Serializer json = event;
|
||||
|
||||
|
||||
metadata["system"]["loaded"] = true;
|
||||
this->removeBehavior<uf::LoadingBehavior>();
|
||||
@ -52,31 +73,6 @@ void uf::LoadingBehavior::initialize( uf::Object& self ) {
|
||||
|
||||
scene.queueHook("system:Destroy", payload);
|
||||
}
|
||||
/*
|
||||
auto& parent = this->getParent();
|
||||
// unbind all children
|
||||
for ( auto* child : this->getChildren() ) {
|
||||
this->removeChild(*child);
|
||||
parent.addChild(*child);
|
||||
}
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
if ( parent.getUid() != scene.getUid() ) {
|
||||
uf::Serializer payload;
|
||||
payload["uid"] = parent.getUid();
|
||||
parent.removeChild(*this);
|
||||
scene.queueHook("system:Destroy", payload);
|
||||
}
|
||||
*/
|
||||
|
||||
return "true";
|
||||
});
|
||||
this->addHook( "asset:Parsed.%UID%", [&](const std::string& event)->std::string{
|
||||
uf::Serializer json = event;
|
||||
|
||||
float portion = 1.0f / metadata["system"]["load"]["total"].asFloat();
|
||||
auto& progress = metadata["system"]["load"]["progress"];
|
||||
progress = progress.asFloat() + portion;
|
||||
|
||||
return "true";
|
||||
});
|
||||
}
|
||||
@ -85,8 +81,25 @@ void uf::LoadingBehavior::destroy( uf::Object& self ) {
|
||||
}
|
||||
void uf::LoadingBehavior::tick( uf::Object& self ) {
|
||||
auto& metadata = this->getComponent<uf::Serializer>();
|
||||
// if ( this->getChildren().empty() ) return;
|
||||
/* Check if we're a loading screen */ if ( !metadata["system"]["loaded"].asBool() ) {
|
||||
if ( metadata["system"]["loaded"].asBool() ) return;
|
||||
size_t loading = 0;
|
||||
size_t loaded = 1;
|
||||
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
|
||||
if ( !entity || entity->getUid() == 0 || !entity->hasComponent<uf::Serializer>() ) return;
|
||||
auto& metadata = entity->getComponent<uf::Serializer>();
|
||||
if ( metadata["system"]["load"].isNull() ) return;
|
||||
++loading;
|
||||
if ( metadata["system"]["load"]["progress"].asInt() < metadata["system"]["load"]["total"].asInt() ) return;
|
||||
++loaded;
|
||||
};
|
||||
this->process(filter);
|
||||
if ( loading == loaded ) {
|
||||
metadata["system"]["loaded"] = true;
|
||||
this->callHook("system:Load.Finished.%UID%");
|
||||
}
|
||||
/*
|
||||
auto& metadata = this->getComponent<uf::Serializer>();
|
||||
if ( !metadata["system"]["loaded"].asBool() ) {
|
||||
size_t loading = 0;
|
||||
size_t loaded = 0;
|
||||
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
|
||||
@ -102,7 +115,12 @@ void uf::LoadingBehavior::tick( uf::Object& self ) {
|
||||
if ( loading == loaded ) {
|
||||
this->callHook("system:Load.Finished.%UID%");
|
||||
}
|
||||
auto& metadata = this->getComponent<uf::Serializer>();
|
||||
if ( metadata["system"]["load"]["progress"].asFloat() >= 1.0f ) {
|
||||
this->callHook("system:Load.Finished.%UID%");
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
void uf::LoadingBehavior::render( uf::Object& self ) {
|
||||
|
||||
|
||||
@ -180,10 +180,24 @@ bool uf::Object::load( const uf::Serializer& _json ) {
|
||||
}
|
||||
}
|
||||
|
||||
uf::Scene& scene = this->getRootParent<uf::Scene>();
|
||||
uf::Scene& scene = uf::scene::getCurrentScene();
|
||||
uf::Asset& assetLoader = scene.getComponent<uf::Asset>();
|
||||
// initialize base entity, needed for asset hooks
|
||||
|
||||
#define UF_OBJECT_LOAD_ASSET(...)\
|
||||
std::string canonical = "";\
|
||||
std::string f = target[i].isObject() ? target[i]["filename"].asString() : target[i].asString();\
|
||||
float delay = target[i].isObject() ? target[i]["delay"].asFloat() : 0;\
|
||||
std::string filename = grabURI( f, json["root"].asString() );\
|
||||
bool singleThreaded = target[i].isObject() ? target[i]["single threaded"].asBool() : false;\
|
||||
std::vector<std::string> allowedExtensions = {__VA_ARGS__};\
|
||||
if ( std::find( allowedExtensions.begin(), allowedExtensions.end(), uf::io::extension(filename) ) == allowedExtensions.end() ) continue;\
|
||||
uf::Serializer payload;\
|
||||
payload["filename"] = filename;\
|
||||
payload["single threaded"] = singleThreaded;\
|
||||
this->queueHook( "asset:QueueLoad.%UID%", payload, delay );\
|
||||
|
||||
|
||||
// Audio (singular)
|
||||
{
|
||||
// find first valid texture in asset list
|
||||
@ -196,15 +210,7 @@ bool uf::Object::load( const uf::Serializer& _json ) {
|
||||
target = json["assets"]["audio"];
|
||||
}
|
||||
for ( uint i = 0; i < target.size(); ++i ) {
|
||||
std::string canonical = "";
|
||||
std::string f = target[i].isObject() ? target[i]["filename"].asString() : target[i].asString();
|
||||
float delay = target[i].isObject() ? target[i]["delay"].asFloat() : 0;
|
||||
std::string filename = grabURI( f, json["root"].asString() );
|
||||
if ( uf::io::extension(filename) != "ogg" ) continue;
|
||||
if ( (canonical = assetLoader.load( filename )) == "" ) continue;
|
||||
uf::Serializer payload;
|
||||
payload["filename"] = canonical;
|
||||
this->queueHook( "asset:Load.%UID%", payload, delay );
|
||||
UF_OBJECT_LOAD_ASSET("ogg")
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,15 +226,7 @@ bool uf::Object::load( const uf::Serializer& _json ) {
|
||||
target = json["assets"]["textures"];
|
||||
}
|
||||
for ( uint i = 0; i < target.size(); ++i ) {
|
||||
std::string canonical = "";
|
||||
std::string f = target[i].isObject() ? target[i]["filename"].asString() : target[i].asString();
|
||||
float delay = target[i].isObject() ? target[i]["delay"].asFloat() : 0;
|
||||
std::string filename = grabURI( f, json["root"].asString() );
|
||||
if ( uf::io::extension(filename) != "png" ) continue;
|
||||
if ( (canonical = assetLoader.load( filename )) == "" ) continue;
|
||||
uf::Serializer payload;
|
||||
payload["filename"] = canonical;
|
||||
this->queueHook( "asset:Load.%UID%", payload, delay );
|
||||
UF_OBJECT_LOAD_ASSET("png")
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,15 +242,10 @@ bool uf::Object::load( const uf::Serializer& _json ) {
|
||||
target = json["assets"]["models"];
|
||||
}
|
||||
for ( uint i = 0; i < target.size(); ++i ) {
|
||||
std::string canonical = "";
|
||||
std::string f = target[i].isObject() ? target[i]["filename"].asString() : target[i].asString();
|
||||
float delay = target[i].isObject() ? target[i]["delay"].asFloat() : 0;
|
||||
std::string filename = grabURI( f, json["root"].asString() );
|
||||
if ( uf::io::extension(filename) != "gltf" && uf::io::extension(filename) != "glb" ) continue;
|
||||
if ( (canonical = assetLoader.load( filename )) == "" ) continue;
|
||||
uf::Serializer payload;
|
||||
payload["filename"] = canonical;
|
||||
this->queueHook( "asset:Load.%UID%", payload, delay );
|
||||
UF_OBJECT_LOAD_ASSET("gltf", "glb")
|
||||
|
||||
auto& aMetadata = assetLoader.getComponent<uf::Serializer>();
|
||||
aMetadata[filename] = json["metadata"]["model"];
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,26 +308,6 @@ bool uf::Object::load( const uf::Serializer& _json ) {
|
||||
json["hot reload"]["mtime"] = uf::io::mtime( filename ) + 10;
|
||||
if ( this->loadChildUid(json) == -1 ) continue;
|
||||
}
|
||||
/*
|
||||
uf::Serializer json;
|
||||
std::string canonical = "";
|
||||
if ( target[i].isObject() ) {
|
||||
|
||||
continue;
|
||||
}
|
||||
std::string f = target[i].isObject() ? target[i]["filename"].asString() : target[i].asString();
|
||||
std::string filename = grabURI( f, metadata["system"]["root"].asString() );
|
||||
if ( uf::io::extension(filename) != "json" ) continue;
|
||||
if ( (filename = assetLoader.load(filename) ) == "" ) continue;
|
||||
if ( !json.readFromFile(filename) ) {
|
||||
uf::iostream << "Error @ " << __FILE__ << ":" << __LINE__ << ": failed to open `" + filename + "`" << "\n";
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
*/
|
||||
}
|
||||
}
|
||||
// Add lights
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include <uf/utils/thread/thread.h>
|
||||
#include <uf/utils/serialize/serializer.h>
|
||||
#include <uf/utils/math/collision.h>
|
||||
#include <uf/utils/image/atlas.h>
|
||||
|
||||
namespace {
|
||||
|
||||
@ -37,6 +38,7 @@ VkFilter getVkFilterMode(int32_t filterMode) {
|
||||
|
||||
void loadNode( uf::Object& entity, const tinygltf::Model& model, const tinygltf::Node& node, uint8_t mode ) {
|
||||
auto& transform = entity.getComponent<pod::Transform<>>();
|
||||
auto& atlas = entity.getComponent<uf::Atlas>();
|
||||
|
||||
if ( node.translation.size() == 3 ) {
|
||||
transform.position.x = node.translation[0];
|
||||
@ -56,7 +58,7 @@ void loadNode( uf::Object& entity, const tinygltf::Model& model, const tinygltf:
|
||||
}
|
||||
// if ( node.matrix.size() == 16 ) {}
|
||||
|
||||
auto fillMesh = [&]( uf::BaseMesh<pod::Vertex_3F2F3F, uint32_t>& mesh, const tinygltf::Primitive& primitive, uf::Collider& collider ) {
|
||||
auto fillMesh = [&]( ext::gltf::mesh_t& mesh, const tinygltf::Primitive& primitive, uf::Collider& collider, size_t num ) {
|
||||
size_t verticesStart = mesh.vertices.size();
|
||||
size_t indicesStart = mesh.indices.size();
|
||||
|
||||
@ -95,56 +97,63 @@ void loadNode( uf::Object& entity, const tinygltf::Model& model, const tinygltf:
|
||||
collider.add(box);
|
||||
}
|
||||
}
|
||||
|
||||
attribute.components = accessor.ByteStride(view) / sizeof(float);
|
||||
attribute.buffer.reserve( accessor.count * attribute.components );
|
||||
attribute.buffer.insert( attribute.buffer.end(), &buffer[0], &buffer[accessor.count * attribute.components] );
|
||||
size_t len = accessor.count * attribute.components;
|
||||
attribute.buffer.reserve( len );
|
||||
attribute.buffer.insert( attribute.buffer.end(), &buffer[0], &buffer[len] );
|
||||
}
|
||||
|
||||
mesh.vertices.reserve( vertices + verticesStart );
|
||||
|
||||
for ( size_t i = 0; i < vertices; ++i ) {
|
||||
auto& vertex = mesh.vertices.emplace_back();
|
||||
|
||||
#define ITERATE_ATTRIBUTE( name, member )\
|
||||
if ( !attributes[name].buffer.empty() ) { \
|
||||
for ( size_t j = 0; j < attributes[name].components; ++j )\
|
||||
vertex.member[j] = attributes[name].buffer[i * attributes[name].components + j];\
|
||||
}
|
||||
|
||||
auto& vertex = mesh.vertices.emplace_back();
|
||||
ITERATE_ATTRIBUTE("POSITION", position);
|
||||
ITERATE_ATTRIBUTE("TEXCOORD_0", uv);
|
||||
ITERATE_ATTRIBUTE("NORMAL", normal);
|
||||
|
||||
#undef ITERATE_ATTRIBUTE
|
||||
if ( !(mode & ext::gltf::LoadMode::SEPARATE_MESHES) && (mode & ext::gltf::LoadMode::USE_ATLAS) ) {
|
||||
vertex.uv = atlas.mapUv( vertex.uv, num );
|
||||
}
|
||||
vertex.id = num;
|
||||
}
|
||||
|
||||
|
||||
if ( primitive.indices > -1 ) {
|
||||
auto& accessor = model.accessors[primitive.indices];
|
||||
auto& view = model.bufferViews[accessor.bufferView];
|
||||
auto& buffer = model.buffers[view.buffer];
|
||||
|
||||
mesh.indices.reserve( accessor.count + indicesStart );
|
||||
|
||||
auto indices = static_cast<uint32_t>(accessor.count);
|
||||
mesh.indices.reserve( indices + indicesStart );
|
||||
const void* pointer = &(buffer.data[accessor.byteOffset + view.byteOffset]);
|
||||
|
||||
#define COPY_INDICES()\
|
||||
for (size_t index = 0; index < indices; index++)\
|
||||
mesh.indices.emplace_back(buf[index] + verticesStart);
|
||||
|
||||
switch (accessor.componentType) {
|
||||
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: {
|
||||
auto* buf = static_cast<const uint32_t*>( pointer );
|
||||
for (size_t index = 0; index < accessor.count; index++) mesh.indices.push_back(buf[index] + verticesStart );
|
||||
COPY_INDICES()
|
||||
break;
|
||||
}
|
||||
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: {
|
||||
auto* buf = static_cast<const uint16_t*>( pointer );
|
||||
for (size_t index = 0; index < accessor.count; index++) mesh.indices.push_back(buf[index] + verticesStart );
|
||||
COPY_INDICES()
|
||||
break;
|
||||
}
|
||||
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: {
|
||||
auto* buf = static_cast<const uint8_t*>( pointer );
|
||||
for (size_t index = 0; index < accessor.count; index++) mesh.indices.push_back(buf[index] + verticesStart );
|
||||
COPY_INDICES()
|
||||
break;
|
||||
}
|
||||
}
|
||||
#undef COPY_INDICES
|
||||
|
||||
if ( mode & ext::gltf::LoadMode::GENERATE_NORMALS ) {
|
||||
for ( size_t i = 0; i < mesh.indices.size(); i+=3 ) {
|
||||
@ -163,13 +172,20 @@ void loadNode( uf::Object& entity, const tinygltf::Model& model, const tinygltf:
|
||||
C.normal = normal;
|
||||
}
|
||||
}
|
||||
|
||||
// validate incides
|
||||
size_t maxIndex = mesh.vertices.size();
|
||||
for ( size_t i = 0; i < mesh.indices.size(); ++i ) {
|
||||
size_t index = mesh.indices[i];
|
||||
if ( index >= maxIndex ) {
|
||||
std::cout << "mesh.indices["<< i <<"] = " << index << " >= " << maxIndex << std::endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// recalc normals
|
||||
if ( mode & ext::gltf::LoadMode::GENERATE_NORMALS ) {
|
||||
// bool invert = false;
|
||||
for ( size_t i = 0; i < mesh.vertices.size(); i+=3 ) {
|
||||
// auto& b = mesh.vertices[i+(invert ? 2 : 1)].position;
|
||||
// auto& c = mesh.vertices[i+(invert ? 1 : 2)].position;
|
||||
auto& a = mesh.vertices[i+0].position;
|
||||
auto& b = mesh.vertices[i+1].position;
|
||||
auto& c = mesh.vertices[i+2].position;
|
||||
@ -192,22 +208,10 @@ void loadNode( uf::Object& entity, const tinygltf::Model& model, const tinygltf:
|
||||
if ( node.mesh > -1 ) {
|
||||
auto& m = model.meshes[node.mesh];
|
||||
std::vector<ext::vulkan::Sampler> samplers;
|
||||
std::vector<uf::Image> images;
|
||||
/*
|
||||
std::vector<uf::Object> lights;
|
||||
for ( auto& l : model.lights ) {
|
||||
auto& light = lights.emplace_back();
|
||||
auto& metadata = light.getComponent<uf::Serializer>();
|
||||
metadata["light"]["color"][0] = l.color[0];
|
||||
metadata["light"]["color"][1] = l.color[1];
|
||||
metadata["light"]["color"][2] = l.color[2];
|
||||
|
||||
metadata["light"]["radius"] = l.range;
|
||||
metadata["light"]["power"] = l.intensity;
|
||||
std::vector<uf::Image> _images;
|
||||
bool useAtlas = (mode & ext::gltf::LoadMode::USE_ATLAS) && (mode & ext::gltf::LoadMode::SEPARATE_MESHES);
|
||||
auto& images = useAtlas ? atlas.getImages() : _images;
|
||||
|
||||
std::cout << metadata << std::endl;
|
||||
}
|
||||
*/
|
||||
for ( auto& s : model.samplers ) {
|
||||
auto& sampler = samplers.emplace_back();
|
||||
sampler.descriptor.filter.min = getVkFilterMode( s.minFilter );
|
||||
@ -219,22 +223,22 @@ void loadNode( uf::Object& entity, const tinygltf::Model& model, const tinygltf:
|
||||
for ( auto& t : model.textures ) {
|
||||
auto& im = model.images[t.source];
|
||||
uf::Image& image = images.emplace_back();
|
||||
// std::cout << "Loading image: " << im.width << ", " << im.height << std::endl;
|
||||
image.loadFromBuffer( &im.image[0], {im.width, im.height}, 8, im.component, true );
|
||||
}
|
||||
// if ( model.textures.size() > 1 && m.primitives.size() == model.textures.size() ) {
|
||||
if ( mode & ext::gltf::LoadMode::SEPARATE_MESHES ) {
|
||||
auto sampler = samplers.begin();
|
||||
auto image = images.begin();
|
||||
size_t num = 0;
|
||||
for ( auto& primitive : m.primitives ) {
|
||||
uf::Object* child = new uf::Object;
|
||||
|
||||
uf::BaseMesh<pod::Vertex_3F2F3F, uint32_t> mesh;
|
||||
//ext::gltf::mesh_t mesh;
|
||||
auto& mesh = child->getComponent<ext::gltf::mesh_t>();
|
||||
auto& cTransform = child->getComponent<pod::Transform<>>();
|
||||
cTransform = transform;
|
||||
|
||||
auto& collider = child->getComponent<uf::Collider>();
|
||||
fillMesh( mesh, primitive, collider );
|
||||
fillMesh( mesh, primitive, collider, num++ );
|
||||
|
||||
if ( (mode & ext::gltf::LoadMode::COLLISION) && !(mode & ext::gltf::LoadMode::AABB) ) {
|
||||
auto* box = new uf::MeshCollider( cTransform );
|
||||
@ -243,12 +247,26 @@ void loadNode( uf::Object& entity, const tinygltf::Model& model, const tinygltf:
|
||||
}
|
||||
if ( mode & ext::gltf::LoadMode::RENDER ) {
|
||||
auto& graphic = child->getComponent<uf::Graphic>();
|
||||
// graphic.descriptor.cullMode = VK_CULL_MODE_NONE;
|
||||
graphic.initialize();
|
||||
graphic.initializeGeometry( mesh );
|
||||
if ( mode & ext::gltf::LoadMode::DEFER_INIT ) {
|
||||
graphic.process = false;
|
||||
} else {
|
||||
graphic.initialize();
|
||||
graphic.initializeGeometry( mesh );
|
||||
|
||||
graphic.material.attachShader("./data/shaders/base.stereo.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
||||
graphic.material.attachShader("./data/shaders/base.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
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);
|
||||
|
||||
auto& shader = graphic.material.shaders.back();
|
||||
struct SpecializationConstant {
|
||||
uint32_t textures = 1;
|
||||
};
|
||||
auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0];
|
||||
specializationConstants->textures = graphic.material.textures.size();
|
||||
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
|
||||
if ( binding.descriptorCount > 1 )
|
||||
binding.descriptorCount = specializationConstants->textures;
|
||||
}
|
||||
}
|
||||
|
||||
if ( image != images.end() ) graphic.material.textures.emplace_back().loadFromImage( *(image++) );
|
||||
if ( sampler != samplers.end() ) graphic.material.samplers.push_back( *(sampler++) );
|
||||
@ -260,11 +278,14 @@ void loadNode( uf::Object& entity, const tinygltf::Model& model, const tinygltf:
|
||||
|
||||
if ( mode & ext::gltf::LoadMode::APPLY_TRANSFORMS ) cTransform = {};
|
||||
}
|
||||
} else {
|
||||
uf::BaseMesh<pod::Vertex_3F2F3F, uint32_t> mesh;
|
||||
} else {
|
||||
auto& mesh = entity.getComponent<ext::gltf::mesh_t>();
|
||||
auto& collider = entity.getComponent<uf::Collider>();
|
||||
|
||||
for ( auto& primitive : m.primitives ) fillMesh( mesh, primitive, collider );
|
||||
size_t num = 0;
|
||||
for ( auto& primitive : m.primitives ) {
|
||||
fillMesh( mesh, primitive, collider, num++ );
|
||||
}
|
||||
|
||||
if ( (mode & ext::gltf::LoadMode::COLLISION) && !(mode & ext::gltf::LoadMode::AABB) ) {
|
||||
auto* c = new uf::MeshCollider( transform );
|
||||
@ -276,14 +297,32 @@ void loadNode( uf::Object& entity, const tinygltf::Model& model, const tinygltf:
|
||||
|
||||
if ( mode & ext::gltf::LoadMode::RENDER ) {
|
||||
auto& graphic = entity.getComponent<uf::Graphic>();
|
||||
if ( mode & ext::gltf::LoadMode::DEFER_INIT ) {
|
||||
graphic.process = false;
|
||||
} else {
|
||||
graphic.initialize();
|
||||
graphic.initializeGeometry( mesh );
|
||||
|
||||
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);
|
||||
|
||||
graphic.material.attachShader("./data/shaders/base.stereo.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
||||
graphic.material.attachShader("./data/shaders/base.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
|
||||
for ( auto& image : images ) graphic.material.textures.emplace_back().loadFromImage( image );
|
||||
auto& shader = graphic.material.shaders.back();
|
||||
struct SpecializationConstant {
|
||||
uint32_t textures = 1;
|
||||
};
|
||||
auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0];
|
||||
specializationConstants->textures = graphic.material.textures.size();
|
||||
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
|
||||
if ( binding.descriptorCount > 1 )
|
||||
binding.descriptorCount = specializationConstants->textures;
|
||||
}
|
||||
}
|
||||
if ( useAtlas ) {
|
||||
atlas.generate();
|
||||
graphic.material.textures.emplace_back().loadFromImage( atlas.getAtlas() );
|
||||
} else {
|
||||
for ( auto& image : images ) graphic.material.textures.emplace_back().loadFromImage( image );
|
||||
}
|
||||
for ( auto& sampler : samplers ) graphic.material.samplers.push_back(sampler);
|
||||
}
|
||||
if ( mode & ext::gltf::LoadMode::APPLY_TRANSFORMS ) transform = {};
|
||||
@ -319,31 +358,21 @@ bool ext::gltf::load( uf::Object& entity, const std::string& filename, uint8_t m
|
||||
}
|
||||
|
||||
auto& metadata = entity.getComponent<uf::Serializer>();
|
||||
bool threaded = mode & ext::gltf::LoadMode::THREADED;
|
||||
pod::Thread& thread = metadata["model"]["flags"]["USE_WORKER_THREAD"].asBool() ? uf::thread::fetchWorker() : (uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false ));
|
||||
auto function = [&]() -> int {
|
||||
const auto& scene = model.scenes[model.defaultScene > -1 ? model.defaultScene : 0];
|
||||
for ( auto i : scene.nodes ) {
|
||||
loadNode( entity, model, model.nodes[i], mode );
|
||||
}
|
||||
const auto& scene = model.scenes[model.defaultScene > -1 ? model.defaultScene : 0];
|
||||
for ( auto i : scene.nodes ) {
|
||||
loadNode( entity, model, model.nodes[i], mode );
|
||||
}
|
||||
|
||||
auto& transform = entity.getComponent<pod::Transform<>>();
|
||||
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* child ) {
|
||||
// add default render behavior
|
||||
if ( child->hasComponent<uf::Graphic>() ) uf::instantiator::bind("RenderBehavior", *child);
|
||||
auto& transform = entity.getComponent<pod::Transform<>>();
|
||||
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* child ) {
|
||||
// add default render behavior
|
||||
if ( child->hasComponent<uf::Graphic>() ) uf::instantiator::bind("RenderBehavior", *child);
|
||||
|
||||
// parent transform
|
||||
if ( child == &entity ) return;
|
||||
if ( !child->hasComponent<pod::Transform<>>() ) return;
|
||||
child->getComponent<pod::Transform<>>().reference = &transform;
|
||||
};
|
||||
entity.process(filter);
|
||||
|
||||
uf::Serializer payload;
|
||||
entity.queueHook("asset:Parsed.%UID%", payload);
|
||||
|
||||
return 0;
|
||||
// parent transform
|
||||
if ( child == &entity ) return;
|
||||
if ( !child->hasComponent<pod::Transform<>>() ) return;
|
||||
child->getComponent<pod::Transform<>>().reference = &transform;
|
||||
};
|
||||
if ( threaded ) uf::thread::add( thread, function, true ); else function();
|
||||
entity.process(filter);
|
||||
return true;
|
||||
}
|
||||
@ -323,6 +323,7 @@ void ext::vulkan::Device::flushCommandBuffer( VkCommandBuffer commandBuffer, boo
|
||||
|
||||
// Submit to the queue
|
||||
VK_CHECK_RESULT(vkQueueSubmit(device.queues.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));
|
||||
|
||||
@ -539,7 +540,7 @@ void ext::vulkan::Device::initialize() {
|
||||
// Memory properties are used regularly for creating all kinds of buffers
|
||||
vkGetPhysicalDeviceMemoryProperties( this->physicalDevice, &memoryProperties );
|
||||
}
|
||||
{
|
||||
if ( false ) {
|
||||
vkGetPhysicalDeviceProperties2( this->physicalDevice, &properties2 );
|
||||
// Features should be checked by the examples before using them
|
||||
vkGetPhysicalDeviceFeatures2( this->physicalDevice, &features2 );
|
||||
|
||||
@ -60,9 +60,11 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& _device, const std::s
|
||||
spirv_cross::ShaderResources res = comp.get_shader_resources();
|
||||
|
||||
auto parseResource = [&]( const spirv_cross::Resource& resource, VkDescriptorType descriptorType ) {
|
||||
const auto& type = comp.get_type(resource.type_id);
|
||||
const auto& base_type = comp.get_type(resource.base_type_id);
|
||||
|
||||
switch ( descriptorType ) {
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
|
||||
const auto& base_type = comp.get_type(resource.base_type_id);
|
||||
size_t size = comp.get_declared_struct_size(base_type);
|
||||
if ( size <= 0 ) break;
|
||||
auto& uniform = uniforms.emplace_back();
|
||||
@ -77,10 +79,20 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& _device, const std::s
|
||||
*/
|
||||
}
|
||||
|
||||
const auto& type = comp.get_type(resource.type_id);
|
||||
size_t size = 1;
|
||||
if ( !type.array.empty() ) size = type.array[0];
|
||||
|
||||
if ( !type.array.empty() ) {
|
||||
size = type.array[0];
|
||||
/*
|
||||
std::cout << "ARRAY: " << filename << ":\t";
|
||||
for ( auto v : type.array )
|
||||
std::cout << v << " ";
|
||||
std::cout << std::endl;
|
||||
std::cout << "ARRAY: " << filename << ":\t";
|
||||
for ( auto v : type.array_size_literal )
|
||||
std::cout << v << " ";
|
||||
std::cout << std::endl;
|
||||
*/
|
||||
}
|
||||
descriptorSetLayoutBindings.push_back( ext::vulkan::initializers::descriptorSetLayoutBinding( descriptorType, stage, comp.get_decoration(resource.id, spv::DecorationBinding), size ) );
|
||||
};
|
||||
|
||||
@ -120,9 +132,10 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& _device, const std::s
|
||||
specializationSize += size;
|
||||
}
|
||||
if ( specializationSize > 0 ) {
|
||||
specializationConstants.create( specializationSize );
|
||||
// specializationConstants.create( specializationSize );
|
||||
specializationConstants.resize( specializationSize, 0 );
|
||||
|
||||
uint8_t* s = (uint8_t*) (void*) specializationConstants;
|
||||
uint8_t* s = (uint8_t*) &specializationConstants[0];
|
||||
size_t offset = 0;
|
||||
for ( const auto& constant : comp.get_specialization_constants() ) {
|
||||
const auto& value = comp.get_constant(constant.id);
|
||||
@ -441,35 +454,9 @@ void ext::vulkan::Pipeline::record( Graphic& graphic, VkCommandBuffer commandBuf
|
||||
len = sizeof(stereo);
|
||||
pointer = &stereo;
|
||||
}
|
||||
if ( len > 0 && pointer )
|
||||
if ( len > 0 && pointer ) {
|
||||
vkCmdPushConstants( commandBuffer, pipelineLayout, shader.descriptor.stage, 0, len, pointer );
|
||||
/*
|
||||
size_t len = pushConstant.data().len;
|
||||
void* pointer = pushConstant.data().data;
|
||||
std::cout << pointer << ": " << len << std::endl;
|
||||
if ( len == 4 ) {
|
||||
struct Stereo {
|
||||
uint32_t pass;
|
||||
};
|
||||
auto& stereo = pushConstant.get<Stereo>();
|
||||
std::cout << pointer << ": Got " << stereo.pass << std::endl;
|
||||
}
|
||||
vkCmdPushConstants( commandBuffer, pipelineLayout, shader.descriptor.stage, 0, len, pointer );
|
||||
*/
|
||||
/*
|
||||
struct PushConstant {
|
||||
uint32_t pass;
|
||||
} p = { ext::openvr::renderPass };
|
||||
vkCmdPushConstants( commandBuffer, pipelineLayout, shader.descriptor.stage, 0, sizeof(p), &p );
|
||||
*/
|
||||
/*
|
||||
pod::Userdata& userdata = pushConstant.data();
|
||||
{
|
||||
pushConstant.get<PushConstant>() = { 0 };//ext::openvr::renderPass };
|
||||
}
|
||||
vkCmdPushConstants( commandBuffer, pipelineLayout, shader.descriptor.stage, offset, userdata.len, userdata.data );
|
||||
offset += userdata.len;
|
||||
*/
|
||||
}
|
||||
}
|
||||
// Bind descriptor sets describing shader binding points
|
||||
@ -521,7 +508,11 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
|
||||
size_t imageInfosStart = imageInfos.size();
|
||||
// assume we have a texture, and fill it in the slots as defaults
|
||||
for ( size_t i = 0; i < layout.descriptorCount; ++i ) {
|
||||
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() ) {
|
||||
d = (textures++)->descriptor;
|
||||
@ -533,13 +524,15 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
|
||||
}
|
||||
imageInfos.push_back( d );
|
||||
}
|
||||
|
||||
|
||||
size_t len = imageInfos.size() - imageInfosStart;
|
||||
|
||||
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
|
||||
descriptorSet,
|
||||
layout.descriptorType,
|
||||
layout.binding,
|
||||
&imageInfos[imageInfosStart],
|
||||
imageInfos.size() - imageInfosStart
|
||||
len
|
||||
));
|
||||
} break;
|
||||
}
|
||||
|
||||
@ -81,6 +81,7 @@ void ext::vulkan::RenderMode::render() {
|
||||
|
||||
// Submit to the graphics queue passing a wait fence
|
||||
VK_CHECK_RESULT(vkQueueSubmit(device->queues.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
|
||||
|
||||
@ -44,6 +44,7 @@ void ext::vulkan::ComputeRenderMode::initialize( Device& device ) {
|
||||
auto& metadata = scene.getComponent<uf::Serializer>();
|
||||
|
||||
auto& shader = compute.material.shaders.front();
|
||||
/*
|
||||
struct SpecializationConstant {
|
||||
int32_t eyes = 2;
|
||||
int32_t maxLights = 16;
|
||||
@ -51,6 +52,18 @@ void ext::vulkan::ComputeRenderMode::initialize( Device& device ) {
|
||||
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
|
||||
specializationConstants.maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64();
|
||||
specializationConstants.eyes = ext::openvr::context ? 2 : 1;
|
||||
*/
|
||||
struct SpecializationConstant {
|
||||
uint32_t eyes = 2;
|
||||
uint32_t maxLights = 16;
|
||||
};
|
||||
auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0];
|
||||
specializationConstants->maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64();
|
||||
specializationConstants->eyes = ext::openvr::context ? 2 : 1;
|
||||
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
|
||||
if ( binding.descriptorCount > 1 )
|
||||
binding.descriptorCount = specializationConstants->maxLights;
|
||||
}
|
||||
}
|
||||
|
||||
// update buffers
|
||||
@ -103,6 +116,7 @@ void ext::vulkan::ComputeRenderMode::render() {
|
||||
submitInfo.pCommandBuffers = &commands[currentBuffer];
|
||||
|
||||
VK_CHECK_RESULT(vkQueueSubmit(device->queues.compute, 1, &submitInfo, fences[currentBuffer]));
|
||||
//vkQueueSubmit(device->queues.compute, 1, &submitInfo, fences[currentBuffer]);
|
||||
}
|
||||
void ext::vulkan::ComputeRenderMode::tick() {
|
||||
ext::vulkan::RenderMode::tick();
|
||||
|
||||
@ -103,13 +103,23 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
{
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& metadata = scene.getComponent<uf::Serializer>();
|
||||
|
||||
auto& shader = blitter.material.shaders.back();
|
||||
/*
|
||||
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;
|
||||
};
|
||||
auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0];
|
||||
specializationConstants->maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64();
|
||||
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
|
||||
if ( binding.descriptorCount > 1 )
|
||||
binding.descriptorCount = specializationConstants->maxLights;
|
||||
}
|
||||
}
|
||||
blitter.initializePipeline();
|
||||
}
|
||||
|
||||
@ -146,6 +146,7 @@ void ext::vulkan::RenderTargetRenderMode::render() {
|
||||
submitInfo.commandBufferCount = 1;
|
||||
|
||||
VK_CHECK_RESULT(vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[currentBuffer]));
|
||||
//vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[currentBuffer]);
|
||||
/*
|
||||
VkSemaphoreWaitInfo waitInfo = {};
|
||||
waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO;
|
||||
|
||||
@ -121,11 +121,23 @@ void ext::vulkan::StereoscopicDeferredRenderMode::initialize( Device& device ) {
|
||||
auto& metadata = scene.getComponent<uf::Serializer>();
|
||||
|
||||
auto& shader = blitter.material.shaders.back();
|
||||
/*
|
||||
struct SpecializationConstant {
|
||||
int32_t maxLights = 16;
|
||||
};
|
||||
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
|
||||
specializationConstants.maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64();
|
||||
*/
|
||||
struct SpecializationConstant {
|
||||
uint32_t maxLights = 16;
|
||||
};
|
||||
auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0];
|
||||
specializationConstants->maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64();
|
||||
|
||||
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
|
||||
if ( binding.descriptorCount > 1 )
|
||||
binding.descriptorCount = specializationConstants->maxLights;
|
||||
}
|
||||
}
|
||||
blitter.initializePipeline();
|
||||
}
|
||||
|
||||
@ -78,6 +78,7 @@ void UF_API uf::Audio::setTime( ALfloat pos ) {
|
||||
if ( this->playing() ) return;
|
||||
this->m_source.source("SEC_OFFSET", std::vector<ALfloat>{ pos } );
|
||||
}
|
||||
|
||||
ALfloat UF_API uf::Audio::getPitch() {
|
||||
if ( this->playing() ) return 0;
|
||||
ALfloat pitch;
|
||||
@ -88,6 +89,7 @@ void UF_API uf::Audio::setPitch( ALfloat pitch ) {
|
||||
if ( this->playing() ) return;
|
||||
this->m_source.source("PITCH", std::vector<ALfloat>{ pitch } );
|
||||
}
|
||||
|
||||
ALfloat UF_API uf::Audio::getGain() {
|
||||
if ( this->playing() ) return 0;
|
||||
ALfloat gain;
|
||||
@ -98,12 +100,36 @@ void UF_API uf::Audio::setGain( ALfloat gain ) {
|
||||
if ( this->playing() ) return;
|
||||
this->m_source.source("GAIN", std::vector<ALfloat>{ gain } );
|
||||
}
|
||||
|
||||
ALfloat UF_API uf::Audio::getRolloffFactor() {
|
||||
if ( this->playing() ) return 0;
|
||||
ALfloat rolloffFactor;
|
||||
alGetSourcef(this->m_source.getIndex(), AL_ROLLOFF_FACTOR, &rolloffFactor ); ext::oal.checkError(__FUNCTION__, __LINE__);
|
||||
return rolloffFactor;
|
||||
}
|
||||
void UF_API uf::Audio::setRolloffFactor( ALfloat rolloffFactor ) {
|
||||
if ( this->playing() ) return;
|
||||
this->m_source.source("ROLLOFF_FACTOR", std::vector<ALfloat>{ rolloffFactor } );
|
||||
}
|
||||
|
||||
ALfloat UF_API uf::Audio::getMaxDistance() {
|
||||
if ( this->playing() ) return 0;
|
||||
ALfloat maxDistance;
|
||||
alGetSourcef(this->m_source.getIndex(), AL_MAX_DISTANCE, &maxDistance ); ext::oal.checkError(__FUNCTION__, __LINE__);
|
||||
return maxDistance;
|
||||
}
|
||||
void UF_API uf::Audio::setMaxDistance( ALfloat maxDistance ) {
|
||||
if ( this->playing() ) return;
|
||||
this->m_source.source("MAX_DISTANCE", std::vector<ALfloat>{ maxDistance } );
|
||||
}
|
||||
|
||||
void UF_API uf::Audio::setPosition( const pod::Vector3& position ) {
|
||||
this->m_source.source("POSITION", std::vector<ALfloat>{position.x, position.y, position.z} );
|
||||
}
|
||||
void UF_API uf::Audio::setOrientation( const pod::Quaternion<>& orientation ) {
|
||||
|
||||
}
|
||||
|
||||
void UF_API uf::Audio::setVolume( float volume ) {
|
||||
this->m_source.source("GAIN", std::vector<ALfloat>{volume} );
|
||||
}
|
||||
|
||||
@ -55,6 +55,39 @@ std::vector<ext::vulkan::VertexDescriptor> pod::Vertex_2F2F::descriptor = {
|
||||
offsetof(pod::Vertex_2F2F, uv)
|
||||
}
|
||||
};
|
||||
// used for texture arrays
|
||||
std::vector<ext::vulkan::VertexDescriptor> pod::Vertex_3F3F3F::descriptor = {
|
||||
{
|
||||
VK_FORMAT_R32G32B32_SFLOAT,
|
||||
offsetof(pod::Vertex_3F3F3F, position)
|
||||
},
|
||||
{
|
||||
VK_FORMAT_R32G32B32_SFLOAT,
|
||||
offsetof(pod::Vertex_3F3F3F, uv)
|
||||
},
|
||||
{
|
||||
VK_FORMAT_R32G32B32_SFLOAT,
|
||||
offsetof(pod::Vertex_3F3F3F, normal)
|
||||
}
|
||||
};
|
||||
std::vector<ext::vulkan::VertexDescriptor> pod::Vertex_3F2F3F1UI::descriptor = {
|
||||
{
|
||||
VK_FORMAT_R32G32B32_SFLOAT,
|
||||
offsetof(pod::Vertex_3F2F3F1UI, position)
|
||||
},
|
||||
{
|
||||
VK_FORMAT_R32G32_SFLOAT,
|
||||
offsetof(pod::Vertex_3F2F3F1UI, uv)
|
||||
},
|
||||
{
|
||||
VK_FORMAT_R32G32B32_SFLOAT,
|
||||
offsetof(pod::Vertex_3F2F3F1UI, normal)
|
||||
},
|
||||
{
|
||||
VK_FORMAT_R32_UINT,
|
||||
offsetof(pod::Vertex_3F2F3F1UI, id)
|
||||
}
|
||||
};
|
||||
// Basic
|
||||
std::vector<ext::vulkan::VertexDescriptor> pod::Vertex_3F::descriptor = {
|
||||
{
|
||||
|
||||
120
engine/src/utils/image/atlas.cpp
Normal file
120
engine/src/utils/image/atlas.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#include <uf/utils/image/atlas.h>
|
||||
#include <iostream>
|
||||
|
||||
void uf::Atlas::addImage( const uf::Image& _image, bool regenerate ) {
|
||||
auto& image = this->m_images.emplace_back( _image );
|
||||
if ( regenerate ) this->generate();
|
||||
}
|
||||
void uf::Atlas::addImage( uf::Image&& _image, bool regenerate ) {
|
||||
auto& image = this->m_images.emplace_back( _image );
|
||||
if ( regenerate ) this->generate();
|
||||
}
|
||||
void uf::Atlas::addImage( const uint8_t* pointer, const pod::Vector2ui& size, std::size_t bpp, std::size_t channels, bool flip, bool regenerate ) {
|
||||
auto& image = this->m_images.emplace_back();
|
||||
image.loadFromBuffer( pointer, size, bpp, channels, flip );
|
||||
if ( regenerate ) this->generate();
|
||||
|
||||
}
|
||||
void uf::Atlas::generate() {
|
||||
if ( this->m_images.empty() ) return;
|
||||
// destroy atlas
|
||||
this->m_image.clear();
|
||||
|
||||
BinPack2D::ContentAccumulator<uf::Atlas::identifier_t> queue;
|
||||
pod::Vector2ui size = {0,0};
|
||||
size_t index = 0;
|
||||
size_t area = 0;
|
||||
for ( auto& image : this->m_images ) {
|
||||
auto& dim = image.getDimensions();
|
||||
size += dim;
|
||||
area += dim.x * dim.y;
|
||||
queue += BinPack2D::Content<uf::Atlas::identifier_t>({index++}, BinPack2D::Coord(), BinPack2D::Size(dim.x, dim.y), false );
|
||||
}
|
||||
{
|
||||
size_t side = std::sqrt( area );
|
||||
size = { side, side };
|
||||
{
|
||||
size.x--;
|
||||
size.x |= size.x >> 1;
|
||||
size.x |= size.x >> 2;
|
||||
size.x |= size.x >> 4;
|
||||
size.x |= size.x >> 8;
|
||||
size.x |= size.x >> 16;
|
||||
size.x++;
|
||||
size.y--;
|
||||
size.y |= size.y >> 1;
|
||||
size.y |= size.y >> 2;
|
||||
size.y |= size.y >> 4;
|
||||
size.y |= size.y >> 8;
|
||||
size.y |= size.y >> 16;
|
||||
size.y++;
|
||||
}
|
||||
this->m_image.loadFromBuffer( NULL, size, 8, 4 );
|
||||
}
|
||||
queue.Sort();
|
||||
this->m_atlas = BinPack2D::UniformCanvasArrayBuilder<uf::Atlas::identifier_t>(size.x, size.y ,1).Build();
|
||||
BinPack2D::ContentAccumulator<uf::Atlas::identifier_t> stored, remainder;
|
||||
bool success = this->m_atlas.Place( queue, remainder );
|
||||
this->m_atlas.CollectContent( stored );
|
||||
|
||||
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+1] = 0;
|
||||
dstBuffer[i+2] = 255;
|
||||
dstBuffer[i+3] = 255;
|
||||
}
|
||||
|
||||
for ( auto& it : stored.Get() ) {
|
||||
size_t index = it.content.index;
|
||||
auto& image = this->m_images[index];
|
||||
auto& dim = image.getDimensions();
|
||||
auto channels = image.getChannels();
|
||||
auto& srcBuffer = image.getPixels();
|
||||
|
||||
for ( size_t y = 0; y < dim.y; ++y ) {
|
||||
for ( size_t x = 0; x < dim.x; ++x ) {
|
||||
size_t src = (y * dim.x * channels) + (x * channels);
|
||||
size_t dst = ((y + it.coord.y) * size.x * 4) + ((x + it.coord.x) * 4);
|
||||
for ( size_t i = 0; i < channels; ++i ) {
|
||||
dstBuffer[dst+i] = srcBuffer[src+i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pod::Vector2f uf::Atlas::mapUv( const pod::Vector2f& uv, size_t index ) {
|
||||
BinPack2D::ContentAccumulator<uf::Atlas::identifier_t> stored;
|
||||
this->m_atlas.CollectContent( stored );
|
||||
auto& size = this->m_image.getDimensions();
|
||||
for ( auto& it : stored.Get() ) {
|
||||
if ( it.content.index != index ) continue;
|
||||
auto& image = this->m_images[index];
|
||||
auto& dim = image.getDimensions();
|
||||
pod::Vector2f nuv = uv;
|
||||
if ( nuv.x > 1.0f ) nuv.x = std::fmod( nuv.x, 1.0f );
|
||||
if ( nuv.y > 1.0f ) nuv.y = std::fmod( nuv.y, 1.0f );
|
||||
// while ( nuv.x > 1.0f ) nuv.x -= 1.0f;
|
||||
// while ( nuv.y > 1.0f ) nuv.y -= 1.0f;
|
||||
|
||||
pod::Vector2ui coord = { uv.x * dim.x + it.coord.x, uv.y * dim.y + it.coord.y };
|
||||
nuv = { (float) coord.x / (float) size.x, (float) coord.y / (float) size.y };
|
||||
nuv.y = 1.0f - nuv.y;
|
||||
return nuv;
|
||||
}
|
||||
return uv;
|
||||
}
|
||||
pod::Vector3f uf::Atlas::mapUv( const pod::Vector3f& uv ) {
|
||||
pod::Vector2f nuv = mapUv( { uv.x, uv.y }, uv.z );
|
||||
return { nuv.x, nuv.y, uv.z };
|
||||
}
|
||||
uf::Image& uf::Atlas::getAtlas() {
|
||||
return this->m_image;
|
||||
}
|
||||
uf::Atlas::images_t& uf::Atlas::getImages() {
|
||||
return this->m_images;
|
||||
}
|
||||
const uf::Atlas::images_t& uf::Atlas::getImages() const {
|
||||
return this->m_images;
|
||||
}
|
||||
@ -199,21 +199,13 @@ void uf::Image::loadFromBuffer( const Image::pixel_t::type_t* pointer, const pod
|
||||
this->m_pixels.clear();
|
||||
this->m_pixels.resize( len );
|
||||
//for ( size_t i = 0; i < len; ++i ) this->m_pixels[i] = pointer[i];
|
||||
memcpy( &this->m_pixels[0], pointer, len );
|
||||
|
||||
if ( flip ) {
|
||||
auto w = this->m_dimensions.x;
|
||||
auto h = this->m_dimensions.y;
|
||||
uint8_t* pixels = &this->m_pixels[0];
|
||||
for (uint j = 0; j * 2 < h; ++j) {
|
||||
uint x = j * w * this->m_bpp/8;
|
||||
uint y = (h - 1 - j) * w * this->m_bpp/8;
|
||||
for (uint i = w * this->m_bpp/8; i > 0; --i) {
|
||||
std::swap( pixels[x], pixels[y] );
|
||||
++x, ++y;
|
||||
}
|
||||
}
|
||||
if ( pointer ) {
|
||||
memcpy( &this->m_pixels[0], pointer, len );
|
||||
} else {
|
||||
memset( &this->m_pixels[0], 0, len );
|
||||
}
|
||||
|
||||
if ( flip ) this->flip();
|
||||
}
|
||||
void uf::Image::loadFromBuffer( const Image::container_t& container, const pod::Vector2ui& size, std::size_t bit_depth, std::size_t channels, bool flip ) {
|
||||
this->m_dimensions = size;
|
||||
@ -221,17 +213,18 @@ void uf::Image::loadFromBuffer( const Image::container_t& container, const pod::
|
||||
this->m_channels = channels;
|
||||
this->m_pixels = container;
|
||||
|
||||
if ( flip ) {
|
||||
auto w = this->m_dimensions.x;
|
||||
auto h = this->m_dimensions.y;
|
||||
uint8_t* pixels = &this->m_pixels[0];
|
||||
for (uint j = 0; j * 2 < h; ++j) {
|
||||
uint x = j * w * this->m_bpp/8;
|
||||
uint y = (h - 1 - j) * w * this->m_bpp/8;
|
||||
for (uint i = w * this->m_bpp/8; i > 0; --i) {
|
||||
std::swap( pixels[x], pixels[y] );
|
||||
++x, ++y;
|
||||
}
|
||||
if ( flip ) this->flip();
|
||||
}
|
||||
void uf::Image::flip() {
|
||||
auto w = this->m_dimensions.x;
|
||||
auto h = this->m_dimensions.y;
|
||||
uint8_t* pixels = &this->m_pixels[0];
|
||||
for (uint j = 0; j * 2 < h; ++j) {
|
||||
uint x = j * w * this->m_bpp/8;
|
||||
uint y = (h - 1 - j) * w * this->m_bpp/8;
|
||||
for (uint i = w * this->m_bpp/8; i > 0; --i) {
|
||||
std::swap( pixels[x], pixels[y] );
|
||||
++x, ++y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,8 @@ uf::thread::container_t uf::thread::threads;
|
||||
double uf::thread::limiter = 1.0f / 120.0f;
|
||||
uint uf::thread::workers = 1;
|
||||
|
||||
#define UF_THREAD_ANNOUNCE 0
|
||||
|
||||
void UF_API uf::thread::start( pod::Thread& thread ) { if ( thread.running ) return;
|
||||
thread.thread = std::thread( uf::thread::tick, std::ref(thread) );
|
||||
thread.running = true;
|
||||
@ -21,12 +23,12 @@ void UF_API uf::thread::quit( pod::Thread& thread ) { // if ( !thread.running )
|
||||
void UF_API uf::thread::tick( pod::Thread& thread ) {
|
||||
/*
|
||||
bool res = SetThreadAffinityMask(GetCurrentThread(), (1u << thread.affinity));
|
||||
if ( !res ) uf::iostream << "Failed to set affinity of Thread #" << thread.uid << " (" << thread.name << " on ID " << pthread_self() << "/" << thread.affinity << ")" << "\n";
|
||||
if ( !res ) if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Failed to set affinity of Thread #" << thread.uid << " (" << thread.name << " on ID " << pthread_self() << "/" << thread.affinity << ")" << "\n";
|
||||
if ( !thread.timer.running() ) thread.timer.start();
|
||||
*/
|
||||
bool res = SetThreadAffinityMask(GetCurrentThread(), (1u << thread.affinity));
|
||||
if ( !res ) uf::iostream << "Failed to set affinity of Thread #" << thread.uid << " (" << thread.name << " on ID " << pthread_self() << "/" << thread.affinity << ")" << "\n";
|
||||
uf::iostream << "Starting Thread #" << thread.uid << " (" << thread.name << " on ID " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)" << "\n";
|
||||
if ( !res ) if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Failed to set affinity of Thread #" << thread.uid << " (" << thread.name << " on ID " << pthread_self() << "/" << thread.affinity << ")" << "\n";
|
||||
if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Starting Thread #" << thread.uid << " (" << thread.name << " on ID " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)" << "\n";
|
||||
|
||||
thread.timer.start();
|
||||
|
||||
@ -58,8 +60,8 @@ pod::Thread& UF_API uf::thread::fetchWorker( const std::string& name ) {
|
||||
pod.affinity = (current + 1) % threads;
|
||||
std::cout << "Create: " << thread << ": " << pod.affinity << std::endl;
|
||||
BOOL res = SetThreadAffinityMask((HANDLE) pod.thread.native_handle(), 1u << pod.affinity );
|
||||
if ( res ) uf::iostream << "Bound worker thread #" << current << " to ID " << pod.affinity << "\n";
|
||||
else uf::iostream << "Failed to bind worker thread #" << current << " to ID " << pod.affinity << "\n";
|
||||
if ( res ) if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Bound worker thread #" << current << " to ID " << pod.affinity << "\n";
|
||||
else if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Failed to bind worker thread #" << current << " to ID " << pod.affinity << "\n";
|
||||
*/
|
||||
}
|
||||
return pod;
|
||||
@ -79,7 +81,7 @@ void UF_API uf::thread::add( pod::Thread& thread, const pod::Thread::function_t&
|
||||
temporary ? thread.temps.push( function ) : thread.consts.push_back( function );
|
||||
if ( thread.mutex != NULL ) thread.mutex->unlock();
|
||||
}
|
||||
void UF_API uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(uf::thread::uid(thread)) ) { uf::iostream << "Bad Thread: " << thread.uid << " " << thread.name << "\n"; return; } //ops
|
||||
void UF_API uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(uf::thread::uid(thread)) ) { if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Bad Thread: " << thread.uid << " " << thread.name << "\n"; return; } //ops
|
||||
std::function<int()> temps = [&] {
|
||||
int i = 0;
|
||||
while ( !thread.temps.empty() ) {
|
||||
@ -144,7 +146,7 @@ pod::Thread& UF_API uf::thread::create( const std::string& name, bool start, boo
|
||||
thread.limiter = uf::thread::limiter;
|
||||
thread.affinity = (thread.uid % limit) + 1;
|
||||
|
||||
uf::iostream << "Creating Thread #" << thread.uid << " (" << name << ") " << &thread << " (Affinity: " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)"<< "\n";
|
||||
if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Creating Thread #" << thread.uid << " (" << name << ") " << &thread << " (Affinity: " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)"<< "\n";
|
||||
|
||||
if ( start ) uf::thread::start( thread );
|
||||
|
||||
@ -153,9 +155,9 @@ pod::Thread& UF_API uf::thread::create( const std::string& name, bool start, boo
|
||||
void UF_API uf::thread::destroy( pod::Thread& thread ) {
|
||||
if ( !uf::thread::has( uf::thread::uid(thread) ) ) return; // oops
|
||||
|
||||
uf::iostream << "Quitting Thread #" << thread.uid << " (" << thread.name << ")" << "\n";
|
||||
if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Quitting Thread #" << thread.uid << " (" << thread.name << ")" << "\n";
|
||||
uf::thread::quit( thread );
|
||||
uf::iostream << "Quitted Thread #" << thread.uid << " (" << thread.name << ")" << "\n";
|
||||
if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Quitted Thread #" << thread.uid << " (" << thread.name << ")" << "\n";
|
||||
|
||||
if ( thread.mutex != NULL ) delete thread.mutex;
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include <uf/utils/audio/audio.h>
|
||||
#include <uf/utils/thread/thread.h>
|
||||
#include <uf/utils/camera/camera.h>
|
||||
#include <uf/utils/math/physics.h>
|
||||
|
||||
#include <uf/engine/asset/asset.h>
|
||||
#include <uf/engine/asset/masterdata.h>
|
||||
@ -194,11 +195,17 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
|
||||
/* Updates Sound Listener */ {
|
||||
auto& controller = this->getController();
|
||||
auto& transform = controller.getComponent<pod::Transform<>>();
|
||||
|
||||
// copy
|
||||
pod::Transform<> transform = controller.getComponent<pod::Transform<>>();
|
||||
if ( controller.hasComponent<uf::Camera>() ) {
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
transform.position += camera.getTransform().position;
|
||||
transform = uf::transform::reorient( transform );
|
||||
}
|
||||
transform.forward *= -1;
|
||||
ext::oal.listener( "POSITION", { transform.position.x, transform.position.y, transform.position.z } );
|
||||
ext::oal.listener( "VELOCITY", { 0, 0, 0 } );
|
||||
ext::oal.listener( "ORIENTATION", { 0, 0, 1, 1, 0, 0 } );
|
||||
ext::oal.listener( "ORIENTATION", { transform.forward.x, transform.forward.y, transform.forward.z, transform.up.x, transform.up.y, transform.up.z } );
|
||||
}
|
||||
|
||||
if ( uf::scene::getCurrentScene().getUid() == this->getUid() ) {
|
||||
@ -236,6 +243,10 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
alignas(16) pod::Matrix4f projection[2];
|
||||
} matrices;
|
||||
alignas(16) pod::Vector4f ambient;
|
||||
struct Mode {
|
||||
alignas(8) pod::Vector2ui type;
|
||||
alignas(16) pod::Vector4f parameters;
|
||||
} mode;
|
||||
struct {
|
||||
alignas(8) pod::Vector2f range;
|
||||
alignas(16) pod::Vector4f color;
|
||||
@ -251,7 +262,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
};
|
||||
|
||||
struct SpecializationConstant {
|
||||
int32_t maxLights = 32;
|
||||
uint32_t maxLights = 32;
|
||||
} specializationConstants;
|
||||
|
||||
for ( size_t _ = 0; _ < blitters.size(); ++_ ) {
|
||||
@ -267,7 +278,8 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
buffer = (uint8_t*) (void*) userdata;
|
||||
len = userdata.data().len;
|
||||
shader = &_;
|
||||
specializationConstants = _.specializationConstants.get<SpecializationConstant>();
|
||||
// specializationConstants = _.specializationConstants.get<SpecializationConstant>();
|
||||
specializationConstants = *((SpecializationConstant*) &_.specializationConstants[0]);
|
||||
}
|
||||
|
||||
if ( !buffer ) continue;
|
||||
@ -291,6 +303,19 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
uniforms->fog.range.x = metadata["light"]["fog"]["range"][0].asFloat();
|
||||
uniforms->fog.range.y = metadata["light"]["fog"]["range"][1].asFloat();
|
||||
}
|
||||
{
|
||||
uniforms->mode.type.x = metadata["system"]["renderer"]["shader"]["mode"].asUInt();
|
||||
uniforms->mode.type.y = metadata["system"]["renderer"]["shader"]["scalar"].asUInt();
|
||||
uniforms->mode.parameters.x = metadata["system"]["renderer"]["shader"]["parameters"][0].asFloat();
|
||||
uniforms->mode.parameters.y = metadata["system"]["renderer"]["shader"]["parameters"][1].asFloat();
|
||||
uniforms->mode.parameters.z = metadata["system"]["renderer"]["shader"]["parameters"][2].asFloat();
|
||||
|
||||
if ( metadata["system"]["renderer"]["shader"]["parameters"][3].asString() == "time" ) {
|
||||
uniforms->mode.parameters.w = uf::physics::time::current;
|
||||
} else {
|
||||
uniforms->mode.parameters.w = metadata["system"]["renderer"]["shader"]["parameters"][3].asFloat();
|
||||
}
|
||||
}
|
||||
{
|
||||
std::vector<uf::Entity*> entities;
|
||||
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
|
||||
|
||||
@ -31,12 +31,20 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) {
|
||||
uf::Audio& audio = this->getComponent<uf::Audio>(); //emitter.add(filename);
|
||||
audio.load(filename);
|
||||
{
|
||||
float volume = metadata["volume"].isNumeric() ? metadata["volume"].asFloat() : sMetadata["volumes"]["sfx"].asFloat();
|
||||
float volume = metadata["audio"]["volume"].isNumeric() ? metadata["audio"]["volume"].asFloat() : sMetadata["volumes"]["sfx"].asFloat();
|
||||
audio.setVolume(volume);
|
||||
}
|
||||
{
|
||||
float pitch = metadata["volume"].isNumeric() ? metadata["volume"].asFloat() : 1;
|
||||
audio.setPitch(pitch);
|
||||
if ( metadata["audio"]["pitch"].isNumeric() ) {
|
||||
audio.setPitch(metadata["audio"]["pitch"].asFloat());
|
||||
}
|
||||
if ( metadata["audio"]["gain"].isNumeric() ) {
|
||||
audio.setGain(metadata["audio"]["gain"].asFloat());
|
||||
}
|
||||
if ( metadata["audio"]["rolloffFactor"].isNumeric() ) {
|
||||
audio.setRolloffFactor(metadata["audio"]["rolloffFactor"].asFloat());
|
||||
}
|
||||
if ( metadata["audio"]["maxDistance"].isNumeric() ) {
|
||||
audio.setMaxDistance(metadata["audio"]["maxDistance"].asFloat());
|
||||
}
|
||||
audio.play();
|
||||
|
||||
@ -55,7 +63,7 @@ void ext::SoundEmitterBehavior::tick( uf::Object& self ) {
|
||||
audio.setPosition( transform.position );
|
||||
audio.setOrientation( transform.orientation );
|
||||
|
||||
if ( metadata["loop"].asBool() ) {
|
||||
if ( metadata["audio"]["loop"].asBool() ) {
|
||||
float current = audio.getTime();
|
||||
float end = audio.getDuration();
|
||||
float epsilon = 0.005f;
|
||||
|
||||
54
ext/behaviors/staticemitter/behavior.cpp
Normal file
54
ext/behaviors/staticemitter/behavior.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "behavior.h"
|
||||
|
||||
#include <uf/utils/serialize/serializer.h>
|
||||
|
||||
#include <uf/utils/audio/audio.h>
|
||||
#include <uf/utils/math/transform.h>
|
||||
#include <uf/engine/asset/asset.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
EXT_BEHAVIOR_REGISTER_CPP(StaticEmitterBehavior)
|
||||
#define this ((uf::Scene*) &self)
|
||||
|
||||
void ext::StaticEmitterBehavior::initialize( uf::Object& self ) {
|
||||
|
||||
}
|
||||
void ext::StaticEmitterBehavior::tick( uf::Object& self ) {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& controller = scene.getController();
|
||||
|
||||
auto& cTransform = controller.getComponent<pod::Transform<>>();
|
||||
auto& transform = this->getComponent<pod::Transform<>>();
|
||||
|
||||
float distanceSquared = uf::vector::distanceSquared( transform.position, cTransform.position );
|
||||
|
||||
auto& metadata = this->getComponent<uf::Serializer>();
|
||||
auto& sMetadata = scene.getComponent<uf::Serializer>();
|
||||
if ( metadata["static"]["scale"].isNumeric() ) {
|
||||
distanceSquared *= metadata["static"]["scale"].asFloat();
|
||||
}
|
||||
{
|
||||
float lo = metadata["static"]["range"][0].isNumeric() ? metadata["static"]["range"][0].asFloat() : 0.1f;
|
||||
float hi = metadata["static"]["range"][1].isNumeric() ? metadata["static"]["range"][1].asFloat() : 0.5f;
|
||||
float staticBlend = std::clamp( distanceSquared > 1 ? 1.0f / distanceSquared : 1.0f, lo, hi );
|
||||
|
||||
float flicker = metadata["static"]["flicker"].isNumeric() ? metadata["static"]["flicker"].asFloat() : 0.001;
|
||||
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;
|
||||
}
|
||||
|
||||
sMetadata["system"]["renderer"]["shader"]["mode"] = mode;
|
||||
sMetadata["system"]["renderer"]["shader"]["parameters"][0] = flicker;
|
||||
sMetadata["system"]["renderer"]["shader"]["parameters"][1] = pieces;
|
||||
sMetadata["system"]["renderer"]["shader"]["parameters"][2] = staticBlend;
|
||||
sMetadata["system"]["renderer"]["shader"]["parameters"][3] = "time";
|
||||
}
|
||||
}
|
||||
|
||||
void ext::StaticEmitterBehavior::render( uf::Object& self ){}
|
||||
void ext::StaticEmitterBehavior::destroy( uf::Object& self ){}
|
||||
#undef this
|
||||
17
ext/behaviors/staticemitter/behavior.h
Normal file
17
ext/behaviors/staticemitter/behavior.h
Normal 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 StaticEmitterBehavior {
|
||||
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& );
|
||||
};
|
||||
}
|
||||
@ -41,8 +41,8 @@ namespace {
|
||||
uf::renderer::height,
|
||||
};
|
||||
pod::Vector2ui reference = {
|
||||
1280,
|
||||
720,
|
||||
1920,
|
||||
1080,
|
||||
};
|
||||
} size;
|
||||
/*
|
||||
@ -492,7 +492,7 @@ EXT_BEHAVIOR_REGISTER_AS_OBJECT(GuiBehavior, Gui)
|
||||
#define this (&self)
|
||||
void ext::GuiBehavior::initialize( uf::Object& self ) {
|
||||
{
|
||||
const uf::Scene& world = this->getRootParent<uf::Scene>();
|
||||
const uf::Scene& world = uf::scene::getCurrentScene();
|
||||
const uf::Serializer& _metadata = world.getComponent<uf::Serializer>();
|
||||
::size.current = {
|
||||
_metadata["window"]["size"]["x"].asFloat(),
|
||||
@ -587,8 +587,8 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
|
||||
|
||||
if ( uf::io::extension(filename) != "png" ) return "false";
|
||||
|
||||
uf::Scene& world = this->getRootParent<uf::Scene>();
|
||||
uf::Asset& assetLoader = world.getComponent<uf::Asset>();
|
||||
uf::Scene& scene = uf::scene::getCurrentScene();
|
||||
uf::Asset& assetLoader = scene.getComponent<uf::Asset>();
|
||||
const uf::Image* imagePointer = NULL;
|
||||
try { imagePointer = &assetLoader.get<uf::Image>(filename); } catch ( ... ) {}
|
||||
if ( !imagePointer ) return "false";
|
||||
@ -669,7 +669,9 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
|
||||
float xi = metadata["box"][i]["x"].asFloat(), yi = metadata["box"][i]["y"].asFloat();
|
||||
float xj = metadata["box"][j]["x"].asFloat(), yj = metadata["box"][j]["y"].asFloat();
|
||||
bool intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
||||
if (intersect) clicked = !clicked;
|
||||
if (intersect) {
|
||||
clicked = !clicked;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -715,7 +717,9 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
|
||||
float xi = metadata["box"][i]["x"].asFloat(), yi = metadata["box"][i]["y"].asFloat();
|
||||
float xj = metadata["box"][j]["x"].asFloat(), yj = metadata["box"][j]["y"].asFloat();
|
||||
bool intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
||||
if (intersect) clicked = !clicked;
|
||||
if (intersect) {
|
||||
clicked = !clicked;
|
||||
}
|
||||
}
|
||||
}
|
||||
metadata["hovered"] = clicked;
|
||||
@ -805,7 +809,7 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
|
||||
void ext::GuiBehavior::render( uf::Object& self ){
|
||||
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
|
||||
/* Update uniforms */ if ( this->hasComponent<uf::GuiMesh>() ) {
|
||||
auto& scene = this->getRootParent<uf::Scene>();
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& mesh = this->getComponent<uf::GuiMesh>();
|
||||
auto& graphic = this->getComponent<uf::Graphic>();
|
||||
auto& controller = scene.getController();
|
||||
@ -884,7 +888,7 @@ void ext::GuiBehavior::render( uf::Object& self ){
|
||||
|
||||
for ( std::size_t i = 0; i < 2; ++i ) {
|
||||
if ( metadata["text settings"]["world"].asBool() ) {
|
||||
auto& scene = this->getRootParent<uf::Scene>();
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
|
||||
@ -958,7 +962,7 @@ void ext::GuiBehavior::render( uf::Object& self ){
|
||||
pod::Matrix4 rotation = uf::quaternion::matrix( uf::vector::multiply( { 1, 1, 1, -1 }, flatten.orientation) );
|
||||
uniforms.matrices.model[i] = ::matrix * rotation;
|
||||
*/
|
||||
auto& scene = this->getRootParent<uf::Scene>();
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
|
||||
@ -1012,7 +1016,7 @@ void ext::GuiBehavior::render( uf::Object& self ){
|
||||
} else {
|
||||
{
|
||||
/* Update GUI panel */ {
|
||||
auto& scene = this->getRootParent<uf::Scene>();
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
auto* renderMode = (uf::renderer::RenderTargetRenderMode*) &uf::renderer::getRenderMode("Gui");
|
||||
|
||||
@ -101,12 +101,12 @@ void ext::RayTracingSceneBehavior::tick( uf::Object& self ) {
|
||||
};
|
||||
|
||||
struct SpecializationConstant {
|
||||
int32_t eyes = 2;
|
||||
int32_t maxLights = 16;
|
||||
uint32_t eyes = 2;
|
||||
uint32_t maxLights = 16;
|
||||
} specializationConstants;
|
||||
|
||||
auto& shader = renderMode.compute.material.shaders.front();
|
||||
specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
|
||||
specializationConstants = *((SpecializationConstant*) &shader.specializationConstants[0]);
|
||||
|
||||
struct PushConstant {
|
||||
uint32_t marchingSteps;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#!/bin/bash
|
||||
tskill program
|
||||
cd bin
|
||||
./program.bat
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user