-
Notifications
You must be signed in to change notification settings - Fork 0
/
shader.cpp
161 lines (126 loc) · 3.59 KB
/
shader.cpp
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include "shader.hpp"
#include <sys/stat.h>
#include <cassert>
#include <cstdio>
#include <cstring>
#define INFO_LOG_BUFFER_SIZE 512
const char *const kShaderTypeStrings[kShaderType__Count] = {"vertex",
"fragment"};
static int HasPostfix(const char *str, const char *postfix) {
std::size_t str_len = std::strlen(str);
std::size_t postfix_len = std::strlen(postfix);
if (str_len < postfix_len) {
return 0;
}
const char *str_end = str + str_len - postfix_len;
int res = std::strcmp(str_end, postfix) == 0;
return res;
}
GLenum GlShaderType(ShaderType t) {
switch (t) {
case kShaderType_Vertex: {
return GL_VERTEX_SHADER;
}
case kShaderType_Fragment: {
return GL_FRAGMENT_SHADER;
}
default: {
assert(false);
}
}
}
const char *String(ShaderType t) {
assert(t < kShaderType__Count);
return kShaderTypeStrings[t];
}
ShaderType FromFilepath(const char *path) {
int rc = HasPostfix(path, "vert.glsl");
if (rc) {
return kShaderType_Vertex;
}
rc = HasPostfix(path, "frag.glsl");
if (rc) {
return kShaderType_Fragment;
}
assert(false);
}
Status LoadFile(const char *path, std::string *content) {
assert(path);
assert(content);
std::FILE *file = std::fopen(path, "rb");
if (!file) {
std::fprintf(stderr, "Failed to open file %s.\n", path);
return kStatus_IoError;
}
struct stat stat_buf;
{
int rc = stat(path, &stat_buf);
if (rc) {
std::fprintf(stderr, "Failed to get status of file %s.\n", path);
std::fclose(file);
return kStatus_IoError;
}
}
content->resize(stat_buf.st_size);
std::size_t rc =
std::fread(content->data(), sizeof((*content)[0]), content->size(), file);
if (rc < content->size()) {
std::fprintf(stderr, "Failed to read file %s.\n", path);
std::fclose(file);
return kStatus_IoError;
}
std::fclose(file);
return kStatus_Ok;
}
Status MakeShaderObj(const std::string *src, ShaderType type, GLuint *name) {
assert(src);
assert(name);
*name = glCreateShader(GlShaderType(type));
if (*name == 0) {
std::fprintf(stderr,
"Failed to create GL shader object of type %s from file.\n",
String(type));
return kStatus_GlError;
}
const GLchar *const srcs[1] = {src->data()};
const GLint lens[1] = {(GLint)src->size()};
glShaderSource(*name, 1, srcs, lens);
glCompileShader(*name);
GLint status = GL_FALSE;
glGetShaderiv(*name, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
std::fprintf(stderr, "Failed to compile shader.\n");
GLchar info_log[INFO_LOG_BUFFER_SIZE];
glGetShaderInfoLog(*name, INFO_LOG_BUFFER_SIZE, 0, info_log);
std::fprintf(stderr, "%s", info_log);
return kStatus_GlError;
}
return kStatus_Ok;
}
Status MakeShaderProg(const std::vector<GLuint> *shader_obj_names,
GLuint *name) {
assert(shader_obj_names);
assert(name);
*name = glCreateProgram();
if (*name == 0) {
std::fprintf(stderr, "Failed to create GL program.\n");
return kStatus_GlError;
}
for (GLuint n : *shader_obj_names) {
glAttachShader(*name, n);
}
glLinkProgram(*name);
GLint status;
glGetProgramiv(*name, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
std::fprintf(stderr, "Failed to link program.\n");
GLchar info_log[INFO_LOG_BUFFER_SIZE];
glGetProgramInfoLog(*name, INFO_LOG_BUFFER_SIZE, 0, info_log);
std::fprintf(stderr, "%s", info_log);
return kStatus_GlError;
}
for (GLuint n : *shader_obj_names) {
glDeleteShader(n);
}
return kStatus_Ok;
}