rework sprites and labels so the nodes own the instance buffer

This commit is contained in:
milo 2024-02-05 13:13:36 -05:00
parent 94acf18470
commit 3818e4f550
7 changed files with 93 additions and 126 deletions

View File

@ -76,7 +76,7 @@ module Sprite_graph = struct
include (val Ohlog.sublogs logger "SG")
type t = {
sprite_maps : (string, Sprite.map) Hashtbl.t;
sprite_maps : (string, Sprite_map.t) Hashtbl.t;
fonts : (string, Font.t) Hashtbl.t;
mutable list_rev : node list;
mutable list : node list;
@ -85,14 +85,14 @@ module Sprite_graph = struct
and node =
| Sprites of {
tf : mat2a;
map : Sprite.map;
(* mutable *)sprites : (Sprite.t * vec2) array;
map : Sprite_map.t;
frames : Floatbuffer.t;
(* tint : color *)
}
| Label of {
tf : mat2a;
font : Font.t;
(* mutable *)text : string;
glyphs : Floatbuffer.t;
fg : color;
}
@ -124,22 +124,28 @@ module Sprite_graph = struct
end
let add_sprites t ~tf ~map ~sprites =
let node = Sprites { tf; map; sprites } in
let frames = Floatbuffer.make (List.length sprites * 8) in
List.iter (fun (frame, pos) -> Sprite_map.emit_sprite map frames ~frame ~pos) sprites;
let node = Sprites { tf; map; frames } in
push t node;
node
let add_label t ~tf ~font ~text ~fg =
let node = Label { tf; font; text; fg } in
let glyphs = Floatbuffer.make (String.length text * 10) in
Font.emit_glyphs font glyphs ~text;
let node = Label { tf; font; glyphs; fg } in
push t node;
node
let _white = Color.white ()
let rec render_rec ren = function
| [] -> ()
| Sprites { tf; map; sprites } :: nodes ->
Renderer.draw_sprites ren map sprites ~tf;
| Sprites { tf; map; frames } :: nodes ->
Renderer.draw_sprites ren map frames ~tf ~tint:_white;
render_rec ren nodes
| Label { tf; font; text; fg } :: nodes ->
Renderer.draw_text ren font text ~tf ~fg;
| Label { tf; font; glyphs; fg } :: nodes ->
Renderer.draw_text ren font glyphs ~tf ~fg;
render_rec ren nodes
let render t ~ren =
@ -148,34 +154,6 @@ module Sprite_graph = struct
render_rec ren t.list
end
(*
module Entity = struct
include (val Ohlog.sublogs logger "Entity")
type t = {
name : string option;
id : int;
}
let _next_id = ref (-1)
let make ?name () = {
name;
id = (incr _next_id; !_next_id);
}
let pp ppf t =
Format.fprintf ppf "<%s@%d>"
(Option.value t.name ~default:"")
t.id
let make ?name () =
let ent = make ?name () in
trace (fun m -> m "new entity %a" pp ent);
ent
end
*)
module Scene = struct
module Sexp = Sexplib0.Sexp
open Sexplib0.Sexp_conv
@ -210,20 +188,18 @@ module Scene = struct
of_sexp_error "bad argument to transform" sexp
let parse_sprite_arg ~map = function
| Sexp.List [Atom sprite; x; y] ->
let sprite = Sprite.get map sprite in
| Sexp.List [Atom frame; x; y] ->
let pos = vec2 (float_of_sexp x) (float_of_sexp y) in
sprite, pos
| Atom sprite ->
let sprite = Sprite.get map sprite in
sprite, vec2 0.0 0.0
frame, pos
| Atom frame ->
frame, vec2 0.0 0.0
| sexp ->
of_sexp_error "bad sprite argument" sexp
let parse_sprites ~sg ~tf = function
| Sexp.List (Atom "sprites" :: Atom map :: args) ->
let map = Sprite_graph.get_sprite_map sg map in
let sprites = List.map (parse_sprite_arg ~map) args |> Array.of_list in
let sprites = List.map (parse_sprite_arg ~map) args in
Sprite_graph.add_sprites sg ~tf ~map ~sprites |> ignore
| sexp ->
of_sexp_error "invalid sprites" sexp

View File

@ -19,7 +19,7 @@ module Sprite_graph : sig
type node
val make : unit -> t
val register_sprite_map : t -> string -> Sprite.map -> unit
val register_sprite_map : t -> string -> Sprite_map.t -> unit
val register_font : t -> string -> Font.t -> unit
val render : t -> ren:Renderer.t -> unit
end

View File

@ -14,26 +14,24 @@ type t = {
let empty = aabb 1.0 1.0 0.0 0.0
module Renderer = struct
let offset = vec2 0.0 0.0
let emit_glyphs t ~text buffer =
let offset = vec2 0.0 0.0 in
for i = 0 to String.length text - 1 do
(* TODO: line breaks *)
let { advance; atlas; plane } = Hashtbl.find t.glyphs text.[i] in
if not (AABB.is_empty atlas) then
Renderer.emit_glyph_geometry buffer ~offset ~atlas ~plane;
offset.x <- offset.x +. advance;
done
let draw_text ren ~tf ~fg { msdf; glyphs } str =
begin
offset.x <- 0.0;
offset.y <- 0.0;
Renderer.begin_glyph_batch ren msdf ~tf ~fill:fg;
for i = 0 to String.length str - 1 do
(* TODO: line breaks *)
let { advance; atlas; plane } = Hashtbl.find glyphs str.[i] in
if not (AABB.is_empty atlas) then
Renderer.draw_glyph ren ~offset ~atlas ~plane;
offset.x <- offset.x +. advance;
done;
Renderer.end_glyph_batch ren;
end
module Renderer = struct
let draw_text ren ~tf ~fg font buffer =
Renderer.draw_text ren font.msdf buffer ~tf ~fg
end
(* sexp conv *)
let bounds_of_sexp = function
| Sexp.List [x0; y0; x1; y1] ->
AABB.make

View File

@ -231,7 +231,7 @@ let set_tex : texture set_fn =
type t = {
window : Sdl.window;
gl_ctx : Sdl.gl_context;
buffer : Floatbuffer.t;
(* buffer : Floatbuffer.t; *)
polygon : shader;
polygon_rect_g : geometry;
@ -339,7 +339,6 @@ let make ~(wnd : Sdl.window) : t =
{
window = wnd;
gl_ctx;
buffer = Floatbuffer.make 128;
polygon;
polygon_rect_g;
sprite;
@ -385,45 +384,35 @@ let draw_rect t ~tf ~fill rect =
draw_geometry t.polygon_rect_g 1;
end
let begin_sprite_batch t tex ~tf ~tint =
let draw_sprites t tex buffer ~tf ~tint =
begin
use t.sprite;
set_mat2a (uniform t.sprite "Transform") tf;
set_tex (uniform t.sprite "Texture") tex;
set_color (uniform t.sprite "Tint") tint;
Floatbuffer.clear t.buffer;
update_vertex_buffer t.sprite_instances buffer;
draw_geometry t.sprite_g (Floatbuffer.length buffer / 8);
end
let draw_sprite t ~rect ~clip =
let emit_sprite_geometry buffer ~rect ~clip =
begin
Floatbuffer.add_aabb t.buffer rect;
Floatbuffer.add_aabb t.buffer clip;
Floatbuffer.add_aabb buffer rect;
Floatbuffer.add_aabb buffer clip;
end
let end_sprite_batch t =
begin
update_vertex_buffer t.sprite_instances t.buffer;
draw_geometry t.sprite_g (Floatbuffer.length t.buffer / 8);
end
let begin_glyph_batch t tex ~tf ~fill =
let draw_text t tex buffer ~tf ~fg =
begin
use t.msdf;
set_mat2a (uniform t.msdf "Transform") tf;
set_tex (uniform t.msdf "Texture") tex;
set_color (uniform t.msdf "Fill") fill;
Floatbuffer.clear t.buffer;
set_color (uniform t.msdf "Fill") fg;
update_vertex_buffer t.msdf_instances buffer;
draw_geometry t.msdf_glyph_g (Floatbuffer.length buffer / 10);
end
let draw_glyph t ~offset ~atlas ~plane =
let emit_glyph_geometry buffer ~offset ~atlas ~plane =
begin
Floatbuffer.add_vec2 t.buffer offset;
Floatbuffer.add_aabb t.buffer atlas;
Floatbuffer.add_aabb t.buffer plane;
end
let end_glyph_batch t =
begin
update_vertex_buffer t.msdf_instances t.buffer;
draw_geometry t.msdf_glyph_g (Floatbuffer.length t.buffer / 10);
Floatbuffer.add_vec2 buffer offset;
Floatbuffer.add_aabb buffer atlas;
Floatbuffer.add_aabb buffer plane;
end

View File

@ -1,14 +1,14 @@
module Window = Window
module Sprite = Sprite
module Sprite_map = Sprite_map
module Font = Font
module Renderer = struct
include Renderer
include Sprite.Renderer
include Sprite_map.Renderer
include Font.Renderer
end
module Asset = struct
include Asset
include Sprite.Asset
include Sprite_map.Asset
include Font.Asset
end
module Sdl = Sdl

View File

@ -14,14 +14,18 @@ module Window : sig
val event_loop : t -> render:(float -> unit) -> unit
end
module Sprite : sig
module Sprite_map : sig
open Adam
type t
type map
val get : map -> string -> t
val emit_sprite : t -> frame:string -> pos:vec2 -> Floatbuffer.t -> unit
end
module Font : sig
open Adam
type t
val emit_glyphs : t -> text:string -> Floatbuffer.t -> unit
end
module Renderer : sig
@ -35,8 +39,8 @@ module Renderer : sig
val post_draw : t -> unit
val clear : t -> color -> unit
val draw_rect : t -> tf:mat2a -> fill:color -> aabb -> unit
val draw_sprites : t -> tf:mat2a -> ?tint:color -> Sprite.map -> (Sprite.t * vec2) array -> unit
val draw_text : t -> tf:mat2a -> fg:color -> Font.t -> string -> unit
val draw_sprites : t -> tf:mat2a -> tint:color -> Sprite_map.t -> Floatbuffer.t -> unit
val draw_text : t -> tf:mat2a -> fg:color -> Font.t -> Floatbuffer.t -> unit
end
module Asset : sig
@ -49,6 +53,6 @@ module Asset : sig
val load_string : string -> string
val load_file : string -> (bigstring -> 'a) -> 'a
val load_sexp_conv : string -> (Sexp.t -> 'a) -> 'a
val load_sprite_map : ?dpi:int -> string -> Sprite.map
val load_sprite_map : ?dpi:int -> string -> Sprite_map.t
val load_font : string -> Font.t
end

View File

@ -4,11 +4,21 @@ include (val Ohlog.sublogs logger "Sprite")
(* TODO: spritemap has one texture shared by all the sprites *)
type t = {
texture : Texture.t;
frames : (string, frame) Hashtbl.t;
}
and frame = {
clip : aabb;
offs : aabb;
}
let make ~pdf ~x ~y ~w ~h ~ox ~oy =
let make ~texture ~frames = {
texture;
frames = Hashtbl.of_seq frames;
}
let make_frame ~pdf ~x ~y ~w ~h ~ox ~oy =
let x0 = Float.of_int x *. pdf
and y0 = Float.of_int y *. pdf
and x1 = Float.of_int (x + w) *. pdf
@ -22,41 +32,31 @@ let make ~pdf ~x ~y ~w ~h ~ox ~oy =
offs = aabb ox0 oy0 ox1 oy1;
}
type map = {
texture : Texture.t;
frames : (string, t) Hashtbl.t;
}
let make_map ~texture ~frames = {
texture;
frames = Hashtbl.of_seq frames;
}
let get map name =
try Hashtbl.find map.frames name
with Not_found ->
Format.ksprintf failwith "no sprite %S in sprite map" name
module Renderer = struct
let _white = Color.white ()
let rect = aabb 0.0 0.0 0.0 0.0
let emit_sprite t ~frame ~pos buffer =
let rect = aabb 0.0 0.0 0.0 0.0 in
let { clip; offs } = Hashtbl.find t.frames frame in
rect.x0 <- offs.x0 +. (pos : vec2).x;
rect.y0 <- offs.y0 +. (pos : vec2).y;
rect.x1 <- offs.x1 +. (pos : vec2).x;
rect.y1 <- offs.y1 +. (pos : vec2).y;
Renderer.emit_sprite_geometry buffer ~rect ~clip
let draw_sprites ren ~tf ?(tint = _white) { texture; _ } frames =
Renderer.begin_sprite_batch ren texture ~tf ~tint;
for i = 0 to Array.length frames - 1 do
let { clip; offs }, (pos : vec2) = frames.(i) in
rect.x0 <- offs.x0 +. pos.x;
rect.y0 <- offs.y0 +. pos.y;
rect.x1 <- offs.x1 +. pos.x;
rect.y1 <- offs.y1 +. pos.y;
Renderer.draw_sprite ren ~rect ~clip;
done;
Renderer.end_sprite_batch ren
module Renderer = struct
let draw_sprites ren ~tf ~tint t buffer =
Renderer.draw_sprites ren t.texture buffer ~tf ~tint
end
let sprite_of_sexp ~pdf = function
(* sexp conv *)
let frame_of_sexp ~pdf = function
| Sexp.List [Atom name; x; y; w; h; ox; oy] ->
name, make ~pdf
name, make_frame ~pdf
~x:(Sexp_conv.int_of_sexp x)
~y:(Sexp_conv.int_of_sexp y)
~w:(Sexp_conv.int_of_sexp w)
@ -72,8 +72,8 @@ let of_sexp ~texture ?dpi = function
| Some dpi -> Float.of_int dpi /. 96.0
| None -> 1.0
in
make_map ~texture
~frames:(List.to_seq args |> Seq.map (sprite_of_sexp ~pdf))
let frames = List.to_seq args |> Seq.map (frame_of_sexp ~pdf) in
make ~texture ~frames
| sexp ->
Sexp_conv.of_sexp_error "invalid sprite map" sexp