From a7546372ccdec02ba961c52a4b43a7fc59010d92 Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Sat, 2 Feb 2013 22:52:58 +0000
Subject: [PATCH] [Add] Vec2 now uses polor coords.

---
 src/main.c    |  11 ++++-
 src/opengl.c  |  12 ++---
 src/physics.c | 133 ++++++++++++++++++++++++++++++--------------------
 src/physics.h |  19 ++++++--
 src/pilot.c   |   6 +--
 src/player.c  |   3 +-
 src/space.c   |  23 +++++----
 7 files changed, 128 insertions(+), 79 deletions(-)

diff --git a/src/main.c b/src/main.c
index fc187ae..abb5b25 100644
--- a/src/main.c
+++ b/src/main.c
@@ -121,6 +121,10 @@ int main(int argc, char** argv) {
           else if(strcmp(str, "keyboard")==0)   type = KEYBIND_KEYBOARD;
           else if(strcmp(str, "jaxis")==0)      type = KEYBIND_JAXIS;
           else if(strcmp(str, "jbutton")==0)    type = KEYBIND_JBUTTON;
+          else {
+            WARN("Unknown keybinding of type %s", str);
+            continue;
+          }
           // Set the keybind.
           input_setKeybind((char*)keybindNames[i], type, key, reverse);
         } else WARN("Malformed keybind in %s", CONF_FILE);
@@ -239,9 +243,11 @@ static void update_all(void) {
   time = SDL_GetTicks();
   
   if(dt > MINIMUM_FPS) {
-    Vec2 pos = { .x = 10., .y = gl_screen.h-40 };
+    Vec2 pos;
+    vect_cinit(&pos, 10., (double)(gl_screen.h-40));
     gl_print(NULL, &pos, "FPS is really low! Skipping frames.");
     SDL_GL_SwapBuffers();
+    return;
   }
 
   glClear(GL_COLOR_BUFFER_BIT);
@@ -266,7 +272,8 @@ static void display_fps(const double dt) {
     fps = fps_cur / fps_dt;
     fps_dt = fps_cur = 0.;
   }
-  Vec2 pos = { .x = 10., .y = (double)(gl_screen.h-20) };
+  Vec2 pos;
+  vect_cinit(&pos, 10., (double)(gl_screen.h-20));
   gl_print(NULL, &pos, "%3.2f", fps);
 }
 
