mirror of
https://github.com/gligli/nulldc-360.git
synced 2025-04-02 11:11:56 -04:00
615 lines
No EOL
15 KiB
C++
615 lines
No EOL
15 KiB
C++
#include <xetypes.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <input/input.h>
|
|
#include <console/console.h>
|
|
#include <png.h>
|
|
#include <_pnginfo.h>
|
|
#include <ppc/timebase.h>
|
|
#include <time/time.h>
|
|
#include <ppc/atomic.h>
|
|
|
|
#include <xenos/xe.h>
|
|
#include <xenos/xenos.h>
|
|
#include <xenos/edram.h>
|
|
#include <xenos/xenos.h>
|
|
|
|
#include <debug.h>
|
|
#define TR {printf("[Trace] in function %s, line %d, file %s\n",__FUNCTION__,__LINE__,__FILE__);}
|
|
|
|
#include "Vec.h"
|
|
#include "video.h"
|
|
#include "input.h"
|
|
#include "gui/gui.h"
|
|
|
|
#if 0
|
|
|
|
struct ati_info {
|
|
uint32_t unknown1[4];
|
|
uint32_t base;
|
|
uint32_t unknown2[8];
|
|
uint32_t width;
|
|
uint32_t height;
|
|
} __attribute__((__packed__));
|
|
|
|
#define MAX_SHADER 10
|
|
|
|
#define SNES_THUMBNAIL_W 64
|
|
#define SNES_THUMBNAIL_H 48
|
|
|
|
typedef unsigned int DWORD;
|
|
|
|
typedef void (*video_callback)(void*);
|
|
|
|
typedef struct {
|
|
char name[30];
|
|
struct XenosShader * ps;
|
|
struct XenosShader * vs;
|
|
video_callback callback;
|
|
} SnesShader;
|
|
|
|
typedef struct {
|
|
float x, y, z, w;
|
|
float u, v;
|
|
} SnesVerticeFormats;
|
|
|
|
typedef struct {
|
|
float w;
|
|
float h;
|
|
} float2;
|
|
|
|
typedef struct {
|
|
float2 video_size;
|
|
float2 texture_size;
|
|
float2 output_size;
|
|
} _shaderParameters;
|
|
|
|
#include "shaders/5xBR-v3.7a.ps.h"
|
|
#include "shaders/5xBR-v3.7a.vs.h"
|
|
|
|
#include "shaders/2xBR-v3.5a.ps.h"
|
|
#include "shaders/2xBR-v3.5a.vs.h"
|
|
|
|
#include "shaders/5xBR-v3.7b.ps.h"
|
|
#include "shaders/5xBR-v3.7b.vs.h"
|
|
|
|
#include "shaders/5xBR-v3.7c.ps.h"
|
|
#include "shaders/5xBR-v3.7c.vs.h"
|
|
|
|
//#include "shaders/5xBR-v3.7c_crt.ps.h"
|
|
//#include "shaders/5xBR-v3.7c_crt.vs.h"
|
|
|
|
#include "shaders/scanline.ps.h"
|
|
#include "shaders/scanline.vs.h"
|
|
|
|
#include "shaders/simple.ps.h"
|
|
#include "shaders/simple.vs.h"
|
|
|
|
static matrix4x4 modelViewProj;
|
|
static struct XenosVertexBuffer *snes_vb = NULL;
|
|
static struct XenosVertexBuffer *render_to_target_vb = NULL;
|
|
// bitmap emulation
|
|
static struct XenosSurface * g_SnesSurface = NULL;
|
|
// fb copy of snes display used by gui
|
|
static struct XenosSurface * g_SnesSurfaceShadow = NULL;
|
|
// used for double buffering
|
|
static struct XenosSurface * g_framebuffer[2] = {NULL};
|
|
|
|
#define r32(o) g_pVideoDevice->regs[(o)/4]
|
|
#define w32(o, v) g_pVideoDevice->regs[(o)/4] = (v)
|
|
|
|
// 64 * 48 -- tiled
|
|
u8 * gameScreenPng = NULL;
|
|
u8 * gameScreenThumbnail = NULL;
|
|
int gameScreenPngSize = 0;
|
|
static struct XenosSurface * g_SnesThumbnail = NULL;
|
|
|
|
static int selected_snes_shader = 0;
|
|
static int nb_snes_shaders = 0;
|
|
static SnesShader SnesShaders[MAX_SHADER];
|
|
|
|
static _shaderParameters shaderParameters;
|
|
|
|
static void default_callback(void*) {
|
|
Xe_SetVertexShaderConstantF(g_pVideoDevice, 0, (float*) &modelViewProj, 4);
|
|
Xe_SetVertexShaderConstantF(g_pVideoDevice, 4, (float*) &shaderParameters, 2);
|
|
Xe_SetPixelShaderConstantF(g_pVideoDevice, 0, (float*) &shaderParameters, 2);
|
|
}
|
|
|
|
static void no_filtering_callback(void*) {
|
|
// Disable filtering for xbr
|
|
g_SnesSurface->use_filtering = 0;
|
|
|
|
// Shader constant
|
|
Xe_SetVertexShaderConstantF(g_pVideoDevice, 0, (float*) &modelViewProj, 4);
|
|
Xe_SetVertexShaderConstantF(g_pVideoDevice, 4, (float*) &shaderParameters, 2);
|
|
Xe_SetPixelShaderConstantF(g_pVideoDevice, 0, (float*) &shaderParameters, 2);
|
|
}
|
|
|
|
static void loadShader(char * name, const XenosVBFFormat * vbf, const void * ps_main, const void * vs_main, video_callback callback) {
|
|
strcpy(SnesShaders[nb_snes_shaders].name, name);
|
|
|
|
SnesShaders[nb_snes_shaders].ps = Xe_LoadShaderFromMemory(g_pVideoDevice, (void*) ps_main);
|
|
Xe_InstantiateShader(g_pVideoDevice, SnesShaders[nb_snes_shaders].ps, 0);
|
|
|
|
SnesShaders[nb_snes_shaders].vs = Xe_LoadShaderFromMemory(g_pVideoDevice, (void*) vs_main);
|
|
Xe_InstantiateShader(g_pVideoDevice, SnesShaders[nb_snes_shaders].vs, 0);
|
|
Xe_ShaderApplyVFetchPatches(g_pVideoDevice, SnesShaders[nb_snes_shaders].vs, 0, vbf);
|
|
|
|
SnesShaders[nb_snes_shaders].callback = callback;
|
|
|
|
nb_snes_shaders++;
|
|
|
|
if (nb_snes_shaders >= MAX_SHADER) {
|
|
printf("Too much shader created !!!\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
void initSnesVideo() {
|
|
static const struct XenosVBFFormat vbf = {
|
|
2,
|
|
{
|
|
{XE_USAGE_POSITION, 0, XE_TYPE_FLOAT4},
|
|
{XE_USAGE_TEXCOORD, 0, XE_TYPE_FLOAT2},
|
|
}
|
|
};
|
|
|
|
XenosSurface * fb = Xe_GetFramebufferSurface(g_pVideoDevice);
|
|
|
|
|
|
loadShader("Normal", &vbf, PSSimple, VSSimple, default_callback);
|
|
//loadShader("Xbr 2x 3.5a", &vbf, PS2xBRa, VS2xBRa, no_filtering_callback); /// too slow ?
|
|
loadShader("Xbr 5x 3.7a", &vbf, PS5xBRa, VS5xBRa, no_filtering_callback);
|
|
loadShader("Xbr 5x 3.7b", &vbf, PS5xBRb, VS5xBRb, no_filtering_callback);
|
|
loadShader("Xbr 5x 3.7c", &vbf, PS5xBRc, VS5xBRc, no_filtering_callback);
|
|
|
|
//loadShader("Scanlines", &vbf, PSScanline, VSScanline, no_filtering_callback);
|
|
|
|
snes_vb = Xe_CreateVertexBuffer(g_pVideoDevice, 4096);
|
|
render_to_target_vb = Xe_CreateVertexBuffer(g_pVideoDevice, 4096);
|
|
|
|
// Create surfaces
|
|
g_SnesSurface = Xe_CreateTexture(g_pVideoDevice, MAX_SNES_WIDTH, MAX_SNES_HEIGHT, 1, XE_FMT_565 | XE_FMT_16BE, 0);
|
|
g_SnesThumbnail = Xe_CreateTexture(g_pVideoDevice, SNES_THUMBNAIL_W, SNES_THUMBNAIL_H, 0, XE_FMT_8888 | XE_FMT_BGRA, 1);
|
|
|
|
// Create surface for double buffering
|
|
g_framebuffer[0] = Xe_CreateTexture(g_pVideoDevice, fb->width, fb->height, 0, XE_FMT_8888 | XE_FMT_BGRA, 1);
|
|
g_framebuffer[1] = Xe_CreateTexture(g_pVideoDevice, fb->width, fb->height, 0, XE_FMT_8888 | XE_FMT_BGRA, 1);
|
|
|
|
|
|
g_SnesSurfaceShadow = g_framebuffer[0];
|
|
|
|
g_SnesSurface->u_addressing = XE_TEXADDR_WRAP;
|
|
g_SnesSurface->v_addressing = XE_TEXADDR_WRAP;
|
|
|
|
GFX.Screen = (uint16*) g_SnesSurface->base;
|
|
GFX.Pitch = g_SnesSurface->wpitch;
|
|
|
|
memset(g_SnesSurface->base, 0, g_SnesSurface->wpitch * g_SnesSurface->hpitch);
|
|
memset(g_SnesSurfaceShadow->base, 0, g_SnesSurfaceShadow->wpitch * g_SnesSurfaceShadow->hpitch);
|
|
|
|
// init fake matrices
|
|
matrixLoadIdentity(&modelViewProj);
|
|
|
|
// thumbnail png
|
|
gameScreenPng = (u8*) malloc(SNES_THUMBNAIL_W * SNES_THUMBNAIL_H * sizeof (uint32));
|
|
gameScreenThumbnail = (u8*) malloc(SNES_THUMBNAIL_W * SNES_THUMBNAIL_H * sizeof (uint32));
|
|
}
|
|
|
|
static int detect_changes(int w, int h) {
|
|
static int old_width = -2000;
|
|
static int old_height = -2000;
|
|
static int widescreen = -2000;
|
|
static int xshift = -2000;
|
|
static int yshift = -2000;
|
|
static float zoomVert = -2000;
|
|
static float zoomHor = -2000;
|
|
|
|
int changed = 0;
|
|
|
|
if (w != old_width) {
|
|
changed = 1;
|
|
goto end;
|
|
}
|
|
if (h != old_height) {
|
|
changed = 1;
|
|
goto end;
|
|
}
|
|
|
|
if (widescreen != GCSettings.widescreen) {
|
|
changed = 1;
|
|
goto end;
|
|
}
|
|
|
|
if (xshift != GCSettings.xshift) {
|
|
changed = 1;
|
|
goto end;
|
|
}
|
|
|
|
if (yshift != GCSettings.yshift) {
|
|
changed = 1;
|
|
goto end;
|
|
}
|
|
|
|
if (zoomVert != GCSettings.zoomVert) {
|
|
changed = 1;
|
|
goto end;
|
|
}
|
|
|
|
if (zoomHor != GCSettings.zoomHor) {
|
|
changed = 1;
|
|
goto end;
|
|
}
|
|
|
|
// save values for next loop
|
|
end:
|
|
old_width = w;
|
|
old_height = h;
|
|
widescreen = GCSettings.widescreen;
|
|
xshift = GCSettings.xshift;
|
|
yshift = GCSettings.yshift;
|
|
zoomHor = GCSettings.zoomHor;
|
|
zoomVert = GCSettings.zoomVert;
|
|
|
|
return changed;
|
|
}
|
|
|
|
static void RenderInSurface(XenosSurface * source, XenosSurface * dest) {
|
|
// Update Vb
|
|
float x = -1, y = -1, w = 2, h = 2;
|
|
float u = (screenwidth/dest->width);
|
|
float v = (screenheight/dest->height);
|
|
SnesVerticeFormats* Rect = (SnesVerticeFormats*) Xe_VB_Lock(g_pVideoDevice, render_to_target_vb, 0, 4096, XE_LOCK_WRITE);
|
|
{
|
|
Rect[0].x = x;
|
|
Rect[0].y = y + h;
|
|
Rect[0].u = 0;
|
|
Rect[0].v = 0;
|
|
|
|
// bottom left
|
|
Rect[1].x = x;
|
|
Rect[1].y = y;
|
|
Rect[1].u = 0;
|
|
Rect[1].v = v;
|
|
|
|
// top right
|
|
Rect[2].x = x + w;
|
|
Rect[2].y = y + h;
|
|
Rect[2].u = u;
|
|
Rect[2].v = 0;
|
|
|
|
// top right
|
|
Rect[3].x = x + w;
|
|
Rect[3].y = y + h;
|
|
Rect[3].u = u;
|
|
Rect[3].v = 0;
|
|
|
|
// bottom left
|
|
Rect[4].x = x;
|
|
Rect[4].y = y;
|
|
Rect[4].u = 0;
|
|
Rect[4].v = v;
|
|
|
|
// bottom right
|
|
Rect[5].x = x + w;
|
|
Rect[5].y = y;
|
|
Rect[5].u = u;
|
|
Rect[5].v = v;
|
|
|
|
int i = 0;
|
|
for (i = 0; i < 6; i++) {
|
|
Rect[i].z = 0.0;
|
|
Rect[i].w = 1.0;
|
|
}
|
|
}
|
|
Xe_VB_Unlock(g_pVideoDevice, render_to_target_vb);
|
|
|
|
// Begin draw
|
|
Xe_InvalidateState(g_pVideoDevice);
|
|
//Xe_SetAlphaTestEnable(g_pVideoDevice, 0);
|
|
|
|
Xe_SetCullMode(g_pVideoDevice, XE_CULL_NONE);
|
|
Xe_SetClearColor(g_pVideoDevice, 0);
|
|
|
|
Xe_SetShader(g_pVideoDevice, SHADER_TYPE_PIXEL, SnesShaders[0].ps, 0);
|
|
Xe_SetShader(g_pVideoDevice, SHADER_TYPE_VERTEX, SnesShaders[0].vs, 0);
|
|
Xe_SetStreamSource(g_pVideoDevice, 0, render_to_target_vb, 0, sizeof (SnesVerticeFormats));
|
|
|
|
Xe_SetTexture(g_pVideoDevice, 0, source);
|
|
|
|
Xe_DrawPrimitive(g_pVideoDevice, XE_PRIMTYPE_RECTLIST, 0, 1);
|
|
|
|
Xe_ResolveInto(g_pVideoDevice, dest, XE_SOURCE_COLOR, XE_CLEAR_COLOR | XE_CLEAR_DS);
|
|
|
|
Xe_Sync(g_pVideoDevice);
|
|
}
|
|
|
|
// used to know which fb to use
|
|
static int ibuffer = 0;
|
|
|
|
static void DrawSnes(XenosSurface * data) {
|
|
if (data == NULL)
|
|
return;
|
|
|
|
// double buffering
|
|
ibuffer ^= 1;
|
|
|
|
// detect if something changed
|
|
if (detect_changes(g_SnesSurface->width, g_SnesSurface->height)) {
|
|
// work on vb
|
|
float x, y, w, h;
|
|
float scale = 1.f;
|
|
|
|
if (GCSettings.widescreen) {
|
|
scale = 3.f / 4.f;
|
|
}
|
|
|
|
w = (scale * 2.f) * GCSettings.zoomHor;
|
|
h = 2.f * GCSettings.zoomVert;
|
|
|
|
x = (GCSettings.xshift / (float) screenwidth) - (w / 2.f);
|
|
y = (-GCSettings.yshift / (float) screenheight) - (h / 2.f);
|
|
|
|
// Update Vb
|
|
SnesVerticeFormats* Rect = (SnesVerticeFormats*) Xe_VB_Lock(g_pVideoDevice, snes_vb, 0, 4096, XE_LOCK_WRITE);
|
|
{
|
|
Rect[0].x = x;
|
|
Rect[0].y = y + h;
|
|
Rect[0].u = 0;
|
|
Rect[0].v = 0;
|
|
|
|
// bottom left
|
|
Rect[1].x = x;
|
|
Rect[1].y = y;
|
|
Rect[1].u = 0;
|
|
Rect[1].v = 1;
|
|
|
|
// top right
|
|
Rect[2].x = x + w;
|
|
Rect[2].y = y + h;
|
|
Rect[2].u = 1;
|
|
Rect[2].v = 0;
|
|
|
|
// top right
|
|
Rect[3].x = x + w;
|
|
Rect[3].y = y + h;
|
|
Rect[3].u = 1;
|
|
Rect[3].v = 0;
|
|
|
|
// bottom left
|
|
Rect[4].x = x;
|
|
Rect[4].y = y;
|
|
Rect[4].u = 0;
|
|
Rect[4].v = 1;
|
|
|
|
// bottom right
|
|
Rect[5].x = x + w;
|
|
Rect[5].y = y;
|
|
Rect[5].u = 1;
|
|
Rect[5].v = 1;
|
|
|
|
int i = 0;
|
|
for (i = 0; i < 6; i++) {
|
|
Rect[i].z = 0.0;
|
|
Rect[i].w = 1.0;
|
|
}
|
|
}
|
|
Xe_VB_Unlock(g_pVideoDevice, snes_vb);
|
|
}
|
|
|
|
// Begin draw
|
|
Xe_InvalidateState(g_pVideoDevice);
|
|
|
|
Xe_SetCullMode(g_pVideoDevice, XE_CULL_NONE);
|
|
Xe_SetClearColor(g_pVideoDevice, 0);
|
|
|
|
// Refresh texture cache
|
|
Xe_Surface_LockRect(g_pVideoDevice, data, 0, 0, 0, 0, XE_LOCK_WRITE);
|
|
Xe_Surface_Unlock(g_pVideoDevice, data);
|
|
|
|
// Set Stream, shader, textures
|
|
Xe_SetShader(g_pVideoDevice, SHADER_TYPE_PIXEL, SnesShaders[selected_snes_shader].ps, 0);
|
|
Xe_SetShader(g_pVideoDevice, SHADER_TYPE_VERTEX, SnesShaders[selected_snes_shader].vs, 0);
|
|
Xe_SetStreamSource(g_pVideoDevice, 0, snes_vb, 0, sizeof (SnesVerticeFormats));
|
|
|
|
// use the callback related to selected shader
|
|
SnesShaders[selected_snes_shader].callback(NULL);
|
|
|
|
Xe_SetTexture(g_pVideoDevice, 0, data);
|
|
|
|
// Draw
|
|
Xe_DrawPrimitive(g_pVideoDevice, XE_PRIMTYPE_RECTLIST, 0, 1);
|
|
|
|
// Display
|
|
Xe_Resolve(g_pVideoDevice);
|
|
|
|
while (!Xe_IsVBlank(g_pVideoDevice));
|
|
|
|
// must be called between vblank and vsync
|
|
if(ibuffer ==0) {
|
|
// hack !!
|
|
w32(0x6110,g_framebuffer[0]->base);
|
|
g_pVideoDevice->tex_fb.base = g_framebuffer[0]->base;
|
|
Xe_SetRenderTarget(g_pVideoDevice,g_framebuffer[0]);
|
|
}
|
|
else{
|
|
w32(0x6110,g_framebuffer[1]->base);
|
|
g_pVideoDevice->tex_fb.base = g_framebuffer[1]->base;
|
|
Xe_SetRenderTarget(g_pVideoDevice,g_framebuffer[1]);
|
|
}
|
|
Xe_Sync(g_pVideoDevice);
|
|
}
|
|
|
|
XenosSurface * get_snes_surface() {
|
|
Xe_Surface_LockRect(g_pVideoDevice, g_SnesSurfaceShadow, 0, 0, 0, 0, XE_LOCK_WRITE);
|
|
Xe_Surface_Unlock(g_pVideoDevice, g_SnesSurfaceShadow);
|
|
return g_SnesSurfaceShadow;
|
|
}
|
|
|
|
static void ShowFPS(void) {
|
|
static unsigned long lastTick = 0;
|
|
static int frames = 0;
|
|
unsigned long nowTick;
|
|
frames++;
|
|
nowTick = mftb() / (PPC_TIMEBASE_FREQ / 1000);
|
|
if (lastTick + 1000 <= nowTick) {
|
|
|
|
printf("%d fps\r\n", frames);
|
|
|
|
frames = 0;
|
|
lastTick = nowTick;
|
|
}
|
|
}
|
|
|
|
static int frame = 0;
|
|
|
|
struct file_buffer_t {
|
|
char name[256];
|
|
unsigned char *data;
|
|
long length;
|
|
long offset;
|
|
};
|
|
|
|
struct pngMem {
|
|
unsigned char *png_end;
|
|
unsigned char *data;
|
|
int size;
|
|
int offset; //pour le parcours
|
|
};
|
|
|
|
static int offset = 0;
|
|
|
|
static void png_mem_write(png_structp png_ptr, png_bytep data, png_size_t length) {
|
|
struct file_buffer_t *dst = (struct file_buffer_t *) png_get_io_ptr(png_ptr);
|
|
/* Copy data from image buffer */
|
|
memcpy(dst->data + dst->offset, data, length);
|
|
/* Advance in the file */
|
|
dst->offset += length;
|
|
}
|
|
|
|
static struct XenosSurface *savePNGToMemory(XenosSurface * surface, unsigned char *PNGdata, int * size) {
|
|
png_structp png_ptr_w;
|
|
png_infop info_ptr_w;
|
|
// int number_of_passes;
|
|
png_bytep * row_pointers;
|
|
|
|
offset = 0;
|
|
|
|
struct file_buffer_t *file;
|
|
file = (struct file_buffer_t *) malloc(sizeof (struct file_buffer_t));
|
|
file->length = 1024 * 1024 * 5;
|
|
file->data = PNGdata; //5mo ...
|
|
file->offset = 0;
|
|
|
|
/* initialize stuff */
|
|
png_ptr_w = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
|
|
if (!png_ptr_w) {
|
|
printf("[write_png_file] png_create_read_struct failed\n");
|
|
return 0;
|
|
}
|
|
|
|
info_ptr_w = png_create_info_struct(png_ptr_w);
|
|
if (!info_ptr_w) {
|
|
printf("[write_png_file] png_create_info_struct failed\n");
|
|
return 0;
|
|
}
|
|
|
|
png_set_write_fn(png_ptr_w, (png_voidp *) file, png_mem_write, NULL);
|
|
png_set_IHDR(png_ptr_w, info_ptr_w, surface->width, surface->height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
|
|
|
uint32_t *data = (uint32_t *) surface->base;
|
|
uint32_t * untile_buffer = new uint32_t[surface->width * surface->height];
|
|
row_pointers = new png_bytep[surface->height];
|
|
|
|
int y, x;
|
|
for (y = 0; y < surface->height; ++y) {
|
|
for (x = 0; x < surface->width; ++x) {
|
|
unsigned int base = ((((y & ~31) * surface->width) + (x & ~31)*32) +
|
|
(((x & 3) + ((y & 1) << 2) + ((x & 28) << 1) + ((y & 30) << 5)) ^ ((y & 8) << 2)));
|
|
untile_buffer[y * surface->width + x] = 0xFF | __builtin_bswap32(data[base] >> 8);
|
|
}
|
|
row_pointers[y] = (png_bytep) (untile_buffer + y * surface->width);
|
|
}
|
|
|
|
png_set_rows(png_ptr_w, info_ptr_w, row_pointers);
|
|
png_write_png(png_ptr_w, info_ptr_w, PNG_TRANSFORM_IDENTITY, 0);
|
|
png_write_end(png_ptr_w, info_ptr_w);
|
|
png_destroy_write_struct(&png_ptr_w, &info_ptr_w);
|
|
|
|
*size = file->offset;
|
|
|
|
//free(file->data);
|
|
free(file);
|
|
//delete(data);
|
|
delete(row_pointers);
|
|
|
|
return (surface);
|
|
}
|
|
|
|
void update_video(int width, int height) {
|
|
g_SnesSurface->width = width;
|
|
g_SnesSurface->height = height;
|
|
|
|
shaderParameters.texture_size.w = width;
|
|
shaderParameters.texture_size.h = height;
|
|
shaderParameters.video_size.w = width;
|
|
shaderParameters.video_size.h = height;
|
|
shaderParameters.output_size.w = width;
|
|
shaderParameters.output_size.h = height;
|
|
|
|
if (GCSettings.render == 0 || GCSettings.render == 2 || selected_snes_shader)
|
|
g_SnesSurface->use_filtering = 0;
|
|
else
|
|
g_SnesSurface->use_filtering = 1;
|
|
|
|
DrawSnes(g_SnesSurface);
|
|
|
|
// Display Menu ?
|
|
if (ScreenshotRequested) {
|
|
// thumbnail
|
|
RenderInSurface(g_SnesSurface, g_SnesThumbnail);
|
|
// fb shadow
|
|
//RenderInSurface(g_SnesSurface, g_SnesSurfaceShadow);
|
|
if(ibuffer ==0) {
|
|
g_SnesSurfaceShadow = g_framebuffer[1];
|
|
}
|
|
else {
|
|
g_SnesSurfaceShadow = g_framebuffer[0];
|
|
}
|
|
|
|
// convert to png
|
|
savePNGToMemory(g_SnesThumbnail, gameScreenPng, &gameScreenPngSize);
|
|
|
|
|
|
ScreenshotRequested = 0;
|
|
//TakeScreenshot();
|
|
EmuConfigRequested = 1;
|
|
}
|
|
|
|
ShowFPS();
|
|
}
|
|
|
|
const char* GetFilterName(int filterID) {
|
|
if (filterID >= nb_snes_shaders) {
|
|
return "Unknown";
|
|
} else {
|
|
return SnesShaders[filterID].name;
|
|
}
|
|
}
|
|
|
|
void SelectFilterMethod() {
|
|
if (GCSettings.FilterMethod >= nb_snes_shaders) {
|
|
GCSettings.FilterMethod = nb_snes_shaders - 1;
|
|
}
|
|
selected_snes_shader = GCSettings.FilterMethod;
|
|
}
|
|
|
|
int GetFilterNumber() {
|
|
return nb_snes_shaders;
|
|
}
|
|
|
|
#endif
|