diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 1542 |
1 files changed, 0 insertions, 1542 deletions
diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 48b8fc8..0000000 --- a/src/main.c +++ /dev/null @@ -1,1542 +0,0 @@ -/* - * Copyright (c) 2019-2020, yzrh <yzrh@noema.org> - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include <fcntl.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <pthread.h> -#include <unistd.h> - -#ifdef __linux__ - -#include <sys/types.h> -#include <sys/stat.h> -#include <poll.h> - -#endif /* __linux__ */ - -#include <SDL2/SDL.h> -#include <SDL2/SDL_ttf.h> - -#ifdef SOUND - -#include <SDL2/SDL_mixer.h> - -#endif /* SOUND */ - -#include "version.h" -#include "extern.h" -#include "screen.h" - -#ifdef GPIO - -#include "gpio.h" - -#endif /* GPIO */ - -static pthread_mutex_t mutex; -static pthread_cond_t cond; - -static SDL_Renderer *renderer; -static TTF_Font *font_20; -static TTF_Font *font_24; - -/* - * Default to keyboard, - * GPIO inputs are mapped to controller keys - */ -static Snake_Device device = SNAKE_KEYBOARD; -static int selection = 0; - -static Snake_Text text_title; -static Snake_Text text_help_top; -static Snake_Text text_help_0; -static Snake_Text text_help_1; -static Snake_Text text_help_2; -static Snake_Text text_help_3; -static Snake_Text text_help_4; -static Snake_Text text_help_5; -static Snake_Text text_help_6; -static Snake_Text text_help_7; - -static Snake_Text text_score; - -static Snake_Text text_prompt_start; -static Snake_Text text_prompt_resume; - -static Snake_Text text_prompt_0; -static Snake_Text text_prompt_1; -static Snake_Text text_prompt_2; - -static bool start = 1; -static bool end = 0; -static bool begin = 0; - -static bool god = 0; -static bool reset = 0; -static bool wait = 0; -static bool multiplayer = 0; -static bool flappy = 0; - -static struct timespec delay = { - .tv_sec = 0, - .tv_nsec = TICK_TIME_INIT -}; - -static int score; -static int result; -static int distance; -static int speed; - -static Snake_Input input = SNAKE_EMPTY; -static Snake_Input head[2][2]; - -static Snake_Pos *snake0 = NULL; -static Snake_Pos *snake1 = NULL; - -static int fruit[2]; - -static Snake_Pos *gap = NULL; - -static void* -handler_rendering(void *args) -{ - const SDL_Color fg = { - COLOUR_FOREGROUND_R, - COLOUR_FOREGROUND_G, - COLOUR_FOREGROUND_B - }; - const SDL_Color bg = { - COLOUR_BACKGROUND_R, - COLOUR_BACKGROUND_G, - COLOUR_BACKGROUND_B - }; - const SDL_Color bg_s = { - COLOUR_BACKGROUND_SHADE_R, - COLOUR_BACKGROUND_SHADE_G, - COLOUR_BACKGROUND_SHADE_B - }; - - char result_str[23]; - char score_str[11]; - - Snake_Text text_result; - - Snake_Text text_welcome; - Snake_Text text_clear; - Snake_Text text_gameover; - Snake_Text text_pause; - - while (!end) { - draw_clear(renderer); - draw_colour(renderer, SNAKE_FOREGROUND); - - draw_wall(renderer); - - draw_text(renderer, - font_20, - SCREEN_HEIGHT + 4 * SCREEN_UNIT_X, - SCREEN_UNIT_Y, - "Snake", - 1, - 0, - fg, - bg, - &text_title); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + 4 * SCREEN_UNIT_X, - 2 * SCREEN_UNIT_Y, - "Help", - 1, - 0, - fg, - bg, - &text_help_top); - if (god) - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 2.5 * SCREEN_UNIT_Y, - "0. Don't forget to cheat", - 0, - 0, - fg, - bg, - &text_help_0); - if (device == SNAKE_KEYBOARD) { - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 3 * SCREEN_UNIT_Y, - "1. Classic: use arrow keys to move", - 0, - 0, - fg, - bg, - &text_help_1); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 3.5 * SCREEN_UNIT_Y, - "2. Multiplayer: use s, e, d, f keys", - 0, - 0, - fg, - bg, - &text_help_2); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 4 * SCREEN_UNIT_Y, - "3. Flappy: SPACE key to jump", - 0, - 0, - fg, - bg, - &text_help_3); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 4.5 * SCREEN_UNIT_Y, - "4. ESCAPE key to pause", - 0, - 0, - fg, - bg, - &text_help_4); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 5 * SCREEN_UNIT_Y, - "5. r key to reset", - 0, - 0, - fg, - bg, - &text_help_5); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 5.5 * SCREEN_UNIT_Y, - "6. m key to toggle music", - 0, - 0, - fg, - bg, - &text_help_6); - } else if (device == SNAKE_TOUCHSCREEN) { - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 3 * SCREEN_UNIT_Y, - "1. Classic: swipe to move", - 0, - 0, - fg, - bg, - &text_help_1); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 3.5 * SCREEN_UNIT_Y, - "2. Multiplayer: use different side", - 0, - 0, - fg, - bg, - &text_help_2); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 4 * SCREEN_UNIT_Y, - "3. Flappy: tap to jump", - 0, - 0, - fg, - bg, - &text_help_3); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 4.5 * SCREEN_UNIT_Y, - "4. Tap here to pause", - 0, - 1, - fg, - bg, - &text_help_4); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 5 * SCREEN_UNIT_Y, - "5. Tap here to reset", - 0, - 1, - fg, - bg, - &text_help_5); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 5.5 * SCREEN_UNIT_Y, - "6. Tap here to toggle music", - 0, - 1, - fg, - bg, - &text_help_6); - } else if (device == SNAKE_CONTROLLER) { - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 3 * SCREEN_UNIT_Y, - "1. Classic: use D-pad to move", - 0, - 0, - fg, - bg, - &text_help_1); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 3.5 * SCREEN_UNIT_Y, - "2. Multiplayer: second controller", - 0, - 0, - fg, - bg, - &text_help_2); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 4 * SCREEN_UNIT_Y, - "3. Flappy: Press A to jump", - 0, - 0, - fg, - bg, - &text_help_3); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 4.5 * SCREEN_UNIT_Y, - "4. Press BACK to pause", - 0, - 0, - fg, - bg, - &text_help_4); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 5 * SCREEN_UNIT_Y, - "5. Press X to reset", - 0, - 0, - fg, - bg, - &text_help_5); - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 5.5 * SCREEN_UNIT_Y, - "6. Press Y to toggle music", - 0, - 0, - fg, - bg, - &text_help_6); - } - draw_text(renderer, - font_20, - SCREEN_HEIGHT + SCREEN_UNIT_X / 4, - 6 * SCREEN_UNIT_Y, - "7. Have fun", - 0, - 0, - fg, - bg, - &text_help_7); - - snprintf(score_str, 11, "Score: %d", score); - - draw_text(renderer, - font_20, - SCREEN_HEIGHT + 4 * SCREEN_UNIT_X, - 7 * SCREEN_UNIT_Y, - score_str, - 1, - 0, - fg, - bg, - &text_score); - - draw_snake(renderer, &snake0); - - if (flappy) { - draw_pipe(renderer, &gap); - } else if (multiplayer) - draw_snake(renderer, &snake1); - else if (!start) - draw_fruit(renderer, fruit); - - if (start || reset) { - if (multiplayer) { - if (result == 3) - snprintf(result_str, 23, "Draw"); - else if (result > 0) - snprintf(result_str, 23, - "%s is the winner", - result == 1 ? - "Player 2" : "Player 1"); - else - snprintf(result_str, 23, "Reset"); - text_result.cache = 0; - - draw_text(renderer, - font_24, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2 - - 0.75 * SCREEN_UNIT_Y, - result_str, - 1, - 0, - fg, - bg_s, - &text_result); - } - if (start) - draw_text(renderer, - font_24, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2, - "Welcome", - 1, - 0, - fg, - bg_s, - &text_welcome); - else if (!flappy && !multiplayer && - score == SCREEN_BLOCK / 2) - draw_text(renderer, - font_24, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2, - "Why don't you have legs?", - 1, - 0, - fg, - bg_s, - &text_clear); - else - draw_text(renderer, - font_24, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2, - "Game over!", - 1, - 0, - fg, - bg_s, - &text_gameover); - if (device == SNAKE_KEYBOARD) - draw_text(renderer, - font_20, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2 + - 0.75 * SCREEN_UNIT_Y, - "Press RETURN key for selection", - 1, - 0, - fg, - bg_s, - &text_prompt_start); - else if (device == SNAKE_TOUCHSCREEN) - draw_text(renderer, - font_20, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2 + - 0.75 * SCREEN_UNIT_Y, - "Tap the option to select", - 1, - 0, - fg, - bg_s, - &text_prompt_start); - else if (device == SNAKE_CONTROLLER) - draw_text(renderer, - font_20, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2 + - 0.75 * SCREEN_UNIT_Y, - "Press START to select", - 1, - 0, - fg, - bg_s, - &text_prompt_start); - draw_text(renderer, - font_20, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2 + 1.5 * SCREEN_UNIT_Y, - "Classic", - 1, - device == SNAKE_TOUCHSCREEN || - selection == 0 ? 1 : 0, - fg, - bg_s, - &text_prompt_0); - draw_text(renderer, - font_20, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2 + 2.25 * SCREEN_UNIT_Y, - "Multiplayer", - 1, - device == SNAKE_TOUCHSCREEN || - selection == 1 ? 1 : 0, - fg, - bg_s, - &text_prompt_1); - draw_text(renderer, - font_20, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2 + 3 * SCREEN_UNIT_Y, - "Flappy", - 1, - device == SNAKE_TOUCHSCREEN || - selection == 2 ? 1 : 0, - fg, - bg_s, - &text_prompt_2); - } else if (wait) { - draw_text(renderer, - font_24, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2, - "Paused", - 1, - 0, - fg, - bg_s, - &text_pause); - if (device == SNAKE_KEYBOARD) - draw_text(renderer, - font_20, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2 + - 0.75 * SCREEN_UNIT_Y, - "Press ESCAPE key to resume", - 1, - 0, - fg, - bg_s, - &text_prompt_resume); - else if (device == SNAKE_TOUCHSCREEN) - draw_text(renderer, - font_20, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2 + - 0.75 * SCREEN_UNIT_Y, - "Tap here to resume", - 1, - 1, - fg, - bg_s, - &text_prompt_resume); - else if (device == SNAKE_CONTROLLER) - draw_text(renderer, - font_20, - SCREEN_HEIGHT / 2, - SCREEN_HEIGHT / 2 + - 0.75 * SCREEN_UNIT_Y, - "Press START to resume", - 1, - 0, - fg, - bg_s, - &text_prompt_resume); - } - - SDL_RenderPresent(renderer); - } - return 0; -} - -static void* -handler_logic(void *args) -{ - struct timespec clock_start; - struct timespec clock_end; - double clock_pass = 0; - int pipe_dim[6]; - int pipe_pos = 0; - - clock_gettime(CLOCK_MONOTONIC, &clock_start); - - for (;;) { - pthread_mutex_lock(&mutex); - while (start || reset || wait) { - if (!wait) { - clock_pass = 0; - pipe_pos = 0; - } - pthread_cond_wait(&cond, &mutex); - clock_gettime(CLOCK_MONOTONIC, &clock_start); - } - pthread_mutex_unlock(&mutex); - - if (end) - return 0; - - if (flappy) { - pthread_mutex_lock(&mutex); - while (!begin) - pthread_cond_wait(&cond, &mutex); - pthread_mutex_unlock(&mutex); - - game_pipe_bound(&gap, pipe_dim); - - if (pipe_pos - SCREEN_UNIT > pipe_dim[0]) { - score++; - text_score.cache = 0; - } - pipe_pos = pipe_dim[0]; - - if (!god && (collision( - (int[]) {snake0->next->x, snake0->next->y, - 2 * SCREEN_UNIT, SCREEN_UNIT}, - (int[]) {pipe_dim[0], pipe_dim[2], - pipe_dim[1], pipe_dim[3]}) || - collision( - (int[]) {snake0->next->x, snake0->next->y, - 2 * SCREEN_UNIT, SCREEN_UNIT}, - (int[]) {pipe_dim[0], pipe_dim[4], - pipe_dim[1], pipe_dim[5]}) || - snake0->y < 0 || - snake0->y + SCREEN_UNIT > SCREEN_HEIGHT)) { - pthread_mutex_lock(&mutex); - reset = 1; - pthread_mutex_unlock(&mutex); - } else { - game_pipe_move(&gap); - - game_pipe_pos(&gap, &result); - if (result == 3) { - game_pipe_del(&gap); - game_pipe_add(&gap); - } else if (result == 2) { - game_pipe_add(&gap); - } else if (result == 1) { - game_pipe_del(&gap); - } - } - } else if (!multiplayer) { - game_snake_move(&snake0, NULL, - head[0], !god, &result); - - if (result == 0 || god) { - head[1][0] = head[0][0]; - - if (collision_block(fruit, - (int[]) {snake0->x, snake0->y})) { - score++; - text_score.cache = 0; - game_snake_grow(&snake0); - - if (score == SCREEN_BLOCK / 2) { - pthread_mutex_lock(&mutex); - reset = 1; - pthread_mutex_unlock(&mutex); - } - - game_fruit(fruit, &snake0); - - if (delay.tv_nsec - TICK_TIME_DEC >= - TICK_TIME_MIN) - delay.tv_nsec -= TICK_TIME_DEC; - } - } else { - pthread_mutex_lock(&mutex); - reset = 1; - pthread_mutex_unlock(&mutex); - } - } else { - game_snake_move(&snake0, &snake1, - head[0], !god, &result); - - if (result == 0 || god) { - head[1][0] = head[0][0]; - head[1][1] = head[0][1]; - - clock_gettime(CLOCK_MONOTONIC, &clock_end); - clock_pass += (clock_end.tv_sec - - clock_start.tv_sec) + - (clock_end.tv_nsec - - clock_start.tv_nsec) * 0.000000001; - clock_gettime(CLOCK_MONOTONIC, &clock_start); - - score = clock_pass; - text_score.cache = 0; - game_snake_grow(&snake0); - game_snake_grow(&snake1); - } else { - pthread_mutex_lock(&mutex); - reset = 1; - pthread_mutex_unlock(&mutex); - } - } - - nanosleep(&delay, NULL); - } -} - -static void* -handler_gravity(void *args) -{ - const struct timespec delay = { - .tv_sec = 0, - .tv_nsec = 1000000000 / SCREEN_UNIT - }; - - for (;;) { - pthread_mutex_lock(&mutex); - while (!flappy || !begin || start || reset || wait) - pthread_cond_wait(&cond, &mutex); - pthread_mutex_unlock(&mutex); - - if (end) - return 0; - - if (distance > 0) { - game_snake_fall(&snake0, 0, - distance > speed ? speed : distance); - speed++; - - pthread_mutex_lock(&mutex); - distance -= distance > speed ? speed : distance; - if (distance == 0) - speed = 1; - pthread_mutex_unlock(&mutex); - } else { - game_snake_fall(&snake0, 1, speed); - speed++; - } - - nanosleep(&delay, NULL); - } -} - -#ifdef GPIO - -#ifdef __FreeBSD__ - -static void* -handler_gpio(void *args) -{ - const struct timespec delay = { - .tv_sec = 0, - .tv_nsec = 50000000 - }; - - SDL_Event event; - event.type = SDL_CONTROLLERBUTTONUP; - - while (!end) { - if (gpio_read(GPIO_PIN_IN0) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_DPAD_LEFT; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN1) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_DPAD_UP; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN2) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_DPAD_DOWN; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN3) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_DPAD_RIGHT; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN4) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_BACK; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN5) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_GUIDE; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN6) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_START; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN7) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_A; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN8) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_B; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN9) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_X; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN10) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_Y; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN11) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_LEFTSHOULDER; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN12) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN13) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_LEFTSTICK; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN14) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_RIGHTSTICK; - event.cbutton.which = 0; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN15) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_DPAD_LEFT; - event.cbutton.which = 1; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN16) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_DPAD_UP; - event.cbutton.which = 1; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN17) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_DPAD_DOWN; - event.cbutton.which = 1; - SDL_PushEvent(&event); - } else if (gpio_read(GPIO_PIN_IN18) == 0) { - event.cbutton.button = - SDL_CONTROLLER_BUTTON_DPAD_RIGHT; - event.cbutton.which = 1; - SDL_PushEvent(&event); - } - - nanosleep(&delay, NULL); - } - return 0; -} - -#elif __linux__ - -static void* -handler_gpio(void *args) -{ - struct pollfd pfd[19]; - char path[29]; - - for (int i = 0; i < 19; i++) - pfd[i].events = POLLPRI | POLLERR; - - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN0); - pfd[0].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN1); - pfd[1].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN2); - pfd[2].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN3); - pfd[3].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN4); - pfd[4].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN5); - pfd[5].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN6); - pfd[6].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN7); - pfd[7].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN8); - pfd[8].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN9); - pfd[9].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN10); - pfd[10].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN11); - pfd[11].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN12); - pfd[12].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN13); - pfd[13].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN14); - pfd[14].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN15); - pfd[15].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN16); - pfd[16].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN17); - pfd[17].fd = open(path, O_RDONLY); - snprintf(path, 29, "/sys/class/gpio/gpio%d/value", GPIO_PIN_IN18); - pfd[18].fd = open(path, O_RDONLY); - - SDL_Event event; - event.type = SDL_CONTROLLERBUTTONUP; - - char val[2]; - - while (!end) { - poll(pfd, 19, -1); - - for (int i = 0; i < 19; i++) { - if (pfd[i].revents & (POLLPRI | POLLERR)) { - pfd[i].revents &= ~(POLLPRI | POLLERR); - read(pfd[i].fd, val, 2); - lseek(pfd[i].fd, 0, SEEK_SET); - - if (atoi(val) != 0) - continue; - - input_gpio(i % 15, &event.cbutton.button); - - if (i < 15) - event.cbutton.which = 0; - else - event.cbutton.which = 1; - - SDL_PushEvent(&event); - break; - } - } - } - return 0; -} - -#endif /* __FreeBSD__ */ - -#endif /* GPIO */ - -int -main(void) -{ - printf("Snake " VERSION "." RELEASE "." PATCH EXTRA "\n" - "Copyright (c) 2019-2020, yzrh <yzrh@noema.org>\n"); - - if (SDL_Init(SDL_INIT_VIDEO | - SDL_INIT_AUDIO | - SDL_INIT_GAMECONTROLLER) != 0) { - fprintf(stderr, "SDL initialisation failure: %s\n", - SDL_GetError()); - return 1; - } - - SDL_Window *window = SDL_CreateWindow( - "Snake " VERSION "." RELEASE "." PATCH EXTRA, - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, - SCREEN_HEIGHT, - SDL_WINDOW_OPENGL); - - if (window == NULL) { - fprintf(stderr, "Window creation failure: %s\n", - SDL_GetError()); - return 1; - } - - renderer = SDL_CreateRenderer( - window, - -1, - SDL_RENDERER_ACCELERATED | - SDL_RENDERER_PRESENTVSYNC); - - if (renderer == NULL) { - fprintf(stderr, "Renderer creation failure: %s\n", - SDL_GetError()); - return 1; - } - - if (TTF_Init() != 0) { - fprintf(stderr, "TTF initialisation failure: %s\n", - TTF_GetError()); - return 1; - } - - font_20 = TTF_OpenFont("../contrib/font.ttf", 20); - font_24 = TTF_OpenFont("../contrib/font.ttf", 24); - - if (font_20 == NULL) { - font_20 = TTF_OpenFont("/usr/local/share/snake/font.ttf", 20); - font_24 = TTF_OpenFont("/usr/local/share/snake/font.ttf", 24); - } - - if (font_20 == NULL) { - font_20 = TTF_OpenFont("/usr/share/snake/font.ttf", 20); - font_24 = TTF_OpenFont("/usr/share/snake/font.ttf", 24); - } - - if (font_20 == NULL) { - fprintf(stderr, "%s\n", TTF_GetError()); - return 1; - } - -#ifdef SOUND - - if ((Mix_Init(MIX_INIT_FLAC) & MIX_INIT_FLAC) != MIX_INIT_FLAC) - fprintf(stderr, "Mixer initialisation failure: %s\n", - Mix_GetError()); - - if (Mix_OpenAudio(48000, AUDIO_S16SYS, 2, 4096) == -1) - fprintf(stderr, "%s\n", Mix_GetError()); - - Mix_Music *music = Mix_LoadMUS("../contrib/music.flac"); - - if (music == NULL) - music = Mix_LoadMUS("/usr/local/share/snake/music.flac"); - - if (music == NULL) - music = Mix_LoadMUS("/usr/share/snake/music.flac"); - - if (music == NULL) - fprintf(stderr, "%s\n", Mix_GetError()); - - if (Mix_PlayMusic(music, -1) == -1) - fprintf(stderr, "Audio playback failure: %s\n", - Mix_GetError()); - -#endif /* SOUND */ - -#ifdef GPIO - -#ifdef __linux__ - - gpio_export(GPIO_PIN_IN0); - gpio_export(GPIO_PIN_IN1); - gpio_export(GPIO_PIN_IN2); - gpio_export(GPIO_PIN_IN3); - gpio_export(GPIO_PIN_IN4); - gpio_export(GPIO_PIN_IN5); - gpio_export(GPIO_PIN_IN6); - gpio_export(GPIO_PIN_IN7); - gpio_export(GPIO_PIN_IN8); - gpio_export(GPIO_PIN_IN9); - gpio_export(GPIO_PIN_IN10); - gpio_export(GPIO_PIN_IN11); - gpio_export(GPIO_PIN_IN12); - gpio_export(GPIO_PIN_IN13); - gpio_export(GPIO_PIN_IN14); - gpio_export(GPIO_PIN_IN15); - gpio_export(GPIO_PIN_IN16); - gpio_export(GPIO_PIN_IN17); - gpio_export(GPIO_PIN_IN18); - - /* Wait for sysfs directory to show up */ - sleep(1); - -#endif /* __linux__ */ - - gpio_config(GPIO_PIN_IN0, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN1, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN2, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN3, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN4, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN5, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN6, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN7, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN8, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN9, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN10, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN11, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN12, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN13, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN14, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN15, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN16, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN17, GPIO_IN, GPIO_INT); - gpio_config(GPIO_PIN_IN18, GPIO_IN, GPIO_INT); - -#endif /* GPIO */ - - int seed; - int random = open("/dev/random", O_RDONLY); - if (read(random, &seed, sizeof(int)) > 0) - srand(seed); - close(random); - - SDL_JoystickID player = 0; - SDL_Event event; - - pthread_mutex_init(&mutex, NULL); - pthread_cond_init(&cond, NULL); - pthread_t th_renderer; - pthread_t th_logic; - pthread_t th_gravity; - - #ifdef GPIO - - pthread_t th_gpio; - - #endif /* GPIO */ - - pthread_create(&th_renderer, NULL, handler_rendering, NULL); - pthread_create(&th_logic, NULL, handler_logic, NULL); - pthread_create(&th_gravity, NULL, handler_gravity, NULL); - - #ifdef GPIO - - pthread_create(&th_gpio, NULL, handler_gpio, NULL); - - #endif /* GPIO */ - - while (SDL_WaitEvent(&event)) { - if (event.type == SDL_QUIT) - break; - - switch (event.type) { - case SDL_KEYUP: - if (device != SNAKE_KEYBOARD) { - device = SNAKE_KEYBOARD; - text_help_1.cache = 0; - text_help_2.cache = 0; - text_help_3.cache = 0; - text_help_4.cache = 0; - text_help_5.cache = 0; - text_help_6.cache = 0; - text_prompt_start.cache = 0; - text_prompt_resume.cache = 0; - } - input_keyboard(event.key.keysym.sym, &input); - if (multiplayer && - (event.key.keysym.sym == - SDLK_s || - event.key.keysym.sym == - SDLK_e || - event.key.keysym.sym == - SDLK_d || - event.key.keysym.sym == - SDLK_f)) - player = 1; - else - player = 0; - break; - case SDL_FINGERUP: - if (device != SNAKE_TOUCHSCREEN) { - device = SNAKE_TOUCHSCREEN; - text_help_1.cache = 0; - text_help_2.cache = 0; - text_help_3.cache = 0; - text_help_4.cache = 0; - text_help_5.cache = 0; - text_help_6.cache = 0; - text_prompt_start.cache = 0; - text_prompt_resume.cache = 0; - } - if (start || reset || wait) { - if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_help_5)) { - input = SNAKE_RESET; - } else if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_help_6)) { - input = SNAKE_MUSIC; - } else if (wait) { - if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_prompt_resume)) - input = SNAKE_PAUSE; - } else { - if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_prompt_0)) { - selection = 0; - input = SNAKE_SELECT; - } else if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_prompt_1)) { - selection = 1; - input = SNAKE_SELECT; - } else if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_prompt_2)) { - selection = 2; - input = SNAKE_SELECT; - } - } - } else if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_help_4)) { - input = SNAKE_PAUSE; - } else if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_help_5)) { - input = SNAKE_RESET; - } else if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_help_6)) { - input = SNAKE_MUSIC; - } else if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_help_top)) { - input = SNAKE_GOD; - } else if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_score)) { - input = SNAKE_GROW; - } else if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_title)) { - input = SNAKE_TELEPORT; - } else if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_help_1)) { - input = SNAKE_TICK_DECREASE; - } else if (collision_bound( - event.tfinger.x, - event.tfinger.y, - &text_help_7)) { - input = SNAKE_TICK_INCREASE; - } else if (flappy) { - input = SNAKE_JUMP; - } else { - input = SNAKE_EMPTY; - } - break; - case SDL_FINGERMOTION: - if (device != SNAKE_TOUCHSCREEN) { - device = SNAKE_TOUCHSCREEN; - text_help_1.cache = 0; - text_help_2.cache = 0; - text_help_3.cache = 0; - text_help_4.cache = 0; - text_help_5.cache = 0; - text_help_6.cache = 0; - text_prompt_start.cache = 0; - text_prompt_resume.cache = 0; - } - if ((event.tfinger.dx * - event.tfinger.dx) > - (event.tfinger.dy * - event.tfinger.dy)) { - if (event.tfinger.dx > 1) - input = SNAKE_RIGHT; - else if (event.tfinger.dx < -1) - input = SNAKE_LEFT; - } else { - if (event.tfinger.dy > 1) - input = SNAKE_DOWN; - else if (event.tfinger.dy < -1) - input = SNAKE_UP; - } - if (multiplayer && - event.tfinger.x > SCREEN_HEIGHT / 2) - player = 1; - else - player = 0; - break; - case SDL_CONTROLLERBUTTONUP: - if (device != SNAKE_CONTROLLER) { - device = SNAKE_CONTROLLER; - text_help_1.cache = 0; - text_help_2.cache = 0; - text_help_3.cache = 0; - text_help_4.cache = 0; - text_help_5.cache = 0; - text_help_6.cache = 0; - text_prompt_start.cache = 0; - text_prompt_resume.cache = 0; - } - input_controller(event.cbutton.button, &input); - player = event.cbutton.which; - break; - default: - break; - } - - if (!start && !reset && !wait) { - switch (input) { - case SNAKE_LEFT: - if (head[1][player] != SNAKE_RIGHT) - head[0][player] = SNAKE_LEFT; - break; - case SNAKE_UP: - if (head[1][player] != SNAKE_DOWN) - head[0][player] = SNAKE_UP; - break; - case SNAKE_DOWN: - if (head[1][player] != SNAKE_UP) - head[0][player] = SNAKE_DOWN; - break; - case SNAKE_RIGHT: - if (head[1][player] != SNAKE_LEFT) - head[0][player] = SNAKE_RIGHT; - break; - case SNAKE_JUMP: - if (!begin) { - pthread_mutex_lock(&mutex); - begin = 1; - pthread_cond_broadcast(&cond); - pthread_mutex_unlock(&mutex); - } - if (flappy) { - pthread_mutex_lock(&mutex); - distance += PIPE_GAP / 2 * - SCREEN_UNIT; - if (distance == 0) - speed = 1; - pthread_mutex_unlock(&mutex); - } - break; - case SNAKE_RESET: - pthread_mutex_lock(&mutex); - reset = 1; - pthread_mutex_unlock(&mutex); - break; - case SNAKE_GOD: - god = 1; - break; - case SNAKE_GROW: - if (god && !flappy && !multiplayer) - game_snake_grow(&snake0); - break; - case SNAKE_TELEPORT: - if (god) { - snake0->x = snake0->y = - SCREEN_HEIGHT / 2; - if (flappy) { - snake0->next->x = - SCREEN_HEIGHT / - 2 - SCREEN_UNIT; - snake0->next->y = - SCREEN_HEIGHT / - 2; - } - } - break; - case SNAKE_MUSIC: -#ifdef SOUND - if (Mix_PausedMusic()) - Mix_ResumeMusic(); - else - Mix_PauseMusic(); -#endif /* SOUND */ - break; - case SNAKE_TICK_DECREASE: - if (god && !flappy && delay.tv_nsec - - TICK_TIME_DEC >= TICK_TIME_MIN) - delay.tv_nsec -= TICK_TIME_DEC; - break; - case SNAKE_TICK_INCREASE: - if (god && !flappy) - delay.tv_nsec += TICK_TIME_DEC; - break; - case SNAKE_PAUSE: - wait = 1; - break; - default: - break; - } - } else { - switch (input) { - case SNAKE_RESET: - wait = 0; - - pthread_mutex_lock(&mutex); - reset = 1; - pthread_mutex_unlock(&mutex); - break; - case SNAKE_MUSIC: -#ifdef SOUND - if (Mix_PausedMusic()) - Mix_ResumeMusic(); - else - Mix_PauseMusic(); -#endif /* SOUND */ - break; - case SNAKE_SELECT: - if (wait) - break; - - if (selection == 0) { - flappy = 0; - multiplayer = 0; - } else if (selection == 1) { - flappy = 0; - multiplayer = 1; - } else if (selection == 2) { - multiplayer = 0; - flappy = 1; - } - - delay.tv_nsec = TICK_TIME_INIT; - - god = 0; - - head[0][0] = head[0][1] = - SNAKE_UP; - head[1][0] = head[1][1] = - SNAKE_EMPTY; - - score = 0; - text_score.cache = 0; - - if (flappy) { - delay.tv_nsec = TICK_TIME_INIT / - SCREEN_UNIT; - - game_snake_init(&snake0, 0); - - snake0->next->x = - SCREEN_HEIGHT / 2 - - SCREEN_UNIT; - snake0->next->y = - SCREEN_HEIGHT / 2; - - game_pipe_init(&gap); - - pthread_mutex_lock(&mutex); - begin = 0; - distance = 0; - speed = 1; - pthread_mutex_unlock(&mutex); - } else if (!multiplayer) { - game_snake_init( - &snake0, 0); - game_fruit( - fruit, - &snake0); - } else { - game_snake_init( - &snake0, - -4 * - SCREEN_UNIT); - game_snake_init( - &snake1, - 4 * - SCREEN_UNIT); - } - start = 0; - - pthread_mutex_lock(&mutex); - reset = 0; - pthread_cond_broadcast(&cond); - pthread_mutex_unlock(&mutex); - break; - case SNAKE_PAUSE: - wait = 0; - - pthread_mutex_lock(&mutex); - pthread_cond_broadcast(&cond); - pthread_mutex_unlock(&mutex); - break; - case SNAKE_UP: - if ((start || reset) && - selection - 1 >= 0) - selection--; - break; - case SNAKE_DOWN: - if ((start || reset) && - selection + 1 <= 2) - selection++; - break; - default: - break; - } - } - input = SNAKE_EMPTY; - } - - start = 0; - end = 1; - - wait = 0; - flappy = 1; - - pthread_mutex_lock(&mutex); - reset = 0; - pthread_cond_broadcast(&cond); - pthread_mutex_unlock(&mutex); - - #ifdef GPIO - - pthread_join(th_gpio, NULL); - - #endif /* GPIO */ - - pthread_join(th_gravity, NULL); - pthread_join(th_logic, NULL); - pthread_join(th_renderer, NULL); - pthread_cond_destroy(&cond); - pthread_mutex_destroy(&mutex); - -#ifdef GPIO - -#ifdef __linux__ - - gpio_unexport(GPIO_PIN_IN0); - gpio_unexport(GPIO_PIN_IN1); - gpio_unexport(GPIO_PIN_IN2); - gpio_unexport(GPIO_PIN_IN3); - gpio_unexport(GPIO_PIN_IN4); - gpio_unexport(GPIO_PIN_IN5); - gpio_unexport(GPIO_PIN_IN6); - gpio_unexport(GPIO_PIN_IN7); - gpio_unexport(GPIO_PIN_IN8); - gpio_unexport(GPIO_PIN_IN9); - gpio_unexport(GPIO_PIN_IN10); - gpio_unexport(GPIO_PIN_IN11); - gpio_unexport(GPIO_PIN_IN12); - gpio_unexport(GPIO_PIN_IN13); - gpio_unexport(GPIO_PIN_IN14); - gpio_unexport(GPIO_PIN_IN15); - gpio_unexport(GPIO_PIN_IN16); - gpio_unexport(GPIO_PIN_IN17); - gpio_unexport(GPIO_PIN_IN18); - -#endif /* __linux__ */ - -#endif /* GPIO */ - -#ifdef SOUND - Mix_Quit(); -#endif /* SOUND */ - - TTF_Quit(); - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - SDL_Quit(); -} |