Browse Source

base

master
Gitea 3 years ago
commit
3ba95ff850
  1. 1
      .gitignore
  2. 5
      Makefile
  3. 95
      src/app.cpp
  4. 34
      src/app.hpp
  5. 61
      src/cloth.cpp
  6. 17
      src/cloth.hpp
  7. 7
      src/color.hpp
  8. 8
      src/connection.hpp
  9. 97
      src/main.cpp
  10. 19
      src/point.hpp
  11. 11
      src/vec.hpp
  12. 90
      src/window.cpp
  13. 20
      src/window.hpp

1
.gitignore vendored

@ -0,0 +1 @@
./cloth_sim

5
Makefile

@ -0,0 +1,5 @@
all:
g++ -lSDL2 -O2 -Wall -Werror src/*.cpp -o cloth_sim
clean:
rm -f cloth_sim

95
src/app.cpp

@ -0,0 +1,95 @@
#include "app.hpp"
#include "cloth.hpp"
#include "window.hpp"
#include <SDL2/SDL_events.h>
#include <SDL2/SDL_keycode.h>
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_timer.h>
#include <SDL2/SDL_video.h>
App* app_init(App_config conf) {
App* app = new App;
if (conf.window_dimensions.x <= 0) {
conf.window_dimensions.x = 500;
}
if (conf.window_dimensions.y <= 0) {
conf.window_dimensions.y = 500;
}
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);
if (app->window == NULL || app->cloth == NULL) {
return NULL;
}
return app;
}
void app_handle_input(App* app) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
app->is_running = false;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
app->is_running = false;
break;
case SDLK_q:
app->is_running = false;
break;
case SDLK_SPACE:
toggle_pause(app);
break;
}
}
}
}
void app_render(App* app) {
fill_screen(app->window, app->conf.background_color);
draw_cloth(
app->window, app->cloth,
app->conf.point_color, app->conf.connection_color, app->conf.point_selected_color);
SDL_RenderPresent(app->window->renderer);
}
void app_update(App* app) {
if (app->paused) {
return;
}
compute_cloth_forces(app->cloth, app->conf.gravity);
app->conf.gravity = Vec2f{app->conf.gravity.x-0.0005f, app->conf.gravity.y-0.001f};
int updated_window_w;
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};
}
void destroy_app(App* app) {
destroy_cloth(app->cloth);
destroy_window(app->window);
app->cloth = NULL;
app->window = NULL;
app->is_running = false;
}
void toggle_pause(App* app) {
if (app->paused) {
app->paused = false;
} else {
app->paused = true;
}
}

34
src/app.hpp

@ -0,0 +1,34 @@
#pragma once
#include "window.hpp"
#include "cloth.hpp"
#include <SDL2/SDL_render.h>
struct App_config {
const char* win_name;
Vec2 window_dimensions;
Vec2 cloth_startpos;
Vec2 cloth_dimensions;
unsigned int cloth_spacing;
Vec2f gravity;
RGB background_color;
RGB point_color;
RGB point_selected_color;
RGB connection_color;
};
struct App {
bool is_running;
bool paused;
App_config conf;
Window* window;
Cloth* cloth;
};
App* app_init(App_config conf);
void app_update(App* app);
void app_handle_input(App* app);
void app_render(App* app);
void destroy_app(App* app);
void toggle_pause(App* app);

61
src/cloth.cpp

@ -0,0 +1,61 @@
#include "cloth.hpp"
#include "connection.hpp"
#include <cstddef>
#include <cstdio>
#include <vector>
Cloth* new_cloth(Vec2 startpos, Vec2 dimensions, unsigned int spacing) {
Cloth* new_cloth = new Cloth;
new_cloth->startpos = startpos;
new_cloth->dimensions = dimensions;
new_cloth->points = std::vector<Point*>();
new_cloth->connections = std::vector<Connection*>();
for (unsigned int y = 0; y < dimensions.y; y += spacing) {
for (unsigned int x = 0; x < dimensions.x; x += spacing) {
Point* new_point = new Point{static_cast<float>(startpos.x + x), static_cast<float>(startpos.y + y), startpos.x + x, startpos.y + y, false};
new_cloth->points.push_back(new_point);
if (x > 0) {
Point* p0_left = new_cloth->points[new_cloth->points.size() - 2];
Connection* new_conn = new Connection{*p0_left, *new_point};
new_cloth->connections.push_back(new_conn);
}
if (y != 0) {
Point* p0_up = new_cloth->points[new_cloth->points.size()-1 - dimensions.x/spacing];
Connection* new_conn = new Connection{*p0_up, *new_point};
new_cloth->connections.push_back(new_conn);
}
}
}
return new_cloth;
}
void destroy_cloth(Cloth* cloth) {
if (cloth == NULL) {
return;
}
for (unsigned int i = 0; i < cloth->points.size(); i++) {
delete cloth->points[i];
}
for (unsigned int i = 0; i < cloth->connections.size(); i++) {
delete cloth->connections[i];
}
cloth->points.clear();
cloth->connections.clear();
delete cloth;
}
void compute_cloth_forces(Cloth* cloth, Vec2f gravity_vec) {
for (Point* p : cloth->points) {
p->x += gravity_vec.x;
p->y += gravity_vec.y;
}
}

17
src/cloth.hpp

@ -0,0 +1,17 @@
#pragma once
#include "point.hpp"
#include "connection.hpp"
#include "vec.hpp"
#include <vector>
struct Cloth {
Vec2 startpos;
Vec2 dimensions;
std::vector<Point*> points;
std::vector<Connection*> connections;
};
Cloth* new_cloth(Vec2 startpos, Vec2 dimensions, unsigned int spacing);
void destroy_cloth(Cloth* cloth);
void compute_cloth_forces(Cloth* cloth, Vec2f gravity_vec);

7
src/color.hpp

@ -0,0 +1,7 @@
#pragma once
struct RGB {
unsigned char r;
unsigned char g;
unsigned char b;
};

8
src/connection.hpp

@ -0,0 +1,8 @@
#pragma once
#include "point.hpp"
struct Connection {
Point& p0;
Point& p1;
};

97
src/main.cpp

@ -0,0 +1,97 @@
#include "app.hpp"
#include <SDL2/SDL_error.h>
#include <cstdlib>
#include <ostream>
#include <string>
#include <thread>
#include <SDL2/SDL_timer.h>
const char* HELP_ARG = "--help";
const char* HELP_ARG_LITTLE = "-h";
const char* WINDOW_NAME_ARG = "--window_name";
const char* WINDOW_NAME_ARG_LITTLE = "-wn";
const char* FRAMERATE_ARG = "--framerate";
const char* FRAMERATE_ARG_LITTLE = "-fr";
void print_help() {
printf("cloth_sim\n");
printf("\nARGS\n");
printf("%s or %s --> print this message and exit\n", HELP_ARG, HELP_ARG_LITTLE);
printf("%s (string) or %s (string) --> set a custom window name\n", WINDOW_NAME_ARG, WINDOW_NAME_ARG_LITTLE);
printf("%s (unsigned integer) or %s (unsigned integer) --> set framerate\n", FRAMERATE_ARG, FRAMERATE_ARG_LITTLE);
printf("\nKEYS\n");
printf("ESC or q --> exit\n");
printf("SPACE --> pause\n");
}
int main(const int argc, char** argv) {
std::string window_name = "cloth simulation";
unsigned int FRAMERATE = 60;
const unsigned int FRAME_TIME = 1000.0f / FRAMERATE;
unsigned int i = 0;
while (i < (unsigned int) argc) {
if (strcmp(argv[i], HELP_ARG) == 0 || strcmp(argv[i], HELP_ARG_LITTLE) == 0) {
print_help();
return 0;
}
if (strcmp(argv[i], WINDOW_NAME_ARG) == 0 || strcmp(argv[i], WINDOW_NAME_ARG_LITTLE) == 0) {
if (i == (unsigned int) (argc-1)) {
break;
}
i++;
window_name = std::string(argv[i]);
}
if (strcmp(argv[i], FRAMERATE_ARG) == 0 || strcmp(argv[i], FRAMERATE_ARG_LITTLE) == 0) {
if (i == (unsigned int) (argc-1)) {
break;
}
i++;
FRAMERATE = std::stoi(argv[i]);
if (FRAMERATE == 0) {
FRAMERATE = 60;
}
}
i++;
}
App_config config = {
.win_name = window_name.c_str(),
.window_dimensions = Vec2{500, 500},
.cloth_startpos = Vec2{50, 50},
.cloth_dimensions = Vec2{400, 400},
.cloth_spacing = 20,
.gravity = Vec2f{0.3f, 0.8f},
.background_color = RGB{80, 100, 255},
.point_color = RGB{10, 10, 10},
.point_selected_color = RGB{200, 40, 12},
.connection_color = RGB{100, 100, 100},
};
App* app = app_init(config);
app->is_running = true;
unsigned int frame_start_time, total_frame_time;
while (app->is_running) {
frame_start_time = SDL_GetTicks();
app_handle_input(app);
app_update(app);
app_render(app);
total_frame_time = SDL_GetTicks() - frame_start_time;
if (total_frame_time < FRAME_TIME) {
SDL_Delay(FRAME_TIME - total_frame_time);
}
}
destroy_app(app);
return 0;
}

19
src/point.hpp

@ -0,0 +1,19 @@
#pragma once
// struct Point {
// unsigned int x;
// unsigned int y;
// unsigned int prev_x;
// unsigned int prev_y;
// unsigned int mass;
// bool selected;
// };
struct Point {
float x;
float y;
unsigned int prev_x;
unsigned int prev_y;
unsigned int mass;
bool selected;
};

11
src/vec.hpp

@ -0,0 +1,11 @@
#pragma once
struct Vec2 {
unsigned int x;
unsigned int y;
};
struct Vec2f {
float x;
float y;
};

90
src/window.cpp

@ -0,0 +1,90 @@
#include "window.hpp"
#include <SDL2/SDL.h>
#include <SDL2/SDL_error.h>
#include <SDL2/SDL_rect.h>
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_video.h>
#include <cstdio>
#include <stdexcept>
Window* new_window(const char* window_name, Vec2 dimensions) {
Window* new_win = new Window;
new_win->dimensions = dimensions;
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("[ERROR] Window initialization error: %s\n", SDL_GetError());
return NULL;
}
new_win->sdl_win = SDL_CreateWindow(
window_name,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
dimensions.x, dimensions.y,
SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE);
if (new_win->sdl_win == NULL) {
printf("[ERROR] Could not create SDL window: %s\n", SDL_GetError());
return NULL;
}
new_win->renderer = SDL_CreateRenderer(new_win->sdl_win, -1, SDL_RENDERER_PRESENTVSYNC);
return new_win;
}
void destroy_window(Window* window) {
if (window == NULL) {
return;
}
if (window->sdl_win != NULL) {
SDL_DestroyWindow(window->sdl_win);
window->sdl_win = NULL;
SDL_Quit();
}
if (window->renderer != NULL) {
SDL_DestroyRenderer(window->renderer);
window->renderer = NULL;
}
delete window;
window = NULL;
}
void fill_screen(Window* window, RGB color) {
if (window->renderer != NULL) {
SDL_SetRenderDrawColor(window->renderer, color.r, color.g, color.b, 255);
SDL_RenderClear(window->renderer);
}
}
void draw_point(Window* window, Point point, RGB color) {
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);
}
}
void draw_connection(Window* window, Connection connection, RGB color) {
if (window->renderer != NULL) {
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
);
}
}
void draw_cloth(Window* window, Cloth* cloth, RGB point_color, RGB connection_color, RGB selected_p_color) {
for (const Connection* conn : cloth->connections) {
draw_connection(window, *conn, connection_color);
}
for (const Point* point : cloth->points) {
draw_point(window, *point, point_color);
}
}

20
src/window.hpp

@ -0,0 +1,20 @@
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_render.h>
#include "cloth.hpp"
#include "color.hpp"
struct Window {
Vec2 dimensions;
SDL_Window* sdl_win;
SDL_Renderer* renderer;
};
Window* new_window(const char* window_name, Vec2 dimensions);
void destroy_window(Window* window);
void render_cloth(Window* window, Cloth* cloth);
void fill_screen(Window* window, RGB color);
void draw_point(Window* window, Point point);
void draw_connection(Window* window, Connection connection);
void draw_cloth(Window* window, Cloth* cloth, RGB point_color, RGB connection_color, RGB selected_p_color);
Loading…
Cancel
Save