dbf-udg

annotate src/mballs.cc @ 5:e09cbb2e9d4f

metaballs
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 18 Feb 2013 03:46:52 +0200
parents
children f0a47f46ee45
rev   line source
nuclear@5 1 #include <vector>
nuclear@5 2 #include "opengl.h"
nuclear@5 3 #include "mballs.h"
nuclear@5 4 #include "metasurf.h"
nuclear@5 5 #include "vmath/vmath.h"
nuclear@5 6
nuclear@5 7 struct MetaBall {
nuclear@5 8 Vector3 pos;
nuclear@5 9 float orbit;
nuclear@5 10 float energy;
nuclear@5 11 float phase_offs;
nuclear@5 12 };
nuclear@5 13
nuclear@5 14 #define VOL_SZ 2
nuclear@5 15 #define MBALL_GRID_SZ 50
nuclear@5 16
nuclear@5 17 static void update();
nuclear@5 18 static float calc_field(float x, float y, float z);
nuclear@5 19 static float eval(float x, float y, float z);
nuclear@5 20 static void vertex(float x, float y, float z);
nuclear@5 21 static void normal(float x, float y, float z);
nuclear@5 22
nuclear@5 23 static float grid[MBALL_GRID_SZ][MBALL_GRID_SZ][MBALL_GRID_SZ];
nuclear@5 24 static std::vector<MetaBall> balls;
nuclear@5 25 static struct metasurface *msurf;
nuclear@5 26
nuclear@5 27 bool mball_init()
nuclear@5 28 {
nuclear@5 29 static const float bbmin = -VOL_SZ / 2.0;
nuclear@5 30 static const float bbmax = VOL_SZ / 2.0;
nuclear@5 31
nuclear@5 32 if(!(msurf = msurf_create())) {
nuclear@5 33 return false;
nuclear@5 34 }
nuclear@5 35 msurf_threshold(msurf, 10);
nuclear@5 36 msurf_resolution(msurf, MBALL_GRID_SZ, MBALL_GRID_SZ, MBALL_GRID_SZ);
nuclear@5 37 msurf_bounds(msurf, bbmin, bbmin, bbmin, bbmax, bbmax, bbmax);
nuclear@5 38 msurf_eval_func(msurf, eval);
nuclear@5 39 msurf_vertex_func(msurf, vertex);
nuclear@5 40 //msurf_normal_func(msurf, normal);
nuclear@5 41
nuclear@5 42 for(int i=0; i<10; i++) {
nuclear@5 43 MetaBall mb;
nuclear@5 44 mb.orbit = 0.25 * rand() / (float)RAND_MAX + 0.35;
nuclear@5 45 mb.energy = 0.2 * rand() / (float)RAND_MAX + 0.15;
nuclear@5 46 mb.phase_offs = rand() / (float)RAND_MAX * M_PI * 2.0;
nuclear@5 47 balls.push_back(mb);
nuclear@5 48 }
nuclear@5 49
nuclear@5 50 return true;
nuclear@5 51 }
nuclear@5 52
nuclear@5 53 void mball_render()
nuclear@5 54 {
nuclear@5 55 update();
nuclear@5 56
nuclear@5 57 glMatrixMode(GL_MODELVIEW);
nuclear@5 58 glPushMatrix();
nuclear@5 59 glScalef(4.0, 4.0, 4.0);
nuclear@5 60
nuclear@5 61 glBegin(GL_TRIANGLES);
nuclear@5 62 msurf_polygonize(msurf);
nuclear@5 63 glEnd();
nuclear@5 64
nuclear@5 65 glPopMatrix();
nuclear@5 66 }
nuclear@5 67
nuclear@5 68
nuclear@5 69 static void update()
nuclear@5 70 {
nuclear@5 71 unsigned int msec = glutGet(GLUT_ELAPSED_TIME);
nuclear@5 72 float sec = msec / 1000.0;
nuclear@5 73
nuclear@5 74 for(size_t i=0; i<balls.size(); i++) {
nuclear@5 75 float t = sec + balls[i].phase_offs;
nuclear@5 76 balls[i].pos.x = cos(t * 1.8) * balls[i].orbit;
nuclear@5 77 balls[i].pos.z = sin(t * 1.2) * balls[i].orbit;
nuclear@5 78 balls[i].pos.y = (sin(t) + cos(t * 2.0) / 2.0 + sin(t * 3.0) / 3.0) * 0.45;
nuclear@5 79 }
nuclear@5 80
nuclear@5 81 for(int i=0; i<MBALL_GRID_SZ; i++) {
nuclear@5 82 float x = (float)i / (float)MBALL_GRID_SZ * 2.0 - 1.0;
nuclear@5 83 for(int j=0; j<MBALL_GRID_SZ; j++) {
nuclear@5 84 float y = (float)j / (float)MBALL_GRID_SZ * 2.0 - 1.0;
nuclear@5 85 for(int k=0; k<MBALL_GRID_SZ; k++) {
nuclear@5 86 float z = (float)k / (float)MBALL_GRID_SZ * 2.0 - 1.0;
nuclear@5 87 grid[i][j][k] = calc_field(x, y, z);
nuclear@5 88 }
nuclear@5 89 }
nuclear@5 90 }
nuclear@5 91 }
nuclear@5 92
nuclear@5 93 static float calc_field(float x, float y, float z)
nuclear@5 94 {
nuclear@5 95 Vector3 pt(x, y, z);
nuclear@5 96
nuclear@5 97 float sum = 0.0f;
nuclear@5 98 for(size_t i=0; i<balls.size(); i++) {
nuclear@5 99 float dist_sq = (balls[i].pos - pt).length_sq();
nuclear@5 100 if(dist_sq > 1e-6) {
nuclear@5 101 sum += balls[i].energy / dist_sq;
nuclear@5 102 } else {
nuclear@5 103 sum += 1000.0;
nuclear@5 104 }
nuclear@5 105 }
nuclear@5 106 return sum;
nuclear@5 107 }
nuclear@5 108
nuclear@5 109 static inline int clamp(int x, int a, int b)
nuclear@5 110 {
nuclear@5 111 return x < a ? a : (x > b ? b : x);
nuclear@5 112 }
nuclear@5 113
nuclear@5 114 static float eval(float x, float y, float z)
nuclear@5 115 {
nuclear@5 116 int cell_x = clamp((int)((x / VOL_SZ + 0.5) * MBALL_GRID_SZ), 0, MBALL_GRID_SZ - 1);
nuclear@5 117 int cell_y = clamp((int)((y / VOL_SZ + 0.5) * MBALL_GRID_SZ), 0, MBALL_GRID_SZ - 1);
nuclear@5 118 int cell_z = clamp((int)((z / VOL_SZ + 0.5) * MBALL_GRID_SZ), 0, MBALL_GRID_SZ - 1);
nuclear@5 119
nuclear@5 120 return grid[cell_x][cell_y][cell_z];
nuclear@5 121 }
nuclear@5 122
nuclear@5 123 static void vertex(float x, float y, float z)
nuclear@5 124 {
nuclear@5 125 float delta = (float)VOL_SZ / (float)MBALL_GRID_SZ;
nuclear@5 126
nuclear@5 127 float dfdx = calc_field(x - delta, y, z) - calc_field(x + delta, y, z);
nuclear@5 128 float dfdy = calc_field(x, y - delta, z) - calc_field(x, y + delta, z);
nuclear@5 129 float dfdz = calc_field(x, y, z - delta) - calc_field(x, y, z + delta);
nuclear@5 130
nuclear@5 131 float len = sqrt(dfdx * dfdx + dfdy * dfdy + dfdz * dfdz);
nuclear@5 132
nuclear@5 133 glNormal3f(dfdx / len, dfdy / len, dfdz / len);
nuclear@5 134 glVertex3f(x, y, z);
nuclear@5 135 }
nuclear@5 136
nuclear@5 137 static void normal(float x, float y, float z)
nuclear@5 138 {
nuclear@5 139 glNormal3f(x, y, z);
nuclear@5 140 }