File include/fg3/fg3.h changed (mode: 100644) (index 7d9c6dc..a515b1c) |
8 |
8 |
#if defined(__APPLE__) |
#if defined(__APPLE__) |
9 |
9 |
# include <TargetConditionals.h> |
# include <TargetConditionals.h> |
10 |
10 |
# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE==1 |
# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE==1 |
11 |
|
# define GLAD_GLES2_IMPLEMENTATION |
|
|
11 |
|
# ifdef FG3_IMPLEMENTATION |
|
12 |
|
# define GLAD_GLES2_IMPLEMENTATION |
|
13 |
|
# endif |
12 |
14 |
# include "glad_gles2.h" |
# include "glad_gles2.h" |
13 |
15 |
# else |
# else |
14 |
|
# define GLAD_GL_IMPLEMENTATION |
|
|
16 |
|
# ifdef FG3_IMPLEMENTATION |
|
17 |
|
# define GLAD_GL_IMPLEMENTATION |
|
18 |
|
# endif |
15 |
19 |
# include "glad_gl.h" |
# include "glad_gl.h" |
16 |
20 |
# endif |
# endif |
17 |
21 |
#elif defined(__ANDROID__) |
#elif defined(__ANDROID__) |
18 |
|
# define GLAD_GLES2_IMPLEMENTATION |
|
|
22 |
|
# ifdef FG3_IMPLEMENTATION |
|
23 |
|
# define GLAD_GLES2_IMPLEMENTATION |
|
24 |
|
# endif |
19 |
25 |
# include "glad_gles2.h" |
# include "glad_gles2.h" |
20 |
26 |
#else |
#else |
21 |
|
# define GLAD_GL_IMPLEMENTATION |
|
|
27 |
|
# ifdef FG3_IMPLEMENTATION |
|
28 |
|
# define GLAD_GL_IMPLEMENTATION |
|
29 |
|
# endif |
22 |
30 |
# include "glad_gl.h" |
# include "glad_gl.h" |
23 |
31 |
#endif |
#endif |
24 |
32 |
|
|
|
34 |
42 |
#include <string> |
#include <string> |
35 |
43 |
#include <vector> |
#include <vector> |
36 |
44 |
|
|
37 |
|
namespace fg3 |
|
38 |
|
{ |
|
39 |
|
|
|
40 |
|
bool verbose = true; |
|
41 |
|
|
|
42 |
45 |
#ifndef _VERBOUT_ |
#ifndef _VERBOUT_ |
43 |
46 |
#define _VERBOUT_ if( verbose ) std::cout |
#define _VERBOUT_ if( verbose ) std::cout |
44 |
47 |
#endif |
#endif |
|
... |
... |
bool verbose = true; |
47 |
50 |
#define _ERROUT_ std::cerr |
#define _ERROUT_ std::cerr |
48 |
51 |
#endif |
#endif |
49 |
52 |
|
|
50 |
|
#ifdef GLAD_GL |
|
51 |
|
const GLchar* shaderHeader = R"( |
|
52 |
|
#version 330 |
|
53 |
|
)"; |
|
54 |
|
#else // GLES |
|
55 |
|
const GLchar* shaderHeader = R"( |
|
56 |
|
#version 300 es |
|
57 |
|
precision highp float; |
|
58 |
|
)"; |
|
59 |
|
#endif |
|
60 |
|
|
|
61 |
|
// vec2/3 can become vec4 automatically |
|
62 |
|
// https://stackoverflow.com/questions/18935203/shader-position-vec4-or-vec3 |
|
63 |
|
|
|
64 |
|
const GLchar* unlitVert = R"( |
|
65 |
|
uniform mat4 u_matrices[6]; // 0:mvp 1:mv 2:m 3:normal 4:texture 5:light |
|
66 |
|
layout(location = 0) in vec4 a_Position; |
|
67 |
|
layout(location = 1) in vec4 a_Normal; |
|
68 |
|
layout(location = 2) in vec4 a_Tangent; |
|
69 |
|
layout(location = 3) in vec4 a_UV; |
|
70 |
|
out vec2 v_UV; |
|
71 |
|
out vec4 v_RelativePos; |
|
72 |
|
void main(){ |
|
73 |
|
v_UV = vec2( u_matrices[4] * a_UV ); |
|
74 |
|
v_RelativePos = u_matrices[1] * a_Position; |
|
75 |
|
gl_Position = u_matrices[0] * a_Position; |
|
76 |
|
} |
|
77 |
|
)"; |
|
78 |
|
|
|
79 |
|
const GLchar* unlitFrag = R"( |
|
80 |
|
uniform sampler2D u_texture; |
|
81 |
|
uniform vec4 u_fog; |
|
82 |
|
uniform vec3 u_camera; |
|
83 |
|
in vec2 v_UV; |
|
84 |
|
in vec4 v_RelativePos; |
|
85 |
|
layout(location = 0) out vec4 fragColor; |
|
86 |
|
void main(){ |
|
87 |
|
vec4 texColor = texture( u_texture, v_UV ); |
|
88 |
|
if( texColor.a < 0.001 ) discard; |
|
89 |
|
if( u_fog.a > 0.0 ){ |
|
90 |
|
float fogFactor = 1.0 - clamp( 1.0 / exp( length( v_RelativePos ) * u_fog.a ), 0.0, 1.0 ); |
|
91 |
|
fragColor = vec4( mix( texColor.rgb, u_fog.rgb, fogFactor ), texColor.a ); |
|
92 |
|
}else{ |
|
93 |
|
fragColor = texColor; |
|
94 |
|
} |
|
95 |
|
} |
|
96 |
|
)"; |
|
97 |
|
|
|
98 |
|
std::vector<std::string> unlitSamplers = { "u_texture" }; |
|
99 |
|
|
|
100 |
|
const GLchar* colorModFrag = R"( |
|
101 |
|
uniform sampler2D u_texture; |
|
102 |
|
uniform vec4 u_fog; |
|
103 |
|
uniform vec3 u_camera; |
|
104 |
|
in vec2 v_UV; |
|
105 |
|
in vec4 v_RelativePos; |
|
106 |
|
layout(location = 0) out vec4 fragColor; |
|
107 |
|
void main(){ |
|
108 |
|
vec4 texColor = texture( u_texture, v_UV ); |
|
109 |
|
if( texColor.a < 0.001 ) discard; |
|
110 |
|
fragColor = texColor * u_fog; |
|
111 |
|
} |
|
112 |
|
)"; |
|
113 |
|
|
|
114 |
|
std::vector<std::string> colorModSamplers = { "u_texture" }; |
|
115 |
|
|
|
116 |
|
// Instanced arrays are used for instancing. |
|
117 |
|
// https://learnopengl.com/Advanced-OpenGL/Instancing |
|
118 |
|
|
|
119 |
|
const GLchar* unlitInstanceVert = R"( |
|
120 |
|
uniform mat4 u_matrices[3]; // 0:view 1:projection 2:light |
|
121 |
|
layout(location = 0) in vec4 a_Position; |
|
122 |
|
layout(location = 1) in vec4 a_Normal; |
|
123 |
|
layout(location = 2) in vec4 a_Tangent; |
|
124 |
|
layout(location = 3) in vec4 a_UV; |
|
125 |
|
layout(location = 4) in vec4 a_Color; |
|
126 |
|
layout(location = 5) in mat4 a_ModelMat; |
|
127 |
|
layout(location = 9) in mat4 a_TexMat; |
|
128 |
|
out vec2 v_UV; |
|
129 |
|
out vec4 v_Color; |
|
130 |
|
out vec4 v_RelativePos; |
|
131 |
|
void main(){ |
|
132 |
|
v_UV = vec2( a_TexMat * a_UV ); |
|
133 |
|
v_Color = a_Color; |
|
134 |
|
mat4 mv = u_matrices[0] * a_ModelMat; |
|
135 |
|
v_RelativePos = mv * a_Position; |
|
136 |
|
gl_Position = u_matrices[1] * mv * a_Position; |
|
137 |
|
} |
|
138 |
|
)"; |
|
139 |
|
|
|
140 |
|
const GLchar* unlitInstanceFrag = R"( |
|
141 |
|
uniform sampler2D u_texture; |
|
142 |
|
uniform vec4 u_fog; |
|
143 |
|
in vec2 v_UV; |
|
144 |
|
in vec4 v_Color; |
|
145 |
|
in vec4 v_RelativePos; |
|
146 |
|
layout(location = 0) out vec4 fragColor; |
|
147 |
|
void main(){ |
|
148 |
|
vec4 texColor = texture( u_texture, v_UV ) * v_Color; |
|
149 |
|
if( texColor.a < 0.001 ) discard; |
|
150 |
|
if( u_fog.a > 0.0 ){ |
|
151 |
|
float fogFactor = 1.0 - clamp( 1.0 / exp( length( v_RelativePos ) * u_fog.a ), 0.0, 1.0 ); |
|
152 |
|
fragColor = vec4( mix( texColor.rgb, u_fog.rgb, fogFactor ), texColor.a ); |
|
153 |
|
}else{ |
|
154 |
|
fragColor = texColor; |
|
155 |
|
} |
|
156 |
|
} |
|
157 |
|
)"; |
|
158 |
|
|
|
159 |
|
std::vector<std::string> unlitInstanceSamplers = { "u_texture" }; |
|
160 |
|
|
|
161 |
|
const GLchar* skyboxVert = R"( |
|
162 |
|
uniform mat4 u_matrices[6]; // 0:mvp 1:mv 2:m 3:normal 4:texture 5:light |
|
163 |
|
layout(location = 0) in vec4 a_Position; |
|
164 |
|
layout(location = 1) in vec4 a_Normal; |
|
165 |
|
layout(location = 2) in vec4 a_Tangent; |
|
166 |
|
layout(location = 3) in vec4 a_UV; |
|
167 |
|
out vec3 v_STR; |
|
168 |
|
void main(){ |
|
169 |
|
v_STR = a_Position.xyz; |
|
170 |
|
vec4 pos = u_matrices[0] * a_Position; |
|
171 |
|
gl_Position = pos.xyww; |
|
172 |
|
} |
|
173 |
|
)"; |
|
174 |
|
|
|
175 |
|
const GLchar* skyboxFrag = R"( |
|
176 |
|
uniform samplerCube u_cubemap; |
|
177 |
|
uniform vec4 u_fog; |
|
178 |
|
uniform vec3 u_camera; |
|
179 |
|
in vec3 v_STR; |
|
180 |
|
layout(location = 0) out vec4 fragColor; |
|
181 |
|
void main(){ |
|
182 |
|
fragColor = texture( u_cubemap, v_STR ); |
|
183 |
|
} |
|
184 |
|
)"; |
|
185 |
|
|
|
186 |
|
std::vector<std::string> skyboxSamplers = { "u_cubemap" }; |
|
187 |
|
|
|
188 |
|
const GLchar* irradianceFrag = R"( |
|
189 |
|
uniform samplerCube u_cubemap; |
|
190 |
|
uniform vec4 u_fog; |
|
191 |
|
uniform vec3 u_camera; |
|
192 |
|
in vec3 v_STR; |
|
193 |
|
layout(location = 0) out vec4 fragColor; |
|
194 |
|
const float PI = 3.1415927; |
|
195 |
|
mat4 rotationMatrix( vec3 axis, float angle ){ |
|
196 |
|
axis = normalize( axis ); |
|
197 |
|
float s = sin( angle ); |
|
198 |
|
float c = cos( angle ); |
|
199 |
|
float oc = 1.0 - c; |
|
200 |
|
return mat4( mat3( |
|
201 |
|
oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, |
|
202 |
|
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, |
|
203 |
|
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c |
|
204 |
|
) ); |
|
205 |
|
} |
|
206 |
|
vec3 getIrradiance( vec3 normal ){ |
|
207 |
|
float grain = 0.05; |
|
208 |
|
vec3 irradiance = vec3( 0.0 ); |
|
209 |
|
vec3 up = vec3( 0.0, 1.0, 0.0 ); |
|
210 |
|
vec3 right = normalize( cross( normal, up ) ); |
|
211 |
|
float index = 0.0; |
|
212 |
|
for( float longi = 0.0; longi <= PI * 0.5; longi += grain ){ |
|
213 |
|
mat4 trl = rotationMatrix( right, longi ); |
|
214 |
|
for( float azi = 0.0; azi <= PI * 2.0; azi += grain ){ |
|
215 |
|
mat4 tra = rotationMatrix( normal, azi ); |
|
216 |
|
vec3 sampleVec = ( tra * trl * vec4( normal, 1.0 ) ).xyz; |
|
217 |
|
irradiance += texture( u_cubemap, sampleVec ).rgb * sin( longi ) * cos( longi ); |
|
218 |
|
index += 1.0; |
|
219 |
|
} |
|
220 |
|
} |
|
221 |
|
float hemispherePDF = 1.0 / ( 2.0 * PI ); |
|
222 |
|
irradiance /= index * hemispherePDF; |
|
223 |
|
return irradiance; |
|
224 |
|
} |
|
225 |
|
void main(){ |
|
226 |
|
vec3 N = normalize( v_STR ); |
|
227 |
|
fragColor = vec4( getIrradiance( N ) / PI, 1.0 ); |
|
228 |
|
} |
|
229 |
|
)"; |
|
230 |
|
|
|
231 |
|
std::vector<std::string> irradianceSamplers = { "u_cubemap" }; |
|
|
53 |
|
namespace fg3 |
|
54 |
|
{ |
232 |
55 |
|
|
233 |
56 |
struct Display { |
struct Display { |
234 |
57 |
bool success; |
bool success; |
|
... |
... |
struct Display { |
237 |
60 |
std::string title; |
std::string title; |
238 |
61 |
}; |
}; |
239 |
62 |
|
|
240 |
|
Display newDisplay = { false, 0, 0, "" }; |
|
|
63 |
|
static const Display newDisplay = { false, 0, 0, "" }; |
241 |
64 |
|
|
242 |
65 |
struct Color { |
struct Color { |
243 |
66 |
GLfloat r; |
GLfloat r; |
|
... |
... |
struct Color { |
246 |
69 |
GLfloat a; |
GLfloat a; |
247 |
70 |
}; |
}; |
248 |
71 |
|
|
249 |
|
Color newColor = { 1.0f, 1.0f, 1.0f, 1.0f }; |
|
250 |
|
|
|
251 |
|
Color fogColor = { 0.0f, 0.0f, 0.0f, 0.0f }; |
|
|
72 |
|
static const Color newColor = { 1.0f, 1.0f, 1.0f, 1.0f }; |
252 |
73 |
|
|
253 |
74 |
struct Texture { |
struct Texture { |
254 |
75 |
bool success; |
bool success; |
|
... |
... |
struct Texture { |
260 |
81 |
GLenum type; |
GLenum type; |
261 |
82 |
}; |
}; |
262 |
83 |
|
|
263 |
|
Texture newTexture = { false, 0, 0, 0, 0, false, 0 }; |
|
264 |
|
|
|
265 |
|
Texture blankTexture = { false, 0, 0, 0, 0, false, 0 }; |
|
|
84 |
|
static const Texture newTexture = { false, 0, 0, 0, 0, false, 0 }; |
266 |
85 |
|
|
267 |
86 |
struct Framebuffer { |
struct Framebuffer { |
268 |
87 |
bool success; |
bool success; |
|
... |
... |
struct Framebuffer { |
277 |
96 |
GLsizei multisample; |
GLsizei multisample; |
278 |
97 |
}; |
}; |
279 |
98 |
|
|
280 |
|
Framebuffer newFramebuffer = { false, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
|
|
99 |
|
static const Framebuffer newFramebuffer = { false, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
281 |
100 |
|
|
282 |
101 |
struct Vertex { |
struct Vertex { |
283 |
102 |
GLfloat Position[3]; |
GLfloat Position[3]; |
|
... |
... |
struct Vertex { |
286 |
105 |
GLfloat UV[2]; |
GLfloat UV[2]; |
287 |
106 |
}; |
}; |
288 |
107 |
|
|
289 |
|
Vertex newVertex = { |
|
|
108 |
|
static const Vertex newVertex = { |
290 |
109 |
{ 0.0f, 0.0f, 0.0f }, |
{ 0.0f, 0.0f, 0.0f }, |
291 |
110 |
{ 0.0f, 0.0f, 0.0f }, |
{ 0.0f, 0.0f, 0.0f }, |
292 |
111 |
{ 0.0f, 0.0f, 0.0f }, |
{ 0.0f, 0.0f, 0.0f }, |
|
... |
... |
struct Pipeline { |
311 |
130 |
std::vector<GLuint> slots; |
std::vector<GLuint> slots; |
312 |
131 |
}; |
}; |
313 |
132 |
|
|
314 |
|
Pipeline |
|
315 |
|
newPipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }, |
|
316 |
|
drawPipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }, |
|
317 |
|
unlitPipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }, |
|
318 |
|
colorModPipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }, |
|
319 |
|
unlitInstancePipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }, |
|
320 |
|
skyboxPipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }, |
|
321 |
|
irradiancePipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }; |
|
|
133 |
|
static const Pipeline newPipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }; |
322 |
134 |
|
|
323 |
135 |
struct Mesh { |
struct Mesh { |
324 |
136 |
bool success; |
bool success; |
|
... |
... |
struct Mesh { |
333 |
145 |
GLfloat zmax; |
GLfloat zmax; |
334 |
146 |
}; |
}; |
335 |
147 |
|
|
336 |
|
Mesh newMesh = { false, {}, {}, { 0, 0, 0 }, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; |
|
337 |
|
|
|
338 |
|
Mesh planeMesh = { false, {}, {}, { 0, 0, 0 }, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; |
|
339 |
|
|
|
340 |
|
Mesh cubeMesh = { false, {}, {}, { 0, 0, 0 }, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; |
|
|
148 |
|
static const Mesh newMesh = { false, {}, {}, { 0, 0, 0 }, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; |
|
149 |
|
|
|
150 |
|
// Define stb_truetype types without the header to make cross-TU cleanup work. |
|
151 |
|
#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ |
|
152 |
|
struct stbtt_pack_context { |
|
153 |
|
void *user_allocator_context; |
|
154 |
|
void *pack_info; |
|
155 |
|
int width; |
|
156 |
|
int height; |
|
157 |
|
int stride_in_bytes; |
|
158 |
|
int padding; |
|
159 |
|
int skip_missing; |
|
160 |
|
unsigned int h_oversample, v_oversample; |
|
161 |
|
unsigned char *pixels; |
|
162 |
|
void *nodes; |
|
163 |
|
}; |
|
164 |
|
// private structure |
|
165 |
|
typedef struct |
|
166 |
|
{ |
|
167 |
|
unsigned char *data; |
|
168 |
|
int cursor; |
|
169 |
|
int size; |
|
170 |
|
} stbtt__buf; |
|
171 |
|
struct stbtt_fontinfo |
|
172 |
|
{ |
|
173 |
|
void * userdata; |
|
174 |
|
unsigned char * data; // pointer to .ttf file |
|
175 |
|
int fontstart; // offset of start of font |
|
176 |
|
|
|
177 |
|
int numGlyphs; // number of glyphs, needed for range checking |
|
178 |
|
|
|
179 |
|
int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf |
|
180 |
|
int index_map; // a cmap mapping for our chosen character encoding |
|
181 |
|
int indexToLocFormat; // format needed to map from glyph index to glyph |
|
182 |
|
|
|
183 |
|
stbtt__buf cff; // cff font data |
|
184 |
|
stbtt__buf charstrings; // the charstring index |
|
185 |
|
stbtt__buf gsubrs; // global charstring subroutines index |
|
186 |
|
stbtt__buf subrs; // private charstring subroutines index |
|
187 |
|
stbtt__buf fontdicts; // array of font dicts |
|
188 |
|
stbtt__buf fdselect; // map from glyph to fontdict |
|
189 |
|
}; |
|
190 |
|
typedef struct |
|
191 |
|
{ |
|
192 |
|
unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap |
|
193 |
|
float xoff,yoff,xadvance; |
|
194 |
|
float xoff2,yoff2; |
|
195 |
|
} stbtt_packedchar; |
|
196 |
|
#endif |
341 |
197 |
|
|
342 |
198 |
struct Font { |
struct Font { |
343 |
199 |
Texture texture; |
Texture texture; |
|
... |
... |
struct Font { |
349 |
205 |
std::vector<unsigned char> buffer; |
std::vector<unsigned char> buffer; |
350 |
206 |
std::vector<unsigned char> atlas; |
std::vector<unsigned char> atlas; |
351 |
207 |
bool needSync; |
bool needSync; |
352 |
|
#ifdef __STB_INCLUDE_STB_TRUETYPE_H__ |
|
353 |
208 |
stbtt_pack_context pc; |
stbtt_pack_context pc; |
354 |
209 |
stbtt_fontinfo info; |
stbtt_fontinfo info; |
355 |
210 |
std::vector<stbtt_packedchar> packedChars; |
std::vector<stbtt_packedchar> packedChars; |
356 |
|
#else |
|
357 |
|
void* pc; |
|
358 |
|
void* info; |
|
359 |
|
std::vector<void*> packedChars; |
|
360 |
|
#endif |
|
361 |
211 |
}; |
}; |
362 |
212 |
|
|
363 |
|
Font newFont = { newTexture, newMesh, 0.0f, 0.0f, {}, {}, {}, {}, false, {}, {}, {} }; |
|
|
213 |
|
static const Font newFont = { newTexture, newMesh, 0.0f, 0.0f, {}, {}, {}, {}, false, {}, {}, {} }; |
364 |
214 |
|
|
365 |
|
// Globals. |
|
366 |
|
linalg::mat<double,4,4> texMatrix = linalg::identity, lightMatrix = linalg::identity; |
|
|
215 |
|
// Functions. |
|
216 |
|
|
|
217 |
|
std::u32string utf8ToUtf32( std::string in ); |
|
218 |
|
linalg::vec<double,4> eulerToQuat( double aX, double aY, double aZ ); |
|
219 |
|
linalg::vec<double,4> directionToQuat( linalg::vec<double,3> forward, linalg::vec<double,3> up ); |
|
220 |
|
double wrapAngle( double a ); |
|
221 |
|
Color rgb( float r, float g, float b ); |
|
222 |
|
void cls( Color col, bool clearDepth = true ); |
|
223 |
|
Mesh loadMesh( std::vector<Vertex> &vertices, std::vector<Index> &indices, bool streaming = false ); |
|
224 |
|
void updateMesh( Mesh &mesh, std::vector<Vertex> &vertices, std::vector<Index> &indices, bool streaming = false ); |
|
225 |
|
void uploadModelTransforms( const linalg::mat<double,4,4> &modelMat, const linalg::mat<double,4,4> &viewMat, const linalg::mat<double,4,4> &projMat ); |
|
226 |
|
void drawMesh( Mesh &mesh, linalg::mat<double,4,4> modelMat, linalg::mat<double,4,4> viewMat, linalg::mat<double,4,4> projMat ); |
|
227 |
|
void normalizeVertices( std::vector<Vertex> &verts ); |
|
228 |
|
Mesh loadOBJ( std::string filepath ); |
|
229 |
|
Mesh loadPLY( std::string filepath ); |
|
230 |
|
void freeMesh( Mesh &mesh ); |
|
231 |
|
Mesh getPlaneMesh(); |
|
232 |
|
Mesh getCubeMesh(); |
|
233 |
|
Texture loadTexture( const GLvoid* data, GLsizei width, GLsizei height, unsigned int channels, bool mipmap = true, bool filter = true ); |
|
234 |
|
Texture loadCubemap( std::vector<GLvoid*> faces, GLsizei width, GLsizei height, unsigned int channels, bool mipmap = true, bool filter = true ); |
|
235 |
|
void freeTexture( Texture &tex ); |
|
236 |
|
void updateTexture( Texture &tex, const GLvoid* data ); |
|
237 |
|
void updateCubemap( Texture &tex, std::vector<GLvoid*> faces ); |
|
238 |
|
void updateCubemapFace( Texture &tex, const GLvoid* data, unsigned int face ); |
|
239 |
|
void setTexture( Texture tex, GLuint texSlot ); |
|
240 |
|
Texture getBlankTexture(); |
|
241 |
|
void setFog( Color col ); |
|
242 |
|
Color getFog(); |
|
243 |
|
void setMetallicFactor( GLfloat f ); |
|
244 |
|
void setRoughnessFactor( GLfloat f ); |
|
245 |
|
void setBaseColorFactor( Color col ); |
|
246 |
|
void setEmissiveFactor( GLfloat r, GLfloat g, GLfloat b ); |
|
247 |
|
void setPipeline( Pipeline pipeline ); |
|
248 |
|
Pipeline getPipeline(); |
|
249 |
|
Pipeline getUnlitPipeline(); |
|
250 |
|
Pipeline getColorModPipeline(); |
|
251 |
|
Pipeline getUnlitInstancePipeline(); |
|
252 |
|
Pipeline getSkyboxPipeline(); |
|
253 |
|
Pipeline getIrradiancePipeline(); |
|
254 |
|
void setTextureMatrix( linalg::mat<double,4,4> texMat ); |
|
255 |
|
linalg::mat<double,4,4> getTextureMatrix(); |
|
256 |
|
void setLightMatrix( linalg::mat<double,4,4> lightMat ); |
|
257 |
|
linalg::mat<double,4,4> getLightMatrix(); |
|
258 |
|
Framebuffer createFramebuffer( GLsizei width, GLsizei height, bool cubemap = false, GLenum internalFmt = GL_RGB, GLsizei multisample = 0 ); |
|
259 |
|
void resizeFramebuffer( Framebuffer &fb, GLsizei width, GLsizei height, GLsizei multisample = 0 ); |
|
260 |
|
Texture getFramebufferTexture( Framebuffer &fb ); |
|
261 |
|
void setFramebuffer( Framebuffer fb = newFramebuffer ); |
|
262 |
|
void drawFramebuffer( Framebuffer &fb, bool draw_z = false ); |
|
263 |
|
Framebuffer getIrradianceFramebuffer( Texture in_cubemap, Framebuffer fb = newFramebuffer ); |
|
264 |
|
void drawSkybox( Texture &tex, linalg::mat<double,4,4> view, linalg::mat<double,4,4> proj, Color tint = newColor ); |
|
265 |
|
int compileShader( GLuint shader ); |
|
266 |
|
int linkProgram( GLuint programObject ); |
|
267 |
|
Pipeline loadPipeline( const GLchar* vertSrc, const GLchar* fragSrc, std::vector<std::string> samplers = {} ); |
|
268 |
|
Display createDisplay( unsigned int width, unsigned int height, std::string title, int multisamples = 4, bool HiDPI = true, bool vsync = true ); |
|
269 |
|
void focusDisplay(); |
|
270 |
|
int getMouseX(); |
|
271 |
|
int getMouseY(); |
|
272 |
|
Display getDisplay(); |
|
273 |
|
unsigned int getDisplayWidth(); |
|
274 |
|
unsigned int getDisplayHeight(); |
|
275 |
|
double deltaTime(); |
|
276 |
|
void syncEvents(); |
|
277 |
|
void sync(); |
|
278 |
|
void setTextInput( int x = 0, int y = 0, int w = 0, int h = 0 ); |
|
279 |
|
int upKey(); |
|
280 |
|
int downKey(); |
|
281 |
|
int leftKey(); |
|
282 |
|
int rightKey(); |
|
283 |
|
int shiftKey(); |
|
284 |
|
int commandKey(); |
|
285 |
|
int controlKey(); |
|
286 |
|
int enterKey(); |
|
287 |
|
int escapeKey(); |
|
288 |
|
int spaceKey(); |
|
289 |
|
int tabKey(); |
|
290 |
|
int charKey( char key ); |
|
291 |
|
int upPad(); |
|
292 |
|
int downPad(); |
|
293 |
|
int leftPad(); |
|
294 |
|
int rightPad(); |
|
295 |
|
int selectButton(); |
|
296 |
|
int startButton(); |
|
297 |
|
int aButton(); |
|
298 |
|
int bButton(); |
|
299 |
|
int xButton(); |
|
300 |
|
int yButton(); |
|
301 |
|
int left1(); |
|
302 |
|
int right1(); |
|
303 |
|
float left2(); |
|
304 |
|
float right2(); |
|
305 |
|
int leftStick(); |
|
306 |
|
int rightStick(); |
|
307 |
|
float leftStickX(); |
|
308 |
|
float leftStickY(); |
|
309 |
|
float rightStickX(); |
|
310 |
|
float rightStickY(); |
|
311 |
|
int mouseButton( int button ); |
|
312 |
|
void showMouse( bool show ); |
|
313 |
|
void trapMouse( bool trap ); |
|
314 |
|
void hapticRumble( float strength, unsigned int length ); |
|
315 |
|
void end(); |
|
316 |
|
void packFontRange( Font &font, int cpStart, int cpEnd ); |
|
317 |
|
int getCharacterIndex( int cp, Font &font ); |
|
318 |
|
Font loadFont( std::string fileName, float fontSize, int oversampleX, int oversampleY, |
|
319 |
|
bool prepack = true, int atlasWidth = 512, int atlasHeight = 512 ); |
|
320 |
|
float getTextWidthUtf32( std::u32string codepoints, Font &font ); |
|
321 |
|
float getTextWidth( std::string text, Font &font ); |
|
322 |
|
void drawTextUtf32( std::u32string codepoints, Font &font, float posX, float posY, float scale, int align = 0, float wordWrap = 0.0f ); |
|
323 |
|
void drawText( std::string text, Font &font, float posX, float posY, float scale, int align = 0, float wordWrap = 0.0f ); |
367 |
324 |
|
|
368 |
325 |
// Instancing. |
// Instancing. |
369 |
326 |
struct InstanceAttributes { |
struct InstanceAttributes { |
|
... |
... |
struct InstanceAttributes { |
372 |
329 |
GLfloat texMat[16]; |
GLfloat texMat[16]; |
373 |
330 |
}; |
}; |
374 |
331 |
|
|
375 |
|
// Used by testDraw. |
|
376 |
|
void setPipeline( Pipeline pipeline ); |
|
377 |
|
void setTexture( Texture tex, GLuint texSlot ); |
|
378 |
|
|
|
379 |
332 |
class InstanceBuffer { |
class InstanceBuffer { |
380 |
333 |
public: |
public: |
381 |
334 |
GLuint vbo = 0; |
GLuint vbo = 0; |
382 |
335 |
std::vector<InstanceAttributes> attributes; |
std::vector<InstanceAttributes> attributes; |
383 |
336 |
|
|
384 |
|
void push( const Color &color, linalg::mat<double,4,4> modelMat ){ |
|
|
337 |
|
void push( const Color &color, linalg::mat<double,4,4> modelMat, linalg::mat<double,4,4> texMat ){ |
385 |
338 |
attributes.push_back( { |
attributes.push_back( { |
386 |
339 |
color, { |
color, { |
387 |
340 |
(GLfloat)modelMat[0][0], (GLfloat)modelMat[0][1], (GLfloat)modelMat[0][2], (GLfloat)modelMat[0][3], |
(GLfloat)modelMat[0][0], (GLfloat)modelMat[0][1], (GLfloat)modelMat[0][2], (GLfloat)modelMat[0][3], |
388 |
341 |
(GLfloat)modelMat[1][0], (GLfloat)modelMat[1][1], (GLfloat)modelMat[1][2], (GLfloat)modelMat[1][3], |
(GLfloat)modelMat[1][0], (GLfloat)modelMat[1][1], (GLfloat)modelMat[1][2], (GLfloat)modelMat[1][3], |
389 |
342 |
(GLfloat)modelMat[2][0], (GLfloat)modelMat[2][1], (GLfloat)modelMat[2][2], (GLfloat)modelMat[2][3], |
(GLfloat)modelMat[2][0], (GLfloat)modelMat[2][1], (GLfloat)modelMat[2][2], (GLfloat)modelMat[2][3], |
390 |
343 |
(GLfloat)modelMat[3][0], (GLfloat)modelMat[3][1], (GLfloat)modelMat[3][2], (GLfloat)modelMat[3][3] }, { |
(GLfloat)modelMat[3][0], (GLfloat)modelMat[3][1], (GLfloat)modelMat[3][2], (GLfloat)modelMat[3][3] }, { |
391 |
|
(GLfloat)texMatrix[0][0], (GLfloat)texMatrix[0][1], (GLfloat)texMatrix[0][2], (GLfloat)texMatrix[0][3], |
|
392 |
|
(GLfloat)texMatrix[1][0], (GLfloat)texMatrix[1][1], (GLfloat)texMatrix[1][2], (GLfloat)texMatrix[1][3], |
|
393 |
|
(GLfloat)texMatrix[2][0], (GLfloat)texMatrix[2][1], (GLfloat)texMatrix[2][2], (GLfloat)texMatrix[2][3], |
|
394 |
|
(GLfloat)texMatrix[3][0], (GLfloat)texMatrix[3][1], (GLfloat)texMatrix[3][2], (GLfloat)texMatrix[3][3] } |
|
|
344 |
|
(GLfloat)texMat[0][0], (GLfloat)texMat[0][1], (GLfloat)texMat[0][2], (GLfloat)texMat[0][3], |
|
345 |
|
(GLfloat)texMat[1][0], (GLfloat)texMat[1][1], (GLfloat)texMat[1][2], (GLfloat)texMat[1][3], |
|
346 |
|
(GLfloat)texMat[2][0], (GLfloat)texMat[2][1], (GLfloat)texMat[2][2], (GLfloat)texMat[2][3], |
|
347 |
|
(GLfloat)texMat[3][0], (GLfloat)texMat[3][1], (GLfloat)texMat[3][2], (GLfloat)texMat[3][3] } |
395 |
348 |
} ); |
} ); |
396 |
349 |
} |
} |
397 |
350 |
|
|
|
... |
... |
class InstanceBuffer { |
402 |
355 |
glBufferData( GL_ARRAY_BUFFER, attributes.size() * sizeof(InstanceAttributes), attributes.data(), GL_STREAM_DRAW ); |
glBufferData( GL_ARRAY_BUFFER, attributes.size() * sizeof(InstanceAttributes), attributes.data(), GL_STREAM_DRAW ); |
403 |
356 |
} |
} |
404 |
357 |
|
|
405 |
|
void draw( Mesh &mesh, linalg::mat<double,4,4> viewMat, linalg::mat<double,4,4> projMat ){ |
|
|
358 |
|
void draw( Mesh &mesh, linalg::mat<double,4,4> viewMat, linalg::mat<double,4,4> projMat, linalg::mat<double,4,4> lightMat ){ |
406 |
359 |
if( attributes.empty() || !mesh.success || !vbo ) return; |
if( attributes.empty() || !mesh.success || !vbo ) return; |
407 |
360 |
|
|
408 |
361 |
// Bind the VBO. |
// Bind the VBO. |
|
... |
... |
class InstanceBuffer { |
421 |
374 |
(GLfloat)projMat[1][0], (GLfloat)projMat[1][1], (GLfloat)projMat[1][2], (GLfloat)projMat[1][3], |
(GLfloat)projMat[1][0], (GLfloat)projMat[1][1], (GLfloat)projMat[1][2], (GLfloat)projMat[1][3], |
422 |
375 |
(GLfloat)projMat[2][0], (GLfloat)projMat[2][1], (GLfloat)projMat[2][2], (GLfloat)projMat[2][3], |
(GLfloat)projMat[2][0], (GLfloat)projMat[2][1], (GLfloat)projMat[2][2], (GLfloat)projMat[2][3], |
423 |
376 |
(GLfloat)projMat[3][0], (GLfloat)projMat[3][1], (GLfloat)projMat[3][2], (GLfloat)projMat[3][3], |
(GLfloat)projMat[3][0], (GLfloat)projMat[3][1], (GLfloat)projMat[3][2], (GLfloat)projMat[3][3], |
424 |
|
(GLfloat)lightMatrix[0][0], (GLfloat)lightMatrix[0][1], (GLfloat)lightMatrix[0][2], (GLfloat)lightMatrix[0][3], |
|
425 |
|
(GLfloat)lightMatrix[1][0], (GLfloat)lightMatrix[1][1], (GLfloat)lightMatrix[1][2], (GLfloat)lightMatrix[1][3], |
|
426 |
|
(GLfloat)lightMatrix[2][0], (GLfloat)lightMatrix[2][1], (GLfloat)lightMatrix[2][2], (GLfloat)lightMatrix[2][3], |
|
427 |
|
(GLfloat)lightMatrix[3][0], (GLfloat)lightMatrix[3][1], (GLfloat)lightMatrix[3][2], (GLfloat)lightMatrix[3][3], |
|
|
377 |
|
(GLfloat)lightMat[0][0], (GLfloat)lightMat[0][1], (GLfloat)lightMat[0][2], (GLfloat)lightMat[0][3], |
|
378 |
|
(GLfloat)lightMat[1][0], (GLfloat)lightMat[1][1], (GLfloat)lightMat[1][2], (GLfloat)lightMat[1][3], |
|
379 |
|
(GLfloat)lightMat[2][0], (GLfloat)lightMat[2][1], (GLfloat)lightMat[2][2], (GLfloat)lightMat[2][3], |
|
380 |
|
(GLfloat)lightMat[3][0], (GLfloat)lightMat[3][1], (GLfloat)lightMat[3][2], (GLfloat)lightMat[3][3] |
428 |
381 |
}; |
}; |
429 |
382 |
|
|
430 |
|
glUniformMatrix4fv( drawPipeline.u_matrices, 3, GL_FALSE, glmats ); |
|
|
383 |
|
glUniformMatrix4fv( getPipeline().u_matrices, 3, GL_FALSE, glmats ); |
431 |
384 |
|
|
432 |
385 |
// Switch graphics memory to the VAO. |
// Switch graphics memory to the VAO. |
433 |
386 |
glBindVertexArray( mesh.vao[0] ); |
glBindVertexArray( mesh.vao[0] ); |
|
... |
... |
class InstanceBuffer { |
468 |
421 |
for( int z = -5; z < 5; z++ ){ |
for( int z = -5; z < 5; z++ ){ |
469 |
422 |
push( |
push( |
470 |
423 |
(Color){ ( x + 6 ) * 0.09f, ( y + 6 ) * 0.09f, 0.0f, 1.0f }, |
(Color){ ( x + 6 ) * 0.09f, ( y + 6 ) * 0.09f, 0.0f, 1.0f }, |
471 |
|
linalg::translation_matrix( linalg::vec<double,3>( x * 3.0, y * 3.0, z * 3.0 ) ) |
|
|
424 |
|
linalg::translation_matrix( linalg::vec<double,3>( x * 3.0, y * 3.0, z * 3.0 ) ), |
|
425 |
|
linalg::identity |
472 |
426 |
); |
); |
473 |
427 |
} |
} |
474 |
428 |
} |
} |
|
... |
... |
class InstanceBuffer { |
476 |
430 |
// Upload attributes. |
// Upload attributes. |
477 |
431 |
upload(); |
upload(); |
478 |
432 |
// Draw the instance buffer. |
// Draw the instance buffer. |
479 |
|
auto old_pipeline = drawPipeline; |
|
480 |
|
setPipeline( unlitInstancePipeline ); |
|
481 |
|
setTexture( blankTexture, 0 ); |
|
482 |
|
draw( cubeMesh, viewMat, projMat ); |
|
|
433 |
|
auto old_pipeline = getPipeline(); |
|
434 |
|
setPipeline( getUnlitInstancePipeline() ); |
|
435 |
|
setTexture( getBlankTexture(), 0 ); |
|
436 |
|
Mesh cube = getCubeMesh(); |
|
437 |
|
draw( cube, viewMat, projMat, linalg::identity ); |
483 |
438 |
clear(); |
clear(); |
484 |
439 |
setPipeline( old_pipeline ); |
setPipeline( old_pipeline ); |
485 |
440 |
} |
} |
|
... |
... |
class InstanceBuffer { |
489 |
444 |
} |
} |
490 |
445 |
}; |
}; |
491 |
446 |
|
|
|
447 |
|
// Implementation begins here. |
|
448 |
|
|
|
449 |
|
#ifdef FG3_IMPLEMENTATION |
|
450 |
|
|
|
451 |
|
// TODO: Don't use a global verbose flag. |
|
452 |
|
bool verbose = false; |
|
453 |
|
|
|
454 |
|
// Globals. |
|
455 |
|
|
|
456 |
|
#ifdef GLAD_GL |
|
457 |
|
static const GLchar* shaderHeader = R"( |
|
458 |
|
#version 330 |
|
459 |
|
)"; |
|
460 |
|
#else // GLES |
|
461 |
|
static const GLchar* shaderHeader = R"( |
|
462 |
|
#version 300 es |
|
463 |
|
precision highp float; |
|
464 |
|
)"; |
|
465 |
|
#endif |
|
466 |
|
|
|
467 |
|
// vec2/3 can become vec4 automatically |
|
468 |
|
// https://stackoverflow.com/questions/18935203/shader-position-vec4-or-vec3 |
|
469 |
|
|
|
470 |
|
static const GLchar* unlitVert = R"( |
|
471 |
|
uniform mat4 u_matrices[6]; // 0:mvp 1:mv 2:m 3:normal 4:texture 5:light |
|
472 |
|
layout(location = 0) in vec4 a_Position; |
|
473 |
|
layout(location = 1) in vec4 a_Normal; |
|
474 |
|
layout(location = 2) in vec4 a_Tangent; |
|
475 |
|
layout(location = 3) in vec4 a_UV; |
|
476 |
|
out vec2 v_UV; |
|
477 |
|
out vec4 v_RelativePos; |
|
478 |
|
void main(){ |
|
479 |
|
v_UV = vec2( u_matrices[4] * a_UV ); |
|
480 |
|
v_RelativePos = u_matrices[1] * a_Position; |
|
481 |
|
gl_Position = u_matrices[0] * a_Position; |
|
482 |
|
} |
|
483 |
|
)"; |
|
484 |
|
|
|
485 |
|
static const GLchar* unlitFrag = R"( |
|
486 |
|
uniform sampler2D u_texture; |
|
487 |
|
uniform vec4 u_fog; |
|
488 |
|
uniform vec3 u_camera; |
|
489 |
|
in vec2 v_UV; |
|
490 |
|
in vec4 v_RelativePos; |
|
491 |
|
layout(location = 0) out vec4 fragColor; |
|
492 |
|
void main(){ |
|
493 |
|
vec4 texColor = texture( u_texture, v_UV ); |
|
494 |
|
if( texColor.a < 0.001 ) discard; |
|
495 |
|
if( u_fog.a > 0.0 ){ |
|
496 |
|
float fogFactor = 1.0 - clamp( 1.0 / exp( length( v_RelativePos ) * u_fog.a ), 0.0, 1.0 ); |
|
497 |
|
fragColor = vec4( mix( texColor.rgb, u_fog.rgb, fogFactor ), texColor.a ); |
|
498 |
|
}else{ |
|
499 |
|
fragColor = texColor; |
|
500 |
|
} |
|
501 |
|
} |
|
502 |
|
)"; |
|
503 |
|
|
|
504 |
|
static const std::vector<std::string> unlitSamplers = { "u_texture" }; |
|
505 |
|
|
|
506 |
|
static const GLchar* colorModFrag = R"( |
|
507 |
|
uniform sampler2D u_texture; |
|
508 |
|
uniform vec4 u_fog; |
|
509 |
|
uniform vec3 u_camera; |
|
510 |
|
in vec2 v_UV; |
|
511 |
|
in vec4 v_RelativePos; |
|
512 |
|
layout(location = 0) out vec4 fragColor; |
|
513 |
|
void main(){ |
|
514 |
|
vec4 texColor = texture( u_texture, v_UV ); |
|
515 |
|
if( texColor.a < 0.001 ) discard; |
|
516 |
|
fragColor = texColor * u_fog; |
|
517 |
|
} |
|
518 |
|
)"; |
|
519 |
|
|
|
520 |
|
static const std::vector<std::string> colorModSamplers = { "u_texture" }; |
|
521 |
|
|
|
522 |
|
// Instanced arrays are used for instancing. |
|
523 |
|
// https://learnopengl.com/Advanced-OpenGL/Instancing |
|
524 |
|
|
|
525 |
|
static const GLchar* unlitInstanceVert = R"( |
|
526 |
|
uniform mat4 u_matrices[3]; // 0:view 1:projection 2:light |
|
527 |
|
layout(location = 0) in vec4 a_Position; |
|
528 |
|
layout(location = 1) in vec4 a_Normal; |
|
529 |
|
layout(location = 2) in vec4 a_Tangent; |
|
530 |
|
layout(location = 3) in vec4 a_UV; |
|
531 |
|
layout(location = 4) in vec4 a_Color; |
|
532 |
|
layout(location = 5) in mat4 a_ModelMat; |
|
533 |
|
layout(location = 9) in mat4 a_TexMat; |
|
534 |
|
out vec2 v_UV; |
|
535 |
|
out vec4 v_Color; |
|
536 |
|
out vec4 v_RelativePos; |
|
537 |
|
void main(){ |
|
538 |
|
v_UV = vec2( a_TexMat * a_UV ); |
|
539 |
|
v_Color = a_Color; |
|
540 |
|
mat4 mv = u_matrices[0] * a_ModelMat; |
|
541 |
|
v_RelativePos = mv * a_Position; |
|
542 |
|
gl_Position = u_matrices[1] * mv * a_Position; |
|
543 |
|
} |
|
544 |
|
)"; |
|
545 |
|
|
|
546 |
|
static const GLchar* unlitInstanceFrag = R"( |
|
547 |
|
uniform sampler2D u_texture; |
|
548 |
|
uniform vec4 u_fog; |
|
549 |
|
in vec2 v_UV; |
|
550 |
|
in vec4 v_Color; |
|
551 |
|
in vec4 v_RelativePos; |
|
552 |
|
layout(location = 0) out vec4 fragColor; |
|
553 |
|
void main(){ |
|
554 |
|
vec4 texColor = texture( u_texture, v_UV ) * v_Color; |
|
555 |
|
if( texColor.a < 0.001 ) discard; |
|
556 |
|
if( u_fog.a > 0.0 ){ |
|
557 |
|
float fogFactor = 1.0 - clamp( 1.0 / exp( length( v_RelativePos ) * u_fog.a ), 0.0, 1.0 ); |
|
558 |
|
fragColor = vec4( mix( texColor.rgb, u_fog.rgb, fogFactor ), texColor.a ); |
|
559 |
|
}else{ |
|
560 |
|
fragColor = texColor; |
|
561 |
|
} |
|
562 |
|
} |
|
563 |
|
)"; |
|
564 |
|
|
|
565 |
|
static const std::vector<std::string> unlitInstanceSamplers = { "u_texture" }; |
|
566 |
|
|
|
567 |
|
static const GLchar* skyboxVert = R"( |
|
568 |
|
uniform mat4 u_matrices[6]; // 0:mvp 1:mv 2:m 3:normal 4:texture 5:light |
|
569 |
|
layout(location = 0) in vec4 a_Position; |
|
570 |
|
layout(location = 1) in vec4 a_Normal; |
|
571 |
|
layout(location = 2) in vec4 a_Tangent; |
|
572 |
|
layout(location = 3) in vec4 a_UV; |
|
573 |
|
out vec3 v_STR; |
|
574 |
|
void main(){ |
|
575 |
|
v_STR = a_Position.xyz; |
|
576 |
|
vec4 pos = u_matrices[0] * a_Position; |
|
577 |
|
gl_Position = pos.xyww; |
|
578 |
|
} |
|
579 |
|
)"; |
|
580 |
|
|
|
581 |
|
static const GLchar* skyboxFrag = R"( |
|
582 |
|
uniform samplerCube u_cubemap; |
|
583 |
|
uniform vec4 u_fog; |
|
584 |
|
uniform vec3 u_camera; |
|
585 |
|
in vec3 v_STR; |
|
586 |
|
layout(location = 0) out vec4 fragColor; |
|
587 |
|
void main(){ |
|
588 |
|
fragColor = texture( u_cubemap, v_STR ); |
|
589 |
|
} |
|
590 |
|
)"; |
|
591 |
|
|
|
592 |
|
static const std::vector<std::string> skyboxSamplers = { "u_cubemap" }; |
|
593 |
|
|
|
594 |
|
static const GLchar* irradianceFrag = R"( |
|
595 |
|
uniform samplerCube u_cubemap; |
|
596 |
|
uniform vec4 u_fog; |
|
597 |
|
uniform vec3 u_camera; |
|
598 |
|
in vec3 v_STR; |
|
599 |
|
layout(location = 0) out vec4 fragColor; |
|
600 |
|
const float PI = 3.1415927; |
|
601 |
|
mat4 rotationMatrix( vec3 axis, float angle ){ |
|
602 |
|
axis = normalize( axis ); |
|
603 |
|
float s = sin( angle ); |
|
604 |
|
float c = cos( angle ); |
|
605 |
|
float oc = 1.0 - c; |
|
606 |
|
return mat4( mat3( |
|
607 |
|
oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, |
|
608 |
|
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, |
|
609 |
|
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c |
|
610 |
|
) ); |
|
611 |
|
} |
|
612 |
|
vec3 getIrradiance( vec3 normal ){ |
|
613 |
|
float grain = 0.05; |
|
614 |
|
vec3 irradiance = vec3( 0.0 ); |
|
615 |
|
vec3 up = vec3( 0.0, 1.0, 0.0 ); |
|
616 |
|
vec3 right = normalize( cross( normal, up ) ); |
|
617 |
|
float index = 0.0; |
|
618 |
|
for( float longi = 0.0; longi <= PI * 0.5; longi += grain ){ |
|
619 |
|
mat4 trl = rotationMatrix( right, longi ); |
|
620 |
|
for( float azi = 0.0; azi <= PI * 2.0; azi += grain ){ |
|
621 |
|
mat4 tra = rotationMatrix( normal, azi ); |
|
622 |
|
vec3 sampleVec = ( tra * trl * vec4( normal, 1.0 ) ).xyz; |
|
623 |
|
irradiance += texture( u_cubemap, sampleVec ).rgb * sin( longi ) * cos( longi ); |
|
624 |
|
index += 1.0; |
|
625 |
|
} |
|
626 |
|
} |
|
627 |
|
float hemispherePDF = 1.0 / ( 2.0 * PI ); |
|
628 |
|
irradiance /= index * hemispherePDF; |
|
629 |
|
return irradiance; |
|
630 |
|
} |
|
631 |
|
void main(){ |
|
632 |
|
vec3 N = normalize( v_STR ); |
|
633 |
|
fragColor = vec4( getIrradiance( N ) / PI, 1.0 ); |
|
634 |
|
} |
|
635 |
|
)"; |
|
636 |
|
|
|
637 |
|
static const std::vector<std::string> irradianceSamplers = { "u_cubemap" }; |
|
638 |
|
|
|
639 |
|
Color fogColor = { 0.0f, 0.0f, 0.0f, 0.0f }; |
|
640 |
|
|
|
641 |
|
Texture blankTexture = { false, 0, 0, 0, 0, false, 0 }; |
|
642 |
|
|
|
643 |
|
Pipeline |
|
644 |
|
drawPipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }, |
|
645 |
|
unlitPipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }, |
|
646 |
|
colorModPipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }, |
|
647 |
|
unlitInstancePipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }, |
|
648 |
|
skyboxPipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }, |
|
649 |
|
irradiancePipeline = { false, 0, 0, 0, 0, 0, 0, 0, 0, {} }; |
|
650 |
|
|
|
651 |
|
Mesh planeMesh = { false, {}, {}, { 0, 0, 0 }, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; |
|
652 |
|
|
|
653 |
|
Mesh cubeMesh = { false, {}, {}, { 0, 0, 0 }, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; |
|
654 |
|
|
|
655 |
|
linalg::mat<double,4,4> texMatrix = linalg::identity, lightMatrix = linalg::identity; |
|
656 |
|
|
492 |
657 |
// TODO: SFML mouse wheel. |
// TODO: SFML mouse wheel. |
493 |
658 |
int mouseX = 0, mouseY = 0, mouseMoveX = 0, mouseMoveY = 0, mouseWheel = 0; |
int mouseX = 0, mouseY = 0, mouseMoveX = 0, mouseMoveY = 0, mouseWheel = 0; |
494 |
659 |
bool mouseTrapped = false; |
bool mouseTrapped = false; |
|
... |
... |
Color rgb( float r, float g, float b ){ |
603 |
768 |
return col; |
return col; |
604 |
769 |
} |
} |
605 |
770 |
|
|
606 |
|
// Used by cls. |
|
607 |
|
void drawMesh( Mesh &mesh, linalg::mat<double,4,4> modelMat, linalg::mat<double,4,4> viewMat, linalg::mat<double,4,4> projMat ); |
|
608 |
|
void setPipeline( Pipeline pipeline ); |
|
609 |
|
|
|
610 |
|
void cls( Color col, bool clearDepth = true ){ |
|
|
771 |
|
void cls( Color col, bool clearDepth ){ |
611 |
772 |
if( clearDepth ){ |
if( clearDepth ){ |
612 |
773 |
// GL_DEPTH_BUFFER_BIT is not usually problematic. |
// GL_DEPTH_BUFFER_BIT is not usually problematic. |
613 |
774 |
glClear( GL_DEPTH_BUFFER_BIT ); |
glClear( GL_DEPTH_BUFFER_BIT ); |
|
... |
... |
void cls( Color col, bool clearDepth = true ){ |
636 |
797 |
setPipeline( p ); |
setPipeline( p ); |
637 |
798 |
} |
} |
638 |
799 |
|
|
639 |
|
Mesh loadMesh( std::vector<Vertex> &vertices, std::vector<Index> &indices, bool streaming = false ){ |
|
|
800 |
|
Mesh loadMesh( std::vector<Vertex> &vertices, std::vector<Index> &indices, bool streaming ){ |
640 |
801 |
Mesh mesh = newMesh; |
Mesh mesh = newMesh; |
641 |
802 |
|
|
642 |
803 |
if( vertices.size() > 0 ){ |
if( vertices.size() > 0 ){ |
|
... |
... |
Mesh loadMesh( std::vector<Vertex> &vertices, std::vector<Index> &indices, bool |
718 |
879 |
return mesh; |
return mesh; |
719 |
880 |
} |
} |
720 |
881 |
|
|
721 |
|
void updateMesh( Mesh &mesh, std::vector<Vertex> &vertices, std::vector<Index> &indices, bool streaming = false ){ |
|
|
882 |
|
void updateMesh( Mesh &mesh, std::vector<Vertex> &vertices, std::vector<Index> &indices, bool streaming ){ |
722 |
883 |
// switch graphics memory to the VAO |
// switch graphics memory to the VAO |
723 |
884 |
glBindVertexArray( mesh.vao[0] ); |
glBindVertexArray( mesh.vao[0] ); |
724 |
885 |
|
|
|
... |
... |
void freeMesh( Mesh &mesh ){ |
1071 |
1232 |
mesh = newMesh; |
mesh = newMesh; |
1072 |
1233 |
} |
} |
1073 |
1234 |
|
|
1074 |
|
Texture loadTexture( const GLvoid* data, GLsizei width, GLsizei height, unsigned int channels, bool mipmap = true, bool filter = true ){ |
|
|
1235 |
|
Mesh getPlaneMesh(){ |
|
1236 |
|
return planeMesh; |
|
1237 |
|
} |
|
1238 |
|
|
|
1239 |
|
Mesh getCubeMesh(){ |
|
1240 |
|
return cubeMesh; |
|
1241 |
|
} |
|
1242 |
|
|
|
1243 |
|
Texture loadTexture( const GLvoid* data, GLsizei width, GLsizei height, unsigned int channels, bool mipmap, bool filter ){ |
1075 |
1244 |
Texture tex = newTexture; |
Texture tex = newTexture; |
1076 |
1245 |
if( !data ) return tex; |
if( !data ) return tex; |
1077 |
1246 |
|
|
|
... |
... |
Texture loadTexture( const GLvoid* data, GLsizei width, GLsizei height, unsigned |
1148 |
1317 |
return tex; |
return tex; |
1149 |
1318 |
} |
} |
1150 |
1319 |
|
|
1151 |
|
Texture loadCubemap( std::vector<GLvoid*> faces, GLsizei width, GLsizei height, unsigned int channels, bool mipmap = true, bool filter = true ){ |
|
|
1320 |
|
Texture loadCubemap( std::vector<GLvoid*> faces, GLsizei width, GLsizei height, unsigned int channels, bool mipmap, bool filter ){ |
1152 |
1321 |
Texture tex = newTexture; |
Texture tex = newTexture; |
1153 |
1322 |
if( faces.size() != 6 ) return tex; |
if( faces.size() != 6 ) return tex; |
1154 |
1323 |
|
|
|
... |
... |
void setTexture( Texture tex, GLuint texSlot ){ |
1310 |
1479 |
} |
} |
1311 |
1480 |
} |
} |
1312 |
1481 |
|
|
|
1482 |
|
Texture getBlankTexture(){ |
|
1483 |
|
return blankTexture; |
|
1484 |
|
} |
|
1485 |
|
|
1313 |
1486 |
void setFog( Color col ){ |
void setFog( Color col ){ |
1314 |
1487 |
glUniform4f( drawPipeline.u_fog, col.r, col.g, col.b, col.a ); |
glUniform4f( drawPipeline.u_fog, col.r, col.g, col.b, col.a ); |
1315 |
1488 |
fogColor = col; |
fogColor = col; |
1316 |
1489 |
} |
} |
1317 |
1490 |
|
|
|
1491 |
|
Color getFog(){ |
|
1492 |
|
return fogColor; |
|
1493 |
|
} |
|
1494 |
|
|
1318 |
1495 |
void setMetallicFactor( GLfloat f ){ |
void setMetallicFactor( GLfloat f ){ |
1319 |
1496 |
glUniform1f( drawPipeline.u_metallicFactor, f ); |
glUniform1f( drawPipeline.u_metallicFactor, f ); |
1320 |
1497 |
} |
} |
|
... |
... |
Pipeline getPipeline(){ |
1346 |
1523 |
return drawPipeline; |
return drawPipeline; |
1347 |
1524 |
} |
} |
1348 |
1525 |
|
|
|
1526 |
|
Pipeline getUnlitPipeline(){ |
|
1527 |
|
return unlitPipeline; |
|
1528 |
|
} |
|
1529 |
|
|
|
1530 |
|
Pipeline getColorModPipeline(){ |
|
1531 |
|
return colorModPipeline; |
|
1532 |
|
} |
|
1533 |
|
Pipeline getUnlitInstancePipeline(){ |
|
1534 |
|
return unlitInstancePipeline; |
|
1535 |
|
} |
|
1536 |
|
|
|
1537 |
|
Pipeline getSkyboxPipeline(){ |
|
1538 |
|
return skyboxPipeline; |
|
1539 |
|
} |
|
1540 |
|
|
|
1541 |
|
Pipeline getIrradiancePipeline(){ |
|
1542 |
|
return irradiancePipeline; |
|
1543 |
|
} |
|
1544 |
|
|
1349 |
1545 |
void setTextureMatrix( linalg::mat<double,4,4> texMat ){ |
void setTextureMatrix( linalg::mat<double,4,4> texMat ){ |
1350 |
1546 |
texMatrix = texMat; |
texMatrix = texMat; |
1351 |
1547 |
} |
} |
1352 |
1548 |
|
|
|
1549 |
|
linalg::mat<double,4,4> getTextureMatrix(){ |
|
1550 |
|
return texMatrix; |
|
1551 |
|
} |
|
1552 |
|
|
1353 |
1553 |
void setLightMatrix( linalg::mat<double,4,4> lightMat ){ |
void setLightMatrix( linalg::mat<double,4,4> lightMat ){ |
1354 |
1554 |
lightMatrix = lightMat; |
lightMatrix = lightMat; |
1355 |
1555 |
} |
} |
1356 |
1556 |
|
|
1357 |
|
Framebuffer createFramebuffer( GLsizei width, GLsizei height, bool cubemap = false, GLenum internalFmt = GL_RGB, GLsizei multisample = 0 ){ |
|
|
1557 |
|
linalg::mat<double,4,4> getLightMatrix(){ |
|
1558 |
|
return lightMatrix; |
|
1559 |
|
} |
|
1560 |
|
|
|
1561 |
|
Framebuffer createFramebuffer( GLsizei width, GLsizei height, bool cubemap, GLenum internalFmt, GLsizei multisample ){ |
1358 |
1562 |
// https://stackoverflow.com/questions/46535341 |
// https://stackoverflow.com/questions/46535341 |
1359 |
1563 |
// This framebuffer API does not currently support mipmapping. |
// This framebuffer API does not currently support mipmapping. |
1360 |
1564 |
|
|
|
... |
... |
Framebuffer createFramebuffer( GLsizei width, GLsizei height, bool cubemap = fal |
1363 |
1567 |
glBindFramebuffer( GL_FRAMEBUFFER, fb.fbo ); |
glBindFramebuffer( GL_FRAMEBUFFER, fb.fbo ); |
1364 |
1568 |
|
|
1365 |
1569 |
// Multisample textures are not available in core GLES 3.0. |
// Multisample textures are not available in core GLES 3.0. |
1366 |
|
#ifdef GLAD_GLES2_IMPLEMENTATION |
|
|
1570 |
|
#ifdef GLAD_GLES2 |
1367 |
1571 |
multisample = 0; |
multisample = 0; |
1368 |
1572 |
fb.texture_type = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; |
fb.texture_type = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; |
1369 |
1573 |
#else |
#else |
|
... |
... |
Framebuffer createFramebuffer( GLsizei width, GLsizei height, bool cubemap = fal |
1423 |
1627 |
glTexParameteri( fb.texture_type, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); |
glTexParameteri( fb.texture_type, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); |
1424 |
1628 |
}else{ |
}else{ |
1425 |
1629 |
// Create a blank surface. |
// Create a blank surface. |
1426 |
|
#ifdef GLAD_GL_IMPLEMENTATION |
|
|
1630 |
|
#ifdef GLAD_GL |
1427 |
1631 |
if( fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE ) |
if( fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE ) |
1428 |
1632 |
glTexImage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, multisample, internalFmt, width, height, GL_TRUE ); |
glTexImage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, multisample, internalFmt, width, height, GL_TRUE ); |
1429 |
1633 |
else |
else |
|
... |
... |
Framebuffer createFramebuffer( GLsizei width, GLsizei height, bool cubemap = fal |
1444 |
1648 |
glBindTexture( fb.texture_type, 0 ); |
glBindTexture( fb.texture_type, 0 ); |
1445 |
1649 |
|
|
1446 |
1650 |
if( cubemap |
if( cubemap |
1447 |
|
#ifdef GLAD_GL_IMPLEMENTATION |
|
|
1651 |
|
#ifdef GLAD_GL |
1448 |
1652 |
|| fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE |
|| fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE |
1449 |
1653 |
#endif |
#endif |
1450 |
1654 |
){ |
){ |
|
... |
... |
Framebuffer createFramebuffer( GLsizei width, GLsizei height, bool cubemap = fal |
1453 |
1657 |
// Create a depth renderbuffer. |
// Create a depth renderbuffer. |
1454 |
1658 |
glGenRenderbuffers( 1, &fb.rbo ); |
glGenRenderbuffers( 1, &fb.rbo ); |
1455 |
1659 |
glBindRenderbuffer( GL_RENDERBUFFER, fb.rbo ); |
glBindRenderbuffer( GL_RENDERBUFFER, fb.rbo ); |
1456 |
|
#ifdef GLAD_GL_IMPLEMENTATION |
|
|
1660 |
|
#ifdef GLAD_GL |
1457 |
1661 |
if( fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE ) |
if( fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE ) |
1458 |
1662 |
glRenderbufferStorageMultisample( GL_RENDERBUFFER, multisample, GL_DEPTH_COMPONENT32F, width, height ); |
glRenderbufferStorageMultisample( GL_RENDERBUFFER, multisample, GL_DEPTH_COMPONENT32F, width, height ); |
1459 |
1663 |
else |
else |
|
... |
... |
Framebuffer createFramebuffer( GLsizei width, GLsizei height, bool cubemap = fal |
1484 |
1688 |
|
|
1485 |
1689 |
GLenum glerr; |
GLenum glerr; |
1486 |
1690 |
while( ( glerr = glGetError() ) != GL_NO_ERROR ){ |
while( ( glerr = glGetError() ) != GL_NO_ERROR ){ |
1487 |
|
fprintf( stderr, "OpenGL error: %d\n", (int)glerr ); |
|
|
1691 |
|
printf( "OpenGL error: 0x%.4X\n", glerr ); |
1488 |
1692 |
} |
} |
1489 |
1693 |
|
|
1490 |
1694 |
fb.width = width; |
fb.width = width; |
|
... |
... |
Framebuffer createFramebuffer( GLsizei width, GLsizei height, bool cubemap = fal |
1493 |
1697 |
return fb; |
return fb; |
1494 |
1698 |
} |
} |
1495 |
1699 |
|
|
1496 |
|
void resizeFramebuffer( Framebuffer &fb, GLsizei width, GLsizei height, GLsizei multisample = 0 ){ |
|
1497 |
|
#ifdef GLAD_GLES2_IMPLEMENTATION |
|
|
1700 |
|
void resizeFramebuffer( Framebuffer &fb, GLsizei width, GLsizei height, GLsizei multisample ){ |
|
1701 |
|
#ifdef GLAD_GLES2 |
1498 |
1702 |
multisample = 0; |
multisample = 0; |
1499 |
1703 |
#endif |
#endif |
1500 |
1704 |
|
|
|
... |
... |
void resizeFramebuffer( Framebuffer &fb, GLsizei width, GLsizei height, GLsizei |
1543 |
1747 |
} |
} |
1544 |
1748 |
}else{ |
}else{ |
1545 |
1749 |
// Resize the texture. |
// Resize the texture. |
1546 |
|
#ifdef GLAD_GL_IMPLEMENTATION |
|
|
1750 |
|
#ifdef GLAD_GL |
1547 |
1751 |
if( fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE ) |
if( fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE ) |
1548 |
1752 |
glTexImage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, multisample, fb.texture_fmt, width, height, GL_TRUE ); |
glTexImage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, multisample, fb.texture_fmt, width, height, GL_TRUE ); |
1549 |
1753 |
else |
else |
|
... |
... |
void resizeFramebuffer( Framebuffer &fb, GLsizei width, GLsizei height, GLsizei |
1555 |
1759 |
glBindTexture( fb.texture_type, 0 ); |
glBindTexture( fb.texture_type, 0 ); |
1556 |
1760 |
|
|
1557 |
1761 |
if( fb.texture_type == GL_TEXTURE_CUBE_MAP |
if( fb.texture_type == GL_TEXTURE_CUBE_MAP |
1558 |
|
#ifdef GLAD_GL_IMPLEMENTATION |
|
|
1762 |
|
#ifdef GLAD_GL |
1559 |
1763 |
|| fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE |
|| fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE |
1560 |
1764 |
#endif |
#endif |
1561 |
1765 |
){ |
){ |
|
... |
... |
void resizeFramebuffer( Framebuffer &fb, GLsizei width, GLsizei height, GLsizei |
1563 |
1767 |
glDeleteRenderbuffers( 1, &fb.rbo ); |
glDeleteRenderbuffers( 1, &fb.rbo ); |
1564 |
1768 |
glGenRenderbuffers( 1, &fb.rbo ); |
glGenRenderbuffers( 1, &fb.rbo ); |
1565 |
1769 |
glBindRenderbuffer( GL_RENDERBUFFER, fb.rbo ); |
glBindRenderbuffer( GL_RENDERBUFFER, fb.rbo ); |
1566 |
|
#ifdef GLAD_GL_IMPLEMENTATION |
|
|
1770 |
|
#ifdef GLAD_GL |
1567 |
1771 |
if( fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE ) |
if( fb.texture_type == GL_TEXTURE_2D_MULTISAMPLE ) |
1568 |
1772 |
glRenderbufferStorageMultisample( GL_RENDERBUFFER, multisample, GL_DEPTH_COMPONENT32F, width, height ); |
glRenderbufferStorageMultisample( GL_RENDERBUFFER, multisample, GL_DEPTH_COMPONENT32F, width, height ); |
1569 |
1773 |
else |
else |
|
... |
... |
Texture getFramebufferTexture( Framebuffer &fb ){ |
1597 |
1801 |
return tex; |
return tex; |
1598 |
1802 |
} |
} |
1599 |
1803 |
|
|
1600 |
|
// Used by setFramebuffer |
|
1601 |
|
Display getDisplay(); |
|
1602 |
|
|
|
1603 |
|
void setFramebuffer( Framebuffer fb = newFramebuffer ){ |
|
|
1804 |
|
void setFramebuffer( Framebuffer fb ){ |
1604 |
1805 |
// Set the drawing target to the framebuffer or the screen. |
// Set the drawing target to the framebuffer or the screen. |
1605 |
1806 |
if( fb.success ){ |
if( fb.success ){ |
1606 |
1807 |
glBindFramebuffer( GL_FRAMEBUFFER, fb.fbo ); |
glBindFramebuffer( GL_FRAMEBUFFER, fb.fbo ); |
|
... |
... |
void setFramebuffer( Framebuffer fb = newFramebuffer ){ |
1612 |
1813 |
} |
} |
1613 |
1814 |
} |
} |
1614 |
1815 |
|
|
1615 |
|
void drawFramebuffer( Framebuffer &fb, bool draw_z = false ){ |
|
|
1816 |
|
void drawFramebuffer( Framebuffer &fb, bool draw_z ){ |
1616 |
1817 |
if( !fb.success ) return; |
if( !fb.success ) return; |
1617 |
1818 |
if( fb.multisample > 0 ){ |
if( fb.multisample > 0 ){ |
1618 |
1819 |
// Blit and rely on OpenGL to resolve samples. |
// Blit and rely on OpenGL to resolve samples. |
|
... |
... |
void drawFramebuffer( Framebuffer &fb, bool draw_z = false ){ |
1642 |
1843 |
} |
} |
1643 |
1844 |
} |
} |
1644 |
1845 |
|
|
1645 |
|
Framebuffer getIrradianceFramebuffer( Texture in_cubemap, Framebuffer fb = newFramebuffer ){ |
|
|
1846 |
|
Framebuffer getIrradianceFramebuffer( Texture in_cubemap, Framebuffer fb ){ |
1646 |
1847 |
if( !fb.success ) fb = createFramebuffer( 32, 32, true ); |
if( !fb.success ) fb = createFramebuffer( 32, 32, true ); |
1647 |
1848 |
setFramebuffer( fb ); |
setFramebuffer( fb ); |
1648 |
1849 |
|
|
|
... |
... |
Framebuffer getIrradianceFramebuffer( Texture in_cubemap, Framebuffer fb = newFr |
1694 |
1895 |
return fb; |
return fb; |
1695 |
1896 |
} |
} |
1696 |
1897 |
|
|
1697 |
|
void drawSkybox( Texture &tex, linalg::mat<double,4,4> view, linalg::mat<double,4,4> proj, Color tint = newColor ){ |
|
|
1898 |
|
void drawSkybox( Texture &tex, linalg::mat<double,4,4> view, linalg::mat<double,4,4> proj, Color tint ){ |
1698 |
1899 |
if( !skyboxPipeline.success ) return; |
if( !skyboxPipeline.success ) return; |
1699 |
1900 |
auto old_pipeline = drawPipeline; |
auto old_pipeline = drawPipeline; |
1700 |
1901 |
setPipeline( skyboxPipeline ); |
setPipeline( skyboxPipeline ); |
|
... |
... |
int linkProgram( GLuint programObject ){ |
1788 |
1989 |
return 1; |
return 1; |
1789 |
1990 |
} |
} |
1790 |
1991 |
|
|
1791 |
|
Pipeline loadPipeline( const GLchar* vertSrc, const GLchar* fragSrc, std::vector<std::string> samplers = {} ){ |
|
|
1992 |
|
Pipeline loadPipeline( const GLchar* vertSrc, const GLchar* fragSrc, std::vector<std::string> samplers ){ |
1792 |
1993 |
Pipeline pipeline = newPipeline; |
Pipeline pipeline = newPipeline; |
1793 |
1994 |
|
|
1794 |
1995 |
GLuint vert; |
GLuint vert; |
|
... |
... |
Pipeline loadPipeline( const GLchar* vertSrc, const GLchar* fragSrc, std::vector |
1834 |
2035 |
return pipeline; |
return pipeline; |
1835 |
2036 |
} |
} |
1836 |
2037 |
|
|
1837 |
|
Display createDisplay( unsigned int width, unsigned int height, std::string title, int multisamples = 4, bool HiDPI = true, bool vsync = true ){ |
|
|
2038 |
|
Display createDisplay( unsigned int width, unsigned int height, std::string title, int multisamples, bool HiDPI, bool vsync ){ |
1838 |
2039 |
// Opens a window with a GL context. |
// Opens a window with a GL context. |
1839 |
2040 |
// Display display = createDisplay( 800, 600, "Title" ); |
// Display display = createDisplay( 800, 600, "Title" ); |
1840 |
2041 |
|
|
|
... |
... |
Display createDisplay( unsigned int width, unsigned int height, std::string titl |
2014 |
2215 |
glDepthFunc( GL_LEQUAL ); |
glDepthFunc( GL_LEQUAL ); |
2015 |
2216 |
glDepthMask( GL_TRUE ); |
glDepthMask( GL_TRUE ); |
2016 |
2217 |
// Multisample textures and seamless cubemaps are not available in core GLES 3.0. |
// Multisample textures and seamless cubemaps are not available in core GLES 3.0. |
2017 |
|
#ifdef GLAD_GL_IMPLEMENTATION |
|
|
2218 |
|
#ifdef GLAD_GL |
2018 |
2219 |
glEnable( GL_MULTISAMPLE ); |
glEnable( GL_MULTISAMPLE ); |
2019 |
2220 |
glEnable( GL_TEXTURE_CUBE_MAP_SEAMLESS ); |
glEnable( GL_TEXTURE_CUBE_MAP_SEAMLESS ); |
2020 |
2221 |
#endif |
#endif |
|
... |
... |
Display createDisplay( unsigned int width, unsigned int height, std::string titl |
2140 |
2341 |
return disp; |
return disp; |
2141 |
2342 |
} |
} |
2142 |
2343 |
|
|
|
2344 |
|
void focusDisplay(){ |
|
2345 |
|
#ifdef SDL_MAJOR_VERSION |
|
2346 |
|
SDL_HideWindow( window ); |
|
2347 |
|
SDL_ShowWindow( window ); |
|
2348 |
|
SDL_RaiseWindow( window ); |
|
2349 |
|
#endif |
|
2350 |
|
// TODO: SFML. |
|
2351 |
|
} |
|
2352 |
|
|
|
2353 |
|
int getMouseX(){ |
|
2354 |
|
return mouseX; |
|
2355 |
|
} |
|
2356 |
|
|
|
2357 |
|
int getMouseY(){ |
|
2358 |
|
return mouseY; |
|
2359 |
|
} |
|
2360 |
|
|
2143 |
2361 |
#ifdef SDL_MAJOR_VERSION |
#ifdef SDL_MAJOR_VERSION |
2144 |
2362 |
|
|
2145 |
2363 |
Display getDisplay(){ |
Display getDisplay(){ |
|
... |
... |
void sync(){ |
2264 |
2482 |
syncEvents(); |
syncEvents(); |
2265 |
2483 |
} |
} |
2266 |
2484 |
|
|
2267 |
|
void setTextInput( int x = 0, int y = 0, int w = 0, int h = 0 ){ |
|
|
2485 |
|
void setTextInput( int x, int y, int w, int h ){ |
2268 |
2486 |
// https://wiki.libsdl.org/Tutorials/TextInput |
// https://wiki.libsdl.org/Tutorials/TextInput |
2269 |
2487 |
if( x || y || w || h ){ |
if( x || y || w || h ){ |
2270 |
2488 |
if( !SDL_IsTextInputActive() ) |
if( !SDL_IsTextInputActive() ) |
|
... |
... |
int getCharacterIndex( int cp, Font &font ){ |
2654 |
2872 |
} |
} |
2655 |
2873 |
|
|
2656 |
2874 |
Font loadFont( std::string fileName, float fontSize, int oversampleX, int oversampleY, |
Font loadFont( std::string fileName, float fontSize, int oversampleX, int oversampleY, |
2657 |
|
bool prepack = true, int atlasWidth = 512, int atlasHeight = 512 ){ |
|
|
2875 |
|
bool prepack, int atlasWidth, int atlasHeight ){ |
2658 |
2876 |
Font font = newFont; |
Font font = newFont; |
2659 |
2877 |
|
|
2660 |
2878 |
FILE* file = fopen( fileName.c_str(), "rb" ); |
FILE* file = fopen( fileName.c_str(), "rb" ); |
|
... |
... |
float getTextWidth( std::string text, Font &font ){ |
2727 |
2945 |
return getTextWidthUtf32( utf8ToUtf32( text ), font ); |
return getTextWidthUtf32( utf8ToUtf32( text ), font ); |
2728 |
2946 |
} |
} |
2729 |
2947 |
|
|
2730 |
|
void drawTextUtf32( std::u32string codepoints, Font &font, float posX, float posY, float scale, int align = 0, float wordWrap = 0.0f ){ |
|
|
2948 |
|
void drawTextUtf32( std::u32string codepoints, Font &font, float posX, float posY, float scale, int align, float wordWrap ){ |
2731 |
2949 |
// align modes -- 0: left, 1: center, 2: right |
// align modes -- 0: left, 1: center, 2: right |
2732 |
2950 |
|
|
2733 |
2951 |
Texture &tex = font.texture; |
Texture &tex = font.texture; |
|
... |
... |
void drawTextUtf32( std::u32string codepoints, Font &font, float posX, float pos |
2844 |
3062 |
texMatrix = oldTexMatrix; |
texMatrix = oldTexMatrix; |
2845 |
3063 |
} |
} |
2846 |
3064 |
|
|
2847 |
|
void drawText( std::string text, Font &font, float posX, float posY, float scale, int align = 0, float wordWrap = 0.0f ){ |
|
|
3065 |
|
void drawText( std::string text, Font &font, float posX, float posY, float scale, int align, float wordWrap ){ |
2848 |
3066 |
// align modes -- 0: left, 1: center, 2: right |
// align modes -- 0: left, 1: center, 2: right |
2849 |
3067 |
|
|
2850 |
3068 |
if( !font.texture.success ) return; |
if( !font.texture.success ) return; |
|
... |
... |
int getCharacterIndex( int cp, Font &font ){ |
2863 |
3081 |
} |
} |
2864 |
3082 |
|
|
2865 |
3083 |
Font loadFont( std::string fileName, float fontSize, int oversampleX, int oversampleY, |
Font loadFont( std::string fileName, float fontSize, int oversampleX, int oversampleY, |
2866 |
|
bool prepack = true, int atlasWidth = 512, int atlasHeight = 512 ){ |
|
|
3084 |
|
bool prepack, int atlasWidth, int atlasHeight ){ |
2867 |
3085 |
_ERROUT_ << "Include stb_truetype.h before fg3.h to load TrueType fonts.\n" << std::endl; |
_ERROUT_ << "Include stb_truetype.h before fg3.h to load TrueType fonts.\n" << std::endl; |
2868 |
3086 |
return newFont; |
return newFont; |
2869 |
3087 |
} |
} |
|
... |
... |
float getTextWidth( std::string text, Font &font ){ |
2876 |
3094 |
return 0.0f; |
return 0.0f; |
2877 |
3095 |
} |
} |
2878 |
3096 |
|
|
2879 |
|
void drawTextUtf32( std::u32string codepoints, Font &font, float posX, float posY, float scale, int align = 0, float wordWrap = 0.0f ){ |
|
|
3097 |
|
void drawTextUtf32( std::u32string codepoints, Font &font, float posX, float posY, float scale, int align, float wordWrap ){ |
2880 |
3098 |
return; |
return; |
2881 |
3099 |
} |
} |
2882 |
3100 |
|
|
2883 |
|
void drawText( std::string text, Font &font, float posX, float posY, float scale, int align = 0, float wordWrap = 0.0f ){ |
|
|
3101 |
|
void drawText( std::string text, Font &font, float posX, float posY, float scale, int align, float wordWrap ){ |
2884 |
3102 |
return; |
return; |
2885 |
3103 |
} |
} |
2886 |
3104 |
|
|
2887 |
3105 |
#endif // __STB_INCLUDE_STB_TRUETYPE_H__ |
#endif // __STB_INCLUDE_STB_TRUETYPE_H__ |
2888 |
3106 |
|
|
|
3107 |
|
#endif // FG3_IMPLEMENTATION |
|
3108 |
|
|
2889 |
3109 |
} // namespace fg3 |
} // namespace fg3 |
2890 |
3110 |
|
|
2891 |
3111 |
#endif // FG3_H |
#endif // FG3_H |