summaryrefslogtreecommitdiff
path: root/src/graphics
diff options
context:
space:
mode:
authorTengu712 <genreihoutengu@gmail.com>2026-10-07 00:57:01 +0900
committerTengu712 <genreihoutengu@gmail.com>2026-10-07 00:57:01 +0900
commit3bbe5ebcdb2a5aa6810dd05576c6ec031efdc1c7 (patch)
tree844e4ba5efc755dabf091a51178937a93e1d47ed /src/graphics
parent503486e2ce889858aac619985516374bddeb7a8f (diff)
render imageHEADmain
Diffstat (limited to 'src/graphics')
-rw-r--r--src/graphics/command.rs53
-rw-r--r--src/graphics/font.rs10
-rw-r--r--src/graphics/image.rs51
3 files changed, 104 insertions, 10 deletions
diff --git a/src/graphics/command.rs b/src/graphics/command.rs
index f0330cb..6c0b036 100644
--- a/src/graphics/command.rs
+++ b/src/graphics/command.rs
@@ -1,8 +1,10 @@
use super::{
InstanceData,
font::{self, CharAtlas},
+ image::ImageId,
+ texture::TextureWrapper,
};
-use glam::Vec2;
+use glam::{Mat2, Vec2};
use wgpu::Queue;
pub enum HorizontalAlign {
@@ -25,8 +27,18 @@ pub struct Text {
pub v_align: VerticalAlign,
}
+pub struct Image {
+ pub id: ImageId,
+ pub origin: Vec2,
+ pub rotation: f32,
+ pub scale: Vec2,
+ pub uv_offset: Vec2,
+ pub uv_size: Vec2,
+}
+
pub enum RenderCommand {
Text(Text),
+ Image(Image),
}
impl RenderCommand {
@@ -37,6 +49,7 @@ impl RenderCommand {
/// * scale_factor - 画面拡大率
/// * queue - queue
/// * char_atlas - 文字テクスチャアトラス
+ /// * images - 画像テクスチャ
/// * buf - インスタンスバッファ
pub fn build(
&self,
@@ -45,6 +58,7 @@ impl RenderCommand {
scale_factor: f32,
queue: &Queue,
char_atlas: &mut CharAtlas,
+ images: &[TextureWrapper],
buf: &mut Vec<InstanceData>,
) {
match self {
@@ -57,6 +71,9 @@ impl RenderCommand {
char_atlas,
buf,
),
+ RenderCommand::Image(image) => {
+ build_image(image, screen_width, screen_height, images, buf)
+ }
}
}
}
@@ -108,12 +125,18 @@ fn build_text(
let center_x = x + ci.x_offset + ci.width / 2.0;
let center_y = y + ci.y_offset + ci.height / 2.0;
buf.push(InstanceData {
- position: Vec2::new(
+ transform: Mat2::from_diagonal(Vec2::new(
+ ci.width / screen_width * 2.0,
+ -ci.height / screen_height * 2.0,
+ )),
+ translation: Vec2::new(
center_x / screen_width * 2.0 - 1.0,
1.0 - center_y / screen_height * 2.0,
),
- scale: Vec2::new(ci.width / screen_width, ci.height / screen_height),
- uv: ci.uv,
+ uv_offset: ci.uv_offset,
+ uv_size: ci.uv_size,
+ tex_id: u32::MAX,
+ _pad: 0,
});
ox += font::h_advance(scale, ci.glyph_id);
}
@@ -128,9 +151,29 @@ fn build_text(
let left = (left * scale_factor).round() / scale_factor;
for instance in &mut buf[start..] {
- instance.position.x += left / screen_width * 2.0;
+ instance.translation.x += left / screen_width * 2.0;
}
baseline += line_height;
}
}
+
+fn build_image(
+ image: &Image,
+ screen_width: f32,
+ screen_height: f32,
+ images: &[TextureWrapper],
+ buf: &mut Vec<InstanceData>,
+) {
+ let texture = &images[image.id as usize];
+ let size = image.uv_size * Vec2::new(texture.width as f32, texture.height as f32) * image.scale;
+ let ndc = Vec2::new(2.0 / screen_width, -2.0 / screen_height);
+ buf.push(InstanceData {
+ transform: Mat2::from_diagonal(ndc) * Mat2::from_scale_angle(size, image.rotation),
+ translation: image.origin * ndc + Vec2::new(-1.0, 1.0),
+ uv_offset: image.uv_offset,
+ uv_size: image.uv_size,
+ tex_id: image.id as u32,
+ _pad: 0,
+ });
+}
diff --git a/src/graphics/font.rs b/src/graphics/font.rs
index c20e691..88163cc 100644
--- a/src/graphics/font.rs
+++ b/src/graphics/font.rs
@@ -1,7 +1,7 @@
use super::texture::TextureWrapper;
use ab_glyph::*;
use etagere::{AllocId, AtlasAllocator};
-use glam::Vec4;
+use glam::Vec2;
use lru::LruCache;
use std::sync::LazyLock;
use ttf_parser::{
@@ -103,7 +103,8 @@ pub struct CharInfo {
pub height: f32,
pub x_offset: f32,
pub y_offset: f32,
- pub uv: Vec4,
+ pub uv_offset: Vec2,
+ pub uv_size: Vec2,
}
pub struct CharAtlas {
@@ -236,12 +237,11 @@ impl CharAtlas {
height: height / self.scale_factor,
x_offset: rasterized.x_offset / self.scale_factor,
y_offset: rasterized.y_offset / self.scale_factor,
- uv: Vec4::new(
+ uv_offset: Vec2::new(
(allocated.rectangle.min.x as f32 + MARGIN as f32) / self.width,
(allocated.rectangle.min.y as f32 + MARGIN as f32) / self.height,
- width / self.width,
- height / self.height,
),
+ uv_size: Vec2::new(width / self.width, height / self.height),
};
self.registereds.push((c, scale.to_bits()), info);
}
diff --git a/src/graphics/image.rs b/src/graphics/image.rs
new file mode 100644
index 0000000..26833c0
--- /dev/null
+++ b/src/graphics/image.rs
@@ -0,0 +1,51 @@
+// TODO: このファイルは好きな設計ではないので破壊する。
+
+use super::texture::TextureWrapper;
+use png::{BitDepth, ColorType, Decoder};
+use std::io::Cursor;
+use wgpu::{Device, Queue, TextureFormat, TextureUsages};
+
+#[derive(Clone, Copy)]
+pub enum ImageId {
+ Image,
+}
+
+static IMAGE_DATAS: [&[u8]; 1] = [include_bytes!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/assets/image.png"
+))];
+
+pub fn create_textures(device: &Device, queue: &Queue) -> Vec<TextureWrapper> {
+ IMAGE_DATAS
+ .iter()
+ .map(|data| create_texture(device, queue, data))
+ .collect()
+}
+
+fn create_texture(device: &Device, queue: &Queue, data: &[u8]) -> TextureWrapper {
+ let mut reader = Decoder::new(Cursor::new(data))
+ .read_info()
+ .expect("fatal: failed to load image");
+ let mut buf = vec![
+ 0x00;
+ reader
+ .output_buffer_size()
+ .expect("fatal: image is too large")
+ ];
+ let info = reader
+ .next_frame(&mut buf)
+ .expect("fatal: failed to decode image");
+ if info.color_type != ColorType::Rgba || info.bit_depth != BitDepth::Eight {
+ panic!("fatal: image is not 8-bit RGBA");
+ }
+
+ let texture = TextureWrapper::new(
+ device,
+ info.width,
+ info.height,
+ TextureFormat::Rgba8UnormSrgb,
+ TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,
+ );
+ texture.write(queue, &buf[..info.buffer_size()]);
+ texture
+}