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