Browse Source

Add integer scaling option

master
Nathaniel Walizer 10 months ago
parent
commit
72ba3180c8
9 changed files with 124 additions and 85 deletions
  1. +1
    -0
      src/input.h
  2. +11
    -6
      src/menu.c
  3. +1
    -1
      src/menu.h
  4. +11
    -14
      src/nese.c
  5. +9
    -4
      src/render.h
  6. +0
    -7
      src/sdl_input.c
  7. +83
    -50
      src/sdl_render.c
  8. +5
    -1
      src/state.c
  9. +3
    -2
      src/state.h

+ 1
- 0
src/input.h View File

@@ -18,6 +18,7 @@ typedef enum {
input_Result_Cancel,
input_Result_View,
input_Result_Refresh,
input_Result_Scale,
} nes_Input_Result;

#define nes_controller_num_buttons (8U)


+ 11
- 6
src/menu.c View File

@@ -268,19 +268,22 @@ char* run_main_menu(menu_state* state, nese_Components* comp,
}

int run_game_menu(menu_state* state, nese_Components* comp,
const cart_info* cart) {
static char* items[] = {
const nese_State* nese) {
char* items[] = {
"Resume",
"Save",
"Restore",
"Reset",
"Select ROM",
#ifndef STANDALONE
"Toggle Fullscreen",
(nese->flags & (1 << State_Bit_Fullscreen)) ?
"Windowed" : "Fullscreen",
#endif
(nese->flags & (1 << State_Bit_Integer_Scale)) ?
"Force Aspect" : "Integer Scaling",
"Exit",
};
static int choices[] = {
static const int choices[] = {
input_Result_OK,
input_Result_Save,
input_Result_Load,
@@ -289,9 +292,10 @@ int run_game_menu(menu_state* state, nese_Components* comp,
#ifndef STANDALONE
input_Result_View,
#endif
input_Result_Scale,
input_Result_Quit,
};
static const file_list options = {
const file_list options = {
.files = items,
.count = (sizeof(items) / sizeof(*items)),
};
@@ -299,7 +303,8 @@ int run_game_menu(menu_state* state, nese_Components* comp,
menu_state menu = {0};
if (NULL != state) menu = *state;

int status = run_menu(&menu, &options, 100, comp, cart);
int status = run_menu(&menu, &options, 100,
comp, &nese->cart);

if (input_Result_Menu == status) {
status = input_Result_Cancel;


+ 1
- 1
src/menu.h View File

@@ -35,7 +35,7 @@ char* run_main_menu(menu_state*, nese_Components*,

// Returns nes_Input_Result indicating the choice
int run_game_menu(menu_state*, nese_Components*,
const cart_info*);
const nese_State*);

int modal_popup(const char* message, nese_Components*,
const cart_info*);


+ 11
- 14
src/nese.c View File

@@ -169,18 +169,19 @@ static int do_game_menu(menu_state* menu,
menu_state rom_menu = {0};

while (1) {
status = run_game_menu(menu, comp, &state->cart);
status = run_game_menu(menu, comp, state);

if (input_Result_View == status) {
if ( input_Result_View == status ||
input_Result_Scale == status ) {
if (input_Result_View == status) {
#ifndef STANDALONE
state->flags ^= (1 << State_Bit_Fullscreen);

state->flags ^= (1 << State_Bit_Fullscreen);
#endif
// We call this both times since it does both
// the toggle and the recalculation.
nes_render_fullscreen(
comp->rend,
state->flags & (1 << State_Bit_Fullscreen)
);
} else {
state->flags ^= (1 << State_Bit_Integer_Scale);
}
nes_render_set_flags(comp->rend, state->flags);
continue;

} else if (input_Result_Menu == status) {
@@ -223,11 +224,7 @@ int main(int argc, char* argv[]) {
if (status == 0) {
status = nes_render_init(components.rend);
if (0 == status) {
nes_render_fullscreen(
components.rend,
(state.flags & (1 << State_Bit_Fullscreen))
);
nes_render_refresh(components.rend);
nes_render_set_flags( components.rend, state.flags);
}
}



+ 9
- 4
src/render.h View File

@@ -10,7 +10,7 @@ typedef struct nes_Renderer_t {
void (*done)(struct nes_Renderer_t*);
int (*render)(struct nes_Renderer_t*, nes_ppu*);

void (*fullscreen)(struct nes_Renderer_t*, int enable);
void (*set_flags)(struct nes_Renderer_t*, uint32_t flags);
void (*refresh)(struct nes_Renderer_t*);

void (*draw_last_frame)(struct nes_Renderer_t*, int dim);
@@ -19,6 +19,7 @@ typedef struct nes_Renderer_t {
void (*draw_done)(struct nes_Renderer_t*);

Overlay overlay;
uint32_t flags;
void* data;
} nes_Renderer;

@@ -34,9 +35,13 @@ static inline int nes_render(nes_Renderer* rend, nes_ppu* ppu) {
return rend->render(rend, ppu);
}

static inline void nes_render_fullscreen(nes_Renderer* rend,
int enable) {
rend->fullscreen(rend, enable);
static inline uint32_t nes_render_set_flags(nes_Renderer* rend,
uint32_t flags) {

uint32_t old_flags = rend->flags;
rend->set_flags(rend, flags);
rend->flags = flags;
return old_flags;
}

static inline void nes_render_refresh(nes_Renderer* rend) {


+ 0
- 7
src/sdl_input.c View File

@@ -152,14 +152,7 @@ static int sdl_input_update(nes_Input_Reader* reader,
} else if (SDL_WINDOWEVENT == event.type) {
if ( SDL_WINDOWEVENT_EXPOSED ==
event.window.event) {
// We need to do this to flush both buffers
// nes_draw_last_frame(comp->rend, 1);
// nes_draw_done(comp->rend);

// We call this both times since it does both
// the toggle and the recalculation.
nes_render_refresh(comp->rend);

status = input_Result_Refresh;
}



+ 83
- 50
src/sdl_render.c View File

@@ -37,7 +37,6 @@ static inline uint8_t* chr_mem(const nes_ppu* ppu,
return ppu->mapper->chr_addr(ppu->map_data, addr);
}


typedef struct {
SDL_Window* window;
SDL_Renderer* renderer;
@@ -47,17 +46,84 @@ typedef struct {
sdl_overlay_font font;

SDL_Texture* texture;
int win_w;
int win_h;
SDL_Rect view;
} sdl_render_data;

static sdl_render_data the_render_data = {0};


static void sdl_render_refresh(nes_Renderer* rend) {
sdl_render_data* data = (sdl_render_data*)rend->data;
int win_w = 0, win_h = 0;
SDL_GetWindowSize(data->window, &win_w, &win_h);

// Determine the viewport within the screen

int w = win_w;
int h = win_h;

if (!(rend->flags & (1 << State_Bit_Integer_Scale))) {
// Fullscreen
if ((w * nes_ppu_scan_h) > (h * nes_ppu_scan_w)) {
w = (h * nes_ppu_scan_w) / nes_ppu_scan_h;
} else {
h = (w * nes_ppu_scan_h) / nes_ppu_scan_w;
}

} else {
// Integer Scale
int scale_y = 1, scale_x = 1;
if ((w * nes_ppu_scan_h) > (h * nes_ppu_scan_w)) {
// Wide Window
// printf("Wide\n");
scale_y = h / nes_ppu_scan_h;
scale_x = ( (scale_y * nes_ppu_scan_w) +
(nes_ppu_render_w / 2) ) /
nes_ppu_render_w;
if ((scale_x * nes_ppu_render_w) > w) {
scale_x = w / nes_ppu_render_w;
}

} else {
// Tall Window
// printf("Tall\n");
scale_x = w / nes_ppu_render_w;
scale_y = ( (scale_x * nes_ppu_render_w) +
(nes_ppu_scan_w / 2) ) / nes_ppu_scan_w;
if ((scale_y * nes_ppu_render_h) > h) {
scale_y = h / nes_ppu_render_h;
}
}

h = scale_y * nes_ppu_render_h;
w = scale_x * nes_ppu_render_w;
/*
printf("Scale %d, %d : %d, %d -> %d, %d\n",
scale_x, scale_y, win_w, win_h, w, h);
*/
if (!(rend->flags & (1 << State_Bit_Fullscreen))) {
SDL_SetWindowSize(data->window, w, h);
int x = 0, y = 0;
SDL_GetWindowPosition(data->window, &x, &y);
SDL_SetWindowPosition(data->window,
x - ((w - win_w) / 2),
y - ((h - win_h) / 2));
}
}

data->view.x = (win_w - w) / 2;
data->view.y = (win_h - h) / 2;
data->view.w = w;
data->view.h = h;

SDL_RenderSetClipRect(data->renderer, &data->view);
}

static int sdl_render_init(nes_Renderer* rend) {
sdl_render_data* data = &the_render_data;

rend->data = &the_render_data;

int status = SDL_Init(SDL_INIT_VIDEO);

if (0 != status) {
@@ -70,21 +136,11 @@ static int sdl_render_init(nes_Renderer* rend) {

SDL_GetCurrentDisplayMode(0, &mode);

int yscale = (mode.h - 1) / nes_ppu_scan_h;
int xscale = mode.w / nes_ppu_scan_w;
int scale = (xscale < yscale ? xscale : yscale);

data->win_w = (nes_ppu_scan_w * scale);
data->win_h = (nes_ppu_scan_h * scale);

data->view.w = data->win_w;
data->view.h = data->win_h;

data->window = SDL_CreateWindow(
"NESe",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
data->win_w, data->win_h, 0
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
mode.w, mode.h, 0
);
if (NULL == data->window) {
fprintf(stderr, "SDL: Failed to create window\n");
@@ -106,6 +162,7 @@ static int sdl_render_init(nes_Renderer* rend) {
status = -1;

} else {
sdl_render_refresh(rend);
overlay_init(&rend->overlay);
sdl_overlay_font_init(data->renderer, &data->font);
}
@@ -171,8 +228,6 @@ static int sdl_render_init(nes_Renderer* rend) {
SDL_SetPaletteColors(data->foreground->format->palette,
nes_palette, 0U, 64U);
SDL_SetColorKey(data->foreground, SDL_TRUE, 0xFFU);

rend->data = &the_render_data;
}

return status;
@@ -190,38 +245,16 @@ static void sdl_render_done(nes_Renderer* rend) {
SDL_Quit();
}

static void sdl_render_fullscreen(nes_Renderer* rend, int on) {
sdl_render_data* data = (sdl_render_data*)rend->data;
SDL_SetWindowFullscreen(data->window,
on ? SDL_WINDOW_FULLSCREEN : 0);
}

static void sdl_render_refresh(nes_Renderer* rend) {
static void sdl_render_set_flags(nes_Renderer* rend,
uint32_t flags) {
sdl_render_data* data = (sdl_render_data*)rend->data;
SDL_GetWindowSize(data->window,
&data->win_w, &data->win_h);

// Determine the viewport within the screen

int w = data->win_w;
int h = data->win_h;

if ((w * nes_ppu_scan_h) > (h * nes_ppu_scan_w)) {
w = (h * nes_ppu_scan_w) / nes_ppu_scan_h;
} else {
h = (w * nes_ppu_scan_h) / nes_ppu_scan_w;
}

data->view.x = (data->win_w - w) / 2;
data->view.y = (data->win_h - h) / 2;
data->view.w = w;
data->view.h = h;

SDL_RenderSetClipRect(data->renderer, &data->view);

// We need to do this to flush both buffers
// nes_draw_last_frame(rend, 1);
// nes_draw_done(rend);
SDL_SetWindowFullscreen(
data->window,
(flags & (1 << State_Bit_Fullscreen)) ?
SDL_WINDOW_FULLSCREEN : 0
);
rend->flags = flags;
sdl_render_refresh(rend);
}

static inline void render_sprite_line(
@@ -661,7 +694,7 @@ nes_Renderer sdl_renderer = {
.init = sdl_render_init,
.done = sdl_render_done,
.render = sdl_render,
.fullscreen = sdl_render_fullscreen,
.set_flags = sdl_render_set_flags,
.refresh = sdl_render_refresh,
.draw_last_frame = sdl_redraw_frame,
.draw_text = sdl_draw_text,


+ 5
- 1
src/state.c View File

@@ -43,12 +43,16 @@ static const ini_datum prefs_schema = {
.type = ini_section,
.name = ".flags",
.offset = offsetof(nese_State, flags),
.count = 1,
.count = 2,
.data = (ini_datum[]){
{
.type = ini_flag,
.name = "fullscreen",
.shift = State_Bit_Fullscreen,
}, {
.type = ini_flag,
.name = "integer_scale",
.shift = State_Bit_Integer_Scale,
},
}
},


+ 3
- 2
src/state.h View File

@@ -34,11 +34,12 @@ void cart_info_done(cart_info*);

typedef enum {
State_Bit_Fullscreen = 0,
} nese_State_Flags;
State_Bit_Integer_Scale = 1,
} nese_State_Flag_Bits;

typedef struct {
cart_info cart;
nese_State_Flags flags;
uint32_t flags; // nese_State_Flag_Bits
} nese_State;




Loading…
Cancel
Save