From 05733649bce2623acfad7b163501c6fdefea985a Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Thu, 3 Nov 2016 22:27:01 -0400 Subject: XWorld: some fixes Fixes sound on most platforms, original root cause was bad menu code as well as DMA callbacks taking too long. Worked around with smaller chunk sizes. Permanent fix would include moving mixing out of the callback. Rewrites input with code from rockboy/doom. Cherry-picks a change from Gregory Montoir's `rawgl' to patch the code wheel screen. Finally, adds a motion blur filter on select targets. Change-Id: I8df549c923c5075800c6625c36c8202e53de1d27 --- apps/plugins/xworld/sys.c | 340 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 269 insertions(+), 71 deletions(-) (limited to 'apps/plugins/xworld/sys.c') diff --git a/apps/plugins/xworld/sys.c b/apps/plugins/xworld/sys.c index 03b032c055..b13d4fb9ed 100644 --- a/apps/plugins/xworld/sys.c +++ b/apps/plugins/xworld/sys.c @@ -130,13 +130,32 @@ static bool sys_do_help(void) rb->lcd_set_background(LCD_BLACK); #endif rb->lcd_setfont(FONT_UI); - char* help_text[] = {"XWorld", "", - "XWorld", "is", "an", "interpreter", "for", "Another", "World,", "a", "fantastic", "game", "by", "Eric", "Chahi." - }; + char *help_text[] = { + "XWorld", "", + "XWorld", "is", "a", "port", "of", "a", "bytecode", "interpreter", "for", "`Another", "World',", "a", "cinematic", "adventure", "game", "by", "Eric", "Chahi.", + "", + "", + "Level", "Codes:", "", + "Level", "1:", "LDKD", "", + "Level", "2:", "HTDC", "", + "Level", "3:", "CLLD", "", + "Level", "4:", "LBKG", "", + "Level", "5:", "XDDJ", "", + "Level", "6:", "FXLC", "", + "Level", "7:", "KRFK", "", + "Level", "8:", "KFLB", "", + "Level", "9:", "DDRX", "", + "Level", "10:", "BFLX", "", + "Level", "11:", "BRTD", "", + "Level", "12:", "TFBB", "", + "Level", "13:", "TXHF", "", + "Level", "14:", "CKJL", "", + "Level", "15:", "LFCK", "", + }; struct style_text style[] = { - {0, TEXT_CENTER | TEXT_UNDERLINE}, - LAST_STYLE_ITEM + { 0, TEXT_CENTER | TEXT_UNDERLINE }, }; + return display_text(ARRAYLEN(help_text), help_text, style, NULL, true); } @@ -149,19 +168,22 @@ static const struct opt_items scaling_settings[3] = { }; static const struct opt_items rotation_settings[3] = { - { "Disabled" , -1 }, - { "Clockwise" , -1 }, - { "Anticlockwise", -1 } + { "Disabled" , -1 }, + { "Clockwise" , -1 }, + { "Counterclockwise", -1 } }; static void do_video_settings(struct System* sys) { MENUITEM_STRINGLIST(menu, "Video Settings", NULL, "Negative", +#ifdef SYS_MOTION_BLUR + "Motion Blur", +#endif "Scaling", "Rotation", "Show FPS", - "Zoom on code", + "Zoom on Code", "Back"); int sel = 0; while(1) @@ -171,7 +193,16 @@ static void do_video_settings(struct System* sys) case 0: rb->set_bool("Negative", &sys->settings.negative_enabled); break; +#ifdef SYS_MOTION_BLUR + case 1: + rb->set_bool("Motion Blur", &sys->settings.blur); + break; +#endif +#ifndef SYS_MOTION_BLUR case 1: +#else + case 2: +#endif rb->set_option("Scaling", &sys->settings.scaling_quality, INT, scaling_settings, #ifdef HAVE_LCD_COLOR 3 @@ -186,7 +217,11 @@ static void do_video_settings(struct System* sys) sys->settings.zoom = false; } break; +#ifndef SYS_MOTION_BLUR case 2: +#else + case 3: +#endif rb->set_option("Rotation", &sys->settings.rotation_option, INT, rotation_settings, 3, NULL); if(sys->settings.rotation_option && sys->settings.zoom) @@ -196,45 +231,42 @@ static void do_video_settings(struct System* sys) } sys_rotate_keymap(sys); break; +#ifndef SYS_MOTION_BLUR case 3: +#else + case 4: +#endif rb->set_bool("Show FPS", &sys->settings.showfps); break; +#ifndef SYS_MOTION_BLUR case 4: - rb->set_bool("Zoom on code", &sys->settings.zoom); +#else + case 5: +#endif + rb->set_bool("Zoom on Code", &sys->settings.zoom); /* zoom only works with scaling and rotation disabled */ - if(sys->settings.zoom && - ( sys->settings.scaling_quality | - sys->settings.rotation_option)) + if(sys->settings.zoom && (sys->settings.scaling_quality || sys->settings.rotation_option)) { rb->splash(HZ*2, "Scaling and rotation automatically disabled."); sys->settings.scaling_quality = 0; sys->settings.rotation_option = 0; } break; - case 5: - rb->lcd_clear_display(); + default: sys_save_settings(sys); return; } } } -#define MAX_SOUNDBUF_SIZE 512 -const struct opt_items sound_bufsize_options[] = { - {"8 samples" , 8}, - {"16 samples" , 16}, - {"32 samples" , 32}, - {"64 samples" , 64}, - {"128 samples", 128}, - {"256 samples", 256}, - {"512 samples", 512}, -}; +#define MAX_SOUNDBUF_SIZE 256 static void do_sound_settings(struct System* sys) { MENUITEM_STRINGLIST(menu, "Sound Settings", NULL, "Enabled", "Buffer Level", + "Volume", "Back", ); int sel = 0; @@ -246,10 +278,17 @@ static void do_sound_settings(struct System* sys) rb->set_bool("Enabled", &sys->settings.sound_enabled); break; case 1: - rb->set_option("Buffer Level", &sys->settings.sound_bufsize, INT, - sound_bufsize_options, ARRAYLEN(sound_bufsize_options), NULL); + rb->set_int("Buffer Level", "samples", UNIT_INT, &sys->settings.sound_bufsize, NULL, 16, 16, MAX_SOUNDBUF_SIZE, NULL); break; case 2: + { + const struct settings_list* vol = + rb->find_setting(&rb->global_settings->volume, NULL); + rb->option_screen((struct settings_list*)vol, NULL, false, "Volume"); + break; + } + case 3: + default: sys_save_settings(sys); return; } @@ -259,12 +298,13 @@ static void do_sound_settings(struct System* sys) static void sys_reset_settings(struct System* sys) { sys->settings.negative_enabled = false; - sys->settings.rotation_option = 0; - sys->settings.scaling_quality = 1; + sys->settings.rotation_option = 0; // off + sys->settings.scaling_quality = 1; // fast sys->settings.sound_enabled = true; - sys->settings.sound_bufsize = 64; - sys->settings.showfps = true; + sys->settings.sound_bufsize = 32; /* keep this low */ + sys->settings.showfps = false; sys->settings.zoom = false; + sys->settings.blur = false; sys_rotate_keymap(sys); } @@ -278,18 +318,32 @@ static int mainmenu_cb(int action, const struct menu_item_ex *this_item) return action; } -static AudioCallback audio_callback; +static AudioCallback audio_callback = NULL; +static void get_more(const void** start, size_t* size); static void* audio_param; static struct System* audio_sys; /************************************** MAIN MENU ***************************************/ +/* called after game init */ void sys_menu(struct System* sys) { sys_stopAudio(sys); + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + /* boost for load */ + rb->cpu_boost(true); +#endif + rb->splash(0, "Loading..."); sys->loaded = engine_loadGameState(sys->e, 0); + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(false); +#endif + rb->lcd_update(); + mainmenu_sysptr = sys; MENUITEM_STRINGLIST(menu, "XWorld Menu", mainmenu_cb, "Resume Game", /* 0 */ @@ -352,19 +406,21 @@ void sys_menu(struct System* sys) exit(PLUGIN_OK); break; default: - error("sys_menu: fall-through!"); + break; } } - rb->lcd_clear_display(); + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + /* boost for game */ + rb->cpu_boost(true); +#endif + sys_startAudio(sys, audio_callback, audio_param); } void sys_init(struct System* sys, const char* title) { (void) title; -#ifdef HAVE_ADJUSTABLE_CPU_FREQ - rb->cpu_boost(true); -#endif backlight_ignore_timeout(); rb_atexit(exit_handler); save_sys = sys; @@ -565,9 +621,9 @@ void sys_copyRect(struct System* sys, uint16_t x, uint16_t y, uint16_t w, uint16 int r, g, b; fb_data pix = rb->lcd_framebuffer[y * LCD_WIDTH + x]; #if (LCD_DEPTH == 24) - r = pix.r; - g = pix.g; - b = pix.b; + r = 0xff - pix.r; + g = 0xff - pix.g; + b = 0xff - pix.b; rb->lcd_framebuffer[y * LCD_WIDTH + x] = (fb_data) { b, g, r }; #else r = RGB_UNPACK_RED (pix); @@ -582,6 +638,57 @@ void sys_copyRect(struct System* sys, uint16_t x, uint16_t y, uint16_t w, uint16 } } +#ifdef SYS_MOTION_BLUR + if(sys->settings.blur) + { + static fb_data *prev_frames = NULL; + static fb_data *orig_fb = NULL; + static int prev_baseidx = 0; /* circular buffer */ + if(!prev_frames) + { + prev_frames = sys_get_buffer(sys, sizeof(fb_data) * LCD_WIDTH * LCD_HEIGHT * BLUR_FRAMES); + orig_fb = sys_get_buffer(sys, sizeof(fb_data) * LCD_WIDTH * LCD_HEIGHT); + + rb->memset(prev_frames, 0, sizeof(fb_data) * LCD_WIDTH * LCD_HEIGHT * BLUR_FRAMES); + } + if(prev_frames && orig_fb) + { + + rb->memcpy(orig_fb, rb->lcd_framebuffer, sizeof(fb_data) * LCD_WIDTH * LCD_HEIGHT); + /* fancy useless slow motion blur */ + for(int y = 0; y < LCD_HEIGHT; ++y) + { + for(int x = 0; x < LCD_WIDTH; ++x) + { + int r, g, b; + fb_data pix = rb->lcd_framebuffer[y * LCD_WIDTH + x]; + r = RGB_UNPACK_RED (pix); + g = RGB_UNPACK_GREEN(pix); + b = RGB_UNPACK_BLUE (pix); + r *= BLUR_FRAMES + 1; + g *= BLUR_FRAMES + 1; + b *= BLUR_FRAMES + 1; + for(int i = 0; i < BLUR_FRAMES; ++i) + { + fb_data prev_pix = prev_frames[ (prev_baseidx + i * (LCD_WIDTH * LCD_HEIGHT)) % (LCD_WIDTH * LCD_HEIGHT * BLUR_FRAMES) + y * LCD_WIDTH + x]; + r += (BLUR_FRAMES-i) * RGB_UNPACK_RED(prev_pix); + g += (BLUR_FRAMES-i) * RGB_UNPACK_GREEN(prev_pix); + b += (BLUR_FRAMES-i) * RGB_UNPACK_BLUE(prev_pix); + } + r /= (BLUR_FRAMES + 1) / 2 * (1 + BLUR_FRAMES + 1); + g /= (BLUR_FRAMES + 1) / 2 * (1 + BLUR_FRAMES + 1); + b /= (BLUR_FRAMES + 1) / 2 * (1 + BLUR_FRAMES + 1); + rb->lcd_framebuffer[y * LCD_WIDTH + x] = LCD_RGBPACK(r, g, b); + } + } + prev_baseidx -= LCD_WIDTH * LCD_HEIGHT; + if(prev_baseidx < 0) + prev_baseidx += BLUR_FRAMES * LCD_WIDTH * LCD_HEIGHT; + rb->memcpy(prev_frames + prev_baseidx, orig_fb, sizeof(fb_data) * LCD_WIDTH * LCD_HEIGHT); + } + } +#endif + /*********************** SHOW FPS *************************/ int current_time = sys_getTimeStamp(sys); @@ -599,6 +706,11 @@ void sys_copyRect(struct System* sys, uint16_t x, uint16_t y, uint16_t w, uint16 static void do_pause_menu(struct System* sys) { sys_stopAudio(sys); + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(false); +#endif + int sel = 0; MENUITEM_STRINGLIST(menu, "XWorld Menu", NULL, "Resume Game", /* 0 */ @@ -663,52 +775,130 @@ static void do_pause_menu(struct System* sys) break; } } - rb->lcd_clear_display(); + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); +#endif + sys_startAudio(sys, audio_callback, audio_param); } void sys_processEvents(struct System* sys) { - int btn = rb->button_get(false); - btn &= ~BUTTON_REDRAW; + int btn = rb->button_status(); + rb->button_clear_queue(); + + static int oldbuttonstate = 0; + debug(DBG_SYS, "button is 0x%08x", btn); /* exit early if we can */ - if(btn == BUTTON_NONE) + if(btn == oldbuttonstate) { return; } + /* handle special keys first */ + switch(btn) + { + case BTN_PAUSE: + do_pause_menu(sys); + sys->input.dirMask = 0; + sys->input.button = false; + /* exit early to avoid unwanted button presses being detected */ + return; + default: + exit_on_usb(btn); + break; + } + /* Ignore some buttons that cause errant input */ + + btn &= ~BUTTON_REDRAW; + #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) if(btn & 0x80000000) return; #endif + #if (CONFIG_KEYPAD == SANSA_E200_PAD) if(btn == (BUTTON_SCROLL_FWD || BUTTON_SCROLL_BACK)) return; #endif + #if (CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD) if(btn == (BUTTON_SELECT)) return; #endif - /* handle special keys first */ - switch(btn) + /* copied from doom which was copied from rockboy... */ + unsigned released = ~btn & oldbuttonstate; + unsigned pressed = btn & ~oldbuttonstate; + oldbuttonstate = btn; + + if(released) { - case BTN_PAUSE: - do_pause_menu(sys); - sys->input.dirMask = 0; - sys->input.button = false; - /* exit early to avoid unwanted button presses being detected */ - return; - default: - exit_on_usb(btn); - break; + if(released & BTN_FIRE) + sys->input.button = false; + if(released & sys->keymap.up) + sys->input.dirMask &= ~DIR_UP; + if(released & sys->keymap.down) + sys->input.dirMask &= ~DIR_DOWN; + if(released & sys->keymap.left) + sys->input.dirMask &= ~DIR_LEFT; + if(released & sys->keymap.right) + sys->input.dirMask &= ~DIR_RIGHT; +#ifdef BTN_DOWN_LEFT + if(released & sys->keymap.downleft) + sys->input.dirMask &= ~(DIR_DOWN | DIR_LEFT); +#endif +#ifdef BTN_DOWN_RIGHT + if(released & sys->keymap.downright) + sys->input.dirMask &= ~(DIR_DOWN | DIR_RIGHT); +#endif +#ifdef BTN_UP_LEFT + if(released & sys->keymap.upleft) + sys->input.dirMask &= ~(DIR_UP | DIR_LEFT); +#endif +#ifdef BTN_UP_RIGHT + if(released & sys->keymap.upright) + sys->input.dirMask &= ~(DIR_UP | DIR_RIGHT); +#endif + } + + if(pressed) + { + if(pressed & BTN_FIRE) + sys->input.button = true; + if(pressed & sys->keymap.up) + sys->input.dirMask |= DIR_UP; + if(pressed & sys->keymap.down) + sys->input.dirMask |= DIR_DOWN; + if(pressed & sys->keymap.left) + sys->input.dirMask |= DIR_LEFT; + if(pressed & sys->keymap.right) + sys->input.dirMask |= DIR_RIGHT; +#ifdef BTN_DOWN_LEFT + if(pressed & sys->keymap.downleft) + sys->input.dirMask |= (DIR_DOWN | DIR_LEFT); +#endif +#ifdef BTN_DOWN_RIGHT + if(pressed & sys->keymap.downright) + sys->input.dirMask |= (DIR_DOWN | DIR_RIGHT); +#endif +#ifdef BTN_UP_LEFT + if(pressed & sys->keymap.upleft) + sys->input.dirMask |= (DIR_UP | DIR_LEFT); +#endif +#ifdef BTN_UP_RIGHT + if(pressed & sys->keymap.upright) + sys->input.dirMask |= (DIR_UP | DIR_RIGHT); +#endif } +#if 0 /* handle releases */ if(btn & BUTTON_REL) { @@ -774,6 +964,7 @@ void sys_processEvents(struct System* sys) } debug(DBG_SYS, "dirMask is 0x%02x", sys->input.dirMask); debug(DBG_SYS, "button is %s", sys->input.button == true ? "true" : "false"); +#endif } void sys_sleep(struct System* sys, uint32_t duration) @@ -789,26 +980,28 @@ uint32_t sys_getTimeStamp(struct System* sys) return (uint32_t) (*rb->current_tick * (1000/HZ)); } -static int16_t rb_soundbuf [MAX_SOUNDBUF_SIZE] IBSS_ATTR; -static int8_t temp_soundbuf[MAX_SOUNDBUF_SIZE] IBSS_ATTR; -static void ICODE_ATTR get_more(const void** start, size_t* size) +/* game provides us mono samples, we need stereo */ +static int16_t rb_soundbuf[MAX_SOUNDBUF_SIZE * 2]; +static int8_t temp_soundbuf[MAX_SOUNDBUF_SIZE]; + +static void get_more(const void** start, size_t* size) { - if(audio_sys->settings.sound_enabled) + if(audio_sys->settings.sound_enabled && audio_callback) { audio_callback(audio_param, temp_soundbuf, audio_sys->settings.sound_bufsize); - /* convert xworld format (signed 8-bit) to rockbox format (signed 16-bit) */ + + /* convert xworld format (signed 8-bit) to rockbox format (stereo signed 16-bit) */ for(int i = 0; i < audio_sys->settings.sound_bufsize; ++i) { - rb_soundbuf[i] = temp_soundbuf[i] * 0x100; + rb_soundbuf[2*i] = rb_soundbuf[2*i+1] = temp_soundbuf[i] * 256; } - *start = rb_soundbuf; - *size = audio_sys->settings.sound_bufsize; } else { - *start = NULL; - *size = 0; + rb->memset(rb_soundbuf, 0, audio_sys->settings.sound_bufsize * 2 * sizeof(int16_t)); } + *start = rb_soundbuf; + *size = audio_sys->settings.sound_bufsize * 2 * sizeof(int16_t); } void sys_startAudio(struct System* sys, AudioCallback callback, void *param) @@ -817,6 +1010,7 @@ void sys_startAudio(struct System* sys, AudioCallback callback, void *param) audio_callback = callback; audio_param = param; audio_sys = sys; + rb->pcm_play_data(get_more, NULL, NULL, 0); } @@ -872,13 +1066,18 @@ void *sys_createMutex(struct System* sys) { if(!sys) error("sys is NULL!"); + + debug(DBG_SYS, "allocating mutex"); + + /* this bitfield works as follows: bit set = free, unset = in use */ for(int i = 0; i < MAX_MUTEXES; ++i) { + /* check that the corresponding bit is 1 (free) */ if(sys->mutex_bitfield & (1 << i)) { - rb->mutex_init(&sys->mutex_memory[i]); - sys->mutex_bitfield |= (1 << i); - return &sys->mutex_memory[i]; + rb->mutex_init(sys->mutex_memory + i); + sys->mutex_bitfield &= ~(1 << i); + return sys->mutex_memory + i; } } warning("Out of mutexes!"); @@ -888,20 +1087,18 @@ void *sys_createMutex(struct System* sys) void sys_destroyMutex(struct System* sys, void *mutex) { int mutex_number = ((char*)mutex - (char*)sys->mutex_memory) / sizeof(struct mutex); /* pointer arithmetic! check for bugs! */ - sys->mutex_bitfield &= ~(1 << mutex_number); + sys->mutex_bitfield |= 1 << mutex_number; } void sys_lockMutex(struct System* sys, void *mutex) { (void) sys; - debug(DBG_SYS, "calling mutex_lock"); rb->mutex_lock((struct mutex*) mutex); } void sys_unlockMutex(struct System* sys, void *mutex) { (void) sys; - debug(DBG_SYS, "calling mutex_unlock"); rb->mutex_unlock((struct mutex*) mutex); } @@ -937,4 +1134,5 @@ void MutexStack(struct MutexStack_t* s, struct System *stub, void *mutex) void MutexStack_destroy(struct MutexStack_t* s) { sys_unlockMutex(s->sys, s->_mutex); + } -- cgit v1.2.3