Commit for 2020.10.08.7z

This commit is contained in:
mrq 2020-10-08 00:00:00 -05:00
parent 0563fdfb4a
commit 3fdc1820ea
40 changed files with 1868 additions and 391 deletions

View File

@ -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

View File

@ -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);
}

View 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);
}

View 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);
}

View 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 ***/

View File

@ -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;

View File

@ -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>

View File

@ -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 );
}

View File

@ -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();

View File

@ -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
);
}

View File

@ -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;

View File

@ -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;

View 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;
};
}

View File

@ -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

View File

@ -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 ) {

View File

@ -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 ) {

View File

@ -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>();

View File

@ -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";
});
}

View File

@ -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 ) {

View File

@ -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

View File

@ -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;
}

View File

@ -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 );

View File

@ -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;
}

View File

@ -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

View File

@ -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();

View File

@ -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();
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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} );
}

View File

@ -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 = {
{

View 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;
}

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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 ) {

View File

@ -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;

View 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

View File

@ -0,0 +1,17 @@
#pragma once
#include <uf/config.h>
#include <uf/ext/ext.h>
#include <uf/engine/entity/entity.h>
#include <uf/engine/scene/scene.h>
namespace ext {
class EXT_API 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& );
};
}

View File

@ -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");

View File

@ -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;

View File

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