summaryrefslogtreecommitdiff
path: root/base/opengl.c
blob: 641a2a0b5835ebe59c37421afce844b082e12669 (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
130
131
132
133

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

/* [=]===^=[ setup_render_target ]================================================================^===[=] */
static void setup_render_target(void) {
	glDeleteTextures(1, &state.texture);

	glGenTextures(1, &state.texture);
	glBindTexture(GL_TEXTURE_2D, state.texture);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, state.render_width, state.render_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);
}

/* [=]===^=[ 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);
		DEBUG_PRINT("%s shader compilation failed:\n%s\n", (shader_type == GL_VERTEX_SHADER) ? "Vertex" : "Fragment", info_log);
	}
	return shader;
}

/* [=]===^=[ setup_opengl ]================================================================^===[=] */
static void opengl_setup(const char *vertex_shader_src, const char *fragment_shader_src) {
	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);

	// Shader setup
	GLuint vertex_shader = compile_shader(GL_VERTEX_SHADER, vertex_shader_src);
	GLuint fragment_shader = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_src);

	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) {
		char log[512];
		glGetProgramInfoLog(state.shader_program, sizeof(log), NULL, log);
		DEBUG_PRINT("Shader Linking Failed: %s\n", log);
	}

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

	// Calculations for the shader.
	state.contrast = 1.0f;
	state.saturation = 0.3f;
	state.brightness = 1.0f;
	CrtsTone(state.tone_data, state.contrast, state.saturation, INPUT_THIN, INPUT_MASK);	// NOTE(peter): Move this into the mainloop if change of contrast/saturation is added as an interactive thing.

	// Retrieve shader uniforms
	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);
	glGenBuffers(1, &state.vbo);
	glGenBuffers(1, &state.ebo);
	glBindVertexArray(state.vao);

	// Vertex data: Position (x, y) and Texture Coordinates (u, v)
	const float vertices[] = {
		-1.0f, -1.0f, 0.0f, 0.0f,  // Bottom-left
		 1.0f, -1.0f, 1.0f, 0.0f,  // Bottom-right
		 1.0f,  1.0f, 1.0f, 1.0f,  // Top-right
		-1.0f,  1.0f, 0.0f, 1.0f   // Top-left
	};

	static const unsigned int indices[] = { 0, 1, 2, 2, 3, 0 };

	glBindBuffer(GL_ARRAY_BUFFER, state.vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state.ebo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);        // Position
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); // Texture Coord
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
}

/* [=]===^=[ 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, state.render_width, state.render_height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, display_buffer);
	glUniform2f(state.uniform_src_image_size, (float)state.render_width, (float)state.render_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);
}