mirror of
https://github.com/nicbarker/clay.git
synced 2025-05-09 11:58:05 +00:00
[Bindings/Odin] Odin Raylib renderer rewrite (#395)
This commit is contained in:
parent
970919e1fb
commit
ea8288158e
@ -475,11 +475,11 @@ createLayout :: proc(lerpValue: f32) -> clay.ClayArray(clay.RenderCommand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadFont :: proc(fontId: u16, fontSize: u16, path: cstring) {
|
loadFont :: proc(fontId: u16, fontSize: u16, path: cstring) {
|
||||||
raylibFonts[fontId] = RaylibFont {
|
assign_at(&raylib_fonts,fontId,Raylib_Font{
|
||||||
font = raylib.LoadFontEx(path, cast(i32)fontSize * 2, nil, 0),
|
font = raylib.LoadFontEx(path, cast(i32)fontSize * 2, nil, 0),
|
||||||
fontId = cast(u16)fontId,
|
fontId = cast(u16)fontId,
|
||||||
}
|
})
|
||||||
raylib.SetTextureFilter(raylibFonts[fontId].font.texture, raylib.TextureFilter.TRILINEAR)
|
raylib.SetTextureFilter(raylib_fonts[fontId].font.texture, raylib.TextureFilter.TRILINEAR)
|
||||||
}
|
}
|
||||||
|
|
||||||
errorHandler :: proc "c" (errorData: clay.ErrorData) {
|
errorHandler :: proc "c" (errorData: clay.ErrorData) {
|
||||||
@ -493,7 +493,7 @@ main :: proc() {
|
|||||||
memory := make([^]u8, minMemorySize)
|
memory := make([^]u8, minMemorySize)
|
||||||
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)
|
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)
|
||||||
clay.Initialize(arena, {cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()}, { handler = errorHandler })
|
clay.Initialize(arena, {cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()}, { handler = errorHandler })
|
||||||
clay.SetMeasureTextFunction(measureText, nil)
|
clay.SetMeasureTextFunction(measure_text, nil)
|
||||||
|
|
||||||
raylib.SetConfigFlags({.VSYNC_HINT, .WINDOW_RESIZABLE, .MSAA_4X_HINT})
|
raylib.SetConfigFlags({.VSYNC_HINT, .WINDOW_RESIZABLE, .MSAA_4X_HINT})
|
||||||
raylib.InitWindow(windowWidth, windowHeight, "Raylib Odin Example")
|
raylib.InitWindow(windowWidth, windowHeight, "Raylib Odin Example")
|
||||||
@ -536,7 +536,7 @@ main :: proc() {
|
|||||||
clay.SetLayoutDimensions({cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()})
|
clay.SetLayoutDimensions({cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()})
|
||||||
renderCommands: clay.ClayArray(clay.RenderCommand) = createLayout(animationLerpValue < 0 ? (animationLerpValue + 1) : (1 - animationLerpValue))
|
renderCommands: clay.ClayArray(clay.RenderCommand) = createLayout(animationLerpValue < 0 ? (animationLerpValue + 1) : (1 - animationLerpValue))
|
||||||
raylib.BeginDrawing()
|
raylib.BeginDrawing()
|
||||||
clayRaylibRender(&renderCommands)
|
clay_raylib_render(&renderCommands)
|
||||||
raylib.EndDrawing()
|
raylib.EndDrawing()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,189 +3,199 @@ package main
|
|||||||
import clay "../../clay-odin"
|
import clay "../../clay-odin"
|
||||||
import "core:math"
|
import "core:math"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
RaylibFont :: struct {
|
Raylib_Font :: struct {
|
||||||
fontId: u16,
|
fontId: u16,
|
||||||
font: raylib.Font,
|
font: rl.Font,
|
||||||
}
|
}
|
||||||
|
|
||||||
clayColorToRaylibColor :: proc(color: clay.Color) -> raylib.Color {
|
clay_color_to_rl_color :: proc(color: clay.Color) -> rl.Color {
|
||||||
return raylib.Color{cast(u8)color.r, cast(u8)color.g, cast(u8)color.b, cast(u8)color.a}
|
return {u8(color.r), u8(color.g), u8(color.b), u8(color.a)}
|
||||||
}
|
}
|
||||||
|
|
||||||
raylibFonts := [10]RaylibFont{}
|
raylib_fonts := [dynamic]Raylib_Font{}
|
||||||
|
|
||||||
measureText :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: rawptr) -> clay.Dimensions {
|
measure_text :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: rawptr) -> clay.Dimensions {
|
||||||
// Measure string size for Font
|
line_width: f32 = 0
|
||||||
textSize: clay.Dimensions = {0, 0}
|
|
||||||
|
|
||||||
maxTextWidth: f32 = 0
|
font := raylib_fonts[config.fontId].font
|
||||||
lineTextWidth: f32 = 0
|
|
||||||
|
|
||||||
textHeight := cast(f32)config.fontSize
|
for i in 0 ..< text.length {
|
||||||
fontToUse := raylibFonts[config.fontId].font
|
glyph_index := text.chars[i] - 32
|
||||||
|
|
||||||
for i in 0 ..< int(text.length) {
|
glyph := font.glyphs[glyph_index]
|
||||||
if (text.chars[i] == '\n') {
|
|
||||||
maxTextWidth = max(maxTextWidth, lineTextWidth)
|
if glyph.advanceX != 0 {
|
||||||
lineTextWidth = 0
|
line_width += f32(glyph.advanceX)
|
||||||
continue
|
|
||||||
}
|
|
||||||
index := cast(i32)text.chars[i] - 32
|
|
||||||
if (fontToUse.glyphs[index].advanceX != 0) {
|
|
||||||
lineTextWidth += cast(f32)fontToUse.glyphs[index].advanceX
|
|
||||||
} else {
|
} else {
|
||||||
lineTextWidth += (fontToUse.recs[index].width + cast(f32)fontToUse.glyphs[index].offsetX)
|
line_width += font.recs[glyph_index].width + f32(glyph.offsetX)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
maxTextWidth = max(maxTextWidth, lineTextWidth)
|
return {width = line_width / 2, height = f32(config.fontSize)}
|
||||||
|
|
||||||
textSize.width = maxTextWidth / 2
|
|
||||||
textSize.height = textHeight
|
|
||||||
|
|
||||||
return textSize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clayRaylibRender :: proc(renderCommands: ^clay.ClayArray(clay.RenderCommand), allocator := context.temp_allocator) {
|
clay_raylib_render :: proc(render_commands: ^clay.ClayArray(clay.RenderCommand), allocator := context.temp_allocator) {
|
||||||
for i in 0 ..< int(renderCommands.length) {
|
for i in 0 ..< render_commands.length {
|
||||||
renderCommand := clay.RenderCommandArray_Get(renderCommands, cast(i32)i)
|
render_command := clay.RenderCommandArray_Get(render_commands, i)
|
||||||
boundingBox := renderCommand.boundingBox
|
bounds := render_command.boundingBox
|
||||||
switch (renderCommand.commandType) {
|
|
||||||
case clay.RenderCommandType.None:
|
switch render_command.commandType {
|
||||||
{}
|
case .None: // None
|
||||||
case clay.RenderCommandType.Text:
|
case .Text:
|
||||||
config := renderCommand.renderData.text
|
config := render_command.renderData.text
|
||||||
// Raylib uses standard C strings so isn't compatible with cheap slices, we need to clone the string to append null terminator
|
|
||||||
text := string(config.stringContents.chars[:config.stringContents.length])
|
text := string(config.stringContents.chars[:config.stringContents.length])
|
||||||
cloned := strings.clone_to_cstring(text, allocator)
|
|
||||||
fontToUse: raylib.Font = raylibFonts[config.fontId].font
|
// Raylib uses C strings instead of Odin strings, so we need to clone
|
||||||
raylib.DrawTextEx(
|
// Assume this will be freed elsewhere since we default to the temp allocator
|
||||||
fontToUse,
|
cstr_text := strings.clone_to_cstring(text, allocator)
|
||||||
cloned,
|
|
||||||
raylib.Vector2{boundingBox.x, boundingBox.y},
|
font := raylib_fonts[config.fontId].font
|
||||||
cast(f32)config.fontSize,
|
rl.DrawTextEx(font, cstr_text, {bounds.x, bounds.y}, f32(config.fontSize), f32(config.letterSpacing), clay_color_to_rl_color(config.textColor))
|
||||||
cast(f32)config.letterSpacing,
|
case .Image:
|
||||||
clayColorToRaylibColor(config.textColor),
|
config := render_command.renderData.image
|
||||||
)
|
tint := config.backgroundColor
|
||||||
case clay.RenderCommandType.Image:
|
if tint == 0 {
|
||||||
config := renderCommand.renderData.image
|
tint = {255, 255, 255, 255}
|
||||||
tintColor := config.backgroundColor
|
|
||||||
if (tintColor.rgba == 0) {
|
|
||||||
tintColor = { 255, 255, 255, 255 }
|
|
||||||
}
|
}
|
||||||
// TODO image handling
|
|
||||||
imageTexture := cast(^raylib.Texture2D)config.imageData
|
imageTexture := (^rl.Texture2D)(config.imageData)
|
||||||
raylib.DrawTextureEx(imageTexture^, raylib.Vector2{boundingBox.x, boundingBox.y}, 0, boundingBox.width / cast(f32)imageTexture.width, clayColorToRaylibColor(tintColor))
|
rl.DrawTextureEx(imageTexture^, {bounds.x, bounds.y}, 0, bounds.width / f32(imageTexture.width), clay_color_to_rl_color(tint))
|
||||||
case clay.RenderCommandType.ScissorStart:
|
case .ScissorStart:
|
||||||
raylib.BeginScissorMode(
|
rl.BeginScissorMode(i32(math.round(bounds.x)), i32(math.round(bounds.y)), i32(math.round(bounds.width)), i32(math.round(bounds.height)))
|
||||||
cast(i32)math.round(boundingBox.x),
|
case .ScissorEnd:
|
||||||
cast(i32)math.round(boundingBox.y),
|
rl.EndScissorMode()
|
||||||
cast(i32)math.round(boundingBox.width),
|
case .Rectangle:
|
||||||
cast(i32)math.round(boundingBox.height),
|
config := render_command.renderData.rectangle
|
||||||
)
|
if config.cornerRadius.topLeft > 0 {
|
||||||
case clay.RenderCommandType.ScissorEnd:
|
radius: f32 = (config.cornerRadius.topLeft * 2) / min(bounds.width, bounds.height)
|
||||||
raylib.EndScissorMode()
|
draw_rect_rounded(bounds.x, bounds.y, bounds.width, bounds.height, radius, config.backgroundColor)
|
||||||
case clay.RenderCommandType.Rectangle:
|
|
||||||
config := renderCommand.renderData.rectangle
|
|
||||||
if (config.cornerRadius.topLeft > 0) {
|
|
||||||
radius: f32 = (config.cornerRadius.topLeft * 2) / min(boundingBox.width, boundingBox.height)
|
|
||||||
raylib.DrawRectangleRounded(raylib.Rectangle{boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height}, radius, 8, clayColorToRaylibColor(config.backgroundColor))
|
|
||||||
} else {
|
} else {
|
||||||
raylib.DrawRectangle(cast(i32)boundingBox.x, cast(i32)boundingBox.y, cast(i32)boundingBox.width, cast(i32)boundingBox.height, clayColorToRaylibColor(config.backgroundColor))
|
draw_rect(bounds.x, bounds.y, bounds.width, bounds.height, config.backgroundColor)
|
||||||
}
|
}
|
||||||
case clay.RenderCommandType.Border:
|
case .Border:
|
||||||
config := renderCommand.renderData.border
|
config := render_command.renderData.border
|
||||||
// Left border
|
// Left border
|
||||||
if (config.width.left > 0) {
|
if config.width.left > 0 {
|
||||||
raylib.DrawRectangle(
|
draw_rect(
|
||||||
cast(i32)math.round(boundingBox.x),
|
bounds.x,
|
||||||
cast(i32)math.round(boundingBox.y + config.cornerRadius.topLeft),
|
bounds.y + config.cornerRadius.topLeft,
|
||||||
cast(i32)config.width.left,
|
f32(config.width.left),
|
||||||
cast(i32)math.round(boundingBox.height - config.cornerRadius.topLeft - config.cornerRadius.bottomLeft),
|
bounds.height - config.cornerRadius.topLeft - config.cornerRadius.bottomLeft,
|
||||||
clayColorToRaylibColor(config.color),
|
config.color,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Right border
|
// Right border
|
||||||
if (config.width.right > 0) {
|
if config.width.right > 0 {
|
||||||
raylib.DrawRectangle(
|
draw_rect(
|
||||||
cast(i32)math.round(boundingBox.x + boundingBox.width - cast(f32)config.width.right),
|
bounds.x + bounds.width - f32(config.width.right),
|
||||||
cast(i32)math.round(boundingBox.y + config.cornerRadius.topRight),
|
bounds.y + config.cornerRadius.topRight,
|
||||||
cast(i32)config.width.right,
|
f32(config.width.right),
|
||||||
cast(i32)math.round(boundingBox.height - config.cornerRadius.topRight - config.cornerRadius.bottomRight),
|
bounds.height - config.cornerRadius.topRight - config.cornerRadius.bottomRight,
|
||||||
clayColorToRaylibColor(config.color),
|
config.color,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Top border
|
// Top border
|
||||||
if (config.width.top > 0) {
|
if config.width.top > 0 {
|
||||||
raylib.DrawRectangle(
|
draw_rect(
|
||||||
cast(i32)math.round(boundingBox.x + config.cornerRadius.topLeft),
|
bounds.x + config.cornerRadius.topLeft,
|
||||||
cast(i32)math.round(boundingBox.y),
|
bounds.y,
|
||||||
cast(i32)math.round(boundingBox.width - config.cornerRadius.topLeft - config.cornerRadius.topRight),
|
bounds.width - config.cornerRadius.topLeft - config.cornerRadius.topRight,
|
||||||
cast(i32)config.width.top,
|
f32(config.width.top),
|
||||||
clayColorToRaylibColor(config.color),
|
config.color,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Bottom border
|
// Bottom border
|
||||||
if (config.width.bottom > 0) {
|
if config.width.bottom > 0 {
|
||||||
raylib.DrawRectangle(
|
draw_rect(
|
||||||
cast(i32)math.round(boundingBox.x + config.cornerRadius.bottomLeft),
|
bounds.x + config.cornerRadius.bottomLeft,
|
||||||
cast(i32)math.round(boundingBox.y + boundingBox.height - cast(f32)config.width.bottom),
|
bounds.y + bounds.height - f32(config.width.bottom),
|
||||||
cast(i32)math.round(boundingBox.width - config.cornerRadius.bottomLeft - config.cornerRadius.bottomRight),
|
bounds.width - config.cornerRadius.bottomLeft - config.cornerRadius.bottomRight,
|
||||||
cast(i32)config.width.bottom,
|
f32(config.width.bottom),
|
||||||
clayColorToRaylibColor(config.color),
|
config.color,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (config.cornerRadius.topLeft > 0) {
|
|
||||||
raylib.DrawRing(
|
// Rounded Borders
|
||||||
raylib.Vector2{math.round(boundingBox.x + config.cornerRadius.topLeft), math.round(boundingBox.y + config.cornerRadius.topLeft)},
|
if config.cornerRadius.topLeft > 0 {
|
||||||
math.round(config.cornerRadius.topLeft - cast(f32)config.width.top),
|
draw_arc(
|
||||||
|
bounds.x + config.cornerRadius.topLeft,
|
||||||
|
bounds.y + config.cornerRadius.topLeft,
|
||||||
|
config.cornerRadius.topLeft - f32(config.width.top),
|
||||||
config.cornerRadius.topLeft,
|
config.cornerRadius.topLeft,
|
||||||
180,
|
180,
|
||||||
270,
|
270,
|
||||||
10,
|
config.color,
|
||||||
clayColorToRaylibColor(config.color),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (config.cornerRadius.topRight > 0) {
|
if config.cornerRadius.topRight > 0 {
|
||||||
raylib.DrawRing(
|
draw_arc(
|
||||||
raylib.Vector2{math.round(boundingBox.x + boundingBox.width - config.cornerRadius.topRight), math.round(boundingBox.y + config.cornerRadius.topRight)},
|
bounds.x + bounds.width - config.cornerRadius.topRight,
|
||||||
math.round(config.cornerRadius.topRight - cast(f32)config.width.top),
|
bounds.y + config.cornerRadius.topRight,
|
||||||
|
config.cornerRadius.topRight - f32(config.width.top),
|
||||||
config.cornerRadius.topRight,
|
config.cornerRadius.topRight,
|
||||||
270,
|
270,
|
||||||
360,
|
360,
|
||||||
10,
|
config.color,
|
||||||
clayColorToRaylibColor(config.color),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (config.cornerRadius.bottomLeft > 0) {
|
if config.cornerRadius.bottomLeft > 0 {
|
||||||
raylib.DrawRing(
|
draw_arc(
|
||||||
raylib.Vector2{math.round(boundingBox.x + config.cornerRadius.bottomLeft), math.round(boundingBox.y + boundingBox.height - config.cornerRadius.bottomLeft)},
|
bounds.x + config.cornerRadius.bottomLeft,
|
||||||
math.round(config.cornerRadius.bottomLeft - cast(f32)config.width.top),
|
bounds.y + bounds.height - config.cornerRadius.bottomLeft,
|
||||||
|
config.cornerRadius.bottomLeft - f32(config.width.top),
|
||||||
config.cornerRadius.bottomLeft,
|
config.cornerRadius.bottomLeft,
|
||||||
90,
|
90,
|
||||||
180,
|
180,
|
||||||
10,
|
config.color,
|
||||||
clayColorToRaylibColor(config.color),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (config.cornerRadius.bottomRight > 0) {
|
if config.cornerRadius.bottomRight > 0 {
|
||||||
raylib.DrawRing(
|
draw_arc(
|
||||||
raylib.Vector2 {
|
bounds.x + bounds.width - config.cornerRadius.bottomRight,
|
||||||
math.round(boundingBox.x + boundingBox.width - config.cornerRadius.bottomRight),
|
bounds.y + bounds.height - config.cornerRadius.bottomRight,
|
||||||
math.round(boundingBox.y + boundingBox.height - config.cornerRadius.bottomRight),
|
config.cornerRadius.bottomRight - f32(config.width.bottom),
|
||||||
},
|
|
||||||
math.round(config.cornerRadius.bottomRight - cast(f32)config.width.bottom),
|
|
||||||
config.cornerRadius.bottomRight,
|
config.cornerRadius.bottomRight,
|
||||||
0.1,
|
0.1,
|
||||||
90,
|
90,
|
||||||
10,
|
config.color,
|
||||||
clayColorToRaylibColor(config.color),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case clay.RenderCommandType.Custom:
|
case clay.RenderCommandType.Custom:
|
||||||
// Implement custom element rendering here
|
// Implement custom element rendering here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper procs, mainly for repeated conversions
|
||||||
|
|
||||||
|
@(private = "file")
|
||||||
|
draw_arc :: proc(x, y: f32, inner_rad, outer_rad: f32,start_angle, end_angle: f32, color: clay.Color){
|
||||||
|
rl.DrawRing(
|
||||||
|
{math.round(x),math.round(y)},
|
||||||
|
math.round(inner_rad),
|
||||||
|
outer_rad,
|
||||||
|
start_angle,
|
||||||
|
end_angle,
|
||||||
|
10,
|
||||||
|
clay_color_to_rl_color(color),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private = "file")
|
||||||
|
draw_rect :: proc(x, y, w, h: f32, color: clay.Color) {
|
||||||
|
rl.DrawRectangle(
|
||||||
|
i32(math.round(x)),
|
||||||
|
i32(math.round(y)),
|
||||||
|
i32(math.round(w)),
|
||||||
|
i32(math.round(h)),
|
||||||
|
clay_color_to_rl_color(color)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private = "file")
|
||||||
|
draw_rect_rounded :: proc(x,y,w,h: f32, radius: f32, color: clay.Color){
|
||||||
|
rl.DrawRectangleRounded({x,y,w,h},radius,8,clay_color_to_rl_color(color))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user