1 #include <stdio.h>
2 #include <string.h>
3 #include "shader.h"
4 #include "utils.h"
5
6 static const char *vertex_shader = "\n\
7 #version 150 \n\
8 in vec4 aPosition;\n\
9 void main(void) {\n\
10 gl_Position = aPosition;\n\
11 }\n\
12 ";
13
create_shader(const char * source,GLenum type)14 static GLuint create_shader(const char *source, GLenum type)
15 {
16 // Create the shader object
17 GLuint shader = glCreateShader(type);
18 // Load the shader source
19 glShaderSource(shader, 1, &source, 0);
20 // Compile the shader
21 glCompileShader(shader);
22 // Check for errors
23 GLint status = 0;
24 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
25 if (status == GL_FALSE) {
26 GLchar messages[1024];
27 glGetShaderInfoLog(shader, sizeof(messages), 0, &messages[0]);
28 fprintf(stderr, "GLSL Shader Error: %s", messages);
29 }
30 return shader;
31 }
32
create_program(const char * vsh,const char * fsh)33 static GLuint create_program(const char *vsh, const char *fsh)
34 {
35 // Build shaders
36 GLuint vertex_shader = create_shader(vsh, GL_VERTEX_SHADER);
37 GLuint fragment_shader = create_shader(fsh, GL_FRAGMENT_SHADER);
38
39 // Create program
40 GLuint program = glCreateProgram();
41
42 // Attach shaders
43 glAttachShader(program, vertex_shader);
44 glAttachShader(program, fragment_shader);
45
46 // Link program
47 glLinkProgram(program);
48 // Check for errors
49 GLint status;
50 glGetProgramiv(program, GL_LINK_STATUS, &status);
51
52 if (status == GL_FALSE) {
53 GLchar messages[1024];
54 glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);
55 fprintf(stderr, "GLSL Program Error: %s", messages);
56 }
57
58 // Delete shaders
59 glDeleteShader(vertex_shader);
60 glDeleteShader(fragment_shader);
61
62 return program;
63 }
64
65 extern bool uses_gl(void);
init_shader_with_name(shader_t * shader,const char * name)66 bool init_shader_with_name(shader_t *shader, const char *name)
67 {
68 if (!uses_gl()) return false;
69
70 GLint major = 0, minor = 0;
71 glGetIntegerv(GL_MAJOR_VERSION, &major);
72 glGetIntegerv(GL_MINOR_VERSION, &minor);
73
74 if (major * 0x100 + minor < 0x302) {
75 return false;
76 }
77
78 static char master_shader_code[0x801] = {0,};
79 static char shader_code[0x10001] = {0,};
80 static char final_shader_code[0x10801] = {0,};
81 static ssize_t filter_token_location = 0;
82
83 if (!master_shader_code[0]) {
84 FILE *master_shader_f = fopen(resource_path("Shaders/MasterShader.fsh"), "r");
85 if (!master_shader_f) return false;
86 fread(master_shader_code, 1, sizeof(master_shader_code) - 1, master_shader_f);
87 fclose(master_shader_f);
88 filter_token_location = strstr(master_shader_code, "{filter}") - master_shader_code;
89 if (filter_token_location < 0) {
90 master_shader_code[0] = 0;
91 return false;
92 }
93 }
94
95 char shader_path[1024];
96 sprintf(shader_path, "Shaders/%s.fsh", name);
97
98 FILE *shader_f = fopen(resource_path(shader_path), "r");
99 if (!shader_f) return false;
100 memset(shader_code, 0, sizeof(shader_code));
101 fread(shader_code, 1, sizeof(shader_code) - 1, shader_f);
102 fclose(shader_f);
103
104 memset(final_shader_code, 0, sizeof(final_shader_code));
105 memcpy(final_shader_code, master_shader_code, filter_token_location);
106 strcpy(final_shader_code + filter_token_location, shader_code);
107 strcat(final_shader_code + filter_token_location,
108 master_shader_code + filter_token_location + sizeof("{filter}") - 1);
109
110 shader->program = create_program(vertex_shader, final_shader_code);
111
112 // Attributes
113 shader->position_attribute = glGetAttribLocation(shader->program, "aPosition");
114 // Uniforms
115 shader->resolution_uniform = glGetUniformLocation(shader->program, "output_resolution");
116 shader->origin_uniform = glGetUniformLocation(shader->program, "origin");
117
118 glGenTextures(1, &shader->texture);
119 glBindTexture(GL_TEXTURE_2D, shader->texture);
120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
121 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
124 glBindTexture(GL_TEXTURE_2D, 0);
125 shader->texture_uniform = glGetUniformLocation(shader->program, "image");
126
127 glGenTextures(1, &shader->previous_texture);
128 glBindTexture(GL_TEXTURE_2D, shader->previous_texture);
129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
133 glBindTexture(GL_TEXTURE_2D, 0);
134 shader->previous_texture_uniform = glGetUniformLocation(shader->program, "previous_image");
135
136 shader->blending_mode_uniform = glGetUniformLocation(shader->program, "frame_blending_mode");
137
138 // Program
139
140 glUseProgram(shader->program);
141
142 GLuint vao;
143 glGenVertexArrays(1, &vao);
144 glBindVertexArray(vao);
145
146 GLuint vbo;
147 glGenBuffers(1, &vbo);
148
149 // Attributes
150
151
152 static GLfloat const quad[16] = {
153 -1.f, -1.f, 0, 1,
154 -1.f, +1.f, 0, 1,
155 +1.f, -1.f, 0, 1,
156 +1.f, +1.f, 0, 1,
157 };
158
159
160 glBindBuffer(GL_ARRAY_BUFFER, vbo);
161 glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
162 glEnableVertexAttribArray(shader->position_attribute);
163 glVertexAttribPointer(shader->position_attribute, 4, GL_FLOAT, GL_FALSE, 0, 0);
164
165 return true;
166 }
167
render_bitmap_with_shader(shader_t * shader,void * bitmap,void * previous,unsigned source_width,unsigned source_height,unsigned x,unsigned y,unsigned w,unsigned h,GB_frame_blending_mode_t blending_mode)168 void render_bitmap_with_shader(shader_t *shader, void *bitmap, void *previous,
169 unsigned source_width, unsigned source_height,
170 unsigned x, unsigned y, unsigned w, unsigned h,
171 GB_frame_blending_mode_t blending_mode)
172 {
173 glUseProgram(shader->program);
174 glUniform2f(shader->origin_uniform, x, y);
175 glUniform2f(shader->resolution_uniform, w, h);
176 glActiveTexture(GL_TEXTURE0);
177 glBindTexture(GL_TEXTURE_2D, shader->texture);
178 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, source_width, source_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
179 glUniform1i(shader->texture_uniform, 0);
180 glUniform1i(shader->blending_mode_uniform, previous? blending_mode : GB_FRAME_BLENDING_MODE_DISABLED);
181 if (previous) {
182 glActiveTexture(GL_TEXTURE1);
183 glBindTexture(GL_TEXTURE_2D, shader->previous_texture);
184 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, source_width, source_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, previous);
185 glUniform1i(shader->previous_texture_uniform, 1);
186 }
187 glBindFragDataLocation(shader->program, 0, "frag_color");
188 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
189 }
190
free_shader(shader_t * shader)191 void free_shader(shader_t *shader)
192 {
193 if (!uses_gl()) return;
194 GLint major = 0, minor = 0;
195 glGetIntegerv(GL_MAJOR_VERSION, &major);
196 glGetIntegerv(GL_MINOR_VERSION, &minor);
197
198 if (major * 0x100 + minor < 0x302) {
199 return;
200 }
201
202 glDeleteProgram(shader->program);
203 glDeleteTextures(1, &shader->texture);
204 glDeleteTextures(1, &shader->previous_texture);
205
206 }
207