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.