diff --git a/apps/demos/scenery/scenes/ingame.c b/apps/demos/scenery/scenes/ingame.c index 279ba96..027251f 100644 --- a/apps/demos/scenery/scenes/ingame.c +++ b/apps/demos/scenery/scenes/ingame.c @@ -32,7 +32,7 @@ static void process_fly_mode(State *state) { scn->looking_direction = dir_and_up.direction; const Vec3 right = m_vec_norm(m_vec_cross(dir_and_up.direction, dir_and_up.up)); - const float speed = 0.04f; /* TODO: put this in a better place */ + const float speed = 0.1f; /* TODO: put this in a better place */ if (input_action_pressed("player_left")) scn->pos = vec3_sub(scn->pos, m_vec_scale(right, speed)); diff --git a/include/twn_draw.h b/include/twn_draw.h index 3abbf1a..ac60a94 100644 --- a/include/twn_draw.h +++ b/include/twn_draw.h @@ -47,6 +47,13 @@ TWN_API void draw_line(Vec2 start, float thickness, /* optional, default: 1 */ Color color); /* optional, default: all 255 */ +/* intended for debugging and spatial reference */ +TWN_API void draw_line_3d(Vec3 start, + Vec3 finish, + float thickness, /* optional, default: 1 */ + Color color); /* optional, default: all 255 */ + + /* TODO: combine with draw_rectangle()? */ TWN_API void draw_box(Rect rect, float thickness, /* optional, default: 1 */ diff --git a/src/rendering/twn_draw.c b/src/rendering/twn_draw.c index 0712206..27650d0 100644 --- a/src/rendering/twn_draw.c +++ b/src/rendering/twn_draw.c @@ -56,6 +56,9 @@ void render_clear(void) { for (size_t i = 0; i < hmlenu(ctx.quad_batches); ++i) arrsetlen(ctx.quad_batches[i].value.primitives, 0); + + for (size_t i = 0; i < hmlenu(ctx.line_batches); ++i) + arrsetlen(ctx.line_batches[i].value.vertices, 0); } @@ -328,7 +331,7 @@ static void render_2d(void) { render_circle(&invocation.primitive->circle); break; case PRIMITIVE_2D_LINES: - render_lines(&invocation.primitive->line); + render_lines(&invocation.primitive->line, false); stbds_arrfreef(invocation.primitive->line.vertices); break; case PRIMITIVE_2D_TEXT: @@ -361,7 +364,7 @@ static void render_2d(void) { render_text(&invocation.primitive->text); break; case PRIMITIVE_2D_LINES: - render_lines(&invocation.primitive->line); + render_lines(&invocation.primitive->line, false); break; default: SDL_assert(false); @@ -388,6 +391,9 @@ static void render_space(void) { for (size_t i = 0; i < hmlenu(ctx.billboard_batches); ++i) finally_draw_billboard_batch(&ctx.billboard_batches[i].value, ctx.billboard_batches[i].key); + for (size_t i = 0; i < hmlenu(ctx.line_batches); ++i) + render_lines(&ctx.line_batches[i].value, true); + render_skybox(); /* after everything else, as to use depth buffer for early z rejection */ } diff --git a/src/rendering/twn_draw_c.h b/src/rendering/twn_draw_c.h index 988012a..4ce0af1 100644 --- a/src/rendering/twn_draw_c.h +++ b/src/rendering/twn_draw_c.h @@ -322,7 +322,7 @@ IndexBuffer get_circle_element_buffer(void); void render_circle(const CirclePrimitive *circle); -void render_lines(const LinePrimitive *line); +void render_lines(const LinePrimitive *line, bool is_3d); void render_rectangle(const RectPrimitive *rectangle); diff --git a/src/rendering/twn_lines.c b/src/rendering/twn_lines.c index 08eed66..20a71d2 100644 --- a/src/rendering/twn_lines.c +++ b/src/rendering/twn_lines.c @@ -14,6 +14,11 @@ void draw_line(Vec2 start, 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 }; @@ -46,7 +51,36 @@ void draw_line(Vec2 start, } -void render_lines(LinePrimitive const *line) { +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(); @@ -71,7 +105,9 @@ void render_lines(LinePrimitive const *line) { command.primitive_count = (uint32_t)arrlenu(line->vertices); command.geometry_mode = DEFERRED_COMMAND_DRAW_GEOMETRY_MODE_LINES; - command.pipeline = PIPELINE_2D; + 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; diff --git a/src/twn_engine_context_c.h b/src/twn_engine_context_c.h index b2960b2..38389e9 100644 --- a/src/twn_engine_context_c.h +++ b/src/twn_engine_context_c.h @@ -50,6 +50,13 @@ typedef struct EngineContext { MeshBatchItem *uncolored_mesh_batches; MeshBatchItem *billboard_batches; MeshBatchItem *quad_batches; + struct LineBatchItem { + struct LineBatchItemKey { + Color color; + uint8_t thickness; + } key; + struct LinePrimitive value; + } *line_batches; TextCache text_cache; TextureCache texture_cache;