git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

Cocoa/GBGLShader.m

      1 #import "GBGLShader.h"
      2 #import <OpenGL/gl3.h>
      3 
      4 /*
      5  Loosely based of https://www.raywenderlich.com/70208/opengl-es-pixel-shaders-tutorial
      6  
      7  This code probably makes no sense after I upgraded it to OpenGL 3, since OpenGL makes aboslute no sense and has zero
      8  helpful documentation.
      9  */
     10 
     11 static NSString * const vertex_shader = @"\n\
     12 #version 150 \n\
     13 in vec4 aPosition;\n\
     14 void main(void) {\n\
     15     gl_Position = aPosition;\n\
     16 }\n\
     17 ";
     18 
     19 @implementation GBGLShader
     20 {
     21     GLuint resolution_uniform;
     22     GLuint texture_uniform;
     23     GLuint previous_texture_uniform;
     24     GLuint frame_blending_mode_uniform;
     25 
     26     GLuint position_attribute;
     27     GLuint texture;
     28     GLuint previous_texture;
     29     GLuint program;
     30 }
     31 
     32 + (NSString *) shaderSourceForName:(NSString *) name
     33 {
     34     return [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name
     35                                                                               ofType:@"fsh"
     36                                                                          inDirectory:@"Shaders"]
     37                                      encoding:NSUTF8StringEncoding
     38                                         error:nil];
     39 }
     40 
     41 - (instancetype)initWithName:(NSString *) shaderName
     42 {
     43     self = [super init];
     44     if (self) {
     45         // Program
     46         NSString *fragment_shader = [[self class] shaderSourceForName:@"MasterShader"];
     47         fragment_shader = [fragment_shader stringByReplacingOccurrencesOfString:@"{filter}"
     48                                                                      withString:[[self class] shaderSourceForName:shaderName]];
     49         program = [[self class] programWithVertexShader:vertex_shader fragmentShader:fragment_shader];
     50         // Attributes
     51         position_attribute = glGetAttribLocation(program, "aPosition");
     52         // Uniforms
     53         resolution_uniform = glGetUniformLocation(program, "output_resolution");
     54 
     55         glGenTextures(1, &texture);
     56         glBindTexture(GL_TEXTURE_2D, texture);
     57         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     58         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     59         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     60         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     61         glBindTexture(GL_TEXTURE_2D, 0);
     62         texture_uniform = glGetUniformLocation(program, "image");
     63 
     64         glGenTextures(1, &previous_texture);
     65         glBindTexture(GL_TEXTURE_2D, previous_texture);
     66         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     67         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     68         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     69         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     70         glBindTexture(GL_TEXTURE_2D, 0);
     71         previous_texture_uniform = glGetUniformLocation(program, "previous_image");
     72 
     73         frame_blending_mode_uniform = glGetUniformLocation(program, "frame_blending_mode");
     74 
     75         // Configure OpenGL
     76         [self configureOpenGL];
     77 
     78     }
     79     return self;
     80 }
     81 
     82 - (void) renderBitmap: (void *)bitmap previous:(void*) previous sized:(NSSize)srcSize inSize:(NSSize)dstSize scale: (double) scale withBlendingMode:(GB_frame_blending_mode_t)blendingMode
     83 {
     84     glUseProgram(program);
     85     glUniform2f(resolution_uniform, dstSize.width * scale, dstSize.height * scale);
     86     glActiveTexture(GL_TEXTURE0);
     87     glBindTexture(GL_TEXTURE_2D, texture);
     88     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, srcSize.width, srcSize.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
     89     glUniform1i(texture_uniform, 0);
     90     glUniform1i(frame_blending_mode_uniform, blendingMode);
     91     if (blendingMode) {
     92         glActiveTexture(GL_TEXTURE1);
     93         glBindTexture(GL_TEXTURE_2D, previous_texture);
     94         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, srcSize.width, srcSize.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, previous);
     95         glUniform1i(previous_texture_uniform, 1);
     96     }
     97     glBindFragDataLocation(program, 0, "frag_color");
     98     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
     99 }
    100 
    101 - (void)configureOpenGL
    102 {
    103     // Program
    104 
    105     glUseProgram(program);
    106 
    107     GLuint vao;
    108     glGenVertexArrays(1, &vao);
    109     glBindVertexArray(vao);
    110 
    111     GLuint vbo;
    112     glGenBuffers(1, &vbo);
    113 
    114     // Attributes
    115 
    116 
    117     static GLfloat const quad[16] = {
    118         -1.f, -1.f, 0, 1,
    119         -1.f, +1.f, 0, 1,
    120         +1.f, -1.f, 0, 1,
    121         +1.f, +1.f, 0, 1,
    122     };
    123 
    124 
    125     glBindBuffer(GL_ARRAY_BUFFER, vbo);
    126     glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
    127     glEnableVertexAttribArray(position_attribute);
    128     glVertexAttribPointer(position_attribute, 4, GL_FLOAT, GL_FALSE, 0, 0);
    129 }
    130 
    131 + (GLuint)programWithVertexShader:(NSString*)vsh fragmentShader:(NSString*)fsh
    132 {
    133     // Build shaders
    134     GLuint vertex_shader = [self shaderWithContents:vsh type:GL_VERTEX_SHADER];
    135     GLuint fragment_shader = [self shaderWithContents:fsh type:GL_FRAGMENT_SHADER];
    136     // Create program
    137     GLuint program = glCreateProgram();
    138     // Attach shaders
    139     glAttachShader(program, vertex_shader);
    140     glAttachShader(program, fragment_shader);
    141     // Link program
    142     glLinkProgram(program);
    143     // Check for errors
    144     GLint status;
    145     glGetProgramiv(program, GL_LINK_STATUS, &status);
    146     if (status == GL_FALSE) {
    147         GLchar messages[1024];
    148         glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);
    149         NSLog(@"%@:- GLSL Program Error: %s", self, messages);
    150     }
    151     // Delete shaders
    152     glDeleteShader(vertex_shader);
    153     glDeleteShader(fragment_shader);
    154 
    155     return program;
    156 }
    157 
    158 - (void)dealloc
    159 {
    160     glDeleteProgram(program);
    161     glDeleteTextures(1, &texture);
    162     glDeleteTextures(1, &previous_texture);
    163 
    164     /* OpenGL is black magic. Closing one view causes others to be completely black unless we reload their shaders */
    165     /* We're probably not freeing thing in the right place. */
    166     [[NSNotificationCenter defaultCenter] postNotificationName:@"GBFilterChanged$DefaultsObserver" object:nil];
    167 }
    168 
    169 + (GLuint)shaderWithContents:(NSString*)contents type:(GLenum)type
    170 {
    171 
    172     const GLchar *source = [contents UTF8String];
    173     // Create the shader object
    174     GLuint shader = glCreateShader(type);
    175     // Load the shader source
    176     glShaderSource(shader, 1, &source, 0);
    177     // Compile the shader
    178     glCompileShader(shader);
    179     // Check for errors
    180     GLint status = 0;
    181     glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    182     if (status == GL_FALSE) {
    183         GLchar messages[1024];
    184         glGetShaderInfoLog(shader, sizeof(messages), 0, &messages[0]);
    185         NSLog(@"%@:- GLSL Shader Error: %s", self, messages);
    186     }
    187     return shader;
    188 }
    189 
    190 @end

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.