renderer now uses a single pipeline for ugui
This commit is contained in:
parent
622b648d26
commit
be1476d107
@ -1,21 +0,0 @@
|
|||||||
#version 450
|
|
||||||
|
|
||||||
layout(set = 3, binding = 0) uniform Viewport {
|
|
||||||
ivec2 view;
|
|
||||||
};
|
|
||||||
layout(set = 2, binding = 0) uniform sampler2D tx;
|
|
||||||
|
|
||||||
layout(location = 0) in vec2 uv;
|
|
||||||
layout(location = 1) in vec4 color;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
ivec2 ts = textureSize(tx, 0);
|
|
||||||
vec2 fts = vec2(ts);
|
|
||||||
vec2 real_uv = uv / fts;
|
|
||||||
|
|
||||||
vec4 opacity = texture(tx, real_uv);
|
|
||||||
fragColor = vec4(color.rgb, color.a*opacity.r);
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
#version 450
|
|
||||||
|
|
||||||
layout(set = 3, binding = 0) uniform Viewport {
|
|
||||||
ivec2 view;
|
|
||||||
};
|
|
||||||
layout(set = 2, binding = 0) uniform sampler2D tx;
|
|
||||||
|
|
||||||
const float PX_RANGE = 4.0f;
|
|
||||||
|
|
||||||
layout(location = 0) in vec2 uv;
|
|
||||||
layout(location = 1) in vec4 color;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
|
|
||||||
float screen_px_range(vec2 uv) {
|
|
||||||
vec2 unit_range = vec2(PX_RANGE)/vec2(textureSize(tx, 0));
|
|
||||||
vec2 texel_size = vec2(1.0)/fwidth(uv);
|
|
||||||
return max(0.5*dot(unit_range, texel_size), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float median(float r, float g, float b) {
|
|
||||||
return max(min(r, g), min(max(r, g), b));
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
ivec2 ts = textureSize(tx, 0);
|
|
||||||
vec2 fts = vec2(ts);
|
|
||||||
vec2 real_uv = uv / fts;
|
|
||||||
|
|
||||||
vec3 msd = texture(tx, real_uv).rgb;
|
|
||||||
float sd = median(msd.r, msd.g, msd.b);
|
|
||||||
float distance = screen_px_range(real_uv)*(sd - 0.5);
|
|
||||||
float opacity = clamp(distance + 0.5, 0.0, 1.0);
|
|
||||||
fragColor = color * opacity;
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
#version 450
|
|
||||||
|
|
||||||
layout(set = 3, binding = 0) uniform Viewport {
|
|
||||||
ivec2 view;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) in vec4 in_color;
|
|
||||||
layout(location = 1) in vec4 in_quad_size; // x,y, w,h
|
|
||||||
layout(location = 2) in float in_radius;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
|
|
||||||
// SDF for a rounded rectangle given the centerpoint, half size and radius, all in pixels
|
|
||||||
float sdf_rr(vec2 p, vec2 half_size, float radius) {
|
|
||||||
vec2 q = abs(p) - half_size + radius;
|
|
||||||
return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec2 centerpoint = in_quad_size.xy + in_quad_size.zw * 0.5;
|
|
||||||
vec2 half_size = in_quad_size.zw * 0.5;
|
|
||||||
float distance = sdf_rr(vec2(gl_FragCoord) - centerpoint, half_size, in_radius);
|
|
||||||
float alpha = 1.0 - smoothstep(0.0, 1.5, distance);
|
|
||||||
|
|
||||||
fragColor = vec4(in_color.rgb, in_color.a * alpha);
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
#version 450
|
|
||||||
|
|
||||||
layout(set = 1, binding = 0) uniform Viewport {
|
|
||||||
ivec2 view;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) in ivec2 position;
|
|
||||||
layout(location = 1) in ivec4 attr; // quad x,y,w,h
|
|
||||||
layout(location = 2) in ivec2 uv; // x,y in the texture
|
|
||||||
layout(location = 3) in uvec4 color;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 out_color;
|
|
||||||
layout(location = 1) out vec4 out_quad_size;
|
|
||||||
layout(location = 2) out float out_radius;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// vertex position
|
|
||||||
ivec2 px_pos = attr.xy + position.xy * attr.zw;
|
|
||||||
vec2 clip_pos;
|
|
||||||
clip_pos.x = float(px_pos.x)*2.0 / view.x - 1.0;
|
|
||||||
clip_pos.y = -(float(px_pos.y)*2.0 / view.y - 1.0);
|
|
||||||
|
|
||||||
gl_Position = vec4(clip_pos, 0.0, 1.0);
|
|
||||||
|
|
||||||
out_color = vec4(color) / 255.0;
|
|
||||||
out_quad_size = vec4(attr);
|
|
||||||
out_radius = float(abs(uv.x));
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
#version 450
|
|
||||||
|
|
||||||
layout(set = 3, binding = 0) uniform Viewport {
|
|
||||||
ivec2 view;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) in vec2 uv;
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
|
|
||||||
layout(set = 2, binding = 0) uniform sampler2D tx;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
ivec2 ts = textureSize(tx, 0);
|
|
||||||
vec2 fts = vec2(ts);
|
|
||||||
vec2 real_uv = uv / fts;
|
|
||||||
fragColor = texture(tx, real_uv);
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
#version 450
|
|
||||||
|
|
||||||
layout(set = 1, binding = 0) uniform Viewport {
|
|
||||||
ivec2 view;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) in ivec2 position;
|
|
||||||
layout(location = 1) in ivec4 attr; // quad x,y,w,h
|
|
||||||
layout(location = 2) in ivec2 in_uv;
|
|
||||||
layout(location = 3) in uvec4 color;
|
|
||||||
|
|
||||||
layout(location = 0) out vec2 out_uv;
|
|
||||||
layout(location = 1) out vec4 out_color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// vertex position
|
|
||||||
ivec2 px_pos = attr.xy + position.xy * attr.zw;
|
|
||||||
vec2 clip_pos;
|
|
||||||
clip_pos.x = float(px_pos.x)*2.0 / view.x - 1.0;
|
|
||||||
clip_pos.y = -(float(px_pos.y)*2.0 / view.y - 1.0);
|
|
||||||
|
|
||||||
gl_Position = vec4(clip_pos, 0.0, 1.0);
|
|
||||||
|
|
||||||
vec2 px_uv = in_uv.xy + position.xy * attr.zw;
|
|
||||||
out_uv = vec2(px_uv);
|
|
||||||
out_color = vec4(color) / 255.0;
|
|
||||||
}
|
|
118
resources/shaders/source/ugui.frag.glsl
Normal file
118
resources/shaders/source/ugui.frag.glsl
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
/* Combined fragment shader to render UGUI commands */
|
||||||
|
|
||||||
|
// type values, these are the same as in renderer.c3
|
||||||
|
const uint TYPE_RECT = 0;
|
||||||
|
const uint TYPE_FONT = 1;
|
||||||
|
const uint TYPE_SPRITE = 2;
|
||||||
|
const uint TYPE_MSDF = 3;
|
||||||
|
|
||||||
|
// viewport size
|
||||||
|
layout(set = 3, binding = 0) uniform Viewport {
|
||||||
|
ivec2 view;
|
||||||
|
};
|
||||||
|
|
||||||
|
// textures
|
||||||
|
layout(set = 2, binding = 0) uniform sampler2D font_atlas;
|
||||||
|
layout(set = 2, binding = 1) uniform sampler2D sprite_atlas;
|
||||||
|
|
||||||
|
// inputs
|
||||||
|
layout(location = 0) in vec4 in_color;
|
||||||
|
layout(location = 1) in vec2 in_uv;
|
||||||
|
layout(location = 2) in vec4 in_quad_size;
|
||||||
|
layout(location = 3) in float in_radius;
|
||||||
|
layout(location = 4) flat in uint in_type;
|
||||||
|
|
||||||
|
// outputs
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
|
||||||
|
// SDF for a rounded rectangle given the centerpoint, half size and radius, all in pixels
|
||||||
|
float sdf_rr(vec2 p, vec2 half_size, float radius) {
|
||||||
|
vec2 q = abs(p) - half_size + radius;
|
||||||
|
return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const float PX_RANGE = 4.0f;
|
||||||
|
float screen_px_range(vec2 uv, sampler2D tx) {
|
||||||
|
vec2 unit_range = vec2(PX_RANGE)/vec2(textureSize(tx, 0));
|
||||||
|
vec2 texel_size = vec2(1.0)/fwidth(uv);
|
||||||
|
return max(0.5*dot(unit_range, texel_size), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float median(float r, float g, float b) {
|
||||||
|
return max(min(r, g), min(max(r, g), b));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// main for TYPE_RECT, draw a rouded rectangle with a SDF
|
||||||
|
void rect_main()
|
||||||
|
{
|
||||||
|
vec2 centerpoint = in_quad_size.xy + in_quad_size.zw * 0.5;
|
||||||
|
vec2 half_size = in_quad_size.zw * 0.5;
|
||||||
|
float distance = sdf_rr(vec2(gl_FragCoord) - centerpoint, half_size, in_radius);
|
||||||
|
float alpha = 1.0 - smoothstep(0.0, 1.5, distance);
|
||||||
|
fragColor = vec4(in_color.rgb, in_color.a * alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// main for TYPE_SPRITE, draws a sprite sampled from an atlas
|
||||||
|
void sprite_main()
|
||||||
|
{
|
||||||
|
ivec2 ts = textureSize(sprite_atlas, 0);
|
||||||
|
vec2 fts = vec2(ts);
|
||||||
|
vec2 real_uv = in_uv / fts;
|
||||||
|
fragColor = texture(sprite_atlas, real_uv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// main for TYPE_FONT, draws a character sampled from an atlas that contains only the alpha channel
|
||||||
|
void font_main()
|
||||||
|
{
|
||||||
|
ivec2 ts = textureSize(font_atlas, 0);
|
||||||
|
vec2 fts = vec2(ts);
|
||||||
|
vec2 real_uv = in_uv / fts;
|
||||||
|
|
||||||
|
vec4 opacity = texture(font_atlas, real_uv);
|
||||||
|
fragColor = vec4(in_color.rgb, in_color.a*opacity.r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// main for TYPE_MSDF, draws a sprite that is stored as a multi-channel SDF
|
||||||
|
void msdf_main() {
|
||||||
|
ivec2 ts = textureSize(sprite_atlas, 0);
|
||||||
|
vec2 fts = vec2(ts);
|
||||||
|
vec2 real_uv = in_uv / fts;
|
||||||
|
|
||||||
|
vec3 msd = texture(sprite_atlas, real_uv).rgb;
|
||||||
|
float sd = median(msd.r, msd.g, msd.b);
|
||||||
|
float distance = screen_px_range(real_uv, sprite_atlas)*(sd - 0.5);
|
||||||
|
float opacity = clamp(distance + 0.5, 0.0, 1.0);
|
||||||
|
fragColor = in_color * opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// shader main
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
switch (in_type) {
|
||||||
|
case TYPE_RECT:
|
||||||
|
rect_main();
|
||||||
|
break;
|
||||||
|
case TYPE_FONT:
|
||||||
|
font_main();
|
||||||
|
break;
|
||||||
|
case TYPE_SPRITE:
|
||||||
|
sprite_main();
|
||||||
|
break;
|
||||||
|
case TYPE_MSDF:
|
||||||
|
msdf_main();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// ERROR, invalid type, return magenta
|
||||||
|
fragColor = vec4(1.0, 0.0, 1.0, 1.0);
|
||||||
|
}
|
||||||
|
}
|
47
resources/shaders/source/ugui.vert.glsl
Normal file
47
resources/shaders/source/ugui.vert.glsl
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
/* Combined vertex shader to render UGUI commands */
|
||||||
|
|
||||||
|
// Viewport size in pixels
|
||||||
|
layout(set = 1, binding = 0) uniform Viewport {
|
||||||
|
ivec2 view;
|
||||||
|
};
|
||||||
|
|
||||||
|
// inputs
|
||||||
|
layout(location = 0) in ivec2 in_position;
|
||||||
|
layout(location = 1) in ivec4 in_attr; // quad x,y,w,h
|
||||||
|
layout(location = 2) in ivec2 in_uv;
|
||||||
|
layout(location = 3) in uvec4 in_color;
|
||||||
|
layout(location = 4) in uint in_type;
|
||||||
|
|
||||||
|
// outputs
|
||||||
|
layout(location = 0) out vec4 out_color;
|
||||||
|
layout(location = 1) out vec2 out_uv;
|
||||||
|
layout(location = 2) out vec4 out_quad_size;
|
||||||
|
layout(location = 3) out float out_radius;
|
||||||
|
layout(location = 4) out uint out_type;
|
||||||
|
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// vertex position
|
||||||
|
ivec2 px_pos = in_attr.xy + in_position.xy * in_attr.zw;
|
||||||
|
vec2 clip_pos;
|
||||||
|
clip_pos.x = float(px_pos.x)*2.0 / view.x - 1.0;
|
||||||
|
clip_pos.y = -(float(px_pos.y)*2.0 / view.y - 1.0);
|
||||||
|
gl_Position = vec4(clip_pos, 0.0, 1.0);
|
||||||
|
|
||||||
|
// color output
|
||||||
|
out_color = vec4(in_color) / 255.0;
|
||||||
|
|
||||||
|
// uv output. only useful if the type is SPRITE
|
||||||
|
vec2 px_uv = in_uv.xy + in_position.xy * in_attr.zw;
|
||||||
|
out_uv = vec2(px_uv);
|
||||||
|
|
||||||
|
// quad size and radius output, only useful if type is RECT
|
||||||
|
out_quad_size = vec4(in_attr);
|
||||||
|
out_radius = float(abs(in_uv.x));
|
||||||
|
|
||||||
|
// type output
|
||||||
|
out_type = in_type;
|
||||||
|
}
|
27
src/main.c3
27
src/main.c3
@ -47,13 +47,8 @@ fn TimeStats Times.get_stats(×)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char[*] MSDF_FS_PATH = "resources/shaders/compiled/msdf.frag.spv";
|
const char[*] VS_PATH = "resources/shaders/compiled/ugui.vert.spv";
|
||||||
const char[*] SPRITE_FS_PATH = "resources/shaders/compiled/sprite.frag.spv";
|
const char[*] FS_PATH = "resources/shaders/compiled/ugui.frag.spv";
|
||||||
const char[*] FONT_FS_PATH = "resources/shaders/compiled/font.frag.spv";
|
|
||||||
const char[*] RECT_FS_PATH = "resources/shaders/compiled/rect.frag.spv";
|
|
||||||
|
|
||||||
const char[*] SPRITE_VS_PATH = "resources/shaders/compiled/sprite.vert.spv";
|
|
||||||
const char[*] RECT_VS_PATH = "resources/shaders/compiled/rect.vert.spv";
|
|
||||||
|
|
||||||
const char[*] STYLESHEET_PATH = "resources/style.css";
|
const char[*] STYLESHEET_PATH = "resources/style.css";
|
||||||
|
|
||||||
@ -79,10 +74,8 @@ fn int main(String[] args)
|
|||||||
// import font in the ui context
|
// import font in the ui context
|
||||||
ui.load_font("font1", "resources/hack-nerd.ttf", 16)!!;
|
ui.load_font("font1", "resources/hack-nerd.ttf", 16)!!;
|
||||||
|
|
||||||
// create the rendering pipeline
|
// set the renderer's font atlas
|
||||||
ren.font_atlas_id = ui.get_font_id("font1");
|
ren.font_atlas_id = ui.get_font_id("font1");
|
||||||
ren.load_spirv_shader_from_file("UGUI_PIPELINE_FONT", SPRITE_VS_PATH, FONT_FS_PATH, 1, 0);
|
|
||||||
ren.create_pipeline("UGUI_PIPELINE_FONT", SPRITE);
|
|
||||||
|
|
||||||
// send the atlas to the gpu
|
// send the atlas to the gpu
|
||||||
Atlas* font_atlas = ui.get_font_atlas("font1")!!;
|
Atlas* font_atlas = ui.get_font_atlas("font1")!!;
|
||||||
@ -96,24 +89,18 @@ fn int main(String[] args)
|
|||||||
ui.import_sprite_file_qoi("tux", "resources/tux.qoi")!!;
|
ui.import_sprite_file_qoi("tux", "resources/tux.qoi")!!;
|
||||||
ui.import_sprite_file_qoi("tick", "resources/tick_sdf.qoi", SpriteType.SPRITE_MSDF)!!;
|
ui.import_sprite_file_qoi("tick", "resources/tick_sdf.qoi", SpriteType.SPRITE_MSDF)!!;
|
||||||
|
|
||||||
// create the rendering pipelines
|
// set the renderer's sprite atlas
|
||||||
ren.sprite_atlas_id = ui.get_sprite_atlas_id("icons");
|
ren.sprite_atlas_id = ui.get_sprite_atlas_id("icons");
|
||||||
// normal sprite pipeline
|
|
||||||
ren.load_spirv_shader_from_file("UGUI_PIPELINE_SPRITE", SPRITE_VS_PATH, SPRITE_FS_PATH, 1, 0);
|
|
||||||
ren.create_pipeline("UGUI_PIPELINE_SPRITE", SPRITE);
|
|
||||||
// msdf sprite pipeline
|
|
||||||
ren.load_spirv_shader_from_file("UGUI_PIPELINE_SPRITE_MSDF", SPRITE_VS_PATH, MSDF_FS_PATH, 1, 0);
|
|
||||||
ren.create_pipeline("UGUI_PIPELINE_SPRITE_MSDF", SPRITE);
|
|
||||||
|
|
||||||
// upload the atlas to the gpu
|
// upload the atlas to the gpu
|
||||||
Atlas atlas = ui.sprite_atlas.atlas;
|
Atlas atlas = ui.sprite_atlas.atlas;
|
||||||
ren.new_texture("icons", FULL_COLOR, atlas.buffer, atlas.width, atlas.height);
|
ren.new_texture("icons", FULL_COLOR, atlas.buffer, atlas.width, atlas.height);
|
||||||
|
|
||||||
// ========================================================================================== //
|
// ========================================================================================== //
|
||||||
// RECT PIPELINE //
|
// PIPELINE SETUP //
|
||||||
// ========================================================================================== //
|
// ========================================================================================== //
|
||||||
ren.load_spirv_shader_from_file("UGUI_PIPELINE_RECT", RECT_VS_PATH, RECT_FS_PATH, 0, 0);
|
ren.load_spirv_shader_from_file("UGUI_PIPELINE", VS_PATH, FS_PATH, 2, 0);
|
||||||
ren.create_pipeline("UGUI_PIPELINE_RECT", RECT);
|
ren.create_pipeline("UGUI_PIPELINE", RECT);
|
||||||
|
|
||||||
// ========================================================================================== //
|
// ========================================================================================== //
|
||||||
// CSS INPUT //
|
// CSS INPUT //
|
||||||
|
294
src/renderer.c3
294
src/renderer.c3
@ -1,8 +1,8 @@
|
|||||||
module idlist{Type};
|
|
||||||
|
|
||||||
// extends the List type to search elements that have a type.id property
|
// extends the List type to search elements that have a type.id property
|
||||||
// TODO: check that type has an id
|
<*
|
||||||
|
@require $defined((Type){}.id) : `No .id member found in the type`
|
||||||
|
*>
|
||||||
|
module idlist{Type};
|
||||||
import std::collections::list;
|
import std::collections::list;
|
||||||
|
|
||||||
alias IdList = List{Type};
|
alias IdList = List{Type};
|
||||||
@ -22,16 +22,61 @@ macro Type* IdList.get_from_id(&self, id)
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
module sdlrenderer::ren;
|
|
||||||
|
|
||||||
// 2D renderer for ugui, based on SDL3 using the new GPU API
|
// 2D renderer for ugui, based on SDL3 using the new GPU API
|
||||||
|
module sdlrenderer::ren;
|
||||||
import std::io;
|
import std::io;
|
||||||
import std::core::mem;
|
import std::core::mem;
|
||||||
import sdl3::sdl;
|
import sdl3::sdl;
|
||||||
import idlist;
|
import idlist;
|
||||||
import ugui;
|
import ugui;
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================================== //
|
||||||
|
// CONSTANTS //
|
||||||
|
// ============================================================================================== //
|
||||||
|
|
||||||
|
const int DEBUG = 1;
|
||||||
|
const bool CYCLE = true;
|
||||||
|
const int MAX_QUAD_BATCH = 2048;
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================================== //
|
||||||
|
// STRUCTURES //
|
||||||
|
// ============================================================================================== //
|
||||||
|
|
||||||
|
// How each vertex is represented in the gpu
|
||||||
|
struct Vertex {
|
||||||
|
short x, y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributes of each quad instance
|
||||||
|
struct QuadAttributes {
|
||||||
|
struct pos {
|
||||||
|
short x, y, w, h;
|
||||||
|
}
|
||||||
|
struct uv {
|
||||||
|
short u, v;
|
||||||
|
}
|
||||||
|
uint color;
|
||||||
|
uint type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A single quad
|
||||||
|
struct Quad {
|
||||||
|
struct vertices {
|
||||||
|
Vertex v1,v2,v3,v4;
|
||||||
|
}
|
||||||
|
struct indices {
|
||||||
|
short i1,i2,i3,i4,i5,i6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the viewport size uniform passed to the gpu
|
||||||
|
struct ViewsizeUniform @align(16) {
|
||||||
|
int w, h;
|
||||||
|
}
|
||||||
|
|
||||||
struct Shader {
|
struct Shader {
|
||||||
sdl::GPUShader* frag;
|
sdl::GPUShader* frag;
|
||||||
sdl::GPUShader* vert;
|
sdl::GPUShader* vert;
|
||||||
@ -51,7 +96,6 @@ struct Texture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The GPU buffers that contain quad info, the size is determined by MAX_QUAD_BATCH
|
// The GPU buffers that contain quad info, the size is determined by MAX_QUAD_BATCH
|
||||||
const int MAX_QUAD_BATCH = 2048;
|
|
||||||
struct QuadBuffer {
|
struct QuadBuffer {
|
||||||
sdl::GPUBuffer* vert_buf; // on-gpu vertex buffer
|
sdl::GPUBuffer* vert_buf; // on-gpu vertex buffer
|
||||||
sdl::GPUBuffer* idx_buf; // on-gpu index buffer
|
sdl::GPUBuffer* idx_buf; // on-gpu index buffer
|
||||||
@ -89,39 +133,17 @@ struct Renderer {
|
|||||||
int scissor_x, scissor_y, scissor_w, scissor_h;
|
int scissor_x, scissor_y, scissor_w, scissor_h;
|
||||||
}
|
}
|
||||||
|
|
||||||
// How each vertex is represented in the gpu
|
|
||||||
struct Vertex {
|
|
||||||
short x, y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attributes of each quad instance
|
// ============================================================================================== //
|
||||||
struct QuadAttributes {
|
// RENDERERER METHODS //
|
||||||
struct pos {
|
// ============================================================================================== //
|
||||||
short x, y, w, h;
|
|
||||||
}
|
|
||||||
struct uv {
|
|
||||||
short u, v;
|
|
||||||
}
|
|
||||||
uint color;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A single quad
|
|
||||||
struct Quad {
|
|
||||||
struct vertices {
|
|
||||||
Vertex v1,v2,v3,v4;
|
|
||||||
}
|
|
||||||
struct indices {
|
|
||||||
short i1,i2,i3,i4,i5,i6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ViewsizeUniform @align(16) {
|
|
||||||
int w, h;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int DEBUG = 1;
|
|
||||||
const bool CYCLE = true;
|
|
||||||
|
|
||||||
|
/* Initialize the renderer structure, this does a couple of things
|
||||||
|
* 1. Initializes the SDL video subsystem with the correct hints
|
||||||
|
* 2. Creates a window and attaches it to the gpu device
|
||||||
|
* 3. Allocates the quad buffer and uploads the quad mesh to the GPU
|
||||||
|
*/
|
||||||
fn void Renderer.init(&self, ZString title, uint width, uint height, bool vsync)
|
fn void Renderer.init(&self, ZString title, uint width, uint height, bool vsync)
|
||||||
{
|
{
|
||||||
// set wayland hint automagically
|
// set wayland hint automagically
|
||||||
@ -199,7 +221,6 @@ $endif
|
|||||||
unreachable("failed to initialize quad buffer (index): %s", sdl::get_error());
|
unreachable("failed to initialize quad buffer (index): %s", sdl::get_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// upload the quad mesh
|
// upload the quad mesh
|
||||||
GPUTransferBuffer *ts = sdl::create_gpu_transfer_buffer(self.gpu,
|
GPUTransferBuffer *ts = sdl::create_gpu_transfer_buffer(self.gpu,
|
||||||
&&(GPUTransferBufferCreateInfo){.usage = GPU_TRANSFERBUFFERUSAGE_UPLOAD, .size = Quad.sizeof}
|
&&(GPUTransferBufferCreateInfo){.usage = GPU_TRANSFERBUFFERUSAGE_UPLOAD, .size = Quad.sizeof}
|
||||||
@ -278,6 +299,13 @@ $endif
|
|||||||
qb.initialized = true;
|
qb.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Frees all the renderer structures:
|
||||||
|
* - Frees all textures and pipelines
|
||||||
|
* - Releases all GPU transfer buffers
|
||||||
|
* - Closes the main window
|
||||||
|
* - Releases the GPU device
|
||||||
|
*/
|
||||||
fn void Renderer.free(&self)
|
fn void Renderer.free(&self)
|
||||||
{
|
{
|
||||||
foreach (&s: self.shaders) {
|
foreach (&s: self.shaders) {
|
||||||
@ -310,17 +338,24 @@ fn void Renderer.free(&self)
|
|||||||
sdl::quit();
|
sdl::quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn void Renderer.resize_window(&self, uint width, uint height)
|
fn void Renderer.resize_window(&self, uint width, uint height)
|
||||||
{
|
{
|
||||||
sdl::set_window_size(self.win, width, height);
|
sdl::set_window_size(self.win, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn void Renderer.get_window_size(&self, int* width, int* height)
|
fn void Renderer.get_window_size(&self, int* width, int* height)
|
||||||
{
|
{
|
||||||
sdl::get_window_size_in_pixels(self.win, width, height);
|
sdl::get_window_size_in_pixels(self.win, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================================== //
|
||||||
|
// SHADER LOADING //
|
||||||
|
// ============================================================================================== //
|
||||||
|
|
||||||
|
|
||||||
// Both the vertex shader and fragment shader have an implicit uniform buffer at binding 0 that
|
// Both the vertex shader and fragment shader have an implicit uniform buffer at binding 0 that
|
||||||
// contains the viewport size. It is populated automatically at every begin_render() call
|
// contains the viewport size. It is populated automatically at every begin_render() call
|
||||||
fn void Renderer.load_spirv_shader_from_mem(&self, String name, char[] vert_code, char[] frag_code, uint textures, uint uniforms)
|
fn void Renderer.load_spirv_shader_from_mem(&self, String name, char[] vert_code, char[] frag_code, uint textures, uint uniforms)
|
||||||
@ -378,6 +413,7 @@ fn void Renderer.load_spirv_shader_from_mem(&self, String name, char[] vert_code
|
|||||||
self.shaders.push(s);
|
self.shaders.push(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn void Renderer.load_spirv_shader_from_file(&self, String name, String vert_path, String frag_path, uint textures, uint uniforms)
|
fn void Renderer.load_spirv_shader_from_file(&self, String name, String vert_path, String frag_path, uint textures, uint uniforms)
|
||||||
{
|
{
|
||||||
if (vert_path == "" || frag_path == "") {
|
if (vert_path == "" || frag_path == "") {
|
||||||
@ -402,6 +438,12 @@ fn void Renderer.load_spirv_shader_from_file(&self, String name, String vert_pat
|
|||||||
self.load_spirv_shader_from_mem(name, vert_code, frag_code, textures, uniforms);
|
self.load_spirv_shader_from_mem(name, vert_code, frag_code, textures, uniforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================================== //
|
||||||
|
// PIPELINE CREATION //
|
||||||
|
// ============================================================================================== //
|
||||||
|
|
||||||
|
|
||||||
// this describes what we want to draw, since for drawing different things we have to change
|
// this describes what we want to draw, since for drawing different things we have to change
|
||||||
// the GPUPrimitiveType and GPURasterizerState for the pipeline.
|
// the GPUPrimitiveType and GPURasterizerState for the pipeline.
|
||||||
enum PipelineType : (GPUPrimitiveType primitive_type, GPURasterizerState raster_state) {
|
enum PipelineType : (GPUPrimitiveType primitive_type, GPURasterizerState raster_state) {
|
||||||
@ -467,9 +509,15 @@ fn void Renderer.create_pipeline(&self, String shader_name, PipelineType type)
|
|||||||
.buffer_slot = 1,
|
.buffer_slot = 1,
|
||||||
.format = GPU_VERTEXELEMENTFORMAT_UBYTE4,
|
.format = GPU_VERTEXELEMENTFORMAT_UBYTE4,
|
||||||
.offset = QuadAttributes.color.offsetof,
|
.offset = QuadAttributes.color.offsetof,
|
||||||
|
},
|
||||||
|
{ // at location four there is the quad type
|
||||||
|
.location = 4,
|
||||||
|
.buffer_slot = 1,
|
||||||
|
.format = GPU_VERTEXELEMENTFORMAT_UINT,
|
||||||
|
.offset = QuadAttributes.type.offsetof,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.num_vertex_attributes = 4,
|
.num_vertex_attributes = 5,
|
||||||
},
|
},
|
||||||
// the pipeline's primitive type and rasterizer state differs based on what needs to
|
// the pipeline's primitive type and rasterizer state differs based on what needs to
|
||||||
// be drawn
|
// be drawn
|
||||||
@ -513,12 +561,21 @@ fn void Renderer.create_pipeline(&self, String shader_name, PipelineType type)
|
|||||||
self.pipelines.push(p);
|
self.pipelines.push(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================================== //
|
||||||
|
// TEXTURE LOADING //
|
||||||
|
// ============================================================================================== //
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// NOTE: with TEXTUREUSAGE_SAMPLER the texture format cannot be intger _UINT so it has to be nermalized
|
// NOTE: with TEXTUREUSAGE_SAMPLER the texture format cannot be intger _UINT so it has to be nermalized
|
||||||
enum TextureType : (GPUTextureFormat format) {
|
enum TextureType : (GPUTextureFormat format) {
|
||||||
FULL_COLOR = GPU_TEXTUREFORMAT_R8G8B8A8_UNORM,
|
FULL_COLOR = GPU_TEXTUREFORMAT_R8G8B8A8_UNORM,
|
||||||
JUST_ALPHA = GPU_TEXTUREFORMAT_R8_UNORM
|
JUST_ALPHA = GPU_TEXTUREFORMAT_R8_UNORM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This macro wraps new_texture_by_id() by accepting either a name or an id directly
|
||||||
macro void Renderer.new_texture(&self, name_or_id, TextureType type, char[] pixels, uint width, uint height)
|
macro void Renderer.new_texture(&self, name_or_id, TextureType type, char[] pixels, uint width, uint height)
|
||||||
{
|
{
|
||||||
$switch $typeof(name_or_id):
|
$switch $typeof(name_or_id):
|
||||||
@ -528,6 +585,8 @@ macro void Renderer.new_texture(&self, name_or_id, TextureType type, char[] pixe
|
|||||||
$endswitch
|
$endswitch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This macro wraps update_texture_by_id() by accepting either a name or an id directly
|
||||||
macro void Renderer.update_texture(&self, name_or_id, char[] pixels, uint width, uint height, uint x = 0, uint y = 0)
|
macro void Renderer.update_texture(&self, name_or_id, char[] pixels, uint width, uint height, uint x = 0, uint y = 0)
|
||||||
{
|
{
|
||||||
$switch $typeof(name_or_id):
|
$switch $typeof(name_or_id):
|
||||||
@ -538,8 +597,9 @@ macro void Renderer.update_texture(&self, name_or_id, char[] pixels, uint width,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// create a new gpu texture from a pixel buffer, the format has to be specified
|
/* Create a new gpu texture from a pixel buffer, the format has to be specified.
|
||||||
// the new texture s given an id and pushed into a texture list
|
* The new texture is given an id and pushed into the renderer's texture list.
|
||||||
|
*/
|
||||||
fn void Renderer.new_texture_by_id(&self, Id id, TextureType type, char[] pixels, uint width, uint height)
|
fn void Renderer.new_texture_by_id(&self, Id id, TextureType type, char[] pixels, uint width, uint height)
|
||||||
{
|
{
|
||||||
// the texture description
|
// the texture description
|
||||||
@ -587,6 +647,11 @@ fn void Renderer.new_texture_by_id(&self, Id id, TextureType type, char[] pixels
|
|||||||
self.update_texture_by_id(id, pixels, width, height, 0, 0);
|
self.update_texture_by_id(id, pixels, width, height, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Updates a texture on the gpu.
|
||||||
|
* pixels: the pixel array that contais the texture content
|
||||||
|
* width, height: the size of the
|
||||||
|
*/
|
||||||
fn void Renderer.update_texture_by_id(&self, Id id, char[] pixels, uint width, uint height, uint x, uint y)
|
fn void Renderer.update_texture_by_id(&self, Id id, char[] pixels, uint width, uint height, uint x, uint y)
|
||||||
{
|
{
|
||||||
Texture* t = self.textures.get_from_id(id);
|
Texture* t = self.textures.get_from_id(id);
|
||||||
@ -640,23 +705,34 @@ fn void Renderer.update_texture_by_id(&self, Id id, char[] pixels, uint width, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn bool Renderer.push_sprite(&self, short x, short y, short w, short h, short u, short v, uint color = 0xffffffff)
|
// ============================================================================================== //
|
||||||
|
// RENDER COMMANDS //
|
||||||
|
// ============================================================================================== //
|
||||||
|
|
||||||
|
const uint TYPE_RECT = 0;
|
||||||
|
const uint TYPE_FONT = 1;
|
||||||
|
const uint TYPE_SPRITE = 2;
|
||||||
|
const uint TYPE_MSDF = 3;
|
||||||
|
|
||||||
|
fn bool Renderer.push_sprite(&self, short x, short y, short w, short h, short u, short v, uint color = 0xffffffff, uint type)
|
||||||
{
|
{
|
||||||
QuadAttributes qa = {
|
QuadAttributes qa = {
|
||||||
.pos = {.x = x, .y = y, .w = w, .h = h},
|
.pos = {.x = x, .y = y, .w = w, .h = h},
|
||||||
.uv = {.u = u, .v = v},
|
.uv = {.u = u, .v = v},
|
||||||
.color = color
|
.color = color,
|
||||||
|
.type = type,
|
||||||
};
|
};
|
||||||
|
|
||||||
return self.map_quad(qa);
|
return self.map_quad(qa);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bool Renderer.push_quad(&self, short x, short y, short w, short h, uint color, ushort radius = 0)
|
fn bool Renderer.push_quad(&self, short x, short y, short w, short h, uint color, ushort radius, uint type)
|
||||||
{
|
{
|
||||||
QuadAttributes qa = {
|
QuadAttributes qa = {
|
||||||
.pos = {.x = x, .y = y, .w = w, .h = h},
|
.pos = {.x = x, .y = y, .w = w, .h = h},
|
||||||
.uv = {.u = radius, .v = radius},
|
.uv = {.u = radius, .v = radius},
|
||||||
.color = color
|
.color = color,
|
||||||
|
.type = type
|
||||||
};
|
};
|
||||||
|
|
||||||
return self.map_quad(qa);
|
return self.map_quad(qa);
|
||||||
@ -771,12 +847,14 @@ fn void Renderer.begin_render(&self, bool clear_screen)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn void Renderer.end_render(&self)
|
fn void Renderer.end_render(&self)
|
||||||
{
|
{
|
||||||
sdl::submit_gpu_command_buffer(self.render_cmdbuf);
|
sdl::submit_gpu_command_buffer(self.render_cmdbuf);
|
||||||
self.reset_quads();
|
self.reset_quads();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn void Renderer.start_render_pass(&self, String pipeline_name)
|
fn void Renderer.start_render_pass(&self, String pipeline_name)
|
||||||
{
|
{
|
||||||
self.render_pass = sdl::begin_gpu_render_pass(self.render_cmdbuf,
|
self.render_pass = sdl::begin_gpu_render_pass(self.render_cmdbuf,
|
||||||
@ -810,18 +888,42 @@ fn void Renderer.start_render_pass(&self, String pipeline_name)
|
|||||||
sdl::bind_gpu_graphics_pipeline(self.render_pass, p);
|
sdl::bind_gpu_graphics_pipeline(self.render_pass, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn void Renderer.end_render_pass(&self)
|
fn void Renderer.end_render_pass(&self)
|
||||||
{
|
{
|
||||||
sdl::end_gpu_render_pass(self.render_pass);
|
sdl::end_gpu_render_pass(self.render_pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void Renderer.bind_texture(&self, String texture_name)
|
|
||||||
|
fn void Renderer.bind_textures(&self, String... texture_names)
|
||||||
{
|
{
|
||||||
ren::Texture* tx = self.textures.get_from_name(texture_name);
|
// TODO: bind in one pass
|
||||||
sdl::bind_gpu_fragment_samplers(self.render_pass, 0,
|
foreach (idx, name: texture_names) {
|
||||||
|
ren::Texture* tx = self.textures.get_from_name(name);
|
||||||
|
if (tx == null) {
|
||||||
|
unreachable("texture '%s' was not registered", name);
|
||||||
|
}
|
||||||
|
sdl::bind_gpu_fragment_samplers(self.render_pass, (uint)idx,
|
||||||
(GPUTextureSamplerBinding[]){{.texture = tx.texture, .sampler = tx.sampler}}, 1
|
(GPUTextureSamplerBinding[]){{.texture = tx.texture, .sampler = tx.sampler}}, 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn void Renderer.bind_textures_id(&self, ugui::Id... texture_ids)
|
||||||
|
{
|
||||||
|
// TODO: bind in one pass
|
||||||
|
foreach (idx, id: texture_ids) {
|
||||||
|
ren::Texture* tx = self.textures.get_from_id(id);
|
||||||
|
if (tx == null) {
|
||||||
|
unreachable("texture [%d] was not registered", id);
|
||||||
|
}
|
||||||
|
sdl::bind_gpu_fragment_samplers(self.render_pass, (uint)idx,
|
||||||
|
(GPUTextureSamplerBinding[]){{.texture = tx.texture, .sampler = tx.sampler}}, 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn void Renderer.set_scissor(&self, int x, int y, int w, int h)
|
fn void Renderer.set_scissor(&self, int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
@ -866,29 +968,31 @@ fn void Renderer.render_ugui(&self, CmdQueue* queue)
|
|||||||
foreach (&c : queue) {
|
foreach (&c : queue) {
|
||||||
if (c.type == CMD_RECT) {
|
if (c.type == CMD_RECT) {
|
||||||
CmdRect r = c.rect;
|
CmdRect r = c.rect;
|
||||||
self.push_quad(r.rect.x, r.rect.y, r.rect.w, r.rect.h, r.color.to_uint(), r.radius);
|
self.push_quad(r.rect.x, r.rect.y, r.rect.w, r.rect.h, r.color.to_uint(), r.radius, TYPE_RECT);
|
||||||
} else if (c.type == CMD_SPRITE) {
|
} else if (c.type == CMD_SPRITE) {
|
||||||
CmdSprite s = c.sprite;
|
CmdSprite s = c.sprite;
|
||||||
self.push_sprite(s.rect.x, s.rect.y, s.texture_rect.w, s.texture_rect.h, s.texture_rect.x, s.texture_rect.y, s.hue.to_uint());
|
uint type;
|
||||||
|
if (s.texture_id == self.font_atlas_id) {
|
||||||
|
type = TYPE_FONT;
|
||||||
|
} else if (s.texture_id == self.sprite_atlas_id && s.type == SPRITE_NORMAL) {
|
||||||
|
type = TYPE_SPRITE;
|
||||||
|
} else if (s.texture_id == self.sprite_atlas_id && s.type == SPRITE_MSDF) {
|
||||||
|
type = TYPE_MSDF;
|
||||||
|
} else {
|
||||||
|
unreachable("unrecognized command type");
|
||||||
|
}
|
||||||
|
self.push_sprite(s.rect.x, s.rect.y, s.texture_rect.w, s.texture_rect.h, s.texture_rect.x, s.texture_rect.y, s.hue.to_uint(), type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.upload_quads();
|
self.upload_quads();
|
||||||
|
|
||||||
Cmd* last_command;
|
self.start_render_pass("UGUI_PIPELINE");
|
||||||
uint off;
|
self.bind_textures_id(self.font_atlas_id, self.sprite_atlas_id);
|
||||||
uint count;
|
|
||||||
for (Cmd* cmd; (cmd = queue.dequeue() ?? null) != null;) {
|
|
||||||
if (last_command == null || last_command.type != cmd.type) {
|
|
||||||
self.end_command(last_command, off, count);
|
|
||||||
self.begin_command(cmd);
|
|
||||||
off += count;
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
uint calls = 0;
|
||||||
|
uint off;
|
||||||
|
for (Cmd* cmd; (cmd = queue.dequeue() ?? null) != null;) {
|
||||||
switch (cmd.type) {
|
switch (cmd.type) {
|
||||||
case CMD_RECT: nextcase;
|
|
||||||
case CMD_SPRITE:
|
|
||||||
count++;
|
|
||||||
case CMD_UPDATE_ATLAS:
|
case CMD_UPDATE_ATLAS:
|
||||||
// TODO: verify the correct type
|
// TODO: verify the correct type
|
||||||
CmdUpdateAtlas u = cmd.update_atlas;
|
CmdUpdateAtlas u = cmd.update_atlas;
|
||||||
@ -903,60 +1007,20 @@ fn void Renderer.render_ugui(&self, CmdQueue* queue)
|
|||||||
self.scissor_y = s.y;
|
self.scissor_y = s.y;
|
||||||
self.scissor_w = s.w;
|
self.scissor_w = s.w;
|
||||||
self.scissor_h = s.h;
|
self.scissor_h = s.h;
|
||||||
default: unreachable("unknown command: %s", cmd.type);
|
default:
|
||||||
}
|
|
||||||
|
|
||||||
last_command = cmd;
|
|
||||||
}
|
|
||||||
self.end_command(last_command, off, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn void Renderer.begin_command(&self, Cmd* cmd)
|
|
||||||
{
|
|
||||||
if (cmd == null) return;
|
|
||||||
|
|
||||||
switch (cmd.type) {
|
|
||||||
case CMD_RECT:
|
|
||||||
self.start_render_pass("UGUI_PIPELINE_RECT");
|
|
||||||
self.set_scissor(self.scissor_x, self.scissor_y, self.scissor_w, self.scissor_h);
|
self.set_scissor(self.scissor_x, self.scissor_y, self.scissor_w, self.scissor_h);
|
||||||
case CMD_SPRITE:
|
uint count = 1;
|
||||||
// TODO: support multiple sprite and font atlases
|
while (queue.len() != 0 && (queue.get(0).type == CMD_RECT || queue.get(0).type == CMD_SPRITE)) {
|
||||||
CmdSprite s = cmd.sprite;
|
count++;
|
||||||
String pipeline;
|
(void)queue.dequeue();
|
||||||
String texture;
|
|
||||||
if (s.texture_id == self.sprite_atlas_id) {
|
|
||||||
switch (s.type) {
|
|
||||||
case SPRITE_NORMAL: pipeline = "UGUI_PIPELINE_SPRITE";
|
|
||||||
case SPRITE_SDF: pipeline = "UGUI_PIPELINE_SPRITE_SDF";
|
|
||||||
case SPRITE_MSDF: pipeline = "UGUI_PIPELINE_SPRITE_MSDF";
|
|
||||||
case SPRITE_ANIMATED: unreachable("animated sprtes are unsupported for now");
|
|
||||||
default: unreachable("unknown sprite type %s", s.type);
|
|
||||||
}
|
}
|
||||||
texture = "icons";
|
|
||||||
} else if (s.texture_id == self.font_atlas_id) {
|
|
||||||
pipeline = "UGUI_PIPELINE_FONT";
|
|
||||||
texture = "font1";
|
|
||||||
}
|
|
||||||
self.start_render_pass(pipeline);
|
|
||||||
self.bind_texture(texture);
|
|
||||||
self.set_scissor(self.scissor_x, self.scissor_y, self.scissor_w, self.scissor_h);
|
|
||||||
case CMD_UPDATE_ATLAS: break;
|
|
||||||
case CMD_SCISSOR: break;
|
|
||||||
default: unreachable("unknown command: %s", cmd.type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn void Renderer.end_command(&self, Cmd* cmd, uint off, uint count)
|
|
||||||
{
|
|
||||||
if (cmd == null) return;
|
|
||||||
|
|
||||||
switch (cmd.type) {
|
|
||||||
case CMD_RECT: nextcase;
|
|
||||||
case CMD_SPRITE:
|
|
||||||
self.draw_quads(off, count);
|
self.draw_quads(off, count);
|
||||||
|
off += count;
|
||||||
|
calls++;
|
||||||
|
// self.draw_quads(off++, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
self.end_render_pass();
|
self.end_render_pass();
|
||||||
case CMD_UPDATE_ATLAS: break;
|
// ugui::println("calls: ", calls);
|
||||||
case CMD_SCISSOR: break;
|
|
||||||
default: unreachable("unknown command: %s", cmd.type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user