diff --git a/apps/tools/twndel/data/bong.ogg b/apps/tools/twndel/data/bong.ogg index 491187a..867e8cc 100644 --- a/apps/tools/twndel/data/bong.ogg +++ b/apps/tools/twndel/data/bong.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d21d0f0b782445db579d11e2506b24cd1ac9d664ee33aeaf807761aa7b6fd710 -size 4848 +oid sha256:d5a728e246088087dce9c01c8f9fd03775196d79c2811dacdd3fe1dac9ab9f2b +size 7932 diff --git a/apps/tools/twndel/state.h b/apps/tools/twndel/state.h index 1acf518..fbe224f 100644 --- a/apps/tools/twndel/state.h +++ b/apps/tools/twndel/state.h @@ -78,6 +78,10 @@ typedef struct State { Object *objects; uint8_t objects_sz; + + /* which axes are blocked and which are not */ + /* order: x, y, z */ + bool axis_mask[3]; } State; diff --git a/apps/tools/twndel/tool.c b/apps/tools/twndel/tool.c index 42b9914..e43c6a3 100644 --- a/apps/tools/twndel/tool.c +++ b/apps/tools/twndel/tool.c @@ -247,13 +247,53 @@ static void process_operation_move_point(Operation *op) { /* TODO: show thresholds */ /* change along axes, delta is accumulated when threshold is met*/ - int16_t zch = (int16_t)(floorf(vec3_dot(b, (Vec3){0,0,1}) * (float)POINTS_PER_METER)); - op->data.move_point.delta_x += zch; - state.points[op->data.move_point.point].x += zch; + int16_t xch = (int16_t)(floorf(vec3_dot(b, (Vec3){0,0,1}) * (float)POINTS_PER_METER)) * !state.axis_mask[0]; + xch -= xch % state.grid_snap_granularity; + state.points[op->data.move_point.point].x += xch; + op->data.move_point.delta_x += xch; + + int16_t ych = (int16_t)(floorf(vec3_dot(b, (Vec3){0,-1,0}) * (float)POINTS_PER_METER)) * !state.axis_mask[1]; + ych -= ych % state.grid_snap_granularity; + state.points[op->data.move_point.point].y += ych; + op->data.move_point.delta_y += ych; + + int16_t zch = (int16_t)(floorf(vec3_dot(b, (Vec3){-1,0,0}) * (float)POINTS_PER_METER)) * !state.axis_mask[2]; + zch -= zch % state.grid_snap_granularity; + state.points[op->data.move_point.point].z += zch; + op->data.move_point.delta_z += zch; + + if (xch != 0 || ych != 0 || zch != 0) + audio_play("/data/bong.ogg", NULL, false, 0.12f, 0.0f); +} + + +static void reverse_operation_move_point(Operation *op) { + SDL_assert(op->kind == OPERATION_MOVE_POINT); + state.points[op->data.move_point.point].x -= op->data.move_point.delta_x; + state.points[op->data.move_point.point].y -= op->data.move_point.delta_y; + state.points[op->data.move_point.point].z -= op->data.move_point.delta_z; + audio_play("/data/drop.ogg", NULL, false, 0.4f, 0.0f); } static void process_operations(void) { + if (input_action_just_pressed("undo")) { + /* TODO: checks and defined limit */ + Operation *op = &state.op_stack[state.op_stack_ptr % UNDO_STACK_SIZE]; + state.op_stack_ptr--; + + switch (op->kind) { + case OPERATION_MOVE_POINT: { + reverse_operation_move_point(op); + + break; + } + + default: + (void)0; + } + } + if (!state.op_active) { uint16_t point_select; uint8_t obj_select; if (find_closest_point(&obj_select, &point_select)) { @@ -280,6 +320,7 @@ static void process_operations(void) { break; } + default: (void)0; } @@ -294,13 +335,20 @@ void game_tick(void) { state.camera_position = (Vec3){2,1,2}; state.camera_direction = vec3_norm(((Vec3){-2,-1,-2})); state.camera_zoom = 0.5f; + state.grid_snap_granularity = 16; + state.axis_mask[1] = 1; state.axis_mask[2] = 1; init = true; } input_action("toggle_display_mode", "Q"); input_action("toggle_projection", "E"); + input_action("toggle_x_axis", "Z"); + input_action("toggle_y_axis", "X"); + input_action("toggle_z_axis", "C"); + input_action("select", "LCLICK"); + input_action("undo", "F"); if (input_action_just_pressed("toggle_display_mode")) { audio_play("/data/click.wav", NULL, false, 0.7f, 0.0f); @@ -312,32 +360,46 @@ void game_tick(void) { state.camera_is_orthographic = !state.camera_is_orthographic; } + if (input_action_just_pressed("toggle_x_axis")) { + state.axis_mask[0] = 0; state.axis_mask[1] = 1; state.axis_mask[2] = 1; + } + + if (input_action_just_pressed("toggle_y_axis")) { + state.axis_mask[0] = 1; state.axis_mask[1] = 0; state.axis_mask[2] = 1; + } + + if (input_action_just_pressed("toggle_z_axis")) { + state.axis_mask[0] = 1; state.axis_mask[1] = 1; state.axis_mask[2] = 0; + } + process_camera_movement(); process_operations(); /* axis helpers */ /* idea: black out inactives when dragging points */ /* idea: double selection of axes for diagonal edits */ - draw_line_3d((Vec3){0}, (Vec3){0,0,256}, 1, (Color){255,0,0,125}); + draw_line_3d((Vec3){0}, (Vec3){256,0,0}, 1, state.axis_mask[0] ? (Color){0,0,0,75} : (Color){255,0,0,125}); draw_billboard("/data/x.png", - (Vec3){0,0,2}, - (Vec2){0.1f, 0.1f}, - (Rect){0}, - (Color){255,0,0,255}, - false); - draw_line_3d((Vec3){0}, (Vec3){256,0,0}, 1, (Color){0,0,255,125}); - draw_billboard("/data/y.png", (Vec3){2,0,0}, (Vec2){0.1f, 0.1f}, (Rect){0}, - (Color){0,0,255,255}, + state.axis_mask[0] ? (Color){0,0,0,255} : (Color){255,0,0,255}, false); - draw_line_3d((Vec3){0}, (Vec3){0,256,0}, 1, (Color){75,125,25,125}); - draw_billboard("/data/z.png", + + draw_line_3d((Vec3){0}, (Vec3){0,256,0}, 1, state.axis_mask[1] ? (Color){0,0,0,75} : (Color){75,125,25,125}); + draw_billboard("/data/y.png", (Vec3){0,1.5f,0}, (Vec2){0.1f, 0.1f}, (Rect){0}, - (Color){75,125,25,255}, + state.axis_mask[1] ? (Color){0,0,0,255} : (Color){75,125,25,255}, + false); + + draw_line_3d((Vec3){0}, (Vec3){0,0,256}, 1, state.axis_mask[2] ? (Color){0,0,0,75} : (Color){0,0,255,125}); + draw_billboard("/data/z.png", + (Vec3){0,0,2}, + (Vec2){0.1f, 0.1f}, + (Rect){0}, + state.axis_mask[2] ? (Color){0,0,0,255} : (Color){0,0,255,255}, false); for (uint8_t obj = 0; obj < state.objects_sz; ++obj) diff --git a/include/twn_audio.h b/include/twn_audio.h index f6304a0..37deabf 100644 --- a/include/twn_audio.h +++ b/include/twn_audio.h @@ -8,6 +8,7 @@ /* plays audio file at specified channel or at scratch channel if NULL is passed, without ability to refer to it later */ /* path path must contain valid file extension to infer which file format it is */ /* supported formats: .ogg, .xm */ +/* mono or stereo only */ TWN_API void audio_play(const char *audio, const char *channel, /* optional */ bool repeat, /* default: false */ diff --git a/src/twn_audio.c b/src/twn_audio.c index 0bd3bfb..e4c599c 100644 --- a/src/twn_audio.c +++ b/src/twn_audio.c @@ -9,6 +9,9 @@ #include #include +#define STB_VORBIS_MAX_CHANNELS 2 +#define STB_VORBIS_NO_STDIO +#define STB_VORBIS_NO_INTEGER_CONVERSION #define STB_VORBIS_NO_PUSHDATA_API #define STB_VORBIS_HEADER_ONLY #include