nuclear@5: #include nuclear@5: #include "opengl.h" nuclear@5: #include "mballs.h" nuclear@5: #include "metasurf.h" nuclear@5: #include "vmath/vmath.h" nuclear@9: #include "dsys.h" nuclear@11: #include "udg.h" nuclear@5: nuclear@5: struct MetaBall { nuclear@5: Vector3 pos; nuclear@5: float orbit; nuclear@5: float energy; nuclear@5: float phase_offs; nuclear@5: }; nuclear@5: nuclear@5: #define VOL_SZ 2 nuclear@5: #define MBALL_GRID_SZ 50 nuclear@5: nuclear@9: static void update(float sec); nuclear@5: static float calc_field(float x, float y, float z); nuclear@5: static float eval(float x, float y, float z); nuclear@5: static void vertex(float x, float y, float z); nuclear@5: static void normal(float x, float y, float z); nuclear@5: nuclear@5: static float grid[MBALL_GRID_SZ][MBALL_GRID_SZ][MBALL_GRID_SZ]; nuclear@5: static std::vector balls; nuclear@5: static struct metasurface *msurf; nuclear@8: static float floor_height = -0.95; nuclear@5: nuclear@11: static struct dsys_event *evrise; nuclear@11: nuclear@5: bool mball_init() nuclear@5: { nuclear@5: static const float bbmin = -VOL_SZ / 2.0; nuclear@5: static const float bbmax = VOL_SZ / 2.0; nuclear@5: nuclear@5: if(!(msurf = msurf_create())) { nuclear@5: return false; nuclear@5: } nuclear@5: msurf_threshold(msurf, 10); nuclear@5: msurf_resolution(msurf, MBALL_GRID_SZ, MBALL_GRID_SZ, MBALL_GRID_SZ); nuclear@5: msurf_bounds(msurf, bbmin, bbmin, bbmin, bbmax, bbmax, bbmax); nuclear@5: msurf_eval_func(msurf, eval); nuclear@5: msurf_vertex_func(msurf, vertex); nuclear@5: //msurf_normal_func(msurf, normal); nuclear@5: nuclear@5: for(int i=0; i<10; i++) { nuclear@5: MetaBall mb; nuclear@5: mb.orbit = 0.25 * rand() / (float)RAND_MAX + 0.35; nuclear@9: mb.energy = 0.1 * rand() / (float)RAND_MAX + 0.15; nuclear@5: mb.phase_offs = rand() / (float)RAND_MAX * M_PI * 2.0; nuclear@5: balls.push_back(mb); nuclear@5: } nuclear@5: nuclear@11: evrise = dsys_event(demo, "mball_rise"); nuclear@11: dsys_set_event_eval(evrise, dsys_eval_sigmoid); nuclear@11: nuclear@5: return true; nuclear@5: } nuclear@5: nuclear@9: void mball_render(float sec) nuclear@5: { nuclear@9: update(sec); nuclear@5: nuclear@8: const float blue[] = {0.4, 0.45, 1.0, 1}; nuclear@8: const float dark_red[] = {0.6, 0.2, 0.1, 1}; nuclear@8: const float white[] = {1, 1, 1, 1}; nuclear@8: const float black[] = {0, 0, 0, 1}; nuclear@8: nuclear@5: glMatrixMode(GL_MODELVIEW); nuclear@5: glPushMatrix(); nuclear@5: glScalef(4.0, 4.0, 4.0); nuclear@5: nuclear@8: glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue); nuclear@8: glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white); nuclear@8: glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 80.0); nuclear@8: nuclear@5: glBegin(GL_TRIANGLES); nuclear@5: msurf_polygonize(msurf); nuclear@5: glEnd(); nuclear@5: nuclear@8: // floor nuclear@8: glBegin(GL_QUADS); nuclear@8: glNormal3f(0, 1, 0); nuclear@8: glVertex3f(-5, -1, 5); nuclear@8: glVertex3f(5, -1, 5); nuclear@8: glVertex3f(5, -1, -5); nuclear@8: glVertex3f(-5, -1, -5); nuclear@8: glEnd(); nuclear@8: nuclear@8: glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, dark_red); nuclear@8: glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); nuclear@8: glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 80.0); nuclear@8: nuclear@8: // box nuclear@8: glPushMatrix(); nuclear@8: glTranslatef(0, -1.7, 1); nuclear@8: glScalef(1.05, 1, 0.05); nuclear@8: glutSolidCube(2.0); nuclear@8: glPopMatrix(); nuclear@8: nuclear@8: glPushMatrix(); nuclear@8: glTranslatef(0, -1.7, -1); nuclear@8: glScalef(1.05, 1, 0.05); nuclear@8: glutSolidCube(2.0); nuclear@8: glPopMatrix(); nuclear@8: nuclear@8: glPushMatrix(); nuclear@8: glTranslatef(1, -1.7, 0); nuclear@8: glScalef(0.05, 1, 1); nuclear@8: glutSolidCube(2.0); nuclear@8: glPopMatrix(); nuclear@8: nuclear@8: glPushMatrix(); nuclear@8: glTranslatef(-1, -1.7, 0); nuclear@8: glScalef(0.05, 1, 1); nuclear@8: glutSolidCube(2.0); nuclear@8: glPopMatrix(); nuclear@8: nuclear@5: glPopMatrix(); nuclear@5: } nuclear@5: nuclear@5: nuclear@9: static void update(float sec) nuclear@5: { nuclear@11: float trise = dsys_event_value(evrise); nuclear@11: nuclear@5: for(size_t i=0; i 1e-6) { nuclear@5: sum += balls[i].energy / dist_sq; nuclear@5: } else { nuclear@5: sum += 1000.0; nuclear@5: } nuclear@5: } nuclear@8: nuclear@8: // floor nuclear@8: float height = y - floor_height; nuclear@8: if(height > 1e-6) { nuclear@8: sum += 1.0 / height; nuclear@8: } else { nuclear@8: sum += 1000.0; nuclear@8: } nuclear@8: nuclear@5: return sum; nuclear@5: } nuclear@5: nuclear@5: static inline int clamp(int x, int a, int b) nuclear@5: { nuclear@5: return x < a ? a : (x > b ? b : x); nuclear@5: } nuclear@5: nuclear@5: static float eval(float x, float y, float z) nuclear@5: { nuclear@5: int cell_x = clamp((int)((x / VOL_SZ + 0.5) * MBALL_GRID_SZ), 0, MBALL_GRID_SZ - 1); nuclear@5: int cell_y = clamp((int)((y / VOL_SZ + 0.5) * MBALL_GRID_SZ), 0, MBALL_GRID_SZ - 1); nuclear@5: int cell_z = clamp((int)((z / VOL_SZ + 0.5) * MBALL_GRID_SZ), 0, MBALL_GRID_SZ - 1); nuclear@5: nuclear@5: return grid[cell_x][cell_y][cell_z]; nuclear@5: } nuclear@5: nuclear@5: static void vertex(float x, float y, float z) nuclear@5: { nuclear@5: float delta = (float)VOL_SZ / (float)MBALL_GRID_SZ; nuclear@5: nuclear@5: float dfdx = calc_field(x - delta, y, z) - calc_field(x + delta, y, z); nuclear@5: float dfdy = calc_field(x, y - delta, z) - calc_field(x, y + delta, z); nuclear@5: float dfdz = calc_field(x, y, z - delta) - calc_field(x, y, z + delta); nuclear@5: nuclear@5: float len = sqrt(dfdx * dfdx + dfdy * dfdy + dfdz * dfdz); nuclear@5: nuclear@5: glNormal3f(dfdx / len, dfdy / len, dfdz / len); nuclear@5: glVertex3f(x, y, z); nuclear@5: } nuclear@5: nuclear@5: static void normal(float x, float y, float z) nuclear@5: { nuclear@5: glNormal3f(x, y, z); nuclear@5: }