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