Commit for 2022.04.24 23-41-03.7z

This commit is contained in:
mrq 2022-04-24 23:41:00 -05:00
parent 947423860d
commit ccf743d344
45 changed files with 816 additions and 450 deletions

View File

@ -31,8 +31,8 @@ EXT_LIB_NAME += ext
#VULKAN_SDK_PATH += /c/VulkanSDK/1.2.162.0/
#VULKAN_SDK_PATH += /c/VulkanSDK/1.2.176.1/
#VULKAN_SDK_PATH += /c/VulkanSDK/1.2.182.0/
#VULKAN_SDK_PATH += /c/VulkanSDK/1.2.198.1/
VULKAN_SDK_PATH += /c/VulkanSDK/1.3.204.1/
VULKAN_SDK_PATH += /c/VulkanSDK/1.2.198.1/
#VULKAN_SDK_PATH += /c/VulkanSDK/1.3.204.1/
#GLSLC += $(VULKAN_SDK_PATH)/Bin/glslangValidator
GLSLC += $(VULKAN_SDK_PATH)/Bin/glslc

View File

@ -1,7 +1,7 @@
{
"engine": {
"scenes": {
"start": "SS2",
"start": "SH2_McDonalds",
"meshes": { "interleave": false },
"matrix": { "reverseInfinite": true },
"lights": {
@ -23,7 +23,7 @@
}
},
"vxgi": {
"limiter": 0.5,
"limiter": 2,
"size": 96,
"dispatch": 8,
"cascades": 4,
@ -62,8 +62,9 @@
"size": 1,
// "size": [ 640, 480, "NEAREST" ],
// "size": [ 1280, 720 ],
"size": [ 960, 540 ],
"msaa": 16
// "size": [ 960, 540 ],
// "size": [ 640, 480 ],
"msaa": 0
},
"experimental": {
"rebuild on tick begin": false,
@ -77,7 +78,7 @@
"vsync": true,
"hdr": true,
"vxgi": true,
"deferred sampling": false,
"deferred sampling": true, // broken for some scenes
"culling": true,
"bloom": false
},
@ -243,7 +244,7 @@
"cursor" : {
"visible" : true,
"center" : false,
"sensitivity": [ 0.8, 0.8 ]
"sensitivity": [ 1, 1 ]
},
"mode" : "windowed", // fullscreen, borderless, windowed
"icon" : "./data/textures/icon.png",

View File

@ -32,9 +32,17 @@
"trigger": { "mode": "rendered" },
"output": "./lightmap.png"
},
"grid": {
"/^worldspawn/": {
"size": [3,3,3],
// "epsilon": 0.01,
"cleanup": true,
"print": true
}
},
// "lightmap": "./lightmap.min.png",
// "lightmap": "./lightmap.png",
"filter": "NEAREST",
// "filter": "NEAREST",
"flags": {
"ATLAS": false,
"INVERT": false,

View File

@ -1,7 +1,7 @@
{
"type": "Object",
"name": "Player: Model",
"ignore": true,
"ignore": false,
"assets": [
"/player/bear.glb"
// { "filename": "/player/bear/graph.json", "delay": 0, "single threaded": false, "category": "models" }

View File

@ -6,12 +6,13 @@
// { "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false }
// { "filename": "./models/mcdonalds/graph.json", "delay": 0, "single threaded": false, "category": "models" }
{ "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/mini_mcd.glb", "delay": 0, "single threaded": false }
// { "filename": "./models/mini_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
],
"metadata": {
"model": {
// "grid": { "/^worldspawn/": { "size": 1 } },
"cull mode": "none",
"tags": {
"worldspawn": { "physics": { "type": "mesh", "static": true } },

View File

@ -20,11 +20,6 @@
],
"metadata": {
"model": {
"chunk": {
"enabled": true,
"size": 3, // [3,3,3],
"target": "worldspawn"
},
"exporter": {
"enabled": false
},
@ -35,6 +30,7 @@
"trigger": { "mode": "rendered" },
"output": "./lightmap.png"
},
"filter": "NEAREST",
"tags": {
"worldspawn": { "physics": { "type": "mesh", "static": true } },
"worldspawn_20": { "physics": { "type": "mesh", "static": true } },

View File

@ -21,7 +21,7 @@ layout (location = 1) out vec2 outNormals;
#endif
void main() {
float mip = mipLevel(inUv.xy);
float mip = mipLevel(dFdx(inUv), dFdy(inUv));
vec2 uv = inUv.xy;
vec4 C = vec4(1, 1, 1, 1);
vec3 P = inPosition;

View File

@ -53,27 +53,21 @@ bool validTextureIndex( uint start, int offset ) {
uint textureIndex( uint start, int offset ) {
return start + offset;
}
#if TEXTURE_WORKAROUND
vec4 sampleTexture( uint id, vec2 uv ) {
const Texture t = textures[id];
return texture( samplerTextures[nonuniformEXT(t.index - surface.instance.imageID)], mix( t.lerp.xy, t.lerp.zw, uv ) );
}
vec4 sampleTexture( uint id, vec2 uv, float mip ) {
const Texture t = textures[id];
return textureLod( samplerTextures[nonuniformEXT(t.index - surface.instance.imageID)], mix( t.lerp.xy, t.lerp.zw, uv ), mip );
}
#else
vec4 sampleTexture( uint id, vec2 uv ) {
const Texture t = textures[id];
return texture( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ) );
}
vec4 sampleTexture( uint id, vec2 uv, float mip ) {
#if QUERY_MIPMAP
return sampleTexture( id, uv );
#else
const Texture t = textures[id];
return textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip );
}
#endif
vec4 sampleTexture( uint id ) { return sampleTexture( id, surface.uv ); }
vec4 sampleTexture( uint id, float mip ) { return sampleTexture( id, surface.uv, mip ); }
}
vec4 sampleTexture( uint id, vec3 uvm ) { return sampleTexture( id, uvm.xy, uvm.z ); }
vec4 sampleTexture( uint id ) { return sampleTexture( id, surface.uv.xy, surface.uv.z ); }
vec4 sampleTexture( uint id, float mip ) { return sampleTexture( id, surface.uv.xy, mip ); }
#endif
vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) {
const vec3 t0 = (boundsMin - ray.origin) / ray.direction;
@ -101,10 +95,12 @@ void whitenoise(inout vec3 color, const vec4 parameters) {
const float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) );
color = mix( color, vec3(whiteNoise), blend );
}
float mipLevel( in vec2 uv ) {
const vec2 dx_vtc = dFdx(uv);
const vec2 dy_vtc = dFdy(uv);
return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)));
float mipLevel( in vec2 dx_vtc, in vec2 dy_vtc ) {
const float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
return 0.5 * log2(delta_max_sqr);
// return max(0.0, 0.5 * log2(delta_max_sqr) - 1.0);
// return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)));
}
vec4 resolve( subpassInputMS t, const uint samples ) {
vec4 resolved = vec4(0);

View File

@ -6,6 +6,9 @@
#ifndef MULTISAMPLING
#define MULTISAMPLING 1
#endif
#ifndef MAX_MSAA_SAMPLES
#define MAX_MSAA_SAMPLES 16
#endif
#ifndef DEFERRED_SAMPLING
#define DEFERRED_SAMPLING 1
#endif

View File

@ -148,8 +148,8 @@ struct SurfaceMaterial {
struct Surface {
uint pass;
vec2 uv;
vec2 st;
vec3 uv;
vec3 st;
Space position;
Space normal;
@ -161,6 +161,15 @@ struct Surface {
vec4 fragment;
} surface;
// MSAA info
#if MULTISAMPLING
struct MSAA {
int currentID;
uvec2 IDs[MAX_MSAA_SAMPLES];
vec4 fragment;
vec4 fragments[MAX_MSAA_SAMPLES];
} msaa;
#endif
// VXGI stuff
struct Vxgi {
mat4 matrix;

View File

@ -9,7 +9,7 @@
#if DEFERRED_SAMPLING
layout (binding = 3) uniform sampler2D samplerUvs;
#else
layout (binding = 4) uniform sampler2D samplerAlbedo;
layout (binding = 3) uniform sampler2D samplerAlbedo;
#endif
#else
layout (binding = 1) uniform usampler2DMS samplerId;
@ -17,7 +17,7 @@
#if DEFERRED_SAMPLING
layout (binding = 3) uniform sampler2DMS samplerUvs;
#else
layout (binding = 4) uniform sampler2DMS samplerAlbedo;
layout (binding = 3) uniform sampler2DMS samplerAlbedo;
#endif
#endif

View File

@ -1,8 +1,8 @@
#version 450
#pragma shader_stage(fragment)
#define MULTISAMPLING 1
#define DEFERRED_SAMPLING 1
#define MULTISAMPLING 0
#include "./subpass.h"

View File

@ -2,7 +2,7 @@
#pragma shader_stage(fragment)
#define DEFERRED_SAMPLING 0
#define MULTISAMPLING 1
#define MULTISAMPLING 0
#include "./subpass.h"
void main() {

View File

@ -3,6 +3,8 @@
#define DEFERRED 1
#define MAX_TEXTURES TEXTURES
//#define TEXTURE_WORKAROUND 0
#include "../common/macros.h"
layout (constant_id = 0) const uint TEXTURES = 512;
@ -20,6 +22,9 @@ layout (constant_id = 1) const uint CUBEMAPS = 128;
layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerAlbedo;
#endif
layout (input_attachment_index = 3, binding = 3) uniform subpassInput samplerDepth;
#if DEFERRED_SAMPLING
layout (input_attachment_index = 4, binding = 4) uniform subpassInput samplerMips;
#endif
#else
layout (input_attachment_index = 0, binding = 0) uniform usubpassInputMS samplerId;
layout (input_attachment_index = 1, binding = 1) uniform subpassInputMS samplerNormal;
@ -29,6 +34,9 @@ layout (constant_id = 1) const uint CUBEMAPS = 128;
layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerAlbedo;
#endif
layout (input_attachment_index = 3, binding = 3) uniform subpassInputMS samplerDepth;
#if DEFERRED_SAMPLING
layout (input_attachment_index = 4, binding = 4) uniform subpassInputMS samplerMips;
#endif
#endif
#include "../common/structs.h"
@ -120,12 +128,14 @@ void postProcess() {
}
void populateSurface() {
surface.fragment = vec4(0);
surface.pass = inPushConstantPass.x;
{
#if !MULTISAMPLING
const float depth = subpassLoad(samplerDepth).r;
#else
const float depth = resolve(samplerDepth, ubo.msaa).r;
const float depth = subpassLoad(samplerDepth, msaa.currentID).r; // resolve(samplerDepth, ubo.msaa).r;
#endif
vec4 positionEye = ubo.eyes[surface.pass].iProjection * vec4(inUv * 2.0 - 1.0, depth, 1.0);
@ -165,12 +175,13 @@ void populateSurface() {
surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz;
}
#endif
#if !MULTISAMPLING
surface.normal.world = decodeNormals( subpassLoad(samplerNormal).xy );
const uvec2 ID = subpassLoad(samplerId).xy;
#else
surface.normal.world = decodeNormals( resolve(samplerNormal, ubo.msaa).xy );
const uvec2 ID = subpassLoad(samplerId, 0).xy; //resolve(samplerId, ubo.msaa).xy;
surface.normal.world = decodeNormals( subpassLoad(samplerNormal, msaa.currentID).xy ); // decodeNormals( resolve(samplerNormal, ubo.msaa).xy );
const uvec2 ID = msaa.IDs[msaa.currentID]; // subpassLoad(samplerId, msaa.currentID).xy; //resolve(samplerId, ubo.msaa).xy;
#endif
surface.normal.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0.0) );
@ -198,16 +209,20 @@ void populateSurface() {
#if DEFERRED_SAMPLING
{
#if !MULTISAMPLING
vec4 uv = subpassLoad(samplerUv);
const vec4 uv = subpassLoad(samplerUv);
const vec2 mips = vec2(0); // subpassLoad(samplerMips).xy;
#else
vec4 uv = resolve(samplerUv, ubo.msaa);
const vec4 uv = subpassLoad(samplerUv, msaa.currentID); // resolve(samplerUv, ubo.msaa);
const vec2 mips = vec2(0); // subpassLoad(samplerMips, msaa.currentID).xy; // resolve(samplerUv, ubo.msaa);
#endif
surface.uv = uv.xy;
surface.st = uv.zw;
surface.uv.xy = uv.xy;
surface.uv.z = mips.x;
surface.st.xy = uv.zw;
surface.st.z = mips.y;
}
const float mip = mipLevel(inUv.xy);
if ( validTextureIndex( material.indexAlbedo ) ) {
surface.material.albedo = sampleTexture( material.indexAlbedo, mip );
surface.material.albedo = sampleTexture( material.indexAlbedo );
}
// OPAQUE
if ( material.modeAlpha == 0 ) {
@ -225,15 +240,15 @@ void populateSurface() {
}
// Emissive textures
if ( validTextureIndex( material.indexEmissive ) ) {
surface.material.albedo += sampleTexture( material.indexEmissive, mip );
surface.material.albedo += sampleTexture( material.indexEmissive );
}
// Occlusion map
if ( validTextureIndex( material.indexOcclusion ) ) {
surface.material.occlusion = sampleTexture( material.indexOcclusion, mip ).r;
surface.material.occlusion = sampleTexture( material.indexOcclusion ).r;
}
// Metallic/Roughness map
if ( validTextureIndex( material.indexMetallicRoughness ) ) {
vec4 samp = sampleTexture( material.indexMetallicRoughness, mip );
vec4 samp = sampleTexture( material.indexMetallicRoughness );
surface.material.metallic = samp.r;
surface.material.roughness = samp.g;
}
@ -241,7 +256,7 @@ void populateSurface() {
#if !MULTISAMPLING
surface.material.albedo = subpassLoad(samplerAlbedo);
#else
surface.material.albedo = resolve(samplerAlbedo, ubo.msaa);
surface.material.albedo = subpassLoad(samplerAlbedo, msaa.currentID); // resolve(samplerAlbedo, ubo.msaa);
#endif
#endif
}
@ -263,4 +278,36 @@ void directLighting() {
#elif PHONG
phong();
#endif
}
}
#if MULTISAMPLING
void resolveSurfaceFragment() {
for ( int i = 0; i < ubo.msaa; ++i ) {
msaa.currentID = i;
msaa.IDs[i] = subpassLoad(samplerId, msaa.currentID).xy;
// check if ID is already used
bool unique = true;
for ( int j = msaa.currentID - 1; j >= 0; --j ) {
if ( msaa.IDs[j] == msaa.IDs[i] ) {
surface.fragment = msaa.fragments[j];
unique = false;
break;
}
}
if ( unique ) {
populateSurface();
#if VXGI
indirectLighting();
#endif
directLighting();
}
msaa.fragment += surface.fragment;
msaa.fragments[msaa.currentID] = surface.fragment;
}
surface.fragment = msaa.fragment / ubo.msaa;
}
#endif

View File

@ -2,10 +2,10 @@
#pragma shader_stage(fragment)
#define DEFERRED_SAMPLING 1
#define MULTISAMPLING 1
#include "./subpass.h"
void main() {
populateSurface();
directLighting();
resolveSurfaceFragment();
postProcess();
}

View File

@ -2,10 +2,11 @@
#pragma shader_stage(fragment)
#define DEFERRED_SAMPLING 0
#define MULTISAMPLING 1
#include "./subpass.h"
void main() {
populateSurface();
directLighting();
resolveSurfaceFragment();
postProcess();
}

View File

@ -3,11 +3,10 @@
#define VXGI 1
#define DEFERRED_SAMPLING 1
#define MULTISAMPLING 1
#include "./subpass.h"
void main() {
populateSurface();
indirectLighting();
directLighting();
resolveSurfaceFragment();
postProcess();
}

View File

@ -3,11 +3,10 @@
#define VXGI 1
#define DEFERRED_SAMPLING 0
#define MULTISAMPLING 1
#include "./subpass.h"
void main() {
populateSurface();
indirectLighting();
directLighting();
resolveSurfaceFragment();
postProcess();
}

View File

@ -99,8 +99,8 @@ void main() {
#if DEFERRED_SAMPLING
{
vec4 uv = imageLoad(voxelUv[CASCADE], ivec3(tUvw) );
surface.uv = uv.xy;
surface.st = uv.zw;
surface.uv.xy = uv.xy;
surface.st.xy = uv.zw;
}
if ( validTextureIndex( material.indexAlbedo ) ) {
surface.material.albedo = sampleTexture( material.indexAlbedo );

View File

@ -48,14 +48,14 @@ layout (location = 8) flat in uvec4 inId;
layout (location = 0) out vec4 outAlbedo;
void main() {
const float mip = mipLevel(inUv.xy);
const uint drawID = uint(inId.x);
const uint instanceID = uint(inId.y);
const uint materialID = uint(inId.z);
vec4 A = vec4(1, 1, 1, 1);
surface.normal.world = normalize( inNormal );
surface.uv = wrap(inUv.xy);
surface.uv.xy = wrap(inUv.xy);
surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv));
surface.position.world = inPosition;
const Material material = materials[materialID];

View File

@ -2,4 +2,5 @@
#pragma shader_stage(fragment)
#define DEFERRED_SAMPLING 0
#define QUERY_MIPMAP 1
#include "./base.frag.h"

View File

@ -1,5 +1,4 @@
//#extension GL_EXT_nonuniform_qualifier : enable
#define CUBEMAPS 1
#define FRAGMENT 1
// #define MAX_TEXTURES TEXTURES
@ -34,6 +33,7 @@ layout (location = 0) out uvec2 outId;
layout (location = 1) out vec2 outNormals;
#if DEFERRED_SAMPLING
layout (location = 2) out vec4 outUvs;
layout (location = 3) out vec2 outMips;
#else
layout (location = 2) out vec4 outAlbedo;
#endif
@ -42,12 +42,13 @@ void main() {
const uint drawID = uint(inId.x);
const uint instanceID = uint(inId.y);
const uint materialID = uint(inId.z);
const float mip = mipLevel(inUv.xy);
const vec2 uv = wrap(inUv.xy);
const vec3 P = inPosition;
surface.uv = uv;
surface.st = inSt;
surface.uv.xy = uv;
surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv));
surface.st.xy = inSt;
surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt));
vec3 N = inNormal;
vec4 A = vec4(0, 0, 0, 0);
@ -64,7 +65,7 @@ void main() {
// sample albedo
if ( !validTextureIndex( material.indexAlbedo ) ) discard; {
A = sampleTexture( material.indexAlbedo, mip );
A = sampleTexture( material.indexAlbedo );
// alpha mode OPAQUE
if ( material.modeAlpha == 0 ) {
A.a = 1;
@ -80,7 +81,7 @@ void main() {
}
#if USE_LIGHTMAP && !DEFERRED_SAMPLING
if ( validTextureIndex( instance.lightmapID ) ) {
A.rgb *= sampleTexture( instance.lightmapID, inSt, mip ).rgb;
A.rgb *= sampleTexture( instance.lightmapID, surface.st ).rgb;
}
#endif
#endif
@ -88,13 +89,13 @@ void main() {
// sample normal
if ( validTextureIndex( material.indexNormal ) ) {
Texture t = textures[material.indexNormal];
N = inTBN * normalize( sampleTexture( material.indexNormal, mip ).xyz * 2.0 - vec3(1.0));
N = inTBN * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - vec3(1.0));
}
#if 0
// sample metallic/roughness
if ( validTextureIndex( material.indexMetallicRoughness ) ) {
Texture t = textures[material.indexMetallicRoughness];
const vec4 sampled = textureLod( samplerTextures[nonuniformEXT((useAtlas)?textureAtlas.index:t.index)], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
const vec4 sampled = textureLod( samplerTextures[nonuniformEXT((useAtlas)?textureAtlas.index:t.index)], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mipUv );
M = sampled.b;
R = sampled.g;
}
@ -107,8 +108,11 @@ void main() {
#endif
outAlbedo = A * inColor;
#else
outUvs.xy = surface.uv;
outUvs.zw = surface.st;
outUvs.xy = surface.uv.xy;
outUvs.zw = surface.st.xy;
outMips.x = surface.uv.z;
outMips.y = surface.st.z;
#endif
outNormals = encodeNormals( N );
outId = uvec2(drawID + 1, instanceID + 1);

View File

@ -35,17 +35,17 @@ void main() {
const uint drawID = uint(inId.x);
const uint instanceID = uint(inId.y);
const uint materialID = uint(inId.z);
const float mip = mipLevel(inUv.xy);
const vec2 uv = wrap(inUv.xy);
vec4 A = vec4(0, 0, 0, 0);
surface.uv = uv;
surface.uv.xy = uv;
surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv));
const Material material = materials[materialID];
// sample albedo
if ( !validTextureIndex( material.indexAlbedo ) ) discard; {
// const Texture t = textures[material.indexAlbedo];
// A = textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip );
A = sampleTexture( material.indexAlbedo, mip );
A = sampleTexture( material.indexAlbedo );
// alpha mode OPAQUE
if ( material.modeAlpha == 0 ) {
A.a = 1;

View File

@ -61,11 +61,13 @@ void main() {
const uint drawID = uint(inId.x);
const uint instanceID = uint(inId.y);
const uint materialID = uint(inId.z);
const float mip = mipLevel(inUv.xy);
const vec2 uv = wrap(inUv.xy);
surface.uv = uv;
surface.st = inSt;
surface.uv.xy = uv;
surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv));
surface.st.xy = inSt;
surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt));
vec3 N = inNormal;
vec4 A = vec4(0, 0, 0, 0);
@ -80,7 +82,7 @@ void main() {
// sample albedo
if ( !validTextureIndex( material.indexAlbedo ) ) discard; {
if ( surface.instance.imageID <= 0 ) {
A = sampleTexture( material.indexAlbedo, mip );
A = sampleTexture( material.indexAlbedo );
} else {
const Texture t = textures[material.indexAlbedo];
A = texture( samplerTextures[nonuniformEXT(t.index - surface.instance.imageID)], mix( t.lerp.xy, t.lerp.zw, uv ) );
@ -100,7 +102,7 @@ void main() {
}
#if USE_LIGHTMAP && !DEFERRED_SAMPLING
if ( validTextureIndex( instance.lightmapID ) ) {
// A.rgb *= sampleTexture( instance.lightmapID, inSt, mip ).rgb;
A.rgb *= sampleTexture( instance.lightmapID, inSt ).rgb;
}
#endif

View File

@ -24,8 +24,8 @@ layout (location = 1) out vec2 outNormals;
void main() {
if ( inUv.x < inGui.offset.x || inUv.y < inGui.offset.y || inUv.x > inGui.offset.z || inUv.y > inGui.offset.w ) discard;
const float mip = mipLevel(inUv.xy);
const vec2 uv = inUv.xy;
const float mip = mipLevel(dFdx(inUv), dFdy(inUv));
vec4 C = inGui.color;
#if GLYPH
if ( enabled(inGui.mode, 1) ) {

View File

@ -65,14 +65,19 @@ namespace pod {
public:
uf::stl::vector<Key> keys;
uf::stl::unordered_map<Key, T> map;
uf::stl::unordered_map<Key, size_t> indices;
T& operator[]( const Key& key ) {
if ( map.count( key ) == 0 ) keys.emplace_back( key );
if ( map.count( key ) == 0 ) {
indices[key] = keys.size();
keys.emplace_back( key );
}
return map[key];
}
void reserve( size_t i ) {
keys.reserve(i);
indices.reserve(i);
map.reserve(i);
}
};

View File

@ -1,42 +1,10 @@
namespace pod {
struct UF_API DrawCommand {
uint32_t indices = 0; // triangle count
uint32_t instances = 0; // instance count
uint32_t indexID = 0; // starting triangle position
int32_t vertexID = 0; // starting vertex position
uint32_t instanceID = 0; // starting instance position
// extra data
uint32_t padding1 = 0; //
uint32_t padding2 = 0; //
uint32_t vertices = 0; //
};
template<typename T, typename U = uint32_t>
struct UF_API Meshlet_T {
uf::stl::vector<T> vertices;
uf::stl::vector<U> indices;
struct UF_API Instance {
pod::Matrix4f model;
pod::Vector4f color = {1,1,1,1};
alignas(4) uint32_t materialID = 0;
alignas(4) uint32_t primitiveID = 0;
alignas(4) uint32_t meshID = 0;
alignas(4) uint32_t objectID = 0;
alignas(4) int32_t jointID = -1;
alignas(4) int32_t lightmapID = -1;
alignas(4) uint32_t imageID = 0;
alignas(4) uint32_t padding3 = 0;
struct Bounds {
pod::Vector3f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
alignas(4) float padding1 = 0;
pod::Vector3f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
alignas(4) float padding2 = 0;
} bounds;
};
struct Primitive {
pod::DrawCommand drawCommand;
pod::Instance instance;
pod::Primitive primitive;
};
struct UF_API Material {

View File

@ -1,10 +1,10 @@
#pragma once
#if 0
#include <uf/config.h>
#include <cstdint>
namespace pod {
struct UF_API Primitive {
struct UF_API RTPrimitive {
static const uint32_t EMPTY = (uint32_t) -1;
static const uint32_t CUBE = 1;
static const uint32_t LEAF = 2;
@ -27,9 +27,10 @@ namespace pod {
namespace uf {
namespace primitive {
uf::stl::vector<pod::Tree> UF_API populate( const uf::stl::vector<pod::Primitive>& cubes );
uf::stl::vector<pod::Tree> UF_API populateEntirely( const uf::stl::vector<pod::Primitive>& cubes );
uf::stl::vector<pod::Tree> UF_API populate( const uf::stl::vector<pod::RTPrimitive>& cubes );
uf::stl::vector<pod::Tree> UF_API populateEntirely( const uf::stl::vector<pod::RTPrimitive>& cubes );
uf::stl::vector<pod::Tree> UF_API populateEntirely( const uf::stl::vector<pod::Tree>& trees, bool = false );
void UF_API test( const uf::stl::vector<pod::Primitive>& cubes, const uf::stl::vector<pod::Tree>& trees );
void UF_API test( const uf::stl::vector<pod::RTPrimitive>& cubes, const uf::stl::vector<pod::Tree>& trees );
}
}
}
#endif

View File

@ -528,4 +528,15 @@ namespace pod {
};
}
namespace std {
template<typename T, size_t N>
struct hash<pod::Vector<T,N>> {
size_t operator()(const pod::Vector<T,N>& v) const {
size_t hash = 0;
for ( size_t i = 0; i < N; ++i ) hash ^= v[i];
return hash;
}
};
}
#include "vector/vector.inl"

View File

@ -2,22 +2,28 @@
#include <uf/config.h>
#include <uf/utils/mesh/mesh.h>
#include <uf/engine/graph/graph.h>
#include <limits>
namespace uf {
namespace meshgrid {
struct UF_API Node {
struct Node {
struct {
pod::Vector3f min = {};
pod::Vector3f max = {};
} extents;
struct {
pod::Vector3f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
pod::Vector3f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
} effectiveExtents;
pod::Vector3ui id = {};
uf::stl::vector<uint32_t> indices;
uf::stl::unordered_map<size_t, uf::Meshlet_T<>> meshlets;
};
struct Grid {
int divisions = 1;
pod::Vector3ui divisions = {1,1,1};
int indices = 0;
struct {
pod::Vector3f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
@ -30,25 +36,81 @@ namespace uf {
pod::Vector3f piece = {};
} extents;
uf::stl::vector<Node> nodes;
// uf::stl::vector<Node> nodes;
uf::stl::unordered_map<pod::Vector3ui, Node> nodes;
};
void UF_API print( const Grid&, size_t indices );
Grid UF_API generate( int divisions, void* pPointer, size_t pStride, size_t pFirst, size_t pCount, void* iPointer, size_t iStride, size_t iFirst, size_t iCount );
Grid UF_API partition( uf::Mesh&, int );
void UF_API print( const Grid& );
void UF_API cleanup( Grid& );
void UF_API calculate( uf::meshgrid::Grid&, float = std::numeric_limits<float>::epsilon() );
void UF_API calculate( uf::meshgrid::Grid&, int, float = std::numeric_limits<float>::epsilon() );
void UF_API calculate( uf::meshgrid::Grid&, const pod::Vector3ui&, float = std::numeric_limits<float>::epsilon() );
void UF_API partition( uf::meshgrid::Grid&, const void*, size_t, const void*, size_t, const pod::Primitive& );
void UF_API partition( uf::meshgrid::Grid&, uf::Mesh&, const pod::Primitive& );
template<typename T, typename U = uint32_t>
Grid UF_API partition( uf::stl::vector<T>& vertices, uf::stl::vector<U>& indices, int divisions ) {
void UF_API partition( uf::meshgrid::Grid& grid, const uf::stl::vector<T>& vertices, const uf::stl::vector<U>& indices, const pod::Primitive& primitive ) {
auto vertexDescriptor = T::descriptor.front();
for ( auto& descriptor : T::descriptor ) if ( descriptor.name == "position" ) { vertexDescriptor = descriptor; break; }
UF_ASSERT( vertexDescriptor.name == "position" );
return generate( divisions,
vertices.data(), sizeof(T), 0, vertices.size(),
indices.data(), sizeof(U), 0, indices.size()
return partition( grid,
vertices.data(), sizeof(T),
indices.data(), sizeof(U),
primitive
);
}
template<typename T, typename U = uint32_t>
uf::stl::vector<uf::Meshlet_T<T,U>> UF_API partition( uf::meshgrid::Grid& grid, const uf::stl::vector<uf::Meshlet_T<T,U>>& meshlets, float eps = std::numeric_limits<float>::epsilon() ) {
uf::stl::vector<uf::Meshlet_T<T,U>> partitioned;
for ( auto& meshlet : meshlets ) {
grid.extents.min = uf::vector::min( grid.extents.min, meshlet.primitive.instance.bounds.min );
grid.extents.max = uf::vector::max( grid.extents.max, meshlet.primitive.instance.bounds.max );
}
uf::meshgrid::calculate( grid, eps );
for ( auto& meshlet : meshlets ) {
uf::meshgrid::partition<T,U>( grid, meshlet.vertices, meshlet.indices, meshlet.primitive );
}
uf::meshgrid::cleanup( grid );
for ( auto& pair : grid.nodes ) { auto& node = pair.second;
for ( auto& pair2 : node.meshlets ) { auto& mlet = pair2.second;
if ( mlet.indices.empty() ) continue;
auto& meshlet = meshlets[mlet.primitive.instance.primitiveID];
auto& slice = partitioned.emplace_back();
slice.vertices.reserve( mlet.indices.size() );
slice.indices.reserve( mlet.indices.size() );
for ( auto idx : mlet.indices ) {
slice.vertices.emplace_back( meshlet.vertices[idx] );
slice.indices.emplace_back( slice.indices.size() );
}
slice.primitive.instance.materialID = meshlet.primitive.instance.materialID;
slice.primitive.instance.primitiveID = partitioned.size() - 1;
slice.primitive.instance.meshID = meshlet.primitive.instance.meshID;
slice.primitive.instance.objectID = 0;
slice.primitive.instance.bounds.min = node.effectiveExtents.min;
slice.primitive.instance.bounds.max = node.effectiveExtents.max;
slice.primitive.drawCommand.indices = slice.indices.size();
slice.primitive.drawCommand.instances = 1;
slice.primitive.drawCommand.indexID = 0;
slice.primitive.drawCommand.vertexID = 0;
slice.primitive.drawCommand.instanceID = 0;
slice.primitive.drawCommand.vertices = slice.vertices.size();
}
}
return partitioned;
}
}
}

View File

@ -46,6 +46,48 @@ namespace ext {
}
}
namespace pod {
struct UF_API DrawCommand {
uint32_t indices = 0; // triangle count
uint32_t instances = 0; // instance count
uint32_t indexID = 0; // starting triangle position
int32_t vertexID = 0; // starting vertex position
uint32_t instanceID = 0; // starting instance position
// extra data
uint32_t padding1 = 0; //
uint32_t padding2 = 0; //
uint32_t vertices = 0; //
};
struct UF_API Instance {
pod::Matrix4f model;
pod::Vector4f color = {1,1,1,1};
alignas(4) uint32_t materialID = 0;
alignas(4) uint32_t primitiveID = 0;
alignas(4) uint32_t meshID = 0;
alignas(4) uint32_t objectID = 0;
alignas(4) int32_t jointID = -1;
alignas(4) int32_t lightmapID = -1;
alignas(4) uint32_t imageID = 0;
alignas(4) uint32_t padding3 = 0;
struct Bounds {
pod::Vector3f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
alignas(4) float padding1 = 0;
pod::Vector3f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
alignas(4) float padding2 = 0;
} bounds;
};
struct Primitive {
pod::DrawCommand drawCommand;
pod::Instance instance;
};
}
namespace uf {
struct UF_API Mesh {
public:
@ -210,15 +252,6 @@ namespace uf {
_bind( interleave );
}
};
template<typename T, typename U = uint32_t>
struct UF_API Mesh_T {
typedef T vertex_t;
typedef U index_t;
uf::stl::vector<vertex_t> vertices;
uf::stl::vector<index_t> indices;
};
}
namespace ext {
@ -350,4 +383,26 @@ namespace pod {
static UF_API uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
};
}
namespace uf {
template<typename T = pod::Vertex_3F, typename U = ext::RENDERER::index_t>
struct UF_API Mesh_T {
typedef T vertex_t;
typedef U index_t;
uf::stl::vector<vertex_t> vertices;
uf::stl::vector<index_t> indices;
uf::stl::vector<pod::Primitive> primitives;
};
template<typename T = pod::Vertex_3F, typename U = ext::RENDERER::index_t>
struct UF_API Meshlet_T {
typedef T vertex_t;
typedef U index_t;
uf::stl::vector<vertex_t> vertices;
uf::stl::vector<index_t> indices;
pod::Primitive primitive;
};
}

View File

@ -9,6 +9,9 @@
namespace uf {
namespace string {
// bool match( const uf::stl::string& str, const uf::stl::string& r );
bool UF_API isRegex( const uf::stl::string& str );
uf::stl::vector<uf::stl::string> UF_API matches( const uf::stl::string& str, const uf::stl::string& r );
uf::stl::string UF_API replace( const uf::stl::string&, const uf::stl::string&, const uf::stl::string& );
uf::stl::string UF_API lowercase( const uf::stl::string& );

View File

@ -11,7 +11,7 @@
namespace {
size_t UF_API process( uf::Object& object, pod::Graph& graph, pod::Node& parent ) {
size_t process( uf::Object& object, pod::Graph& graph, pod::Node& parent ) {
// grab relevant IDs
size_t nodeID = graph.nodes.size();
size_t instanceID = uf::graph::storage.instances.keys.size(); // graph.instances.size();

View File

@ -7,6 +7,7 @@
#include <uf/utils/graphic/graphic.h>
#include <uf/utils/camera/camera.h>
#include <uf/utils/math/physics.h>
#include <uf/utils/memory/map.h>
#include <uf/ext/xatlas/xatlas.h>
#if UF_ENV_DREAMCAST
@ -84,11 +85,21 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity ) {
else if ( mode == "both" ) graphic.descriptor.cullMode = uf::renderer::enums::CullMode::BOTH;
}
{
for ( auto& i : graph.images ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[i] );
for ( auto& s : graph.samplers ) graphic.material.samplers.emplace_back( uf::graph::storage.samplers.map[s] );
// for ( auto pair : uf::graph::storage.texture2Ds.map ) graphic.material.textures.emplace_back().aliasTexture( pair.second );
// for ( auto& s : graph.samplers ) graphic.material.samplers.emplace_back( uf::graph::storage.samplers.map[s] );
// for ( auto pair : uf::graph::storage.samplers.map ) graphic.material.samplers.emplace_back( pair.second );
// for ( auto& key : uf::graph::storage.samplers.keys ) graphic.material.samplers.emplace_back( uf::graph::storage.samplers.map[key] );
// for ( auto& i : graph.images ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[i] );
// for ( auto pair : uf::graph::storage.texture2Ds.map ) graphic.material.textures.emplace_back().aliasTexture( pair.second );
#if 1
for ( auto& key : uf::graph::storage.texture2Ds.keys ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[key] );
#else
uf::stl::map<size_t, uf::stl::string> texture2DOrderedMap; // texture2DOrderedMap.reserve( uf::graph::storage.texture2Ds.keys.size() );
for ( auto key : uf::graph::storage.texture2Ds.keys ) {
texture2DOrderedMap[uf::graph::storage.texture2Ds.indices[key]] = key;
}
for ( auto pair : texture2DOrderedMap ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[pair.second] );
#endif
// bind scene's voxel texture
if ( uf::renderer::settings::experimental::vxgi ) {
@ -395,9 +406,15 @@ void uf::graph::process( pod::Graph& graph ) {
// setup textures
uf::graph::storage.texture2Ds.reserve( uf::graph::storage.images.map.size() );
// not having this block will cause our images and texture2Ds to be ordered out of sync
for ( auto& key : graph.images ) {
uf::graph::storage.images[key];
uf::graph::storage.texture2Ds[key];
}
// figure out what texture is what exactly
for ( auto& keyName : graph.materials ) {
auto& material = uf::graph::storage.materials[keyName];
for ( auto& key : graph.materials ) {
auto& material = uf::graph::storage.materials[key];
auto ID = material.indexAlbedo;
if ( !(0 <= ID && ID < graph.textures.size()) ) continue;
@ -407,11 +424,11 @@ void uf::graph::process( pod::Graph& graph ) {
texture.srgb = true;
}
for ( auto& keyName : graph.images ) {
auto& image = uf::graph::storage.images[keyName];
auto& texture = uf::graph::storage.texture2Ds[keyName];
for ( auto& key : graph.images ) {
auto& image = uf::graph::storage.images[key];
auto& texture = uf::graph::storage.texture2Ds[key];
if ( !texture.generated() ) {
bool isLightmap = graph.metadata["lightmapped"].as<uf::stl::string>() == keyName;
bool isLightmap = graph.metadata["lightmapped"].as<uf::stl::string>() == key;
auto filter = graph.metadata["filter"].as<uf::stl::string>() == "NEAREST" && !isLightmap ? uf::renderer::enums::Filter::NEAREST : uf::renderer::enums::Filter::LINEAR;
texture.sampler.descriptor.filter.min = filter;
texture.sampler.descriptor.filter.mag = filter;
@ -427,28 +444,54 @@ void uf::graph::process( pod::Graph& graph ) {
// process nodes
for ( auto index : graph.root.children ) process( graph, index, *graph.root.entity );
// remap materials->texture IDs
for ( auto& name : graph.materials ) {
auto& material = uf::graph::storage.materials[name];
auto& keys = uf::graph::storage.textures.keys;
int32_t* IDs[] = { &material.indexAlbedo, &material.indexNormal, &material.indexEmissive, &material.indexOcclusion, &material.indexMetallicRoughness };
for ( auto* pointer : IDs ) {
auto& ID = *pointer;
if ( !(0 <= ID && ID < graph.materials.size()) ) continue;
auto it = std::find( keys.begin(), keys.end(), graph.textures[ID] );
UF_ASSERT( it != keys.end() );
ID = it - keys.begin();
}
}
// remap textures->images IDs
for ( auto& name : graph.textures ) {
auto& texture = uf::graph::storage.textures[name];
auto& keys = uf::graph::storage.images.keys;
if ( !(0 <= texture.index && texture.index < graph.textures.size()) ) continue;
auto it = std::find( keys.begin(), keys.end(), graph.images[texture.index] );
auto& indices = uf::graph::storage.images.indices;
if ( !(0 <= texture.index && texture.index < graph.images.size()) ) continue;
auto& needle = graph.images[texture.index];
#if 1
texture.index = indices[needle];
#elif 1
for ( size_t i = 0; i < keys.size(); ++i ) {
if ( keys[i] != needle ) continue;
texture.index = i;
break;
}
#else
auto it = std::find( keys.begin(), keys.end(), needle );
UF_ASSERT( it != keys.end() );
texture.index = it - keys.begin();
#endif
}
// remap materials->texture IDs
for ( auto& name : graph.materials ) {
auto& material = uf::graph::storage.materials[name];
auto& keys = uf::graph::storage.textures.keys;
auto& indices = uf::graph::storage.textures.indices;
int32_t* IDs[] = { &material.indexAlbedo, &material.indexNormal, &material.indexEmissive, &material.indexOcclusion, &material.indexMetallicRoughness };
for ( auto* pointer : IDs ) {
auto& ID = *pointer;
if ( !(0 <= ID && ID < graph.textures.size()) ) continue;
auto& needle = graph.textures[ID];
#if 1
ID = indices[needle];
#elif 1
for ( size_t i = 0; i < keys.size(); ++i ) {
if ( keys[i] != needle ) continue;
ID = i;
break;
}
#else
if ( !(0 <= ID && ID < graph.textures.size()) ) continue;
auto it = std::find( keys.begin(), keys.end(), needle );
UF_ASSERT( it != keys.end() );
ID = it - keys.begin();
#endif
}
}
// remap instance variables
for ( auto& name : graph.instances ) {
@ -456,16 +499,56 @@ void uf::graph::process( pod::Graph& graph ) {
if ( 0 <= instance.materialID && instance.materialID < graph.materials.size() ) {
auto& keys = /*graph.storage*/uf::graph::storage.materials.keys;
auto it = std::find( keys.begin(), keys.end(), graph.materials[instance.materialID] );
auto& indices = /*graph.storage*/uf::graph::storage.materials.indices;
if ( !(0 <= instance.materialID && instance.materialID < graph.materials.size()) ) continue;
auto& needle = graph.materials[instance.materialID];
#if 1
instance.materialID = indices[needle];
#elif 1
for ( size_t i = 0; i < keys.size(); ++i ) {
if ( keys[i] != needle ) continue;
instance.materialID = i;
break;
}
#else
auto it = std::find( keys.begin(), keys.end(), needle );
UF_ASSERT( it != keys.end() );
instance.materialID = it - keys.begin();
#endif
}
if ( 0 <= instance.lightmapID && instance.lightmapID < graph.textures.size() ) {
auto& keys = /*graph.storage*/uf::graph::storage.textures.keys;
auto& indices = /*graph.storage*/uf::graph::storage.textures.indices;
if ( !(0 <= instance.lightmapID && instance.lightmapID < graph.textures.size()) ) continue;
auto& needle = graph.textures[instance.lightmapID];
#if 1
instance.lightmapID = indices[needle];
#elif 1
for ( size_t i = 0; i < keys.size(); ++i ) {
if ( keys[i] != needle ) continue;
instance.lightmapID = i;
break;
}
#else
auto it = std::find( keys.begin(), keys.end(), needle );
UF_ASSERT( it != keys.end() );
instance.lightmapID = it - keys.begin();
#endif
}
#if 0
// i genuinely dont remember what this is used for
if ( 0 <= instance.imageID && instance.imageID < graph.images.size() ) {
auto& keys = /*graph.storage*/uf::graph::storage.images.keys;
auto it = std::find( keys.begin(), keys.end(), graph.images[instance.imageID] );
UF_ASSERT( it != keys.end() );
instance.imageID = it - keys.begin();
}
#endif
// remap a skinID as an actual jointID
if ( 0 <= instance.jointID && instance.jointID < graph.skins.size() ) {
auto& name = graph.skins[instance.jointID];
@ -476,12 +559,6 @@ void uf::graph::process( pod::Graph& graph ) {
instance.jointID += joints.size();
}
}
if ( 0 <= instance.lightmapID && instance.lightmapID < graph.textures.size() ) {
auto& keys = /*graph.storage*/uf::graph::storage.textures.keys;
auto it = std::find( keys.begin(), keys.end(), graph.textures[instance.lightmapID] );
UF_ASSERT( it != keys.end() );
instance.lightmapID = it - keys.begin();
}
}
uf::graph::reload();
@ -814,7 +891,7 @@ void uf::graph::initialize( pod::Graph& graph ) {
}
void uf::graph::animate( pod::Graph& graph, const uf::stl::string& _name, float speed, bool immediate ) {
if ( !(graph.metadata["flags"]["SKINNED"].as<bool>()) ) return;
const uf::stl::string name = graph.name + "/" + _name;
const uf::stl::string name = /*graph.name + "/" +*/ _name;
// UF_MSG_DEBUG( graph.name << " " << name );
// if ( graph.animations.count( name ) > 0 ) {
if ( uf::graph::storage.animations.map.count( name ) > 0 ) {
@ -980,9 +1057,22 @@ void uf::graph::tick() {
uf::stl::vector<pod::Texture> textures; textures.reserve(uf::graph::storage.textures.map.size());
for ( auto key : uf::graph::storage.drawCommands.keys ) drawCommands.insert( drawCommands.end(), uf::graph::storage.drawCommands.map[key].begin(), uf::graph::storage.drawCommands.map[key].end() );
#if 1
for ( auto key : uf::graph::storage.materials.keys ) materials.emplace_back( uf::graph::storage.materials.map[key] );
for ( auto key : uf::graph::storage.textures.keys ) textures.emplace_back( uf::graph::storage.textures.map[key] );
#else
uf::stl::map<size_t, uf::stl::string> materialOrderedMap; // materialOrderedMap.reserve( uf::graph::storage.materials.keys.size() );
for ( auto key : uf::graph::storage.materials.keys ) {
materialOrderedMap[uf::graph::storage.materials.indices[key]] = key;
}
for ( auto pair : materialOrderedMap ) materials.emplace_back( uf::graph::storage.materials.map[pair.second] );
uf::stl::map<size_t, uf::stl::string> textureOrderedMap; // textureOrderedMap.reserve( uf::graph::storage.textures.keys.size() );
for ( auto key : uf::graph::storage.textures.keys ) {
textureOrderedMap[uf::graph::storage.textures.indices[key]] = key;
}
for ( auto pair : textureOrderedMap ) textures.emplace_back( uf::graph::storage.textures.map[pair.second] );
#endif
// uf::graph::storage.buffers.drawCommands.update( (const void*) drawCommands.data(), drawCommands.size() * sizeof(pod::DrawCommand) );
uf::graph::storage.buffers.material.update( (const void*) materials.data(), materials.size() * sizeof(pod::Material) );
uf::graph::storage.buffers.texture.update( (const void*) textures.data(), textures.size() * sizeof(pod::Texture) );

View File

@ -108,14 +108,6 @@ namespace {
}
return nodeIndex;
}
template<typename T = uf::graph::mesh::Skinned, typename U = uint32_t>
struct Primitive {
uf::stl::vector<T> vertices;
uf::stl::vector<U> indices;
pod::Primitive primitive;
};
}
pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serializer& metadata ) {
@ -147,7 +139,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
for ( auto& i : model.images ) {
auto imageID = graph.images.size();
auto keyName = graph.images.emplace_back(filename + "/" + i.name);
auto keyName = graph.images.emplace_back(/*filename + "/" +*/ i.name);
auto& image = /*graph.storage*/uf::graph::storage.images[keyName];
image.loadFromBuffer( &i.image[0], {i.width, i.height}, 8, i.component, graph.metadata["flip textures"].as<bool>(true) );
}
@ -157,7 +149,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
/*graph.storage*/uf::graph::storage.samplers.reserve(model.samplers.size());
for ( auto& s : model.samplers ) {
auto samplerID = graph.samplers.size();
auto keyName = graph.samplers.emplace_back(filename + "/" + s.name);
auto keyName = graph.samplers.emplace_back(/*filename + "/" +*/ s.name);
auto& sampler = /*graph.storage*/uf::graph::storage.samplers[keyName];
sampler.descriptor.filter.min = getFilterMode( s.minFilter );
@ -174,7 +166,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
for ( auto& t : model.textures ) {
auto textureID = graph.textures.size();
auto keyName = graph.textures.emplace_back((t.name == "" ? graph.images[t.source] : (filename + "/" + t.name)));
auto keyName = graph.textures.emplace_back((t.name == "" ? graph.images[t.source] : (/*filename + "/" +*/ t.name)));
auto& texture = /*graph.storage*/uf::graph::storage.textures[keyName];
texture.index = t.source;
@ -188,7 +180,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
for ( auto& m : model.materials ) {
auto materialID = graph.materials.size();
auto keyName = graph.materials.emplace_back(filename + "/" + m.name);
auto keyName = graph.materials.emplace_back(/*filename + "/" +*/ m.name);
auto& material = /*graph.storage*/uf::graph::storage.materials[keyName];
material.indexAlbedo = m.pbrMetallicRoughness.baseColorTexture.index;
@ -232,7 +224,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
for ( auto& m : model.meshes ) {
auto meshID = graph.meshes.size();
auto keyName = graph.meshes.emplace_back(filename + "/" + m.name);
auto keyName = graph.meshes.emplace_back(/*filename + "/" +*/ m.name);
graph.primitives.emplace_back(keyName);
graph.drawCommands.emplace_back(keyName);
@ -241,9 +233,38 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
auto& primitives = /*graph.storage*/uf::graph::storage.primitives[keyName];
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[keyName];
mesh.bindIndirect<pod::DrawCommand>();
size_t divisions = m.name == "worldspawn_20" ? 2 : 1;
struct {
uf::meshgrid::Grid grid;
ext::json::Value metadata;
float eps = std::numeric_limits<float>::epsilon();
bool print = false;
bool cleanup = true;
} meshgrid;
if ( ext::json::isObject( graph.metadata["grid"][m.name] ) ) {
meshgrid.metadata = graph.metadata["grid"][m.name];
} else {
ext::json::forEach( graph.metadata["grid"], [&]( const uf::stl::string& key, ext::json::Value& value ) {
if ( !ext::json::isNull( meshgrid.metadata["size"] ) ) return;
if ( !uf::string::isRegex( key ) ) return;
if ( uf::string::matches( m.name, key ).empty() ) return;
meshgrid.metadata = value;
});
}
if ( ext::json::isObject( meshgrid.metadata ) ) {
if ( meshgrid.metadata["size"].is<size_t>() ) {
size_t d = meshgrid.metadata["size"].as<size_t>();
meshgrid.grid.divisions = {d, d, d};
} else {
meshgrid.grid.divisions = uf::vector::decode( meshgrid.metadata["size"], meshgrid.grid.divisions );
}
meshgrid.eps = meshgrid.metadata["epsilon"].as(meshgrid.eps);
meshgrid.print = meshgrid.metadata["print"].as(meshgrid.print);
meshgrid.cleanup = meshgrid.metadata["cleanup"].as(meshgrid.cleanup);
}
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
#define UF_GRAPH_MESH_FORMAT uf::graph::mesh::Skinned, uint32_t
#define UF_GRAPH_PROCESS_PRIMITIVES_FULL 1
@ -259,9 +280,6 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
#undef UF_GRAPH_MESH_FORMAT
}
mesh.insertIndirects(drawCommands);
mesh.updateDescriptor();
#if 0
if ( m.name == "worldspawn_20" ) {
uf::stl::vector<::Primitive<>> objs;
@ -339,7 +357,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
for ( auto& s : model.skins ) {
auto skinID = graph.skins.size();
auto keyName = graph.skins.emplace_back(filename + "/" + s.name);
auto keyName = graph.skins.emplace_back(/*filename + "/" +*/ s.name);
auto& skin = /*graph.storage*/uf::graph::storage.skins[keyName];
skin.name = s.name;
@ -373,7 +391,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
for ( auto& a : model.animations ) {
auto animationID = graph.animations.size();
auto keyName = graph.animations.emplace_back(filename + "/" + a.name);
auto keyName = graph.animations.emplace_back(/*filename + "/" +*/ a.name);
auto& animation = /*graph.storage*/uf::graph::storage.animations[keyName];
animation.name = a.name;

View File

@ -1,10 +1,7 @@
uf::stl::vector<::Primitive<UF_GRAPH_MESH_FORMAT>> objs;
uf::stl::vector<::Primitive<UF_GRAPH_MESH_FORMAT>> slices;
mesh.bind<UF_GRAPH_MESH_FORMAT>();
uf::stl::vector<uf::Meshlet_T<UF_GRAPH_MESH_FORMAT>> meshlets;
for ( auto& p : m.primitives ) {
auto& obj = objs.emplace_back();
auto& meshlet = meshlets.emplace_back();
struct Attribute {
uf::stl::string name = "";
@ -41,13 +38,13 @@ for ( auto& p : m.primitives ) {
auto& view = model.bufferViews[accessor.bufferView];
if ( attribute.name == "POSITION" ) {
obj.vertices.resize(accessor.count);
obj.primitive.instance.bounds.min = pod::Vector3f{ accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] };
obj.primitive.instance.bounds.max = pod::Vector3f{ accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] };
meshlet.vertices.resize(accessor.count);
meshlet.primitive.instance.bounds.min = pod::Vector3f{ accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] };
meshlet.primitive.instance.bounds.max = pod::Vector3f{ accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] };
if ( !(graph.metadata["flags"]["INVERT"].as<bool>()) ){
obj.primitive.instance.bounds.min.x = -obj.primitive.instance.bounds.min.x;
obj.primitive.instance.bounds.max.x = -obj.primitive.instance.bounds.max.x;
meshlet.primitive.instance.bounds.min.x = -meshlet.primitive.instance.bounds.min.x;
meshlet.primitive.instance.bounds.max.x = -meshlet.primitive.instance.bounds.max.x;
}
}
@ -83,7 +80,7 @@ for ( auto& p : m.primitives ) {
}
}
for ( size_t i = 0; i < obj.vertices.size(); ++i ) {
for ( size_t i = 0; i < meshlet.vertices.size(); ++i ) {
#if 0
#define ITERATE_ATTRIBUTE( name, member )\
memcpy( &vertex.member[0], &attributes[name].buffer[i * attributes[name].components], attributes[name].stride );
@ -104,7 +101,7 @@ for ( auto& p : m.primitives ) {
}
#endif
auto& vertex = obj.vertices[i];
auto& vertex = meshlet.vertices[i];
ITERATE_ATTRIBUTE("POSITION", position, 1);
ITERATE_ATTRIBUTE("TEXCOORD_0", uv, 1);
ITERATE_ATTRIBUTE("COLOR_0", color, 255.0f);
@ -133,9 +130,9 @@ for ( auto& p : m.primitives ) {
auto& view = model.bufferViews[accessor.bufferView];
auto& buffer = model.buffers[view.buffer];
obj.indices.reserve( static_cast<uint32_t>(accessor.count) );
meshlet.indices.reserve( static_cast<uint32_t>(accessor.count) );
#define COPY_INDICES() for (size_t index = 0; index < accessor.count; index++) obj.indices.emplace_back(buf[index]);
#define COPY_INDICES() for (size_t index = 0; index < accessor.count; index++) meshlet.indices.emplace_back(buf[index]);
const void* pointer = &(buffer.data[accessor.byteOffset + view.byteOffset]);
switch (accessor.componentType) {
@ -158,72 +155,54 @@ for ( auto& p : m.primitives ) {
#undef COPY_INDICES
}
obj.primitive.instance.materialID = p.material;
obj.primitive.instance.primitiveID = objs.size() - 1;
obj.primitive.instance.meshID = meshID;
obj.primitive.instance.objectID = 0;
meshlet.primitive.instance.materialID = p.material;
meshlet.primitive.instance.primitiveID = meshlets.size() - 1;
meshlet.primitive.instance.meshID = meshID;
meshlet.primitive.instance.objectID = 0;
obj.primitive.drawCommand.indices = obj.indices.size();
obj.primitive.drawCommand.instances = 1;
obj.primitive.drawCommand.indexID = 0;
obj.primitive.drawCommand.vertexID = 0;
obj.primitive.drawCommand.instanceID = 0;
obj.primitive.drawCommand.vertices = obj.vertices.size();
meshlet.primitive.drawCommand.indices = meshlet.indices.size();
meshlet.primitive.drawCommand.instances = 1;
meshlet.primitive.drawCommand.indexID = 0;
meshlet.primitive.drawCommand.vertexID = 0;
meshlet.primitive.drawCommand.instanceID = 0;
meshlet.primitive.drawCommand.vertices = meshlet.vertices.size();
}
if ( divisions > 1 ) {
for ( auto& obj : objs ) {
auto grid = uf::meshgrid::partition( obj.vertices, obj.indices, divisions );
// uf::meshgrid::print( grid, obj.indices.size() );
for ( auto& node : grid.nodes ) {
auto& slice = slices.emplace_back();
slice.vertices.reserve( node.indices.size() );
slice.indices.reserve( node.indices.size() );
for ( auto& index : node.indices ) {
slice.vertices.emplace_back( obj.vertices[index] );
slice.indices.emplace_back( slice.indices.size() );
}
if ( meshgrid.grid.divisions.x > 1 && meshgrid.grid.divisions.y > 1 && meshgrid.grid.divisions.z > 1 ) {
auto partitioned = uf::meshgrid::partition( meshgrid.grid, meshlets, meshgrid.eps );
if ( meshgrid.print ) UF_MSG_DEBUG( "Draw commands: " << m.name << ": " << meshlets.size() << " -> " << partitioned.size() );
meshlets = std::move( partitioned );
}
slice.primitive.instance.materialID = obj.primitive.instance.materialID;
slice.primitive.instance.primitiveID = slices.size() - 1;
slice.primitive.instance.meshID = meshID;
slice.primitive.instance.objectID = 0;
{
size_t indexID = 0;
size_t vertexID = 0;
slice.primitive.drawCommand.indices = slice.indices.size();
slice.primitive.drawCommand.instances = 1;
slice.primitive.drawCommand.indexID = 0;
slice.primitive.drawCommand.vertexID = 0;
slice.primitive.drawCommand.instanceID = 0;
slice.primitive.drawCommand.vertices = slice.vertices.size();
}
mesh.bindIndirect<pod::DrawCommand>();
mesh.bind<UF_GRAPH_MESH_FORMAT>();
for ( auto& meshlet : meshlets ) {
drawCommands.emplace_back(pod::DrawCommand{
.indices = meshlet.indices.size(),
.instances = 1,
.indexID = indexID,
.vertexID = vertexID,
.instanceID = 0,
.vertices = meshlet.vertices.size(),
});
primitives.emplace_back( meshlet.primitive );
indexID += meshlet.indices.size();
vertexID += meshlet.vertices.size();
mesh.insertVertices(meshlet.vertices);
mesh.insertIndices(meshlet.indices);
}
UF_MSG_DEBUG( "Draw commands: " << m.name << ": " << objs.size() << " -> " << slices.size() );
} else {
slices = std::move( objs );
}
size_t indexID = 0;
size_t vertexID = 0;
for ( auto& obj : slices ) {
drawCommands.emplace_back(pod::DrawCommand{
.indices = obj.indices.size(),
.instances = 1,
.indexID = indexID,
.vertexID = vertexID,
.instanceID = 0,
.vertices = obj.vertices.size(),
});
primitives.emplace_back( obj.primitive );
indexID += obj.indices.size();
vertexID += obj.vertices.size();
mesh.insertVertices(obj.vertices);
mesh.insertIndices(obj.indices);
mesh.insertIndirects(drawCommands);
mesh.updateDescriptor();
}

View File

@ -94,7 +94,7 @@ namespace {
pod::Vector3f position;
pod::Vector3f color;
static UF_API uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
static uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
};
UF_VERTEX_DESCRIPTOR(VertexLine,
@ -323,11 +323,11 @@ pod::PhysicsState& ext::reactphysics::create( uf::Object& object, const uf::Mesh
rMesh->addSubpart(new rp3d::TriangleVertexArray(
vertexInput.count,
(const uint8_t*) (vertexAttribute.pointer + vertexAttribute.stride * vertexInput.first),
(const uint8_t*) (vertexAttribute.pointer) + vertexAttribute.stride * vertexInput.first,
vertexAttribute.stride,
indexInput.count / 3,
(const uint8_t*) (indexAttribute.pointer + indexAttribute.stride * indexInput.first),
(const uint8_t*) (indexAttribute.pointer) + indexAttribute.stride * indexInput.first,
indexAttribute.stride * 3,
vertexType,
@ -337,11 +337,11 @@ pod::PhysicsState& ext::reactphysics::create( uf::Object& object, const uf::Mesh
} else {
rMesh->addSubpart(new rp3d::TriangleVertexArray(
vertexInput.count,
(const uint8_t*) (vertexAttribute.pointer + vertexAttribute.stride * vertexInput.first),
(const uint8_t*) (vertexAttribute.pointer) + vertexAttribute.stride * vertexInput.first,
vertexAttribute.stride,
indexInput.count / 3,
(const uint8_t*) (indexAttribute.pointer + indexAttribute.stride * indexInput.first),
(const uint8_t*) (indexAttribute.pointer) + indexAttribute.stride * indexInput.first,
indexAttribute.stride * 3,
vertexType,

View File

@ -49,7 +49,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
size_t msaa = ext::vulkan::settings::msaa;
struct {
size_t id, normals, uvs, albedo, depth, color, bright, scratch, output;
size_t id, normals, uvs, mips, albedo, depth, color, bright, scratch, output;
} attachments = {};
bool blend = true; // !ext::vulkan::settings::experimental::deferredSampling;
@ -71,7 +71,15 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
if ( ext::vulkan::settings::experimental::deferredSampling ) {
attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{
// /*.format = */VK_FORMAT_R32G32B32A32_SFLOAT,
/*.format = */VK_FORMAT_R16G16B16A16_UNORM,
/*.format = */VK_FORMAT_R16G16B16A16_SFLOAT,
/*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
/*.blend = */false,
/*.samples = */msaa,
});
attachments.mips = renderTarget.attach(RenderTarget::Attachment::Descriptor{
// /*.format = */VK_FORMAT_R32G32B32A32_SFLOAT,
/*.format = */VK_FORMAT_R16G16_SFLOAT,
/*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
/*.blend = */false,
@ -158,7 +166,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
{
renderTarget.addPass(
/*.*/ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
/*.colors =*/ { attachments.id, attachments.normals, attachments.uvs },
/*.colors =*/ { attachments.id, attachments.normals, attachments.uvs, attachments.mips },
/*.inputs =*/ {},
/*.resolve =*/{},
/*.depth = */ attachments.depth,
@ -171,7 +179,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
renderTarget.addPass(
/*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
/*.colors =*/ { attachments.color, attachments.bright },
/*.inputs =*/ { attachments.id, attachments.normals, attachments.uvs, attachments.depth },
/*.inputs =*/ { attachments.id, attachments.normals, attachments.uvs, attachments.depth, attachments.mips },
/*.resolve =*/{},
/*.depth = */attachments.depth,
/*.layer = */eye,

View File

@ -70,16 +70,16 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
auto& decl = entry.decl;
decl.vertexPositionData = positionAttribute.pointer + positionAttribute.stride * vertexInput.first;
decl.vertexPositionData = static_cast<uint8_t*>(positionAttribute.pointer) + positionAttribute.stride * vertexInput.first;
decl.vertexPositionStride = positionAttribute.stride;
decl.vertexUvData = uvAttribute.pointer + uvAttribute.stride * vertexInput.first;
decl.vertexUvData = static_cast<uint8_t*>(uvAttribute.pointer) + uvAttribute.stride * vertexInput.first;
decl.vertexUvStride = uvAttribute.stride;
decl.vertexCount = vertexInput.count;
decl.indexCount = indexInput.count;
decl.indexData = indexAttribute.pointer + indexAttribute.stride * indexInput.first;
decl.indexData = static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.stride * indexInput.first;
decl.indexFormat = indexType;
}
} else {
@ -87,16 +87,16 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
entry.index = index;
auto& decl = entry.decl;
decl.vertexPositionData = positionAttribute.pointer + positionAttribute.stride * vertexInput.first;
decl.vertexPositionData = static_cast<uint8_t*>(positionAttribute.pointer) + positionAttribute.stride * vertexInput.first;
decl.vertexPositionStride = positionAttribute.stride;
decl.vertexUvData = uvAttribute.pointer + uvAttribute.stride * vertexInput.first;
decl.vertexUvData = static_cast<uint8_t*>(uvAttribute.pointer) + uvAttribute.stride * vertexInput.first;
decl.vertexUvStride = uvAttribute.stride;
decl.vertexCount = vertexInput.count;
decl.indexCount = indexInput.count;
decl.indexData = indexAttribute.pointer + indexAttribute.stride * indexInput.first;
decl.indexData = static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.stride * indexInput.first;
decl.indexFormat = indexType;
}
} else UF_EXCEPTION("to-do: not require indices for meshes");
@ -181,10 +181,10 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
auto dstAttribute = mesh.vertex.attributes[k];
if ( dstAttribute.descriptor.name == "st" ) {
pod::Vector2f& st = *(pod::Vector2f*) ( dstAttribute.pointer + dstAttribute.stride * (j + dstInput.first) );
pod::Vector2f& st = *(pod::Vector2f*) ( static_cast<uint8_t*>(dstAttribute.pointer) + dstAttribute.stride * (j + dstInput.first) );
st = pod::Vector2f{ vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height };
} else {
memcpy( dstAttribute.pointer + dstAttribute.stride * (j + dstInput.first), srcAttribute.pointer + srcAttribute.stride * (ref + srcInput.first), srcAttribute.stride );
memcpy( static_cast<uint8_t*>(dstAttribute.pointer) + dstAttribute.stride * (j + dstInput.first), static_cast<uint8_t*>(srcAttribute.pointer) + srcAttribute.stride * (ref + srcInput.first), srcAttribute.stride );
}
}
}
@ -193,7 +193,7 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
uf::Mesh::Input indexInput = mesh.remapIndexInput( entry.command );
uf::Mesh::Attribute indexAttribute = mesh.index.attributes.front();
// uf::Mesh::Attribute indexAttribute = mesh.remapIndexAttribute( mesh.index.attributes.front(), entry.command );
uint8_t* pointer = (uint8_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first;
uint8_t* pointer = (uint8_t*) static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.stride * indexInput.first;
for ( auto index = 0; index < xmesh.indexCount; ++index ) {
switch ( mesh.index.size ) {
case 1: (( uint8_t*) pointer)[index] = xmesh.indexArray[index]; break;
@ -220,7 +220,7 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
pod::Vector2f& st = *(pod::Vector2f*) ( ((uint8_t*) dstAttribute.pointer) + dstAttribute.stride * j);
st = pod::Vector2f{ vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height };
} else {
memcpy( dstAttribute.pointer + dstAttribute.stride * j, srcAttribute.pointer + srcAttribute.stride * ref, srcAttribute.stride );
memcpy( static_cast<uint8_t*>(dstAttribute.pointer) + dstAttribute.stride * j, static_cast<uint8_t*>(srcAttribute.pointer) + srcAttribute.stride * ref, srcAttribute.stride );
}
}
/*
@ -304,10 +304,10 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
auto& srcAttribute = source.vertex.attributes[_];
auto& dstAttribute = mesh.vertex.attributes[_];
memcpy( dstAttribute.pointer + dstAttribute.stride * (vertexInput.first + v), srcAttribute.pointer + srcAttribute.stride * (vertexInput.first + ref), srcAttribute.stride );
memcpy( static_cast<uint8_t*>(dstAttribute.pointer) + dstAttribute.stride * (vertexInput.first + v), static_cast<uint8_t*>(srcAttribute.pointer) + srcAttribute.stride * (vertexInput.first + ref), srcAttribute.stride );
}
pod::Vector2f& st = *(pod::Vector2f*) (stAttribute.pointer + stAttribute.stride * (vertexInput.first + v));
pod::Vector2f& st = *(pod::Vector2f*) (static_cast<uint8_t*>(stAttribute.pointer) + stAttribute.stride * (vertexInput.first + v));
st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height };
}
// indices
@ -315,9 +315,9 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
indexInput = mesh.remapIndexInput( entry.command );
for ( auto index = 0; index < xmesh.indexCount; ++index ) {
switch ( mesh.index.size ) {
case 1: (( uint8_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
case 2: ((uint16_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
case 4: ((uint32_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
case 1: (( uint8_t*) static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
case 2: ((uint16_t*) static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
case 4: ((uint32_t*) static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
}
}
} else {
@ -329,18 +329,18 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
auto& srcAttribute = source.vertex.attributes[_];
auto& dstAttribute = mesh.vertex.attributes[_];
memcpy( dstAttribute.pointer + dstAttribute.stride * (vertexInput.first + v), srcAttribute.pointer + srcAttribute.stride * (vertexInput.first + ref), srcAttribute.stride );
memcpy( static_cast<uint8_t*>(dstAttribute.pointer) + dstAttribute.stride * (vertexInput.first + v), static_cast<uint8_t*>(srcAttribute.pointer) + srcAttribute.stride * (vertexInput.first + ref), srcAttribute.stride );
}
pod::Vector2f& st = *(pod::Vector2f*) (stAttribute.pointer + stAttribute.stride * (vertexInput.first + v));
pod::Vector2f& st = *(pod::Vector2f*) (static_cast<uint8_t*>(stAttribute.pointer) + stAttribute.stride * (vertexInput.first + v));
st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height };
}
for ( auto index = 0; index < xmesh.indexCount; ++index ) {
switch ( mesh.index.size ) {
case 1: (( uint8_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
case 2: ((uint16_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
case 4: ((uint32_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
case 1: (( uint8_t*) static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
case 2: ((uint16_t*) static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
case 4: ((uint32_t*) static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break;
}
}
}

View File

@ -1,3 +1,4 @@
#if 0
#include <uf/utils/math/collision.h>
#include <uf/utils/math/rayt.h>
#include <iostream>
@ -333,4 +334,5 @@ void uf::primitive::test( const uf::stl::vector<pod::Primitive>& cubes, const uf
}
}
std::cout << "ID: " << id << std::endl;
}
}
#endif

View File

@ -8,17 +8,21 @@ namespace {
}
void UF_API uf::meshgrid::print( const uf::meshgrid::Grid& grid, size_t indices ) {
void UF_API uf::meshgrid::print( const uf::meshgrid::Grid& grid ) {
UF_MSG_DEBUG( "== == == ==");
float total = 0.0f;
for ( auto& node : grid.nodes ) {
float percentage = 100.0f * node.indices.size() / indices;
for ( auto& pair : grid.nodes ) { auto& node = pair.second;
size_t indices = 0;
for ( auto& pair2 : node.meshlets ) indices += pair2.second.indices.size();
float percentage = 100.0f * indices / grid.indices;
total += percentage;
UF_MSG_DEBUG(
"[" << node.id.x << "," << node.id.y << "," << node.id.z << "] "
"[" << percentage << "%|" << total << "%] "
"Min: " << uf::vector::toString( node.extents.min ) << " | "
"Max: " << uf::vector::toString( node.extents.max )
"Max: " << uf::vector::toString( node.extents.max ) << " | "
"Meshlets: " << node.meshlets.size() << " | "
"Indices: " << indices
);
}
@ -29,92 +33,228 @@ void UF_API uf::meshgrid::print( const uf::meshgrid::Grid& grid, size_t indices
UF_MSG_DEBUG( "Corner: " << uf::vector::toString( grid.extents.corner ) );
UF_MSG_DEBUG( "Size: " << uf::vector::toString( grid.extents.size ) );
UF_MSG_DEBUG( "Piece: " << uf::vector::toString( grid.extents.piece ) );
UF_MSG_DEBUG( "Divisions: " << uf::vector::toString( grid.divisions ) );
UF_MSG_DEBUG( "Nodes: " << grid.nodes.size() );
UF_MSG_DEBUG( "Indices: " << grid.indices );
UF_MSG_DEBUG( "== == == ==");
}
void UF_API uf::meshgrid::cleanup( uf::meshgrid::Grid& grid ) {
uf::stl::vector<pod::Vector3ui> eraseNodes;
uf::meshgrid::Grid uf::meshgrid::generate( int divisions,
void* pPointer, size_t pStride, size_t pFirst, size_t pCount,
void* iPointer, size_t iStride, size_t iFirst, size_t iCount
) {
uf::meshgrid::Grid grid;
grid.divisions = divisions;
// calculate extents
for ( size_t i = 0; i < pCount; ++i ) {
pod::Vector3f& position = *(pod::Vector3f*) (pPointer + pStride * (pFirst + i));
grid.extents.min = uf::vector::min( position, grid.extents.min );
grid.extents.max = uf::vector::max( position, grid.extents.max );
for ( auto& pair : grid.nodes ) { auto& node = pair.second;
uf::stl::vector<size_t> eraseMeshlets;
for ( auto& pair2 : node.meshlets ) { auto& meshlet = pair2.second;
if ( !meshlet.indices.empty() ) continue;
eraseMeshlets.emplace_back(pair2.first);
}
for ( auto& e : eraseMeshlets ) node.meshlets.erase(e);
if ( !node.meshlets.empty() ) continue;
eraseNodes.emplace_back(pair.first);
}
for ( auto& e : eraseNodes ) grid.nodes.erase(e);
/*
for ( auto it = grid.nodes.begin(); it != grid.nodes.end(); ++it ) {
auto& node = it->second;
uf::stl::vector<size_t> eraseMeshlets;
for ( auto it2 = node.meshlets.begin(); it2 != node.meshlets.end(); ++it2 ) {
auto& meshlet = it2->second;
if ( !meshlet.indices.empty() ) continue;
UF_MSG_DEBUG("Erase: " << it2->first);
it2 = node.meshlets.erase(it2);
}
if ( !node.meshlets.empty() ) continue;
UF_MSG_DEBUG("Erase: " << uf::vector::toString(it->first));
it = grid.nodes.erase(it);
}
*/
/*
for ( auto& pair : grid.nodes ) { auto& node = pair.second;
for ( auto& pair2 : node.meshlets ) { auto& meshlet = pair2.second;
if ( !meshlet.indices.empty() ) continue;
// node.meshlets.erase(pair2.first);
// UF_MSG_DEBUG("Erase: " << pair2.first);
}
if ( !node.meshlets.empty() ) continue;
UF_MSG_DEBUG("Erase: " << uf::vector::toString(pair.first));
grid.nodes.erase(pair.first);
}
*/
}
void uf::meshgrid::calculate( uf::meshgrid::Grid& grid, int divisions, float eps ){
grid.divisions = {divisions, divisions, divisions};
return calculate( grid, eps );
}
void uf::meshgrid::calculate( uf::meshgrid::Grid& grid, const pod::Vector3ui& divisions, float eps ){
grid.divisions = divisions;
return calculate( grid, eps );
}
void uf::meshgrid::calculate( uf::meshgrid::Grid& grid, float eps ){
// calculate extents
constexpr float epsilon = std::numeric_limits<float>::epsilon();
grid.extents.min -= pod::Vector3f{ epsilon, epsilon, epsilon }; // dilate
grid.extents.max += pod::Vector3f{ epsilon, epsilon, epsilon }; // dilate
grid.extents.size = uf::vector::abs(grid.extents.max - grid.extents.min);
grid.extents.piece = grid.extents.size / divisions;
grid.extents.piece = grid.extents.size / grid.divisions;
grid.extents.center = (grid.extents.max + grid.extents.min) * 0.5f;
grid.extents.corner = grid.extents.size * 0.5f;
// initialize
grid.nodes.reserve( divisions * divisions * divisions );
for ( int z = 0; z < divisions; ++z ) {
for ( int y = 0; y < divisions; ++y ) {
for ( int x = 0; x < divisions; ++x ) {
grid.nodes.emplace_back(uf::meshgrid::Node{
// initialize
grid.nodes.reserve( grid.divisions.x * grid.divisions.y * grid.divisions.z );
for ( int z = 0; z < grid.divisions.z; ++z ) {
for ( int y = 0; y < grid.divisions.y; ++y ) {
for ( int x = 0; x < grid.divisions.x; ++x ) {
auto id = pod::Vector3ui{ x, y, z };
grid.nodes[id] = {
.extents = {
.min = grid.extents.min + grid.extents.piece * pod::Vector3f{ x, y, z },
.max = grid.extents.min + grid.extents.piece * pod::Vector3f{ x+1, y+1, z+1 },
},
.id = pod::Vector3ui{ x, y, z },
});
.id = id
};
}
}
}
}
void uf::meshgrid::partition( uf::meshgrid::Grid& grid,
const void* pPointer, size_t pStride,
const void* iPointer, size_t iStride,
const pod::Primitive& primitive
) {
size_t pFirst = primitive.drawCommand.vertexID;
size_t pCount = primitive.drawCommand.vertices;
size_t iFirst = primitive.drawCommand.indexID;
size_t iCount = primitive.drawCommand.indices;
const float oneOverThree = 1.0f / 3.0f;
struct Triangle {
pod::Vector3ui indices;
pod::Vector3f center;
pod::Vector3f vertices[3];
};
uf::stl::vector<Triangle> rejects;
for ( auto& pair : grid.nodes ) { auto& node = pair.second;
auto& meshlet = node.meshlets[primitive.instance.primitiveID];
meshlet.primitive = primitive;
meshlet.primitive.instance.bounds.min = node.extents.min;
meshlet.primitive.instance.bounds.max = node.extents.max;
}
// iterate
for ( size_t i = 0; i < iCount; i+=3 ) {
size_t indexA = 0;
size_t indexB = 0;
size_t indexC = 0;
uint8_t* indexPointerA = (uint8_t*) (iPointer + iStride * (iFirst + i + 0));
uint8_t* indexPointerB = (uint8_t*) (iPointer + iStride * (iFirst + i + 1));
uint8_t* indexPointerC = (uint8_t*) (iPointer + iStride * (iFirst + i + 2));
Triangle tri{};
const uint8_t* indexPointers[3] = {
(static_cast<const uint8_t*>(iPointer) + iStride * (iFirst + i + 0)),
(static_cast<const uint8_t*>(iPointer) + iStride * (iFirst + i + 1)),
(static_cast<const uint8_t*>(iPointer) + iStride * (iFirst + i + 2)),
};
switch ( iStride ) {
case sizeof(uint8_t): {
indexA = *( uint8_t*) indexPointerA;
indexB = *( uint8_t*) indexPointerB;
indexC = *( uint8_t*) indexPointerC;
tri.indices[0] = *( const uint8_t*) indexPointers[0];
tri.indices[1] = *( const uint8_t*) indexPointers[1];
tri.indices[2] = *( const uint8_t*) indexPointers[2];
} break;
case sizeof(uint16_t): {
indexA = *(uint16_t*) indexPointerA;
indexB = *(uint16_t*) indexPointerB;
indexC = *(uint16_t*) indexPointerC;
tri.indices[0] = *(const uint16_t*) indexPointers[0];
tri.indices[1] = *(const uint16_t*) indexPointers[1];
tri.indices[2] = *(const uint16_t*) indexPointers[2];
} break;
case sizeof(uint32_t): {
indexA = *(uint32_t*) indexPointerA;
indexB = *(uint32_t*) indexPointerB;
indexC = *(uint32_t*) indexPointerC;
tri.indices[0] = *(const uint32_t*) indexPointers[0];
tri.indices[1] = *(const uint32_t*) indexPointers[1];
tri.indices[2] = *(const uint32_t*) indexPointers[2];
} break;
}
pod::Vector3f& positionA = *(pod::Vector3f*) (pPointer + pStride * (pFirst + indexA));
pod::Vector3f& positionB = *(pod::Vector3f*) (pPointer + pStride * (pFirst + indexB));
pod::Vector3f& positionC = *(pod::Vector3f*) (pPointer + pStride * (pFirst + indexC));
tri.vertices[0] = *(const pod::Vector3f*) (static_cast<const uint8_t*>(pPointer) + pStride * (pFirst + tri.indices[0]));
tri.vertices[1] = *(const pod::Vector3f*) (static_cast<const uint8_t*>(pPointer) + pStride * (pFirst + tri.indices[1]));
tri.vertices[2] = *(const pod::Vector3f*) (static_cast<const uint8_t*>(pPointer) + pStride * (pFirst + tri.indices[2]));
tri.center = (tri.vertices[0] + tri.vertices[1] + tri.vertices[2]) * oneOverThree;
for ( auto& node : grid.nodes ) {
// if ( isInside( positionA, node.extents.min, node.extents.max ) || isInside( positionB, node.extents.min, node.extents.max ) || isInside( positionC, node.extents.min, node.extents.max ) ) {
if ( isInside( (positionA + positionB + positionC) / 3.0f, node.extents.min, node.extents.max ) ) {
node.indices.emplace_back( indexA );
node.indices.emplace_back( indexB );
node.indices.emplace_back( indexC );
bool found = false;
for ( auto& pair : grid.nodes ) { auto& node = pair.second;
auto& meshlet = node.meshlets[primitive.instance.primitiveID];
// if ( isInside( tri.vertices[0], node.extents.min, node.extents.max ) || isInside( tri.vertices[1], node.extents.min, node.extents.max ) || isInside( tri.vertices[2], node.extents.min, node.extents.max ) ) {
if ( isInside( tri.center, node.extents.min, node.extents.max ) ) {
meshlet.indices.emplace_back( tri.indices[0] );
meshlet.indices.emplace_back( tri.indices[1] );
meshlet.indices.emplace_back( tri.indices[2] );
#pragma unroll // GCC unroll N
for ( uint_fast8_t _ = 0; _ < 3; ++_ ) {
node.effectiveExtents.min = uf::vector::min( node.effectiveExtents.min, tri.vertices[_] );
node.effectiveExtents.max = uf::vector::max( node.effectiveExtents.max, tri.vertices[_] );
}
found = true;
break;
}
if ( isInside( tri.vertices[0], node.extents.min, node.extents.max ) || isInside( tri.vertices[1], node.extents.min, node.extents.max ) || isInside( tri.vertices[2], node.extents.min, node.extents.max ) ) {
// if ( isInside( tri.center, node.extents.min, node.extents.max ) ) {
meshlet.indices.emplace_back( tri.indices[0] );
meshlet.indices.emplace_back( tri.indices[1] );
meshlet.indices.emplace_back( tri.indices[2] );
#pragma unroll // GCC unroll N
for ( uint_fast8_t _ = 0; _ < 3; ++_ ) {
node.effectiveExtents.min = uf::vector::min( node.effectiveExtents.min, tri.vertices[_] );
node.effectiveExtents.max = uf::vector::max( node.effectiveExtents.max, tri.vertices[_] );
}
found = true;
break;
}
}
if ( found ) continue;
rejects.emplace_back(tri);
}
for ( auto& tri : rejects ) {
uf::meshgrid::Node* closest = NULL;
float closestDistance = std::numeric_limits<float>::max();
for ( auto& pair : grid.nodes ) { auto& node = pair.second;
auto nodeCenter = (node.extents.max + node.extents.min) * 0.5f;
float curDistance = uf::vector::distanceSquared( nodeCenter, tri.center );
if ( curDistance < closestDistance ) {
closestDistance = curDistance;
closest = &node;
}
}
if ( closest ) {
auto& meshlet = closest->meshlets[primitive.instance.primitiveID];
meshlet.indices.emplace_back( tri.indices[0] );
meshlet.indices.emplace_back( tri.indices[1] );
meshlet.indices.emplace_back( tri.indices[2] );
#pragma unroll // GCC unroll N
for ( uint_fast8_t _ = 0; _ < 3; ++_ ) {
closest->effectiveExtents.min = uf::vector::min( closest->effectiveExtents.min, tri.vertices[_] );
closest->effectiveExtents.max = uf::vector::max( closest->effectiveExtents.max, tri.vertices[_] );
}
// UF_MSG_DEBUG("REASSIGNED TRI: " << uf::vector::toString(tri.center) << " -> " << uf::vector::toString(closest->id) << " (" << closestDistance << ")");
} else {
// UF_MSG_DEBUG("REJECT TRI: " << tri.center.x << " " << tri.center.y << " " << tri.center.z);
}
}
return grid;
grid.indices += iCount;
}
uf::meshgrid::Grid UF_API uf::meshgrid::partition( uf::Mesh& mesh, int divisions ) {
void UF_API uf::meshgrid::partition( uf::meshgrid::Grid& grid, uf::Mesh& mesh, const pod::Primitive& primitive ) {
uf::Mesh::Input vertexInput = mesh.vertex;
uf::Mesh::Input indexInput = mesh.index;
@ -124,83 +264,11 @@ uf::meshgrid::Grid UF_API uf::meshgrid::partition( uf::Mesh& mesh, int divisions
for ( auto& attribute : mesh.vertex.attributes ) if ( attribute.descriptor.name == "position" ) { vertexAttribute = attribute; break; }
UF_ASSERT( vertexAttribute.descriptor.name == "position" );
return generate( divisions,
vertexAttribute.pointer + vertexAttribute.offset, vertexAttribute.stride, vertexInput.first, mesh.vertex.count,
indexAttribute.pointer + indexAttribute.offset, indexAttribute.stride, indexInput.first, mesh.index.count
return partition( grid,
static_cast<uint8_t*>(vertexAttribute.pointer) + vertexAttribute.offset, vertexAttribute.stride,
static_cast<uint8_t*>(indexAttribute.pointer) + indexAttribute.offset, indexAttribute.stride,
primitive
);
/*
for ( size_t i = 0; i < mesh.vertex.count; ++i ) {
pod::Vector3f& position = *(pod::Vector3f*) (vertexAttribute.pointer + vertexAttribute.stride * (vertexInput.first + i));
grid.extents.min = uf::vector::min( position, grid.extents.min );
grid.extents.max = uf::vector::max( position, grid.extents.max );
}
constexpr float epsilon = std::numeric_limits<float>::epsilon();
grid.extents.min -= pod::Vector3f{ epsilon, epsilon, epsilon }; // dilate
grid.extents.max += pod::Vector3f{ epsilon, epsilon, epsilon }; // dilate
grid.extents.size = uf::vector::abs(grid.extents.max - grid.extents.min);
grid.extents.piece = grid.extents.size / divisions;
grid.extents.center = (grid.extents.max + grid.extents.min) * 0.5f;
grid.extents.corner = grid.extents.size * 0.5f;
grid.nodes.reserve( divisions * divisions * divisions );
for ( int z = 0; z < divisions; ++z ) {
for ( int y = 0; y < divisions; ++y ) {
for ( int x = 0; x < divisions; ++x ) {
grid.nodes.emplace_back(uf::meshgrid::Node{
.extents = {
.min = grid.extents.min + grid.extents.piece * pod::Vector3f{ x, y, z },
.max = grid.extents.min + grid.extents.piece * pod::Vector3f{ x+1, y+1, z+1 },
},
.id = pod::Vector3ui{ x, y, z },
});
}
}
}
for ( size_t i = 0; i < indexInput.count; i+=3 ) {
size_t indexA = 0;
size_t indexB = 0;
size_t indexC = 0;
uint8_t* indexPointerA = (uint8_t*) (indexAttribute.pointer + indexAttribute.stride * (indexInput.first + i + 0));
uint8_t* indexPointerB = (uint8_t*) (indexAttribute.pointer + indexAttribute.stride * (indexInput.first + i + 1));
uint8_t* indexPointerC = (uint8_t*) (indexAttribute.pointer + indexAttribute.stride * (indexInput.first + i + 2));
switch ( indexInput.size ) {
case sizeof(uint8_t): {
indexA = *( uint8_t*) indexPointerA;
indexB = *( uint8_t*) indexPointerB;
indexC = *( uint8_t*) indexPointerC;
} break;
case sizeof(uint16_t): {
indexA = *(uint16_t*) indexPointerA;
indexB = *(uint16_t*) indexPointerB;
indexC = *(uint16_t*) indexPointerC;
} break;
case sizeof(uint32_t): {
indexA = *(uint32_t*) indexPointerA;
indexB = *(uint32_t*) indexPointerB;
indexC = *(uint32_t*) indexPointerC;
} break;
}
pod::Vector3f& positionA = *(pod::Vector3f*) (vertexAttribute.pointer + vertexAttribute.stride * (vertexInput.first + indexA));
pod::Vector3f& positionB = *(pod::Vector3f*) (vertexAttribute.pointer + vertexAttribute.stride * (vertexInput.first + indexB));
pod::Vector3f& positionC = *(pod::Vector3f*) (vertexAttribute.pointer + vertexAttribute.stride * (vertexInput.first + indexC));
for ( auto& node : grid.nodes ) {
// if ( isInside( positionA, node.extents.min, node.extents.max ) || isInside( positionB, node.extents.min, node.extents.max ) || isInside( positionC, node.extents.min, node.extents.max ) ) {
if ( isInside( (positionA + positionB + positionC) / 3.0f, node.extents.min, node.extents.max ) ) {
node.indices.emplace_back( indexA );
node.indices.emplace_back( indexB );
node.indices.emplace_back( indexC );
}
}
}
return grid;
*/
}
#if 0

View File

@ -132,8 +132,8 @@ uf::Mesh uf::Mesh::expand( bool interleaved ) {
auto& dstIndex = res.index.attributes.front();
#define GET_INDEX(T) {\
index = *(const T*) (srcIndex.pointer + idx * srcIndex.stride);\
*((T*) (dstIndex.pointer + idx * dstIndex.stride)) = idx;\
index = *(const T*) (static_cast<uint8_t*>(srcIndex.pointer) + idx * srcIndex.stride);\
*((T*) (static_cast<uint8_t*>(dstIndex.pointer) + idx * dstIndex.stride)) = idx;\
}
for ( size_t idx = 0; idx < index.count; ++idx ) {
@ -148,8 +148,8 @@ uf::Mesh uf::Mesh::expand( bool interleaved ) {
auto& srcInput = vertex.attributes[_];
auto& dstInput = res.vertex.attributes[_];
memcpy( dstInput.pointer, srcInput.pointer + index * srcInput.stride, srcInput.descriptor.size );
dstInput.pointer += dstInput.stride;
memcpy( dstInput.pointer, static_cast<uint8_t*>(srcInput.pointer) + index * srcInput.stride, srcInput.descriptor.size );
dstInput.pointer = static_cast<uint8_t*>(dstInput.pointer) + dstInput.stride;
}
}
@ -362,7 +362,9 @@ void uf::Mesh::_updateDescriptor( uf::Mesh::Input& input ) {
attribute.length = buffer.size();
attribute.pointer = buffer.data() + attribute.offset;
input.size += attribute.descriptor.size;
if ( interleaved ) attribute.pointer += attribute.descriptor.offset;
if ( interleaved ) {
attribute.pointer = static_cast<uint8_t*>(attribute.pointer) + attribute.descriptor.offset;
}
}
for ( auto& attribute : input.attributes ) {
attribute.stride = isInterleaved(input.interleaved) ? input.size : attribute.descriptor.size;
@ -377,10 +379,10 @@ uf::Mesh::Attribute uf::Mesh::_remapAttribute( const uf::Mesh::Input& input, con
auto& drawCommand = ((const pod::DrawCommand*) getBuffer(indirect).data())[i];
if ( &input == &vertex ) {
res.pointer += drawCommand.vertexID * res.stride;
res.pointer = static_cast<uint8_t*>(res.pointer) + drawCommand.vertexID * res.stride;
res.length = drawCommand.vertices * res.stride;
} else if ( &input == &index ) {
res.pointer += drawCommand.indexID * res.stride;
res.pointer = static_cast<uint8_t*>(res.pointer) + drawCommand.indexID * res.stride;
res.length = drawCommand.indices * res.stride;
}
return res;
@ -426,7 +428,7 @@ void uf::Mesh::_insertVs( uf::Mesh::Input& dstInput, const uf::Mesh& mesh, const
while ( _++ < _srcInput.count ) {
for ( auto& srcAttribute : _srcInput.attributes ) {
dst.insert( dst.end(), (uint8_t*) srcAttribute.pointer, (uint8_t*) srcAttribute.pointer + srcAttribute.descriptor.size );
srcAttribute.pointer += srcAttribute.descriptor.size;
srcAttribute.pointer = static_cast<uint8_t*>(srcAttribute.pointer) + srcAttribute.descriptor.size;
}
}
} else if ( !isInterleaved(dstInput.interleaved) && isInterleaved(srcInput.interleaved) ) {
@ -476,7 +478,7 @@ void uf::Mesh::_insertIs( uf::Mesh::Input& dstInput, const uf::Mesh& mesh, const
while ( _++ < _srcInput.count ) {
for ( auto& srcAttribute : _srcInput.attributes ) {
dst.insert( dst.end(), (uint8_t*) srcAttribute.pointer, (uint8_t*) srcAttribute.pointer + srcAttribute.descriptor.size );
srcAttribute.pointer += srcAttribute.descriptor.size;
srcAttribute.pointer = static_cast<uint8_t*>(srcAttribute.pointer) + srcAttribute.descriptor.size;
}
}
} else if ( !isInterleaved(dstInput.interleaved) && isInterleaved(srcInput.interleaved) ) {

View File

@ -6,6 +6,33 @@
#include <cmath>
#include <iostream>
#include <regex>
/*
bool UF_API uf::string::match( const uf::stl::string& str, const uf::stl::string& r ) {
std::regex regex(r);
std::smatch match;
return std::regex_search( str, match, regex );
}
*/
bool UF_API uf::string::isRegex( const uf::stl::string& str ) {
return str.front() == '/' && str.back() == '/';
}
uf::stl::vector<uf::stl::string> UF_API uf::string::matches( const uf::stl::string& str, const uf::stl::string& r ) {
std::regex regex(r.substr(1,r.length()-2));
std::smatch match;
uf::stl::vector<uf::stl::string> matches;
if ( std::regex_search( str, match, regex ) ) {
for ( auto& m : match ) {
UF_MSG_DEBUG(m);
matches.emplace_back(m.str());
}
}
return matches;
}
uf::stl::string UF_API uf::string::lowercase( const uf::stl::string& str ) {
uf::stl::string lower = str;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);

View File

@ -91,7 +91,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
*/
});
this->addHook( "world:Entity.LoadAsset", [&](pod::payloads::assetLoad& payload){
assetLoader.load("asset:Load." + payload.uid, payload);
assetLoader.load("asset:Load." + std::to_string(payload.uid), payload);
});
this->addHook( "shader:Update.%UID%", [&](ext::json::Value& json){
metadata.shader.mode = json["mode"].as<uint32_t>();

View File

@ -908,7 +908,7 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
UF_ASSERT( vertexAttribute.descriptor.name == "position" );
for ( auto i = 0; i < mesh.vertex.count; ++i ) {
float* p = (float*) (vertexAttribute.pointer + i * vertexAttribute.stride );
float* p = (float*) (static_cast<uint8_t*>(vertexAttribute.pointer) + i * vertexAttribute.stride );
pod::Vector4f position = { p[0], p[1], 0, 1 };
pod::Vector4f translated = uf::matrix::multiply<float>( model, position );
min.x = std::min( min.x, translated.x );