# HG changeset patch # User Michael Pavone # Date 1707106299 28800 # Node ID da3dc881d3f0d0d52a094a56a5f9308168b48de6 # Parent 65c2e4d990cc4831bf6ce1b7c79c747c923166d8 Initial implementation of storbook artwork display diff -r 65c2e4d990cc -r da3dc881d3f0 genesis.c --- a/genesis.c Sat Feb 03 18:32:41 2024 -0800 +++ b/genesis.c Sun Feb 04 20:11:39 2024 -0800 @@ -1393,10 +1393,10 @@ case 6: return gen->pico_page; case 8: - printf("uPD7759 data read @ %u\n", m68k->current_cycle); + //printf("uPD7759 data read @ %u\n", m68k->current_cycle); return 0xFF; case 9: - printf("uPD7759 contro/status read @ %u\n", m68k->current_cycle); + //printf("uPD7759 contro/status read @ %u\n", m68k->current_cycle); return 0; default: printf("Unknown Pico IO read %X @ %u\n", location, m68k->current_cycle); @@ -1993,6 +1993,41 @@ } } +static void pico_update_page(genesis_context *gen) +{ +#ifndef IS_LIB + uint8_t page_num = 0; + uint8_t page = gen->pico_page; + while (page) + { + page_num++; + page >>= 1; + } + render_clear_window(gen->pico_story_window, 236, 205, 27); + int x, width; + if (page_num) { + x = 0; + width = 640; + } else { + render_fill_rect(gen->pico_story_window, 50, 29, 96, 0, 0, 320, 320); + x = 320; + width = 320; + } + if (gen->pico_story_pages[page_num] == 0xFF && page_num == 6 && gen->pico_story_pages[page_num - 1]) { + //repeat last page if storybook doesn't have a full 6 pages + //hack to deal with storybooks that skip page 5 + page_num--; + } + if (gen->pico_story_pages[page_num] != 0xFF) { + render_draw_image(gen->pico_story_window, gen->pico_story_pages[page_num], x, 0, width, 320); + } else { + uint8_t grey = page * (255 / 5); + render_fill_rect(gen->pico_story_window, grey, grey, grey, x, 0, width, 320); + } + render_window_refresh(gen->pico_story_window); +#endif +} + static void gamepad_down_pico(system_header *system, uint8_t gamepad_num, uint8_t button) { genesis_context *gen = (genesis_context *)system; @@ -2004,8 +2039,10 @@ gen->pico_page <<= 1; gen->pico_page |= 1; gen->pico_page &= 0x3F; + pico_update_page(gen); } else if (button == BUTTON_Z) { gen->pico_page >>= 1; + pico_update_page(gen); } else if (button < BUTTON_B) { gen->pico_button_state &= ~(1 << (button - 1)); } @@ -2066,10 +2103,17 @@ static void mouse_motion_absolute_pico(system_header *system, uint8_t mouse_num, uint16_t x, uint16_t y) { genesis_context *gen = (genesis_context *)system; - //TODO: scale properly + //FIXME: coordinate translation feels a little off for storybook area //TODO: limit to mouse motion on emulated storyware/drawing area - gen->pico_pen_x = (x >> 1) + 0x3C; - gen->pico_pen_y = y + 0x1FC; + if (y < 24) { + y = 24; + } + gen->pico_pen_x = x * (0x17D - 0x3C) / 640 + 0x3C; + if (y < 320) { + gen->pico_pen_y = (y-24) * (0x3F4-0x2F8) / (320-24) + 0x2F8; + } else { + gen->pico_pen_y = (y - 320) * (0x2f8-0x1FC) / 320 + 0x1FC; + } } static void mouse_motion_relative_pico(system_header *system, uint8_t mouse_num, int32_t x, int32_t y) @@ -2959,5 +3003,48 @@ set_audio_config(gen); bindings_set_mouse_mode(MOUSE_ABSOLUTE); + memset(gen->pico_story_pages, 0xFF, sizeof(gen->pico_story_pages)); +#ifndef IS_LIB + gen->pico_story_window = render_create_window("Pico Storybook & Pad", 640, 640, NULL); + const char *parts[] = {current_media()->dir, PATH_SEP, current_media()->name, ".manifest"}; + char *manifest_path = alloc_concat_m(sizeof(parts)/sizeof(*parts), parts); + tern_node *manifest = parse_config_file(manifest_path); + if (!manifest) { + printf("Manifest not found at %s\n", manifest_path); + } + if (manifest) { + tern_node *pages = tern_find_node(manifest, "pages"); + if (pages) { + char numkey[13]; + for (int i = 0; i < 7; i++) { + sprintf(numkey, "%d", i); + char *page_path = tern_find_ptr(pages, numkey); + if (page_path) { + printf("page %d: %s\n", i, page_path); + } else { + continue; + } + char *img_path; + if (is_absolute_path(current_media()->dir)) { + const char *img_parts[] = {current_media()->dir, PATH_SEP, page_path}; + img_path = alloc_concat_m(sizeof(img_parts)/sizeof(*img_parts), img_parts); + } else { + const char *img_parts[] = {path_current_dir(), PATH_SEP, current_media()->dir, PATH_SEP, page_path}; + img_path = alloc_concat_m(sizeof(img_parts)/sizeof(*img_parts), img_parts); + } + gen->pico_story_pages[i] = render_static_image(gen->pico_story_window, img_path); + if (gen->pico_story_pages[i] == 0xFF) { + printf("Failed to load page %d from %s\n", i, img_path); + } + free(img_path); + } + } else { + printf("No pages key in %s\n", manifest_path); + } + tern_free(manifest); + } + free(manifest_path); + pico_update_page(gen); +#endif return gen; } diff -r 65c2e4d990cc -r da3dc881d3f0 genesis.h --- a/genesis.h Sat Feb 03 18:32:41 2024 -0800 +++ b/genesis.h Sun Feb 04 20:11:39 2024 -0800 @@ -81,6 +81,8 @@ uint8_t tmss; uint8_t vdp_unlocked; uint8_t enter_z80_debugger; + uint8_t pico_story_window; + uint8_t pico_story_pages[7]; eeprom_state eeprom; nor_state nor; }; diff -r 65c2e4d990cc -r da3dc881d3f0 render.h --- a/render.h Sat Feb 03 18:32:41 2024 -0800 +++ b/render.h Sun Feb 04 20:11:39 2024 -0800 @@ -151,6 +151,11 @@ int render_ui_to_pixels_y(int ui); #ifndef IS_LIB uint8_t render_create_thread(render_thread *thread, const char *name, render_thread_fun fun, void *data); +uint8_t render_static_image(uint8_t window, char *path); +void render_draw_image(uint8_t window, uint8_t image, int x, int y, int width, int height); +void render_clear_window(uint8_t window, uint8_t r, uint8_t g, uint8_t b); +void render_fill_rect(uint8_t window, uint8_t r, uint8_t g, uint8_t b, int x, int y, int width, int height); +void render_window_refresh(uint8_t window); #endif #endif //RENDER_H_ diff -r 65c2e4d990cc -r da3dc881d3f0 render_sdl.c --- a/render_sdl.c Sat Feb 03 18:32:41 2024 -0800 +++ b/render_sdl.c Sun Feb 04 20:11:39 2024 -0800 @@ -1528,6 +1528,93 @@ extra_windows[win_idx] = NULL; } +SDL_Texture **static_images; +uint8_t num_static; +uint8_t render_static_image(uint8_t window, char *path) +{ + uint32_t fsize; + uint8_t *buffer; + if (is_absolute_path(path)) { + FILE *f = fopen(path, "rb"); + if (!f) { + return 0xFF; + } + fsize = file_size(f); + buffer = calloc(1, fsize); + if (fread(buffer, 1, fsize, f) != fsize) { + free(buffer); + fclose(f); + return 0xFF; + } + fclose(f); + } else { + buffer = (uint8_t *)read_bundled_file(path, &fsize); + } + if (!buffer) { + return 0xFF; + } + + uint32_t width, height; + uint32_t *pixels = load_png(buffer, fsize, &width, &height); + free(buffer); + if (!pixels) { + return 0xFF; + } + uint8_t img_index = 0; + if (!num_static) { + num_static = 8; + static_images = calloc(num_static, sizeof(SDL_Texture*)); + } + for (; img_index < num_static; img_index++) + { + if (!static_images[img_index]) { + break; + } + } + if (img_index == num_static) { + num_static *= 2; + static_images = realloc(static_images, num_static * sizeof(SDL_Texture*)); + } + static_images[img_index] = SDL_CreateTexture(extra_renderers[window - FRAMEBUFFER_USER_START], SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height); + SDL_UpdateTexture(static_images[img_index], NULL, pixels, sizeof(uint32_t) * width); + free(pixels); + return img_index; +} + +void render_draw_image(uint8_t window, uint8_t image, int x, int y, int width, int height) +{ + SDL_Rect dst = { + .x = x, + .y = y, + .w = width, + .h = height + }; + SDL_RenderCopy(extra_renderers[window - FRAMEBUFFER_USER_START], static_images[image], NULL, &dst); +} + +void render_clear_window(uint8_t window, uint8_t r, uint8_t g, uint8_t b) +{ + SDL_SetRenderDrawColor(extra_renderers[window - FRAMEBUFFER_USER_START], r, g, b, 255); + SDL_RenderClear(extra_renderers[window - FRAMEBUFFER_USER_START]); +} + +void render_fill_rect(uint8_t window, uint8_t r, uint8_t g, uint8_t b, int x, int y, int width, int height) +{ + SDL_SetRenderDrawColor(extra_renderers[window - FRAMEBUFFER_USER_START], r, g, b, 255); + SDL_Rect dst = { + .x = x, + .y = y, + .w = width, + .h = height + }; + SDL_RenderFillRect(extra_renderers[window - FRAMEBUFFER_USER_START], &dst); +} + +void render_window_refresh(uint8_t window) +{ + SDL_RenderPresent(extra_renderers[window - FRAMEBUFFER_USER_START]); +} + uint32_t *locked_pixels; uint32_t locked_pitch; uint32_t *render_get_framebuffer(uint8_t which, int *pitch)