#include #include #include #include #include #include #include #include #include #include #include #include #include #include SDL_Window *sdlWindow; SDL_Renderer *sdlRenderer; SDL_Texture *sdlTexture; SDL_Surface *screen; SDL_Window *sdlVramWindow; SDL_Renderer *sdlVramRenderer; SDL_Texture *sdlVramTexture; SDL_Surface *vramScreen; SDL_Window *sdlAudioWindow; SDL_Renderer *sdlAudioRenderer; SDL_Texture *sdlAudioTexture; SDL_Surface *audioScreen; TTF_Font *sans; static int scale = 4; static int screenWidth; static int screenHeight; void ui_init(){ screenWidth = XRES*scale; screenHeight = YRES*scale; SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER); printf("SDL INIT\n"); TTF_Init(); printf("TTF INIT\n"); //SDL_JoystickEventState(SDL_ENABLE); //SDL_JoystickOpen(0); SDL_GameControllerOpen(0); //char buffer[1024]; //strcpy(buffer, emu_get_context()->app_path); //*strrchr(buffer, '\\') = 0; //strcat(buffer,"/Sans.ttf"); sans = TTF_OpenFont("Sans.ttf", 24); if ( !sans ) { printf("Failed to load font: %s\n", TTF_GetError()); } SDL_CreateWindowAndRenderer(screenWidth, screenHeight, 0, &sdlWindow, &sdlRenderer); screen = SDL_CreateRGBSurface(0, screenWidth, screenHeight, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, screenWidth, screenHeight); SDL_CreateWindowAndRenderer(16 * 9 * scale, 24 * 9 * scale, SDL_WINDOW_HIDDEN, &sdlVramWindow, &sdlVramRenderer); vramScreen = SDL_CreateRGBSurface(0, (16 * 9 * scale), (24 * 9 * scale), 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); sdlVramTexture = SDL_CreateTexture(sdlVramRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, (16 * 9 * scale), (24 * 9 * scale)); SDL_CreateWindowAndRenderer(384, 730, SDL_WINDOW_HIDDEN, &sdlAudioWindow, &sdlAudioRenderer); audioScreen = SDL_CreateRGBSurface(0, 384, 730, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); sdlAudioTexture = SDL_CreateTexture(sdlAudioRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 384, 730); } static unsigned long tile_colors[4] = {0xFFFFFFFF, 0xFFAAAAAA, 0xFF555555, 0xFF000000}; void display_tile(SDL_Surface *surface, u16 startLocation, u16 tileNum, int x, int y) { SDL_Rect rc; for(int tileY = 0; tileY < 16; tileY += 2) { u8 b1 = bus_read(startLocation+(tileNum * 16) + tileY); u8 b2 = bus_read(startLocation+(tileNum * 16) + tileY + 1); for (int bit=7; bit >= 0; bit--) { u8 hi = !!(b1 & (1 << bit)) << 1; u8 lo = !!(b2 & (1 << bit)); u8 color = hi | lo; rc.x = x + ((7 - bit) * scale); rc.y = y + (tileY/2 * scale); rc.w = scale; rc.h = scale; SDL_FillRect(surface, &rc, tile_colors[color]); } } } void update_vram_window() { int xDraw = 0; int yDraw = 0; int tileNum = 0; SDL_Rect rc; rc.x = 0; rc.y = 0; rc.w = vramScreen->w; rc.h = vramScreen->h; SDL_FillRect(vramScreen, &rc, 0xFF111111); u16 addr = 0x8000; //384 tiles, 24 x 16 for(int y = 0; y < 24; y++) { for(int x = 0; x < 16; x++) { display_tile(vramScreen, addr, tileNum, xDraw + (x * scale), yDraw + (y * scale)); xDraw += (8 * scale); tileNum++; } yDraw += (8 * scale); xDraw = 0; } SDL_UpdateTexture(sdlVramTexture, NULL, vramScreen->pixels, vramScreen->pitch); SDL_RenderClear(sdlVramRenderer); SDL_RenderCopy(sdlVramRenderer, sdlVramTexture, NULL, NULL); SDL_RenderPresent(sdlVramRenderer); } void update_audio_window() { int xDraw = 0; int yDraw = 0; int tileNum = 0; SDL_Rect rc; rc.x = 0; rc.y = 0; rc.w = audioScreen->w; rc.h = audioScreen->h; SDL_FillRect(audioScreen, &rc, 0xFF111111); SDL_UpdateTexture(sdlAudioTexture, NULL, audioScreen->pixels, audioScreen->pitch); SDL_RenderClear(sdlAudioRenderer); SDL_RenderCopy(sdlAudioRenderer, sdlAudioTexture, NULL, NULL); SDL_Color text_color = {255,255,255}; int yOffset = 70; int lastY = (yOffset) - (audio_get_context()->sq1_history[audio_get_context()->sq1_index] * 50); int xOffset = 0; SDL_Surface* message = TTF_RenderText_Solid(sans, "Square 1", text_color); SDL_Texture* messageTexture = SDL_CreateTextureFromSurface(sdlAudioRenderer, message); SDL_Rect messageRect; messageRect.x = xOffset; messageRect.y = yOffset-70; messageRect.w = 50; messageRect.h = 20; SDL_RenderCopy(sdlAudioRenderer, messageTexture, NULL, &messageRect); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); SDL_FreeSurface(message); SDL_DestroyTexture(messageTexture); for(int x = 1; x < 384; x++){ int y = (yOffset) - (audio_get_context()->sq1_history[(x + audio_get_context()->sq1_index) % 384] * 50); SDL_RenderDrawLine(sdlAudioRenderer, x-1+xOffset, lastY, x+xOffset, y); lastY = y; if(x+xOffset == screenWidth) { break; } } yOffset = 190; lastY = (yOffset) - (audio_get_context()->sq2_history[audio_get_context()->sq2_index] * 50); message = TTF_RenderText_Solid(sans, "Square 2", text_color); messageTexture = SDL_CreateTextureFromSurface(sdlAudioRenderer, message); messageRect.x = xOffset; messageRect.y = yOffset-70; messageRect.w = 50; messageRect.h = 20; SDL_RenderCopy(sdlAudioRenderer, messageTexture, NULL, &messageRect); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); SDL_FreeSurface(message); SDL_DestroyTexture(messageTexture); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); for(int x = 1; x < 384; x++){ int y = (yOffset) - (audio_get_context()->sq2_history[(x + audio_get_context()->sq2_index) % 384] * 50); SDL_RenderDrawLine(sdlAudioRenderer, x-1+xOffset, lastY, x+xOffset, y); lastY = y; if(x+xOffset == screenWidth) { break; } } yOffset = 310; lastY = (yOffset) - (audio_get_context()->ch3_history[audio_get_context()->ch3_index] * 50); message = TTF_RenderText_Solid(sans, "Wave", text_color); messageTexture = SDL_CreateTextureFromSurface(sdlAudioRenderer, message); messageRect.x = xOffset; messageRect.y = yOffset-70; messageRect.w = 50; messageRect.h = 20; SDL_RenderCopy(sdlAudioRenderer, messageTexture, NULL, &messageRect); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); SDL_FreeSurface(message); SDL_DestroyTexture(messageTexture); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); for(int x = 1; x < 384; x++){ int y = (yOffset) - (audio_get_context()->ch3_history[(x + audio_get_context()->ch3_index) % 384] * 50); SDL_RenderDrawLine(sdlAudioRenderer, x-1+xOffset, lastY, x+xOffset, y); lastY = y; if(x+xOffset == screenWidth) { break; } } yOffset = 430; lastY = (yOffset) - (audio_get_context()->ch4_history[audio_get_context()->ch4_index] * 50); message = TTF_RenderText_Solid(sans, "Noise", text_color); messageTexture = SDL_CreateTextureFromSurface(sdlAudioRenderer, message); messageRect.x = xOffset; messageRect.y = yOffset-70; messageRect.w = 50; messageRect.h = 20; SDL_RenderCopy(sdlAudioRenderer, messageTexture, NULL, &messageRect); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); SDL_FreeSurface(message); SDL_DestroyTexture(messageTexture); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); for(int x = 1; x < 384; x++){ int y = (yOffset) - (audio_get_context()->ch4_history[(x + audio_get_context()->ch4_index) % 384] * 50); SDL_RenderDrawLine(sdlAudioRenderer, x-1+xOffset, lastY, x+xOffset, y); lastY = y; if(x+xOffset == screenWidth) { break; } } yOffset = 550; lastY = (yOffset) - (audio_get_context()->left_history[audio_get_context()->left_index] * 50); message = TTF_RenderText_Solid(sans, "Left Out", text_color); messageTexture = SDL_CreateTextureFromSurface(sdlAudioRenderer, message); messageRect.x = xOffset; messageRect.y = yOffset-70; messageRect.w = 50; messageRect.h = 20; SDL_RenderCopy(sdlAudioRenderer, messageTexture, NULL, &messageRect); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); SDL_FreeSurface(message); SDL_DestroyTexture(messageTexture); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 0, 255, 255); for(int x = 1; x < 384; x++){ int y = (yOffset) - (audio_get_context()->left_history[(x + audio_get_context()->left_index) % 384] * 50); SDL_RenderDrawLine(sdlAudioRenderer, x-1+xOffset, lastY, x+xOffset, y); lastY = y; if(x+xOffset == screenWidth) { break; } } yOffset = 680; lastY = (yOffset) - (audio_get_context()->right_history[audio_get_context()->right_index] * 50); message = TTF_RenderText_Solid(sans, "Right Out", text_color); messageTexture = SDL_CreateTextureFromSurface(sdlAudioRenderer, message); messageRect.x = xOffset; messageRect.y = yOffset-70; messageRect.w = 50; messageRect.h = 20; SDL_RenderCopy(sdlAudioRenderer, messageTexture, NULL, &messageRect); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); SDL_FreeSurface(message); SDL_DestroyTexture(messageTexture); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 255, 0, 255); SDL_SetRenderDrawColor(sdlAudioRenderer, 0, 0, 255, 255); for(int x = 1; x < 384; x++){ int y = (yOffset) - (audio_get_context()->right_history[(x + audio_get_context()->right_index) % 384] * 50); SDL_RenderDrawLine(sdlAudioRenderer, x-1+xOffset, lastY, x+xOffset, y); lastY = y; if(x+xOffset == screenWidth) { break; } } SDL_RenderPresent(sdlAudioRenderer); } void ui_update() { SDL_Rect rc; rc.x = rc.y = 0; rc.w = rc.h = 2048; u32 *video_buffer = ppu_get_context()->video_buffer; for(int line_num = 0; line_num < YRES; line_num++) { for(int x = 0; x < XRES; x++) { rc.x = x * scale; rc.y = line_num * scale; rc.w = scale; rc.h = scale; SDL_FillRect(screen, &rc, video_buffer[x + (line_num * XRES)]); } } SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); SDL_RenderClear(sdlRenderer); SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); SDL_RenderPresent(sdlRenderer); update_vram_window(); update_audio_window(); } void ui_on_key(bool down, u32 key_code) { if(key_code == SDLK_SPACE && down == true) { emu_get_context()->fast_forward = !emu_get_context()->fast_forward; if(emu_get_context()->fast_forward){ ppu_get_context()->target_frame_time = 1000/(60 * FAST_FORWARD_SPEED); } else { ppu_get_context()->target_frame_time = 1000/60; } printf("target frame time: %d\n", ppu_get_context()->target_frame_time); } if(ppu_get_context()->paused) { if(key_code == SDLK_PERIOD && down == true){ ppu_get_context()->frame = true; } } if(key_code == SDLK_p && down == true) { ppu_get_context()->paused = !ppu_get_context()->paused; if(ppu_get_context()->paused) { printf("Paused Emulation\n"); } else { printf("Resumed Emulation\n"); } } if(key_code == SDLK_d && down == true) { emu_get_context()->debug = true; debug_get_context()->state = DS_MAIN; emu_get_context()->paused = true; } if(key_code == SDLK_r && down == true) { emu_stop(); emu_reset(); emu_start(); } if(key_code == SDLK_s && down == true) { emu_stop(); state_save_file(0); emu_start(); } if(key_code == SDLK_l && down == true) { emu_stop(); emu_reset(); state_load_file(0); emu_start(); } if(key_code == SDLK_v && down == true) { if(SDL_GetWindowFlags(sdlVramWindow) & SDL_WINDOW_HIDDEN) { SDL_ShowWindow(sdlVramWindow); } else { SDL_HideWindow(sdlVramWindow); } } if(key_code == SDLK_a && down == true) { if(SDL_GetWindowFlags(sdlAudioWindow) & SDL_WINDOW_HIDDEN) { SDL_ShowWindow(sdlAudioWindow); } else { SDL_HideWindow(sdlAudioWindow); } } switch(key_code){ case SDLK_z: gamepad_get_state()->b = down; break; case SDLK_x: gamepad_get_state()->a = down; break; case SDLK_RETURN: gamepad_get_state()->start = down; break; case SDLK_TAB: gamepad_get_state()->select = down; break; case SDLK_UP: gamepad_get_state()->up = down; break; case SDLK_DOWN: gamepad_get_state()->down = down; break; case SDLK_LEFT: gamepad_get_state()->left = down; break; case SDLK_RIGHT: gamepad_get_state()->right = down; break; } gamepad_int_update(); } void ui_on_joy_button(u8 button, bool down) { switch(button){ case 0: gamepad_get_state()->b = down; break; case 1: gamepad_get_state()->a = down; break; case 7: gamepad_get_state()->start = down; break; case 6: gamepad_get_state()->select = down; break; } } void ui_on_controller_button(u8 button, bool down) { switch(button){ case SDL_CONTROLLER_BUTTON_A: gamepad_get_state()->b = down; break; case SDL_CONTROLLER_BUTTON_B: gamepad_get_state()->a = down; break; case SDL_CONTROLLER_BUTTON_START: gamepad_get_state()->start = down; break; case SDL_CONTROLLER_BUTTON_BACK: gamepad_get_state()->select = down; break; case SDL_CONTROLLER_BUTTON_DPAD_DOWN: gamepad_get_state()->down = down; break; case SDL_CONTROLLER_BUTTON_DPAD_UP: gamepad_get_state()->up = down; break; case SDL_CONTROLLER_BUTTON_DPAD_LEFT: gamepad_get_state()->left = down; break; case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: gamepad_get_state()->right = down; break; } } void ui_on_joy_hat(u8 hat, u8 value) { if(hat == 0){ gamepad_get_state()->up = value & SDL_HAT_UP; gamepad_get_state()->down = value & SDL_HAT_DOWN; gamepad_get_state()->left = value & SDL_HAT_LEFT; gamepad_get_state()->right = value & SDL_HAT_RIGHT; } } #define DEADZONE 10000 void ui_on_Joy_axis(u8 axis, int16_t value) { if(axis == 1) { gamepad_get_state()->up = false; gamepad_get_state()->down = false; if(value < -DEADZONE) { gamepad_get_state()->up = true; } if(value > DEADZONE) { gamepad_get_state()->down = true; } } if(axis == 0) { gamepad_get_state()->left = false; gamepad_get_state()->right = false; if(value < -DEADZONE) { gamepad_get_state()->left = true; } if(value > DEADZONE) { gamepad_get_state()->right = true; } } } void ui_on_controller_axis(u8 axis, int16_t value) { if(axis == SDL_CONTROLLER_AXIS_LEFTY) { gamepad_get_state()->up = false; gamepad_get_state()->down = false; if(value < -DEADZONE) { gamepad_get_state()->up = true; } if(value > DEADZONE) { gamepad_get_state()->down = true; } } if(axis == SDL_CONTROLLER_AXIS_LEFTX) { gamepad_get_state()->left = false; gamepad_get_state()->right = false; if(value < -DEADZONE) { gamepad_get_state()->left = true; } if(value > DEADZONE) { gamepad_get_state()->right = true; } } } void ui_handle_events(){ SDL_Event e; while(SDL_PollEvent(&e) > 0) { if(e.type == SDL_KEYDOWN) { ui_on_key(true, e.key.keysym.sym); } if(e.type == SDL_KEYUP) { ui_on_key(false, e.key.keysym.sym); } if(e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_CLOSE) { if(e.window.windowID == SDL_GetWindowID(sdlWindow)){ emu_get_context()->die = true; } else { SDL_Window *w = SDL_GetWindowFromID(e.window.windowID); SDL_HideWindow(w); } } if(e.type == SDL_JOYBUTTONDOWN) { //ui_on_joy_button(e.jbutton.button, true); } if(e.type == SDL_JOYBUTTONUP) { //ui_on_joy_button(e.jbutton.button, false); } if(e.type == SDL_JOYHATMOTION) { // ui_on_joy_hat(e.jhat.hat, e.jhat.value); } if(e.type == SDL_JOYAXISMOTION) { //ui_on_Joy_axis(e.jaxis.axis, e.jaxis.value); } if(e.type == SDL_CONTROLLERBUTTONDOWN) { ui_on_controller_button(e.cbutton.button, true); } if(e.type == SDL_CONTROLLERBUTTONUP) { ui_on_controller_button(e.cbutton.button, false); } if(e.type == SDL_CONTROLLERAXISMOTION) { ui_on_controller_axis(e.caxis.axis, e.caxis.value); } //if(e.type == sdl_controllerhat) } } void delay(u32 ms) { SDL_Delay(ms); } u32 get_ticks() { return SDL_GetTicks(); }