| @@ -54,7 +54,7 @@ SRC_SRCS_1 += overlay.c menu.c | |||||
| SRC_SRCS_1 += state.c ini.c | SRC_SRCS_1 += state.c ini.c | ||||
| SRC_SRCS_1 += compat.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_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 | PLAT_SRCS_1 = filemap.c | ||||
| @@ -19,6 +19,7 @@ typedef enum { | |||||
| input_Result_View, | input_Result_View, | ||||
| input_Result_Refresh, | input_Result_Refresh, | ||||
| input_Result_Scale, | input_Result_Scale, | ||||
| input_Result_Effect, | |||||
| } nes_Input_Result; | } nes_Input_Result; | ||||
| #define nes_controller_num_buttons (8U) | #define nes_controller_num_buttons (8U) | ||||
| @@ -281,6 +281,8 @@ int run_game_menu(menu_state* state, nese_Components* comp, | |||||
| #endif | #endif | ||||
| (nese->flags & (1 << State_Bit_Integer_Scale)) ? | (nese->flags & (1 << State_Bit_Integer_Scale)) ? | ||||
| "Force Aspect" : "Integer Scaling", | "Force Aspect" : "Integer Scaling", | ||||
| (nese->flags & (1 << State_Bit_CRT_Effect)) ? | |||||
| "No Effect" : "CRT Effect", | |||||
| "Exit", | "Exit", | ||||
| }; | }; | ||||
| static const int choices[] = { | static const int choices[] = { | ||||
| @@ -293,6 +295,7 @@ int run_game_menu(menu_state* state, nese_Components* comp, | |||||
| input_Result_View, | input_Result_View, | ||||
| #endif | #endif | ||||
| input_Result_Scale, | input_Result_Scale, | ||||
| input_Result_Effect, | |||||
| input_Result_Quit, | input_Result_Quit, | ||||
| }; | }; | ||||
| const file_list options = { | const file_list options = { | ||||
| @@ -179,14 +179,17 @@ static int do_game_menu(menu_state* menu, | |||||
| status = run_game_menu(menu, comp, state); | status = run_game_menu(menu, comp, state); | ||||
| if ( input_Result_View == status || | if ( input_Result_View == status || | ||||
| input_Result_Scale == status ) { | |||||
| input_Result_Scale == status || | |||||
| input_Result_Effect == status ) { | |||||
| if (input_Result_View == status) { | if (input_Result_View == status) { | ||||
| #ifndef STANDALONE | #ifndef STANDALONE | ||||
| state->flags ^= (1 << State_Bit_Fullscreen); | state->flags ^= (1 << State_Bit_Fullscreen); | ||||
| #endif | #endif | ||||
| } else { | |||||
| } else if (input_Result_Scale == status) { | |||||
| state->flags ^= (1 << State_Bit_Integer_Scale); | state->flags ^= (1 << State_Bit_Integer_Scale); | ||||
| } else { | |||||
| state->flags ^= (1 << State_Bit_CRT_Effect); | |||||
| } | } | ||||
| nes_render_set_flags(comp->rend, state->flags); | nes_render_set_flags(comp->rend, state->flags); | ||||
| continue; | 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 "mapper.h" | ||||
| #include "menu.h" | #include "menu.h" | ||||
| #include "sdl_overlay.h" | #include "sdl_overlay.h" | ||||
| #include "sdl_effect.h" | |||||
| static SDL_Color nes_palette[64] = { | static SDL_Color nes_palette[64] = { | ||||
| @@ -47,6 +48,8 @@ typedef struct { | |||||
| SDL_Texture* texture; | SDL_Texture* texture; | ||||
| SDL_Rect view; | SDL_Rect view; | ||||
| struct sdl_effect* effect; | |||||
| } sdl_render_data; | } sdl_render_data; | ||||
| static sdl_render_data the_render_data = {0}; | static sdl_render_data the_render_data = {0}; | ||||
| @@ -221,6 +224,11 @@ static int sdl_render_init(nes_Renderer* rend) { | |||||
| } | } | ||||
| if (0 == status) { | if (0 == status) { | ||||
| data->effect = effect_init( | |||||
| data->renderer, | |||||
| nes_ppu_render_w, nes_ppu_render_h | |||||
| ); | |||||
| SDL_SetPaletteColors(data->background->format->palette, | SDL_SetPaletteColors(data->background->format->palette, | ||||
| nes_palette, 0U, 64U); | nes_palette, 0U, 64U); | ||||
| SDL_SetColorKey(data->background, SDL_TRUE, 0xFFU); | 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) { | static void sdl_render_done(nes_Renderer* rend) { | ||||
| sdl_render_data* data = (sdl_render_data*)rend->data; | sdl_render_data* data = (sdl_render_data*)rend->data; | ||||
| if (data->effect) effect_done(data->effect); | |||||
| overlay_done(&rend->overlay); | overlay_done(&rend->overlay); | ||||
| sdl_overlay_font_done(&data->font); | sdl_overlay_font_done(&data->font); | ||||
| SDL_DestroyTexture(data->texture); | SDL_DestroyTexture(data->texture); | ||||
| @@ -629,6 +638,11 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { | |||||
| SDL_LockTextureToSurface(data->texture, NULL, | SDL_LockTextureToSurface(data->texture, NULL, | ||||
| &data->target); | &data->target); | ||||
| if (rend->flags & (1 << State_Bit_CRT_Effect)) { | |||||
| effect_apply(data->effect, data->renderer, | |||||
| &data->view); | |||||
| } | |||||
| sdl_overlay_frame( | sdl_overlay_frame( | ||||
| &rend->overlay, &data->font, data->renderer, | &rend->overlay, &data->font, data->renderer, | ||||
| data->view.x, data->view.y, | data->view.x, data->view.y, | ||||
| @@ -662,6 +676,10 @@ static void sdl_redraw_frame(nes_Renderer* rend, int dim) { | |||||
| NULL, &data->view); | NULL, &data->view); | ||||
| SDL_LockTextureToSurface(data->texture, NULL, &data->target); | 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) { | if (dim) { | ||||
| SDL_SetTextureBlendMode(data->texture, | SDL_SetTextureBlendMode(data->texture, | ||||
| SDL_BLENDMODE_NONE); | SDL_BLENDMODE_NONE); | ||||
| @@ -43,7 +43,7 @@ static const ini_datum prefs_schema = { | |||||
| .type = ini_section, | .type = ini_section, | ||||
| .name = ".flags", | .name = ".flags", | ||||
| .offset = offsetof(nese_State, flags), | .offset = offsetof(nese_State, flags), | ||||
| .count = 2, | |||||
| .count = 3, | |||||
| .data = (ini_datum[]){ | .data = (ini_datum[]){ | ||||
| { | { | ||||
| .type = ini_flag, | .type = ini_flag, | ||||
| @@ -53,6 +53,10 @@ static const ini_datum prefs_schema = { | |||||
| .type = ini_flag, | .type = ini_flag, | ||||
| .name = "integer_scale", | .name = "integer_scale", | ||||
| .shift = State_Bit_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 { | typedef enum { | ||||
| State_Bit_Fullscreen = 0, | State_Bit_Fullscreen = 0, | ||||
| State_Bit_Integer_Scale = 1, | State_Bit_Integer_Scale = 1, | ||||
| State_Bit_CRT_Effect = 2, | |||||
| } nese_State_Flag_Bits; | } nese_State_Flag_Bits; | ||||
| typedef struct { | typedef struct { | ||||