114 lines
4.3 KiB
Zig
114 lines
4.3 KiB
Zig
const std = @import("std");
|
|
const mach = @import("../main.zig");
|
|
const gpu = mach.gpu;
|
|
const gfx = mach.gfx;
|
|
const Engine = mach.Engine;
|
|
|
|
const math = mach.math;
|
|
const vec2 = math.vec2;
|
|
const Vec2 = math.Vec2;
|
|
const Vec3 = math.Vec3;
|
|
const Mat3x3 = math.Mat3x3;
|
|
const Mat4x4 = math.Mat4x4;
|
|
|
|
pub const name = .mach_gfx_sprite;
|
|
pub const Mod = mach.Mod(@This());
|
|
|
|
pub const components = .{
|
|
.transform = .{ .type = Mat4x4, .description =
|
|
\\ The sprite model transformation matrix. A sprite is measured in pixel units, starting from
|
|
\\ (0, 0) at the top-left corner and extending to the size of the sprite. By default, the world
|
|
\\ origin (0, 0) lives at the center of the window.
|
|
\\
|
|
\\ Example: in a 500px by 500px window, a sprite located at (0, 0) with size (250, 250) will
|
|
\\ cover the top-right hand corner of the window.
|
|
},
|
|
|
|
.uv_transform = .{ .type = Mat3x3, .description =
|
|
\\ UV coordinate transformation matrix describing top-left corner / origin of sprite, in pixels.
|
|
},
|
|
|
|
.size = .{ .type = Vec2, .description =
|
|
\\ The size of the sprite, in pixels.
|
|
},
|
|
|
|
.pipeline = .{ .type = mach.EntityID, .description =
|
|
\\ Which render pipeline to use for rendering the sprite.
|
|
\\
|
|
\\ This determines which shader, textures, etc. are used for rendering the sprite.
|
|
},
|
|
};
|
|
|
|
pub const local_events = .{
|
|
.update = .{ .handler = update },
|
|
};
|
|
|
|
fn update(core: *mach.Core.Mod, sprite: *Mod, sprite_pipeline: *gfx.SpritePipeline.Mod) !void {
|
|
var archetypes_iter = sprite_pipeline.entities.query(.{ .all = &.{
|
|
.{ .mach_gfx_sprite_pipeline = &.{
|
|
.built,
|
|
} },
|
|
} });
|
|
while (archetypes_iter.next()) |archetype| {
|
|
const ids = archetype.slice(.entity, .id);
|
|
const built_pipelines = archetype.slice(.mach_gfx_sprite_pipeline, .built);
|
|
for (ids, built_pipelines) |pipeline_id, *built| {
|
|
try updatePipeline(core, sprite, sprite_pipeline, pipeline_id, built);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn updatePipeline(
|
|
core: *mach.Core.Mod,
|
|
sprite: *Mod,
|
|
sprite_pipeline: *gfx.SpritePipeline.Mod,
|
|
pipeline_id: mach.EntityID,
|
|
built: *gfx.SpritePipeline.BuiltPipeline,
|
|
) !void {
|
|
const device = core.state().device;
|
|
const encoder = device.createCommandEncoder(null);
|
|
defer encoder.release();
|
|
|
|
var archetypes_iter = sprite.entities.query(.{ .all = &.{
|
|
.{ .mach_gfx_sprite = &.{
|
|
.uv_transform,
|
|
.transform,
|
|
.size,
|
|
.pipeline,
|
|
} },
|
|
} });
|
|
var num_sprites: u32 = 0;
|
|
var i: usize = 0;
|
|
while (archetypes_iter.next()) |archetype| {
|
|
const transforms = archetype.slice(.mach_gfx_sprite, .transform);
|
|
const uv_transforms = archetype.slice(.mach_gfx_sprite, .uv_transform);
|
|
const sizes = archetype.slice(.mach_gfx_sprite, .size);
|
|
const pipelines = archetype.slice(.mach_gfx_sprite, .pipeline);
|
|
|
|
// TODO: currently we cannot query all sprites which have a _single_ pipeline component
|
|
// value and get back contiguous memory for all of them. This is because all sprites with
|
|
// possibly different pipeline component values are stored as the same archetype. If we
|
|
// introduce a new concept of tagging-by-value to our entity storage then we can enforce
|
|
// that all entities with the same pipeline value are stored in contiguous memory, and
|
|
// skip this copy.
|
|
for (transforms, uv_transforms, sizes, pipelines) |transform, uv_transform, size, sprite_pipeline_id| {
|
|
if (sprite_pipeline_id == pipeline_id) {
|
|
gfx.SpritePipeline.cp_transforms[i] = transform;
|
|
gfx.SpritePipeline.cp_uv_transforms[i] = uv_transform;
|
|
gfx.SpritePipeline.cp_sizes[i] = size;
|
|
i += 1;
|
|
num_sprites += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
try sprite_pipeline.set(pipeline_id, .num_sprites, num_sprites);
|
|
if (num_sprites > 0) {
|
|
encoder.writeBuffer(built.transforms, 0, gfx.SpritePipeline.cp_transforms[0..i]);
|
|
encoder.writeBuffer(built.uv_transforms, 0, gfx.SpritePipeline.cp_uv_transforms[0..i]);
|
|
encoder.writeBuffer(built.sizes, 0, gfx.SpritePipeline.cp_sizes[0..i]);
|
|
var command = encoder.finish(null);
|
|
defer command.release();
|
|
core.state().queue.submit(&[_]*gpu.CommandBuffer{command});
|
|
}
|
|
}
|