summaryrefslogtreecommitdiff
path: root/opengl.c
blob: 847fc12a28e0ce0c58ffb6797c0efeca9719b710 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

#include "shader.c"
#include "shader.h"
#include "fragment_shader.h"
#include "vertex_shader.h"

/* [=]===^=[ compile_shader ]==============================================================^===[=] */
static GLuint compile_shader(GLenum shader_type, const char *shader_source) {
	GLuint shader = glCreateShader(shader_type);
	glShaderSource(shader, 1, &shader_source, 0);
	glCompileShader(shader);

	GLint success;
	GLchar info_log[512];
	glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
	if(!success) {
		glGetShaderInfoLog(shader, sizeof(info_log), 0, info_log);
		printf("%s shader compilation failed:\n%s\n", (shader_type == GL_VERTEX_SHADER) ? "Vertex" : "Fragment", info_log);
	}
	return shader;
}

/* [=]===^=[ opengl_setup ]================================================================^===[=] */
static void opengl_setup(void) {
	gl_loader();

	glEnable(GL_FRAMEBUFFER_SRGB);
	glDisable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glDisable(GL_CULL_FACE);

	// Compile shaders
	GLuint vertex_shader = compile_shader(GL_VERTEX_SHADER, vertex_shader_start);
	GLuint fragment_shader = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_start);

printf("%d %d\n", vertex_shader, fragment_shader);

	state.shader_program = glCreateProgram();
	glAttachShader(state.shader_program, vertex_shader);
	glAttachShader(state.shader_program, fragment_shader);
	glBindAttribLocation(state.shader_program, 0, "position");
	glBindAttribLocation(state.shader_program, 1, "texture_coord");
	glLinkProgram(state.shader_program);

	GLint success;
	glGetProgramiv(state.shader_program, GL_LINK_STATUS, &success);
	if(!success) {
		GLchar log[512];
		glGetProgramInfoLog(state.shader_program, sizeof(log), 0, log);
		printf("Shader Linking Failed:\n%s\n", log);
	}

	glDeleteShader(vertex_shader);
	glDeleteShader(fragment_shader);
	glUseProgram(state.shader_program);

	state.contrast = 1.0f;
	state.saturation = 0.0f;
	state.brightness = 1.0f;
	CrtsTone(state.tone_data, state.contrast, state.saturation, INPUT_THIN, INPUT_MASK);

	state.uniform_resolution = glGetUniformLocation(state.shader_program, "resolution");
	state.uniform_src_image_size = glGetUniformLocation(state.shader_program, "src_image_size");
	state.uniform_brightness = glGetUniformLocation(state.shader_program, "brightness");
	state.uniform_tone = glGetUniformLocation(state.shader_program, "tone_data");
	state.uniform_crt_emulation = glGetUniformLocation(state.shader_program, "crt_emulation");
	state.uniform_sampler_location = glGetUniformLocation(state.shader_program, "iChannel0");

	glGenVertexArrays(1, &state.vao);
	glBindVertexArray(state.vao);

	glGenBuffers(1, &state.vbo);
	glGenBuffers(1, &state.ebo);

	glBindBuffer(GL_ARRAY_BUFFER, state.vbo);
	const float vertices[] = {
		-1.0f, -1.0f, 0.0f, 0.0f,
		 1.0f, -1.0f, 1.0f, 0.0f,
		 1.0f,  1.0f, 1.0f, 1.0f,
		-1.0f,  1.0f, 0.0f, 1.0f
	};
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state.ebo);
	static const unsigned int indices[] = { 0, 1, 2, 2, 3, 0 };
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);

	// Setup texture
	glDeleteTextures(1, &state.texture);
	glGenTextures(1, &state.texture);
	glBindTexture(GL_TEXTURE_2D, state.texture);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, BUFFER_WIDTH, BUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, buffer);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glBindTexture(GL_TEXTURE_2D, 0);
}

/* [=]===^=[ render_frame ]=================================================================^===[=] */
__attribute__((always_inline))
static inline void render_frame(void) {
	glClearColor(.0f, 0.f, 0.f, 1.f);
	glClear(GL_COLOR_BUFFER_BIT);

	glUseProgram(state.shader_program);
	glBindVertexArray(state.vao);
	glBindBuffer(GL_ARRAY_BUFFER, state.vbo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state.ebo);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, state.texture);
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, BUFFER_WIDTH, BUFFER_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, display_buffer);
	glUniform2f(state.uniform_src_image_size, (float)BUFFER_WIDTH, (float)BUFFER_HEIGHT);
	glUniform2f(state.uniform_resolution, (float)state.viewport.w, (float)state.viewport.h);
	glUniform1f(state.uniform_brightness, state.brightness);
	glUniform4f(state.uniform_tone, state.tone_data[0], state.tone_data[1], state.tone_data[2], state.tone_data[3]);
	glUniform1i(state.uniform_crt_emulation, state.toggle_crt_emulation);
	glUniform1i(state.uniform_sampler_location, 0);
	glViewport(state.viewport.x, state.viewport.y, state.viewport.w, state.viewport.h);
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}