#include "sprite_drawer.h"
#include "../asset_types/sprite.h"
#include "../libraries/array.h"
#include "../libraries/profiler.h"
#include "../hierarchy.h"
#include "../sk_math_dx.h"
#include "../sk_memory.h"
using namespace DirectX;
namespace sk {
array_t<sprite_buffer_t> sprite_buffers = {};
mesh_t sprite_quad_old;
mesh_t sprite_quad;
void sprite_drawer_add_buffer(material_t material) {
sprite_buffers.add({});
sprite_buffer_t &buffer = sprite_buffers.last();
buffer.material = material;
buffer.mesh = mesh_create();
}
void sprite_buffer_ensure_capacity(sprite_buffer_t &buffer) {
if (buffer.vert_count + 4 <= buffer.vert_cap)
return;
buffer.vert_cap = buffer.vert_count + 4;
buffer.verts = sk_realloc_t(vert_t, buffer.verts, buffer.vert_cap);
vind_t quads = (vind_t)(buffer.vert_cap / 4);
vind_t *inds = sk_malloc_t(vind_t, quads * 6);
for (vind_t i = 0; i < quads; i++) {
vind_t q = i * 4;
vind_t c = i * 6;
inds[c+0] = q+2;
inds[c+1] = q+1;
inds[c+2] = q;
inds[c+3] = q+3;
inds[c+4] = q+2;
inds[c+5] = q;
}
mesh_set_inds(buffer.mesh, inds, quads * 6);
sk_free(inds);
}
void sprite_drawer_add (sprite_t sprite, const matrix &at, color32 color) {
float width = (sprite->uvs[1].x - sprite->uvs[0].x) * sprite->size;
float height = (sprite->uvs[1].y - sprite->uvs[0].y) * sprite->size;
if (sprite->buffer_index == -1) {
render_add_mesh(sprite_quad_old, sprite->material, at, {color.r/255.f, color.g/255.f, color.b/255.f, color.a/255.f });
return;
}
sprite_buffer_t &buffer = sprite_buffers[sprite->buffer_index];
sprite_buffer_ensure_capacity(buffer);
XMMATRIX tr;
if (hierarchy_use_top()) {
matrix_mul(hierarchy_top(), at, tr);
} else {
math_matrix_to_fast(at, &tr);
}
int32_t offset = buffer.vert_count;
vec3 normal = vec3_normalize( matrix_transform_dir(at, vec3_forward) );
buffer.verts[offset + 0] = { matrix_mul_point(tr, vec3{0, 0, 0}), normal, sprite->uvs[0], color };
buffer.verts[offset + 1] = { matrix_mul_point(tr, vec3{width, 0, 0}), normal, vec2{sprite->uvs[1].x, sprite->uvs[0].y}, color };
buffer.verts[offset + 2] = { matrix_mul_point(tr, vec3{width, height, 0}), normal, sprite->uvs[1], color };
buffer.verts[offset + 3] = { matrix_mul_point(tr, vec3{0, height, 0}), normal, vec2{sprite->uvs[0].x, sprite->uvs[1].y}, color };
buffer.vert_count += 4;
}
void sprite_drawer_add_at(sprite_t sprite, matrix at, pivot_ pivot_position, color32 color) {
if (sprite->buffer_index == -1) {
vec3 offset = vec3_zero;
float aspect = sprite_get_aspect(sprite);
if (pivot_position & pivot_x_left ) offset.x = -aspect/2;
else if (pivot_position & pivot_x_right ) offset.x = aspect/2;
if (pivot_position & pivot_y_bottom) offset.y = 0.5f;
else if (pivot_position & pivot_y_top ) offset.y = -0.5f;
render_add_mesh(sprite_quad, sprite->material, matrix_ts(offset, {aspect, 1, 1}) * at, { color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f });
return;
} else {
log_err("Not implemented");
}
}
bool sprite_drawer_init() {
profiler_zone();
sprite_quad = mesh_find(default_id_mesh_quad);
sprite_quad_old = mesh_create();
vert_t verts[4] = {
{ vec3{0, 0,0}, vec3{0,0,-1}, vec2{1,0}, color32{255,255,255,255} },
{ vec3{1, 0,0}, vec3{0,0,-1}, vec2{0,0}, color32{255,255,255,255} },
{ vec3{1,-1,0}, vec3{0,0,-1}, vec2{0,1}, color32{255,255,255,255} },
{ vec3{0,-1,0}, vec3{0,0,-1}, vec2{1,1}, color32{255,255,255,255} },
};
vind_t inds[6] = { 0,1,2, 0,2,3 };
mesh_set_id (sprite_quad_old, "sk/render/sprite_quad");
mesh_set_keep_data(sprite_quad_old, false);
mesh_set_data (sprite_quad_old, verts, 4, inds, 6, false);
return true;
}
void sprite_drawer_step() {
profiler_zone();
for (int32_t i = 0; i < sprite_buffers.count; i++) {
sprite_buffer_t &buffer = sprite_buffers[i];
if (buffer.vert_count <= 0)
continue;
mesh_set_verts(buffer.mesh, buffer.verts, buffer.vert_count, false);
mesh_set_draw_inds(buffer.mesh, (buffer.vert_count / 4) * 6);
render_add_mesh(buffer.mesh, buffer.material, matrix_identity);
buffer.vert_count = 0;
}
}
void sprite_drawer_shutdown() {
mesh_release(sprite_quad);
mesh_release(sprite_quad_old);
for (int32_t i = 0; i < sprite_buffers.count; i++) {
sprite_buffer_t &buffer = sprite_buffers[i];
mesh_release(buffer.mesh);
material_release(buffer.material);
sk_free(buffer.verts);
}
sprite_buffers.clear();
}
}