| @@ -54,7 +54,7 @@ SRC_SRCS_1 += overlay.c menu.c | |||
| SRC_SRCS_1 += state.c ini.c | |||
| SRC_SRCS_1 += compat.c | |||
| SRC_SRCS_1 += sdl_render.c sdl_input.c sdl_audio.c sdl_timer.c | |||
| SRC_SRCS_1 += sdl_overlay.c | |||
| SRC_SRCS_1 += sdl_overlay.c sdl_effect.c | |||
| PLAT_SRCS_1 = filemap.c | |||
| @@ -19,6 +19,7 @@ typedef enum { | |||
| input_Result_View, | |||
| input_Result_Refresh, | |||
| input_Result_Scale, | |||
| input_Result_Effect, | |||
| } nes_Input_Result; | |||
| #define nes_controller_num_buttons (8U) | |||
| @@ -281,6 +281,8 @@ int run_game_menu(menu_state* state, nese_Components* comp, | |||
| #endif | |||
| (nese->flags & (1 << State_Bit_Integer_Scale)) ? | |||
| "Force Aspect" : "Integer Scaling", | |||
| (nese->flags & (1 << State_Bit_CRT_Effect)) ? | |||
| "No Effect" : "CRT Effect", | |||
| "Exit", | |||
| }; | |||
| static const int choices[] = { | |||
| @@ -293,6 +295,7 @@ int run_game_menu(menu_state* state, nese_Components* comp, | |||
| input_Result_View, | |||
| #endif | |||
| input_Result_Scale, | |||
| input_Result_Effect, | |||
| input_Result_Quit, | |||
| }; | |||
| const file_list options = { | |||
| @@ -179,14 +179,17 @@ static int do_game_menu(menu_state* menu, | |||
| status = run_game_menu(menu, comp, state); | |||
| if ( input_Result_View == status || | |||
| input_Result_Scale == status ) { | |||
| input_Result_Scale == status || | |||
| input_Result_Effect == status ) { | |||
| if (input_Result_View == status) { | |||
| #ifndef STANDALONE | |||
| state->flags ^= (1 << State_Bit_Fullscreen); | |||
| #endif | |||
| } else { | |||
| } else if (input_Result_Scale == status) { | |||
| state->flags ^= (1 << State_Bit_Integer_Scale); | |||
| } else { | |||
| state->flags ^= (1 << State_Bit_CRT_Effect); | |||
| } | |||
| nes_render_set_flags(comp->rend, state->flags); | |||
| continue; | |||
| @@ -0,0 +1,71 @@ | |||
| #include "sdl_effect.h" | |||
| /* | |||
| static const uint8_t the_effect[3][3][4] = { | |||
| {{14, 0, 216, 204}, {16, 0, 0, 217}, {21, 225, 1, 0},}, | |||
| {{81, 0, 1, 1}, {83, 1, 0, 3}, {72, 2, 0, 0},}, | |||
| {{ 5, 0, 252, 245}, { 6, 0, 0, 243}, {10, 236, 1, 0},}, | |||
| }; | |||
| static const int effect_w = 3; | |||
| static const int effect_h = 3; | |||
| */ | |||
| static const uint8_t the_effect[2][2][4] = { | |||
| {{ 25, 0, 0, 0}, { 1, 0, 0, 0},}, | |||
| {{144, 0, 0, 0}, {133, 0, 0, 0},}, | |||
| }; | |||
| static const int effect_w = 2; | |||
| static const int effect_h = 2; | |||
| sdl_effect* effect_init(SDL_Renderer* renderer, | |||
| int view_w, int view_h) { | |||
| const int tex_w = view_w * 2; | |||
| const int tex_h = view_h * 2; | |||
| SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); | |||
| SDL_Texture* effect = SDL_CreateTexture( | |||
| renderer, SDL_PIXELFORMAT_BGRA8888, | |||
| SDL_TEXTUREACCESS_STREAMING, tex_w, tex_h | |||
| ); | |||
| void* pixels = NULL; | |||
| int pitch = 0; | |||
| SDL_LockTexture(effect, NULL, &pixels, &pitch); | |||
| uint8_t* dst_line = (uint8_t*)pixels; | |||
| for (int y = 0; y < tex_h; ++y) { | |||
| uint8_t* dst = dst_line; | |||
| for (int x = 0; x < tex_w; ++x) { | |||
| dst[0] = the_effect[y % effect_h][x % effect_w][0]; | |||
| dst[1] = the_effect[y % effect_h][x % effect_w][1]; | |||
| dst[2] = the_effect[y % effect_h][x % effect_w][2]; | |||
| dst[3] = the_effect[y % effect_h][x % effect_w][3]; | |||
| dst += 4; | |||
| } | |||
| dst_line += pitch; | |||
| } | |||
| SDL_UnlockTexture(effect); | |||
| SDL_SetTextureBlendMode(effect, SDL_BLENDMODE_BLEND); | |||
| return (sdl_effect*)effect; | |||
| } | |||
| void effect_done(sdl_effect* effect) { | |||
| if (effect) { | |||
| SDL_DestroyTexture((SDL_Texture*)effect); | |||
| } | |||
| } | |||
| void effect_apply(sdl_effect* effect, SDL_Renderer* renderer, | |||
| const SDL_Rect* rect) { | |||
| if (effect) { | |||
| SDL_RenderCopy(renderer, (SDL_Texture*)effect, | |||
| NULL, rect); | |||
| } | |||
| } | |||
| @@ -0,0 +1,17 @@ | |||
| #ifndef NESE_SDL_EFFECT_H_ | |||
| #define NESE_SDL_EFFECT_H_ | |||
| #include <SDL.h> | |||
| typedef struct sdl_effect sdl_effect; | |||
| sdl_effect* effect_init(SDL_Renderer*, int, int); | |||
| void effect_done(sdl_effect*); | |||
| void effect_apply(sdl_effect*, SDL_Renderer*, const SDL_Rect*); | |||
| #endif // NESE_SDL_EFFECT_H_ | |||
| @@ -7,6 +7,7 @@ | |||
| #include "mapper.h" | |||
| #include "menu.h" | |||
| #include "sdl_overlay.h" | |||
| #include "sdl_effect.h" | |||
| static SDL_Color nes_palette[64] = { | |||
| @@ -47,6 +48,8 @@ typedef struct { | |||
| SDL_Texture* texture; | |||
| SDL_Rect view; | |||
| struct sdl_effect* effect; | |||
| } sdl_render_data; | |||
| static sdl_render_data the_render_data = {0}; | |||
| @@ -221,6 +224,11 @@ static int sdl_render_init(nes_Renderer* rend) { | |||
| } | |||
| if (0 == status) { | |||
| data->effect = effect_init( | |||
| data->renderer, | |||
| nes_ppu_render_w, nes_ppu_render_h | |||
| ); | |||
| SDL_SetPaletteColors(data->background->format->palette, | |||
| nes_palette, 0U, 64U); | |||
| SDL_SetColorKey(data->background, SDL_TRUE, 0xFFU); | |||
| @@ -235,6 +243,7 @@ static int sdl_render_init(nes_Renderer* rend) { | |||
| static void sdl_render_done(nes_Renderer* rend) { | |||
| sdl_render_data* data = (sdl_render_data*)rend->data; | |||
| if (data->effect) effect_done(data->effect); | |||
| overlay_done(&rend->overlay); | |||
| sdl_overlay_font_done(&data->font); | |||
| SDL_DestroyTexture(data->texture); | |||
| @@ -629,6 +638,11 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { | |||
| SDL_LockTextureToSurface(data->texture, NULL, | |||
| &data->target); | |||
| if (rend->flags & (1 << State_Bit_CRT_Effect)) { | |||
| effect_apply(data->effect, data->renderer, | |||
| &data->view); | |||
| } | |||
| sdl_overlay_frame( | |||
| &rend->overlay, &data->font, data->renderer, | |||
| data->view.x, data->view.y, | |||
| @@ -662,6 +676,10 @@ static void sdl_redraw_frame(nes_Renderer* rend, int dim) { | |||
| NULL, &data->view); | |||
| SDL_LockTextureToSurface(data->texture, NULL, &data->target); | |||
| if (rend->flags & (1 << State_Bit_CRT_Effect)) { | |||
| effect_apply(data->effect, data->renderer, &data->view); | |||
| } | |||
| if (dim) { | |||
| SDL_SetTextureBlendMode(data->texture, | |||
| SDL_BLENDMODE_NONE); | |||
| @@ -43,7 +43,7 @@ static const ini_datum prefs_schema = { | |||
| .type = ini_section, | |||
| .name = ".flags", | |||
| .offset = offsetof(nese_State, flags), | |||
| .count = 2, | |||
| .count = 3, | |||
| .data = (ini_datum[]){ | |||
| { | |||
| .type = ini_flag, | |||
| @@ -53,6 +53,10 @@ static const ini_datum prefs_schema = { | |||
| .type = ini_flag, | |||
| .name = "integer_scale", | |||
| .shift = State_Bit_Integer_Scale, | |||
| }, { | |||
| .type = ini_flag, | |||
| .name = "crt_effect", | |||
| .shift = State_Bit_CRT_Effect, | |||
| }, | |||
| } | |||
| }, | |||
| @@ -35,6 +35,7 @@ void cart_info_done(cart_info*); | |||
| typedef enum { | |||
| State_Bit_Fullscreen = 0, | |||
| State_Bit_Integer_Scale = 1, | |||
| State_Bit_CRT_Effect = 2, | |||
| } nese_State_Flag_Bits; | |||
| typedef struct { | |||