14 #include "../aux_vis.hpp"
17 #include <type_traits>
18 #include <unordered_set>
23 #include "shaders/lighting.glsl"
26 #include "shaders/default.vert"
30 #include "shaders/default.frag"
34 #include "shaders/printing.vert"
37 #include "shaders/printing.frag"
43 const std::vector<std::string> CoreGLDevice::unif_list =
69 template<
typename TVtx>
73 "Invalid vertex type, requires at least TVtx::coord to be present.");
80 template<
typename TVtx>
84 "Invalid vertex type, requires at least TVtx::coord to be present.");
91 bool CoreGLDevice::compileShaders()
93 std::unordered_map<int, std::string> attribMap =
104 std::cerr <<
"Failed to create the default shader program." <<
109 #ifndef __EMSCRIPTEN__
110 if (GLEW_EXT_transform_feedback || GLEW_VERSION_3_0)
112 const char * xfrm_varyings[] =
118 glTransformFeedbackVaryings(feedback_prgm.
getProgramId(), 3, xfrm_varyings,
119 GL_INTERLEAVED_ATTRIBS);
123 std::cerr <<
"Failed to create the printing capture program." << std::endl;
132 void CoreGLDevice::initializeShaderState(
const ShaderProgram& prog)
135 uniforms = prog.getUniformMap();
136 for (
const auto& uf : unif_list)
138 if (uniforms.find(uf) == uniforms.end())
141 std::cerr <<
"Uniform \"" << uf
142 <<
"\" missing in shader, ignoring." << std::endl;
145 uniforms.emplace(uf, -1);
149 unordered_set<string> expectedUnifs(unif_list.begin(), unif_list.end());
150 for (
const auto& pairunif : uniforms)
152 if (expectedUnifs.find(pairunif.first) == expectedUnifs.end())
154 std::cerr <<
"Warning: unexpected uniform \""
156 <<
"\" found in shader." << std::endl;
160 glUniform1i(uniforms[
"colorTex"], 0);
161 glUniform1i(uniforms[
"alphaTex"], 1);
162 use_clip_plane =
false;
168 if (!this->compileShaders())
170 std::cerr <<
"Unable to initialize CoreGLDevice." << std::endl;
173 this->initializeShaderState(default_prgm);
174 if (GLEW_VERSION_3_0 || GLEW_ARB_vertex_array_object)
177 glGenVertexArrays(1, &hnd_vao);
179 glBindVertexArray(global_vao);
182 glGenBuffers(1, &hnd_fb_buf);
187 glm::mat4 projection)
191 glm::mat3 inv_normal = glm::inverseTranspose(glm::mat3(model_view));
192 glUniformMatrix4fv(uniforms[
"modelViewMatrix"], 1, GL_FALSE,
193 glm::value_ptr(model_view));
194 glUniformMatrix4fv(uniforms[
"projectionMatrix"], 1, GL_FALSE,
195 glm::value_ptr(projection));
196 glUniformMatrix4fv(uniforms[
"textProjMatrix"], 1, GL_FALSE,
197 glm::value_ptr(proj_text));
198 glUniformMatrix3fv(uniforms[
"normalMatrix"], 1, GL_FALSE,
199 glm::value_ptr(inv_normal));
208 glUniform1i(uniforms[
"num_lights"], i);
213 glUniform4fv(uniforms[
"material.specular"], 1, mat.
specular.data());
214 glUniform1f(uniforms[
"material.shininess"], mat.
shininess);
223 std::string lt_index =
"lights[" + std::to_string(i) +
"]";
224 glUniform4fv(uniforms[lt_index +
".position"], 1, lt.
position.data());
225 glUniform4fv(uniforms[lt_index +
".diffuse"], 1, lt.
diffuse.data());
226 glUniform4fv(uniforms[lt_index +
".specular"], 1, lt.
specular.data());
231 glUniform4fv(uniforms[
"g_ambient"], 1, amb.data());
236 use_clip_plane = enable;
237 glUniform1i(uniforms[
"useClipPlane"], enable);
242 glm::vec4 clip_plane(eqn[0], eqn[1], eqn[2], eqn[3]);
244 glUniform4fv(uniforms[
"clipPlane"], 1, glm::value_ptr(clip_plane));
251 if (buf.
count() == 0) {
return; }
253 glGenBuffers(1, &handle);
255 vbos.emplace_back(VBOData{handle, 0, buf.
getShape(), buf.
count(), layout});
261 glBindBuffer(GL_ARRAY_BUFFER, vbos[buf.
getHandle()].vert_buf);
262 glBufferData(GL_ARRAY_BUFFER, 0,
nullptr, GL_STATIC_DRAW);
264 buf.
getData(), GL_STATIC_DRAW);
271 if (buf.
count() == 0) {
return; }
273 glGenBuffers(2, &handle[0]);
275 vbos.emplace_back(VBOData{handle[0], handle[1], buf.
getShape(), buf.
getIndices().size(), layout});
282 glBindBuffer(GL_ARRAY_BUFFER, vbos[buf.
getHandle()].vert_buf);
283 glBufferData(GL_ARRAY_BUFFER, 0,
nullptr, GL_STATIC_DRAW);
285 buf.
getData(), GL_STATIC_DRAW);
287 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos[buf.
getHandle()].elem_buf);
288 glBufferData(GL_ELEMENT_ARRAY_BUFFER, 0,
nullptr, GL_STATIC_DRAW);
289 glBufferData(GL_ELEMENT_ARRAY_BUFFER, buf.
getIndices().size() *
sizeof(int),
295 std::vector<float> buf_data;
298 for (
auto &e : t_buf)
300 float pen_x = e.ox, pen_y = e.oy;
302 for (
char c : e.text)
307 float cur_x = pen_x + g.
bear_x - 1;
308 float cur_y = -pen_y - g.
bear_y - 1;
317 e.rx, e.ry, e.rz, cur_x, -cur_y, g.
tex_x, 0, 0,
318 e.rx, e.ry, e.rz, cur_x + g.
w, -cur_y, g.
tex_x + g.
w / tex_w, 0, 0,
319 e.rx, e.ry, e.rz, cur_x, -cur_y - g.
h, g.
tex_x, g.
h / tex_h, 0,
320 e.rx, e.ry, e.rz, cur_x + g.
w, -cur_y, g.
tex_x + g.
w / tex_w, 0, 0,
321 e.rx, e.ry, e.rz, cur_x, -cur_y - g.
h, g.
tex_x, g.
h / tex_h, 0,
322 e.rx, e.ry, e.rz, cur_x + g.
w, -cur_y - g.
h, g.
tex_x + g.
w / tex_w, g.
h / tex_h, 0
324 buf_data.insert(buf_data.end(), tris, tris + 8 * 6);
328 if (buf_data.size() == 0) {
return; }
329 if (t_buf.getHandle() == 0)
332 glGenBuffers(1, &handle);
333 t_buf.setHandle(handle);
335 glBindBuffer(GL_ARRAY_BUFFER, t_buf.getHandle());
336 glBufferData(GL_ARRAY_BUFFER,
sizeof(
float) * buf_data.size(), buf_data.data(),
341 void CoreGLDevice::drawDeviceBufferImpl(GLenum shape,
int count,
bool indexed)
347 if (!AttrColor<T>::exists && AttrTexcoord<T>::exists)
351 setupVtxAttrLayout<T>();
354 glDrawElements(shape, count, GL_UNSIGNED_INT, (
void*)0);
358 glDrawArrays(shape, 0, count);
360 clearVtxAttrLayout<T>();
365 if (hnd == 0) {
return; }
366 if (vbos[hnd].count == 0) {
return; }
367 glBindBuffer(GL_ARRAY_BUFFER, vbos[hnd].vert_buf);
368 bool indexed =
false;
369 if (vbos[hnd].elem_buf != 0)
371 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos[hnd].elem_buf);
379 GLenum shape = vbos[hnd].shape;
380 int count = vbos[hnd].count;
381 switch (vbos[hnd].layout)
384 drawDeviceBufferImpl<Vertex>(shape, count, indexed);
387 drawDeviceBufferImpl<VertexColor>(shape, count, indexed);
390 drawDeviceBufferImpl<VertexTex>(shape, count, indexed);
393 drawDeviceBufferImpl<VertexNorm>(shape, count, indexed);
396 drawDeviceBufferImpl<VertexNormColor>(shape, count, indexed);
399 drawDeviceBufferImpl<VertexNormTex>(shape, count, indexed);
402 cerr <<
"WARNING: Unhandled vertex layout " << vbos[hnd].layout << endl;
408 if (t_buf.
count() == 0) {
return; }
409 glUniform1i(uniforms[
"containsText"], GL_TRUE);
413 glBindBuffer(GL_ARRAY_BUFFER, t_buf.
getHandle());
418 t_buf.
getStride(), (
void*)(
sizeof(
float) * 3));
420 (
void*)(
sizeof(
float) * 5));
421 glDrawArrays(GL_TRIANGLES, 0, t_buf.
count());
425 glUniform1i(uniforms[
"containsText"], GL_FALSE);
428 #ifndef __EMSCRIPTEN__
431 float half_w,
float half_h)
433 glm::vec3 coord = glm::make_vec3(v.
pos);
434 glm::vec4 color = glm::make_vec4(v.
color);
438 coord.x = half_w * coord.x + half_w;
439 coord.y = half_h * coord.y + half_h;
440 return { coord, color };
443 void CoreGLDevice::processTriangleXfbBuffer(CaptureBuffer& cbuf,
444 const vector<ShaderXfbVertex>& verts)
451 for (
size_t i = 0; i < verts.size(); i++)
458 for (
size_t t_i = 0; t_i < verts.size() / 3; t_i++)
460 if (verts[t_i*3].clipCoord >= 0.f
461 && verts[t_i*3+1].clipCoord >= 0.f
462 && verts[t_i*3+2].clipCoord >= 0.f)
465 for (
int vert_i = 0; vert_i < 3; vert_i++)
467 cbuf.triangles.emplace_back(
471 else if (verts[3*t_i].clipCoord < 0.f
472 && verts[3*t_i+1].clipCoord < 0.f
473 && verts[3*t_i+2].clipCoord < 0.f)
481 for (
int vert_i = 0; vert_i < 3; vert_i++)
483 int i_a = 3*t_i+vert_i;
484 int i_b = 3*t_i+((vert_i+1) % 3);
485 int i_c = 3*t_i+((vert_i+2) % 3);
487 if ((verts[i_a].clipCoord < 0.f) == (verts[i_b].clipCoord < 0.f))
491 float c_w_a = verts[i_a].clipCoord / verts[i_a].pos[3];
492 float c_w_b = verts[i_b].clipCoord / verts[i_b].pos[3];
493 float c_w_c = verts[i_c].clipCoord / verts[i_c].pos[3];
495 glm::vec4 pos[2], color[2];
497 pos[0] = (glm::make_vec4(verts[i_a].pos) * verts[i_c].clipCoord
498 - glm::make_vec4(verts[i_c].pos) * verts[i_a].clipCoord);
499 color[0] = (glm::make_vec4(verts[i_a].color) * c_w_c
500 - glm::make_vec4(verts[i_c].color) * c_w_a)
503 pos[1] = (glm::make_vec4(verts[i_b].pos) * verts[i_c].clipCoord
504 - glm::make_vec4(verts[i_c].pos) * verts[i_b].clipCoord);
505 color[1] = (glm::make_vec4(verts[i_b].color) * c_w_c
506 - glm::make_vec4(verts[i_c].color) * c_w_b)
508 for (
int i = 0; i < 2; i++)
512 pos[i].x *= half_w; pos[i].x += half_w;
513 pos[i].y *= half_h; pos[i].y += half_h;
516 if (verts[i_c].clipCoord < 0.f)
521 cbuf.triangles.emplace_back(pos[0], color[0]);
522 cbuf.triangles.emplace_back(pos[1], color[1]);
524 cbuf.triangles.emplace_back(pos[1], color[1]);
532 cbuf.triangles.emplace_back(pos[0], color[0]);
533 cbuf.triangles.emplace_back(pos[1], color[1]);
542 void CoreGLDevice::processLineXfbBuffer(CaptureBuffer& cbuf,
543 const vector<ShaderXfbVertex>& verts)
547 for (
size_t i = 0; i < verts.size(); i += 2)
549 if (!use_clip_plane ||
550 (verts[i].clipCoord >= 0.f && verts[i+1].clipCoord >= 0.f))
555 else if (verts[i].clipCoord < 0.f && verts[i+1].clipCoord < 0.f)
563 if (verts[i].clipCoord < 0.f)
576 ShaderXfbVertex clip_vert;
578 float c_w_a = verts[i_a].clipCoord / verts[i_a].pos[3];
579 float c_w_b = verts[i_b].clipCoord / verts[i_b].pos[3];
580 for (
int j = 0; j < 4; j++)
582 clip_vert.pos[j] = verts[i_a].pos[j] * verts[i_b].clipCoord
583 - verts[i_b].pos[j] * verts[i_a].clipCoord;
584 clip_vert.color[j] = (verts[i_a].color[j] * c_w_b
585 - verts[i_b].color[j] * c_w_a)
598 if (hnd == 0) {
return; }
599 if (vbos[hnd].count == 0) {
return; }
602 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
603 buf_size,
nullptr, GL_STATIC_READ);
604 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, feedback_vbo);
606 glBeginTransformFeedback(vbos[hnd].shape);
608 glEndTransformFeedback();
610 vector<ShaderXfbVertex> xfbBuf(buf_size);
611 glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buf_size, xfbBuf.data());
612 if (vbos[hnd].shape == GL_TRIANGLES)
614 processTriangleXfbBuffer(cbuf, xfbBuf);
616 else if (vbos[hnd].shape == GL_LINES)
618 processLineXfbBuffer(cbuf, xfbBuf);
622 std::cerr <<
"Warning: GL_POINTS handling not implemented in transform "
623 <<
"feedback processing" << std::endl;
632 std::cerr <<
"CoreGLDevice::captureXfbBuffer: "
633 <<
"Not implemented for WebGL." << std::endl;
636 #endif // __EMSCRIPTEN__
virtual size_t count() const
Gets the number of vertices contained in the buffer.
void setClipPlaneEqn(const std::array< double, 4 > &eqn) override
void drawDeviceBuffer(int hnd) override
virtual void setTransformMatrices(glm::mat4 model_view, glm::mat4 projection)
virtual size_t getStride() const
Gets the stride between vertices.
GLuint getProgramId() const
virtual size_t count() const =0
Gets the number of vertices contained in the buffer.
bool create(std::string vertexShader, std::string fragmentShader, std::unordered_map< int, std::string > inAttributes, int numOutputs)
std::array< float, 4 > position
const std::string DEFAULT_VS
void setNumLights(int i) override
Handle< boCleanup > BufObjHandle
void setupVtxAttrLayout()
void setClipPlaneUse(bool enable) override
float GetKerning(char cprev, char c)
std::array< float, 4 > specular
void captureXfbBuffer(PaletteState &pal, CaptureBuffer &cbuf, int hnd) override
std::array< float, 4 > diffuse
FeedbackVertex XFBPostTransform(CoreGLDevice::ShaderXfbVertex v, float half_w, float half_h)
const std::string BLINN_PHONG_FS
std::array< float, 4 > static_color
Handle< vaoCleanup > VtxArrayHandle
void bufferToDevice(array_layout layout, IVertexBuffer &buf) override
void setHandle(int dev_hnd)
void clearVtxAttrLayout()
void setPointLight(int i, Light lt) override
virtual const void * getData() const =0
virtual size_t getStride() const =0
Gets the stride between vertices.
void setTransformMatrices(glm::mat4 model_view, glm::mat4 projection) override
std::array< float, 4 > specular
void setAmbientLight(const std::array< float, 4 > &amb) override
virtual const std::vector< int > & getIndices() const =0
virtual GLenum getShape() const =0
Gets the primitive type contained by the vertex buffer.
void setMaterial(Material mat) override
const glyph & GetTexChar(char c) const
const std::string PRINTING_VS
const std::string PRINTING_FS
const std::string DEFAULT_FS