mirror of
https://github.com/libretro/RetroArch
synced 2025-02-28 12:40:23 +00:00
Update for more modern GL approach.
This commit is contained in:
parent
af7819e5cc
commit
c5f433f399
4
Makefile
4
Makefile
@ -3,7 +3,7 @@ include config.mk
|
|||||||
TARGET = ssnes
|
TARGET = ssnes
|
||||||
|
|
||||||
OBJ = ssnes.o
|
OBJ = ssnes.o
|
||||||
LIBS = -lsamplerate -lsnes
|
LIBS = -lsamplerate libsnes.a
|
||||||
|
|
||||||
ifeq ($(BUILD_RSOUND), 1)
|
ifeq ($(BUILD_RSOUND), 1)
|
||||||
OBJ += rsound.o
|
OBJ += rsound.o
|
||||||
@ -42,7 +42,7 @@ CFLAGS = -Wall -O3 -march=native -std=gnu99
|
|||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
ssnes: $(OBJ)
|
ssnes: $(OBJ)
|
||||||
@$(CC) -o $@ $(OBJ) $(LIBS)
|
@$(CXX) -o $@ $(OBJ) $(LIBS)
|
||||||
@echo "LD $@"
|
@echo "LD $@"
|
||||||
|
|
||||||
%.o: %.c config.h config.mk
|
%.o: %.c config.h config.mk
|
||||||
|
2
driver.h
2
driver.h
@ -67,7 +67,7 @@ typedef struct video_driver
|
|||||||
{
|
{
|
||||||
void* (*init)(video_info_t *video, const input_driver_t **input);
|
void* (*init)(video_info_t *video, const input_driver_t **input);
|
||||||
// Should the video driver act as an input driver as well? :)
|
// Should the video driver act as an input driver as well? :)
|
||||||
bool (*frame)(void* data, const uint16_t* frame, int width, int height);
|
bool (*frame)(void* data, const uint16_t* frame, int width, int height, int pitch);
|
||||||
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about syncing to vblank? Fast forwarding.
|
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about syncing to vblank? Fast forwarding.
|
||||||
void (*free)(void* data);
|
void (*free)(void* data);
|
||||||
} video_driver_t;
|
} video_driver_t;
|
||||||
|
148
gl.c
148
gl.c
@ -15,6 +15,7 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>.
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
#include <GL/glfw.h>
|
#include <GL/glfw.h>
|
||||||
@ -23,8 +24,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
static GLuint texture;
|
static GLuint texture, pbo, vbo;
|
||||||
static uint8_t *gl_buffer;
|
static uint8_t *gl_buffer, *vertex_buf;
|
||||||
static bool keep_aspect = true;
|
static bool keep_aspect = true;
|
||||||
static GLuint tex_filter;
|
static GLuint tex_filter;
|
||||||
|
|
||||||
@ -70,7 +71,6 @@ static int init_joypads(int max_pads)
|
|||||||
|
|
||||||
static int16_t glfw_input_state(void *data, const struct snes_keybind **binds, bool port, unsigned device, unsigned index, unsigned id)
|
static int16_t glfw_input_state(void *data, const struct snes_keybind **binds, bool port, unsigned device, unsigned index, unsigned id)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ( device != SNES_DEVICE_JOYPAD )
|
if ( device != SNES_DEVICE_JOYPAD )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -139,29 +139,29 @@ static void GLFWCALL resize(int width, int height)
|
|||||||
|
|
||||||
if ( keep_aspect )
|
if ( keep_aspect )
|
||||||
{
|
{
|
||||||
//float desired_aspect = 256.0/224.0;
|
float desired_aspect = 4.0/3;
|
||||||
float desired_aspect = 296.0/224.0;
|
float device_aspect = (float)width / height;
|
||||||
float in_aspect = (float)width / height;
|
|
||||||
|
|
||||||
if ( (int)(in_aspect*100) > (int)(desired_aspect*100) )
|
// If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff),
|
||||||
|
// assume they are actually equal.
|
||||||
|
if ( (int)(device_aspect*1000) > (int)(desired_aspect*1000) )
|
||||||
{
|
{
|
||||||
float delta = (in_aspect / desired_aspect - 1.0) / 2.0 + 0.5;
|
float delta = (desired_aspect / device_aspect - 1.0) / 2.0 + 0.5;
|
||||||
glOrtho(0.5 - delta, 0.5 + delta, 0, 1, -1, 1);
|
glViewport(width * (0.5 - delta), 0, 2.0 * width * delta, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( (int)(in_aspect*100) < (int)(desired_aspect*100) )
|
else if ( (int)(device_aspect*1000) < (int)(desired_aspect*1000) )
|
||||||
{
|
{
|
||||||
float delta = (desired_aspect / in_aspect - 1.0) / 2.0 + 0.5;
|
float delta = (device_aspect / desired_aspect - 1.0) / 2.0 + 0.5;
|
||||||
glOrtho(0, 1, 0.5 - delta, 0.5 + delta, -1, 1);
|
glViewport(0, height * (0.5 - delta), width, 2.0 * height * delta);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
glOrtho(0, 1, 0, 1, -1, 1);
|
glViewport(0, 0, width, height);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
glOrtho(0, 1, 0, 1, -1, 1);
|
glViewport(0, 0, width, height);
|
||||||
|
|
||||||
glViewport(0, 0, width, height);
|
glOrtho(0, 1, 0, 1, -1, 1);
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
}
|
}
|
||||||
@ -172,53 +172,9 @@ static float tv_to_fps(const struct timeval *tv, const struct timeval *new_tv, i
|
|||||||
return frames/time;
|
return frames/time;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool gl_frame(void *data, const uint16_t* frame, int width, int height)
|
static void show_fps(void)
|
||||||
{
|
{
|
||||||
gl_t *gl = data;
|
// Shows FPS in taskbar.
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex_filter);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex_filter);
|
|
||||||
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
|
|
||||||
|
|
||||||
glLoadIdentity();
|
|
||||||
glColor4f(1, 1, 1, 1);
|
|
||||||
|
|
||||||
float h = 224.0/256.0;
|
|
||||||
|
|
||||||
GLfloat vertexes[] = {
|
|
||||||
0, 0, 0,
|
|
||||||
0, 1, 0,
|
|
||||||
1, 1, 0,
|
|
||||||
1, 0, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
GLfloat tex_coords[] = {
|
|
||||||
0, h*height/gl->real_y,
|
|
||||||
0, 0,
|
|
||||||
(float)width/gl->real_x, 0,
|
|
||||||
(float)width/gl->real_x, h*height/gl->real_y
|
|
||||||
};
|
|
||||||
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
|
|
||||||
glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), vertexes);
|
|
||||||
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), tex_coords);
|
|
||||||
|
|
||||||
glDrawArrays(GL_QUADS, 0, 4);
|
|
||||||
|
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
|
|
||||||
// Shows FPS in taskbar.
|
|
||||||
static int frames = 0;
|
static int frames = 0;
|
||||||
static struct timeval tv;
|
static struct timeval tv;
|
||||||
struct timeval new_tv;
|
struct timeval new_tv;
|
||||||
@ -242,7 +198,28 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height)
|
|||||||
glfwSetWindowTitle(tmpstr);
|
glfwSetWindowTitle(tmpstr);
|
||||||
}
|
}
|
||||||
frames++;
|
frames++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gl_frame(void *data, const uint16_t* frame, int width, int height, int pitch)
|
||||||
|
{
|
||||||
|
gl_t *gl = data;
|
||||||
|
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
GLfloat tex_coords[] = {
|
||||||
|
0, (float)height/gl->real_y,
|
||||||
|
0, 0,
|
||||||
|
(float)width/gl->real_x, 0,
|
||||||
|
(float)width/gl->real_x, (float)height/gl->real_y
|
||||||
|
};
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch >> 1);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 128, sizeof(tex_coords), tex_coords);
|
||||||
|
glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, height * pitch, frame);
|
||||||
|
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
|
||||||
|
glDrawArrays(GL_QUADS, 0, 4);
|
||||||
|
|
||||||
|
show_fps();
|
||||||
glfwSwapBuffers();
|
glfwSwapBuffers();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -250,9 +227,14 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height)
|
|||||||
|
|
||||||
static void gl_free(void *data)
|
static void gl_free(void *data)
|
||||||
{
|
{
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
glDeleteTextures(1, &texture);
|
glDeleteTextures(1, &texture);
|
||||||
|
glDeleteBuffers(1, &pbo);
|
||||||
|
glDeleteBuffers(1, &vbo);
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
free(gl_buffer);
|
free(gl_buffer);
|
||||||
|
free(vertex_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gl_set_nonblock_state(void *data, bool state)
|
static void gl_set_nonblock_state(void *data, bool state)
|
||||||
@ -284,7 +266,7 @@ static void* gl_init(video_info_t *video, const input_driver_t **input)
|
|||||||
int res;
|
int res;
|
||||||
res = glfwOpenWindow(video->width, video->height, 0, 0, 0, 0, 0, 0, (video->fullscreen) ? GLFW_FULLSCREEN : GLFW_WINDOW);
|
res = glfwOpenWindow(video->width, video->height, 0, 0, 0, 0, 0, 0, (video->fullscreen) ? GLFW_FULLSCREEN : GLFW_WINDOW);
|
||||||
|
|
||||||
if ( !res )
|
if (!res)
|
||||||
{
|
{
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -298,19 +280,22 @@ static void* gl_init(video_info_t *video, const input_driver_t **input)
|
|||||||
glfwSwapInterval(0);
|
glfwSwapInterval(0);
|
||||||
gl->vsync = video->vsync;
|
gl->vsync = video->vsync;
|
||||||
|
|
||||||
gl_buffer = malloc(256 * 256 * 2 * video->input_scale * video->input_scale);
|
gl_buffer = calloc(1, 256 * 256 * 2 * video->input_scale * video->input_scale);
|
||||||
if ( !gl_buffer )
|
vertex_buf = calloc(1, 256);
|
||||||
|
if ( !gl_buffer || !vertex_buf )
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Couldn't allocate memory :<\n");
|
fprintf(stderr, "Couldn't allocate memory :<\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
gl->real_x = video->input_scale * 256;
|
gl->real_x = video->input_scale * 256;
|
||||||
gl->real_y = video->input_scale * 224;
|
gl->real_y = video->input_scale * 256;
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glEnable(GL_DITHER);
|
glEnable(GL_DITHER);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glColor3f(1, 1, 1);
|
||||||
|
glClearColor(0, 0, 0, 0);
|
||||||
|
|
||||||
glfwSetWindowTitle("SSNES");
|
glfwSetWindowTitle("SSNES");
|
||||||
|
|
||||||
@ -318,11 +303,36 @@ static void* gl_init(video_info_t *video, const input_driver_t **input)
|
|||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
|
||||||
glGenTextures(1, &texture);
|
glGenTextures(1, &texture);
|
||||||
|
glGenBuffers(1, &pbo);
|
||||||
|
glGenBuffers(1, &vbo);
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
|
||||||
|
glBufferData(GL_PIXEL_UNPACK_BUFFER, 256 * 256 * 2 * video->input_scale * video->input_scale, gl_buffer, GL_STREAM_DRAW);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
//glPixelStorei(GL_UNPACK_ROW_LENGTH, 256 * video->input_scale);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D,
|
glTexImage2D(GL_TEXTURE_2D,
|
||||||
0, GL_RGB, 256 * video->input_scale, 256 * video->input_scale, 0, GL_BGRA,
|
0, GL_RGB, 256 * video->input_scale, 256 * video->input_scale, 0, GL_BGRA,
|
||||||
GL_UNSIGNED_SHORT_1_5_5_5_REV, gl_buffer);
|
GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex_filter);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex_filter);
|
||||||
|
|
||||||
|
GLfloat vertexes[] = {
|
||||||
|
0, 0, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
1, 1, 0,
|
||||||
|
1, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, 256, vertex_buf, GL_STREAM_DRAW);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertexes), vertexes);
|
||||||
|
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), NULL);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), (void*)128);
|
||||||
|
|
||||||
*input = &input_glfw;
|
*input = &input_glfw;
|
||||||
return gl;
|
return gl;
|
||||||
|
13
ssnes.c
13
ssnes.c
@ -212,6 +212,7 @@ static void uninit_video_input(void)
|
|||||||
driver.input->free(driver.input_data);
|
driver.input->free(driver.input_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if VIDEO_FILTER != FILTER_NONE
|
||||||
static inline void process_frame (uint16_t * restrict out, const uint16_t * restrict in, unsigned width, unsigned height)
|
static inline void process_frame (uint16_t * restrict out, const uint16_t * restrict in, unsigned width, unsigned height)
|
||||||
{
|
{
|
||||||
int pitch = 1024;
|
int pitch = 1024;
|
||||||
@ -226,6 +227,7 @@ static inline void process_frame (uint16_t * restrict out, const uint16_t * rest
|
|||||||
memcpy(dst, src, width * sizeof(uint16_t));
|
memcpy(dst, src, width * sizeof(uint16_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// libsnes: 0.065
|
// libsnes: 0.065
|
||||||
// Format received is 16-bit 0RRRRRGGGGGBBBBB
|
// Format received is 16-bit 0RRRRRGGGGGBBBBB
|
||||||
@ -241,14 +243,13 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
|
|||||||
#elif VIDEO_FILTER == FILTER_NTSC
|
#elif VIDEO_FILTER == FILTER_NTSC
|
||||||
uint16_t output_ntsc[SNES_NTSC_OUT_WIDTH(width) * height];
|
uint16_t output_ntsc[SNES_NTSC_OUT_WIDTH(width) * height];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if VIDEO_FILTER != FILTER_NONE
|
||||||
uint16_t output[width * height];
|
uint16_t output[width * height];
|
||||||
|
|
||||||
process_frame(output, data, width, height);
|
process_frame(output, data, width, height);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if VIDEO_FILTER == FILTER_NONE
|
#if VIDEO_FILTER == FILTER_HQ2X
|
||||||
if ( !driver.video->frame(driver.video_data, output, width, height) )
|
|
||||||
video_active = false;
|
|
||||||
#elif VIDEO_FILTER == FILTER_HQ2X
|
|
||||||
ProcessHQ2x(output, outputHQ2x);
|
ProcessHQ2x(output, outputHQ2x);
|
||||||
if ( !driver.video->frame(driver.video_data, outputHQ2x, width * 2, height * 2) )
|
if ( !driver.video->frame(driver.video_data, outputHQ2x, width * 2, height * 2) )
|
||||||
video_active = false;
|
video_active = false;
|
||||||
@ -269,7 +270,7 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
|
|||||||
if ( !driver.video->frame(driver.video_data, output_ntsc, SNES_NTSC_OUT_WIDTH(width), height) )
|
if ( !driver.video->frame(driver.video_data, output_ntsc, SNES_NTSC_OUT_WIDTH(width), height) )
|
||||||
video_active = false;
|
video_active = false;
|
||||||
#else
|
#else
|
||||||
if ( !driver.video->frame(driver.video_data, output, width, height) )
|
if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) )
|
||||||
video_active = false;
|
video_active = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user