-
-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: new tetris example from tinyc.games
just some minor adjustments on the small tetris implementation by @superjer and it runs smoothly in cjit, tested both on linux and windows
Showing
15 changed files
with
2,141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,354 @@ | ||
#include "tet.h" | ||
#include "utils.c" | ||
#include "font.c" | ||
|
||
#define VBUFLEN 40000 | ||
|
||
unsigned main_prog_id; | ||
GLuint main_vao; | ||
GLuint main_vbo; | ||
float vbuf[VBUFLEN]; | ||
int vbuf_n; | ||
float color_r, color_g, color_b; | ||
|
||
// render a line of text optionally with a %d value in it | ||
void text(char *fstr, int value) | ||
{ | ||
if (!fstr) return; | ||
char str[100]; | ||
snprintf(str, 99, fstr, value); | ||
font_begin(win_x, win_y); | ||
font_add_text(str, text_x, text_y, 3 * bs / 4); | ||
font_end(1, 1, 1); | ||
text_y += bs * 125 / 100 + (fstr[strlen(fstr) - 1] == ' ' ? bs : 0); | ||
} | ||
|
||
void draw_setup() | ||
{ | ||
fprintf(stderr, "GLSL version on this system is %s\n", (char *)glGetString(GL_SHADING_LANGUAGE_VERSION)); | ||
unsigned int vertex = file2shader(GL_VERTEX_SHADER, "examples/tetris/shaders/main.vert"); | ||
unsigned int fragment = file2shader(GL_FRAGMENT_SHADER, "examples/tetris/shaders/main.frag"); | ||
main_prog_id = glCreateProgram(); | ||
glAttachShader(main_prog_id, vertex); | ||
glAttachShader(main_prog_id, fragment); | ||
glLinkProgram(main_prog_id); | ||
check_program_errors(main_prog_id, "main"); | ||
glDeleteShader(vertex); | ||
glDeleteShader(fragment); | ||
glGenVertexArrays(1, &main_vao); | ||
glGenBuffers(1, &main_vbo); | ||
} | ||
|
||
void vertex(float x, float y, float r, float g, float b) | ||
{ | ||
if (vbuf_n >= VBUFLEN - 5) return; | ||
vbuf[vbuf_n++] = x; | ||
vbuf[vbuf_n++] = y; | ||
vbuf[vbuf_n++] = r; | ||
vbuf[vbuf_n++] = g; | ||
vbuf[vbuf_n++] = b; | ||
} | ||
|
||
void rect(float x, float y, float w, float h) | ||
{ | ||
vertex(x , y , color_r, color_g, color_b); | ||
vertex(x + w, y , color_r, color_g, color_b); | ||
vertex(x , y + h, color_r, color_g, color_b); | ||
vertex(x , y + h, color_r, color_g, color_b); | ||
vertex(x + w, y , color_r, color_g, color_b); | ||
vertex(x + w, y + h, color_r, color_g, color_b); | ||
} | ||
|
||
void draw_start() | ||
{ | ||
glViewport(0, 0, win_x, win_y); | ||
glClear(GL_COLOR_BUFFER_BIT); | ||
} | ||
|
||
void draw_end() | ||
{ | ||
glUseProgram(main_prog_id); | ||
|
||
float near = -1.f; | ||
float far = 1.f; | ||
float x = 1.f / (win_x / 2.f); | ||
float y = -1.f / (win_y / 2.f); | ||
float z = -1.f / ((far - near) / 2.f); | ||
float tz = -(far + near) / (far - near); | ||
float ortho[] = { | ||
x, 0, 0, 0, | ||
0, y, 0, 0, | ||
0, 0, z, 0, | ||
-1, 1, tz, 1, | ||
}; | ||
glUniformMatrix4fv(glGetUniformLocation(main_prog_id, "proj"), 1, GL_FALSE, ortho); | ||
|
||
glBindVertexArray(main_vao); | ||
glBindBuffer(GL_ARRAY_BUFFER, main_vbo); | ||
glBufferData(GL_ARRAY_BUFFER, sizeof vbuf, vbuf, GL_STATIC_DRAW); | ||
|
||
// show GL where the position data is | ||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0); | ||
glEnableVertexAttribArray(0); | ||
|
||
// show GL where the color data is | ||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(2 * sizeof(float))); | ||
glEnableVertexAttribArray(1); | ||
|
||
glDrawArrays(GL_TRIANGLES, 0, vbuf_n / 5); | ||
if (vbuf_n > VBUFLEN * 3 / 4) | ||
fprintf(stderr, "vbuf fullness (%d/%d)\n", vbuf_n, VBUFLEN); | ||
vbuf_n = 0; | ||
} | ||
|
||
// set the current draw color to the color assoc. with a shape | ||
void set_color_from_shape(int shape, int shade) | ||
{ | ||
color_r = MAX((colors[shape] >> 16 & 0xFF) + shade, 0) / 255.f; | ||
color_g = MAX((colors[shape] >> 8 & 0xFF) + shade, 0) / 255.f; | ||
color_b = MAX((colors[shape] >> 0 & 0xFF) + shade, 0) / 255.f; | ||
} | ||
|
||
void set_color(int r, int g, int b) | ||
{ | ||
color_r = r / 255.f; | ||
color_g = g / 255.f; | ||
color_b = b / 255.f; | ||
} | ||
|
||
void draw_menu() | ||
{ | ||
if (state != MAIN_MENU && state != NUMBER_MENU) return; | ||
|
||
menu_pos = MAX(menu_pos, 0); | ||
menu_pos = MIN(menu_pos, state == NUMBER_MENU ? 3 : 2); | ||
p = play; // just grab first player :) | ||
|
||
set_color(0, 0, 0); | ||
rect(p->held.x, | ||
p->held.y + p->box_w + bs2 + line_height * (menu_pos + 1), | ||
p->board_w, | ||
line_height); | ||
draw_end(); | ||
|
||
text_x = p->held.x; | ||
text_y = p->held.y + p->box_w + bs2; | ||
if (state == MAIN_MENU) | ||
{ | ||
text("Main Menu" , 0); | ||
text("Endless" , 0); | ||
text("Garbage Race" , 0); | ||
text("Quit" , 0); | ||
} | ||
else if (state == NUMBER_MENU) | ||
{ | ||
text("How many players?", 0); | ||
text("1" , 0); | ||
text("2" , 0); | ||
text("3" , 0); | ||
text("4" , 0); | ||
} | ||
} | ||
|
||
void draw_particles() | ||
{ | ||
set_color(254, 254, 254); | ||
for (int i = 0; i < NPARTS; i++) | ||
{ | ||
if (parts[i].r <= 0.5f) | ||
continue; | ||
rect(parts[i].x, parts[i].y, parts[i].r, parts[i].r); | ||
} | ||
} | ||
|
||
// draw a single mino (square) of a shape | ||
void draw_mino(int x, int y, int shape, int outline, int part) | ||
{ | ||
if (!part) return; | ||
int bw = MAX(1, outline ? bs / 10 : bs / 6); | ||
set_color_from_shape(shape, -50); | ||
rect(x, y, bs, bs); | ||
set_color_from_shape(shape, outline ? -255 : 0); | ||
rect( // horizontal band | ||
x + (part & 8 ? 0 : bw), | ||
y + bw, | ||
bs - (part & 8 ? 0 : bw) - (part & 2 ? 0 : bw), | ||
bs - bw - bw); | ||
rect( // vertical band | ||
x + (part & 32 ? 0 : bw), | ||
y + (part & 1 ? 0 : bw), | ||
bs - (part & 32 ? 0 : bw) - (part & 16 ? 0 : bw), | ||
bs - (part & 1 ? 0 : bw) - (part & 4 ? 0 : bw)); | ||
} | ||
|
||
#define CENTER 1 | ||
#define OUTLINE 2 | ||
|
||
void draw_shape(int x, int y, int color, int rot, int flags) | ||
{ | ||
for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) | ||
draw_mino( | ||
x + bs * i + ((flags & CENTER) ? bs2 + bs2 * center[2 * color ] : 0), | ||
y + bs * j + ((flags & CENTER) ? bs + bs2 * center[2 * color + 1] : 0), | ||
color, | ||
flags & OUTLINE, | ||
is_solid_part(color, rot, i, j) | ||
); | ||
} | ||
|
||
// draw everything in the game on the screen for current player | ||
void draw_player() | ||
{ | ||
if (state == MAIN_MENU || state == NUMBER_MENU) return; | ||
|
||
int x = p->board_x + bs * p->shake_x; | ||
int y = p->board_y + bs * p->shake_y; | ||
|
||
// draw background, black boxes | ||
set_color(16, 26, 24); | ||
rect(p->held.x, p->held.y, p->box_w, p->box_w); | ||
rect(x, y, p->board_w, bs * VHEIGHT); | ||
|
||
// find ghost piece position | ||
int ghost_y = p->it.y; | ||
while (ghost_y < BHEIGHT && !collide(p->it.x, ghost_y + 1, p->it.rot)) | ||
ghost_y++; | ||
|
||
// draw shadow | ||
if (p->it.color) | ||
{ | ||
struct shadow shadow = shadows[p->it.rot][p->it.color]; | ||
int top = MAX(0, p->it.y + shadow.y - 5); | ||
set_color(8, 13, 12); | ||
rect(x + bs * (p->it.x + shadow.x), | ||
y + bs * top, | ||
bs * shadow.w, | ||
MAX(0, bs * (ghost_y - top + shadow.y - 5))); | ||
} | ||
|
||
// draw hard drop beam | ||
float loss = .1f * (tick - p->beam_tick); | ||
if (loss < 1.f && p->beam.color) | ||
{ | ||
struct shadow shadow = shadows[p->beam.rot][p->beam.color]; | ||
int rw = bs * shadow.w; | ||
int rh = bs * (p->beam.y + shadow.y - 5); | ||
int lossw = (1.f - ((1.f - loss) * (1.f - loss))) * rw; | ||
int lossh = loss < .5f ? 0.f : (1.f - ((1.f - loss) * (1.f - loss))) * rh; | ||
set_color(66, 74, 86); | ||
rect(x + bs * (p->beam.x + shadow.x) + lossw / 2, | ||
y + lossh, | ||
rw - lossw, | ||
rh - lossh); | ||
} | ||
|
||
// draw pieces on board | ||
for (int i = 0; i < BWIDTH; i++) for (int j = 0; j < BHEIGHT; j++) | ||
draw_mino(x + bs * i, y + bs * (j-5) - p->row[j].offset, | ||
p->row[j].col[i].color, 0, p->row[j].col[i].part); | ||
|
||
// draw queued garbage | ||
p->top_garb = y + bs * VHEIGHT; | ||
int garb_height = 0; | ||
for (int i = 0; i < GARB_LVLS; i++) | ||
for (int j = 0; j < p->garbage[i]; j++) | ||
{ | ||
draw_mino(x - 3 * bs2, (p->top_garb -= bs), (3 - i) + 9, 0, '@'); | ||
garb_height++; | ||
} | ||
if (p->flash > 8) | ||
{ | ||
int flash_sq = p->flash * p->flash; | ||
set_color(flash_sq, flash_sq, flash_sq); | ||
rect(x - 3 * bs2 - bs4, p->top_garb - bs4, bs + bs4 + bs4, garb_height * bs + bs2); | ||
} | ||
p->top_garb = y + bs * VHEIGHT; | ||
for (int i = 0; i < GARB_LVLS; i++) | ||
for (int j = 0; j < p->garbage[i]; j++) | ||
draw_mino(x - 3 * bs2, (p->top_garb -= bs), (3 - i) + 9, 0, '@'); | ||
|
||
// draw falling piece & ghost | ||
draw_shape(x + bs * p->it.x, y + bs * (ghost_y - 5), p->it.color, p->it.rot, OUTLINE); | ||
draw_shape(x + bs * p->it.x, y + bs * (p->it.y - 5), p->it.color, p->it.rot, 0); | ||
|
||
// draw next pieces | ||
for (int n = 0; n < 5; n++) | ||
draw_shape(p->preview_x, p->preview_y + 3 * bs * n, p->next[n], 0, CENTER); | ||
|
||
// draw held piece | ||
draw_shape(p->held.x, p->held.y, p->held.color, 0, CENTER); | ||
|
||
draw_end(); | ||
|
||
// draw scores etc | ||
text_x = p->held.x; | ||
text_y = p->held.y + p->box_w + bs2; | ||
text("%d pts ", p->score); | ||
text("%d lines ", p->lines); | ||
|
||
int secs = p->ticks / 120 % 60; | ||
int mins = p->ticks / 120 / 60 % 60; | ||
char minsec[80]; | ||
sprintf(minsec, "%d:%02d.%02d ", mins, secs, p->ticks % 120 * 1000 / 1200); | ||
text(minsec, 0); | ||
text(p->dev_name, 0); | ||
if (p->combo > 1) text("%d combo ", p->combo); | ||
if (p->tspin == TSPIN_FULL) | ||
text("T-SPIN", 0); | ||
else if (p->tspin == TSPIN_MINI) | ||
text("T-SPIN MINI", 0); | ||
|
||
if (p->reward) | ||
{ | ||
text_x = p->reward_x - bs; | ||
text_y = p->reward_y--; | ||
text("%d", p->reward); | ||
} | ||
|
||
text_x = x + bs2; | ||
text_y = y + bs2 * 19; | ||
if (p->countdown_time > 0) | ||
text(countdown_msg[p->countdown_time / CTDN_TICKS], 0); | ||
|
||
if (state == ASSIGN) | ||
text(p >= play + assign_me ? "Press button to join" : p->dev_name, 0); | ||
|
||
if (state == GAMEOVER) text("Game over", 0); | ||
} | ||
|
||
void reflow() | ||
{ | ||
float strength = 0.0005f * (1 + rand() % 10); | ||
for (int n = 0; n < NFLOWS; n++) | ||
{ | ||
flows[n].x = rand() % win_x; | ||
flows[n].y = rand() % win_y; | ||
flows[n].r = rand() % 100 + 100; | ||
flows[n].vx = (rand() % 10 - 5) * strength; | ||
flows[n].vy = (rand() % 10 - 5) * strength; | ||
} | ||
} | ||
|
||
// recalculate sizes and positions on resize | ||
void resize(int x, int y) | ||
{ | ||
win_x = x; | ||
win_y = y; | ||
bs = MIN(win_x / (nplay * 22), win_y / 24); | ||
bs2 = bs / 2; | ||
bs4 = bs / 4; | ||
line_height = bs * 125 / 100; | ||
int n = 0; | ||
for (p = play; p < play + nplay; p++, n++) | ||
{ | ||
p->board_x = (x / (nplay * 2)) * (2 * n + 1) - bs2 * BWIDTH; | ||
p->board_y = (y / 2) - bs2 * VHEIGHT; | ||
p->board_w = bs * 10; | ||
p->box_w = bs * 5; | ||
p->held.x = p->board_x - p->box_w - bs2; | ||
p->held.y = p->board_y; | ||
p->preview_x = p->board_x + p->board_w + bs2; | ||
p->preview_y = p->board_y; | ||
} | ||
reflow(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
#include "tet.h" | ||
#include <audio.h> | ||
|
||
#define WASD -1 | ||
#define ARROW_KEYS -2 | ||
|
||
void resize(int, int); | ||
|
||
void down() | ||
{ | ||
p->down = 1; | ||
p->move_cooldown = 0; | ||
} | ||
|
||
void left() | ||
{ | ||
p->left = 1; | ||
p->move_cooldown = 0; | ||
} | ||
|
||
void right() | ||
{ | ||
p->right = 1; | ||
p->move_cooldown = 0; | ||
} | ||
|
||
// spin the falling piece left or right, if possible | ||
void spin(int dir) | ||
{ | ||
int new_rot = (p->it.rot + dir) % 4; | ||
int k = new_rot * 20 + (dir == 1 ? 0 : 10) + (p->it.color == 4 ? 80 : 0); | ||
|
||
for (int i = 0; i < 5; i++) | ||
{ | ||
int kx = kicks[k++]; | ||
int ky = kicks[k++]; | ||
if (!collide(p->it.x + kx, p->it.y + ky, new_rot)) | ||
{ | ||
p->it.rot = new_rot; | ||
p->it.x += kx; | ||
p->it.y += ky; | ||
if (p->grounded && p->grounded_moves < 15) | ||
{ | ||
p->idle_time = 0; | ||
p->grounded_moves++; | ||
} | ||
audio_tone(TRIANGLE, C5, B5, 1, 1, 1, 1); | ||
return; | ||
} | ||
} | ||
audio_tone(SQUARE, C5, B5, 1, 1, 1, 1); | ||
} | ||
|
||
// move the falling piece as far down as it will go | ||
void hard() | ||
{ | ||
for (; !collide(p->it.x, p->it.y + 1, p->it.rot); p->it.y++) | ||
p->score++; | ||
p->idle_time = 100; | ||
p->beam = p->it; | ||
p->beam_tick = tick; | ||
p->shake_y += .25f; | ||
audio_tone(TRIANGLE, A1, E3, 5, 5, 5, 90); | ||
} | ||
|
||
// hold a piece for later | ||
void hold() | ||
{ | ||
if (p->hold_uses++) return; | ||
SWAP(p->held.color, p->it.color); | ||
reset_fall(); | ||
} | ||
|
||
void joy_setup() | ||
{ | ||
for (int i = 0; i < SDL_NumJoysticks(); i++) | ||
{ | ||
if (!SDL_IsGameController(i)) | ||
{ | ||
printf("Controller not supported: %s", SDL_JoystickNameForIndex(i)); | ||
printf(" - Google SDL_GAMECONTROLLERCONFIG to fix this\n"); | ||
continue; | ||
} | ||
SDL_GameController *cont = SDL_GameControllerOpen(i); | ||
printf("Controller added: %s %p\n", SDL_GameControllerNameForIndex(i), (void*)cont); | ||
} | ||
SDL_GameControllerEventState(SDL_ENABLE); | ||
} | ||
|
||
// set current player to match an input device | ||
void set_player_from_device(int device) | ||
{ | ||
for (int i = 0; i < NPLAY; i++) | ||
{ | ||
if (play[i].device < 0) | ||
p = play + i; // default to any keyboard | ||
|
||
if (play[i].device == device) | ||
{ | ||
p = play + i; | ||
return; | ||
} | ||
} | ||
} | ||
|
||
// figure out which "device" from key pressed, i.e. WASD or Arrow keys | ||
int device_from_key() | ||
{ | ||
switch(event.key.keysym.sym) { | ||
case SDLK_w: case SDLK_a: case SDLK_s: case SDLK_d: case SDLK_z: case SDLK_x: | ||
case SDLK_TAB: case SDLK_CAPSLOCK: case SDLK_LSHIFT: | ||
return WASD; | ||
default: | ||
return ARROW_KEYS; | ||
} | ||
} | ||
|
||
int menu_input(int key_or_button) | ||
{ | ||
switch (key_or_button) | ||
{ | ||
case SDLK_s: case SDLK_DOWN: | ||
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: menu_pos++; break; | ||
|
||
case SDLK_w: case SDLK_UP: | ||
case SDL_CONTROLLER_BUTTON_DPAD_UP: menu_pos--; break; | ||
|
||
case SDLK_RETURN: case SDLK_z: | ||
case SDL_CONTROLLER_BUTTON_A: | ||
if (state == MAIN_MENU) | ||
{ | ||
if (menu_pos == 0) garbage_race = 0; | ||
if (menu_pos == 1) garbage_race = 1; | ||
if (menu_pos == 2) exit(0); | ||
state = NUMBER_MENU; | ||
menu_pos = 0; | ||
} | ||
else | ||
{ | ||
nplay = menu_pos + 1; | ||
resize(win_x, win_y); | ||
state = ASSIGN; | ||
assign_me = 0; | ||
} | ||
break; | ||
} | ||
return 0; | ||
} | ||
|
||
int assign(int device) | ||
{ | ||
for (int i = 0; i < assign_me; i++) | ||
if (play[i].device == device) | ||
return 0; | ||
|
||
play[assign_me].device = device; | ||
sprintf(play[assign_me].dev_name, "%.10s", | ||
device == WASD ? "WASD keys" : | ||
device == ARROW_KEYS ? "Arrow keys" : | ||
SDL_GameControllerName(SDL_GameControllerFromInstanceID(device))); | ||
|
||
if (++assign_me == nplay) | ||
{ | ||
state = PLAY; | ||
assign_me = 0; | ||
seed = rand(); | ||
for (p = play; p < play + nplay; p++) | ||
new_game(); | ||
} | ||
return 0; | ||
} | ||
|
||
// handle a key press from a player | ||
int key_down() | ||
{ | ||
if (event.key.repeat) return 0; | ||
if (state == MAIN_MENU || state == NUMBER_MENU) return menu_input(event.key.keysym.sym); | ||
if (state == GAMEOVER) return (state = MAIN_MENU); | ||
if (state == ASSIGN) return assign(device_from_key()); | ||
|
||
set_player_from_device(device_from_key()); | ||
|
||
if (!p->it.color || p->countdown_time >= CTDN_TICKS) return 0; | ||
|
||
switch (event.key.keysym.sym) | ||
{ | ||
case SDLK_a: case SDLK_LEFT: left(); break; | ||
case SDLK_s: case SDLK_DOWN: down(); break; | ||
case SDLK_d: case SDLK_RIGHT: right(); break; | ||
|
||
case SDLK_w: case SDLK_UP: hard(); break; | ||
case SDLK_z: case SDLK_CAPSLOCK: case SDLK_COMMA: spin(3); break; | ||
case SDLK_x: case SDLK_LSHIFT: case SDLK_PERIOD: spin(1); break; | ||
case SDLK_TAB: case SDLK_SLASH: hold(); break; | ||
|
||
case SDLK_l: | ||
p->level++; | ||
p->lines += 10; | ||
break; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
void key_up() | ||
{ | ||
if (state == ASSIGN) return; | ||
set_player_from_device(device_from_key()); | ||
|
||
switch (event.key.keysym.sym) | ||
{ | ||
case SDLK_a: case SDLK_LEFT: p->left = 0; break; | ||
case SDLK_d: case SDLK_RIGHT: p->right = 0; break; | ||
case SDLK_s: case SDLK_DOWN: p->down = 0; break; | ||
} | ||
} | ||
|
||
int joy_down() | ||
{ | ||
if (state == ASSIGN) return assign(event.cbutton.which); | ||
if (state == GAMEOVER) return (state = MAIN_MENU); | ||
if (state == MAIN_MENU || state == NUMBER_MENU) return menu_input(event.cbutton.button); | ||
set_player_from_device(event.cbutton.which); | ||
|
||
if (p->it.color) switch(event.cbutton.button) | ||
{ | ||
case SDL_CONTROLLER_BUTTON_A: spin(3); break; | ||
case SDL_CONTROLLER_BUTTON_B: spin(1); break; | ||
case SDL_CONTROLLER_BUTTON_DPAD_UP: hard(); break; | ||
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: down(); break; | ||
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: left(); break; | ||
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: right(); break; | ||
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: hold(); break; | ||
} | ||
return 0; | ||
} | ||
|
||
void joy_up() | ||
{ | ||
if (state == ASSIGN) return; | ||
set_player_from_device(event.cbutton.which); | ||
|
||
switch(event.cbutton.button) | ||
{ | ||
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: p->down = 0; break; | ||
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: p->left = 0; break; | ||
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: p->right = 0; break; | ||
} | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#version 330 core | ||
in vec3 color2; | ||
|
||
out vec4 color; | ||
|
||
void main() | ||
{ | ||
color = vec4(color2.xyz, 1.0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#version 330 core | ||
layout (location = 0) in vec2 pos; | ||
layout (location = 1) in vec3 color; | ||
|
||
out vec3 color2; | ||
|
||
uniform mat4 proj; | ||
|
||
void main() | ||
{ | ||
gl_Position = proj * vec4(pos.xy, 0.0, 1.0); | ||
color2 = color; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
#pragma once | ||
#include <SDL2/SDL.h> | ||
|
||
#define GL3_PROTOTYPES 1 | ||
|
||
#ifdef __APPLE__ | ||
#include <OpenGL/gl3.h> | ||
#else | ||
#include <GL/glew.h> | ||
#endif | ||
|
||
#define BWIDTH 10 // board width, height | ||
#define BHEIGHT 25 | ||
#define VHEIGHT 20 // visible height | ||
#define BAG_SZ 7 // bag size | ||
#define GARB_LVLS 4 // levels of queued garbage | ||
#define NPLAY 4 | ||
#define NPARTS 1000 | ||
#define NFLOWS 20 | ||
#define CTDN_TICKS 96 | ||
#define SHOW_FPS 0 | ||
|
||
// collision test results | ||
enum { NONE = 0, WALL, NORMAL }; | ||
|
||
enum { TSPIN_NONE = 0, TSPIN_FULL, TSPIN_MINI }; | ||
|
||
// Bits in each letter indicate which sides connect when drawing | ||
// A 1000001 - up | ||
// B 1000010 - right | ||
// D 1000100 - down | ||
// H 1001000 - left | ||
// 1010000 - connect left corner where up or down connects - for square piece | ||
// 1100000 - ... right ... | ||
|
||
char shapes[] = | ||
".... D... ..D. .Vl. .... BL.. .FH. ;D;. " | ||
".... CJH. BJI. .Si. BJJH .CH. BI.. BKH. " | ||
".... .... .... .... .... .... .... ,.,. " | ||
".... .... .... .... .... .... .... .... " | ||
|
||
".... .FH. .D.. .Vl. ..D. ..D. .D.. ,D;. " | ||
".... .E.. .E.. .Si. ..E. .FI. .CL. .GH. " | ||
".... .A.. .CH. .... ..E. .A.. ..A. ,A;. " | ||
".... .... .... .... ..A. .... .... .... " | ||
|
||
".... .... .... .Vl. .... .... .... ,.,. " | ||
".... BJL. FJH. .Si. .... BL.. .FH. BNH. " | ||
".... ..A. A... .... BJJH .CH. BI.. ;A;. " | ||
".... .... .... .... .... .... .... .... " | ||
|
||
".... .D.. BL.. .Vl. .D.. .D.. D... ;D,. " | ||
".... .E.. .E.. .Si. .E.. FI.. CL.. BM.. " | ||
".... BI.. .A.. .... .E.. A... .A.. ;A,. " | ||
".... .... .... .... .A.. .... .... .... "; | ||
|
||
struct shadow { int x, w, y; } shadows[4][8] = { // pre-computed shadow positions for each piece | ||
{{0,0,0}, {0,3,1}, {0,3,1}, {1,2,0}, {0,4,1}, {0,3,1}, {0,3,1}, {0,3,1}}, | ||
{{0,0,0}, {1,2,0}, {1,2,2}, {1,2,0}, {2,1,0}, {1,2,1}, {1,2,1}, {1,2,1}}, | ||
{{0,0,0}, {0,3,1}, {0,3,1}, {1,2,0}, {0,4,2}, {0,3,2}, {0,3,2}, {0,3,1}}, | ||
{{0,0,0}, {0,2,2}, {0,2,0}, {1,2,0}, {1,1,0}, {0,2,1}, {0,2,1}, {0,2,1}}, | ||
}; | ||
|
||
// helps center shapes in preview box | ||
int center[] = {0,0, 1,1, 1,1, 0,1, 0,0, 1,1, 1,1, 1,1}; | ||
|
||
int colors[] = { | ||
0x000000, // unused | ||
0x1983c4, // J | ||
0xfa8333, // L | ||
0xffca39, // square | ||
0x1be7ff, // line | ||
0xff5a5f, // Z | ||
0x89c926, // S | ||
0x88488f, // T | ||
0xffffff, // shine color | ||
0x6f7866, // garbage colors | ||
0x9fa896, | ||
0xffca39, | ||
0xff5a5f, | ||
}; | ||
|
||
int kicks[] = { // clockwise counterclockwise | ||
0,0, -1, 0, -1, 1, 0,-2, -1,-2, 0,0, 1, 0, 1, 1, 0,-2, 1,-2, // rot 0 | ||
0,0, -1, 0, -1,-1, 0, 2, -1, 2, 0,0, -1, 0, -1,-1, 0, 2, -1, 2, // rot 1 | ||
0,0, 1, 0, 1, 1, 0,-2, 1,-2, 0,0, -1, 0, -1, 1, 0,-2, -1,-2, // rot 2 | ||
0,0, 1, 0, 1,-1, 0, 2, 1, 2, 0,0, 1, 0, 1,-1, 0, 2, 1, 2, // rot 3 | ||
// line-clockwise line-counterclockwise | ||
0,0, 2, 0, -1, 0, 2,-1, -1, 2, 0,0, 1, 0, -2, 0, 1, 2, -2,-1, // rot 0 | ||
0,0, -2, 0, 1, 0, -2, 1, 1,-2, 0,0, 1, 0, -2, 0, 1, 2, -2,-1, // rot 1 | ||
0,0, -1, 0, 2, 0, -1,-2, 2, 1, 0,0, -2, 0, 1, 0, -2, 1, 1,-2, // rot 2 | ||
0,0, 2, 0, -1, 0, 2,-1, -1, 2, 0,0, -1, 0, 2, 0, -1,-2, 2, 1, // rot 3 | ||
}; | ||
|
||
float combo_bonus[] = { | ||
1.f, 1.5f, 2.f, 3.f, 4.f, 5.f, 6.f, 8.f, 10.f, 12.f, 15.f, 20.f, | ||
25.f, 30.f, 40.f, 50.f, 75.f, 100.f | ||
}; | ||
#define MAX_COMBO ((sizeof combo_bonus / sizeof *combo_bonus) - 1) | ||
|
||
int rewards[] = {0, 100, 250, 500, 1000}; // points for clearing 0,1,2,3,4 lines | ||
|
||
int speeds[] = {100, 80, 70, 60, 52, 46, 40, 35, 30, 26, 22, 18, 15, 12, 10, 8, 6, 5, 4, 3, 2}; | ||
#define MAX_SPEED ((sizeof speeds / sizeof *speeds) - 1) | ||
|
||
char countdown_msg[][20] = {" Go!", " - 1 -", " - 2 -", " - 3 -"}; | ||
|
||
struct piece { int x, y, rot, color; }; | ||
struct spot { int color, part; }; | ||
struct row { | ||
struct spot col[BWIDTH]; | ||
int fullness; | ||
int special; | ||
int offset; | ||
}; | ||
|
||
struct player { | ||
struct row row[BHEIGHT]; // the board, excluding the falling piece | ||
int left, right, down; // true when holding a direction | ||
int move_cooldown; // cooldown before hold-to-repeat movement | ||
struct piece it; // current falling piece - "it" | ||
struct piece beam; // hard drop beam | ||
struct piece held; // shape in the hold box | ||
int beam_tick; // tick that beam was created | ||
int hold_uses; // have we swapped with the hold already? | ||
int bag[BAG_SZ]; // "bag" of upcoming pieces | ||
int bag_idx; // last position used up in bag | ||
int next[5]; // next pieces in preview (take from bag) | ||
int grounded; // is piece on the ground? | ||
int grounded_moves; // how many moves have we made on the ground? | ||
int last_dx_tick; // tick of most recent left/right movement | ||
int lines, score, best; // scoring | ||
int combo; // clears in-a-row | ||
int reward, reward_x, reward_y; // for hovering points indicator | ||
int garbage[GARB_LVLS + 1]; // queued garbage, e.g. received from opponents | ||
int garbage_tick; // keeps track of when to age garbage | ||
int garbage_remaining; // how many lines of garbage remain to clear to win | ||
int garbage_bits; // fractions of garbage attached to each particle | ||
int top_garb; // highest position of garbage stack drawn | ||
int level; // difficultly level (lines/10) | ||
int countdown_time; // ready-set-go countdown | ||
int idle_time; // how long the player has been idle in ticks | ||
int shiny_lines; | ||
int shine_time; // delay in ticks before clearing line(s) | ||
int dead_time; // delay in ticks after game over | ||
int board_x, board_y, board_w; // positions and sizes of things | ||
int preview_x, preview_y; // position of preview | ||
int box_w; // width of hold box / preview box | ||
int ticks; // counts up while game is going | ||
int seed1, seed2; // make garbage and bags fair | ||
float shake_x, shake_y; // amount the board is offset by shaking | ||
int flash; // flashing from receiving garbage | ||
int tspin; | ||
int device; // SDL's input device id | ||
char dev_name[80]; // input device "name" | ||
} play[NPLAY], *p; // one per player | ||
|
||
struct particle { float x, y, r, vx, vy; int opponent, bits; }; | ||
struct particle parts[NPARTS]; | ||
struct particle flows[NFLOWS]; | ||
|
||
enum state { MAIN_MENU = 0, NUMBER_MENU, ASSIGN, PLAY, GAMEOVER} state; | ||
int win_x = 1000; // window size | ||
int win_y = 750; | ||
int bs, bs2, bs4; // individual block size, in half, in quarters | ||
int tick; // counts up one per frame | ||
int nplay = 1; // number of players | ||
int assign_me; // who is getting an input device assigned? | ||
int menu_pos; // current position in menu | ||
int text_x, text_y; // position of text drawing | ||
int line_height; // text line height | ||
int garbage_race; | ||
int npart; | ||
int seed; | ||
|
||
SDL_GLContext ctx; | ||
SDL_Event event; | ||
SDL_Window *win; | ||
SDL_Renderer *renderer; | ||
|
||
void do_events(); | ||
void setup(); | ||
void update_player(); | ||
void move(int dx, int dy, int gravity); | ||
void reset_fall(); | ||
void bake(); | ||
void new_game(); | ||
int is_solid_part(int shape, int rot, int i, int j); | ||
int is_tspin_part(int shape, int rot, int i, int j); | ||
int collide(int x, int y, int rot); | ||
void update_particles(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#define TIMER_NAMES \ | ||
X(SDL_Delay), \ | ||
X(do_events), \ | ||
X(update_player), \ | ||
X(update_particles), \ | ||
X(draw_start), \ | ||
X(draw_menu), \ | ||
X(draw_player), \ | ||
X(draw_particles), \ | ||
X(draw_end), \ | ||
X(SDL_GL_SwapWindow), | ||
|
||
#include <timer.c> | ||
|
||
#undef TIMER_NAMES |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// tinyc.games audio - copyright 2023 Jer Wilson | ||
// | ||
// 1. Add SDL_INIT_AUDIO to your SDL_Init() | ||
// 2. Call audioinit() before playing sound | ||
// 3. Play tones with audio_tone() | ||
|
||
#include <math.h> | ||
#include <SDL2/SDL_audio.h> | ||
#include "audio.h" | ||
|
||
void audio_tone(int shape, int note_lo, int note_hi, | ||
double attack, double decay, double sustain, double release) | ||
{ | ||
int note = note_lo + rand() % (note_hi - note_lo + 1); | ||
if (note < A0 || note > C6) return; | ||
|
||
envs[rand() % NUM_ENVS] = (struct envelope){ | ||
.shape = shape, | ||
.start_freq = music_notes[note].frequency, | ||
.volume = 1.0 + 0.08 * music_notes[note].wavelength, | ||
.attack = (attack ) / 1000.f, | ||
.decay = (attack + decay ) / 1000.f, | ||
.sustain = (attack + decay + sustain ) / 1000.f, | ||
.release = (attack + decay + sustain + release) / 1000.f, | ||
}; | ||
} | ||
|
||
static void mix_audio(void *unused, unsigned char *stream, int len) | ||
{ | ||
short *out = (short*)stream; | ||
|
||
for (int j = 0; j < len/2; j++) | ||
{ | ||
int samp = 0; | ||
|
||
for (int n = 0; n < NUM_ENVS; n++) | ||
{ | ||
struct envelope *e = envs + n; | ||
if (e->pos >= e->release) | ||
continue; | ||
|
||
double freq = e->start_freq; | ||
double wl = 1.0 / freq; | ||
double wl2 = wl / 2.0; | ||
double frac = fmod(e->pos, wl); | ||
double t = e->pos; | ||
e->pos += 1.0 / 44100; | ||
|
||
double veloc = e->volume * 2200; | ||
if (t <= e->attack ) veloc *= t / e->attack * 1.5; | ||
else if (t <= e->decay ) veloc *= (e->decay - t) / (e->decay - e->attack) * .5 + 1.0; | ||
else if (t <= e->sustain) ; | ||
else if (t <= e->release) veloc *= (e->release - t) / (e->release - e->sustain); | ||
|
||
switch (e->shape) | ||
{ | ||
case SINE: samp += veloc * sin(frac * freq * 6.28318531); break; | ||
case SQUARE: samp += frac > wl2 ? veloc : -veloc; break; | ||
case TRIANGLE: samp += (4 * freq * (frac > wl2 ? (wl - frac) : frac) - 1) * veloc; break; | ||
} | ||
} | ||
|
||
out[j] = samp > 32767 ? 32768 : | ||
samp < -32767 ? -32767 : | ||
samp; | ||
} | ||
} | ||
|
||
void audio_init() | ||
{ | ||
SDL_AudioDeviceID id; | ||
SDL_AudioSpec actual, desired = { | ||
.freq = 44100, | ||
.format = AUDIO_S16LSB, | ||
.channels = 1, | ||
.samples = 512, | ||
.callback = mix_audio, | ||
}; | ||
id = SDL_OpenAudioDevice(NULL, 0, &desired, &actual, SDL_AUDIO_ALLOW_ANY_CHANGE); | ||
if (!id) | ||
fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError()); | ||
else | ||
SDL_PauseAudioDevice(id, 0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#pragma once | ||
|
||
#define NUM_ENVS 20 | ||
|
||
enum shape {SINE, SQUARE, TRIANGLE}; | ||
|
||
struct envelope { | ||
enum shape shape; | ||
double start_freq; | ||
double volume; | ||
double attack, decay, sustain, release; // envelope timings | ||
double pos; // current play position | ||
double noiseval; | ||
int noisectr; | ||
int noisesign; | ||
} envs[NUM_ENVS]; | ||
|
||
enum notes { | ||
A0, As0, B0, C1, Cs1, D1, Ds1, E1, F1, Fs1, G1, Gs1, | ||
A1, As1, B1, C2, Cs2, D2, Ds2, E2, F2, Fs2, G2, Gs2, | ||
A2, As2, B2, C3, Cs3, D3, Ds3, E3, F3, Fs3, G3, Gs3, | ||
A3, As3, B3, C4, Cs4, D4, Ds4, E4, F4, Fs4, G4, Gs4, | ||
A4, As4, B4, C5, Cs5, D5, Ds5, E5, F5, Fs5, G5, Gs5, | ||
A5, As5, B5, C6, | ||
}; | ||
|
||
struct { | ||
char name[3]; | ||
int octave; | ||
double frequency; | ||
double wavelength; | ||
} music_notes[] = { | ||
{"A" , 0, 27.500, 12.374}, // Piano low | ||
{"A#", 0, 29.135, 11.680}, | ||
{"B" , 0, 30.868, 11.024}, | ||
{"C" , 1, 32.703, 10.405}, | ||
{"C#", 1, 34.648, 9.821}, | ||
{"D" , 1, 36.708, 9.270}, | ||
{"D#", 1, 38.891, 8.750}, | ||
{"E" , 1, 41.203, 8.259}, | ||
{"F" , 1, 43.654, 7.795}, | ||
{"F#", 1, 46.249, 7.358}, | ||
{"G" , 1, 48.999, 6.945}, | ||
{"G#", 1, 51.913, 6.555}, | ||
{"A" , 1, 55.000, 6.187}, | ||
{"A#", 1, 58.270, 5.840}, | ||
{"B" , 1, 61.735, 5.512}, | ||
{"C" , 2, 65.406, 5.203}, | ||
{"C#", 2, 69.296, 4.911}, | ||
{"D" , 2, 73.416, 4.635}, | ||
{"D#", 2, 77.782, 4.375}, | ||
{"E" , 2, 82.407, 4.129}, | ||
{"F" , 2, 87.307, 3.898}, | ||
{"F#", 2, 92.499, 3.679}, | ||
{"G" , 2, 97.999, 3.472}, | ||
{"G#", 2, 103.826, 3.278}, | ||
{"A" , 2, 110.000, 3.094}, | ||
{"A#", 2, 116.541, 2.920}, | ||
{"B" , 2, 123.471, 2.756}, | ||
{"C" , 3, 130.813, 2.601}, | ||
{"C#", 3, 138.591, 2.455}, | ||
{"D" , 3, 146.832, 2.318}, | ||
{"D#", 3, 155.563, 2.187}, | ||
{"E" , 3, 164.814, 2.065}, | ||
{"F" , 3, 174.614, 1.949}, | ||
{"F#", 3, 184.997, 1.839}, | ||
{"G" , 3, 195.998, 1.736}, | ||
{"G#", 3, 207.652, 1.639}, | ||
{"A" , 3, 220.000, 1.547}, | ||
{"A#", 3, 233.082, 1.460}, | ||
{"B" , 3, 246.942, 1.378}, | ||
{"C" , 4, 261.626, 1.301}, // middle C | ||
{"C#", 4, 277.183, 1.228}, | ||
{"D" , 4, 293.665, 1.159}, | ||
{"D#", 4, 311.127, 1.094}, | ||
{"E" , 4, 329.628, 1.032}, | ||
{"F" , 4, 349.228, 0.974}, | ||
{"F#", 4, 369.994, 0.920}, | ||
{"G" , 4, 391.995, 0.868}, | ||
{"G#", 4, 415.305, 0.819}, | ||
{"A" , 4, 440.000, 0.773}, // A 440 | ||
{"A#", 4, 466.164, 0.730}, | ||
{"B" , 4, 493.883, 0.689}, | ||
{"C" , 5, 523.251, 0.650}, | ||
{"C#", 5, 554.365, 0.614}, | ||
{"D" , 5, 587.330, 0.579}, | ||
{"D#", 5, 622.254, 0.547}, | ||
{"E" , 5, 659.255, 0.516}, | ||
{"F" , 5, 698.456, 0.487}, | ||
{"F#", 5, 739.989, 0.460}, | ||
{"G" , 5, 783.991, 0.434}, | ||
{"G#", 5, 830.609, 0.410}, | ||
{"A" , 5, 880.000, 0.387}, | ||
{"A#", 5, 932.328, 0.365}, | ||
{"B" , 5, 987.767, 0.345}, | ||
}; | ||
|
||
void audio_init(); | ||
void audio_tone(int shape, int note_lo, int note_hi, | ||
double attack, double decay, double sustain, double release); |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#version 330 core | ||
in vec2 uv; | ||
out vec4 color; | ||
|
||
uniform vec3 incolor; | ||
uniform sampler2D tex; | ||
|
||
void main() | ||
{ | ||
color = vec4(incolor, texture(tex, uv).r); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#version 330 core | ||
layout (location = 0) in vec4 pos; | ||
out vec2 uv; | ||
|
||
uniform mat4 proj; | ||
|
||
void main() | ||
{ | ||
gl_Position = proj * vec4(pos.xy, 0.0, 1.0); | ||
uv = pos.zw; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#include <stdio.h> | ||
#include <stdbool.h> | ||
#include <SDL2/SDL.h> | ||
|
||
// You must X-define TIMER_NAMES before including this file, e.g: | ||
// | ||
// #define TIMER_NAMES X(create_hmap), X(update_world), X(update_player), | ||
// | ||
|
||
#ifndef TIMER_NAMES | ||
#define TIMER_NAMES | ||
#endif | ||
|
||
#define TIMER(name) { \ | ||
unsigned long long now = SDL_GetPerformanceCounter(); \ | ||
if (!timer_then) timer_then = now; \ | ||
timer_times[ timer_curr_id ] += now - timer_then; \ | ||
timer_curr_id = timer_ ## name; \ | ||
timer_then = now; \ | ||
} | ||
|
||
// FIXME: push id onto stack if re-entering | ||
#define TIMECALL(f, args) { \ | ||
unsigned long long now = SDL_GetPerformanceCounter(); \ | ||
if (!timer_then) timer_then = now; \ | ||
timer_times[ timer_curr_id ] += now - timer_then; \ | ||
timer_then = now; \ | ||
(f)args; \ | ||
now = SDL_GetPerformanceCounter(); \ | ||
timer_times[ timer_ ## f ] += now - timer_then; \ | ||
timer_curr_id = timer_; \ | ||
timer_then = now; \ | ||
} | ||
|
||
enum timernames { | ||
#define X(x) timer_ ## x | ||
TIMER_NAMES | ||
#undef X | ||
timer_ | ||
}; | ||
|
||
char timernamesprint[][80] = { | ||
#define X(x) #x | ||
TIMER_NAMES | ||
#undef X | ||
"uncounted" | ||
}; | ||
|
||
int timer_curr_id = timer_; | ||
unsigned long long timer_then = 0; | ||
unsigned long long timer_times[timer_ + 1] = { 0 }; | ||
|
||
void timer_print(char *buf, size_t n, bool show_all) | ||
{ | ||
char *p = buf; | ||
int i = 0; | ||
unsigned long long sum = 0; | ||
unsigned long long freq = SDL_GetPerformanceFrequency(); | ||
|
||
for (i = 0; i <= timer_; i++) | ||
sum += timer_times[i]; | ||
|
||
for (i = 0; i <= timer_; i++) | ||
{ | ||
float secs = (float)timer_times[i] / (float)freq; | ||
float pct = 100.f * (float)timer_times[i] / sum; | ||
if ((show_all && secs > 0.f) || pct >= 0.1f || secs >= 0.01f) | ||
p += snprintf(p, n - (p-buf), | ||
"%6.1f %2.0f%% %s\n", secs, pct, timernamesprint[i]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#pragma once | ||
|
||
#define MAX(a,b) ((a) > (b) ? (a) : (b)) | ||
#define MIN(a,b) ((a) < (b) ? (a) : (b)) | ||
#define SWAP(a,b) {int *x = &(a); int *y = &(b); int t = *x; *x = *y; *y = t;} | ||
#define CLAMP(lo,x,hi) ((x) < (lo) ? (lo) : (x) > (hi) ? (hi) : (x)) | ||
|
||
int check_shader_errors(GLuint shader, char *name) | ||
{ | ||
GLint success; | ||
GLchar log[1024]; | ||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success); | ||
if (success) return 0; | ||
glGetShaderInfoLog(shader, 1024, NULL, log); | ||
fprintf(stderr, "ERROR in %s shader program: %s\n", name, log); | ||
exit(1); | ||
return 1; | ||
} | ||
|
||
int check_program_errors(GLuint shader, char *name) | ||
{ | ||
GLint success; | ||
GLchar log[1024]; | ||
glGetProgramiv(shader, GL_LINK_STATUS, &success); | ||
if (success) return 0; | ||
glGetProgramInfoLog(shader, 1024, NULL, log); | ||
fprintf(stderr, "ERROR in %s shader: %s\n", name, log); | ||
exit(1); | ||
return 1; | ||
} | ||
|
||
// please free() the returned string | ||
char *file2str(char *filename) | ||
{ | ||
FILE *f; | ||
|
||
#if defined(_MSC_VER) && _MSC_VER >= 1400 | ||
if (fopen_s(&f, filename, "r")) | ||
f = NULL; | ||
#else | ||
f = fopen(filename, "r"); | ||
#endif | ||
|
||
if (!f) goto bad; | ||
fseek(f, 0, SEEK_END); | ||
size_t sz = ftell(f); | ||
rewind(f); | ||
char *buf = calloc(sz + 1, sizeof *buf); | ||
if (fread(buf, 1, sz, f) != sz) goto bad; | ||
fclose(f); | ||
return buf; | ||
|
||
bad: | ||
fprintf(stderr, "Failed to open/read %s\n", filename); | ||
return NULL; | ||
} | ||
|
||
unsigned int file2shader(unsigned int type, char *filename) | ||
{ | ||
char *code = file2str(filename); | ||
unsigned int id = glCreateShader(type); | ||
glShaderSource(id, 1, (const char *const *)&code, NULL); | ||
glCompileShader(id); | ||
check_shader_errors(id, filename); | ||
free(code); | ||
return id; | ||
} |