Browse Source

Mouse, constraints in cloth step now

master
Gitea 3 years ago
parent
commit
52de904d10
  1. 44
      src/app.cpp
  2. 3
      src/app.hpp
  3. 66
      src/cloth.cpp
  4. 4
      src/cloth.hpp
  5. 3
      src/main.cpp
  6. 14
      src/mouse.cpp
  7. 13
      src/mouse.hpp
  8. 4
      src/point.hpp
  9. 20
      src/window.cpp

44
src/app.cpp

@ -1,9 +1,11 @@
#include "app.hpp" #include "app.hpp"
#include "cloth.hpp" #include "cloth.hpp"
#include "mouse.hpp"
#include "window.hpp" #include "window.hpp"
#include "vec.hpp" #include "vec.hpp"
#include <SDL2/SDL_events.h> #include <SDL2/SDL_events.h>
#include <SDL2/SDL_keycode.h> #include <SDL2/SDL_keycode.h>
#include <SDL2/SDL_mouse.h>
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
#include <SDL2/SDL_timer.h> #include <SDL2/SDL_timer.h>
#include <SDL2/SDL_video.h> #include <SDL2/SDL_video.h>
@ -22,6 +24,7 @@ App* app_init(App_config conf) {
} }
app->conf = conf; app->conf = conf;
app->mouse = new_mouse(Vec2{0, 0}, 30);
app->window = new_window(conf.win_name, conf.window_dimensions); app->window = new_window(conf.win_name, conf.window_dimensions);
app->cloth = new_cloth( app->cloth = new_cloth(
conf.cloth_startpos, conf.cloth_startpos,
@ -61,12 +64,44 @@ void app_handle_input(App* app) {
case SDLK_SPACE: case SDLK_SPACE:
toggle_pause(app); toggle_pause(app);
break; 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<unsigned int>(event.motion.x),
static_cast<unsigned int>(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); fill_screen(app->window, app->conf.background_color);
draw_cloth( draw_cloth(
app->window, app->cloth, app->window, app->cloth,
@ -83,16 +118,19 @@ void app_update(App* app) {
int updated_window_h; int updated_window_h;
SDL_GetWindowSize(app->window->sdl_win, &updated_window_w, &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}; 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.x = app->window->dimensions.x;
app->cloth->constraint_bottom_right.y = app->window->dimensions.y-5; 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) { void destroy_app(App* app) {
destroy_mouse(app->mouse);
destroy_cloth(app->cloth); destroy_cloth(app->cloth);
destroy_window(app->window); destroy_window(app->window);
app->mouse = NULL;
app->cloth = NULL; app->cloth = NULL;
app->window = NULL; app->window = NULL;
app->is_running = false; app->is_running = false;

3
src/app.hpp

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "mouse.hpp"
#include "window.hpp" #include "window.hpp"
#include "cloth.hpp" #include "cloth.hpp"
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
@ -13,6 +14,7 @@ struct App_config {
Vec2f gravity; Vec2f gravity;
float efficiency_factor; float efficiency_factor;
float friction_factor; float friction_factor;
float timestep;
RGB background_color; RGB background_color;
RGB point_color; RGB point_color;
RGB point_selected_color; RGB point_selected_color;
@ -23,6 +25,7 @@ struct App {
bool is_running; bool is_running;
bool paused; bool paused;
App_config conf; App_config conf;
Mouse* mouse;
Window* window; Window* window;
Cloth* cloth; Cloth* cloth;
}; };

66
src/cloth.cpp

@ -1,5 +1,7 @@
#include "cloth.hpp" #include "cloth.hpp"
#include "connection.hpp" #include "connection.hpp"
#include "mouse.hpp"
#include <cmath>
#include <cstddef> #include <cstddef>
#include <cstdio> #include <cstdio>
#include <vector> #include <vector>
@ -26,18 +28,12 @@ Cloth* new_cloth(
bool frozen_point = false; bool frozen_point = false;
for (unsigned int y = 0; y < dimensions.y; y += spacing) { for (unsigned int y = 0; y < dimensions.y; y += spacing) {
for (unsigned int x = 0; x < dimensions.x; x += 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{ Point* new_point = new Point{
.x = static_cast<float>(startpos.x + x), .pos = Vec2f{static_cast<float>(startpos.x + x), static_cast<float>(startpos.y + y)},
.y = static_cast<float>(startpos.y + y),
.mass = 10.0f, .mass = 10.0f,
.frozen = frozen_point, .frozen = frozen_point,
.selected = false, .selected = false,
.radius = 2.5,
}; };
new_cloth->points.push_back(new_point); new_cloth->points.push_back(new_point);
@ -78,57 +74,57 @@ void destroy_cloth(Cloth* cloth) {
delete cloth; delete cloth;
} }
// calculate forces and actually MOVE points // calculate forces, move points and satisfy constraints
void cloth_step(Cloth* cloth, Vec2f gravity_vec, float timedelta) { void cloth_step(Cloth* cloth, Mouse* mouse, Vec2f gravity_vec, float timedelta) {
for (Point* p : cloth->points) { for (Point* p : cloth->points) {
if (p->frozen) { if (p->frozen) {
continue; continue;
} }
// calculate velocity // handle mouse
if (p->y == cloth->constraint_bottom_right.y) { // ((x0 - x1)^2 + (y0 - y1)^2)^0.5
// if this point's x velocity is too small -> just stop it float distance_to_point = std::sqrt(pow(p->pos.x - mouse->pos.x, 2.0f)+pow(p->pos.y - mouse->pos.y, 2.0f));
// else -> handle friction if (distance_to_point <= mouse->cursor_radius_size) {
if (p->velocity.x <= 0.5) { p->selected = true;
p->velocity.x = 0;
} else { } else {
p->velocity.x = p->velocity.x*cloth->friction_factor * timedelta; p->selected = false;
} }
} else {
p->velocity.x = p->velocity.x+(gravity_vec.x/p->mass) * timedelta; if (p->selected && mouse->left_button_clicked) {
p->velocity.y = p->velocity.y+(gravity_vec.y/p->mass) * timedelta; 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 // move point
p->x += p->velocity.x; p->pos.x += p->velocity.x;
p->y += p->velocity.y; p->pos.y += p->velocity.y;
}
}
// handle constraints, bounces // now handle constraints
void satisfy_cloth_constraints(Cloth* cloth) {
for (Point* p : cloth->points) {
// bottom // bottom
if (p->y > cloth->constraint_bottom_right.y) { if (p->pos.y >= cloth->constraint_bottom_right.y) {
p->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; p->velocity.y = -p->velocity.y * cloth->efficiency_factor;
} }
// right // right
if (p->x > cloth->constraint_bottom_right.x) { if (p->pos.x >= cloth->constraint_bottom_right.x) {
p->x = cloth->constraint_bottom_right.x; p->pos.x = cloth->constraint_bottom_right.x;
p->velocity.x = -p->velocity.x * cloth->efficiency_factor; p->velocity.x = -p->velocity.x * cloth->efficiency_factor;
} }
// left // left
if (p->x < cloth->constraint_top_left.x) { if (p->pos.x <= cloth->constraint_top_left.x) {
p->x = cloth->constraint_top_left.x; p->pos.x = cloth->constraint_top_left.x;
p->velocity.x = -p->velocity.x * cloth->efficiency_factor; p->velocity.x = -p->velocity.x * cloth->efficiency_factor;
} }
// up // up
if (p->y < cloth->constraint_top_left.y) { if (p->pos.y <= cloth->constraint_top_left.y) {
p->y = cloth->constraint_top_left.y; p->pos.y = cloth->constraint_top_left.y;
p->velocity.y = -p->velocity.y * cloth->efficiency_factor; p->velocity.y = -p->velocity.y * cloth->efficiency_factor;
} }
} }

4
src/cloth.hpp

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "mouse.hpp"
#include "point.hpp" #include "point.hpp"
#include "connection.hpp" #include "connection.hpp"
#include "vec.hpp" #include "vec.hpp"
@ -25,5 +26,4 @@ Cloth* new_cloth(
Vec2 constraint_top_left, Vec2 constraint_bottom_right Vec2 constraint_top_left, Vec2 constraint_bottom_right
); );
void destroy_cloth(Cloth* cloth); void destroy_cloth(Cloth* cloth);
void cloth_step(Cloth* cloth, Vec2f gravity_vec, float timedelta); void cloth_step(Cloth* cloth, Mouse* mouse, Vec2f gravity_vec, float timedelta);
void satisfy_cloth_constraints(Cloth* cloth);

3
src/main.cpp

@ -68,8 +68,9 @@ int main(const int argc, char** argv) {
.cloth_startpos = Vec2{50, 50}, .cloth_startpos = Vec2{50, 50},
.cloth_dimensions = Vec2{400, 400}, .cloth_dimensions = Vec2{400, 400},
.cloth_spacing = 20, .cloth_spacing = 20,
.gravity = Vec2f{0.65f, 0.45f}, .gravity = Vec2f{0.5f, 0.75f},
.efficiency_factor = 0.25f, .efficiency_factor = 0.25f,
.timestep = 1.0f,
.background_color = RGB{205, 222, 242}, .background_color = RGB{205, 222, 242},
.point_color = RGB{2, 10, 1}, .point_color = RGB{2, 10, 1},
.point_selected_color = RGB{200, 40, 12}, .point_selected_color = RGB{200, 40, 12},

14
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;
}

13
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);

4
src/point.hpp

@ -4,10 +4,10 @@
#include "vec.hpp" #include "vec.hpp"
struct Point { struct Point {
float x; Vec2f pos;
float y;
float mass; float mass;
bool frozen; bool frozen;
bool selected; bool selected;
float radius;
Vec2f velocity; Vec2f velocity;
}; };

20
src/window.cpp

@ -62,7 +62,13 @@ void fill_screen(Window* window, RGB color) {
void draw_point(Window* window, Point point, 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_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_SetRenderDrawColor(window->renderer, color.r, color.g, color.b, 255);
SDL_RenderDrawLine( SDL_RenderDrawLine(
window->renderer, window->renderer,
(int) connection.p0.x, (int) connection.p0.pos.x,
(int) connection.p0.y, (int) connection.p0.pos.y,
(int) connection.p1.x, (int) connection.p1.pos.x,
(int) connection.p1.y (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) { for (const Point* point : cloth->points) {
if (point->selected) {
draw_point(window, *point, selected_p_color);
} else {
draw_point(window, *point, point_color); draw_point(window, *point, point_color);
} }
} }
}
Loading…
Cancel
Save