panels
This commit is contained in:
@@ -25,6 +25,7 @@ UIRenderer :: struct {
|
||||
dpi_scale: f32;
|
||||
white_texture: u32;
|
||||
current_texture: u32;
|
||||
draw_calls: s64;
|
||||
|
||||
init :: (self: *UIRenderer) {
|
||||
// Create shader (ES for WASM/WebGL2, Core for desktop)
|
||||
@@ -70,11 +71,22 @@ UIRenderer :: struct {
|
||||
self.white_texture = create_white_texture();
|
||||
}
|
||||
|
||||
begin :: (self: *UIRenderer, width: f32, height: f32) {
|
||||
begin :: (self: *UIRenderer, width: f32, height: f32, font_texture: u32) {
|
||||
self.screen_width = width;
|
||||
self.screen_height = height;
|
||||
self.vertex_count = 0;
|
||||
self.current_texture = self.white_texture;
|
||||
self.current_texture = font_texture;
|
||||
self.draw_calls = 0;
|
||||
|
||||
// Set up GL state once for the entire frame
|
||||
glUseProgram(self.shader);
|
||||
proj := Mat4.ortho(0.0, width, height, 0.0, -1.0, 1.0);
|
||||
glUniformMatrix4fv(self.proj_loc, 1, 0, proj.data);
|
||||
glUniform1i(self.tex_loc, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, font_texture);
|
||||
glBindVertexArray(self.vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.vbo);
|
||||
}
|
||||
|
||||
bind_texture :: (self: *UIRenderer, tex: u32) {
|
||||
@@ -148,8 +160,13 @@ UIRenderer :: struct {
|
||||
}
|
||||
case .image: {
|
||||
self.bind_texture(node.texture_id);
|
||||
self.push_quad(node.frame, COLOR_WHITE, 0.0, 0.0);
|
||||
self.bind_texture(self.white_texture);
|
||||
neg2 : f32 = 0.0 - 2.0;
|
||||
self.push_quad(node.frame, COLOR_WHITE, neg2, 0.0);
|
||||
// Re-bind font atlas after image
|
||||
font := g_font;
|
||||
if xx font != 0 {
|
||||
self.bind_texture(font.texture_id);
|
||||
}
|
||||
}
|
||||
case .clip_push: {
|
||||
self.flush();
|
||||
@@ -176,27 +193,16 @@ UIRenderer :: struct {
|
||||
flush :: (self: *UIRenderer) {
|
||||
if self.vertex_count == 0 { return; }
|
||||
|
||||
glUseProgram(self.shader);
|
||||
|
||||
// Orthographic projection: (0,0) top-left, (w,h) bottom-right
|
||||
proj := Mat4.ortho(0.0, self.screen_width, self.screen_height, 0.0, -1.0, 1.0);
|
||||
glUniformMatrix4fv(self.proj_loc, 1, 0, proj.data);
|
||||
|
||||
// Bind current texture
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
// Only bind the current texture (program, projection, VAO already bound in begin())
|
||||
glBindTexture(GL_TEXTURE_2D, self.current_texture);
|
||||
glUniform1i(self.tex_loc, 0);
|
||||
|
||||
glBindVertexArray(self.vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.vbo);
|
||||
|
||||
upload_size : s64 = self.vertex_count * UI_VERTEX_BYTES;
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, xx upload_size, self.vertices);
|
||||
|
||||
// Use glBufferData to orphan the old buffer and avoid GPU sync stalls
|
||||
glBufferData(GL_ARRAY_BUFFER, xx upload_size, self.vertices, GL_DYNAMIC_DRAW);
|
||||
glDrawArrays(GL_TRIANGLES, 0, xx self.vertex_count);
|
||||
|
||||
glBindVertexArray(0);
|
||||
self.vertex_count = 0;
|
||||
self.draw_calls += 1;
|
||||
}
|
||||
|
||||
render_text :: (self: *UIRenderer, node: RenderNode) {
|
||||
@@ -206,9 +212,8 @@ UIRenderer :: struct {
|
||||
// Shape text into positioned glyphs
|
||||
font.shape_text(node.text, node.font_size);
|
||||
|
||||
// Flush any new glyphs to the atlas texture before rendering
|
||||
// Flush any new glyphs to the atlas texture (no texture switch needed — atlas is already bound)
|
||||
font.flush();
|
||||
self.bind_texture(font.texture_id);
|
||||
|
||||
r := node.text_color.rf();
|
||||
g := node.text_color.gf();
|
||||
@@ -256,7 +261,6 @@ UIRenderer :: struct {
|
||||
|
||||
// Flush any glyphs rasterized during this text draw
|
||||
font.flush();
|
||||
self.bind_texture(self.white_texture);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,33 +316,37 @@ float roundedBoxSDF(vec2 center, vec2 half_size, float radius) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
float radius = vParams.x;
|
||||
float mode = vParams.x;
|
||||
float border = vParams.y;
|
||||
vec2 rectSize = vParams.zw;
|
||||
|
||||
if (radius < 0.0) {
|
||||
if (mode < -1.5) {
|
||||
// Image mode (mode == -2.0): sample texture
|
||||
FragColor = texture(uTex, vUV) * vColor;
|
||||
} else if (mode < 0.0) {
|
||||
// Text mode (mode == -1.0): sample glyph atlas .r as alpha
|
||||
float alpha = texture(uTex, vUV).r;
|
||||
float ew = fwidth(alpha) * 0.7;
|
||||
alpha = smoothstep(0.5 - ew, 0.5 + ew, alpha);
|
||||
FragColor = vec4(vColor.rgb, vColor.a * pow(alpha, 0.9));
|
||||
} else if (radius > 0.0 || border > 0.0) {
|
||||
vec4 texColor = texture(uTex, vUV);
|
||||
} else if (mode > 0.0 || border > 0.0) {
|
||||
// Rounded rect: SDF alpha, vertex color only (no texture sample)
|
||||
vec2 half_size = rectSize * 0.5;
|
||||
vec2 center = (vUV - vec2(0.5)) * rectSize;
|
||||
float dist = roundedBoxSDF(center, half_size, radius);
|
||||
float dist = roundedBoxSDF(center, half_size, mode);
|
||||
float aa = fwidth(dist);
|
||||
float alpha = 1.0 - smoothstep(-aa, aa, dist);
|
||||
|
||||
if (border > 0.0) {
|
||||
float inner = roundedBoxSDF(center, half_size - vec2(border), max(radius - border, 0.0));
|
||||
float inner = roundedBoxSDF(center, half_size - vec2(border), max(mode - border, 0.0));
|
||||
float border_alpha = smoothstep(-aa, aa, inner);
|
||||
alpha = alpha * max(border_alpha, 0.0);
|
||||
}
|
||||
|
||||
FragColor = vec4(texColor.rgb * vColor.rgb, texColor.a * vColor.a * alpha);
|
||||
FragColor = vec4(vColor.rgb, vColor.a * alpha);
|
||||
} else {
|
||||
vec4 texColor = texture(uTex, vUV);
|
||||
FragColor = texColor * vColor;
|
||||
// Plain rect: vertex color only (no texture sample)
|
||||
FragColor = vColor;
|
||||
}
|
||||
}
|
||||
GLSL;
|
||||
@@ -384,33 +392,37 @@ float roundedBoxSDF(vec2 center, vec2 half_size, float radius) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
float radius = vParams.x;
|
||||
float mode = vParams.x;
|
||||
float border = vParams.y;
|
||||
vec2 rectSize = vParams.zw;
|
||||
|
||||
if (radius < 0.0) {
|
||||
if (mode < -1.5) {
|
||||
// Image mode (mode == -2.0): sample texture
|
||||
FragColor = texture(uTex, vUV) * vColor;
|
||||
} else if (mode < 0.0) {
|
||||
// Text mode (mode == -1.0): sample glyph atlas .r as alpha
|
||||
float alpha = texture(uTex, vUV).r;
|
||||
float ew = fwidth(alpha) * 0.7;
|
||||
alpha = smoothstep(0.5 - ew, 0.5 + ew, alpha);
|
||||
FragColor = vec4(vColor.rgb, vColor.a * pow(alpha, 0.9));
|
||||
} else if (radius > 0.0 || border > 0.0) {
|
||||
vec4 texColor = texture(uTex, vUV);
|
||||
} else if (mode > 0.0 || border > 0.0) {
|
||||
// Rounded rect: SDF alpha, vertex color only
|
||||
vec2 half_size = rectSize * 0.5;
|
||||
vec2 center = (vUV - vec2(0.5)) * rectSize;
|
||||
float dist = roundedBoxSDF(center, half_size, radius);
|
||||
float dist = roundedBoxSDF(center, half_size, mode);
|
||||
float aa = fwidth(dist);
|
||||
float alpha = 1.0 - smoothstep(-aa, aa, dist);
|
||||
|
||||
if (border > 0.0) {
|
||||
float inner = roundedBoxSDF(center, half_size - vec2(border), max(radius - border, 0.0));
|
||||
float inner = roundedBoxSDF(center, half_size - vec2(border), max(mode - border, 0.0));
|
||||
float border_alpha = smoothstep(-aa, aa, inner);
|
||||
alpha = alpha * max(border_alpha, 0.0);
|
||||
}
|
||||
|
||||
FragColor = vec4(texColor.rgb * vColor.rgb, texColor.a * vColor.a * alpha);
|
||||
FragColor = vec4(vColor.rgb, vColor.a * alpha);
|
||||
} else {
|
||||
vec4 texColor = texture(uTex, vUV);
|
||||
FragColor = texColor * vColor;
|
||||
// Plain rect: vertex color only
|
||||
FragColor = vColor;
|
||||
}
|
||||
}
|
||||
GLSL;
|
||||
|
||||
Reference in New Issue
Block a user