summaryrefslogtreecommitdiff
path: root/bowshock/source/client/ShaderProgram/compile_shader.cxx
blob: f736868240395a07b5097c88091760094079a1e0 (plain) (blame)
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
// Copyright 2022-2023 Gabriel Bjørnager Jensen.

#include <bow/client.hxx>

#include <cstdio>
#include <filesystem>
#include <fmt/core.h>
#include <glad/glad.h>
#include <stdexcept>
#include <string>
#include <vector>

using namespace ::std::literals::string_literals;

auto bow::ShaderProgram::compile_shader(::std::string const& name, ::bow::ShaderType const pretty_type) -> ::GLuint {
	auto const type = [pretty_type]() -> ::GLuint {
		using ::bow::ShaderType;

		switch (pretty_type) {
		case ShaderType::Fragment:
			return GL_FRAGMENT_SHADER;

		case ShaderType::Geometry:
			return GL_GEOMETRY_SHADER;

		case ShaderType::Vertex:
			return GL_VERTEX_SHADER;
		}
	}();

	auto const type_suffix = [type]() -> ::std::string {
		switch (type) {
		default:
			// Until C++23:
			::__builtin_unreachable();

		case GL_FRAGMENT_SHADER:
			return "frag"s;

		case GL_GEOMETRY_SHADER:
			return "geom"s;

		case GL_VERTEX_SHADER:
			return "vert"s;
		}
	}();

	auto const type_string = [type]() -> ::std::string {
		switch (type) {
		default:
			::__builtin_unreachable();

		case GL_FRAGMENT_SHADER:
			return "fragment"s;

		case GL_GEOMETRY_SHADER:
			return "geometry"s;

		case GL_VERTEX_SHADER:
			return "vertex"s;
		}
	}();

	using ::bow::DATA_DIRECTORY;

	auto const path = DATA_DIRECTORY + "/shaders/" + name + "." + type_suffix + "." + ::bow::SHADER_FILE_SUFFIX;

	::fmt::print(stderr, "[client] compiling {} shader at \"{}\"\n", type_string, path);

	::std::FILE* file = ::std::fopen(path.c_str(), "r");

	auto const file_size = ::std::filesystem::file_size(path);

	static_assert(sizeof (::GLchar) == sizeof (char));
	auto source = ::std::vector<::GLchar>(file_size + 0x1u);

	if (::std::fread(source.data(), sizeof (::GLchar), file_size, file) < file_size) [[unlikely]] {
		throw ::std::runtime_error("unable to read shader source");
	}

	source.push_back('\x00');

	auto const source_pointer = source.data();

	auto shader = glCreateShader(type);
	glShaderSource(shader, 0x1, const_cast<::GLchar const* const*>(&source_pointer), nullptr);

	glCompileShader(shader);

	::GLint compilation_status = 0x0;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &compilation_status);

	if (compilation_status == GL_FALSE) [[unlikely]] {
		::GLint log_length = 0x0;
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);

		auto log = new ::GLchar[static_cast<::std::size_t>(log_length)];

		glGetShaderInfoLog(shader, log_length, nullptr, log);

		::fmt::print(stderr, "[client] unable to compiler shader:\n");

		::std::fwrite(log, 0x1u, static_cast<::std::size_t>(log_length), stderr);

		delete[] log;

		throw ::std::runtime_error("unable to compile shader");
	}

	return shader;
}