diff --git a/src/app.cpp b/src/app.cpp index 42b30c7..54df733 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1,6 +1,7 @@ #include "app.hpp" #include "cloth.hpp" #include "window.hpp" +#include "vec.hpp" #include #include #include @@ -16,10 +17,20 @@ App* app_init(App_config conf) { if (conf.window_dimensions.y <= 0) { conf.window_dimensions.y = 500; } + if (conf.efficiency_factor < 0 || conf.efficiency_factor > 1) { + conf.efficiency_factor = 0.6; + } app->conf = conf; app->window = new_window(conf.win_name, conf.window_dimensions); - app->cloth = new_cloth(conf.cloth_startpos, conf.cloth_dimensions, conf.cloth_spacing); + app->cloth = new_cloth( + conf.cloth_startpos, + conf.cloth_dimensions, + conf.cloth_spacing, + conf.efficiency_factor, + conf.friction_factor, + Vec2{0, 0}, Vec2{app->window->dimensions.x-5, app->window->dimensions.y-5} + ); if (app->window == NULL || app->cloth == NULL) { return NULL; @@ -73,8 +84,10 @@ void app_update(App* app) { 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}; - compute_cloth_forces(app->cloth, app->conf.gravity); - satisfy_cloth_constraints(app->cloth, Vec2{0, 0}, Vec2{app->window->dimensions.x-5, 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); } void destroy_app(App* app) { diff --git a/src/app.hpp b/src/app.hpp index 0cf365c..16dfa34 100644 --- a/src/app.hpp +++ b/src/app.hpp @@ -11,6 +11,8 @@ struct App_config { Vec2 cloth_dimensions; unsigned int cloth_spacing; Vec2f gravity; + float efficiency_factor; + float friction_factor; RGB background_color; RGB point_color; RGB point_selected_color; diff --git a/src/cloth.cpp b/src/cloth.cpp index cdefa93..3dc5fbd 100644 --- a/src/cloth.cpp +++ b/src/cloth.cpp @@ -4,27 +4,37 @@ #include #include -Cloth* new_cloth(Vec2 startpos, Vec2 dimensions, unsigned int spacing) { +Cloth* new_cloth( + Vec2 startpos, + Vec2 dimensions, + unsigned int spacing, + float efficiency_factor, + float friction_factor, + Vec2 constraint_top_left, Vec2 constraint_bottom_right + ) { + Cloth* new_cloth = new Cloth; + new_cloth->efficiency_factor = efficiency_factor; + new_cloth->friction_factor = friction_factor; new_cloth->startpos = startpos; new_cloth->dimensions = dimensions; + new_cloth->constraint_top_left = constraint_top_left; + new_cloth->constraint_bottom_right = constraint_bottom_right; new_cloth->points = std::vector(); new_cloth->connections = std::vector(); bool frozen_point = false; - for (unsigned int y = 0; y < dimensions.y; y += spacing) { - if (y == 0) { - frozen_point = true; - } else { - 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), - .prev_x = static_cast(startpos.x + x), - .prev_y = static_cast(startpos.y + y), .mass = 10.0f, .frozen = frozen_point, .selected = false, @@ -68,37 +78,58 @@ void destroy_cloth(Cloth* cloth) { delete cloth; } -void compute_cloth_forces(Cloth* cloth, Vec2f gravity_vec) { +// calculate forces and actually MOVE points +void cloth_step(Cloth* cloth, Vec2f gravity_vec, float timedelta) { for (Point* p : cloth->points) { if (p->frozen) { continue; } - p->x += gravity_vec.x; - p->y += gravity_vec.y; + + // 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; + } + } 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; + } + + // move point + p->x += p->velocity.x; + p->y += p->velocity.y; } } - -void satisfy_cloth_constraints(Cloth* cloth, Vec2 top_left, Vec2 bottom_right) { +// handle constraints, bounces +void satisfy_cloth_constraints(Cloth* cloth) { for (Point* p : cloth->points) { // bottom - if (p->y > bottom_right.y) { - p->y = bottom_right.y; + if (p->y > cloth->constraint_bottom_right.y) { + p->y = cloth->constraint_bottom_right.y; + p->velocity.y = -p->velocity.y*cloth->efficiency_factor; } // right - if (p->x > bottom_right.x) { - p->x = bottom_right.x; + if (p->x > cloth->constraint_bottom_right.x) { + p->x = cloth->constraint_bottom_right.x; + p->velocity.x = -p->velocity.x*cloth->efficiency_factor; } // left - if (p->x < top_left.x) { - p->x = top_left.x; + if (p->x < cloth->constraint_top_left.x) { + p->x = cloth->constraint_top_left.x; + p->velocity.x = -p->velocity.x*cloth->efficiency_factor; } // up - if (p->y < top_left.y) { - p->y = top_left.y; + if (p->y < cloth->constraint_top_left.y) { + p->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 74040a7..0bc4b4f 100644 --- a/src/cloth.hpp +++ b/src/cloth.hpp @@ -6,13 +6,24 @@ #include struct Cloth { + float efficiency_factor; + float friction_factor; Vec2 startpos; Vec2 dimensions; + Vec2 constraint_top_left; + Vec2 constraint_bottom_right; std::vector points; std::vector connections; }; -Cloth* new_cloth(Vec2 startpos, Vec2 dimensions, unsigned int spacing); +Cloth* new_cloth( + Vec2 startpos, + Vec2 dimensions, + unsigned int spacing, + float efficiency_factor, + float friction_factor, + Vec2 constraint_top_left, Vec2 constraint_bottom_right +); void destroy_cloth(Cloth* cloth); -void compute_cloth_forces(Cloth* cloth, Vec2f gravity_vec); -void satisfy_cloth_constraints(Cloth* cloth, Vec2 top_left, Vec2 bottom_right); \ No newline at end of file +void cloth_step(Cloth* cloth, Vec2f gravity_vec, float timedelta); +void satisfy_cloth_constraints(Cloth* cloth); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index ea7b930..27482ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -64,15 +64,16 @@ int main(const int argc, char** argv) { App_config config = { .win_name = window_name.c_str(), - .window_dimensions = Vec2{500, 500}, + .window_dimensions = Vec2{800, 700}, .cloth_startpos = Vec2{50, 50}, .cloth_dimensions = Vec2{400, 400}, .cloth_spacing = 20, - .gravity = Vec2f{0.0f, 1.5f}, - .background_color = RGB{80, 100, 255}, - .point_color = RGB{10, 10, 10}, + .gravity = Vec2f{0.65f, 0.45f}, + .efficiency_factor = 0.25f, + .background_color = RGB{205, 222, 242}, + .point_color = RGB{2, 10, 1}, .point_selected_color = RGB{200, 40, 12}, - .connection_color = RGB{100, 100, 100}, + .connection_color = RGB{48, 142, 31}, }; App* app = app_init(config); diff --git a/src/point.hpp b/src/point.hpp index 3b3b666..a5dedd1 100644 --- a/src/point.hpp +++ b/src/point.hpp @@ -1,20 +1,13 @@ #pragma once -// struct Point { -// unsigned int x; -// unsigned int y; -// unsigned int prev_x; -// unsigned int prev_y; -// unsigned int mass; -// bool selected; -// }; + +#include "vec.hpp" struct Point { float x; float y; - float prev_x; - float prev_y; float mass; bool frozen; bool selected; + Vec2f velocity; }; \ No newline at end of file