diff --git a/src/app.cpp b/src/app.cpp index 54df733..63e879e 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1,9 +1,11 @@ #include "app.hpp" #include "cloth.hpp" +#include "mouse.hpp" #include "window.hpp" #include "vec.hpp" #include #include +#include #include #include #include @@ -22,6 +24,7 @@ App* app_init(App_config conf) { } app->conf = conf; + app->mouse = new_mouse(Vec2{0, 0}, 30); app->window = new_window(conf.win_name, conf.window_dimensions); app->cloth = new_cloth( conf.cloth_startpos, @@ -61,12 +64,44 @@ void app_handle_input(App* app) { case SDLK_SPACE: toggle_pause(app); break; - } + + case SDLK_LEFT: + if (app->conf.timestep >= 0.25) { + app->conf.timestep -= 0.25; + } + break; + + case SDLK_RIGHT: + app->conf.timestep += 0.25; + break; + } + + case SDL_MOUSEMOTION: + app->mouse->last_pos = app->mouse->pos; + app->mouse->pos = Vec2{ + static_cast(event.motion.x), + static_cast(event.motion.y) + }; + break; + + case SDL_MOUSEBUTTONDOWN: + if (event.button.button == SDL_BUTTON_LEFT) { + app->mouse->left_button_clicked = true; + } + break; + + case SDL_MOUSEBUTTONUP: + if (event.button.button == SDL_BUTTON_LEFT) { + app->mouse->left_button_clicked = false; + } + break; } + } } -void app_render(App* app) { +void app_render(App* app) { + SDL_RenderClear(app->window->renderer); fill_screen(app->window, app->conf.background_color); draw_cloth( app->window, app->cloth, @@ -83,16 +118,19 @@ void app_update(App* app) { int updated_window_h; SDL_GetWindowSize(app->window->sdl_win, &updated_window_w, &updated_window_h); app->window->dimensions = Vec2{(unsigned int) updated_window_w, (unsigned int) updated_window_h}; + if (app->cloth->constraint_bottom_right.x != (unsigned int) updated_window_w || app->cloth->constraint_bottom_right.y != (unsigned int) updated_window_h) { + app->cloth->constraint_bottom_right.x = app->window->dimensions.x; + app->cloth->constraint_bottom_right.y = app->window->dimensions.y-5; + } - app->cloth->constraint_bottom_right.x = app->window->dimensions.x; - app->cloth->constraint_bottom_right.y = app->window->dimensions.y-5; - cloth_step(app->cloth, app->conf.gravity, 1); - satisfy_cloth_constraints(app->cloth); + cloth_step(app->cloth, app->mouse, app->conf.gravity, app->conf.timestep); } void destroy_app(App* app) { + destroy_mouse(app->mouse); destroy_cloth(app->cloth); destroy_window(app->window); + app->mouse = NULL; app->cloth = NULL; app->window = NULL; app->is_running = false; diff --git a/src/app.hpp b/src/app.hpp index 16dfa34..8f284de 100644 --- a/src/app.hpp +++ b/src/app.hpp @@ -1,5 +1,6 @@ #pragma once +#include "mouse.hpp" #include "window.hpp" #include "cloth.hpp" #include @@ -13,6 +14,7 @@ struct App_config { Vec2f gravity; float efficiency_factor; float friction_factor; + float timestep; RGB background_color; RGB point_color; RGB point_selected_color; @@ -23,6 +25,7 @@ struct App { bool is_running; bool paused; App_config conf; + Mouse* mouse; Window* window; Cloth* cloth; }; diff --git a/src/cloth.cpp b/src/cloth.cpp index 3dc5fbd..a0fa711 100644 --- a/src/cloth.cpp +++ b/src/cloth.cpp @@ -1,5 +1,7 @@ #include "cloth.hpp" #include "connection.hpp" +#include "mouse.hpp" +#include #include #include #include @@ -26,18 +28,12 @@ Cloth* new_cloth( bool frozen_point = false; for (unsigned int y = 0; y < dimensions.y; y += spacing) { for (unsigned int x = 0; x < dimensions.x; x += spacing) { - // if (y == 0 && x == new_cloth->dimensions.x/2) { - // frozen_point = true; - // } else { - // frozen_point = false; - // } - Point* new_point = new Point{ - .x = static_cast(startpos.x + x), - .y = static_cast(startpos.y + y), + .pos = Vec2f{static_cast(startpos.x + x), static_cast(startpos.y + y)}, .mass = 10.0f, .frozen = frozen_point, .selected = false, + .radius = 2.5, }; new_cloth->points.push_back(new_point); @@ -78,58 +74,58 @@ void destroy_cloth(Cloth* cloth) { delete cloth; } -// calculate forces and actually MOVE points -void cloth_step(Cloth* cloth, Vec2f gravity_vec, float timedelta) { +// calculate forces, move points and satisfy constraints +void cloth_step(Cloth* cloth, Mouse* mouse, Vec2f gravity_vec, float timedelta) { for (Point* p : cloth->points) { if (p->frozen) { continue; } - - // calculate velocity - if (p->y == cloth->constraint_bottom_right.y) { - // if this point's x velocity is too small -> just stop it - // else -> handle friction - if (p->velocity.x <= 0.5) { - p->velocity.x = 0; - } else { - p->velocity.x = p->velocity.x*cloth->friction_factor * timedelta; - } + + // handle mouse + // ((x0 - x1)^2 + (y0 - y1)^2)^0.5 + float distance_to_point = std::sqrt(pow(p->pos.x - mouse->pos.x, 2.0f)+pow(p->pos.y - mouse->pos.y, 2.0f)); + if (distance_to_point <= mouse->cursor_radius_size) { + p->selected = true; } else { - p->velocity.x = p->velocity.x+(gravity_vec.x/p->mass) * timedelta; - p->velocity.y = p->velocity.y+(gravity_vec.y/p->mass) * timedelta; + p->selected = false; + } + + if (p->selected && mouse->left_button_clicked) { + p->pos = Vec2f{(float) mouse->pos.x, (float) mouse->pos.y}; } + // calculate velocity + p->velocity.x = (p->velocity.x + (gravity_vec.x/p->mass)) * timedelta; + p->velocity.y = (p->velocity.y + (gravity_vec.y/p->mass)) * timedelta; + // move point - p->x += p->velocity.x; - p->y += p->velocity.y; - } -} + p->pos.x += p->velocity.x; + p->pos.y += p->velocity.y; -// handle constraints, bounces -void satisfy_cloth_constraints(Cloth* cloth) { - for (Point* p : cloth->points) { + // now handle constraints // bottom - if (p->y > cloth->constraint_bottom_right.y) { - p->y = cloth->constraint_bottom_right.y; - p->velocity.y = -p->velocity.y*cloth->efficiency_factor; + if (p->pos.y >= cloth->constraint_bottom_right.y) { + p->pos.y = cloth->constraint_bottom_right.y; + p->velocity.x = (p->velocity.x * cloth->friction_factor); + p->velocity.y = -p->velocity.y * cloth->efficiency_factor; } // right - if (p->x > cloth->constraint_bottom_right.x) { - p->x = cloth->constraint_bottom_right.x; - p->velocity.x = -p->velocity.x*cloth->efficiency_factor; + if (p->pos.x >= cloth->constraint_bottom_right.x) { + p->pos.x = cloth->constraint_bottom_right.x; + p->velocity.x = -p->velocity.x * cloth->efficiency_factor; } // left - if (p->x < cloth->constraint_top_left.x) { - p->x = cloth->constraint_top_left.x; - p->velocity.x = -p->velocity.x*cloth->efficiency_factor; + if (p->pos.x <= cloth->constraint_top_left.x) { + p->pos.x = cloth->constraint_top_left.x; + p->velocity.x = -p->velocity.x * cloth->efficiency_factor; } // up - if (p->y < cloth->constraint_top_left.y) { - p->y = cloth->constraint_top_left.y; - p->velocity.y = -p->velocity.y*cloth->efficiency_factor; + if (p->pos.y <= cloth->constraint_top_left.y) { + p->pos.y = cloth->constraint_top_left.y; + p->velocity.y = -p->velocity.y * cloth->efficiency_factor; } } } \ No newline at end of file diff --git a/src/cloth.hpp b/src/cloth.hpp index 0bc4b4f..0ac1c85 100644 --- a/src/cloth.hpp +++ b/src/cloth.hpp @@ -1,5 +1,6 @@ #pragma once +#include "mouse.hpp" #include "point.hpp" #include "connection.hpp" #include "vec.hpp" @@ -25,5 +26,4 @@ Cloth* new_cloth( Vec2 constraint_top_left, Vec2 constraint_bottom_right ); void destroy_cloth(Cloth* cloth); -void cloth_step(Cloth* cloth, Vec2f gravity_vec, float timedelta); -void satisfy_cloth_constraints(Cloth* cloth); \ No newline at end of file +void cloth_step(Cloth* cloth, Mouse* mouse, Vec2f gravity_vec, float timedelta); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 27482ae..4d1e75d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,8 +68,9 @@ int main(const int argc, char** argv) { .cloth_startpos = Vec2{50, 50}, .cloth_dimensions = Vec2{400, 400}, .cloth_spacing = 20, - .gravity = Vec2f{0.65f, 0.45f}, + .gravity = Vec2f{0.5f, 0.75f}, .efficiency_factor = 0.25f, + .timestep = 1.0f, .background_color = RGB{205, 222, 242}, .point_color = RGB{2, 10, 1}, .point_selected_color = RGB{200, 40, 12}, diff --git a/src/mouse.cpp b/src/mouse.cpp new file mode 100644 index 0000000..ca1c6a5 --- /dev/null +++ b/src/mouse.cpp @@ -0,0 +1,14 @@ +#include "mouse.hpp" + +Mouse* new_mouse(Vec2 position, float cursor_size) { + return new Mouse{ + .left_button_clicked = false, + .cursor_radius_size = cursor_size, + .pos = position, + .last_pos = position, + }; +} + +void destroy_mouse(Mouse* mouse) { + delete mouse; +} \ No newline at end of file diff --git a/src/mouse.hpp b/src/mouse.hpp new file mode 100644 index 0000000..6e085e8 --- /dev/null +++ b/src/mouse.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "vec.hpp" + +struct Mouse { + bool left_button_clicked; + float cursor_radius_size; + Vec2 pos; + Vec2 last_pos; +}; + +Mouse* new_mouse(Vec2 position, float cursor_size); +void destroy_mouse(Mouse* mouse); \ No newline at end of file diff --git a/src/point.hpp b/src/point.hpp index a5dedd1..97f9098 100644 --- a/src/point.hpp +++ b/src/point.hpp @@ -4,10 +4,10 @@ #include "vec.hpp" struct Point { - float x; - float y; + Vec2f pos; float mass; bool frozen; bool selected; + float radius; Vec2f velocity; }; \ No newline at end of file diff --git a/src/window.cpp b/src/window.cpp index 564ff7e..4707f75 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -60,9 +60,15 @@ void fill_screen(Window* window, RGB color) { } void draw_point(Window* window, Point point, RGB color) { - if (window->renderer != NULL) { + if (window->renderer != NULL) { SDL_SetRenderDrawColor(window->renderer, color.r, color.g, color.b, 255); - SDL_RenderDrawPoint(window->renderer, (int) point.x, (int) point.y); + for (float angle = 0.0f; angle <= 6.283f; angle+=1.0f/point.radius ) { + SDL_RenderDrawPoint( + window->renderer, + point.pos.x+point.radius*cos(angle), + point.pos.y+point.radius*sin(angle) + ); + } } } @@ -71,10 +77,10 @@ void draw_connection(Window* window, Connection connection, RGB color) { SDL_SetRenderDrawColor(window->renderer, color.r, color.g, color.b, 255); SDL_RenderDrawLine( window->renderer, - (int) connection.p0.x, - (int) connection.p0.y, - (int) connection.p1.x, - (int) connection.p1.y + (int) connection.p0.pos.x, + (int) connection.p0.pos.y, + (int) connection.p1.pos.x, + (int) connection.p1.pos.y ); } } @@ -85,6 +91,10 @@ void draw_cloth(Window* window, Cloth* cloth, RGB point_color, RGB connection_co } for (const Point* point : cloth->points) { - draw_point(window, *point, point_color); + if (point->selected) { + draw_point(window, *point, selected_p_color); + } else { + draw_point(window, *point, point_color); + } } } \ No newline at end of file