diff render_sdl.c @ 488:32f053ad9b02 opengl

Basic OpenGL rendering is working
author Mike Pavone <pavone@retrodev.com>
date Sun, 27 Oct 2013 01:29:50 -0700
parents c08a4efeee7f
children e97b80e3bd76
line wrap: on
line diff
--- a/render_sdl.c	Sat Oct 26 22:38:47 2013 -0700
+++ b/render_sdl.c	Sun Oct 27 01:29:50 2013 -0700
@@ -10,9 +10,7 @@
 #include "io.h"
 
 #ifndef DISABLE_OPENGL
-#define GL_GLEXT_PROTOTYPES
-#include <GL/gl.h>
-#include <GL/glext.h>
+#include <GL/glew.h>
 #endif
 
 SDL_Surface *screen;
@@ -93,13 +91,13 @@
 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b)
 {
 	if (render_gl) {
-		return b << 24 | g << 16 | r << 8 | 255;
+		return 255 << 24 | r << 16 | g << 8 | b;
 	} else {
 		return SDL_MapRGB(screen->format, r, g, b);
 	}
 }
 
-GLuint textures[3], buffers[2];
+GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], at_pos;
 
 const GLfloat vertex_data[] = {
 	-1.0f, -1.0f,
@@ -110,6 +108,41 @@
 
 const GLushort element_data[] = {0, 1, 2, 3};
 
+GLuint load_shader(char * fname, GLenum shader_type)
+{
+	FILE * f = fopen(fname, "r");
+	if (!f) {
+		fprintf(stderr, "Failed to open shader file %s for reading\n", fname);
+		return 0;
+	}
+	fseek(f, 0, SEEK_END);
+	long fsize = ftell(f);
+	fseek(f, 0, SEEK_SET);
+	GLchar * text = malloc(fsize);
+	if (fread(text, 1, fsize, f) != fsize) {
+		fprintf(stderr, "Error reading from shader file %s\n", fname);
+		free(text);
+		return 0;
+	}
+	GLuint ret = glCreateShader(shader_type);
+	glShaderSource(ret, 1, (const GLchar **)&text, (const GLint *)&fsize);
+	free(text);
+	glCompileShader(ret);
+	GLint compile_status, loglen;
+	glGetShaderiv(ret, GL_COMPILE_STATUS, &compile_status);
+	if (!compile_status) {
+		fprintf(stderr, "Shader %s failed to compile\n", fname);
+		glGetShaderiv(ret, GL_INFO_LOG_LENGTH, &loglen);
+		text = malloc(loglen);
+		glGetShaderInfoLog(ret, loglen, NULL, text);
+		fputs(text, stderr);
+		free(text);
+		glDeleteShader(ret);
+		return 0;
+	}
+	return ret;
+}
+
 void render_alloc_surfaces(vdp_context * context)
 {
 	if (render_gl) {
@@ -134,8 +167,23 @@
 		glGenBuffers(2, buffers);
 		glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
 		glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
-		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[0]);
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
 		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW);
+		vshader = load_shader("default.v.glsl", GL_VERTEX_SHADER);
+		fshader = load_shader("default.f.glsl", GL_FRAGMENT_SHADER);
+		program = glCreateProgram();
+		glAttachShader(program, vshader);
+		glAttachShader(program, fshader);
+		glLinkProgram(program);
+		GLint link_status;
+		glGetProgramiv(program, GL_LINK_STATUS, &link_status);
+		if (!link_status) {
+			fputs("Failed to link shader program\n", stderr);
+			exit(1);
+		}
+		un_textures[0] = glGetUniformLocation(program, "textures[0]");
+		un_textures[1] = glGetUniformLocation(program, "textures[1]");
+		at_pos = glGetAttribLocation(program, "pos");
 	} else {
 		context->oddbuf = context->framebuf = malloc(320 * 240 * screen->format->BytesPerPixel * 2);
 		context->evenbuf = ((char *)context->oddbuf) + 320 * 240 * screen->format->BytesPerPixel;
@@ -159,6 +207,7 @@
 	atexit(render_close_audio);
 	printf("width: %d, height: %d\n", width, height);
 	uint32_t flags = SDL_ANYFORMAT;
+
 #ifndef DISABLE_OPENGL
 	if (use_gl)
 	{
@@ -188,7 +237,21 @@
 		exit(1);
 	}
 #ifndef DISABLE_OPENGL
-	//TODO: Fallback to plain SDL if OpenGL 2.0 not available
+	//TODO: fallback on standard rendering if OpenGL 2.0 is unavailable or if init fails
+	if (use_gl)
+	{
+		GLenum res = glewInit();
+		if (res != GLEW_OK)
+		{
+			fprintf(stderr, "Initialization of GLEW failed with code %d\n", res);
+			exit(1);
+		}
+		if (!GLEW_VERSION_2_0)
+		{
+			fputs("OpenGL 2.0 is unable, falling back to standard SDL rendering\n", stderr);
+			exit(1);
+		}
+	}
 	render_gl = use_gl;
 #endif
 	SDL_WM_SetCaption(title, title);
@@ -263,6 +326,27 @@
 	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
 	glClear(GL_COLOR_BUFFER_BIT);
 
+	glUseProgram(program);
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_2D, textures[0]);
+	glUniform1i(un_textures[0], 0);
+
+	glActiveTexture(GL_TEXTURE1);
+	//TODO: Select appropriate texture based on status of interlace
+	glBindTexture(GL_TEXTURE_2D, textures[1]);
+	glUniform1i(un_textures[1], 1);
+
+	glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+	glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0);
+	glEnableVertexAttribArray(at_pos);
+
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
+	glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0);
+
+	glDisableVertexAttribArray(at_pos);
+
+	SDL_GL_SwapBuffers();
+
 }
 
 uint32_t blankbuf[320*240];