prosperon/source/engine/debug/debugdraw.c
2024-03-13 16:30:55 -05:00

624 lines
15 KiB
C

#include "debugdraw.h"
#include "render.h"
#include "yugine.h"
#include "log.h"
#include <assert.h>
#include "debug.h"
#include "window.h"
#include "2dphysics.h"
#include "stb_ds.h"
#include "sokol/sokol_gfx.h"
#include "point.sglsl.h"
#include "poly.sglsl.h"
#include "circle.sglsl.h"
#include "line.sglsl.h"
#include "grid.sglsl.h"
#define PAR_STREAMLINES_IMPLEMENTATION
#include "par/par_streamlines.h"
#include "font.h"
#define v_amt 5000
struct flush {
sg_shader shader;
sg_pipeline pipe;
sg_bindings bind;
void *verts;
int c;
int v;
int sc;
int sv;
};
typedef struct flush flush;
static flush fpoint;
static flush circle;
void flushview(flush *f, HMM_Mat4 *view)
{
sg_apply_pipeline(f->pipe);
sg_apply_bindings(&f->bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*view));
sg_draw(f->sc, f->c, 1);
}
void flushpass(flush *f)
{
f->sc = f->c;
f->c = 0;
f->sv = f->v;
f->v = 0;
}
static sg_shader point_shader;
static sg_pipeline point_pipe;
static sg_bindings point_bind;
struct point_vertex {
struct draw_p pos;
struct rgba color;
float radius;
};
static int point_c = 0;
static int point_sc = 0;
static sg_shader line_shader;
static sg_pipeline line_pipe;
static sg_bindings line_bind;
struct line_vert {
struct draw_p pos;
float dist;
struct rgba color;
float seg_len;
float seg_speed;
};
static int line_c = 0;
static int line_v = 0;
static int line_sc = 0;
static int line_sv = 0;
static sg_pipeline grid_pipe;
static sg_bindings grid_bind;
static sg_shader grid_shader;
static int grid_c = 0;
static sg_pipeline poly_pipe;
static sg_bindings poly_bind;
static sg_shader poly_shader;
static int poly_c = 0;
static int poly_v = 0;
static int poly_sc = 0;
static int poly_sv = 0;
struct poly_vertex {
struct draw_p pos;
float uv[2];
struct rgba color;
};
static sg_pipeline circle_pipe;
static sg_bindings circle_bind;
static sg_shader csg;
static int circle_count = 0;
static int circle_sc = 0;
struct circle_vertex {
struct draw_p pos;
float radius;
struct rgba color;
float segsize;
float fill;
};
/* Writes debug data to buffers, and draws */
void debug_flush(HMM_Mat4 *view)
{
if (poly_c != 0) {
sg_apply_pipeline(poly_pipe);
sg_apply_bindings(&poly_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(*view));
sg_draw(poly_sc,poly_c,1);
}
if (point_c != 0) {
sg_apply_pipeline(point_pipe);
sg_apply_bindings(&point_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(*view));
sg_draw(point_sc,point_c,1);
}
if (line_c != 0) {
sg_apply_pipeline(line_pipe);
sg_apply_bindings(&line_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(*view));
lfs_params_t lt;
lt.time = apptime();
sg_apply_uniforms(SG_SHADERSTAGE_FS,0,SG_RANGE_REF(lt));
sg_draw(line_sc,line_c,1);
}
if (circle_count != 0) {
sg_apply_pipeline(circle_pipe);
sg_apply_bindings(&circle_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*view));
sg_draw(circle_sc,4,circle_count);
}
}
void debug_nextpass()
{
point_sc = point_c;
point_c = 0;
circle_sc = circle_count;
circle_count = 0;
line_sv = line_v;
line_v = 0;
line_sc = line_c;
line_c = 0;
poly_sc = poly_c;
poly_c = 0;
poly_sv = poly_v;
poly_v = 0;
}
void debug_newframe()
{
point_sc = 0;
point_c = 0;
circle_sc = circle_count = line_sv = line_v = line_sc = line_c = poly_sc = poly_c = 0;
poly_sv = poly_v = 0;
}
static sg_shader_uniform_block_desc projection_ubo = {
.size = sizeof(projection),
.uniforms = {
[0] = { .name = "proj", .type = SG_UNIFORMTYPE_MAT4 },
}
};
static sg_shader_uniform_block_desc time_ubo = {
.size = sizeof(float),
.uniforms = {
[0] = { .name = "time", .type = SG_UNIFORMTYPE_FLOAT },
}
};
void debugdraw_init()
{
point_shader = sg_make_shader(point_shader_desc(sg_query_backend()));
point_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = point_shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2, /* pos */
[1].format = SG_VERTEXFORMAT_UBYTE4N, /* color */
[2].format = SG_VERTEXFORMAT_FLOAT /* radius */
}
},
.primitive_type = SG_PRIMITIVETYPE_POINTS,
.colors[0].blend = blend_trans,
.label = "dbg point",
});
point_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct point_vertex)*v_amt,
.usage = SG_USAGE_STREAM
});
line_shader = sg_make_shader(line_shader_desc(sg_query_backend()));
line_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = line_shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2, /* pos */
[1].format = SG_VERTEXFORMAT_FLOAT, /* dist */
[2].format = SG_VERTEXFORMAT_UBYTE4N, /* color */
[3].format = SG_VERTEXFORMAT_FLOAT, /* seg length */
[4].format = SG_VERTEXFORMAT_FLOAT /* dashed line speed */
}
},
.primitive_type = SG_PRIMITIVETYPE_LINES,
.index_type = SG_INDEXTYPE_UINT16,
.colors[0].blend = blend_trans,
.label = "dbg line",
});
line_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct line_vert)*v_amt,
.usage = SG_USAGE_STREAM
});
line_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(uint16_t)*v_amt,
.usage = SG_USAGE_STREAM,
.type = SG_BUFFERTYPE_INDEXBUFFER
});
csg = sg_make_shader(circle_shader_desc(sg_query_backend()));
circle_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = csg,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2,
[0].buffer_index = 1,
[1].format = SG_VERTEXFORMAT_FLOAT2,
[2].format = SG_VERTEXFORMAT_FLOAT,
[3].format = SG_VERTEXFORMAT_UBYTE4N,
[4].format = SG_VERTEXFORMAT_FLOAT,
[5].format = SG_VERTEXFORMAT_FLOAT
},
.buffers[0].step_func = SG_VERTEXSTEP_PER_INSTANCE,
},
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
.cull_mode = SG_CULLMODE_BACK,
.colors[0].blend = blend_trans,
.label = "circle pipeline"
});
circle_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct circle_vertex)*v_amt,
.usage = SG_USAGE_STREAM,
});
float circleverts[8] = {
-1,-1,
-1,1,
1,-1,
1,1
};
circle_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
.data = (sg_range){.ptr = circleverts, .size = sizeof(float)*8},
.usage = SG_USAGE_IMMUTABLE,
});
grid_shader = sg_make_shader(grid_shader_desc(sg_query_backend()));
grid_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = grid_shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2, /* pos */
}
},
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
.cull_mode = SG_CULLMODE_BACK,
.label = "grid pipeline",
.colors[0].blend = blend_trans,
});
grid_bind.vertex_buffers[0] = circle_bind.vertex_buffers[1];
poly_shader = sg_make_shader(poly_shader_desc(sg_query_backend()));
poly_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = poly_shader,
.layout = {
.attrs = { [0].format = SG_VERTEXFORMAT_FLOAT2, /* pos */
[1].format = SG_VERTEXFORMAT_FLOAT2, /* uv */
[2].format = SG_VERTEXFORMAT_UBYTE4N /* color rgba */
}
},
.index_type = SG_INDEXTYPE_UINT32,
.colors[0].blend = blend_trans,
// .cull_mode = SG_CULLMODE_FRONT,
.label = "dbg poly",
});
poly_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct poly_vertex)*v_amt,
.usage = SG_USAGE_STREAM,
.type = SG_BUFFERTYPE_VERTEXBUFFER,
});
poly_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(uint32_t)*6*v_amt,
.usage = SG_USAGE_STREAM,
.type = SG_BUFFERTYPE_INDEXBUFFER
});
}
void draw_line(HMM_Vec2 *points, int n, struct rgba color, float seg_len, float seg_speed)
{
if (n < 2) return;
seg_speed = 1;
struct line_vert v[n];
float dist = 0;
for (int i = 0; i < n; i++) {
v[i].pos.x = points[i].x;
v[i].pos.y = points[i].y;
v[i].color = color;
v[i].seg_len = seg_len;
v[i].seg_speed = seg_speed;
}
v[0].dist = 0;
for (int i = 1; i < n; i++) {
dist += HMM_DistV2(points[i-1], points[i]);
v[i].dist = dist;
}
int i_c = (n-1)*2;
uint16_t idxs[i_c];
for (int i = 0, d = 0; i < n-1; i++, d+=2) {
idxs[d] = i + line_v + line_sv;
idxs[d+1] = idxs[d]+1;
}
sg_range vr = {
.ptr = v,
.size = sizeof(struct line_vert)*n
};
sg_range ir = {
.ptr = idxs,
.size = sizeof(uint16_t)*i_c
};
sg_append_buffer(line_bind.vertex_buffers[0], &vr);
sg_append_buffer(line_bind.index_buffer, &ir);
line_c += i_c;
line_v += n;
}
HMM_Vec2 center_of_vects(HMM_Vec2 *v, int n)
{
HMM_Vec2 c;
for (int i = 0; i < n; i++) {
c.x += v[i].x;
c.y += v[i].y;
}
c.x /= n;
c.y /= n;
return c;
}
/* Given a series of points p, computes a new series with them expanded on either side by d */
HMM_Vec2 *inflatepoints(HMM_Vec2 *p, float d, int n)
{
if (d == 0) {
HMM_Vec2 *ret = NULL;
arraddn(ret,n);
for (int i = 0; i < n; i++)
ret[i] = p[i];
return ret;
}
parsl_position par_v[n];
uint16_t spine_lens[] = {n};
for (int i = 0; i < n; i++) {
par_v[i].x = p[i].x;
par_v[i].y = p[i].y;
};
parsl_context *par_ctx = parsl_create_context((parsl_config){
.thickness = d,
.flags= PARSL_FLAG_ANNOTATIONS,
.u_mode = PAR_U_MODE_DISTANCE
});
parsl_mesh *mesh = parsl_mesh_from_lines(par_ctx, (parsl_spine_list){
.num_vertices = n,
.num_spines = 1,
.vertices = par_v,
.spine_lengths = spine_lens,
.closed = 0,
});
HMM_Vec2 *ret = NULL;
arraddn(ret,mesh->num_vertices);
for (int i = 0; i < mesh->num_vertices; i++) {
ret[i].x = mesh->positions[i].x;
ret[i].y = mesh->positions[i].y;
};
return ret;
}
/* Given a strip of points, draws them as segments. So 5 points is 4 segments, and ultimately 8 vertices */
void draw_edge(HMM_Vec2 *points, int n, struct rgba color, int thickness, int flags, struct rgba line_color, float line_seg)
{
int closed = 0;
if (thickness <= 1) {
draw_line(points,n,line_color,0,0);
return;
}
/* todo: should be dashed, and filled. use a texture. */
/* draw polygon outline */
if (HMM_EqV2(points[0], points[n-1])) {
closed = true;
n--;
}
parsl_position par_v[n];
for (int i = 0; i < n; i++) {
par_v[i].x = points[i].x;
par_v[i].y = points[i].y;
}
uint16_t spine_lens[] = {n};
parsl_context *par_ctx = parsl_create_context((parsl_config){
.thickness = thickness,
.flags = PARSL_FLAG_ANNOTATIONS,
});
parsl_mesh *mesh = parsl_mesh_from_lines(par_ctx, (parsl_spine_list){
.num_vertices = n,
.num_spines = 1,
.vertices = par_v,
.spine_lengths = spine_lens,
.closed = closed
});
for (int i = 0; i < mesh->num_triangles*3; i++)
mesh->triangle_indices[i] += (poly_v+poly_sv);
struct poly_vertex vertices[mesh->num_vertices];
for (int i = 0; i < mesh->num_vertices; i++) {
vertices[i].pos = (struct draw_p){ .x = mesh->positions[i].x, .y = mesh->positions[i].y };
vertices[i].uv[0] = mesh->annotations[i].u_along_curve;
vertices[i].uv[1] = mesh->annotations[i].v_across_curve;
vertices[i].color = color;
}
sg_append_buffer(poly_bind.vertex_buffers[0], &(sg_range){.ptr = vertices, .size = sizeof(struct poly_vertex)*mesh->num_vertices});
sg_append_buffer(poly_bind.index_buffer, &(sg_range){.ptr = mesh->triangle_indices, sizeof(uint32_t)*mesh->num_triangles*3});
poly_c += mesh->num_triangles*3;
poly_v += mesh->num_vertices;
parsl_destroy_context(par_ctx);
/* Now drawing the line outlines */
if (thickness == 1) {
draw_line(points,n,line_color,line_seg, 0);
} else {
HMM_Vec2 in_p[n];
HMM_Vec2 out_p[n];
for (int i = 1, v = 0; i < n*2+1; i+=2, v++) {
in_p[v].x = vertices[i].pos.x;
in_p[v].y = vertices[i].pos.y;
}
for (int i = 0, v = 0; i < n*2; i+=2,v++) {
out_p[v].x = vertices[i].pos.x;
out_p[v].y = vertices[i].pos.y;
}
if (!closed) {
HMM_Vec2 p[n*2];
for (int i = 0; i < n; i++)
p[i] = in_p[i];
for (int i = n-1, v = n; i >= 0; i--,v++)
p[v] = out_p[i];
draw_line(p,n*2,line_color,line_seg,0);
return;
}
draw_line(in_p,n,line_color,line_seg,0);
draw_line(out_p,n,line_color,line_seg,0);
}
}
void draw_circle(HMM_Vec2 pos, float radius, float pixels, struct rgba color, float seg)
{
struct circle_vertex cv;
cv.pos.x = pos.x;
cv.pos.y = pos.y;
cv.radius = radius;
cv.color = color;
cv.segsize = seg/radius;
cv.fill = pixels/radius;
sg_append_buffer(circle_bind.vertex_buffers[0], &(sg_range){.ptr = &cv, .size = sizeof(struct circle_vertex)});
circle_count++;
}
void draw_box(HMM_Vec2 c, HMM_Vec2 wh, struct rgba color)
{
float hw = wh.x / 2.f;
float hh = wh.y / 2.f;
HMM_Vec2 verts[4] = {
{ .x = c.x-hw, .y = c.y-hh },
{ .x = c.x+hw, .y = c.y-hh },
{ .x = c.x+hw, .y = c.y+hh },
{ .x = c.x-hw, .y = c.y+hh }
};
draw_poly(verts, 4, color);
}
void draw_grid(float width, float span, struct rgba color)
{
HMM_Vec2 offset = (HMM_Vec2)cam_pos();
offset = HMM_MulV2F(offset, 1/cam_zoom());
float ubo[4];
ubo[0] = offset.x;
ubo[1] = offset.y;
ubo[2] = mainwin.size.x;
ubo[3] = mainwin.size.y;
sg_apply_pipeline(grid_pipe);
sg_apply_bindings(&grid_bind);
float col[4];
rgba2floats(col,color);
fs_params_t pt;
pt.thickness = (float)width;
pt.span = span/cam_zoom();
memcpy(&pt.color, col, sizeof(float)*4);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(ubo));
sg_apply_uniforms(SG_SHADERSTAGE_FS, 0, SG_RANGE_REF(pt));
sg_draw(0,4,1);
}
void draw_cppoint(HMM_Vec2 point, float r, struct rgba color)
{
struct point_vertex p = {
.color = color,
.radius = r
};
p.pos.x = point.X;
p.pos.y = point.Y;
sg_append_buffer(point_bind.vertex_buffers[0], &(sg_range){.ptr = &p, .size = sizeof(struct point_vertex)});
point_c++;
}
void draw_points(HMM_Vec2 *points, int n, float size, struct rgba color)
{
for (int i = 0; i < n; i++)
draw_cppoint(points[i], size, color);
}
void draw_poly(HMM_Vec2 *points, int n, struct rgba color)
{
/* Find polygon mesh */
int tric = n - 2;
if (tric < 1) return;
uint32_t tridxs[tric*3];
for (int i = 2, ti = 0; i < n; i++, ti+=3) {
tridxs[ti] = 0;
tridxs[ti+1] = i-1;
tridxs[ti+2] = i;
}
for (int i = 0; i < tric*3; i++)
tridxs[i] += poly_v+poly_sv;
struct poly_vertex polyverts[n];
for (int i = 0; i < n; i++) {
polyverts[i].pos = (struct draw_p) { .x = points[i].x, .y = points[i].y};
polyverts[i].uv[0] = 0.0;
polyverts[i].uv[1] = 0.0;
polyverts[i].color = color;
}
sg_append_buffer(poly_bind.vertex_buffers[0], &(sg_range){.ptr = polyverts, .size = sizeof(struct poly_vertex)*n});
sg_append_buffer(poly_bind.index_buffer, &(sg_range){.ptr = tridxs, sizeof(uint32_t)*3*tric});
poly_c += tric*3;
poly_v += n;
}