# HG changeset patch # User John Tsiombikas # Date 1360604436 -7200 # Node ID 92983e143a03db5669d5696cdfdd462839d68b51 initial commit diff -r 000000000000 -r 92983e143a03 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Mon Feb 11 19:40:36 2013 +0200 @@ -0,0 +1,4 @@ +\.o$ +\.d$ +\.swp$ +^cloth$ diff -r 000000000000 -r 92983e143a03 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Mon Feb 11 19:40:36 2013 +0200 @@ -0,0 +1,25 @@ +src = $(wildcard src/*.cc) +obj = $(src:.cc=.o) +dep = $(obj:.o=.d) +bin = cloth + +CXXFLAGS = -pedantic -Wall -g +LDFLAGS = $(libgl) -limago -lvmath + +ifeq ($(shell uname -s), Darwin) + libgl = -framework OpenGL -framework GLUT -lGLEW +else + libgl = -lGL -lGLU -lglut -lGLEW +endif + +$(bin): $(obj) + $(CXX) -o $@ $(obj) $(LDFLAGS) + +-include $(dep) + +%.d: %.cc + @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@ + +.PHONY: clean +clean: + rm -f $(obj) $(bin) diff -r 000000000000 -r 92983e143a03 src/main.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.cc Mon Feb 11 19:40:36 2013 +0200 @@ -0,0 +1,144 @@ +#include +#include +#include "opengl.h" + +static bool init(); +static void cleanup(); +static void disp(); +static void idle(); +static void reshape(int x, int y); +static void keyb(unsigned char key, int x, int y); +static void mouse(int bn, int state, int x, int y); +static void motion(int x, int y); + +static float cam_theta, cam_phi, cam_dist = 8.0; + +static bool moving_cloth; + + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitWindowSize(800, 600); + glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); + glutCreateWindow("cloth"); + + glutDisplayFunc(disp); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyb); + glutMouseFunc(mouse); + glutMotionFunc(motion); + glutIdleFunc(idle); + + if(!init()) { + return 1; + } + atexit(cleanup); + + glutMainLoop(); + return 0; +} + + +static bool init() +{ + glewInit(); + + glClearColor(0.2, 0.2, 0.2, 1.0); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + return true; +} + +static void cleanup() +{ +} + +static void disp() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -cam_dist); + glRotatef(cam_phi, 1.0, 0.0, 0.0); + glRotatef(cam_theta, 0.0, 1.0, 0.0); + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + glutSolidTeapot(1.0); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glutSwapBuffers(); +} + +static void idle() +{ + glutPostRedisplay(); +} + +static void reshape(int x, int y) +{ + glViewport(0, 0, x, y); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45.0, (float)x / (float)y, 0.5, 500.0); +} + +static void keyb(unsigned char key, int x, int y) +{ + switch(key) { + case 27: + exit(0); + } +} + +static bool bnstate[16]; +static int prev_x, prev_y; + +static void mouse(int bn, int state, int x, int y) +{ + int idx = bn - GLUT_LEFT_BUTTON; + int st = state == GLUT_DOWN ? 1 : 0; + + if(idx >= 0 && idx < 16) { + bnstate[idx] = st; + } + + prev_x = x; + prev_y = y; +} + +static void motion(int x, int y) +{ + int dx = x - prev_x; + int dy = y - prev_y; + prev_x = x; + prev_y = y; + + if(moving_cloth) { + } else { + if(bnstate[0]) { + cam_theta += dx * 0.5; + cam_phi += dy * 0.5; + + if(cam_phi < -90.0) { + cam_phi = -90.0; + } + if(cam_phi > 90.0) { + cam_phi = 90.0; + } + } + if(bnstate[2]) { + cam_dist += dy * 0.1; + + if(cam_dist < 0.0) { + cam_dist = 0.0; + } + } + } +} diff -r 000000000000 -r 92983e143a03 src/opengl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/opengl.h Mon Feb 11 19:40:36 2013 +0200 @@ -0,0 +1,12 @@ +#ifndef OPENGL_H_ +#define OPENGL_H_ + +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#endif // OPENGL_H_ diff -r 000000000000 -r 92983e143a03 src/particle.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/particle.cc Mon Feb 11 19:40:36 2013 +0200 @@ -0,0 +1,167 @@ +#include +#include "opengl.h" +#include "particle.h" +#include "simworld.h" + +Particle::Particle() + : forces(0, 0, 0), pos(0, 0, 0), velocity(0, 0, 0) +{ + rad = 1.0; + elast = 0.75; + mass = 1.0; + friction = 0.0; +} + +void Particle::add_ignore(const Particle *p) +{ + ignorelist.insert(p); +} + +void Particle::set_radius(float rad) +{ + this->rad = rad; +} + +float Particle::get_radius() const +{ + return rad; +} + +void Particle::set_mass(float m) +{ + mass = m; +} + +float Particle::get_mass() const +{ + return mass; +} + +void Particle::set_elasticity(float e) +{ + elast = e; +} + +float Particle::get_elasticity() const +{ + return elast; +} + +void Particle::set_position(const Vector3 &pos) +{ + this->pos = pos; +} + +void Particle::set_velocity(const Vector3 &vel) +{ + velocity = vel; +} + +Vector3 &Particle::get_position() +{ + return pos; +} + +const Vector3 &Particle::get_position() const +{ + return pos; +} + +Vector3 &Particle::get_velocity() +{ + return velocity; +} + +const Vector3 &Particle::get_velocity() const +{ + return velocity; +} + +void Particle::set_friction(float frict) +{ + friction = frict; +} + +float Particle::get_friction() const +{ + return friction; +} + +void Particle::add_force(const Vector3 &fvec) +{ + forces += fvec; +} + +void Particle::step(SimWorld *world, float dt) +{ + Vector3 accel = forces / mass; + forces.x = forces.y = forces.z = 0.0f; + + velocity = velocity * world->damping + accel * dt - velocity * friction * dt; + + Vector3 newpos = pos + velocity * dt; + + Ray ray(pos, newpos - pos); + Collision col; + + if(world->collision(ray, rad, &col)) { + pos = col.pos; + velocity = -velocity.reflection(col.normal) * elast; + } else { + pos = newpos; + } +} + +bool Particle::collision(const Particle *p2, Collision *col) const +{ + if(ignorelist.find(p2) != ignorelist.end()) { + return false; + } + + Vector3 v = p2->pos - pos; + float dist_sq = dot_product(v, v); + float radsum = rad + p2->rad; + + if(dist_sq < radsum * radsum) { + float rad_ratio = rad / p2->rad; + Vector3 dir = p2->pos - pos; + col->pos = pos + dir * rad_ratio; + col->normal = -dir.normalized(); + col->elast = elast * p2->elast; + return true; + } + return false; +} + +void Particle::draw() const +{ + float color[] = {0.3, 0.9, 0.2, 1}; + + glPushMatrix(); + glTranslatef(pos.x, pos.y, pos.z); + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); + + glutSolidSphere(rad, 16, 8); + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + glLineWidth(2.0); + + glBegin(GL_LINES); + glColor3f(0.3, 0, 0); + glVertex3f(0, 0, 0); + glVertex3f(velocity.x, velocity.y, velocity.z); + + glColor3f(0, 0, 0.8); + glVertex3f(0, 0, 0); + glVertex3f(forces.x, forces.y, forces.z); + glEnd(); + + glPopAttrib(); + + glPopMatrix(); +} diff -r 000000000000 -r 92983e143a03 src/particle.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/particle.h Mon Feb 11 19:40:36 2013 +0200 @@ -0,0 +1,57 @@ +#ifndef PARTICLE_H_ +#define PARTICLE_H_ + +#include +#include "vmath/vmath.h" + +class SimWorld; +struct Collision; + +class Particle { +private: + Vector3 forces; + Vector3 pos, velocity; + float rad; + float elast; + float mass; + float friction; + + std::set ignorelist; + +public: + Particle(); + + void add_ignore(const Particle *p); + + void set_radius(float rad); + float get_radius() const; + + void set_mass(float m); + float get_mass() const; + + void set_elasticity(float e); + float get_elasticity() const; + + void set_position(const Vector3 &pos); + void set_velocity(const Vector3 &vel); + + Vector3 &get_position(); + const Vector3 &get_position() const; + Vector3 &get_velocity(); + const Vector3 &get_velocity() const; + + void set_friction(float frict); + float get_friction() const; + + void add_force(const Vector3 &fvec); + + void step(SimWorld *world, float dt); + + bool collision(const Particle *p2, Collision *col) const; + + void draw() const; + + friend class SimWorld; +}; + +#endif // PARTICLE_H_ diff -r 000000000000 -r 92983e143a03 src/plane.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plane.cc Mon Feb 11 19:40:36 2013 +0200 @@ -0,0 +1,72 @@ +#include "opengl.h" +#include "plane.h" +#include "simworld.h" + +Plane::Plane() + : pt(0, 0, 0), normal(0, 1, 0) +{ +} + +Plane::Plane(const Vector3 &pt, const Vector3 &norm) + this->pt(pt), normal(pt) +{ +} + +Plane::Plane(const Vector3 &norm, float dist) + : normal(norm) +{ + pt = Vector3(0, 0, 0) - norm * dist; +} + +bool Plane::collision(const Ray &ray, float rad, Collision *col) const +{ + Vector3 pt = this->pt - normal * rad; + + float ndotdir = dot_product(ray.dir, normal); + if(fabs(ndotdir) < 1e-6) { + return false; + } + + float ndotptdir = dot_product((pt - ray.origin), normal); + + float t = ndotptdir / ndotdir; + if(t < 1e-6 || t > (1.0 - 1e-6)) { + return false; + } + + col->pos = ray.origin + ray.dir * t; + col->normal = normal; + col->elast = 1.0; + return true; +} + +void Plane::draw(float sz) const +{ + Vector3 up = Vector3(0, 1, 0); + if(fabs(dot_product(up, normal)) < 1e-6) { + up = Vector3(0, 0, 1); + } + + Vector3 right = cross_product(up, normal); + up = cross_product(normal, right); + + Matrix4x4 rot_matrix; + rot_matrix.set_column_vector(right, 0); + rot_matrix.set_column_vector(up, 1); + rot_matrix.set_column_vector(normal, 2); + rot_matrix.set_row_vector(Vector4(0, 0, 0, 1), 3); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glMultTransposeMatrixf((float*)rot_matrix.m); + + glBegin(GL_QUADS); + glNormal3f(normal.x, normal.y, normal.z); + glVertex2f(-sz, -sz); + glVertex2f(sz, -sz); + glVertex2f(sz, sz); + glVertex2f(-sz, sz); + glEnd(); + + glPopMatrix(); +} diff -r 000000000000 -r 92983e143a03 src/plane.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plane.h Mon Feb 11 19:40:36 2013 +0200 @@ -0,0 +1,22 @@ +#ifndef PLANE_H_ +#define PLANE_H_ + +#include + +struct Collision; + +class Plane { +public: + Vector3 pt; + Vector3 normal; + + Plane(); + Plane(const Vector3 &pt, const Vector3 &norm); + Plane(const Vector3 &norm, float dist); + + bool collision(const Ray &ray, float rad, Collision *col) const; + + void draw(float sz) const; +}; + +#endif // PLANE_H_ diff -r 000000000000 -r 92983e143a03 src/simworld.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/simworld.cc Mon Feb 11 19:40:36 2013 +0200 @@ -0,0 +1,104 @@ +#include "simworld.h" + +SimWorld::SimWorld() +{ + bbmin = Vector2(-1, -1); + bbmax = Vector2(1, 1); + grav = Vector3(0, -9.81, 0); + damping = 0.99; +} + +void SimWorld::set_bounds(float xmin, float xmax, float ymin, float ymax) +{ + bbmin.x = xmin; + bbmin.y = ymin; + bbmax.x = xmax; + bbmax.y = ymax; +} + +void SimWorld::add_particle(Particle *p) +{ + part.push_back(p); +} + +bool SimWorld::collision(const Ray &ray, float rad, Collision *col) const +{ + bool found = false; + + Vector2 min = bbmin + Vector2(rad, rad); + Vector2 max = bbmax - Vector2(rad, rad); + + // collision with the boundaries + Vector3 npos = ray.origin + ray.dir; + + Vector3 col_pos, col_norm; + float d, col_depth = 0; + + if((d = min.x - npos.x) > col_depth) { + col->pos = npos; + col->pos.x = min.x; + col->normal = Vector3(1, 0, 0); + col_depth = d; + found = true; + } + if((d = min.y - npos.z) > col_depth) { + col->pos = npos; + col->pos.z = min.y; + col->normal = Vector3(0, 0, 1); + col_depth = d; + found = true; + } + if((d = npos.x - max.x) > col_depth) { + col->pos = npos; + col->pos.x = max.x; + col->normal = Vector3(-1, 0, 0); + col_depth = d; + found = true; + } + if((d = npos.z - max.y) > col_depth) { + col->pos = npos; + col->pos.z = max.y; + col->normal = Vector3(0, 0, -1); + col_depth = d; + found = true; + } + + return found; +} + +void SimWorld::step(float dt) +{ + for(size_t i=0; iadd_force(grav * part[i]->get_mass()); + + part[i]->step(this, dt); + + // handle collisions with other particles + for(size_t j=0; jcollision(part[j], &col)) { + Vector3 rel_vel = part[j]->get_velocity() - part[i]->get_velocity(); + + float kn = 1.0 / part[i]->get_mass() + 1.0 / part[j]->get_mass(); + float imp = dot_product(rel_vel, col.normal) * (col.elast + 1) / kn; + + if(imp < 0.0) imp = 0.0; + + Vector3 v = part[i]->get_position() - part[j]->get_position(); + float dist_sq = v.length_sq(); + float pen_depth_sq = part[i]->get_radius() + part[j]->get_radius() - dist_sq; + if(pen_depth_sq < 0.0) pen_depth_sq = 0.0; + + part[i]->add_force(col.normal * imp * (1.0 / dt * pen_depth_sq + 1)); + } + } + } +} + +void SimWorld::draw_particles() const +{ + for(size_t i=0; idraw(); + } +} diff -r 000000000000 -r 92983e143a03 src/simworld.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/simworld.h Mon Feb 11 19:40:36 2013 +0200 @@ -0,0 +1,39 @@ +#ifndef SIMWORLD_H_ +#define SIMWORLD_H_ + +#include +#include "particle.h" +#include "vmath/vmath.h" + +struct Collision { + Vector3 pos; + Vector3 normal; + float elast; +}; + +class SimWorld { +private: + std::vector objects; + std::vector part; + Vector3 grav; + float damping; + +public: + SimWorld(); + + void set_bounds(float xmin, float xmax, float ymin, float ymax); + + void set_gravity(const Vector3 &f); + + void add_particle(Particle *p); + + bool collision(const Ray &ray, float rad, Collision *col) const; + + void step(float dt); + + void draw_particles() const; + + friend class Particle; +}; + +#endif // SIMWORLD_H_