placing white holes, and changed to n-body gravitational pull instead of
authorJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 16 Aug 2018 07:00:35 +0000 (10:00 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 16 Aug 2018 07:00:35 +0000 (10:00 +0300)
local gradient following. I'm not sure about this last change. I did it
because it would be hard to disregard own influence from the field, but
the way I'm doing it now is extremely heavyweight and negates all the
benefits of the grid I've set up so far

src/game.cc
src/gamescr.cc
src/goatkit/screen.cc
src/goatkit/screen.h
src/main.cc
src/screen.cc
src/screen.h

index 230c619..9d69c69 100644 (file)
@@ -22,8 +22,6 @@ bool game_init()
        glEnable(GL_FRAMEBUFFER_SRGB);
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
-       glEnable(GL_LIGHTING);
-       glEnable(GL_LIGHT0);
 
        active_screen->start();
        return true;
@@ -43,7 +41,7 @@ void game_draw()
 
 void game_reshape(int x, int y)
 {
-       active_screen->draw();
+       active_screen->reshape(x, y);
 }
 
 void game_keyboard(int key, bool pressed)
index 3eec738..4bac184 100644 (file)
@@ -8,10 +8,12 @@
 #include "sdr.h"
 #include "mesh.h"
 #include "meshgen.h"
+#include "goatkit/goatkit.h"
 
 /* NOTES:
  * - whistle hhgg music
  * - select objects and center camera on them
+ * - we need to rely on actual collisions instead of grid occupancy
  */
 
 struct Particle {
@@ -69,6 +71,9 @@ struct QuadMesh {
 /* gravitational strength */
 #define GRAV_STR       16.0f
 
+#define INIT_MASS_BUDGET       600.0f
+#define EM_MASS_DEFAULT                100.0f
+
 static int pos_to_grid_x_noclamp(float x);
 static int pos_to_grid_y_noclamp(float y);
 static int pos_to_grid(float x, float y);
@@ -116,11 +121,25 @@ static Vec2 *targ_pos = &cam_pos;
 static Mat4 view_matrix, proj_matrix;
 
 static bool wireframe;
+static int mouse_x, mouse_y;
 
 // emitter placement data (filled by event handlers, completed in update)
 static bool emit_place_pending;
 static Vec2 emit_place_pos;
 
+static bool placing_emitter;
+
+static float mass_left;
+
+// UI
+static void ui_handler(goatkit::Widget *w, const goatkit::Event &ev, void *cls);
+static int ui_virt_width = 800;
+static int ui_virt_height = 600;
+static goatkit::Screen *ui;
+static goatkit::Button *bn_emitter;
+static goatkit::Slider *slider_mass;
+static bool mouse_over_ui;
+
 
 bool GameScreen::init()
 {
@@ -161,9 +180,28 @@ bool GameScreen::init()
                return false;
        }
 
-       // XXX DBG
-       emit_place_pos = Vec2(0, 0);
-       emit_place_pending = true;
+       mass_left = INIT_MASS_BUDGET;
+
+       ui = new goatkit::Screen;
+       ui->hide();
+
+       bn_emitter = new goatkit::Button;
+       bn_emitter->set_position(5, 5);
+       bn_emitter->set_size(250, 30);
+       bn_emitter->set_text("new white hole");
+       bn_emitter->set_callback(goatkit::EV_CLICK, ui_handler);
+       ui->add_widget(bn_emitter);
+
+       slider_mass = new goatkit::Slider;
+       slider_mass->set_position(300, 5);
+       slider_mass->set_size(400, 30);
+       slider_mass->set_continuous_change(false);
+       slider_mass->set_range(0, mass_left);
+       slider_mass->set_value(EM_MASS_DEFAULT);
+       slider_mass->set_callback(goatkit::EV_CHANGE, ui_handler);
+       ui->add_widget(slider_mass);
+
+       ui->set_visibility_transition(300);
 
        assert(glGetError() == GL_NO_ERROR);
        return true;
@@ -176,20 +214,54 @@ void GameScreen::destroy()
        delete grid_tex;
        destroy_quadmesh(&field_mesh);
        delete pmesh;
+
+       delete bn_emitter;
+}
+
+void GameScreen::start()
+{
+       ui->show();
+       slider_mass->hide();
+}
+
+void GameScreen::stop()
+{
 }
 
 static void simstep()
 {
        if(pause) return;
 
-       // move existing particles
+       // distribute forces
        Particle *p = plist;
        while(p) {
+               int num_emitters = emitters.size();
+               for(int i=0; i<num_emitters; i++) {
+                       Emitter *em = emitters[i];
+                       Vec2 dir = p->pos - em->pos;
+                       p->vel += dir * em->mass * GRAV_STR * 0.01 / dot(dir, dir) * SIM_DT;
+               }
+
+               Particle *q = plist;
+               while(q) {
+                       if(p != q) {
+                               Vec2 dir = q->pos - p->pos;
+                               float accel = GRAV_STR * q->mass / dot(dir, dir);
+                               p->vel += dir * accel * SIM_DT;
+                       }
+                       q = q->next;
+               }
+               p = p->next;
+       }
+
+       // move existing particles
+       p = plist;
+       while(p) {
                // calculate the field gradient at the particle position
                int gidx = pos_to_grid(p->pos.x, p->pos.y);
-               Vec2 grad = calc_field_grad(gidx) * GRAV_STR;
+               //Vec2 grad = calc_field_grad(gidx) * GRAV_STR;
 
-               p->vel += grad * SIM_DT;
+               //p->vel += grad * SIM_DT;
                p->pos += p->vel * SIM_DT;
 
                // if it moved outside of the simulation field, remove it
@@ -307,11 +379,31 @@ static void simstep()
 
 static void update()
 {
+       if(placing_emitter) {
+               float x = (float)mouse_x / (float)win_width;
+               float y = 1.0f - (float)mouse_y / (float)win_height;
+               Ray pick_ray = mouse_pick_ray(x, y, view_matrix, proj_matrix);
+
+               float ndotdir = pick_ray.dir.y;
+               if(fabs(ndotdir) > 1e-6f) {
+                       float ndotpdir = -pick_ray.origin.y;
+                       float t = ndotpdir / ndotdir;
+
+                       x = pick_ray.origin.x + pick_ray.dir.x * t;
+                       y = pick_ray.origin.z + pick_ray.dir.z * t;
+
+                       if(x >= -FIELD_SIZE / 2 && x < FIELD_SIZE / 2 &&
+                                       y >= -FIELD_SIZE / 2 && y < FIELD_SIZE / 2) {
+                               emit_place_pos = Vec2(x, y);
+                       }
+               }
+       }
+
        if(emit_place_pending) {
                emit_place_pending = false;
                Emitter *em = new Emitter;
                em->pos = emit_place_pos;
-               em->mass = 100;
+               em->mass = slider_mass->get_value();
                em->rate = 10;
                em->chunk = 0.001 * em->mass;
                em->angle = -1;
@@ -319,6 +411,9 @@ static void update()
                em->spawn_pending = 0;
                emitters.push_back(em);
 
+               mass_left -= em->mass;
+               if(mass_left < 0.0f) mass_left = 0.0f;
+
                Rect cbox;
                calc_contrib_bounds(em->pos, em->mass, &cbox);
                printf("bounds: %d,%d %dx%d\n", cbox.x, cbox.y, cbox.width, cbox.height);
@@ -403,11 +498,47 @@ void GameScreen::draw()
 
        glUseProgram(0);
 
+       // draw emitter placement marker if we are in placement mode
+       if(placing_emitter && !mouse_over_ui) {
+               glPushMatrix();
+               glTranslatef(emit_place_pos.x, 0, emit_place_pos.y);
+
+               glBegin(GL_LINES);
+               glColor3f(0, 1, 0);
+               glVertex3f(0, -1000, 0);
+               glVertex3f(0, 1000, 0);
+               glEnd();
+
+               float s = MASS_TO_RADIUS(slider_mass->get_value());
+               if(s < 0.1) s = 0.1;
+               glScalef(s, s, s);
+
+               glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+               pmesh->draw();
+               glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+               glPopMatrix();
+       }
+
+       // draw the UI
+       glMatrixMode(GL_PROJECTION);
+       glLoadIdentity();
+       glOrtho(0, ui_virt_width, ui_virt_height, 0, -1, 1);
+
+       glMatrixMode(GL_MODELVIEW);
+       glLoadIdentity();
+
+       ui->draw();
+
+
        assert(glGetError() == GL_NO_ERROR);
 }
 
 void GameScreen::reshape(int x, int y)
 {
+       ui_virt_width = x;
+       ui_virt_height = y;
+       ui->set_size(ui_virt_width, ui_virt_height);
 }
 
 
@@ -467,20 +598,38 @@ void GameScreen::keyboard(int key, bool pressed)
        }
 }
 
-static int prev_x, prev_y;
+#define UI_HEIGHT      50
 
 void GameScreen::mbutton(int bn, bool pressed, int x, int y)
 {
-       prev_x = x;
-       prev_y = y;
+       mouse_x = x;
+       mouse_y = y;
+
+       mouse_over_ui = y < UI_HEIGHT;
+
+       ui->sysev_mouse_button(bn, pressed, x * ui_virt_width / win_width,
+                       y * ui_virt_height / win_height);
+
+       if(placing_emitter && bn == 0 && pressed && !mouse_over_ui) {
+               emit_place_pending = true;
+               placing_emitter = false;
+               slider_mass->hide();
+       }
 }
 
 void GameScreen::mmotion(int x, int y)
 {
-       int dx = x - prev_x;
-       int dy = y - prev_y;
-       prev_x = x;
-       prev_y = y;
+       int dx = x - mouse_x;
+       int dy = y - mouse_y;
+       mouse_x = x;
+       mouse_y = y;
+
+       mouse_over_ui = y < UI_HEIGHT;
+
+       ui->sysev_mouse_motion(x * ui_virt_width / win_width, y * ui_virt_height / win_height);
+       if(ui->get_mouse_grab()) {
+               return;
+       }
 
        if(game_bnstate(0)) {
                float pan_speed = pow(cam_dist, 1.5) * 0.00035; // magic
@@ -501,6 +650,28 @@ void GameScreen::mwheel(int dir, int x, int y)
        if(cam_dist > MAX_CAM_DIST) cam_dist = MAX_CAM_DIST;
 }
 
+static void ui_handler(goatkit::Widget *w, const goatkit::Event &ev, void *cls)
+{
+       if(w == bn_emitter) {
+               if(placing_emitter) {
+                       placing_emitter = false;
+                       slider_mass->hide();
+               } else {
+                       if(mass_left > 0.0f) {
+                               placing_emitter = true;
+                               slider_mass->set_range(0, mass_left);
+                               slider_mass->set_value(mass_left >= EM_MASS_DEFAULT ? EM_MASS_DEFAULT : mass_left);
+                               slider_mass->show();
+                       }
+               }
+               return;
+       }
+
+       if(w == slider_mass) {
+               printf("foo: %f\n", slider_mass->get_value());
+       }
+}
+
 static int pos_to_grid_x_noclamp(float x)
 {
        return ((x / (float)FIELD_SIZE) + 0.5f) * (float)GRID_SIZE;
index 65e734d..2413bcc 100644 (file)
@@ -186,6 +186,11 @@ bool Screen::grab_mouse(Widget *w)
        return false;
 }
 
+Widget *Screen::get_mouse_grab() const
+{
+       return scr->mgrab;
+}
+
 void Screen::draw() const
 {
        for(size_t i=0; i<scr->widgets.size(); i++) {
index d587bae..5483cb8 100644 (file)
@@ -54,6 +54,7 @@ public:
        long get_visibility_transition() const;
 
        bool grab_mouse(Widget *w);
+       Widget *get_mouse_grab() const;
 
        void draw() const;
 
index 4c707d6..fca4fd9 100644 (file)
@@ -99,6 +99,7 @@ void draw_text(float x, float y, float r, float g, float b, const char *fmt, ...
        glLoadIdentity();
        glOrtho(0, win_width, 0, win_height, -1, 1);
 
+       glPushAttrib(GL_ENABLE_BIT);
        glDisable(GL_LIGHTING);
 
        glRasterPos2f(1, 1);
@@ -107,7 +108,7 @@ void draw_text(float x, float y, float r, float g, float b, const char *fmt, ...
                glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *text++);
        }
 
-       glEnable(GL_LIGHTING);
+       glPopAttrib();
 
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
index 1870796..a0aea2f 100644 (file)
@@ -1,4 +1,5 @@
 #include "screen.h"
+#include "game.h"
 
 ScreenBase *active_screen;
 MenuScreen *scr_menu;
@@ -35,6 +36,7 @@ void push_screen(ScreenBase *scr)
        scr->next = active_screen;
        active_screen = scr;
 
+       scr->reshape(win_width, win_height);
        scr->start();
 }
 
index 6978b77..d7cc9da 100644 (file)
@@ -54,6 +54,9 @@ public:
        bool init();
        void destroy();
 
+       void start();
+       void stop();
+
        void draw();
        void reshape(int x, int y);