1use yog_gfx::{Color, GfxContext, Rect, Vec2};
6
7use super::geometry::{
8 BLOCK_PITCH, ENTITY_TURN, ENTITY_YAW, MULTIBLOCK_SWAY, MULTIBLOCK_YAW, SLOT_YAW,
9};
10use super::{CRAFTING_SHEET, recipe::normalize_item_id};
11
12#[derive(Clone, PartialEq)]
13pub(crate) enum SpriteSheet {
14 Book,
15 Crafting,
16 Image(String),
18}
19
20#[derive(Clone)]
22pub(crate) struct BgSprite {
23 pub sheet: SpriteSheet,
24 pub src: Rect,
26 pub dst: Rect,
28}
29
30pub type PageDrawer<'a> = &'a mut dyn FnMut(&GfxContext, &str, &yog_data::Value, [f32; 4]);
32
33#[derive(Clone)]
35pub(crate) enum OverlayCmd {
36 Drawn {
38 drawer: String,
39 data: yog_data::Value,
40 at: Rect,
41 },
42 McItems { items: Vec<String>, at: Rect },
45 Blocks {
48 blocks: Vec<((i32, i32, i32), String)>,
49 at: Rect,
50 turning: bool,
51 },
52 Entity { entity: String, at: Rect },
54 McText {
57 text: String,
58 at: Vec2,
59 color: Color,
60 scale: f32,
61 },
62 McItem { item_id: String, at: Rect },
64 McTexture { path: String, at: Rect },
67}
68
69impl OverlayCmd {
70 pub(crate) fn icon(icon: &str, at: Rect) -> OverlayCmd {
73 if icon.ends_with(yog_ids::res::PNG) {
74 OverlayCmd::McTexture {
75 path: icon.to_string(),
76 at,
77 }
78 } else {
79 OverlayCmd::McItem {
80 item_id: icon.to_string(),
81 at,
82 }
83 }
84 }
85
86 pub(crate) fn animated(&self) -> bool {
88 match self {
89 OverlayCmd::Entity { .. } | OverlayCmd::Blocks { .. } => true,
90 OverlayCmd::McItems { items, .. } => items.iter().filter(|i| !is_tag(i)).count() > 1,
91 _ => false,
92 }
93 }
94}
95
96fn is_tag(item: &str) -> bool {
98 item.starts_with(yog_ids::sep::TAG_SHOWN)
99}
100
101pub(crate) fn draw_sprites(ctx: &GfxContext, sprites: &[BgSprite], book_sheet: &str) {
103 let d2 = ctx.draw2d();
104 for spr in sprites {
105 let sheet = match &spr.sheet {
106 SpriteSheet::Book => book_sheet,
107 SpriteSheet::Crafting => CRAFTING_SHEET,
108 SpriteSheet::Image(source) => source.as_str(),
109 };
110 d2.image_region(sheet, spr.dst, Some(spr.src), Color::WHITE);
111 }
112}
113
114pub(crate) fn draw_scenes(
116 ctx: &GfxContext,
117 overlays: &[OverlayCmd],
118 t: f32,
119 draw: super::PageDrawer<'_>,
120) {
121 let d2 = ctx.draw2d();
122 for ov in overlays {
123 match ov {
124 OverlayCmd::Drawn { drawer, data, at } => {
125 draw(ctx, drawer, data, [at.x, at.y, at.w, at.h])
126 }
127 OverlayCmd::Entity { entity, at } => {
128 d2.entity(entity, *at, ENTITY_YAW + t * ENTITY_TURN, 0.0)
129 }
130 OverlayCmd::Blocks {
131 blocks,
132 at,
133 turning,
134 } => {
135 let list: Vec<((i32, i32, i32), &str)> =
136 blocks.iter().map(|(p, b)| (*p, b.as_str())).collect();
137 let yaw = if *turning {
138 MULTIBLOCK_YAW + t * MULTIBLOCK_SWAY
139 } else {
140 SLOT_YAW
141 };
142 d2.blocks(&list, *at, yaw, BLOCK_PITCH);
143 }
144 _ => {}
145 }
146 }
147}
148
149pub(crate) fn draw_items(ctx: &GfxContext, overlays: &[OverlayCmd], second: usize) {
152 let d2 = ctx.draw2d();
153 for ov in overlays {
154 match ov {
155 OverlayCmd::McItems { items, at } => {
156 let shown: Vec<&String> = items.iter().filter(|i| !is_tag(i)).collect();
157 if !shown.is_empty() {
158 let item = shown[second % shown.len()];
159 d2.item(
160 &normalize_item_id(item),
161 Vec2::new(at.x, at.y),
162 at.w.min(at.h),
163 );
164 }
165 }
166 OverlayCmd::McItem { item_id, at } => d2.item(
167 &normalize_item_id(item_id),
168 Vec2::new(at.x, at.y),
169 at.w.min(at.h),
170 ),
171 OverlayCmd::McText {
172 text,
173 at,
174 color,
175 scale,
176 } => d2.text_scaled(
177 text,
178 *at,
179 &yog_gfx::draw2d::TextStyle {
180 font: "",
181 scale: *scale,
182 color: *color,
183 shadow: false,
184 },
185 ),
186 OverlayCmd::McTexture { path, at } => d2.image(path, *at),
188 _ => {}
189 }
190 }
191}