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