diff --git a/src/opengl.c b/src/opengl.c
index 4807528..63b9ab6 100644
--- a/src/opengl.c
+++ b/src/opengl.c
@@ -233,8 +233,8 @@ void gl_freeTexture(gl_texture* texture) {
 // Blit the sprite at given position.
 void gl_blitSprite(const gl_texture* sprite, const Vec2* pos, const int sx, const int sy) {
   // Don't bother drawing if offscreen -- waste of cycles.
-  if(fabs(pos->x - gl_camera->x) > gl_screen.w / 2 + sprite->sw / 2 ||
-        fabs(pos->y-gl_camera->y) > gl_screen.h / 2 + sprite->sh / 2)
+  if(fabs(VX(*pos) -VX(*gl_camera)) > gl_screen.w / 2 + sprite->sw / 2 ||
+        fabs(VY(*pos) -VY(*gl_camera)) > gl_screen.h / 2 + sprite->sh / 2)
     return;
 
   glEnable(GL_TEXTURE_2D);
@@ -245,8 +245,8 @@ void gl_blitSprite(const gl_texture* sprite, const Vec2* pos, const int sx, cons
 
   glMatrixMode(GL_PROJECTION);
   glPushMatrix(); // Projection translation matrix.
-  glTranslated(pos->x - gl_camera->x - sprite->sw/2.,
-        pos->y - gl_camera->y - sprite->sh/2., 0.);
+  glTranslated(VX(*pos) -VX(*gl_camera) - sprite->sw/2.,
+        VY(*pos) -VY(*gl_camera) - sprite->sh/2., 0.);
   glScalef((double)gl_screen.w/SCREEN_W, (double)gl_screen.h/SCREEN_H, 0.);
 
   // Actual blitting....
@@ -276,7 +276,7 @@ void gl_blitStatic(const gl_texture* texture, const Vec2* pos) {
   glEnable(GL_TEXTURE_2D);
   glMatrixMode(GL_PROJECTION);
   glPushMatrix(); // Set up translation matrix.
-  glTranslated(pos->x - (double)gl_screen.w/2., pos->y - (double)gl_screen.h/2., 0);
+  glTranslated(VX(*pos) - (double)gl_screen.w/2., VY(*pos) - (double)gl_screen.h/2., 0);
   glScaled((double)gl_screen.w/SCREEN_W, (double)gl_screen.h/SCREEN_H, 0.);
   
   // Actual blitting..
@@ -327,7 +327,7 @@ void gl_print(const gl_font* ft_font, const Vec2* pos, const char* fmt, ...) {
   glMatrixMode(GL_PROJECTION);
 
   glPushMatrix(); // Translation matrix.
-  glTranslated(pos->x - (double)gl_screen.w/2., pos->y - (double)gl_screen.h/2., 0);
+  glTranslated(VX(*pos) - (double)gl_screen.w/2., VY(*pos) - (double)gl_screen.h/2., 0);
 
   glColor4d(1., 1., 1., 1.);
   glCallLists(strlen(text), GL_UNSIGNED_BYTE, &text);
diff --git a/src/physics.c b/src/physics.c
index a32fa3c..7bc523d 100644
--- a/src/physics.c
+++ b/src/physics.c
@@ -8,9 +8,17 @@
 #define M_PI 3.14159265358979323846f
 #endif
 
-// Pretty efficient, no need for sine table!!
-#define SIN(dir)(sinf(dir))
-#define COS(dir)(cosf(dir))
+// Init cartesian vector.
+void vect_cinit(Vec2* v, double x, double y) {
+  v->mod = MOD(x,y);
+  v->angle = ANGLE(x, y);
+}
+
+// Init polarized vector
+void vect_pinit(Vec2* v, double mod, double angle) {
+  v->mod = mod;
+  v->angle = angle;
+}
 
 // ==Update method.========================================
 // d^2 x(t) / d t^2 = a, a = constant (acceleration)
@@ -22,26 +30,38 @@
 // Since dt isn't actually differential this gives us an
 // error, so watch out with big values for dt.
 // ========================================================
-#if 0
+#if 0 // Simply commenting this out to avoid silly warnings.
 static void simple_update(Solid* obj, const double dt) {
   // Make sure angle doesn't flip.
-  obj->dir += obj->dir_vel/360.0*dt;
+  obj->dir += obj->dir_vel/360.*dt;
   if(obj->dir > 2*M_PI)   obj->dir -= 2*M_PI;
-  if(obj->dir < 0.0)      obj->dir += 2*M_PI;
-  if(obj->force) {
-    Vec2 acc;
-    acc.x = obj->force / obj->mass * COS(obj->dir);
-    acc.y = obj->force / obj->mass * SIN(obj->dir);
+  if(obj->dir < 0.)      obj->dir += 2*M_PI;
+  
+  double px, py, vx, vy;
+  px = VX(obj->pos);
+  py = VY(obj->pos);
+  vx = VX(obj->vel);
+  vy = VY(obj->vel);
 
-    obj->pos.x += acc.x * dt;
-    obj->vel.y += acc.y * dt;
+  if(obj->force.mod) { // Force applied on an object.
+    double ax, ay;
+    ax = VX(obj->force)/obj->mass;
+    ay = VY(obj->force)/obj->mass;
 
-    obj->pos.x += obj->vel.x * dt + 0.5 * acc.x * dt*dt;
-    obj->pos.y += obj->vel.y * dt + 0.5 * acc.y * dt*dt;
+    vx += ax*dt;
+    vy += ay*dt;
+
+    px += vx*dt + 0.5*ax * dt*dt;
+    py += vy*dt + 0.5*ay * dt*dt;
+
+    obj->vel.mod = MOD(vx, vy);
+    obj->vel.angle = ANGLE(vx, vy);
   } else {
-    obj->pos.x += obj->vel.x * dt;
-    obj->pos.y += obj->vel.y * dt;
+    px += vx*dt;
+    py += vy*dt;
   }
+  obj->pos.mod = MOD(px, py);
+  obj->pos.angle = ANGLE(px, py);
 }
 #endif
 
@@ -60,72 +80,79 @@ static void simple_update(Solid* obj, const double dt) {
 // x_{n+1} = x_n + h/6x'_n + 3*h*a, 4*a)
 // ========================================================
 
-#define RK4_N 4
+#define RK4_MIN_H 0.01 // Minimal pass we want.
 static void rk4_update(Solid* obj, const double dt) {
   // Make sure angle doesn't flip.
   obj->dir += obj->dir_vel/360.0*dt;
   if(obj->dir > 2*M_PI)   obj->dir -= 2*M_PI;
   if(obj->dir < 0.0)      obj->dir += 2*M_PI;
 
-  double h = dt / RK4_N; // Step.
+  int N = (dt > RK4_MIN_H) ? (int)(dt/RK4_MIN_H) : 1;
+  double h = dt / (double)N; // Step.
 
-  if(obj->force) {  // Force applied on object.
+  double px, py, vx, vy;
+  px = VX(obj->pos);
+  py = VY(obj->pos);
+  vx = VX(obj->vel);
+  vy = VY(obj->vel);
+
+  if(obj->force.mod) {  // Force applied on object.
     int i;
-    Vec2 initial, tmp;
+    double ix, iy, tx, ty; // Initial and temp cartesian vector values.
 
-    Vec2 acc;
-    acc.x = obj->force / obj->mass * COS(obj->dir);
-    acc.y = obj->force / obj->mass * SIN(obj->dir);
-
-    for(i = 0; i < RK4_N; i++) {
+    double ax, ay;
+    ax = VX(obj->force)/obj->mass;
+    ay = VY(obj->force)/obj->mass;
+    for(i = 0; i < N; i++) {
       // X component.
-      tmp.x  = initial.x = obj->vel.x;
-      tmp.x += 2*initial.x + h*tmp.x;
-      tmp.x += 2*initial.x + h*tmp.x;
-      tmp.x += initial.x + h*tmp.x;
-      tmp.x *= h/6;
+      tx = ix = vx;
+      tx += 2*ix + h*tx;
+      tx += 2*ix + h*tx;
+      tx += ix + h*tx;
+      tx *= h/6;
 
-      obj->pos.x += tmp.x;
-      obj->vel.x += acc.x*h;
+      px += tx;
+      vx += ax*h;
 
       // Y component.
-      tmp.y  = initial.y = obj->vel.y;
-      tmp.y += 2*(initial.y + h/2*tmp.y);
-      tmp.y += 2*(initial.y + h/2*tmp.y);
-      tmp.y += initial.y + h*tmp.y;
-      tmp.y *= h/6;
+      ty = iy = vy;
+      ty += 2*(iy + h/2*ty);
+      ty += 2*(iy + h/2*ty);
+      ty += iy +h*ty;
+      ty *= h/6;
 
-      obj->pos.y += tmp.y;
-      obj->pos.y += acc.y*h;
+      py += ty;
+      vy += ay*h;
     }
+    obj->vel.mod = MOD(vx, vy);
+    obj->vel.angle = ANGLE(vx, vy);
   } else {
-    obj->pos.x += dt*obj->vel.x;
-    obj->pos.y += dt*obj->vel.y;
+    px += dt*vx;
+    py += dt*vy;
   }
+  obj->pos.mod = MOD(px, py);
+  obj->pos.angle = ANGLE(px, py);
 }
 
 // Initialize a new solid.
 void solid_init(Solid* dest, const double mass, const Vec2* vel, const Vec2* pos) {
   dest->mass = mass;
 
-  dest->force = 0;
-  dest->dir   = 0;
+  dest->force.mod = 0;
+  dest->dir       = 0;
 
   if(vel == NULL)
-    dest->vel.x = dest->vel.y = 0.0;
-  else {
-    dest->vel.x = vel->x;
-    dest->vel.y = vel->y;
-  }
+    vect_cinit(&dest->vel, 0., 0.);
+  else
+    vect_pinit(&dest->vel, vel->mod, vel->angle);
 
   if(pos == NULL)
-    dest->pos.x = dest->pos.y = 0.0;
-  else {
-    dest->pos.x = pos->x;
-    dest->pos.y = pos->y;
-  }
+    vect_cinit(&dest->pos, 0., 0.);
+  else
+    vect_pinit(&dest->pos, pos->mod, pos->angle);
 
   dest->update = rk4_update;
+  //dest->update = simple_update;
 }
 
 // Create a new solid.
diff --git a/src/physics.h b/src/physics.h
index fab782a..ec0645c 100644
--- a/src/physics.h
+++ b/src/physics.h
@@ -1,20 +1,33 @@
 #pragma once
 #include "def.h"
 
+#define VX(v)     ((v).mod*cos((v).angle))
+#define VY(v)     ((v).mod*sin((v).angle))
+#define VMOD(v)   ((v).mod)
+#define VANGLE(v) ((v).angle)
+
+#define MOD(x,y)  (sqrt(x*x + y*y))
+#define ANGLE(x,y)((x==0.) ? 0. : ((x<0.)?atan(y/x)+M_PI:atan(y/x)))
+
 // Base of 2D vectors.
 typedef struct {
-  double x, y; // Basic 2D vector components.
+  double mod, angle; // Basic 2D vector components.
 } Vec2;
 
+// Vector manupulation.
+void vect_cinit(Vec2* v, double x, double y);
+void vect_pinit(Vec2* v, double mod, double angle);
+
 // Describe any solid in 2D space.
 struct Solid {
-  double mass, force, dir, dir_vel; // Properties.
-  Vec2 vel, pos; // Position/velocity vectors.
+  double mass, dir, dir_vel; // Properties.
+  Vec2 vel, pos, force; // Position/velocity vectors.
   void(*update)(struct Solid*, const double); // Update method.
 };
 
 typedef struct Solid Solid;
 
+// Solid manipulation.
 void solid_init(Solid* dest, const double mass, const Vec2* vel, const Vec2* pos);
 Solid* solid_create(const double mass, const Vec2* vel, const Vec2* pos);
 void solid_free(Solid* src);
diff --git a/src/pilot.c b/src/pilot.c
index 37737d9..5440ff3 100644
--- a/src/pilot.c
+++ b/src/pilot.c
@@ -7,9 +7,6 @@
 #include "log.h"
 #include "pilot.h"
 
-#define VMOD(v) (v.x*v.x + v.y*v.y)
-#define NMOD(n) (n*n)
-
 // Stack of pilot id's to assure uniqueness.
 static unsigned int pilot_id = 0;
 
@@ -57,8 +54,9 @@ static void pilot_update(Pilot* pilot, const double dt) {
   // Update the solid.
   pilot->solid->update(pilot->solid, dt);
   
-  if(VMOD(pilot->solid->vel) > NMOD(pilot->ship->speed)) {
+  if(VMOD(pilot->solid->vel) > pilot->ship->speed) {
     // Should not go faster.
+    VMOD(pilot->solid->vel) = pilot->ship->speed;
   }
 
   pilot_render(pilot);
diff --git a/src/player.c b/src/player.c
index 161a641..56a2841 100644
--- a/src/player.c
+++ b/src/player.c
@@ -29,7 +29,8 @@ void player_think(Pilot* player, const double dt) {
   if(player_turn)
     player->solid->dir_vel -= player->ship->turn * player_turn;
 
-  player->solid->force = player->ship->thrust * player_acc;
+  player->solid->force.angle = player->solid->dir;
+  player->solid->force.mod = player->ship->thrust * player_acc;
 }
 
 // Initialization/exit functions (does not assign keys).
diff --git a/src/space.c b/src/space.c
index 0a372b5..f92ab51 100644
--- a/src/space.c
+++ b/src/space.c
@@ -1,3 +1,6 @@
+#include <malloc.h>
+#include <math.h>
+
 #include "log.h"
 #include "physics.h"
 #include "opengl.h"
@@ -7,7 +10,7 @@
 
 #define STAR_BUF 100 // Area to leave around screen.
 typedef struct {
-  Vec2 pos;
+  double x, y;
   double brightness;
 } Star;
 
@@ -20,8 +23,8 @@ void space_init(void) {
   stars = malloc(sizeof(Star)*nstars);
   for(i = 0; i < nstars; i++) {
     stars[i].brightness = (double)RNG(50, 200)/256.;
-    stars[i].pos.x = (double)RNG(-STAR_BUF, gl_screen.w + STAR_BUF);
-    stars[i].pos.y = (double)RNG(-STAR_BUF, gl_screen.h + STAR_BUF);
+    stars[i].x = (double)RNG(-STAR_BUF, gl_screen.w + STAR_BUF);
+    stars[i].y = (double)RNG(-STAR_BUF, gl_screen.h + STAR_BUF);
   }
 }
 
@@ -33,16 +36,16 @@ void space_render(double dt) {
   glBegin(GL_POINTS);
   for(i = 0; i < nstars; i++) {
     // Update the position.
-    stars[i].pos.x -= player->solid->vel.x/(15.-10.*stars[i].brightness)*dt;
-    stars[i].pos.y -= player->solid->vel.y/(15.-10.*stars[i].brightness)*dt;
+    stars[i].x -= VX(player->solid->vel)/(15.-10.*stars[i].brightness)*dt;
+    stars[i].y -= VY(player->solid->vel)/(15.-10.*stars[i].brightness)*dt;
     // Scroll those stars bitch!
-    if(stars[i].pos.x > gl_screen.w + STAR_BUF) stars[i].pos.x = -STAR_BUF;
-    else if(stars[i].pos.x < -STAR_BUF) stars[i].pos.x = gl_screen.w + STAR_BUF;
-    if(stars[i].pos.y > gl_screen.h + STAR_BUF) stars[i].pos.y = -STAR_BUF;
-    else if(stars[i].pos.y < -STAR_BUF) stars[i].pos.y = gl_screen.h + STAR_BUF;
+    if(stars[i].x > gl_screen.w + STAR_BUF) stars[i].x = -STAR_BUF;
+    else if(stars[i].x < -STAR_BUF) stars[i].x = gl_screen.w + STAR_BUF;
+    if(stars[i].y > gl_screen.h + STAR_BUF) stars[i].y = -STAR_BUF;
+    else if(stars[i].y < -STAR_BUF) stars[i].y = gl_screen.h + STAR_BUF;
     // Render.
     glColor4d(1., 1., 1., stars[i].brightness);
-    glVertex2d(stars[i].pos.x, stars[i].pos.y);
+    glVertex2d(stars[i].x, stars[i].y);
   }
   glEnd();
   glPopMatrix(); // Projection translation matrix.