static struct cmesh **meshes[] = {&mesh_suz, &mesh_gout, &mesh_gin};
static const float amb[] = {0.05, 0.05, 0.08, 1};
int i, j;
- struct rsim_rope *rope, *ropes_tail;
+ struct rsim_rope *rope;
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
rsim_init(&rsim);
rsim.damping = 0.3;
- ropes_tail = 0;
+
+ if(!(rope = rsim_alloc_rope(ROPE_MASSES * 4))) {
+ fprintf(stderr, "failed to allocate rope\n");
+ return -1;
+ }
+ rsim_add_rope(&rsim, rope);
/* anchor points on the inner gimbal */
for(i=0; i<4; i++) {
manchor[i].y += 0.15;
- /* create a rope hanging from the anchor point */
- if(!(rope = rsim_alloc_rope(ROPE_MASSES, ROPE_SPRINGS))) {
- fprintf(stderr, "failed to allocate rope\n");
- return -1;
- }
for(j=0; j<ROPE_MASSES; j++) {
+ int midx = i * ROPE_MASSES + j;
+ struct rsim_mass *mass = rope->masses + midx;
+
float t = (float)j / (float)(ROPE_MASSES - 1.0f);
- cgm_vlerp(&rope->masses[j].p, ganchor + i, manchor + i, t);
- rope->masses[j].m = 0.1f;
-
- if(j < ROPE_SPRINGS) {
- rope->springs[j].rest_len = ROPE_LEN / ROPE_SPRINGS;
- rope->springs[j].k = ROPE_K;
- rope->springs[j].mass[0] = rope->masses + j;
- rope->springs[j].mass[1] = rope->masses + j + 1;
+ cgm_vlerp(&mass->p, ganchor + i, manchor + i, t);
+ mass->m = ROPE_MASSES_MASS;
+
+ if(j == 0) {
+ rsim_freeze_rope_mass(rope, rope->masses + i * ROPE_MASSES); /* freeze first mass */
+ } else {
+ rsim_set_rope_spring(rope, midx, midx - 1, ROPE_K, RSIM_RLEN_DEFAULT);
}
}
- rsim_freeze_rope_mass(rope, rope->masses); /* freeze first mass */
- rsim_freeze_rope_mass(rope, rope->masses + j - 1); /* freeze last mass */
-
- if(!ropes_tail) {
- rsim.ropes = ropes_tail = rope;
- } else {
- ropes_tail->next = rope;
- ropes_tail = rope;
- }
- rope->next = 0;
}
return 0;
cgm_vmul_m4v3(&apt0, ginner_xform);
dbgvec[i] = apt0;
- rope->masses[0].p = apt0;
-
- rope = rope->next;
+ rope->masses[i * ROPE_MASSES].p = apt0;
}
rsim_step(&rsim, dt);
{0.5, 0.3, 0.2, 1},
{0.2, 0.3, 0.2, 1}
};
- int i, count;
+ int i, j, count;
long tmsec = glutGet(GLUT_ELAPSED_TIME) - start_msec;
static long prev_tmsec;
struct rsim_rope *rope;
rope = rsim.ropes;
while(rope) {
- glBegin(GL_LINE_STRIP);
+ glBegin(GL_LINES);
glColor3f(0.2, 1, 0.2);
for(i=0; i<rope->num_masses; i++) {
- glVertex3f(rope->masses[i].p.x, rope->masses[i].p.y, rope->masses[i].p.z);
+ for(j=i+1; j<rope->num_masses; j++) {
+ if(rsim_have_spring(rope, i, j)) {
+ glVertex3f(rope->masses[i].p.x, rope->masses[i].p.y, rope->masses[i].p.z);
+ glVertex3f(rope->masses[j].p.x, rope->masses[j].p.y, rope->masses[j].p.z);
+ }
+ }
}
glEnd();
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
#include "ropesim.h"
static void step(struct rsim_world *rsim, struct rsim_rope *rope, float dt);
return 0;
}
+static inline struct rsim_spring *getspring(struct rsim_rope *rope, int aidx, int bidx)
+{
+ struct rsim_spring *spr = rope->springs + aidx * rope->num_masses + bidx;
+ return *(uint32_t*)&spr->rest_len == 0xffffffff ? 0 : spr;
+}
+
/* actual step function, called by rsim_step in a loop to microstep or once if
* microstepping is disabled
*/
static void step(struct rsim_world *rsim, struct rsim_rope *rope, float dt)
{
- int i;
+ int i, j;
float len, fmag;
cgm_vec3 npos, faccel, dir;
float inv_damp = rsim->damping == 0.0f ? 1.0f : (1.0f - rsim->damping);
- struct rsim_mass *mass = rope->masses;
- struct rsim_spring *spr = rope->springs;
-
- /* accumulate forces from springs */
- for(i=0; i<rope->num_springs; i++) {
- dir = spr->mass[1]->p;
- cgm_vsub(&dir, &spr->mass[0]->p);
-
- len = cgm_vlength(&dir);
- if(len != 0.0f) {
- float s = 1.0f / len;
- dir.x *= s;
- dir.y *= s;
- dir.z *= s;
- }
- fmag = (len - spr->rest_len) * spr->k;
+ struct rsim_mass *mass;
+ struct rsim_spring *spr;
- spr->mass[0]->f.x += dir.x * fmag / spr->mass[0]->m;
- spr->mass[0]->f.y += dir.y * fmag / spr->mass[0]->m;
- spr->mass[0]->f.z += dir.z * fmag / spr->mass[0]->m;
+ /* for each mass, add spring forces to every other mass it's connected to */
+ for(i=0; i<rope->num_masses; i++) {
+ for(j=0; j<rope->num_masses; j++) {
+ if(i == j || !(spr = getspring(rope, i, j))) {
+ continue;
+ }
- spr->mass[1]->f.x -= dir.x * fmag / spr->mass[1]->m;
- spr->mass[1]->f.y -= dir.y * fmag / spr->mass[1]->m;
- spr->mass[1]->f.z -= dir.z * fmag / spr->mass[1]->m;
+ dir = rope->masses[i].p;
+ cgm_vsub(&dir, &rope->masses[j].p);
+
+ len = cgm_vlength(&dir);
+ if(len != 0.0f) {
+ float s = 1.0f / len;
+ cgm_vscale(&dir, s);
+ }
+ fmag = (len - spr->rest_len) * spr->k;
- spr++;
+ cgm_vscale(&dir, fmag / rope->masses[j].m);
+ cgm_vadd(&rope->masses[j].f, &dir);
+ }
}
/* update masses */
+ mass = rope->masses;
for(i=0; i<rope->num_masses; i++) {
if(mass->fixed) {
mass++;
}
}
-struct rsim_rope *rsim_alloc_rope(int nmasses, int nsprings)
+struct rsim_rope *rsim_alloc_rope(int nmasses)
{
struct rsim_rope *rope;
if(!(rope = malloc(sizeof *rope))) {
return 0;
}
- if(rsim_init_rope(rope, nmasses, nsprings) == -1) {
+ if(rsim_init_rope(rope, nmasses) == -1) {
free(rope);
return 0;
}
free(rope);
}
-int rsim_init_rope(struct rsim_rope *rope, int nmasses, int nsprings)
+int rsim_init_rope(struct rsim_rope *rope, int nmasses)
{
memset(rope, 0, sizeof *rope);
if(!(rope->masses = calloc(nmasses, sizeof *rope->masses))) {
return -1;
}
- if(!(rope->springs = calloc(nsprings, sizeof *rope->springs))) {
+ rope->num_masses = nmasses;
+
+ if(!(rope->springs = malloc(nmasses * nmasses * sizeof *rope->springs))) {
free(rope->masses);
return -1;
}
- rope->num_masses = nmasses;
- rope->num_springs = nsprings;
+ memset(rope->springs, 0xff, nmasses * nmasses * sizeof *rope->springs);
return 0;
}
free(rope->springs);
}
+int rsim_set_rope_spring(struct rsim_rope *rope, int ma, int mb, float k, float rlen)
+{
+ cgm_vec3 dir;
+ struct rsim_spring *spr;
+
+ if(ma == mb || ma < 0 || ma >= rope->num_masses || mb < 0 || mb >= rope->num_masses) {
+ return -1;
+ }
+
+ if(rlen == RSIM_RLEN_DEFAULT) {
+ dir = rope->masses[ma].p;
+ cgm_vsub(&dir, &rope->masses[mb].p);
+ rlen = cgm_vlength(&dir);
+ }
+
+ spr = rope->springs + ma * rope->num_masses + mb;
+ spr->k = fabs(k);
+ spr->rest_len = rlen;
+ return 0;
+}
+
+int rsim_have_spring(struct rsim_rope *rope, int ma, int mb)
+{
+ return getspring(rope, ma, mb) ? 1 : 0;
+}
+
int rsim_freeze_rope_mass(struct rsim_rope *rope, struct rsim_mass *m)
{
if(m->fixed) return -1;
m->fixed = 1;
- m->next = rope->fixedlist;
- rope->fixedlist = m;
return 0;
}
int rsim_unfreeze_rope_mass(struct rsim_rope *rope, struct rsim_mass *m)
{
- struct rsim_mass *it, dummy;
-
if(!m->fixed) return -1;
- dummy.next = rope->fixedlist;
- it = &dummy;
- while(it->next) {
- if(it->next == m) {
- m->fixed = 0;
- it->next = m->next;
- m->next = 0;
- break;
- }
- it = it->next;
- }
- rope->fixedlist = dummy.next;
-
- return m->fixed ? -1 : 0;
+ m->fixed = 0;
+ return 0;
}
struct rsim_spring {
float rest_len, k;
- struct rsim_mass *mass[2];
};
struct rsim_rope {
struct rsim_mass *masses;
int num_masses;
- struct rsim_spring *springs;
- int num_springs;
-
- /* elements of the masses array which are fixed */
- struct rsim_mass *fixedlist;
+ struct rsim_spring *springs; /* adjacency matrix */
struct rsim_rope *next;
};
void rsim_step(struct rsim_world *rsim, float dt);
-struct rsim_rope *rsim_alloc_rope(int nmasses, int nsprings);
+struct rsim_rope *rsim_alloc_rope(int nmasses);
void rsim_free_rope(struct rsim_rope *rope);
-int rsim_init_rope(struct rsim_rope *rope, int nmasses, int nsprings);
+int rsim_init_rope(struct rsim_rope *rope, int nmasses);
void rsim_destroy_rope(struct rsim_rope *rope);
+#define RSIM_RLEN_DEFAULT (-1.0f)
+int rsim_set_rope_spring(struct rsim_rope *rope, int ma, int mb, float k, float rlen);
+int rsim_have_spring(struct rsim_rope *rope, int ma, int mb);
+
int rsim_freeze_rope_mass(struct rsim_rope *rope, struct rsim_mass *m);
int rsim_unfreeze_rope_mass(struct rsim_rope *rope, struct rsim_mass *m);