aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakamichi Horikawa <takamichiho@gmail.com>2017-03-17 22:29:38 +0900
committerTakamichi Horikawa <takamichiho@gmail.com>2017-03-17 22:29:38 +0900
commit96a63693e1d504f98d7a7a27434c849b3e954ef6 (patch)
treecd33db56d723b2827c79eba5d9f542648efcfd25
parent46e2455027537dc1ef56b98b712cf92edf27dca5 (diff)
fmdsp opengl renderer
-rw-r--r--fmdsp/fmdsp_gl.c177
-rw-r--r--fmdsp/fmdsp_gl.h11
2 files changed, 188 insertions, 0 deletions
diff --git a/fmdsp/fmdsp_gl.c b/fmdsp/fmdsp_gl.c
new file mode 100644
index 0000000..7f62a60
--- /dev/null
+++ b/fmdsp/fmdsp_gl.c
@@ -0,0 +1,177 @@
+// supports OpenGL 2.0 / OpenGL ES 2.0
+// when using OpenGL ES, define MYON_OPENGL_ES
+
+#include "myon_opengl.h"
+#include "fmdsp_gl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef MYON_OPENGL_ES
+static const char sh_version[] = "#version 100\n";
+#else
+static const char sh_version[] = "#version 110\n";
+#endif
+
+static const char v_sh[] =
+ "attribute vec2 coord2d;\n"
+ "varying vec2 texcoord;\n"
+ "uniform float xscale;\n"
+ "uniform float yscale;\n"
+ "void main(void) {\n"
+ " vec2 coord = coord2d * vec2(xscale, yscale);\n"
+ " gl_Position = vec4(coord, 0.0, 1.0);\n"
+ " texcoord = (coord2d + 1.0) / 2.0;\n"
+ " texcoord = vec2(texcoord.x, 1.0-texcoord.y);\n"
+ "}\n"
+;
+
+#ifdef MYON_OPENGL_ES
+static const char f_sh[] =
+ "uniform sampler2D vram;\n"
+ "uniform sampler2D palette;\n"
+ "varying mediump vec2 texcoord;\n"
+ "void main(void) {\n"
+ " mediump float index = texture2D(vram, texcoord).x;\n"
+ " index = index * 256.0 / 9.0;\n"
+ " gl_FragColor = texture2D(palette, vec2(index, 0.0));\n"
+ "}\n"
+;
+#else
+static const char f_sh[] =
+ "uniform sampler2D vram;\n"
+ "uniform sampler2D palette;\n"
+ "varying vec2 texcoord;\n"
+ "void main(void) {\n"
+ " float index = texture2D(vram, texcoord).x;\n"
+ " index = index * 256.0 / 9.0;\n"
+ " gl_FragColor = texture2D(palette, vec2(index, 0.0));\n"
+ "}\n"
+;
+#endif
+
+static const GLfloat triangle_vertices[] = {
+ -1.0, -1.0,
+ 1.0, -1.0,
+ -1.0, 1.0,
+ 1.0, 1.0
+};
+
+static GLuint create_shader(const char *shader, GLenum type) {
+ GLuint s = glCreateShader(type);
+ const char *source[2] = {sh_version, shader};
+ glShaderSource(s, 2, source, 0);
+ glCompileShader(s);
+ GLint ok;
+ glGetShaderiv(s, GL_COMPILE_STATUS, &ok);
+ if (!ok) {
+ GLint len;
+ glGetShaderiv(s, GL_INFO_LOG_LENGTH, &len);
+ if (len > 0) {
+ char *log = malloc(len);
+ if (log) {
+ glGetShaderInfoLog(s, len, 0, log);
+ printf("%s shader error: \n%s\n",
+ (type == GL_VERTEX_SHADER) ? "vertex" : "fragment",
+ log);
+ free(log);
+ }
+ }
+ glDeleteShader(s);
+ return 0;
+ }
+ return s;
+}
+
+struct fmdsp_gl {
+ struct fmdsp *fmdsp;
+ GLuint program;
+ GLint attr_coord2d;
+ GLint uni_vram;
+ GLint uni_palette;
+ GLint uni_xscale;
+ GLint uni_yscale;
+ GLuint tex_vram;
+ GLuint tex_palette;
+ uint8_t prev_palette[FMDSP_PALETTE_COLORS*3];
+};
+
+struct fmdsp_gl *fmdsp_gl_init(struct fmdsp *fmdsp, float xscale, float yscale) {
+ struct fmdsp_gl *fmdsp_gl = 0;
+ GLint vs = 0;
+ GLint fs = 0;
+ fmdsp_gl = malloc(sizeof(*fmdsp_gl));
+ if (!fmdsp_gl) goto err;
+ fmdsp_gl->fmdsp = fmdsp;
+ fmdsp_gl->program = glCreateProgram();
+ glGenTextures(1, &fmdsp_gl->tex_vram);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, fmdsp_gl->tex_vram);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glActiveTexture(GL_TEXTURE1);
+ glGenTextures(1, &fmdsp_gl->tex_palette);
+ glBindTexture(GL_TEXTURE_2D, fmdsp_gl->tex_palette);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ vs = create_shader(v_sh, GL_VERTEX_SHADER);
+ if (!vs) goto err;
+ fs = create_shader(f_sh, GL_FRAGMENT_SHADER);
+ if (!fs) goto err;
+ glAttachShader(fmdsp_gl->program, vs);
+ glAttachShader(fmdsp_gl->program, fs);
+ glLinkProgram(fmdsp_gl->program);
+ GLint ok;
+ glGetProgramiv(fmdsp_gl->program, GL_LINK_STATUS, &ok);
+ if (!ok) {
+ printf("link error\n");
+ goto err;
+ }
+ glUseProgram(fmdsp_gl->program);
+ fmdsp_gl->attr_coord2d = glGetAttribLocation(fmdsp_gl->program, "coord2d");
+ if (fmdsp_gl->attr_coord2d < 0) goto err;
+ fmdsp_gl->uni_vram = glGetUniformLocation(fmdsp_gl->program, "vram");
+ if (fmdsp_gl->uni_vram < 0) goto err;
+ fmdsp_gl->uni_palette = glGetUniformLocation(fmdsp_gl->program, "palette");
+ if (fmdsp_gl->uni_palette < 0) goto err;
+ fmdsp_gl->uni_xscale = glGetUniformLocation(fmdsp_gl->program, "xscale");
+ if (fmdsp_gl->uni_xscale < 0) goto err;
+ fmdsp_gl->uni_yscale = glGetUniformLocation(fmdsp_gl->program, "yscale");
+ if (fmdsp_gl->uni_yscale < 0) goto err;
+ glUniform1i(fmdsp_gl->uni_vram, 0);
+ glUniform1i(fmdsp_gl->uni_palette, 1);
+ glUniform1f(fmdsp_gl->uni_xscale, xscale);
+ glUniform1f(fmdsp_gl->uni_yscale, yscale);
+ glEnableVertexAttribArray(fmdsp_gl->attr_coord2d);
+ glVertexAttribPointer(fmdsp_gl->attr_coord2d,
+ 2, GL_FLOAT, GL_FALSE, 0, triangle_vertices);
+ return fmdsp_gl;
+err:
+ glDeleteShader(vs);
+ glDeleteShader(fs);
+ if (fmdsp_gl) {
+ glDeleteTextures(1, &fmdsp_gl->tex_vram);
+ glDeleteTextures(1, &fmdsp_gl->tex_palette);
+ glDeleteProgram(fmdsp_gl->program);
+ }
+ free(fmdsp_gl);
+ return 0;
+}
+
+void fmdsp_gl_render(struct fmdsp_gl *fmdsp_gl, uint8_t *vram) {
+ glActiveTexture(GL_TEXTURE0);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, PC98_W, PC98_H, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, vram);
+ if (memcmp(fmdsp_gl->prev_palette, fmdsp_gl->fmdsp->palette, sizeof(fmdsp_gl->prev_palette))) {
+ glActiveTexture(GL_TEXTURE1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, FMDSP_PALETTE_COLORS, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, fmdsp_gl->fmdsp->palette);
+ memcpy(fmdsp_gl->prev_palette, fmdsp_gl->fmdsp->palette, sizeof(fmdsp_gl->prev_palette));
+ }
+ glClear(GL_COLOR_BUFFER_BIT);
+ glActiveTexture(GL_TEXTURE1);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ glFlush();
+}
diff --git a/fmdsp/fmdsp_gl.h b/fmdsp/fmdsp_gl.h
new file mode 100644
index 0000000..e279b61
--- /dev/null
+++ b/fmdsp/fmdsp_gl.h
@@ -0,0 +1,11 @@
+#ifndef MYON_FMDSP_GL_H_INCLUDED
+#define MYON_FMDSP_GL_H_INCLUDED
+
+#include "fmdsp/fmdsp.h"
+
+struct fmdsp_gl;
+
+struct fmdsp_gl *fmdsp_gl_init(struct fmdsp *fmdsp, float xscale, float yscale);
+void fmdsp_gl_render(struct fmdsp_gl *fmdsp_gl, uint8_t *vram);
+
+#endif // MYON_FMDSP_GL_H_INCLUDED