#include "twn_draw_c.h" #include "twn_draw.h" #include "twn_engine_context_c.h" #include "twn_util.h" #include /* TODO: Support thickness */ void draw_line(Vec2 start, Vec2 finish, float thickness, Color color) { if (fabsf(1.0f - thickness) >= 0.00001f) log_warn("Thickness isn't yet implemented for line drawing (got %f)", (double)thickness); if (thickness < 1.0f) { log_warn("Invalid thickness given."); return; } struct LineVertex const v0 = { .position = (Vec3){start.x, start.y, 0}, .color = color }; struct LineVertex const v1 = { .position = (Vec3){finish.x, finish.y, 0}, .color = color }; /* combine with existing position if it's compatible */ if (arrlenu(ctx.render_queue_2d) != 0) { Primitive2D *const primitive = &ctx.render_queue_2d[arrlenu(ctx.render_queue_2d) - 1]; if (primitive->type == PRIMITIVE_2D_LINES && fabsf(primitive->line.thickness - thickness) < 0.00001f && primitive->line.color.a == color.a && primitive->line.color.b == color.b && primitive->line.color.r == color.r && primitive->line.color.g == color.g) { arrput(primitive->line.vertices, v0); arrput(primitive->line.vertices, v1); return; } } LinePrimitive line = { .thickness = thickness, .color = color, }; Primitive2D primitive = { .type = PRIMITIVE_2D_LINES, .line = line, }; arrput(primitive.line.vertices, v0); arrput(primitive.line.vertices, v1); arrput(ctx.render_queue_2d, primitive); } void draw_line_3d(Vec3 start, Vec3 finish, float thickness, Color color) { if (fabsf(1.0f - thickness) >= 0.00001f) log_warn("Thickness isn't yet implemented for line drawing (got %f)", (double)thickness); if (thickness < 1.0f) { log_warn("Invalid thickness given."); return; } struct LineVertex const v0 = { .position = start, .color = color }; struct LineVertex const v1 = { .position = finish, .color = color }; /* 3d case, unordered depth based draw */ struct LineBatchItemKey const key = { .color = color, .thickness = (uint8_t)(floorf(thickness)) }; struct LineBatchItem *batch_p = hmgetp_null(ctx.line_batches, key); if (!batch_p) { hmput(ctx.line_batches, key, ((struct LinePrimitive){.thickness = thickness, .color = color})); batch_p = &ctx.line_batches[hmlenu(ctx.line_batches) - 1]; } arrput(batch_p->value.vertices, v0); arrput(batch_p->value.vertices, v1); return; } void render_lines(LinePrimitive const *line, bool is_3d) { DeferredCommandDraw command = {0}; VertexBuffer buffer = get_scratch_vertex_array(); specify_vertex_buffer(buffer, line->vertices, arrlenu(line->vertices) * sizeof (*line->vertices)); command.vertices = (AttributeArrayPointer) { .arity = 3, .type = TWN_FLOAT, .stride = sizeof (struct LineVertex), .offset = offsetof (struct LineVertex, position), .buffer = buffer }; command.colors = (AttributeArrayPointer) { .arity = 4, .type = TWN_UNSIGNED_BYTE, .stride = sizeof (struct LineVertex), .offset = offsetof (struct LineVertex, color), .buffer = buffer }; command.primitive_count = (uint32_t)arrlenu(line->vertices); command.geometry_mode = DEFERRED_COMMAND_DRAW_GEOMETRY_MODE_LINES; command.pipeline = is_3d ? PIPELINE_SPACE : PIPELINE_2D; command.texture_mode = line->color.a == 255 ? TEXTURE_MODE_OPAQUE : TEXTURE_MODE_GHOSTLY; command.depth_range_high = depth_range_high; command.depth_range_low = depth_range_low; DeferredCommand final_command = { .type = DEFERRED_COMMAND_TYPE_DRAW, .draw = command }; arrpush(deferred_commands, final_command); }