void vnormal(float *v) { vscale(v,1.0/vlength(v)); }
/* * Given an axis and angle, compute quaternion. */ void axis_to_quat(double a[3] , double phi , double q[4]) { vnormal(a); vcopy(a, q); vscale(q, (double) sin(phi / 2.0f)); q[3] = (double) cos(phi / 2.0f); }
void vnormal(double *v) { vscale(v, 1.0f / vlength(v)); }
void DoFlares(GLfloat from[3], GLfloat at[3], GLfloat light[3], GLfloat near_clip) { GLfloat view_dir[3], tmp[3], light_dir[3], position[3], dx[3], dy[3], center[3], axis[3], sx[3], sy[3], dot, global_scale = 1.5; GLuint bound_to = 0; int i; /* view_dir = normalize(at-from) */ vdiff(view_dir, at, from); vnorm(view_dir); /* center = from + near_clip * view_dir */ vscale(tmp, view_dir, near_clip); vadd(center, from, tmp); /* light_dir = normalize(light-from) */ vdiff(light_dir, light, from); vnorm(light_dir); /* light = from + dot(light,view_dir)*near_clip*light_dir */ dot = vdot(light_dir, view_dir); vscale(tmp, light_dir, near_clip / dot); vadd(light, from, light_dir); /* axis = light - center */ vdiff(axis, light, center); vcopy(dx, axis); /* dx = normalize(axis) */ vnorm(dx); /* dy = cross(dx,view_dir) */ vcross(dy, dx, view_dir); glDisable(GL_DEPTH_TEST); glDisable(GL_DITHER); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); for (i = 0; i < num_flares; i++) { vscale(sx, dx, flare[i].scale * global_scale); vscale(sy, dy, flare[i].scale * global_scale); glColor3fv(flare[i].color); /* Note logic below to eliminate duplicate texture binds. */ if (flare[i].type < 0) { if (bound_to) glEnd(); glBindTexture(GL_TEXTURE_2D, shineTex[shine_tic]); bound_to = shineTex[shine_tic]; shine_tic = (shine_tic + 1) % 10; glBegin(GL_QUADS); } else { if (bound_to != flareTex[flare[i].type]) { glEnd(); glBindTexture(GL_TEXTURE_2D, flareTex[flare[i].type]); bound_to = flareTex[flare[i].type]; glBegin(GL_QUADS); } } /* position = center + flare[i].loc * axis */ vscale(tmp, axis, flare[i].loc); vadd(position, center, tmp); glTexCoord2f(0.0, 0.0); vadd(tmp, position, sx); vadd(tmp, tmp, sy); glVertex3fv(tmp); glTexCoord2f(1.0, 0.0); vdiff(tmp, position, sx); vadd(tmp, tmp, sy); glVertex3fv(tmp); glTexCoord2f(1.0, 1.0); vdiff(tmp, position, sx); vdiff(tmp, tmp, sy); glVertex3fv(tmp); glTexCoord2f(0.0, 1.0); vadd(tmp, position, sx); vdiff(tmp, tmp, sy); glVertex3fv(tmp); } glEnd(); }
void settle_sheet( tectonic_sheet *ts, size_t iterations, float dt, float equilibrium_distance, float spring_constant, int hold_edges ) { size_t iter, i, j; size_t idx, idx_a, idx_b, idx_c; size_t pw, ph; pw = sheet_pwidth(ts); ph = sheet_pheight(ts); vector *a, *b, *c; // the points of the current triangle vector *f; // the force on the current point vector tmp; // vector used for intermediate calculations for (iter = 0; iter < iterations; ++iter) { // First pass: compute forces by iterating over triangles in the sheet: for (i = 0; i < ts->width; ++i) { for (j = 0; j < ts->height; ++j) { idx_a = sheet_pidx_a(ts, i, j); idx_b = sheet_pidx_b(ts, i, j); idx_c = sheet_pidx_c(ts, i, j); a = &(ts->points[idx_a]); b = &(ts->points[idx_b]); c = &(ts->points[idx_c]); if (i % 2 == j % 2) { // if this triangle points up // All six forces on all three corners of this triangle: // a <- b f = &(ts->forces[idx_a]); spring_force(b, a, &tmp, equilibrium_distance, spring_constant); vadd_to(f, &tmp); // a <- c spring_force(c, a, &tmp, equilibrium_distance, spring_constant); vadd_to(f, &tmp); // b <- a f = &(ts->forces[idx_b]); spring_force(a, b, &tmp, equilibrium_distance, spring_constant); vadd_to(f, &tmp); // b <- c spring_force(c, b, &tmp, equilibrium_distance, spring_constant); vadd_to(f, &tmp); // c <- a f = &(ts->forces[idx_c]); spring_force(a, c, &tmp, equilibrium_distance, spring_constant); vadd_to(f, &tmp); // c <- b spring_force(b, c, &tmp, equilibrium_distance, spring_constant); vadd_to(f, &tmp); } else if (i == 0 && (j % 2 == 1)) { // Both forces on our a <-> b edge: // a <- b f = &(ts->forces[idx_a]); spring_force(b, a, &tmp, equilibrium_distance, spring_constant); vadd_to(f, &tmp); // b <- a f = &(ts->forces[idx_b]); spring_force(a, b, &tmp, equilibrium_distance, spring_constant); vadd_to(f, &tmp); } else if ((i == ts->width - 1) && (j % 2 == 0) ) { // Both forces on our a <-> c edge: // a <- c f = &(ts->forces[idx_a]); spring_force(c, a, &tmp, equilibrium_distance, spring_constant); vadd_to(f, &tmp); // c <- a f = &(ts->forces[idx_c]); spring_force(a, c, &tmp, equilibrium_distance, spring_constant); vadd_to(f, &tmp); } } } // Second pass: apply forces (iterating over points this time) for (i = 0; i < pw; ++i) { for (j = 0; j < ph; ++j) { idx = sheet_pidx(ts, i, j); f = &(ts->forces[idx]); if ( hold_edges && (i == 0 || i == pw - 1 || j == 0 || j == ph - 1) ) { vzero(f); continue; } vscale(f, dt); vadd_to(&(ts->points[idx]), f); vzero(f); } } } }
//----------------------------------------------------------------------------- void RunGame() { // Control main ship if (g_gs == GS_VICTORY || g_gs == GS_STARTING) { if (MAIN_SHIP.vel.y < SHIP_CRUISE_SPEED) { MAIN_SHIP.vel.y = SAFEADD(MAIN_SHIP.vel.y, SHIP_INC_SPEED, SHIP_CRUISE_SPEED); } MAIN_SHIP.fuel = SAFESUB(MAIN_SHIP.fuel, FRAME_FUEL_COST); } // Heal main ship if (g_gs != GS_DYING) { if (MAIN_SHIP.energy < MAX_ENERGY && MAIN_SHIP.fuel > MIN_FUEL_FOR_HEAL) { MAIN_SHIP.energy = SAFEADD(MAIN_SHIP.energy, ENERGY_HEAL_PER_FRAME, MAX_ENERGY); MAIN_SHIP.fuel = SAFESUB(MAIN_SHIP.fuel, FUEL_HEAL_PER_FRAME); LOG(("- energy: %f, fuel: %f\n", MAIN_SHIP.energy, MAIN_SHIP.fuel)); } } // Move entities for (int i = MAX_ENTITIES - 1; i >= 0; i--) { if (g_entities[i].type != E_NULL) { g_entities[i].pos = vadd(g_entities[i].pos, g_entities[i].vel); // Remove entities that fell off screen if (g_entities[i].pos.y < g_camera_offset - G_HEIGHT) g_entities[i].type = E_NULL; } } // Advance "stars" for (int i = 0; i < MAX_ENTITIES; i++) { if (g_entities[i].type == E_STAR) g_entities[i].gfxscale *= 1.008f; } // Dont let steering off the screen if (MAIN_SHIP.pos.x < MAINSHIP_RADIUS) MAIN_SHIP.pos.x = MAINSHIP_RADIUS; if (MAIN_SHIP.pos.x > G_WIDTH - MAINSHIP_RADIUS) MAIN_SHIP.pos.x = G_WIDTH - MAINSHIP_RADIUS; // Check collisions if (g_gs == GS_PLAYING) { // Check everything against ship for (int i = 1; i < MAX_ENTITIES; i++) { // Should check against ship? if (g_entities[i].type == E_ROCK || g_entities[i].type == E_JUICE || g_entities[i].type == E_MINE || g_entities[i].type == E_DRONE) { float distance = vlen2(vsub(g_entities[i].pos, MAIN_SHIP.pos)); // Distance from object to ship float crash_distance = CORE_FSquare(g_entities[i].radius + MAIN_SHIP.radius); // Minimum allowed distance before crash if (distance < crash_distance) { switch (g_entities[i].type) { case E_ROCK: if (g_entities[i].energy > 0) { MAIN_SHIP.energy = SAFESUB(MAIN_SHIP.energy, ROCK_CRASH_ENERGY_LOSS); MAIN_SHIP.vel.y = SHIP_START_SPEED; // Set rock velocity vec2 vel_direction = vsub(g_entities[i].pos, MAIN_SHIP.pos); // direction of rock velocity, away from ship vec2 normalized_vel_direction = vunit(vel_direction); // normalize vec2 vel = vscale(normalized_vel_direction, CRASH_VEL); // Scale, ie give the rock correct speed. g_entities[i].vel = vel; g_entities[i].energy = 0; } break; case E_JUICE: MAIN_SHIP.fuel = SAFEADD(MAIN_SHIP.fuel, JUICE_FUEL, MAX_FUEL); g_entities[i].type = E_NULL; break; case E_MINE: MAIN_SHIP.energy = SAFESUB(MAIN_SHIP.energy, MINE_CRASH_ENERGY_LOSS); MAIN_SHIP.vel.y = SHIP_START_SPEED; g_entities[i].type = E_NULL; break; case E_DRONE: MAIN_SHIP.energy = SAFESUB(MAIN_SHIP.energy, MINE_CRASH_ENERGY_LOSS); MAIN_SHIP.vel.y = SHIP_START_SPEED; g_entities[i].type = E_NULL; break; default: break; } } } else if (g_entities[i].type == E_ROCKET) { // Check all hit-able objects against this rocket for (int j = 1; i < MAX_ENTITIES; j++) { // Should check against rocket? if (g_entities[j].type == E_ROCK || g_entities[j].type == E_MINE || g_entities[j].type == E_DRONE) { float distance = vlen2(vsub(g_entities[i].pos, g_entities[j].pos)); float crash_distance = CORE_FSquare(g_entities[i].radius + g_entities[j].radius); if (distance < crash_distance) { // Impact! g_entities[i].type = E_NULL; g_entities[j].type = E_NULL; break; } } } } } } // Generate new level elements as we advance GenNextElements(); // Possibly insert new juice if (g_gs == GS_PLAYING) { float trench = MAIN_SHIP.pos.y - g_current_race_pos; // How much advanced from previous frame if (CORE_RandChance(trench * JUICE_CHANCE_PER_PIXEL)) { vec2 pos = vmake(CORE_FRand(0.f, G_WIDTH), g_camera_offset + G_HEIGHT + GEN_IN_ADVANCE); // Random x, insert 400y above window vec2 vel = vmake(CORE_FRand(-1.f, +1.f), CORE_FRand(-1.f, +1.f)); // Random small velocity to make rocks "float" InsertEntity(E_JUICE, pos, vel, JUICE_RADIUS, g_juice, false, true); } } // Set camera to follow the main ship g_camera_offset = MAIN_SHIP.pos.y - G_HEIGHT / 8.f; g_current_race_pos = MAIN_SHIP.pos.y; if (g_gs == GS_PLAYING) { if (g_current_race_pos >= RACE_END) // Check if victory { g_gs = GS_VICTORY; g_gs_timer = 0.f; MAIN_SHIP.gfxadditive = true; } } // Advance game mode g_gs_timer += FRAMETIME; switch (g_gs) { case GS_STARTING: if (g_gs_timer >= STARTING_TIME) // Start delay before starting to play { g_gs = GS_PLAYING; g_gs_timer = 0.f; } break; case GS_DYING: if (g_gs_timer >= DYING_TIME) { ResetNewGame(); } break; case GS_PLAYING: if (MAIN_SHIP.energy <= 0.f || MAIN_SHIP.fuel <= 0.f) // No energy or fuel --> die { g_gs = GS_DYING; g_gs_timer = 0.f; MAIN_SHIP.gfx = g_ship_RR; } break; case GS_VICTORY: if (CORE_RandChance(1.f / 10.f)) { InsertEntity(E_STAR, MAIN_SHIP.pos, vadd(MAIN_SHIP.vel, vmake(CORE_FRand(-5.f, 5.f), CORE_FRand(-5.f, 5.f))), 0, g_star, false, true); } if (g_gs_timer >= 8.f) // Should use VICTORY_TIME, but stupid VS dont want me to... { ResetNewGame(); } break; } g_time_from_last_rocket += FRAMETIME; }