diff options
| author | Takamichi Horikawa <takamichiho@gmail.com> | 2017-03-17 22:29:38 +0900 | 
|---|---|---|
| committer | Takamichi Horikawa <takamichiho@gmail.com> | 2017-03-17 22:29:38 +0900 | 
| commit | 96a63693e1d504f98d7a7a27434c849b3e954ef6 (patch) | |
| tree | cd33db56d723b2827c79eba5d9f542648efcfd25 | |
| parent | 46e2455027537dc1ef56b98b712cf92edf27dca5 (diff) | |
fmdsp opengl renderer
| -rw-r--r-- | fmdsp/fmdsp_gl.c | 177 | ||||
| -rw-r--r-- | fmdsp/fmdsp_gl.h | 11 | 
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 | 
