diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index ebeaaf870..5c6f5c0d9 100644 --- a/src/buddies/src/bd/bdReaderOptions.cc +++ b/src/buddies/src/bd/bdReaderOptions.cc @@ -171,11 +171,11 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd) "\n" "* 1/0 2/0 3/0-255:17/0\n" " Selects 1/0, 2/0 and maps layer 3, datatype 0 to 255 to layer 17, datatype 0.\n" - " If clarity, the mapping can also be written with brackets like this: '(1/0) (2/0) (3/0-255:17/0)'.\n" + " For clarity, the mapping can also be written with brackets like this: '(1/0) (2/0) (3/0-255:17/0)'.\n" "\n" "* A:1/0 B:2/0\n" " Maps named layer A to 1/0 and named layer B to 2/0.\n" - " If clarity, the mapping can also be written with brackets like this: '(A:1/0) (B:2/0)'.\n" + " For clarity, the mapping can also be written with brackets like this: '(A:1/0) (B:2/0)'.\n" "\n" "* [*/*] +(10/*:1000)/*\n" " Includes all layers, but in addition copies all datatypes of layer 10 to 1000 while keeping the datatype.\n" diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index f07d4c6d2..08de8a832 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -196,7 +196,7 @@ private: D25ViewWidget::D25ViewWidget (QWidget *parent) : QOpenGLWidget (parent), - m_shapes_program (0), m_lines_program (0), m_gridplane_program (0) + m_shapes_program (0), m_shapes_program_uniform_normals (0), m_lines_program (0), m_gridplane_program (0) { QSurfaceFormat format; format.setDepthBufferSize (24); @@ -220,6 +220,7 @@ D25ViewWidget::~D25ViewWidget () makeCurrent (); delete m_shapes_program; + delete m_shapes_program_uniform_normals; delete m_lines_program; delete m_gridplane_program; @@ -569,6 +570,7 @@ static void lp_to_info (const lay::LayerPropertiesNode &lp, D25ViewWidget::Layer void D25ViewWidget::open_display (const tl::color_t *frame_color, const tl::color_t *fill_color, const db::LayerProperties *like, const std::string *name) { + m_flat_vertex_chunks.push_back (triangle_chunks_type ()); m_vertex_chunks.push_back (triangle_chunks_type ()); m_normals_chunks.push_back (triangle_chunks_type ()); m_line_chunks.push_back (line_chunks_type ()); @@ -671,7 +673,7 @@ D25ViewWidget::entry (const db::Region &data, double dbu, double zstart, double enter (iter, zstart, zstop); tl::AbsoluteProgress progress (tl::to_string (tr ("Rendering ..."))); - render_region (progress, *m_layers.back ().vertex_chunk, *m_layers.back ().normals_chunk, *m_layers.back ().line_chunk, data, dbu, db::CplxTrans (dbu).inverted () * m_bbox, zstart, zstop); + render_region (progress, *m_layers.back ().get_flat_vertex_chunks (zstart, zstop, m_flat_vertex_chunks), *m_layers.back ().vertex_chunk, *m_layers.back ().normals_chunk, *m_layers.back ().line_chunk, data, dbu, db::CplxTrans (dbu).inverted () * m_bbox, zstart, zstop); } void @@ -719,7 +721,7 @@ D25ViewWidget::attach_view (LayoutViewBase *view) } void -D25ViewWidget::render_polygon (D25ViewWidget::triangle_chunks_type &chunks, D25ViewWidget::triangle_chunks_type &normals, D25ViewWidget::line_chunks_type &line_chunks, const db::Polygon &poly, double dbu, double zstart, double zstop) +D25ViewWidget::render_polygon (D25ViewWidget::triangle_chunks_type &flat_chunks, const db::Polygon &poly, double dbu) { if (poly.holes () > 0) { @@ -735,7 +737,7 @@ D25ViewWidget::render_polygon (D25ViewWidget::triangle_chunks_type &chunks, D25V ep.process (out, op); for (std::vector::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) { - render_polygon (chunks, normals, line_chunks, *p, dbu, zstart, zstop); + render_polygon (flat_chunks, *p, dbu); } } else if (poly.hull ().size () > 4) { @@ -744,7 +746,7 @@ D25ViewWidget::render_polygon (D25ViewWidget::triangle_chunks_type &chunks, D25V db::split_polygon (poly, poly_heap); for (std::vector::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) { - render_polygon (chunks, normals, line_chunks, *p, dbu, zstart, zstop); + render_polygon (flat_chunks, *p, dbu); } } else if (poly.hull ().size () >= 3) { @@ -753,46 +755,16 @@ D25ViewWidget::render_polygon (D25ViewWidget::triangle_chunks_type &chunks, D25V std::copy (poly.hull ().begin (), poly.hull ().end (), &pts [0]); // triangle bottom - chunks.add (pts[0].x () * dbu, zstart, pts[0].y () * dbu); - chunks.add (pts[2].x () * dbu, zstart, pts[2].y () * dbu); - chunks.add (pts[1].x () * dbu, zstart, pts[1].y () * dbu); - - // normals - for (unsigned int i = 0; i < 3; ++i) { - normals.add (0.0, 1.0, 0.0); - } - - // triangle top - chunks.add (pts[0].x () * dbu, zstop, pts[0].y () * dbu); - chunks.add (pts[1].x () * dbu, zstop, pts[1].y () * dbu); - chunks.add (pts[2].x () * dbu, zstop, pts[2].y () * dbu); - - // normals - for (unsigned int i = 0; i < 3; ++i) { - normals.add (0.0, -1.0, 0.0); - } + flat_chunks.add (pts[0].x () * dbu, 0.0, pts[0].y () * dbu); + flat_chunks.add (pts[2].x () * dbu, 0.0, pts[2].y () * dbu); + flat_chunks.add (pts[1].x () * dbu, 0.0, pts[1].y () * dbu); if (poly.hull ().size () == 4) { // triangle bottom - chunks.add (pts[0].x () * dbu, zstart, pts[0].y () * dbu); - chunks.add (pts[3].x () * dbu, zstart, pts[3].y () * dbu); - chunks.add (pts[2].x () * dbu, zstart, pts[2].y () * dbu); - - // normals - for (unsigned int i = 0; i < 3; ++i) { - normals.add (0.0, 1.0, 0.0); - } - - // triangle top - chunks.add (pts[0].x () * dbu, zstop, pts[0].y () * dbu); - chunks.add (pts[2].x () * dbu, zstop, pts[2].y () * dbu); - chunks.add (pts[3].x () * dbu, zstop, pts[3].y () * dbu); - - // normals - for (unsigned int i = 0; i < 3; ++i) { - normals.add (0.0, -1.0, 0.0); - } + flat_chunks.add (pts[0].x () * dbu, 0.0, pts[0].y () * dbu); + flat_chunks.add (pts[3].x () * dbu, 0.0, pts[3].y () * dbu); + flat_chunks.add (pts[2].x () * dbu, 0.0, pts[2].y () * dbu); } @@ -830,7 +802,7 @@ D25ViewWidget::render_wall (D25ViewWidget::triangle_chunks_type &chunks, D25View } void -D25ViewWidget::render_region (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &chunks, D25ViewWidget::triangle_chunks_type &normals, D25ViewWidget::line_chunks_type &line_chunks, const db::Region ®ion, double dbu, const db::Box &clip_box, double zstart, double zstop) +D25ViewWidget::render_region (tl::AbsoluteProgress &progress, triangle_chunks_type &flat_chunks, D25ViewWidget::triangle_chunks_type &chunks, D25ViewWidget::triangle_chunks_type &normals, D25ViewWidget::line_chunks_type &line_chunks, const db::Region ®ion, double dbu, const db::Box &clip_box, double zstart, double zstop) { std::vector poly_heap; @@ -843,7 +815,7 @@ D25ViewWidget::render_region (tl::AbsoluteProgress &progress, D25ViewWidget::tri ++progress; - render_polygon (chunks, normals, line_chunks, *p, dbu, zstart, zstop); + render_polygon (flat_chunks, *p, dbu); for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { render_wall (chunks, normals, line_chunks, *e, dbu, zstart, zstop); @@ -915,6 +887,7 @@ void D25ViewWidget::initializeGL () { tl_assert (m_shapes_program == 0); + tl_assert (m_shapes_program_uniform_normals == 0); tl_assert (m_gridplane_program == 0); tl_assert (m_lines_program == 0); @@ -937,6 +910,8 @@ D25ViewWidget::initializeGL () delete m_shapes_program; m_shapes_program = 0; + delete m_shapes_program_uniform_normals; + m_shapes_program_uniform_normals = 0; delete m_lines_program; m_lines_program = 0; delete m_gridplane_program; @@ -969,6 +944,21 @@ D25ViewWidget::do_initialize_gl () " dp = dot(normalsAttr.xyz, illum);\n" "}\n"; + static const char *shapes_vertex_shader_uniform_normals_source = + "#version 120\n" + "\n" + "attribute vec4 posAttr;\n" + "uniform vec4 normal;\n" + "uniform mat4 matrix;\n" + "uniform vec3 illum;\n" + // NOTE: dp is not really varying currently, but we can use the same fragment shader this way + "varying float dp;\n" + "\n" + "void main() {\n" + " gl_Position = matrix * posAttr;\n" + " dp = dot(normal.xyz, illum);\n" + "}\n"; + static const char *shapes_fragment_shader_source = "#version 120\n" "\n" @@ -1009,6 +999,17 @@ D25ViewWidget::do_initialize_gl () throw tl::Exception (std::string ("Shapes shader program linking failed failed:\n") + tl::to_string (m_shapes_program->log ())); } + m_shapes_program_uniform_normals = new QOpenGLShaderProgram (this); + if (! m_shapes_program_uniform_normals->addShaderFromSourceCode (QOpenGLShader::Vertex, shapes_vertex_shader_uniform_normals_source)) { + throw tl::Exception (std::string ("Shapes vertex shader compilation failed (uniform normals):\n") + tl::to_string (m_shapes_program_uniform_normals->log ())); + } + if (! m_shapes_program_uniform_normals->addShaderFromSourceCode (QOpenGLShader::Fragment, shapes_fragment_shader_source)) { + throw tl::Exception (std::string ("Shapes fragment shader compilation failed (uniform normals):\n") + tl::to_string (m_shapes_program_uniform_normals->log ())); + } + if (! m_shapes_program_uniform_normals->link ()) { + throw tl::Exception (std::string ("Shapes shader program linking failed failed (uniform normals):\n") + tl::to_string (m_shapes_program_uniform_normals->log ())); + } + static const char *lines_vertex_shader_source = "#version 120\n" "\n" @@ -1105,7 +1106,7 @@ D25ViewWidget::paintGL () glClearColor (float (c.red ()) / 255.0f, float (c.green ()) / 255.0f, float (c.blue ()) / 255.0f, 1.0); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if (! m_shapes_program || ! m_lines_program || ! m_gridplane_program) { + if (! m_shapes_program || ! m_shapes_program_uniform_normals || ! m_lines_program || ! m_gridplane_program) { return; } @@ -1167,6 +1168,69 @@ D25ViewWidget::paintGL () m_shapes_program->release (); + m_shapes_program_uniform_normals->bind (); + + // NOTE: z axis of illum points towards the scene because we include the z inversion in the scene transformation matrix + m_shapes_program_uniform_normals->setUniformValue ("illum", QVector3D (-3.0, -4.0, 2.0).normalized ()); + + m_shapes_program_uniform_normals->setUniformValue ("ambient", QVector4D (ambient, ambient, ambient, 1.0)); + m_shapes_program_uniform_normals->setUniformValue ("mist_factor", mist_factor); + m_shapes_program_uniform_normals->setUniformValue ("mist_add", mist_add); + + glEnable (GL_DEPTH_TEST); + glEnableVertexAttribArray (positions); + + for (std::vector::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { + + if (l->visible && l->fill_color [3] > 0.5) { + + const LayerInfo &li = *l; + for (auto z = li.flat_vertex_chunks.begin (); z != li.flat_vertex_chunks.end (); ++z) { + + QMatrix4x4 ytop; + ytop.translate (QVector3D (0.0, z->first.second, 0.0)); + + m_shapes_program_uniform_normals->setUniformValue ("matrix", cam_perspective () * cam_trans () * scene_trans * ytop); + + m_shapes_program_uniform_normals->setUniformValue ("normal", QVector4D (0.0, -1.0, 0.0, 1.0)); + m_shapes_program_uniform_normals->setUniformValue ("color", l->fill_color [0], l->fill_color [1], l->fill_color [2], l->fill_color [3]); + + triangle_chunks_type::iterator v = z->second->begin (); + + while (v != z->second->end ()) { + glVertexAttribPointer (positions, 3, gl_type2enum () (), GL_FALSE, 0, v->front ()); + // TODO: use glDrawElements to draw indexed buffers for better memory usage + glDrawArrays (GL_TRIANGLES, 0, GLsizei (v->size () / 3)); + ++v; + } + + QMatrix4x4 ybottom; + ybottom.translate (QVector3D (0.0, z->first.first, 0.0)); + + m_shapes_program_uniform_normals->setUniformValue ("matrix", cam_perspective () * cam_trans () * scene_trans * ybottom); + + m_shapes_program_uniform_normals->setUniformValue ("normal", QVector4D (0.0, 1.0, 0.0, 1.0)); + m_shapes_program_uniform_normals->setUniformValue ("color", l->fill_color [0], l->fill_color [1], l->fill_color [2], l->fill_color [3]); + + v = z->second->begin (); + + while (v != z->second->end ()) { + glVertexAttribPointer (positions, 3, gl_type2enum () (), GL_FALSE, 0, v->front ()); + // TODO: use glDrawElements to draw indexed buffers for better memory usage + glDrawArrays (GL_TRIANGLES, 0, GLsizei (v->size () / 3)); + ++v; + } + + } + + } + } + + glDisableVertexAttribArray (positions); + glDisableVertexAttribArray (normals); + + m_shapes_program_uniform_normals->release (); + // wire lines diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index fd4780fe6..9b5e1d236 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -87,7 +87,21 @@ public: struct LayerInfo { + struct ZRangeCompare + { + bool operator() (const std::pair &a, const std::pair &b) const + { + typedef db::coord_traits coord_traits; + if (coord_traits::equal (a.first, b.first)) { + return coord_traits::less (a.second, b.second); + } else { + return coord_traits::less (a.first, b.first); + } + } + }; + triangle_chunks_type *vertex_chunk; + std::map, triangle_chunks_type *, ZRangeCompare> flat_vertex_chunks; triangle_chunks_type *normals_chunk; line_chunks_type *line_chunk; GLfloat fill_color [4]; @@ -95,6 +109,17 @@ public: bool visible; std::string name; bool has_name; + + triangle_chunks_type *get_flat_vertex_chunks (double zstart, double zstop, std::list &flat_vertex_chunk_list) + { + auto i = flat_vertex_chunks.find (std::make_pair (zstart, zstop)); + if (i != flat_vertex_chunks.end ()) { + return i->second; + } + + flat_vertex_chunk_list.push_back (triangle_chunks_type ()); + return flat_vertex_chunks.insert (std::make_pair (std::make_pair (zstart, zstop), &flat_vertex_chunk_list.back ())).first->second; + } }; D25ViewWidget (QWidget *parent); @@ -182,7 +207,7 @@ public slots: private: std::unique_ptr mp_mode; - QOpenGLShaderProgram *m_shapes_program, *m_lines_program, *m_gridplane_program; + QOpenGLShaderProgram *m_shapes_program, *m_shapes_program_uniform_normals, *m_lines_program, *m_gridplane_program; std::string m_error; bool m_has_error; double m_scale_factor; @@ -195,6 +220,7 @@ private: bool m_display_open; std::list m_vertex_chunks; + std::list m_flat_vertex_chunks; std::list m_normals_chunks; std::list m_line_chunks; @@ -205,10 +231,10 @@ private: void resizeGL (int w, int h); void do_initialize_gl (); - void render_region (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &vertex_chunks, triangle_chunks_type &normals, D25ViewWidget::line_chunks_type &line_chunks, const db::Region ®ion, double dbu, const db::Box &clip_box, double zstart, double zstop); + void render_region (tl::AbsoluteProgress &progress, triangle_chunks_type &flat_chunks, D25ViewWidget::triangle_chunks_type &vertex_chunks, triangle_chunks_type &normals, D25ViewWidget::line_chunks_type &line_chunks, const db::Region ®ion, double dbu, const db::Box &clip_box, double zstart, double zstop); void render_edges (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &vertex_chunks, triangle_chunks_type &normals, D25ViewWidget::line_chunks_type &line_chunks, const db::Edges ®ion, double dbu, const db::Box &clip_box, double zstart, double zstop); void render_edge_pairs (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &vertex_chunks, triangle_chunks_type &normals, D25ViewWidget::line_chunks_type &line_chunks, const db::EdgePairs ®ion, double dbu, const db::Box &clip_box, double zstart, double zstop); - void render_polygon (D25ViewWidget::triangle_chunks_type &vertex_chunks, triangle_chunks_type &normals, D25ViewWidget::line_chunks_type &line_chunks, const db::Polygon &poly, double dbu, double zstart, double zstop); + void render_polygon (D25ViewWidget::triangle_chunks_type &vertex_chunks, const db::Polygon &poly, double dbu); void render_wall (D25ViewWidget::triangle_chunks_type &vertex_chunks, triangle_chunks_type &normals, D25ViewWidget::line_chunks_type &line_chunks, const db::Edge &poly, double dbu, double zstart, double zstop); void reset_viewport (); void enter (const db::RecursiveShapeIterator *iter, double zstart, double zstop);