You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
917 lines
25 KiB
917 lines
25 KiB
#include "draw.h" |
|
#include "environment.h" |
|
#include "game.h" |
|
#include "types.h" |
|
#include <SDL2/SDL_mutex.h> |
|
#include <SDL2/SDL_render.h> |
|
#include <time.h> |
|
|
|
Vect viewport_pos; |
|
int width, height; |
|
|
|
/* generic rendering functions */ |
|
int MAX_ONSCREEN_OBJECTS = 99; |
|
|
|
int num_onscreen = 0; |
|
|
|
double time_delta = 0; |
|
|
|
void render_texture_at(struct SDL_Renderer * ren, struct SDL_Texture * texture,int x, int y) { |
|
/* draw a texture at x.y */ |
|
|
|
SDL_Rect destination; |
|
destination.x = x; |
|
destination.y = y; |
|
|
|
SDL_QueryTexture(texture, NULL, NULL, &destination.w, &destination.h); |
|
|
|
SDL_RenderCopy(ren, texture, NULL, &destination); |
|
} |
|
|
|
|
|
double sigmoid(double x) { |
|
return exp(x) / (exp(x) + 1); |
|
} |
|
|
|
struct timespec get_now_d() { |
|
struct timespec now; |
|
clock_gettime(CLOCK_MONOTONIC, &now); |
|
if (now.tv_nsec >= 1000000000) { |
|
now.tv_nsec -= 1000000000; |
|
} |
|
return now; |
|
} |
|
|
|
Vect in_view(Vect V) { |
|
Vect ret; |
|
ret.x = V.x -viewport_pos.x; |
|
ret.y = V.y -viewport_pos.y; |
|
return ret; |
|
} |
|
|
|
/* Game Specific rendering functions */ |
|
void draw_player(SDL_Renderer * ren, int x, int y, bool red) { |
|
// translate to viewport |
|
|
|
Vect V; |
|
V.x = x; V.y = y; |
|
V = in_view(V); |
|
|
|
/* draw the player as a coloured rect */ |
|
SDL_Rect player_rect; |
|
|
|
player_rect.x = V.x -10; |
|
player_rect.y = V.y -10; |
|
|
|
player_rect.w = 20; |
|
player_rect.h = 20; |
|
|
|
struct colour c = get_scene_watch()->colours.bg; |
|
|
|
SDL_SetRenderDrawColor(ren, c.r, c.g, c.b, 255); |
|
|
|
SDL_RenderDrawRect(ren, &player_rect); |
|
SDL_RenderFillRect(ren, &player_rect); |
|
// draw strings |
|
for (int i = 0; i < player.physics->num_strings; i++) { |
|
if (!player.physics->strings[i].attached) { |
|
continue; |
|
} |
|
Vect B = {x, y}; |
|
B = in_view(B); |
|
Vect E; |
|
E = in_view(player.physics->strings[i].end_point); |
|
SDL_RenderDrawLine(ren, B.x, B.y, E.x, E.y); |
|
} |
|
|
|
|
|
SDL_SetRenderDrawColor(ren, 0,0,0, 255); |
|
|
|
} |
|
|
|
void draw_floor(SDL_Renderer *ren, FloorPoly *poly, bool down) { |
|
SDL_Point left; |
|
SDL_Point right; |
|
left.x = poly->left.x - viewport_pos.x; |
|
|
|
if (left.x > width) { |
|
return; |
|
} |
|
|
|
right.x = poly->right.x - viewport_pos.x; |
|
if (right.x < 0) { |
|
return; |
|
} |
|
|
|
left.y = poly->left.y - viewport_pos.y; |
|
right.y = poly->right.y - viewport_pos.y; |
|
|
|
if (left.y <= 0 && right.y <= 0) { |
|
return; |
|
} |
|
if (left.y >= height && right.y >= height) { |
|
return; |
|
} |
|
|
|
SDL_SetRenderDrawColor(ren, 100,100,100, 255); |
|
|
|
int end = down ? height : 0; |
|
|
|
double m = (double)(right.y - left.y) / (double)(right.x - left.x); |
|
double c = (double)left.y - ((double)left.x * m); |
|
|
|
for (int i = left.x; i <= right.x; i++) { |
|
int y = (int)(m * i + c); |
|
if (y > 0) { |
|
SDL_RenderDrawLine(ren, i, y, i, end); |
|
} |
|
} |
|
|
|
SDL_SetRenderDrawColor(ren, 0,0,0, 255); |
|
} |
|
|
|
// draw collision poly |
|
void draw_collision_poly(SDL_Renderer* ren, Body *body) { |
|
if (!SHOWCOLLISION) { |
|
return; |
|
} |
|
|
|
if (body->colliding) { |
|
SDL_SetRenderDrawColor(ren, 255, 0, 0, 255); |
|
} else { |
|
SDL_SetRenderDrawColor(ren, 0, 255, 0, 255); |
|
} |
|
|
|
// draw strings |
|
for (int i = 0; i < body->num_strings; i++) { |
|
if (!body->strings[i].attached) { |
|
continue; |
|
} |
|
Vect B; |
|
B = in_view(body->position); |
|
Vect E; |
|
E = in_view(body->strings[i].end_point); |
|
SDL_RenderDrawLine(ren, B.x, B.y, E.x, E.y); |
|
} |
|
|
|
if (body->collision_poly_size == 1) { |
|
SDL_Rect dot; |
|
Vect V; |
|
V.x = body->collision_poly[0].x; |
|
V.y = body->collision_poly[0].y; |
|
Vect T = in_view(V); |
|
dot.x = T.x; |
|
dot.y = T.y; |
|
dot.w = 4; |
|
dot.h = 4; |
|
SDL_RenderDrawRect(ren, &dot); |
|
SDL_RenderFillRect(ren, &dot); |
|
} else if (body->collision_poly_size == 2) { |
|
int x_st = body->collision_poly[0].x -viewport_pos.x; |
|
int y_st = body->collision_poly[0].y -viewport_pos.y; |
|
int x_en = body->collision_poly[1].x -viewport_pos.x; |
|
int y_en = body->collision_poly[1].y -viewport_pos.y; |
|
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en); |
|
} else if (body->collision_poly_size > 2) { |
|
int x_st = body->collision_poly[0].x -viewport_pos.x; |
|
int y_st = body->collision_poly[0].y -viewport_pos.y; |
|
int x_en, y_en; |
|
for (int i = 1; i < body->collision_poly_size; i++) { |
|
x_en = body->collision_poly[i].x -viewport_pos.x; |
|
y_en = body->collision_poly[i].y -viewport_pos.y; |
|
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en); |
|
x_st = x_en; |
|
y_st = y_en; |
|
} |
|
x_en = body->collision_poly[0].x-viewport_pos.x; |
|
y_en = body->collision_poly[0].y-viewport_pos.y; |
|
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en); |
|
} |
|
SDL_SetRenderDrawColor(ren, 0,0,0, 255); |
|
} |
|
|
|
// draw indicator of forces acting on an object |
|
void draw_forces(SDL_Renderer *ren, Body *body) { |
|
if (!SHOWFORCES) { |
|
return; |
|
} |
|
Vect start; |
|
start.x = (int)body->position.x -viewport_pos.x; |
|
start.y = (int)body->position.y -viewport_pos.y; |
|
|
|
Vect F; |
|
for (int i = 0; i < body->num_motors; i++) { |
|
if (!get_motor_active(body, i)) { |
|
continue; |
|
} |
|
F.x += body->motors[i].x; |
|
F.y += body->motors[i].y; |
|
Vect end = vect_add(start, F); |
|
SDL_SetRenderDrawColor(ren, 255,0,0, 255); |
|
SDL_RenderDrawLine(ren, start.x, start.y, start.x, end.y); |
|
SDL_SetRenderDrawColor(ren, 0,0,255, 255); |
|
SDL_RenderDrawLine(ren, start.x, start.y, end.x, start.y); |
|
} |
|
|
|
SDL_SetRenderDrawColor(ren, 0,0,0, 255); |
|
} |
|
|
|
void draw_wall(SDL_Renderer *ren, Wall *wall) { |
|
SDL_SetRenderDrawColor(ren, 120, 85, 188, 255); |
|
int x_st, x_en, y_st, y_en; |
|
x_st = wall->nodes[0].x + wall->physics->position.x -viewport_pos.x; |
|
y_st = wall->nodes[0].y + wall->physics->position.y -viewport_pos.y; |
|
for (int i = 1; i < wall->numNodes; i++) { |
|
x_en = wall->nodes[i].x + wall->physics->position.x -viewport_pos.x; |
|
y_en = wall->nodes[i].y + wall->physics->position.y -viewport_pos.y; |
|
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en); |
|
x_st = x_en; |
|
y_st = y_en; |
|
} |
|
x_en = wall->nodes[0].x + wall->physics->position.x -viewport_pos.x; |
|
y_en = wall->nodes[0].y + wall->physics->position.y -viewport_pos.y; |
|
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en); |
|
|
|
SDL_SetRenderDrawColor(ren, 0,0,0, 255); |
|
} |
|
|
|
int distance_colour(int x, int y, int x2, int y2, int blackpoint) { |
|
|
|
int dist = (int) sqrt((x2 - x)*(x2 - x) + (y2 - y)*(y2 - y) ); |
|
|
|
if (dist == 0) { |
|
return 255; |
|
} |
|
if (dist > blackpoint) { |
|
return 0; |
|
} |
|
|
|
int frac = blackpoint / dist; |
|
|
|
// int frac = 255 * (int) sin((double)dist / blackpoint); |
|
if (frac > 255) { |
|
return 255; |
|
} |
|
|
|
return frac; |
|
} |
|
|
|
void new_update_viewport(Body const * const pl) { |
|
int const xmargin = 100; // pixels |
|
int const ymargin = 100; // pixels |
|
int const xmovmagin = width / 4; |
|
int const ymovmagin = height / 3; |
|
double const xrange = width - (2 * xmargin); |
|
double const yrange = height - (2 * ymargin); |
|
double const x_max = 2; |
|
double const y_max = 3; |
|
static Vect target = {}; |
|
static double dirchange = 0; |
|
static Vect last_plpos = {}; |
|
if (last_plpos.x == 0 && last_plpos.y == 0) |
|
last_plpos = pl->position; |
|
|
|
static Vect lmove = {}; |
|
|
|
Vect iv = in_view(pl->position); |
|
|
|
Vect left_pos = {0, 2 * height / 4}; |
|
left_pos = vect_add(pl->position, vect_scalar(left_pos, -1)); |
|
|
|
Vect right_pos = {7 * (width / 8), 2 * height / 4}; |
|
right_pos = vect_add(pl->position, vect_scalar(right_pos, -1)); |
|
|
|
bool recover = false; |
|
|
|
Vect screen_dist = vect_add(in_view(pl->position), vect_scalar(lmove, -1)); |
|
|
|
static double swap = 0; |
|
if (iv.x > width |
|
|| (iv.x < 0 |
|
|| iv.y > height |
|
|| iv.y < 0)) |
|
recover = true; |
|
|
|
Vect delta = vect_add(vect_scalar(pl->position, -1), last_plpos); |
|
double dist_change = vect_mag(delta); |
|
if ((recover) //|| vect_mag((Vect){pl->vel.x, 0}) > 0.4 |
|
|| (dist_change > width / 100)) { |
|
if (iv.x < width / 6) { |
|
target = right_pos; |
|
} else { |
|
target = left_pos; |
|
} |
|
lmove = target; |
|
|
|
last_plpos = pl->position; |
|
} |
|
|
|
if (recover) |
|
viewport_pos = target; |
|
|
|
double v = pl->vel.x; |
|
if (v > x_max) |
|
v = x_max; |
|
if (v < -x_max) |
|
v = -x_max; |
|
if (v < 0) |
|
v = -v; |
|
|
|
// move towards target a set proportion |
|
Vect urgency = vect_add(target, vect_scalar(pl->position, -1)); |
|
Vect p = vect_add(target, vect_scalar(viewport_pos, -1)); |
|
|
|
double proportion = (sigmoid(time_delta) / 100); |
|
proportion = 2 * (pl->vel.x * pl->vel.x / (width)); |
|
proportion = proportion < 0 ? -proportion : proportion; |
|
|
|
proportion > 0.4 ? proportion = 0.4 : 0; |
|
proportion < 0 ? proportion = 0.000001 : 0; |
|
|
|
p = vect_scalar(p, proportion); |
|
viewport_pos = vect_add(viewport_pos, p); |
|
|
|
|
|
} |
|
|
|
void update_viewport(Body *pl) { |
|
float xmargin = 0.5; |
|
float ymargin = 0.2; |
|
|
|
if (pl->position.x - viewport_pos.x > (1-xmargin) * width) { |
|
viewport_pos.x = - ((1-xmargin) * width - pl->position.x); |
|
} |
|
|
|
if (pl->position.x - viewport_pos.x < xmargin * width) { |
|
viewport_pos.x = -(xmargin * width - pl->position.x); |
|
} |
|
|
|
if (pl->position.y - viewport_pos.y > (1-ymargin) * height) { |
|
viewport_pos.y = -((1-ymargin) * height - pl->position.y); |
|
} |
|
|
|
if (pl->position.y - viewport_pos.y < ymargin * height) { |
|
viewport_pos.y = -(ymargin * height - pl->position.y); |
|
} |
|
} |
|
|
|
void accel_update_viewport(Body *pl) { |
|
const double accel = 0.0001; |
|
const float xmargin = 0.5; |
|
const float ymargin = 0.2; |
|
|
|
static Vect target_pos = (Vect) {.x=0, .y=0}; |
|
static Vect vel = (Vect) {.x=0.0, .y=0.0}; |
|
|
|
|
|
if (pl->position.x - viewport_pos.x > (1-xmargin) * width) { |
|
target_pos.x = - ((1-xmargin) * width - pl->position.x); |
|
} |
|
|
|
if (pl->position.x - target_pos.x < xmargin * width) { |
|
target_pos.x = -(xmargin * width - pl->position.x); |
|
} |
|
|
|
if (pl->position.y - target_pos.y > (1-ymargin) * height) { |
|
target_pos.y = -((1-ymargin) * height - pl->position.y); |
|
} |
|
|
|
if (pl->position.y - target_pos.y < ymargin * height) { |
|
target_pos.y = -(ymargin * height - pl->position.y); |
|
} |
|
|
|
viewport_pos = target_pos; |
|
return; |
|
|
|
Vect delta = vect_add(target_pos, vect_scalar(viewport_pos, -1)); |
|
printf("d %f %f\n", delta.x, delta.y); |
|
printf("d %f\n", vect_mag(delta)); |
|
|
|
if ((vect_mag(delta) < 0.001 )) { |
|
return; |
|
} |
|
|
|
Vect dir = vect_scalar(delta, 1/vect_mag(delta)); |
|
Vect vel_delta = vect_scalar(dir, accel * time_delta); |
|
vel = vect_add(vel, vel_delta); |
|
|
|
Vect pos_delta = vect_scalar(vel, time_delta/2); |
|
|
|
viewport_pos = vect_add(viewport_pos, pos_delta); |
|
} |
|
|
|
double interpolate_h(Vect left, Vect right, double x) { |
|
static Vect v; |
|
|
|
double m = (double)(right.y - left.y) / (double)(right.x - left.x); |
|
double c = (double)left.y - ((double)left.x * m); |
|
|
|
return x * m + c; |
|
} |
|
|
|
void draw_environment(SDL_Renderer * ren, const struct environment *scene) { |
|
struct colour c1 = scene->colours.bg; |
|
struct colour c2 = scene->colours.fg1; |
|
struct colour c3 = scene->colours.fg2; |
|
struct colour c4 = scene->colours.fg3; |
|
|
|
// background colour |
|
SDL_SetRenderDrawColor(ren, c1.r, c1.g, c1.b, 255); |
|
|
|
SDL_Rect rect; |
|
rect.x = 0; |
|
rect.y = 0; |
|
rect.w = width; |
|
rect.h = height; |
|
SDL_RenderFillRect(ren, &rect); |
|
|
|
|
|
int k = 0; |
|
for (int i = 0; i < E_ROOM_TILES - 2; i++) { |
|
for (int j = 0; j < E_ROOM_RES; j++) { |
|
k++; |
|
Vect *left; |
|
Vect *right; |
|
|
|
int x = (i * E_ROOM_RES) + j; |
|
if (x - viewport_pos.x > width) { |
|
break; |
|
} |
|
if (x - viewport_pos.x < 0) { |
|
continue; |
|
} |
|
|
|
left = arlst_get(&scene->ceil, i); |
|
right = arlst_get(&scene->ceil, i+1); |
|
|
|
int y0 = interpolate_h(*left, *right, x) - viewport_pos.y; |
|
|
|
left = arlst_get(&scene->bg1, i); |
|
right = arlst_get(&scene->bg1, i+1); |
|
|
|
int y1 = interpolate_h(*left, *right, x) - viewport_pos.y; |
|
|
|
left = arlst_get(&scene->bg2, i); |
|
right = arlst_get(&scene->bg2, i+1); |
|
|
|
int y2 = interpolate_h(*left, *right, x) - viewport_pos.y; |
|
|
|
left = arlst_get(&scene->floor, i); |
|
right = arlst_get(&scene->floor, i+1); |
|
|
|
int y3 = interpolate_h(*left, *right, x) - viewport_pos.y; |
|
|
|
x = x - viewport_pos.x; |
|
|
|
// 3. bg2 to floor |
|
SDL_SetRenderDrawColor(ren, c4.r, c4.g, c4.b, 255); |
|
SDL_RenderDrawLine(ren, x, y2, x, y3); |
|
|
|
// 1. ceil to bg1 |
|
SDL_SetRenderDrawColor(ren, c2.r, c2.g, c2.b, 255); |
|
SDL_RenderDrawLine(ren, x, y0, x, y1); |
|
|
|
// 2. bg1 to bg2 |
|
SDL_SetRenderDrawColor(ren, c3.r, c3.g, c3.b, 255); |
|
SDL_RenderDrawLine(ren, x, y1, x, y2); |
|
|
|
|
|
|
|
} |
|
} |
|
} |
|
|
|
static TTF_Font *fonts[3]; |
|
|
|
void load_fonts(void) { |
|
fonts[0] = TTF_OpenFont("TerminusTTF.ttf", 22); |
|
fonts[1] = TTF_OpenFont("TerminusTTF.ttf", 66); |
|
const char *err = SDL_GetError(); |
|
if (err) { |
|
printf("%s\n", err); |
|
} |
|
} |
|
|
|
void draw_text(SDL_Renderer *ren, enum FontNames fontID, Vect pos, struct colour colour, char *text) { |
|
|
|
TTF_Font *font = fonts[fontID]; |
|
|
|
SDL_Colour sdl_col = {colour.r, colour.g, colour.b, 255}; |
|
SDL_Rect position = {.x = pos.x, .y = pos.y}; |
|
|
|
SDL_SetRenderDrawColor(ren, colour.r, colour.g, colour.b, 255); |
|
SDL_Surface *surf = TTF_RenderText_Solid(font, text, sdl_col); |
|
|
|
SDL_Texture *texture = SDL_CreateTextureFromSurface(ren, surf); |
|
SDL_QueryTexture(texture, NULL, NULL, &position.w, &position.h); |
|
SDL_RenderCopy(ren, texture, NULL, &position); |
|
|
|
SDL_DestroyTexture(texture); |
|
SDL_FreeSurface(surf); |
|
} |
|
|
|
|
|
void draw_text_default(SDL_Renderer *ren, Vect pos, struct colour colour, char *text) { |
|
TTF_Font* font = fonts[0]; |
|
|
|
SDL_Colour sdl_col = {colour.r, colour.g, colour.b, 255}; |
|
SDL_Rect position = {.x = pos.x, .y = pos.y}; |
|
|
|
SDL_SetRenderDrawColor(ren, colour.r, colour.g, colour.b, 255); |
|
SDL_Surface *surf = TTF_RenderText_Solid(font, text, sdl_col); |
|
|
|
SDL_Texture *texture = SDL_CreateTextureFromSurface(ren, surf); |
|
SDL_QueryTexture(texture, NULL, NULL, &position.w, &position.h); |
|
SDL_RenderCopy(ren, texture, NULL, &position); |
|
|
|
SDL_DestroyTexture(texture); |
|
SDL_FreeSurface(surf); |
|
|
|
} |
|
|
|
|
|
void draw_level_chooser_tbox(SDL_Renderer *ren) { |
|
|
|
char string[250]; |
|
snprintf(string, 250,"GOTO LEVEL: %s", gameui.currently_bound_textbox->text_input); |
|
|
|
const struct environment *scene = get_scene_watch(); |
|
|
|
Vect pos = {.x= width - (width / 4), .y = height - (height / 10)}; |
|
draw_text_default(ren, pos, scene->colours.fg1, string); |
|
} |
|
|
|
|
|
int draw_end_screen(SDL_Renderer *ren) { |
|
const struct environment *scene = get_scene_watch(); |
|
|
|
struct colour bg = scene->colours.bg; |
|
struct colour colour = scene->colours.fg1; |
|
struct colour_pallete pal = scene->colours; |
|
|
|
SDL_SetRenderDrawColor(ren, bg.r, bg.g, bg.b,255); |
|
|
|
SDL_RenderClear(ren); |
|
|
|
|
|
SDL_SetRenderDrawColor(ren, pal.fg2.r, pal.fg2.g, pal.fg2.b,255); |
|
for (int i = width - 300; i < width; i++) { |
|
SDL_RenderDrawLine(ren, i, height, width, height - i); |
|
if (!(i % 240)) { |
|
SDL_SetRenderDrawColor(ren, pal.fg3.r, pal.fg3.g, pal.fg3.b,255); |
|
} |
|
if (!(i % 350)) { |
|
SDL_SetRenderDrawColor(ren, pal.fg1.r, pal.fg1.g, pal.fg1.b,255); |
|
} |
|
} |
|
|
|
|
|
int margin = height / 10; |
|
|
|
long fastest = draw_watch.best_time; |
|
|
|
int minutes = level_time / 60000; |
|
float seconds = level_time * 0.001; |
|
char time_string[250]; |
|
|
|
|
|
char * end_str = "level over."; |
|
|
|
Vect position = {.x = width/4, .y = height / 4}; |
|
draw_text_default(ren, position, colour, end_str); |
|
position.y += 60; |
|
|
|
char level_string[250]; |
|
snprintf(level_string, 250,"course: %d", level); |
|
draw_text_default(ren, position, colour, level_string); |
|
position.y += 40; |
|
|
|
char fastest_time[250]; |
|
minutes = fastest / 60000; |
|
seconds = fastest * 0.001; |
|
if (fastest > 0) { |
|
snprintf(fastest_time, 250, "old best time: %d:%.4f", minutes, seconds); |
|
draw_text_default(ren, position, colour, fastest_time); |
|
position.y += 40; |
|
} |
|
|
|
|
|
minutes = level_time / 60000; |
|
seconds = level_time * 0.001; |
|
if (level_time > fastest) { |
|
// base time not set yet. |
|
snprintf(time_string, 250, "TIME: %d:%.4f", minutes, seconds); |
|
} else { |
|
snprintf(time_string, 250, "NEW BEST TIME: %d:%.4f", minutes, seconds); |
|
} |
|
|
|
Vect position2 = {.x = position.x + width/3, .y = 60 + height / 4}; |
|
|
|
if (fastest > 0) { |
|
//position.y += 40; |
|
long diff = level_time - fastest; |
|
char diff_str[250]; |
|
minutes = diff / 60000; |
|
seconds = diff * 0.001; |
|
if (minutes > 0) { |
|
snprintf(diff_str, 250, "DIFF: %d:%.4f", minutes, fabs(seconds)); |
|
} else { |
|
snprintf(diff_str, 250, "DIFF: %.4f s", seconds); |
|
} |
|
|
|
draw_text_default(ren, position2, colour, diff_str); |
|
position2.y += 40; |
|
} |
|
|
|
draw_text_default(ren, position2, colour, time_string); |
|
|
|
position.y += 200; |
|
char * ct_str = "press any key to continue"; |
|
draw_text_default(ren, position, colour, ct_str); |
|
|
|
SDL_RenderPresent(ren); |
|
return 0; |
|
} |
|
|
|
|
|
void draw_level_time(SDL_Renderer *ren, const struct environment * e) { |
|
|
|
int margin = height / 10; |
|
|
|
struct colour colour = e->colours.fg1; |
|
|
|
int minutes = level_time / 60000; |
|
float seconds = level_time * 0.001; |
|
char time_string[250]; |
|
snprintf(time_string, 250, "time: %d:%.4f", minutes, seconds); |
|
|
|
char level_string[250]; |
|
snprintf(level_string, 250,"course: %d", level); |
|
|
|
Vect position = {.x = margin, .y = height - margin}; |
|
draw_text_default(ren, position, colour, level_string); |
|
position.y += 40; |
|
draw_text_default(ren, position, colour, time_string); |
|
|
|
} |
|
void draw_mute_button(SDL_Renderer *ren) { |
|
|
|
struct colour c = get_scene_watch()->colours.fg1; |
|
struct colour i = get_scene_watch()->colours.bg; |
|
|
|
if (mute_button.held) { |
|
struct colour t = c; |
|
c = i; |
|
i = t; |
|
} |
|
|
|
|
|
SDL_Rect rect; |
|
|
|
rect.x = mute_button.x; |
|
rect.y = mute_button.y; |
|
rect.w = mute_button.w; |
|
rect.h = mute_button.h; |
|
|
|
|
|
SDL_SetRenderDrawColor(ren, c.r, c.g, c.b, 255); |
|
SDL_RenderFillRect(ren, &rect); |
|
|
|
rect.x += mute_button.w / 6; |
|
rect.y += mute_button.w / 4; |
|
rect.w = mute_button.w / 5; |
|
rect.h = mute_button.h / 2; |
|
|
|
SDL_SetRenderDrawColor(ren, i.r, i.g, i.b, 255); |
|
SDL_RenderFillRect(ren, &rect); |
|
|
|
int j = 0; |
|
for (int i = rect.x + rect.w; i < rect.x + rect.w + mute_button.w / 5; i++) { |
|
SDL_RenderDrawLine(ren, i, rect.y + j + rect.h, i, rect.y - j); |
|
j++; |
|
} |
|
|
|
j -= 8; |
|
if (!mute_button.state) { |
|
for (int i = rect.x + rect.w + mute_button.w / 5; |
|
i < mute_button.x + mute_button.w - 5; i++) { |
|
if ((i) % 8 < 4) { |
|
SDL_RenderDrawLine(ren, i, rect.y + j + rect.h, i, rect.y - j); |
|
} |
|
if (i % 8 == 0) j += 4; |
|
|
|
} |
|
} else { |
|
int w = mute_button.w / 5; |
|
int i = rect.x + rect.w + mute_button.w / 5 + w/2; |
|
int j = rect.y + w / 2; |
|
SDL_RenderDrawLine(ren, i, j + w, i + w, j); |
|
SDL_RenderDrawLine(ren, i + w, j + w, i, j); |
|
i += 1; |
|
SDL_RenderDrawLine(ren, i, j + w, i + w, j); |
|
SDL_RenderDrawLine(ren, i + w, j + w, i, j); |
|
i -= 1; |
|
|
|
j += 1; |
|
SDL_RenderDrawLine(ren, i, j + w, i + w, j); |
|
SDL_RenderDrawLine(ren, i + w, j + w, i, j); |
|
j -= 1; |
|
|
|
j += 1; |
|
i += 1; |
|
SDL_RenderDrawLine(ren, i, j + w, i + w, j); |
|
SDL_RenderDrawLine(ren, i + w, j + w, i, j); |
|
j -= 1; |
|
i -= 1; |
|
|
|
i -= 1; |
|
SDL_RenderDrawLine(ren, i, j + w, i + w, j); |
|
SDL_RenderDrawLine(ren, i + w, j + w, i, j); |
|
i += 1; |
|
|
|
j -= 1; |
|
SDL_RenderDrawLine(ren, i, j + w, i + w, j); |
|
SDL_RenderDrawLine(ren, i + w, j + w, i, j); |
|
j += 1; |
|
|
|
j -= 1; |
|
i -= 1; |
|
SDL_RenderDrawLine(ren, i, j + w, i + w, j); |
|
SDL_RenderDrawLine(ren, i + w, j + w, i, j); |
|
j += 1; |
|
i += 1; |
|
|
|
} |
|
|
|
|
|
} |
|
|
|
void draw_pause_screen(SDL_Renderer *ren, struct environment *e) { |
|
|
|
char *game_name[] = { |
|
"A_s", |
|
"Y_et", |
|
"U_ntitled", |
|
"G_ame", |
|
"I_nvolving", |
|
"a", |
|
"R_ock", |
|
"W_ith", |
|
"a", |
|
"G_rappling", |
|
"H_ook"}; |
|
|
|
char *te[] = { "GAME PAUSED.", |
|
"controls", |
|
"________", |
|
"pause/unpause: esc", |
|
"grapple and winch: left click", |
|
"grapple: right click", |
|
"go to level: g", |
|
"mute/unmute: m", |
|
"high contrast mode: h", |
|
"quit: q" |
|
}; |
|
|
|
struct colour textc = e->colours.fg1; |
|
struct colour bg = e->colours.bg; |
|
|
|
SDL_SetRenderDrawColor(ren, bg.r, bg.g, bg.b, 255); |
|
int boxwidth = 360; |
|
int boxheight = 388; |
|
int box_x = (2 * width / 3) - (boxwidth / 2); |
|
int box_y = (height - boxheight) / 2; |
|
SDL_Rect r = {.w = boxwidth, .h = boxheight, .x = box_x, .y = box_y}; |
|
SDL_RenderFillRect(ren, &r); |
|
|
|
Vect p = {.x = box_x + 10, .y = box_y + 10}; |
|
draw_text_default(ren, p, textc, te[0]); |
|
p.y += 60; |
|
|
|
draw_text_default(ren, p, textc, te[1]); |
|
p.y += 5; |
|
draw_text_default(ren, p, textc, te[2]); |
|
p.y += 35; |
|
|
|
draw_text_default(ren, p, textc, te[3]); |
|
p.y += 40; |
|
|
|
draw_text_default(ren, p, textc, te[4]); |
|
p.y += 40; |
|
|
|
draw_text_default(ren, p, textc, te[5]); |
|
p.y += 40; |
|
|
|
draw_text_default(ren, p, textc, te[6]); |
|
p.y += 40; |
|
|
|
draw_text_default(ren, p, textc, te[7]); |
|
p.y += 40; |
|
|
|
draw_text_default(ren, p, textc, te[8]); |
|
p.y += 40; |
|
|
|
draw_text_default(ren, p, textc, te[9]); |
|
p.y += 40; |
|
|
|
|
|
p.x = width / 8; |
|
p.y = height / 9; |
|
int arlen = sizeof(game_name) / sizeof(game_name[0]); |
|
for (int i = 0; i < arlen; i ++) { |
|
draw_text(ren, LARGE, p, textc, game_name[i]); |
|
p.y += 75; |
|
} |
|
|
|
} |
|
|
|
void redraw_buffer(SDL_Renderer * ren) { |
|
static int mousex = 0; |
|
static int mousey = 0; |
|
static int newmousex = 0; |
|
static int newmousey = 0; |
|
static SDL_Point *bgPixels[256]; |
|
static int numpixels[256]; |
|
|
|
int col = 0; |
|
Body lplayer; |
|
|
|
if (SDL_LockMutex(player.physics->lock) == 0){ |
|
lplayer = *player.physics; |
|
update_viewport(&lplayer); |
|
} else { |
|
return; |
|
} |
|
|
|
static struct timespec last = {}; |
|
static struct timespec now; |
|
now = get_now_d(); |
|
time_delta = now.tv_nsec - last.tv_nsec; |
|
time_delta *= 0.000001; // convert to ms from ns |
|
|
|
last = now; |
|
|
|
const struct environment* scene = get_scene_watch(); |
|
draw_environment(ren, scene); |
|
if (!game_paused) |
|
draw_level_time(ren, scene); |
|
SDL_UnlockMutex(player.physics->lock); |
|
|
|
for (int i=0; i < world.items.size; i++) { |
|
world_thing thing; |
|
thing = world.get(i); |
|
|
|
switch (thing.kind) { |
|
case STATIC_WALL_W: |
|
draw_wall(ren, thing.wall); |
|
draw_collision_poly(ren, thing.wall->physics); |
|
continue; |
|
case FLOOR: |
|
for (int i = 0; i < thing.floor->numPolys; i++) { |
|
draw_floor(ren, &thing.floor->polys[i], true); |
|
draw_collision_poly(ren, thing.floor->polys[i].physics); |
|
} |
|
continue; |
|
case CEILING: |
|
for (int i = 0; i < thing.floor->numPolys; i++) { |
|
draw_floor(ren, &thing.floor->polys[i], false); |
|
draw_collision_poly(ren, thing.floor->polys[i].physics); |
|
} |
|
continue; |
|
case ROOM_W: |
|
for (int i = 0; i < thing.room->ceil.numItems; i++) { |
|
draw_collision_poly(ren, thing.room->ceil.items[i]); |
|
} |
|
for (int i = 0; i < thing.room->floor.numItems; i++) { |
|
draw_collision_poly(ren, thing.room->floor.items[i]); |
|
} |
|
default: |
|
continue; |
|
} |
|
} |
|
|
|
draw_player(ren, lplayer.position.x, lplayer.position.y, |
|
lplayer.colliding); |
|
draw_collision_poly(ren, &lplayer); |
|
draw_forces(ren, &lplayer); |
|
draw_mute_button(ren); |
|
|
|
if (gameui.currently_bound_textbox) { |
|
draw_level_chooser_tbox(ren); |
|
} |
|
|
|
if (game_paused) { |
|
SDL_Rect r = {.x = 0, .y = 0, .w = width, .h = height}; |
|
SDL_SetRenderDrawColor(ren, 0, 0, 0, 90); |
|
SDL_RenderFillRect(ren, &r); |
|
if (in_game) |
|
draw_pause_screen(ren, scene); |
|
} |
|
|
|
if (draw_watch.goto_level && in_game == false) { |
|
Vect pos = {.x=width/3, .y=height- height/4}; |
|
draw_text(ren, LARGE, pos, scene->colours.fg1, "Press a Key to Continue"); |
|
} |
|
|
|
} |
|
|
|
|