tessalation started
This commit is contained in:
@@ -69,7 +69,8 @@ enum class HYDRA_RENDERABLE_TYPE
|
||||
HYDRA_TRANSPARENT,
|
||||
HYDRA_LIGHTING,
|
||||
HYDRA_OUTPUT,
|
||||
HYDRA_TEXTURE_DEBUG
|
||||
HYDRA_TEXTURE_DEBUG,
|
||||
HYDRA_LANDSCAPE
|
||||
};
|
||||
|
||||
enum class HYDRA_BUFFER_TYPE
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
//*PIXEL*
|
||||
#version 460 core
|
||||
|
||||
#extension GL_ARB_bindless_texture : require
|
||||
|
||||
|
||||
uint INVALID_HYDRA_ID = 4294967295;
|
||||
|
||||
struct MaterialStore
|
||||
{
|
||||
vec4 diffuse_colour;
|
||||
vec4 matalic_rough;
|
||||
uint diffuse_texture_id;
|
||||
uint metallic_rough_texture_id;
|
||||
uint normal_texture_id;
|
||||
uint padding[1];
|
||||
};
|
||||
|
||||
layout(binding = 2, std430) readonly buffer material_buffer
|
||||
{
|
||||
MaterialStore materials[1000];
|
||||
};
|
||||
|
||||
layout( std430, binding = 3) readonly buffer texture_buffer {
|
||||
uvec2 textures[1000];
|
||||
};
|
||||
|
||||
layout (location=0) in TE_OUT
|
||||
{
|
||||
vec2 vsUV;
|
||||
vec4 vsWorldPos;
|
||||
vec3 vsNormal;
|
||||
vec3 vsBiTangent;
|
||||
vec3 vsTangent;
|
||||
mat3 vsTBN;
|
||||
flat uint vsChunkID;
|
||||
flat uint vsMaterialID;
|
||||
}vs_out;
|
||||
|
||||
layout (location=0) out vec4 diffuse_out;
|
||||
layout (location=1) out vec4 metalic_rough_out;
|
||||
layout (location=2) out vec4 normal_out;
|
||||
layout (location=3) out vec4 position_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
MaterialStore mat = materials[vs_out.vsMaterialID];
|
||||
vec4 diffuse_val = mat.diffuse_colour;
|
||||
vec4 mat_rough_val =mat.matalic_rough;
|
||||
vec3 normal_val = vs_out.vsNormal;
|
||||
|
||||
if(mat.diffuse_texture_id != INVALID_HYDRA_ID)
|
||||
{
|
||||
uvec2 diffuse_handle = textures[mat.diffuse_texture_id];
|
||||
diffuse_val = diffuse_val * texture(sampler2D(diffuse_handle), vs_out.vsUV.xy);
|
||||
}
|
||||
if(mat.metallic_rough_texture_id != INVALID_HYDRA_ID)
|
||||
{
|
||||
uvec2 metal_rough_handle = textures[mat.metallic_rough_texture_id];
|
||||
mat_rough_val = texture(sampler2D(metal_rough_handle), vs_out.vsUV.xy);
|
||||
}
|
||||
if(mat.normal_texture_id != INVALID_HYDRA_ID)
|
||||
{
|
||||
uvec2 normal_handle = textures[mat.normal_texture_id];
|
||||
normal_val = texture(sampler2D(normal_handle), vs_out.vsUV.xy).xyz;
|
||||
normal_val = (normal_val * 2.0) - 1.0;
|
||||
normal_val = normalize(vs_out.vsTBN * normal_val);
|
||||
}
|
||||
|
||||
if(diffuse_val[3] <= 0.4)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
diffuse_out = diffuse_val;
|
||||
metalic_rough_out = mat_rough_val;
|
||||
normal_out = vec4(normal_val,1);
|
||||
position_out = vs_out.vsWorldPos;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// tessellation control shader
|
||||
#version 450 core
|
||||
|
||||
// specify number of control points per patch output
|
||||
// this value controls the size of the input and output arrays
|
||||
layout (vertices=4) out;
|
||||
|
||||
layout (location=0) in VS_OUT
|
||||
{
|
||||
vec2 vsUV;
|
||||
vec4 vsWorldPos;
|
||||
vec3 vsNormal;
|
||||
vec3 vsBiTangent;
|
||||
vec3 vsTangent;
|
||||
mat3 vsTBN;
|
||||
flat uint vsChunkID;
|
||||
flat uint vsMaterialID;
|
||||
}tc_in[];
|
||||
|
||||
layout (location=0) out TC_OUT
|
||||
{
|
||||
vec2 vsUV;
|
||||
vec4 vsWorldPos;
|
||||
vec3 vsNormal;
|
||||
vec3 vsBiTangent;
|
||||
vec3 vsTangent;
|
||||
mat3 vsTBN;
|
||||
flat uint vsChunkID;
|
||||
flat uint vsMaterialID;
|
||||
}tc_out[];
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
// ----------------------------------------------------------------------
|
||||
// pass attributes through
|
||||
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
|
||||
tc_out[gl_InvocationID].vsUV = tc_in[gl_InvocationID].vsUV;
|
||||
tc_out[gl_InvocationID].vsWorldPos = tc_in[gl_InvocationID].vsWorldPos;
|
||||
tc_out[gl_InvocationID].vsNormal = tc_in[gl_InvocationID].vsNormal;
|
||||
tc_out[gl_InvocationID].vsBiTangent = tc_in[gl_InvocationID].vsBiTangent;
|
||||
tc_out[gl_InvocationID].vsTangent = tc_in[gl_InvocationID].vsTangent;
|
||||
tc_out[gl_InvocationID].vsTBN = tc_in[gl_InvocationID].vsTBN;
|
||||
tc_out[gl_InvocationID].vsChunkID = tc_in[gl_InvocationID].vsChunkID;
|
||||
tc_out[gl_InvocationID].vsMaterialID = tc_in[gl_InvocationID].vsMaterialID;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// invocation zero controls tessellation levels for the entire patch
|
||||
if (gl_InvocationID == 0)
|
||||
{
|
||||
|
||||
int divs = 63;
|
||||
gl_TessLevelOuter[0] = divs;
|
||||
gl_TessLevelOuter[1] = divs;
|
||||
gl_TessLevelOuter[2] = divs;
|
||||
gl_TessLevelOuter[3] = divs;
|
||||
gl_TessLevelInner[0] = divs;
|
||||
gl_TessLevelInner[1] = divs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// tessellation evaluation shader
|
||||
#version 450 core
|
||||
|
||||
layout (quads, equal_spacing, ccw) in;
|
||||
|
||||
layout(std430, binding = 1) readonly buffer positions_buffer
|
||||
{
|
||||
mat4 model_matrix[];
|
||||
};
|
||||
|
||||
layout(binding = 0) uniform uniform_per_frame
|
||||
{
|
||||
mat4 view;
|
||||
mat4 proj;
|
||||
vec3 viewer_pos;
|
||||
uint light_count;
|
||||
} ubo_per_frame;
|
||||
|
||||
// received from Tessellation Control Shader - all texture coordinates for the patch vertices
|
||||
// varying input from vertex shader
|
||||
|
||||
layout (location=0) in TC_OUT
|
||||
{
|
||||
vec2 vsUV;
|
||||
vec4 vsWorldPos;
|
||||
vec3 vsNormal;
|
||||
vec3 vsBiTangent;
|
||||
vec3 vsTangent;
|
||||
mat3 vsTBN;
|
||||
flat uint vsChunkID;
|
||||
flat uint vsMaterialID;
|
||||
}te_in[];
|
||||
|
||||
layout (location=0) out TE_OUT
|
||||
{
|
||||
vec2 vsUV;
|
||||
vec4 vsWorldPos;
|
||||
vec3 vsNormal;
|
||||
vec3 vsBiTangent;
|
||||
vec3 vsTangent;
|
||||
mat3 vsTBN;
|
||||
flat uint vsChunkID;
|
||||
flat uint vsMaterialID;
|
||||
}te_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
// get patch coordinate
|
||||
te_out.vsUV.x = gl_TessCoord.x;
|
||||
te_out.vsUV.y = gl_TessCoord.y;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// retrieve control point texture coordinates
|
||||
vec2 t00 = te_in[0].vsUV;
|
||||
vec2 t01 = te_in[1].vsUV;
|
||||
vec2 t10 = te_in[2].vsUV;
|
||||
vec2 t11 = te_in[3].vsUV;
|
||||
|
||||
// t00|t10
|
||||
// -------
|
||||
// t10|t11
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// retrieve control point position coordinates
|
||||
vec4 p00 = gl_in[0].gl_Position;
|
||||
vec4 p01 = gl_in[1].gl_Position;
|
||||
vec4 p10 = gl_in[2].gl_Position;
|
||||
vec4 p11 = gl_in[3].gl_Position;
|
||||
|
||||
// compute patch surface normal
|
||||
vec4 uVec = p01 - p00;
|
||||
vec4 vVec = p10 - p00;
|
||||
vec4 normal = normalize( vec4(cross(uVec.xyz, vVec.xyz), 1));
|
||||
|
||||
te_out.vsNormal = normal.xyz;
|
||||
// bilinearly interpolate position coordinate across patch
|
||||
vec4 p0 = (p01 - p00) * te_out.vsUV.x + p00;
|
||||
vec4 p1 = (p11 - p10) * te_out.vsUV.x + p10;
|
||||
vec4 p = (p1 - p0) * te_out.vsUV.y + p0;
|
||||
|
||||
// displace point along normal
|
||||
// p += -normal * height;
|
||||
//height = 0;
|
||||
|
||||
//p[3] = 1;
|
||||
// ----------------------------------------------------------------------
|
||||
// output patch point position in clip space
|
||||
|
||||
mat4 model = model_matrix[te_in[0].vsChunkID];
|
||||
mat4 view = ubo_per_frame.view;
|
||||
mat4 proj = ubo_per_frame.proj;
|
||||
gl_Position = proj * view * model * p;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#version 460 core
|
||||
#extension GL_ARB_bindless_texture : require
|
||||
|
||||
layout(binding = 0) uniform uniform_per_frame
|
||||
{
|
||||
mat4 view;
|
||||
mat4 proj;
|
||||
vec3 viewer_pos;
|
||||
uint light_count;
|
||||
} ubo_per_frame;
|
||||
|
||||
layout(std430, binding = 1) readonly buffer positions_buffer
|
||||
{
|
||||
mat4 model_matrix[];
|
||||
};
|
||||
|
||||
layout (location = 0) in vec3 inPos; //12 bytes : 0
|
||||
layout (location = 1) in vec2 inUV; //8 Bytes : 12
|
||||
layout (location = 2) in uvec3 inChunkID; //12 Bytes : 20
|
||||
layout (location = 3) in vec3 inNormal; //8 Bytes : 12
|
||||
layout (location = 4) in vec3 inBiTangent;
|
||||
layout (location = 5) in vec3 inTangent;
|
||||
|
||||
layout(location=0) out VS_OUT
|
||||
{
|
||||
vec2 vsUV;
|
||||
vec4 vsWorldPos;
|
||||
vec3 vsNormal;
|
||||
vec3 vsBiTangent;
|
||||
vec3 vsTangent;
|
||||
mat3 vsTBN;
|
||||
flat uint vsChunkID;
|
||||
flat uint vsMaterialID;
|
||||
}vs_out;
|
||||
|
||||
out vec2 vertUV_out;
|
||||
out ivec4 vertEdges_out;
|
||||
out int vertChild_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
uint chunkid = inChunkID[0];
|
||||
mat4 model = model_matrix[chunkid];
|
||||
mat4 view = ubo_per_frame.view;
|
||||
mat4 proj = ubo_per_frame.proj;
|
||||
//model = mat4(1);
|
||||
gl_Position = proj * view * model * vec4(inPos, 1.0);
|
||||
vs_out.vsWorldPos = model * vec4(inPos,1);
|
||||
|
||||
vs_out.vsNormal = normalize(vec3(model * vec4(normalize(inNormal),0)));
|
||||
vs_out.vsTangent = normalize(vec3(model *vec4(inTangent,0))) ;
|
||||
vs_out.vsBiTangent = normalize(vec3(model *vec4(inBiTangent,0)));
|
||||
|
||||
vs_out.vsTBN = mat3(vs_out.vsTangent, vs_out.vsBiTangent, vs_out.vsNormal);
|
||||
|
||||
vs_out.vsUV = inUV;
|
||||
vs_out.vsChunkID = chunkid;
|
||||
vs_out.vsMaterialID = inChunkID[1];
|
||||
}
|
||||
@@ -30,7 +30,9 @@ void HydraDeferredPipeline::Initialise()
|
||||
_CreateOutputActor();
|
||||
_CreateFrameBuffer();
|
||||
_CreateColourRenderStage();
|
||||
_CreateLandscapeRenderStage();
|
||||
_CreateOutputRenderStage();
|
||||
|
||||
//_CreateTextureDebugOutputStage();
|
||||
}
|
||||
|
||||
@@ -207,7 +209,7 @@ void HydraDeferredPipeline::_CreateColourRenderStage()
|
||||
std::vector<uint32_t> textures;
|
||||
|
||||
render_stage->Initialise(shader_path + "deferred_shader.vert",
|
||||
shader_path + "deferred_shader.frag", "",
|
||||
shader_path + "deferred_shader.frag", "", "", "",
|
||||
shader_binding,
|
||||
m_frame_buffer_id,
|
||||
textures,
|
||||
@@ -218,6 +220,54 @@ void HydraDeferredPipeline::_CreateColourRenderStage()
|
||||
m_render_stages.push_back(render_stage);
|
||||
}
|
||||
|
||||
void HydraDeferredPipeline::_CreateLandscapeRenderStage()
|
||||
{
|
||||
HydraRenderStage* render_stage = new HydraRenderStage();
|
||||
std::string shader_path = std::string(shader_base);
|
||||
HydraBufferManager* buffer_manager = GetEngine()->BufferManager();
|
||||
|
||||
HydraID pos_buffer_id = buffer_manager->FindBuffer("PositionsBuffer");
|
||||
HydraID mat_buffer_id = buffer_manager->FindBuffer("MaterialBuffer");
|
||||
HydraID tex_buffer_id = buffer_manager->FindBuffer("TextureBuffer");
|
||||
HydraID per_frame_buffer_id = buffer_manager->FindBuffer("DeferredPerFrameUBO");
|
||||
|
||||
HydraShaderBinding shader_binding = {};
|
||||
|
||||
shader_binding.block_name.push_back("positions_buffer");
|
||||
shader_binding.binding_point.push_back(1);
|
||||
shader_binding.buffer_id.push_back(pos_buffer_id);
|
||||
shader_binding.buffer_type.push_back(HYDRA_BUFFER_TYPE::HYDRA_SSBO_BUFFER);
|
||||
|
||||
shader_binding.block_name.push_back("material_buffer");
|
||||
shader_binding.binding_point.push_back(2);
|
||||
shader_binding.buffer_id.push_back(mat_buffer_id);
|
||||
shader_binding.buffer_type.push_back(HYDRA_BUFFER_TYPE::HYDRA_SSBO_BUFFER);
|
||||
|
||||
shader_binding.block_name.push_back("texture_buffer");
|
||||
shader_binding.binding_point.push_back(3);
|
||||
shader_binding.buffer_id.push_back(tex_buffer_id);
|
||||
shader_binding.buffer_type.push_back(HYDRA_BUFFER_TYPE::HYDRA_SSBO_BUFFER);
|
||||
|
||||
shader_binding.block_name.push_back("uniform_per_frame");
|
||||
shader_binding.binding_point.push_back(0);
|
||||
shader_binding.buffer_id.push_back(per_frame_buffer_id);
|
||||
shader_binding.buffer_type.push_back(HYDRA_BUFFER_TYPE::HYDRA_UBO_BUFFER);
|
||||
std::vector<uint32_t> textures;
|
||||
|
||||
render_stage->Initialise(shader_path + "landscape_shader.vert",
|
||||
shader_path + "landscape_shader.frag",
|
||||
"",
|
||||
shader_path + "landscape_shader.tesc",
|
||||
shader_path + "landscape_shader.tese",
|
||||
shader_binding,
|
||||
m_frame_buffer_id,
|
||||
textures,
|
||||
true,
|
||||
GL_BACK,
|
||||
true,
|
||||
HYDRA_RENDERABLE_TYPE::HYDRA_LANDSCAPE);
|
||||
m_render_stages.push_back(render_stage);
|
||||
}
|
||||
|
||||
void HydraDeferredPipeline::_CreateOutputRenderStage()
|
||||
{
|
||||
@@ -283,7 +333,7 @@ void HydraDeferredPipeline::_CreateOutputRenderStage()
|
||||
shader_binding.buffer_type.push_back(HYDRA_BUFFER_TYPE::HYDRA_SSBO_BUFFER);
|
||||
|
||||
render_stage->Initialise(shader_path + "deferred_output_shader.vert",
|
||||
shader_path + "deferred_output_shader.frag", "",
|
||||
shader_path + "deferred_output_shader.frag", "", "", "",
|
||||
shader_binding,
|
||||
0,
|
||||
textures,
|
||||
@@ -328,7 +378,7 @@ void HydraDeferredPipeline::_CreateTextureDebugOutputStage()
|
||||
shader_binding.buffer_type.push_back(HYDRA_BUFFER_TYPE::HYDRA_UBO_BUFFER);
|
||||
|
||||
render_stage->Initialise(shader_path + "texture_debug_shader.vert",
|
||||
shader_path + "texture_debug_shader.frag", "",
|
||||
shader_path + "texture_debug_shader.frag", "", "", "",
|
||||
shader_binding,
|
||||
0,
|
||||
textures,
|
||||
|
||||
@@ -32,7 +32,7 @@ class HydraDeferredPipeline : public HydraPipeline
|
||||
|
||||
void _UpdateUBO();
|
||||
void _CreateFrameBuffer();
|
||||
|
||||
void _CreateLandscapeRenderStage();
|
||||
void _CreateColourRenderStage();
|
||||
void _CreateOutputRenderStage();
|
||||
void _CreateOutputActor();
|
||||
|
||||
@@ -36,7 +36,7 @@ void HydraForwardPipeline::Initialise()
|
||||
std::vector<uint32_t> textures;
|
||||
std::vector<uint32_t> rb_attachments;
|
||||
|
||||
render_stage->Initialise(shader_path + "forward_shader.vert", shader_path + "forward_shader.frag", "", shader_binding, 0, textures, true, GL_BACK, true, HYDRA_RENDERABLE_TYPE::HYDRA_COLOUR);
|
||||
render_stage->Initialise(shader_path + "forward_shader.vert", shader_path + "forward_shader.frag", "", "", "", shader_binding, 0, textures, true, GL_BACK, true, HYDRA_RENDERABLE_TYPE::HYDRA_COLOUR);
|
||||
m_render_stages.push_back(render_stage);
|
||||
|
||||
m_per_frame_ubo = buffer_manager->CreateGPUBuffer("PerFrameUBO",
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
void HydraRenderStage::Initialise(std::string vertex_shader_file,
|
||||
std::string fragment_shader_file,
|
||||
std::string geometry_shader_file,
|
||||
std::string tess_control_shader_file,
|
||||
std::string tess_evaluation_shader_file,
|
||||
HydraShaderBinding shader_binding,
|
||||
uint32_t framebuffer_id,
|
||||
std::vector<uint32_t> textures,
|
||||
@@ -46,6 +48,16 @@ void HydraRenderStage::Initialise(std::string vertex_shader_file,
|
||||
m_geometry_shader = _LoadShader(geometry_shader_file, GL_GEOMETRY_SHADER);
|
||||
glAttachShader(m_program, m_geometry_shader);
|
||||
}
|
||||
if (tess_control_shader_file.length() > 0)
|
||||
{
|
||||
m_tess_control_shader = _LoadShader(tess_control_shader_file, GL_TESS_CONTROL_SHADER);
|
||||
glAttachShader(m_program, m_tess_control_shader);
|
||||
}
|
||||
if (tess_evaluation_shader_file.length() > 0)
|
||||
{
|
||||
m_tess_evaluation_shader = _LoadShader(tess_evaluation_shader_file, GL_TESS_EVALUATION_SHADER);
|
||||
glAttachShader(m_program, m_tess_evaluation_shader);
|
||||
}
|
||||
glLinkProgram(m_program);
|
||||
|
||||
int success;
|
||||
@@ -180,7 +192,6 @@ void HydraRenderStage::_BindBuffers()
|
||||
for (uint32_t bind_idx = 0; bind_idx < m_shader_binding.block_name.size(); bind_idx++)
|
||||
{
|
||||
HydraBuffer buffer = buffer_manager->GetBuffer(m_shader_binding.buffer_id[bind_idx]);
|
||||
|
||||
switch (m_shader_binding.buffer_type[bind_idx])
|
||||
{
|
||||
case HYDRA_BUFFER_TYPE::HYDRA_SSBO_BUFFER:
|
||||
|
||||
@@ -13,6 +13,8 @@ class HydraRenderStage : public HydraObject
|
||||
void Initialise(std::string vertex_shader_file,
|
||||
std::string fragment_shader_file,
|
||||
std::string geometry_shader_file,
|
||||
std::string tess_control_shader_file,
|
||||
std::string tess_evaluation_shader_file,
|
||||
HydraShaderBinding shader_binding,
|
||||
uint32_t framebuffer_id,
|
||||
std::vector<uint32_t> textures,
|
||||
@@ -32,6 +34,8 @@ class HydraRenderStage : public HydraObject
|
||||
uint32_t m_vertex_shader = GL_INVALID_VALUE;
|
||||
uint32_t m_fragment_shader = GL_INVALID_VALUE;
|
||||
uint32_t m_geometry_shader = GL_INVALID_VALUE;
|
||||
uint32_t m_tess_control_shader = GL_INVALID_VALUE;
|
||||
uint32_t m_tess_evaluation_shader = GL_INVALID_VALUE;
|
||||
uint32_t m_program = GL_INVALID_VALUE;
|
||||
uint32_t m_renderable_type;
|
||||
uint32_t m_framebuffer_id = 0;
|
||||
|
||||
@@ -158,6 +158,7 @@ void HydraShadowPipeline::_CreatePointRenderStage()
|
||||
render_stage->Initialise(shader_path + "shadow_point_shader.vert",
|
||||
shader_path + "shadow_point_shader.frag",
|
||||
shader_path + "shadow_point_shader.geom",
|
||||
"", "",
|
||||
shader_binding,
|
||||
0,
|
||||
textures,
|
||||
@@ -212,6 +213,7 @@ void HydraShadowPipeline::_CreateDirectionalRenderStage()
|
||||
render_stage->Initialise(shader_path + "shadow_cascade_shader.vert",
|
||||
shader_path + "shadow_cascade_shader.frag",
|
||||
shader_path + "shadow_cascade_shader.geom",
|
||||
"","",
|
||||
shader_binding,
|
||||
0,
|
||||
textures,
|
||||
@@ -265,7 +267,7 @@ void HydraShadowPipeline::_CreateSpotRenderStage()
|
||||
|
||||
render_stage->Initialise(shader_path + "shadow_spot_shader.vert",
|
||||
shader_path + "shadow_spot_shader.frag",
|
||||
"",
|
||||
"", "", "",
|
||||
shader_binding,
|
||||
0,
|
||||
textures,
|
||||
|
||||
@@ -26,6 +26,7 @@ void HydraRenderer::Initialise(HydraRenderSettings render_settings)
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
|
||||
glfwSwapInterval(0);
|
||||
// glDebugMessageCallback(MessageCallback, 0);
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -2,11 +2,11 @@
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
LastUsed=20260925
|
||||
LastUsed=20260928
|
||||
|
||||
[Window][Hello, world!]
|
||||
Pos=60,60
|
||||
Size=338,157
|
||||
Collapsed=0
|
||||
LastUsed=20260925
|
||||
LastUsed=20260928
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user