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 {
56 text: String,
57 at: Vec2,
58 color: Color,
59 },
60 McItem { item_id: String, at: Rect },
62 McTexture { path: String, at: Rect },
65}
66
67impl OverlayCmd {
68 pub(crate) fn icon(icon: &str, at: Rect) -> OverlayCmd {
71 if icon.ends_with(yog_ids::res::PNG) {
72 OverlayCmd::McTexture {
73 path: icon.to_string(),
74 at,
75 }
76 } else {
77 OverlayCmd::McItem {
78 item_id: icon.to_string(),
79 at,
80 }
81 }
82 }
83
84 pub(crate) fn animated(&self) -> bool {
86 match self {
87 OverlayCmd::Entity { .. } | OverlayCmd::Blocks { .. } => true,
88 OverlayCmd::McItems { items, .. } => items.iter().filter(|i| !is_tag(i)).count() > 1,
89 _ => false,
90 }
91 }
92}
93
94fn is_tag(item: &str) -> bool {
96 item.starts_with(yog_ids::sep::TAG_SHOWN)
97}
98
99pub(crate) fn draw_sprites(ctx: &GfxContext, sprites: &[BgSprite], book_sheet: &str) {
101 let d2 = ctx.draw2d();
102 for spr in sprites {
103 let sheet = match &spr.sheet {
104 SpriteSheet::Book => book_sheet,
105 SpriteSheet::Crafting => CRAFTING_SHEET,
106 SpriteSheet::Image(source) => source.as_str(),
107 };
108 d2.image_region(sheet, spr.dst, Some(spr.src), Color::WHITE);
109 }
110}
111
112pub(crate) fn draw_scenes(
114 ctx: &GfxContext,
115 overlays: &[OverlayCmd],
116 t: f32,
117 draw: super::PageDrawer<'_>,
118) {
119 let d2 = ctx.draw2d();
120 for ov in overlays {
121 match ov {
122 OverlayCmd::Drawn { drawer, data, at } => {
123 draw(ctx, drawer, data, [at.x, at.y, at.w, at.h])
124 }
125 OverlayCmd::Entity { entity, at } => {
126 d2.entity(entity, *at, ENTITY_YAW + t * ENTITY_TURN, 0.0)
127 }
128 OverlayCmd::Blocks {
129 blocks,
130 at,
131 turning,
132 } => {
133 let list: Vec<((i32, i32, i32), &str)> =
134 blocks.iter().map(|(p, b)| (*p, b.as_str())).collect();
135 let yaw = if *turning {
136 MULTIBLOCK_YAW + t * MULTIBLOCK_SWAY
137 } else {
138 SLOT_YAW
139 };
140 d2.blocks(&list, *at, yaw, BLOCK_PITCH);
141 }
142 _ => {}
143 }
144 }
145}
146
147pub(crate) fn draw_items(ctx: &GfxContext, overlays: &[OverlayCmd], second: usize) {
150 let d2 = ctx.draw2d();
151 for ov in overlays {
152 match ov {
153 OverlayCmd::McItems { items, at } => {
154 let shown: Vec<&String> = items.iter().filter(|i| !is_tag(i)).collect();
155 if !shown.is_empty() {
156 let item = shown[second % shown.len()];
157 d2.item(
158 &normalize_item_id(item),
159 Vec2::new(at.x, at.y),
160 at.w.min(at.h),
161 );
162 }
163 }
164 OverlayCmd::McItem { item_id, at } => d2.item(
165 &normalize_item_id(item_id),
166 Vec2::new(at.x, at.y),
167 at.w.min(at.h),
168 ),
169 OverlayCmd::McText { text, at, color } => d2.text(text, *at, *color, false),
170 OverlayCmd::McTexture { path, at } => d2.image(path, *at),
172 _ => {}
173 }
174 }
175}