diff --git a/Makefile.common b/Makefile.common index 4ec5d8990f..16e902f259 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1584,6 +1584,12 @@ ifdef HAVE_COMPRESSION DEFINES += -DHAVE_COMPRESSION endif +# Easter Egg +ifeq ($(HAVE_EASTEREGG),1) + DEFINES += -DHAVE_EASTEREGG + OBJ += cores/libretro-gong/gong.o +endif + # Video4Linux 2 ifeq ($(HAVE_V4L2),1) diff --git a/Makefile.griffin b/Makefile.griffin index 98ec4f48ca..bba02947fa 100644 --- a/Makefile.griffin +++ b/Makefile.griffin @@ -430,7 +430,7 @@ else ifeq ($(platform), windows_msvc2005_x86) CXX = cl.exe LD = link.exe - PLATCFLAGS += -D_WIN32 -D_WIN32_WINNT=0x0410 -D__STDC_CONSTANT_MACROS -D_MBCS + PLATCFLAGS += -D_WIN32 -D_WIN32_WINNT=0x0410 -D__STDC_CONSTANT_MACROS -D_MBCS -DHAVE_EASTEREGG LDFLAGS += shell32.lib user32.lib gdi32.lib comdlg32.lib winmm.lib ole32.lib msimg32.lib PATH := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/bin"):$(PATH) @@ -479,7 +479,7 @@ else ifneq (,$(findstring windows_msvc2010,$(platform))) LD = link.exe PLATCFLAGS += -D_WIN32 -D__STDC_CONSTANT_MACROS -D_MBCS - PLATCFLAGS += -D__i686__ -D__SSE__ -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS -DHAVE_CC_RESAMPLER -DHAVE_GL_SYNC -DHAVE_GLSL -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_OPENGL -DHAVE_SHADERPIPELINE -DHAVE_UPDATE_ASSETS -DWIN32 + PLATCFLAGS += -D__i686__ -D__SSE__ -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS -DHAVE_CC_RESAMPLER -DHAVE_GL_SYNC -DHAVE_GLSL -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_OPENGL -DHAVE_SHADERPIPELINE -DHAVE_UPDATE_ASSETS -DWIN32 -DHAVE_EASTEREGG LDFLAGS += shell32.lib user32.lib gdi32.lib comdlg32.lib winmm.lib ole32.lib iphlpapi.lib PlatformSuffix = $(subst windows_msvc2010_,,$(platform)) @@ -550,7 +550,7 @@ else ifneq (,$(findstring windows_msvc2012,$(platform))) LD = link.exe PLATCFLAGS += -D_WIN32 -D__STDC_CONSTANT_MACROS -D_MBCS - PLATCFLAGS += -D__i686__ -D__SSE__ -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS -DHAVE_CC_RESAMPLER -DHAVE_GL_SYNC -DHAVE_GLSL -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_OPENGL -DHAVE_SHADERPIPELINE -DHAVE_UPDATE_ASSETS -DWIN32 + PLATCFLAGS += -D__i686__ -D__SSE__ -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS -DHAVE_CC_RESAMPLER -DHAVE_GL_SYNC -DHAVE_GLSL -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_OPENGL -DHAVE_SHADERPIPELINE -DHAVE_UPDATE_ASSETS -DWIN32 -DHAVE_EASTEREGG LDFLAGS += shell32.lib user32.lib gdi32.lib comdlg32.lib winmm.lib ole32.lib iphlpapi.lib PlatformSuffix = $(subst windows_msvc2012_,,$(platform)) @@ -625,7 +625,7 @@ else ifneq (,$(findstring windows_msvc2013,$(platform))) LD = link.exe PLATCFLAGS += -D_WIN32 -D__STDC_CONSTANT_MACROS -D_MBCS - PLATCFLAGS += -D__i686__ -D__SSE__ -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS -DHAVE_CC_RESAMPLER -DHAVE_GL_SYNC -DHAVE_GLSL -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_OPENGL -DHAVE_SHADERPIPELINE -DHAVE_UPDATE_ASSETS -DWIN32 + PLATCFLAGS += -D__i686__ -D__SSE__ -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS -DHAVE_CC_RESAMPLER -DHAVE_GL_SYNC -DHAVE_GLSL -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_OPENGL -DHAVE_SHADERPIPELINE -DHAVE_UPDATE_ASSETS -DWIN32 -DHAVE_EASTEREGG LDFLAGS += shell32.lib user32.lib gdi32.lib comdlg32.lib winmm.lib ole32.lib iphlpapi.lib PlatformSuffix = $(subst windows_msvc2013_,,$(platform)) @@ -700,7 +700,7 @@ else ifneq (,$(findstring windows_msvc2015,$(platform))) LD = link.exe PLATCFLAGS += -D_WIN32 -D__STDC_CONSTANT_MACROS -D_MBCS - PLATCFLAGS += -D__i686__ -D__SSE__ -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS -DHAVE_CC_RESAMPLER -DHAVE_GL_SYNC -DHAVE_GLSL -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_OPENGL -DHAVE_SHADERPIPELINE -DHAVE_UPDATE_ASSETS -DWIN32 + PLATCFLAGS += -D__i686__ -D__SSE__ -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS -DHAVE_CC_RESAMPLER -DHAVE_GL_SYNC -DHAVE_GLSL -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_OPENGL -DHAVE_SHADERPIPELINE -DHAVE_UPDATE_ASSETS -DWIN32 -DHAVE_EASTEREGG LDFLAGS += shell32.lib user32.lib gdi32.lib comdlg32.lib winmm.lib ole32.lib iphlpapi.lib PlatformSuffix = $(subst windows_msvc2015_,,$(platform)) diff --git a/core_type.h b/core_type.h index e8933de6bd..40b2d8b16e 100644 --- a/core_type.h +++ b/core_type.h @@ -24,7 +24,8 @@ enum rarch_core_type CORE_TYPE_MPV, CORE_TYPE_IMAGEVIEWER, CORE_TYPE_NETRETROPAD, - CORE_TYPE_VIDEO_PROCESSOR + CORE_TYPE_VIDEO_PROCESSOR, + CORE_TYPE_GONG }; #endif diff --git a/cores/internal_cores.h b/cores/internal_cores.h index 08e916d63e..ff20a5180a 100644 --- a/cores/internal_cores.h +++ b/cores/internal_cores.h @@ -360,6 +360,62 @@ size_t libretro_videoprocessor_retro_get_memory_size(unsigned id); #endif +#ifdef HAVE_EASTEREGG +/* Internal gong core. */ + +void libretro_gong_retro_init(void); + +void libretro_gong_retro_deinit(void); + +unsigned libretro_gong_retro_api_version(void); + +void libretro_gong_retro_get_system_info(struct retro_system_info *info); + +void libretro_gong_retro_get_system_av_info(struct retro_system_av_info *info); + +void libretro_gong_retro_set_environment(retro_environment_t cb); + +void libretro_gong_retro_set_video_refresh(retro_video_refresh_t cb); + +void libretro_gong_retro_set_audio_sample(retro_audio_sample_t cb); + +void libretro_gong_retro_set_audio_sample_batch(retro_audio_sample_batch_t cb); + +void libretro_gong_retro_set_input_poll(retro_input_poll_t cb); + +void libretro_gong_retro_set_input_state(retro_input_state_t cb); + +void libretro_gong_retro_set_controller_port_device(unsigned port, unsigned device); + +void libretro_gong_retro_reset(void); + +void libretro_gong_retro_run(void); + +size_t libretro_gong_retro_serialize_size(void); + +bool libretro_gong_retro_serialize(void *data, size_t size); + +bool libretro_gong_retro_unserialize(const void *data, size_t size); + +void libretro_gong_retro_cheat_reset(void); + +void libretro_gong_retro_cheat_set(unsigned index, bool enabled, const char *code); + +bool libretro_gong_retro_load_game(const struct retro_game_info *game); + +bool libretro_gong_retro_load_game_special(unsigned game_type, + const struct retro_game_info *info, size_t num_info); + +void libretro_gong_retro_unload_game(void); + +unsigned libretro_gong_retro_get_region(void); + +void *libretro_gong_retro_get_memory_data(unsigned id); + +size_t libretro_gong_retro_get_memory_size(unsigned id); + +#endif + RETRO_END_DECLS #endif diff --git a/cores/libretro-gong/gong.c b/cores/libretro-gong/gong.c new file mode 100644 index 0000000000..da1e621f5b --- /dev/null +++ b/cores/libretro-gong/gong.c @@ -0,0 +1,696 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2018 - Brad Parker + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +/* Libretro port by Brad Parker, + Original source code by Dan Zaidan: https://danzaidan.itch.io/ + Original license: + "You can do whatever you want with the code, but I am providing it as is without any warranty whatsoever." + */ + +#include +#include +#include +#include + +#ifdef RARCH_INTERNAL +#include "internal_cores.h" +#define GONG_CORE_PREFIX(s) libretro_gong_##s +#else +#define GONG_CORE_PREFIX(s) s +#endif + +#define WIDTH 320 +#define HEIGHT 240 +#define FPS (60000.0f / 1000.0f) + +static retro_log_printf_t GONG_CORE_PREFIX(log_cb); +static retro_video_refresh_t GONG_CORE_PREFIX(video_cb); +static retro_input_poll_t GONG_CORE_PREFIX(input_poll_cb); +static retro_input_state_t GONG_CORE_PREFIX(input_state_cb); +static retro_audio_sample_t GONG_CORE_PREFIX(audio_cb); +static retro_audio_sample_batch_t GONG_CORE_PREFIX(audio_batch_cb); +static retro_environment_t GONG_CORE_PREFIX(environ_cb); + +static const char *GONG_CORE_PREFIX(valid_extensions) = "gong"; + +static float player1_py = 0.0f; +static float player1_dpy = 0.0f; +static float player2_py = 0.0f; +static float player2_dpy = 0.0f; +static float player2_speed = 0.0f; +static float ball_px = 0.0f; +static float ball_py = 0.0f; +static float ball_dpx = 0.0f; +static float ball_dpy = 0.0f; +static float ball_speed = 0.0f; +static bool is_initialized = 0; +static unsigned player1_score = 0; +static unsigned player2_score = 0; +static float current_play_points = 0.0f; + +static unsigned char *video_buf = NULL; + +enum +{ + B_MOVE_UP, + B_MOVE_DOWN, + B_SPEED_UP, + B_COUNT /* This should always be in the bottom */ +}; + +typedef struct +{ + int half_transition_count; + bool ended_down; +} Game_Button_State; + +typedef struct +{ + Game_Button_State buttons[B_COUNT]; + float last_dt; +} Game_Input; + +static Game_Input g_input = {0}; + +typedef struct +{ + /* Pixels are always 32-bit wide, memory order XX BB GG RR */ + int width; + int height; + int pitch; + void *memory; +} Game_Offscreen_Buffer; + +static Game_Offscreen_Buffer game_buffer = {0}; + +static void game_update_and_render(Game_Input *input, Game_Offscreen_Buffer *draw_buffer); + +static const struct retro_controller_description pads[] = { + { "Joypad", RETRO_DEVICE_JOYPAD }, + { NULL, 0 }, +}; + +static const struct retro_controller_info ports[] = { + { pads, 1 }, + { 0 }, +}; + +struct retro_input_descriptor desc[] = { + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, + { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" }, + { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" }, + + { 0 }, +}; + +static INLINE bool pressed(Game_Button_State state) +{ + return state.half_transition_count > 1 || + (state.half_transition_count == 1 && state.ended_down); +} + +static INLINE bool is_down(Game_Button_State state) +{ + return state.ended_down; +} + +void GONG_CORE_PREFIX(retro_get_system_info)(struct retro_system_info *info) +{ + info->library_name = "gong"; + info->library_version = "v1.0"; + info->need_fullpath = false; + info->block_extract = false; + info->valid_extensions = GONG_CORE_PREFIX(valid_extensions); +} + +void GONG_CORE_PREFIX(retro_get_system_av_info)(struct retro_system_av_info *info) +{ + info->geometry.base_width = WIDTH; + info->geometry.base_height = HEIGHT; + info->geometry.max_width = WIDTH; + info->geometry.max_height = HEIGHT; + info->geometry.aspect_ratio = 4.0f / 3.0f; + info->timing.fps = FPS; + info->timing.sample_rate = 44100.0; +} + +void GONG_CORE_PREFIX(retro_init)(void) +{ + struct retro_log_callback log; + + if (GONG_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) + GONG_CORE_PREFIX(log_cb) = log.log; + else + GONG_CORE_PREFIX(log_cb) = NULL; + + video_buf = (unsigned char*)calloc(1, WIDTH * HEIGHT * sizeof(unsigned)); + + game_buffer.width = WIDTH; + game_buffer.height = HEIGHT; + game_buffer.pitch = WIDTH * sizeof(unsigned); + game_buffer.memory = video_buf; + + g_input.last_dt = 1.0f / FPS; +} + +void GONG_CORE_PREFIX(retro_deinit)(void) +{ + if (video_buf) + free(video_buf); + + video_buf = NULL; + game_buffer.memory = NULL; +} + +void GONG_CORE_PREFIX(retro_set_environment)(retro_environment_t cb) +{ + bool no_content = true; + + static const struct retro_variable vars[] = { + { NULL, NULL }, + }; + + GONG_CORE_PREFIX(environ_cb) = cb; + + cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_content); + cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars); + cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); +} + +void GONG_CORE_PREFIX(retro_set_video_refresh)(retro_video_refresh_t cb) +{ + GONG_CORE_PREFIX(video_cb) = cb; +} + +void GONG_CORE_PREFIX(retro_set_audio_sample)(retro_audio_sample_t cb) +{ + GONG_CORE_PREFIX(audio_cb) = cb; +} + +void GONG_CORE_PREFIX(retro_set_audio_sample_batch)(retro_audio_sample_batch_t cb) +{ + GONG_CORE_PREFIX(audio_batch_cb) = cb; +} + +void GONG_CORE_PREFIX(retro_set_input_poll)(retro_input_poll_t cb) +{ + GONG_CORE_PREFIX(input_poll_cb) = cb; +} + +void GONG_CORE_PREFIX(retro_set_input_state)(retro_input_state_t cb) +{ + GONG_CORE_PREFIX(input_state_cb) = cb; +} + +void GONG_CORE_PREFIX(retro_set_controller_port_device)(unsigned a, unsigned b) +{ +} + +void GONG_CORE_PREFIX(retro_reset)(void) +{ + player1_py = 0.0f; + player1_dpy = 0.0f; + player2_py = 0.0f; + player2_dpy = 0.0f; + player2_speed = 0.0f; + player1_score = 0; + player2_score = 0; + is_initialized = 0; +} + +size_t GONG_CORE_PREFIX(retro_serialize_size)(void) +{ + return 0; +} + +bool GONG_CORE_PREFIX(retro_serialize)(void *data, size_t size) +{ + (void)data; + (void)size; + return false; +} + +bool GONG_CORE_PREFIX(retro_unserialize)(const void *data, size_t size) +{ + (void)data; + (void)size; + return false; +} + +void GONG_CORE_PREFIX(retro_cheat_reset)(void) +{ +} + +void GONG_CORE_PREFIX(retro_cheat_set)(unsigned a, bool b, const char * c) +{ +} + +bool GONG_CORE_PREFIX(retro_load_game)(const struct retro_game_info *info) +{ + enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888; + + if (!GONG_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) + { + if (GONG_CORE_PREFIX(log_cb)) + GONG_CORE_PREFIX(log_cb)(RETRO_LOG_INFO, "XRGB8888 is not supported.\n"); + return false; + } + + return true; +} + +bool GONG_CORE_PREFIX(retro_load_game_special)(unsigned a, const struct retro_game_info *b, size_t c) +{ + return false; +} + +void GONG_CORE_PREFIX(retro_unload_game)(void) +{ +} + +unsigned GONG_CORE_PREFIX(retro_get_region)(void) +{ + return RETRO_REGION_NTSC; +} + +void* GONG_CORE_PREFIX(retro_get_memory_data)(unsigned id) +{ + return NULL; +} + +size_t GONG_CORE_PREFIX(retro_get_memory_size)(unsigned id) +{ + return 0; +} + +static void process_joypad(Game_Button_State *new_state, bool is_down) +{ + if (new_state->ended_down != is_down) + { + new_state->ended_down = is_down; + new_state->half_transition_count += 1; + } +} + +static bool is_key_up_or_down(int16_t input, int16_t not_input, int key) +{ + if (input & (1 << key) || not_input & (1 << key)) + return true; + + return false; +} + +void GONG_CORE_PREFIX(retro_run)(void) +{ + uint16_t input = 0; + uint16_t not_input = 0; + static uint16_t previnput = 0; + uint16_t realinput = 0; + int i = 0; + int16_t analogYLeft1 = 0; + int16_t analogYRight1 = 0; + + GONG_CORE_PREFIX(input_poll_cb)(); + + for (i = 0; i < 16; i++) + { + if (GONG_CORE_PREFIX(input_state_cb)(0, RETRO_DEVICE_JOYPAD, 0, i)) + { + realinput |= 1 << i; + } + } + + analogYLeft1 = GONG_CORE_PREFIX(input_state_cb)(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / 5000.0f; + analogYRight1 = GONG_CORE_PREFIX(input_state_cb)(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / 5000.0f; + + if (analogYLeft1 > 0) + realinput |= (1 << RETRO_DEVICE_ID_JOYPAD_DOWN); + else if (analogYRight1 > 0) + realinput |= (1 << RETRO_DEVICE_ID_JOYPAD_DOWN); + + if (analogYLeft1 < 0) + realinput |= (1 << RETRO_DEVICE_ID_JOYPAD_UP); + else if (analogYRight1 < 0) + realinput |= (1 << RETRO_DEVICE_ID_JOYPAD_UP); + + input = realinput & ~previnput; + not_input = previnput & ~realinput; + + if (is_key_up_or_down(input, not_input, RETRO_DEVICE_ID_JOYPAD_UP)) + process_joypad(&g_input.buttons[B_MOVE_UP], realinput & (1 << RETRO_DEVICE_ID_JOYPAD_UP)); + else if (is_key_up_or_down(input, not_input, RETRO_DEVICE_ID_JOYPAD_DOWN)) + process_joypad(&g_input.buttons[B_MOVE_DOWN], realinput & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN)); + else if (is_key_up_or_down(input, not_input, RETRO_DEVICE_ID_JOYPAD_DOWN)) + process_joypad(&g_input.buttons[B_MOVE_DOWN], realinput & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN)); + + if (is_key_up_or_down(input, not_input, RETRO_DEVICE_ID_JOYPAD_A)) + process_joypad(&g_input.buttons[B_SPEED_UP], realinput & (1 << RETRO_DEVICE_ID_JOYPAD_A)); + else if (is_key_up_or_down(input, not_input, RETRO_DEVICE_ID_JOYPAD_B)) + process_joypad(&g_input.buttons[B_SPEED_UP], realinput & (1 << RETRO_DEVICE_ID_JOYPAD_B)); + else if (is_key_up_or_down(input, not_input, RETRO_DEVICE_ID_JOYPAD_X)) + process_joypad(&g_input.buttons[B_SPEED_UP], realinput & (1 << RETRO_DEVICE_ID_JOYPAD_X)); + else if (is_key_up_or_down(input, not_input, RETRO_DEVICE_ID_JOYPAD_Y)) + process_joypad(&g_input.buttons[B_SPEED_UP], realinput & (1 << RETRO_DEVICE_ID_JOYPAD_Y)); + + previnput = realinput; + + game_update_and_render(&g_input, &game_buffer); + + GONG_CORE_PREFIX(video_cb)(video_buf, WIDTH, HEIGHT, WIDTH * sizeof(uint32_t)); +} + +unsigned GONG_CORE_PREFIX(retro_api_version)(void) +{ + return RETRO_API_VERSION; +} + +static void draw_rect_in_pixels(Game_Offscreen_Buffer *buffer, unsigned color, int min_x, int min_y, int max_x, int max_y) +{ + int y; + + min_x = MAX(min_x, 0); + min_y = MAX(min_y, 0); + max_x = MIN(max_x, buffer->width); + max_y = MIN(max_y, buffer->height); + + for (y = min_y; y < max_y; y++) + { + int x; + + for (x = min_x; x < max_x; x++) + { + unsigned *pixel = (unsigned*)((unsigned char*)buffer->memory + ((buffer->width * (buffer->height - y - 1) + x) * sizeof(unsigned))); + + *pixel++ = color; + } + } +} + +static void clear(Game_Offscreen_Buffer *buffer, unsigned color) +{ + draw_rect_in_pixels(buffer, color, 0, 0, buffer->width, buffer->height); +} + +static void draw_rect(Game_Offscreen_Buffer *buffer, unsigned color, float x, float y, float half_size_x, float half_size_y) +{ + /* @Hardcoded to always keep the playing field area on screen, no matter the aspect ratio */ + float scale = .01f; + float relative_axis = (float)buffer->height; + int min_x, min_y, max_x, max_y; + + if ((float)buffer->width / (float)buffer->height < 1.77f) + { + relative_axis = (float)buffer->width; + scale = .0056f; + } + + half_size_x *= relative_axis * scale; + half_size_y *= relative_axis * scale; + x *= relative_axis * scale; + y *= relative_axis * scale; + + x = x + buffer->width / 2; + y = y + buffer->height / 2; + + min_x = (unsigned)(x - half_size_x); + min_y = (unsigned)(y - half_size_y); + max_x = (unsigned)(x + half_size_x); + max_y = (unsigned)(y + half_size_y); + + draw_rect_in_pixels(buffer, color, min_x, min_y, max_x, max_y); +} + +static void draw_number(Game_Offscreen_Buffer *buffer, unsigned number, unsigned color, float x, float y) +{ + float at_x = x; + + do { + unsigned alg = number % 10; + + number /= 10; + + switch (alg) + { + case 0: + { + draw_rect(buffer, color, at_x - 2.f, y, .5f, 4.f); + draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.f); + draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f); + draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f); + break; + } + + case 1: + { + draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.5f); + break; + } + + case 2: + { + draw_rect(buffer, color, at_x - 2.f, y - 2.f, .5f, 2.f); + draw_rect(buffer, color, at_x + 2.f, y + 2.f, .5f, 2.f); + draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f); + draw_rect(buffer, color, at_x, y, 2.5f, .5f); + draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f); + break; + } + + case 3: + { + draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.f); + draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f); + draw_rect(buffer, color, at_x, y, 2.5f, .5f); + draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f); + break; + }; + + case 4: + { + draw_rect(buffer, color, at_x, y, 2.5f, .5f); + draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.5f); + draw_rect(buffer, color, at_x - 2.f, y+2.5f, .5f, 2.f); + break; + }; + + case 5: + { + draw_rect(buffer, color, at_x + 2.f, y-2.f, .5f, 2.f); + draw_rect(buffer, color, at_x - 2.f, y+2.f, .5f, 2.f); + draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f); + draw_rect(buffer, color, at_x, y, 2.5f, .5f); + draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f); + break; + }; + + case 6: + { + draw_rect(buffer, color, at_x + 2.f, y-2.f, .5f, 2.f); + draw_rect(buffer, color, at_x - 2.f, y, .5f, 4.f); + draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f); + draw_rect(buffer, color, at_x, y, 2.5f, .5f); + draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f); + break; + }; + + case 7: + { + draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.5f); + draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f); + break; + }; + + case 8: + { + draw_rect(buffer, color, at_x - 2.f, y, .5f, 4.f); + draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.f); + draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f); + draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f); + draw_rect(buffer, color, at_x, y, 2.5f, .5f); + break; + }; + + case 9: + { + draw_rect(buffer, color, at_x - 2.f, y + 2.f, .5f, 2.f); + draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.f); + draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f); + draw_rect(buffer, color, at_x, y, 2.5f, .5f); + draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f); + break; + }; + + default: + break; + } + + at_x -= 7.f; + } while(number > 0); +} + +static void game_update_and_render(Game_Input *input, Game_Offscreen_Buffer *draw_buffer) +{ + const float initial_ball_speed = 80.f; + float playing_field_x = 85.f; + float playing_field_y = 48.f; + float player_size_x = 2.5f; + float player_size_y = 10.f; + + if (!is_initialized) + { + is_initialized = 1; + ball_px = 0; + ball_py = 0; + ball_dpx = initial_ball_speed; + ball_dpy = 0; + current_play_points = 10.f; + player2_speed = 80.f; + } + + { + float speed = 80.f; + player1_dpy = 0.f; + + if (is_down(input->buttons[B_SPEED_UP])) + speed = 150.f; + + if (is_down(input->buttons[B_MOVE_UP])) + { + if (player1_py < playing_field_y - player_size_y) + { + player1_dpy = speed; + } + + if (player1_py < -playing_field_y + player_size_y) + { + player1_py = -playing_field_y + player_size_y; + player1_dpy = 0.f; + } + } + if (is_down(input->buttons[B_MOVE_DOWN])) + { + if (player1_py > -playing_field_y + player_size_y) + { + player1_dpy = -speed; + } + + if (player1_py < -playing_field_y + player_size_y) + { + player1_py = -playing_field_y + player_size_y; + player1_dpy = 0.f; + } + } + + player1_py += player1_dpy * input->last_dt; + } + + { + player2_dpy = (ball_py - player2_py) * 100.f; + player2_dpy = MIN(player2_dpy, player2_speed); + player2_dpy = MAX(player2_dpy, -player2_speed); + player2_py += player2_dpy * input->last_dt; + + if (player2_py < -playing_field_y + player_size_y) + { + player2_py = -playing_field_y + player_size_y; + player2_dpy = 0.f; + } + + if (player2_py > playing_field_y - player_size_y) + { + player2_py = playing_field_y - player_size_y; + player2_dpy = 0.f; + } + } + + ball_px += ball_dpx * input->last_dt; + + if (ball_dpx > 0) + { + ball_dpx += 10.f * input->last_dt; + } + else + { + ball_dpx -= 10.f * input->last_dt; + } + + ball_py += ball_dpy * input->last_dt; + + if (ball_py > playing_field_y - 1.f) + { + ball_py = playing_field_y - 1.f; + ball_dpy *= -1.f; + } + else if (ball_py < -playing_field_y + 1) + { + ball_py = -playing_field_y + 1.f; + ball_dpy *= -1; + } + + if (ball_px > 80.f - 2.5f - 1.f) /* @Hardcoded */ + { + if ((ball_py >= (player2_py - 10.f)) && (ball_py <= (player2_py + 10.f))) + { + ball_dpx *= -1.f; + ball_px = 80.f - 2.5f - 1.f; /* @Hardcoded */ + ball_dpy = (ball_py - player2_py) + player2_dpy; + ++current_play_points; + } + else if (ball_px >= playing_field_x - 1) + { + ball_px = 0; + ball_py = 0; + ball_dpy = 0; + ball_dpx = -initial_ball_speed; + player2_score += (unsigned)current_play_points; + current_play_points = 10.f; + } + } + else if (ball_px < -80 + 2.5f + 1.f) /* @Hardcoded */ + { + if ((ball_py >= (player1_py - 10.f)) && (ball_py <= (player1_py + 10.f))) + { + ball_dpx *= -1.f; + ball_px = -80 + 2.5f + 1.f; /* @Hardcoded */ + ball_dpy = (ball_py - player1_py) + player1_dpy; + ++current_play_points; + } + else if (ball_px <= -playing_field_x + 1) + { + ball_px = 0; + ball_py = 0; + ball_dpy = 0; + ball_dpx = initial_ball_speed; + player1_score += (unsigned)current_play_points; + current_play_points = 10.f; + player2_speed += current_play_points * 0.01f; + } + } + + clear(draw_buffer, 0x021077); + draw_rect(draw_buffer, 0x000530, 0.f, 0.f, playing_field_x, playing_field_y); + + draw_rect(draw_buffer, 0x00ffff, -80.f, player1_py, player_size_x, player_size_y); + draw_rect(draw_buffer, 0x00ffff, 80.f, player2_py, player_size_x, player_size_y); + + draw_rect(draw_buffer, 0xffff00, ball_px, ball_py, 1.f, 1.f); + + draw_number(draw_buffer, (unsigned)current_play_points, 0xaaaaaa, 0.f, 38.f); + draw_number(draw_buffer, player1_score, 0xff6611, 20.f, 38.f); + draw_number(draw_buffer, player2_score, 0xff6611, -20.f, 38.f); +} diff --git a/cores/libretro-gong/internal_cores.h b/cores/libretro-gong/internal_cores.h new file mode 100644 index 0000000000..7e1a2aab98 --- /dev/null +++ b/cores/libretro-gong/internal_cores.h @@ -0,0 +1 @@ +#include "../internal_cores.h" diff --git a/cores/libretro-gong/link.T b/cores/libretro-gong/link.T new file mode 100644 index 0000000000..b0c262db9e --- /dev/null +++ b/cores/libretro-gong/link.T @@ -0,0 +1,5 @@ +{ + global: retro_*; + local: *; +}; + diff --git a/dynamic.c b/dynamic.c index cbe706c79a..c7c3ce52c9 100644 --- a/dynamic.c +++ b/dynamic.c @@ -108,6 +108,10 @@ static dylib_t lib_handle; #define SYMBOL_VIDEOPROCESSOR(x) current_core->x = libretro_videoprocessor_##x #endif +#ifdef HAVE_EASTEREGG +#define SYMBOL_GONG(x) current_core->x = libretro_gong_##x +#endif + static bool ignore_environment_cb = false; static bool core_set_shared_context = false; static bool *load_no_content_hook = NULL; @@ -777,6 +781,43 @@ bool init_libretro_sym_custom(enum rarch_core_type type, struct retro_core_t *cu SYMBOL_VIDEOPROCESSOR(retro_get_region); SYMBOL_VIDEOPROCESSOR(retro_get_memory_data); SYMBOL_VIDEOPROCESSOR(retro_get_memory_size); +#endif + break; + case CORE_TYPE_GONG: +#ifdef HAVE_EASTEREGG + SYMBOL_GONG(retro_init); + SYMBOL_GONG(retro_deinit); + + SYMBOL_GONG(retro_api_version); + SYMBOL_GONG(retro_get_system_info); + SYMBOL_GONG(retro_get_system_av_info); + + SYMBOL_GONG(retro_set_environment); + SYMBOL_GONG(retro_set_video_refresh); + SYMBOL_GONG(retro_set_audio_sample); + SYMBOL_GONG(retro_set_audio_sample_batch); + SYMBOL_GONG(retro_set_input_poll); + SYMBOL_GONG(retro_set_input_state); + + SYMBOL_GONG(retro_set_controller_port_device); + + SYMBOL_GONG(retro_reset); + SYMBOL_GONG(retro_run); + + SYMBOL_GONG(retro_serialize_size); + SYMBOL_GONG(retro_serialize); + SYMBOL_GONG(retro_unserialize); + + SYMBOL_GONG(retro_cheat_reset); + SYMBOL_GONG(retro_cheat_set); + + SYMBOL_GONG(retro_load_game); + SYMBOL_GONG(retro_load_game_special); + + SYMBOL_GONG(retro_unload_game); + SYMBOL_GONG(retro_get_region); + SYMBOL_GONG(retro_get_memory_data); + SYMBOL_GONG(retro_get_memory_size); #endif break; } diff --git a/griffin/griffin.c b/griffin/griffin.c index 6318513754..a76f34f015 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1554,3 +1554,7 @@ SSL #endif #endif #endif + +#ifdef HAVE_EASTEREGG +#include "../cores/libretro-gong/gong.c" +#endif diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 9099662cd8..e347201cdf 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -2352,7 +2352,6 @@ static void materialui_list_insert(void *userdata, node->texture_switch2_index = MUI_TEXTURE_DATABASE; node->texture_switch2_set = true; break; - case 32: /* TODO: Need to find out what this is */ case FILE_TYPE_RDB_ENTRY: node->texture_switch2_index = MUI_TEXTURE_SETTINGS; node->texture_switch2_set = true; diff --git a/msg_hash.c b/msg_hash.c index a9e7e7e5b2..2a629e0a09 100644 --- a/msg_hash.c +++ b/msg_hash.c @@ -211,6 +211,8 @@ uint32_t msg_hash_calculate(const char *s) #define MENU_VALUE_FILE_JPEG_CAPS 0x7c87010bU #define MENU_VALUE_FILE_PNG 0x0b889deaU #define MENU_VALUE_FILE_PNG_CAPS 0x0b88118aU +#define MENU_VALUE_FILE_GONG 0x7c977150U +#define MENU_VALUE_FILE_GONG_CAPS 0x7c8558d0U #define MENU_VALUE_FILE_TGA 0x0b88ae01U #define MENU_VALUE_FILE_BMP 0x0b886244U @@ -390,6 +392,11 @@ enum msg_file_type msg_hash_to_file_type(uint32_t hash) return FILE_TYPE_TGA; case MENU_VALUE_FILE_BMP: return FILE_TYPE_BMP; +#endif +#ifdef HAVE_EASTEREGG + case MENU_VALUE_FILE_GONG: + case MENU_VALUE_FILE_GONG_CAPS: + return FILE_TYPE_GONG; #endif case HASH_EXTENSION_CUE: case HASH_EXTENSION_CUE_UPPERCASE: diff --git a/msg_hash.h b/msg_hash.h index 8d52407ba1..bdd5a4a8b0 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -141,6 +141,8 @@ enum msg_file_type FILE_TYPE_DIRECT_LOAD, + FILE_TYPE_GONG, + FILE_TYPE_LAST }; diff --git a/paths.c b/paths.c index 67a71840c2..cb41f93438 100644 --- a/paths.c +++ b/paths.c @@ -779,6 +779,10 @@ enum rarch_content_type path_is_media_type(const char *path) case FILE_TYPE_XM: return RARCH_CONTENT_MUSIC; #endif +#ifdef HAVE_EASTEREGG + case FILE_TYPE_GONG: + return RARCH_CONTENT_GONG; +#endif case FILE_TYPE_NONE: default: diff --git a/paths.h b/paths.h index fd8e0659ef..15c49fa511 100644 --- a/paths.h +++ b/paths.h @@ -28,7 +28,8 @@ enum rarch_content_type RARCH_CONTENT_NONE = 0, RARCH_CONTENT_MOVIE, RARCH_CONTENT_MUSIC, - RARCH_CONTENT_IMAGE + RARCH_CONTENT_IMAGE, + RARCH_CONTENT_GONG }; enum rarch_path_type diff --git a/qb/config.params.sh b/qb/config.params.sh index 0ed6fb676a..c67a19b06b 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -135,3 +135,4 @@ HAVE_OSMESA=no # Off-screen Mesa rendering HAVE_VIDEOPROCESSOR=auto # Enable video processor core HAVE_VIDEOCORE=auto # Broadcom Videocore 4 support HAVE_DRMINGW=no # DrMingw exception handler +HAVE_EASTEREGG=yes diff --git a/retroarch.c b/retroarch.c index 6892dfbfd3..73593f4e4a 100644 --- a/retroarch.c +++ b/retroarch.c @@ -1310,6 +1310,12 @@ static void retroarch_main_init_media(void) retroarch_set_current_core_type(CORE_TYPE_IMAGEVIEWER, false); } break; +#endif +#ifdef HAVE_EASTEREGG + case RARCH_CONTENT_GONG: + retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_LIBRETRO, NULL); + retroarch_set_current_core_type(CORE_TYPE_GONG, false); + break; #endif default: break; @@ -2590,6 +2596,7 @@ static enum runloop_state runloop_check_state( #ifdef HAVE_MENU bool menu_driver_binding_state = menu_driver_is_binding_state(); bool menu_is_alive = menu_driver_is_alive(); + static uint64_t seq = 0; #endif #ifdef HAVE_LIBNX @@ -2860,6 +2867,32 @@ static enum runloop_state runloop_check_state( if (settings->bools.audio_enable_menu && !libretro_running) audio_driver_menu_sample(); + +#ifdef HAVE_EASTEREGG + { + if (string_is_empty(runloop_system.info.library_name) && trigger_input.data[0]) + { + seq |= trigger_input.data[0] & 0xF0; + + if (seq == 1157460427127406720ULL) + { + content_ctx_info_t content_info; + content_info.argc = 0; + content_info.argv = NULL; + content_info.args = NULL; + content_info.environ_get = NULL; + + task_push_start_builtin_core( + &content_info, + CORE_TYPE_GONG, NULL, NULL); + } + + seq <<= 8; + } + else if (!string_is_empty(runloop_system.info.library_name)) + seq = 0; + } +#endif } old_input = current_input; @@ -2877,8 +2910,12 @@ static enum runloop_state runloop_check_state( } else #endif + { + seq = 0; + if (runloop_idle) return RUNLOOP_STATE_SLEEP; + } /* Check game focus toggle */ {