diff --git a/qglengine/formats/loader_assimp.cpp b/qglengine/formats/loader_assimp.cpp index e43ae31..84ef98d 100644 --- a/qglengine/formats/loader_assimp.cpp +++ b/qglengine/formats/loader_assimp.cpp @@ -44,7 +44,7 @@ Mesh * assimpMesh(const aiMesh * m) { QVector & v(ret->vertices()); v.resize(vcnt); QVector & t(ret->texcoords()); t.resize(vcnt); - QVector< Vector3i> & ind(ret->indices()); + QVector< Vector3i> & ind(ret->indicesTriangles()); for (int i = 0; i < vcnt; ++i) v[i] = fromAiVector3D(m->mVertices[i]); diff --git a/qglengine/glmesh.cpp b/qglengine/glmesh.cpp index ced3d35..6c832d8 100644 --- a/qglengine/glmesh.cpp +++ b/qglengine/glmesh.cpp @@ -26,10 +26,11 @@ using namespace QGLEngineShaders; static int _count = 0; -Mesh::Mesh(): buffer_geom(GL_ARRAY_BUFFER, GL_STATIC_DRAW), - buffer_ind (GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW), - buffer_obj (GL_ARRAY_BUFFER, GL_STREAM_DRAW), - buffer_sel (GL_ARRAY_BUFFER, GL_STREAM_DRAW) { +Mesh::Mesh(GLenum geom_type_): geom_type(geom_type_), + buffer_geom(GL_ARRAY_BUFFER, GL_STATIC_DRAW), + buffer_ind (GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW), + buffer_obj (GL_ARRAY_BUFFER, GL_STREAM_DRAW), + buffer_sel (GL_ARRAY_BUFFER, GL_STREAM_DRAW) { vao = 0; hash_ = 0; changed = hash_changed = objects_changed = selected_changed = true; @@ -49,6 +50,8 @@ Mesh * Mesh::clone() { c->normals_ = normals_ ; c->texcoords_ = texcoords_; c->triangles_ = triangles_; + c->lines_ = lines_; + c->geom_type = geom_type; c->hash_ = hash_; c->hash_changed = hash_changed; //qDebug() << "clone VBO"; @@ -163,7 +166,8 @@ bool Mesh::rebuffer(QOpenGLExtraFunctions * f) { v.tex = texcoords_ [i]; } int gsize = data_.size() * sizeof(Vertex); - int isize = triangles_.size() * sizeof(Vector3i); + int tsize = triangles_.size() * sizeof(Vector3i); + int lsize = lines_.size() * sizeof(Vector2i); f->glBindVertexArray(vao); buffer_geom.bind(f); @@ -172,8 +176,13 @@ bool Mesh::rebuffer(QOpenGLExtraFunctions * f) { prepareDrawGeom(f); buffer_ind.bind(f); - buffer_ind.resize(f, isize); - buffer_ind.load(f, triangles_.constData(), isize); + if (geom_type == GL_TRIANGLES) { + buffer_ind.resize(f, tsize); + buffer_ind.load(f, triangles_.constData(), tsize); + } else { + buffer_ind.resize(f, lsize); + buffer_ind.load(f, lines_.constData(), lsize); + } buffer_obj.bind(f); prepareDrawObj(f); @@ -247,10 +256,13 @@ void Mesh::draw(QOpenGLExtraFunctions * f, int count) { if (isEmpty()) return; if (!isInit()) init(f); if (changed) rebuffer(f); - //qDebug() << "draw" << vert_count << count; + //qDebug() << "draw" << geom_type << vert_count << count; f->glBindVertexArray(vao); - f->glDrawElementsInstanced(GL_TRIANGLES, triangles_.size() * 3, GL_UNSIGNED_INT, 0, count); + if (geom_type == GL_TRIANGLES) + f->glDrawElementsInstanced(geom_type, triangles_.size() * 3, GL_UNSIGNED_INT, 0, count); + else + f->glDrawElementsInstanced(geom_type, lines_.size() * 2, GL_UNSIGNED_INT, 0, count); f->glBindVertexArray(0); } @@ -262,6 +274,7 @@ void Mesh::clear() { bitangents_.clear(); texcoords_.clear(); triangles_.clear(); + lines_.clear(); data_.clear(); changed = hash_changed = true; } @@ -290,6 +303,7 @@ uint Mesh::hash() const { hash_ ^= qHashBits(normals_ .constData(), normals_ .size() * sizeof(QVector3D)); hash_ ^= qHashBits(texcoords_.constData(), texcoords_.size() * sizeof(QVector2D)); hash_ ^= qHashBits(triangles_.constData(), triangles_.size() * sizeof( Vector3i)); + hash_ ^= qHashBits(lines_ .constData(), lines_ .size() * sizeof( Vector2i)); } return hash_; } @@ -327,6 +341,10 @@ void Mesh::append(const Mesh * m) { for (int i = 0; i < tri.size(); ++i) tri[i] += vcnt; triangles_.append(tri); + QVector lin = m->lines_; + for (int i = 0; i < lin.size(); ++i) + lin[i] += vcnt; + lines_.append(lin); } @@ -336,7 +354,7 @@ bool Mesh::saveToFile(const QString & filename) { QByteArray ba; if (f.open(QFile::WriteOnly)) { QDataStream out(&ba, QFile::WriteOnly); - out << vertices_ << normals_ << texcoords_ << triangles_; + out << vertices_ << normals_ << texcoords_ << triangles_ << lines_; ba = qCompress(ba); f.resize(0); f.write(ba); @@ -356,7 +374,7 @@ bool Mesh::loadFromFile(const QString & filename) { if (ba.isEmpty()) return false; ba = qUncompress(ba); QDataStream in(ba); - in >> vertices_ >> normals_ >> texcoords_ >> triangles_; + in >> vertices_ >> normals_ >> texcoords_ >> triangles_ >> lines_; changed = hash_changed = true; f.close(); return !isEmpty(); @@ -397,7 +415,8 @@ Box3D Mesh::boundingBox() const { QDataStream & operator <<(QDataStream & s, const Mesh * m) { ChunkStream cs; //qDebug() << "place VBO" << m.vertices_.size() << m.normals_.size() << m.texcoords_.size() << m.colors_.size() << "..."; - cs.add(1, m->vertices_).add(2, m->normals_).add(3, m->texcoords_).add(6, m->triangles_); + cs.add(1, m->vertices_).add(2, m->normals_).add(3, m->texcoords_) + .add(6, m->triangles_).add(7, m->lines_).add(10, int(m->geom_type)); //qDebug() << "place VBO done" << cs.data().size() << "..."; s << /*qCompress*/(cs.data()); return s; } @@ -411,10 +430,12 @@ QDataStream & operator >>(QDataStream & s, Mesh *& m) { ChunkStream cs(s); while (!cs.atEnd()) { switch (cs.read()) { - case 1: cs.get(m->vertices_ ); break; - case 2: cs.get(m->normals_ ); break; - case 3: cs.get(m->texcoords_); break; - case 6: cs.get(m->triangles_); break; + case 1 : cs.get(m->vertices_ ); break; + case 2 : cs.get(m->normals_ ); break; + case 3 : cs.get(m->texcoords_); break; + case 6 : cs.get(m->triangles_); break; + case 7 : cs.get(m->lines_ ); break; + case 10: m->geom_type = cs.getData(); break; } } m->changed = true; diff --git a/qglengine/glmesh.h b/qglengine/glmesh.h index 9bb770c..c1b98eb 100644 --- a/qglengine/glmesh.h +++ b/qglengine/glmesh.h @@ -32,7 +32,7 @@ class Mesh friend QDataStream & operator <<(QDataStream & s, const Mesh * m); friend QDataStream & operator >>(QDataStream & s, Mesh *& m); public: - Mesh(); + Mesh(GLenum geom_type_ = GL_TRIANGLES); ~Mesh(); Mesh * clone(); @@ -50,6 +50,7 @@ public: int verticesCount() const {return vertices_.size();} int trianglesCount() const {return triangles_.size();} + int linesCount() const {return lines_.size();} bool isInit() const {return vao != 0;} bool isEmpty() const {return vertices_.isEmpty();} uint hash() const; @@ -57,10 +58,12 @@ public: QVector & vertices () {changed = hash_changed = true; return vertices_;} QVector & normals () {changed = hash_changed = true; return normals_;} QVector & texcoords() {changed = hash_changed = true; return texcoords_;} - QVector< Vector3i> & indices () {changed = hash_changed = true; return triangles_;} + QVector< Vector3i> & indicesTriangles() {changed = hash_changed = true; return triangles_;} + QVector< Vector2i> & indicesLines () {changed = hash_changed = true; return lines_;} void translatePoints(const QVector3D & dp); void scalePoints (const QVector3D & dp); + void scalePoints (const double & s) {scalePoints(QVector3D(s, s, s));} void append(const Mesh * m); bool saveToFile(const QString & filename); @@ -80,9 +83,10 @@ private: QVector vertices_, normals_, tangents_, bitangents_; QVector texcoords_; QVector< Vector3i> triangles_; + QVector< Vector2i> lines_; QVector data_; - GLenum vao; + GLenum vao, geom_type; Buffer buffer_geom, buffer_ind, buffer_obj, buffer_sel; mutable uint hash_; mutable bool hash_changed; diff --git a/qglengine/globject.h b/qglengine/globject.h index 152018b..3b8c810 100644 --- a/qglengine/globject.h +++ b/qglengine/globject.h @@ -29,6 +29,8 @@ class ObjectBase friend class QGLView; friend class Scene; friend class Renderer; + friend class RendererService; + friend class RendererSelection; friend QDataStream & operator <<(QDataStream & s, const ObjectBase * p); friend QDataStream & operator >>(QDataStream & s, ObjectBase *& p); friend QDataStream & operator >>(QDataStream & s, Scene *& p); diff --git a/qglengine/glprimitives.cpp b/qglengine/glprimitives.cpp index 4f201d4..97c4855 100644 --- a/qglengine/glprimitives.cpp +++ b/qglengine/glprimitives.cpp @@ -27,7 +27,7 @@ Mesh * Primitive::plane(float width, float length) { QVector & v(ret->vertices ()); QVector & n(ret->normals ()); QVector & t(ret->texcoords()); - QVector< Vector3i> & i(ret->indices ()); + QVector< Vector3i> & i(ret->indicesTriangles ()); float hw = width / 2.f, hl = length / 2.f; for (int j = 0; j < 4; ++j) n << QVector3D(0., 0., 1.); t << QVector2D(0., 0.) << QVector2D(0., 1.) << QVector2D(1., 1.) << QVector2D(1., 0.); @@ -43,7 +43,7 @@ Mesh * Primitive::cube(float width, float length, float height) { QVector & v(ret->vertices ()); QVector & n(ret->normals ()); QVector & t(ret->texcoords()); - QVector< Vector3i> & i(ret->indices ()); + QVector< Vector3i> & i(ret->indicesTriangles ()); float hs = 0.5f; int si = 0; QMatrix4x4 mat; @@ -92,7 +92,7 @@ Mesh * Primitive::ellipsoid(int segments_wl, int segments_h, float width, float QVector & v(ret->vertices ()); QVector & n(ret->normals ()); QVector & t(ret->texcoords()); - QVector< Vector3i> & ind(ret->indices()); + QVector< Vector3i> & ind(ret->indicesTriangles()); double hh = height / 2.f; int hseg = segments_h + 1, wlseg = segments_wl + 1; double crw, crl, a, ch, twl; @@ -131,7 +131,7 @@ Mesh * Primitive::disc(int segments, float width, float length, bool up) { QVector & v(ret->vertices ()); QVector & n(ret->normals ()); QVector & t(ret->texcoords()); - QVector< Vector3i> & ind(ret->indices()); + QVector< Vector3i> & ind(ret->indicesTriangles()); segments = qMax(segments + 1, 4); QVector3D cp; @@ -176,7 +176,7 @@ Mesh * Primitive::cone(int segments, float width, float length, float height) { QVector & v(ret->vertices ()); QVector & n(ret->normals ()); QVector & t(ret->texcoords()); - QVector< Vector3i> & ind(ret->indices()); + QVector< Vector3i> & ind(ret->indicesTriangles()); int seg = qMax(segments + 1, 4); double rx = width / 2., ry = length / 2.; @@ -212,7 +212,7 @@ Mesh * Primitive::cylinder(int segments, float width, float length, float height QVector & v(ret->vertices ()); QVector & n(ret->normals ()); QVector & t(ret->texcoords()); - QVector< Vector3i> & ind(ret->indices()); + QVector< Vector3i> & ind(ret->indicesTriangles()); int seg = qMax(segments + 1, 4); double rx = width / 2., ry = length / 2.; @@ -261,3 +261,66 @@ Mesh * Primitive::arrow(int segments, float thick, float angle) { delete m; return ret; } + + +Mesh * Primitive::cubeFrame(float width, float length, float height) { + Mesh * ret = new Mesh(GL_LINES); + QVector3D scale(width, length, height); + QVector & v(ret->vertices ()); + QVector & n(ret->normals ()); + QVector & t(ret->texcoords()); + QVector< Vector2i> & i(ret->indicesLines()); + float hs = 0.5f; + v << QVector3D(-hs, -hs, -hs) << QVector3D(-hs, hs, -hs) << QVector3D( hs, hs, -hs) << QVector3D( hs, -hs, -hs); + v << QVector3D(-hs, -hs, hs) << QVector3D(-hs, hs, hs) << QVector3D( hs, hs, hs) << QVector3D( hs, -hs, hs); + for (int j = 0; j < 8; ++j) { + v[j] *= scale; + t << QVector2D(0, 0); + n << QVector3D(0,0,1); + } + for (int j = 0; j < 4; ++j) { + i << Vector2i(j, (j + 1) % 4); + i << Vector2i(j, j + 4); + i << Vector2i(j + 4, (j + 1) % 4 + 4); + } + return ret; +} + + +Mesh * Primitive::ellipsoidFrame(int segments_wl, int segments_h, float width, float length, float height) { + Mesh * ret = new Mesh(GL_LINES); + QVector & v(ret->vertices ()); + QVector & n(ret->normals ()); + QVector & t(ret->texcoords()); + QVector< Vector2i> & ind(ret->indicesLines()); + double hh = height / 2.f; + int hseg = segments_h + 1, wlseg = segments_wl + 1; + double crw, crl, a, ch, twl; + + QVector3D cp; + for (int i = 0; i <= hseg; i++) { + ch = -cos((double)i / hseg * M_PI); + cp.setZ(ch * hh); + twl = sqrt(1. - ch * ch) / 2.; + crw = twl * width; + crl = twl * length; + int cvcnt = wlseg * 2; + for (int j = 0; j < cvcnt; j++) { + a = (double)j / (cvcnt - 1) * M_2PI; + cp.setX(crl * cos(a)); + cp.setY(crw * sin(a)); + v << cp; t << QVector2D((double)j / (cvcnt - 1), ch/2.f + 0.5f); + int si = v.size() - 1; + if (j > 0 && i > 0) { + ind << Vector2i(si, si - 1); + ind << Vector2i(si - cvcnt, si); + } + } + } + + n.resize(v.size()); + for (int i = 0; i < v.size(); i++) + n[i] = v[i].normalized(); + + return ret; +} diff --git a/qglengine/glprimitives.h b/qglengine/glprimitives.h index 87657d6..96f8a35 100644 --- a/qglengine/glprimitives.h +++ b/qglengine/glprimitives.h @@ -40,6 +40,10 @@ Mesh * cylinder(int segments, float width = 1., float length = 1., float height Mesh * arrow(int segments = 16, float thick = 0.04, float angle = 30.); // length = 1 +Mesh * cubeFrame(float width = 1., float length = 1., float height = 1.); + +Mesh * ellipsoidFrame(int segments_wl, int segments_h, float width = 1., float length = 1., float height = 1.); + } /* diff --git a/qglengine/glscene.h b/qglengine/glscene.h index 8a4b556..df11031 100644 --- a/qglengine/glscene.h +++ b/qglengine/glscene.h @@ -29,6 +29,7 @@ class Scene: public QObject { friend class Renderer; friend class RendererMaterial; friend class RendererService; + friend class RendererSelection; friend class ObjectBase; friend class Light; friend QDataStream & operator <<(QDataStream & s, const Scene * p); diff --git a/qglengine/gltypes.cpp b/qglengine/gltypes.cpp index 6132e8e..2d03b41 100644 --- a/qglengine/gltypes.cpp +++ b/qglengine/gltypes.cpp @@ -275,6 +275,14 @@ void lengthenVector(QVector3D & v, const float & l) { } +Vector2i::Vector2i(const QString & str) { + QString s = str.trimmed(); + int i = s.indexOf("\t"); + p0 = s.left(i).toInt(); s = s.right(s.length() - i - 1); + p1 = s.toInt(); +} + + Vector3i::Vector3i(const QString & str) { QString s = str.trimmed(); int i = s.indexOf("\t"); diff --git a/qglengine/gltypes.h b/qglengine/gltypes.h index caa3f9e..cc55be2 100644 --- a/qglengine/gltypes.h +++ b/qglengine/gltypes.h @@ -178,6 +178,8 @@ class RendererBase; class Renderer; class RendererMaterial; class RendererService; +class RendererSelection; + struct Box3D { GLfloat x; @@ -211,6 +213,33 @@ struct Box3D { inline QDebug operator <<(QDebug d, const Box3D & v) {d << "Box3D {start (" << v.x << "," << v.y << "," << v.z << "), size (" << v.length << "," << v.width << "," << v.height << ")}"; return d;} + +#pragma pack(push, 1) +struct Vector2i { + Vector2i(int p0_ = 0, int p1_ = 0) {p0 = p0_; p1 = p1_;} + Vector2i(const QString & str); + Vector2i movedX(const int & o) {return Vector2i(p0 + o, p1);} + Vector2i movedY(const int & o) {return Vector2i(p0, p1 + o);} + Vector2i moved(const int & x, const int & y) {return Vector2i(p0 + x, p1 + y);} + GLint p0; + GLint p1; + bool operator ==(const Vector2i & o) const {return p0 == o.p0 && p1 == o.p1;} + bool operator !=(const Vector2i & o) const {return p0 != o.p0 || p1 != o.p1;} + void operator +=(int v) {p0 += v; p1 += v;} + QVector2D toQVector2D() const {return QVector2D(p0, p1);} +}; +#pragma pack(pop) + +inline Vector2i operator +(const Vector2i & f, const Vector2i & s) {return Vector2i(f.p0 + s.p0, f.p1 + s.p1);} +inline Vector2i operator -(const Vector2i & f, const Vector2i & s) {return Vector2i(f.p0 - s.p0, f.p1 - s.p1);} +inline Vector2i operator /(const Vector2i & f, const int & s) {return Vector2i(f.p0 / s, f.p1 / s);} +inline uint qHash(const Vector2i & v) {return v.p0 ^ ((v.p1 << 8) | (v.p1 >> 24));} +inline QDebug operator <<(QDebug d, const Vector2i & v) {d.nospace() << "{" << v.p0 << ", " << v.p1 << "}"; return d.space();} + +inline QDataStream & operator <<(QDataStream & s, const Vector2i & v) {s << v.p0 << v.p1; return s;} +inline QDataStream & operator >>(QDataStream & s, Vector2i & v) {s >> v.p0 >> v.p1; return s;} + + #pragma pack(push, 1) struct Vector3i { Vector3i(int p0_ = 0, int p1_ = 0, int p2_ = 0) {p0 = p0_; p1 = p1_; p2 = p2_;} @@ -238,6 +267,7 @@ inline QDebug operator <<(QDebug d, const Vector3i & v) {d.nospace() << "{" << v inline QDataStream & operator <<(QDataStream & s, const Vector3i & v) {s << v.p0 << v.p1 << v.p2; return s;} inline QDataStream & operator >>(QDataStream & s, Vector3i & v) {s >> v.p0 >> v.p1 >> v.p2; return s;} + QVector3D vectorFromString(const QString & str); QColor colorFromString(const QString & str); inline QVector4D QColor2QVector(const QColor & c) {return QVector4D(c.redF(), c.greenF(), c.blueF(), c.alphaF());} diff --git a/qglengine/qglview.cpp b/qglengine/qglview.cpp index 41dd4a8..7bf1ade 100644 --- a/qglengine/qglview.cpp +++ b/qglengine/qglview.cpp @@ -91,7 +91,7 @@ QGLView::QGLView(): OpenGLWindow(), renderer_(this) { //camera().aim_ = camera().pos_; ktm_.restart(); - Mesh * m = Primitive::cube(); + Mesh * m = Primitive::ellipsoidFrame(5,5); ObjectBase * o = new ObjectBase(m); o->setColor(Qt::cyan); scene()->addObject(o); diff --git a/qglengine/qglview.h b/qglengine/qglview.h index f660c6c..8478ad8 100644 --- a/qglengine/qglview.h +++ b/qglengine/qglview.h @@ -39,6 +39,7 @@ class QGLView: public OpenGLWindow friend class Renderer; friend class RendererMaterial; friend class RendererService; + friend class RendererSelection; Q_OBJECT Q_PROPERTY (QColor backColor READ backColor WRITE setBackColor) Q_PROPERTY (float lineWidth READ lineWidth WRITE setLineWidth) diff --git a/qglengine/renderer.cpp b/qglengine/renderer.cpp index b639440..07471d4 100644 --- a/qglengine/renderer.cpp +++ b/qglengine/renderer.cpp @@ -28,25 +28,22 @@ using namespace QGLEngineShaders; Renderer::Renderer(QGLView * view_): RendererBase(view_), - fbo_selection(view_, 4), fbo_ds (view_, 5, true , GL_RGBA16F), fbo_out (view_, 3, false, GL_RGBA16F), fbo_hsmall (view_, 1, false, GL_RGB16F ), - rend_mat(this), rend_service(this) { + rend_mat(this), rend_service(this), rend_selection(this) { quad = Primitive::plane(2., 2.); - sel_frame = quad->clone(); cam_light = new Light(); cam_light->intensity = 0.75; cam_light->setName("Camera_Light"); - line_thick_ = 2.; - id_hover = 0; shader_files[srSelectionFill ] = "selection.glsl"; shader_files[srSelectionHalo ] = "selection_halo.glsl"; shader_files[srSelectionApply] = "selection_apply.glsl"; shader_files[srSelectionFrame] = "selection_frame.glsl"; - shader_files[srService] = "service.glsl"; + shader_files[srServiceFill ] = "service_fill.glsl"; + shader_files[srServiceFrame] = "service_frame.glsl"; shader_files[srGeometryPass] = "ds_geom.glsl"; shader_files[srLightingPass] = "ds_light.glsl"; @@ -70,13 +67,11 @@ Renderer::Renderer(QGLView * view_): RendererBase(view_), << ShaderPair("dof", &shader_dof);*/ exposure_ = 1.; edit_mode = need_init_shaders = is_camera_light = true; - proc_sel_pbo = false; } Renderer::~Renderer() { delete quad; - delete sel_frame; delete cam_light; qDeleteAll(shaders.values()); } @@ -86,6 +81,7 @@ void Renderer::init(int width, int height) { resize(width, height); rend_mat.init(width, height); rend_service.init(width, height); + rend_selection.init(width, height); initQuad(quad); initTextureArrays(); need_init_shaders = true; @@ -95,12 +91,10 @@ void Renderer::init(int width, int height) { void Renderer::resize(int width, int height) { rend_mat.resize(width, height); rend_service.resize(width, height); - fbo_selection.enablePixelBuffer(); - fbo_selection.resize(width, height); + rend_selection.resize(width, height); fbo_ds .resize(width, height); fbo_out .resize(width, height); fbo_hsmall .resize(width / 16, height / 16); - line_thick_ = lineThickness() + 1.; } @@ -139,28 +133,6 @@ void Renderer::releaseShader() { } -void Renderer::generateObjectsID(Scene & scene) { - ids.clear(); - QMapIterator > it(scene.geometries_used); - while (it.hasNext()) { - it.next(); - foreach (ObjectBase * o, it.value()) { - uint id = qHash(o); - ids[id] = o; - o->id_ = id; - } - } -} - - -void Renderer::fillSelectionsBuffer(const QList & ol) { - cur_selections_.resize(ol.size()); - for (int i = 0; i < ol.size(); ++i) { - cur_selections_[i] = (ol[i]->isSelected(true) ? 1 : 0); - } -} - - void Renderer::fillObjectsBuffer(const QList & ol, RenderPass pass) { cur_objects_.resize(ol.size()); for (int i = 0; i < ol.size(); ++i) { @@ -195,94 +167,14 @@ void Renderer::renderObjects(Scene & scene, RenderPass pass) { } if (mesh->selected_changed && edit_mode) { mesh->selected_changed = false; - fillSelectionsBuffer(it.value()); - mesh->loadSelections(f, cur_selections_); + rend_selection.fillSelectionsBuffer(it.value()); + mesh->loadSelections(f, rend_selection.cur_selections_); } mesh->draw(f, it.value().size()); } } -void Renderer::renderSelection(Scene & scene) { - QOpenGLShaderProgram * prog = 0; - if (bindShader(srSelectionFill, &prog)) { - view->hov_objects.clear(); - id_hover = 0; - if (fbo_selection.queriedPoints() > 0) { - if (fbo_selection.queriedPoints() == 1) { - id_hover = fbo_selection.getPoint(); - view->hov_objects.resize(1); - view->hov_objects[0] = ids.value(id_hover); - //qDebug() << id_hover; - } else { - QVector points = fbo_selection.getPoints(); - QSet ids_hover; - foreach (uint i, points) - ids_hover << i; - view->hov_objects.clear(); - foreach (uint i, ids_hover) - view->hov_objects << ids.value(i); - //qDebug() << ids_hover; - } - } - - fbo_selection.bind(); - - fbo_selection.setWriteBuffers(); - glEnableDepth(); - glClearFramebuffer(QColor(0,0,0,0)); - setUniformCamera(prog, view->camera()); - renderObjects(scene, rpSelection); - //mouse_rect = fbo_selection.rect(); - if (mouse_rect.isNull()) - fbo_selection.queryPoint(0, mouse_pos); - else - fbo_selection.queryPoints(0, mouse_rect); - - //qDebug() << id_hover; - fbo_selection.bindColorTextures(); - fbo_selection.setWriteBuffers(); - if (!view->hoverHalo_ && !view->selectionHalo_) - glClearFramebuffer(QColor(0,0,0,0), false); - else { - bindShader(srSelectionHalo, &prog); - setUniformHalo(prog, "hover" , view->hoverHaloColor() , view->hoverHaloFillAlpha()); - setUniformHalo(prog, "selection", view->selectionHaloColor(), view->selectionHaloFillAlpha()); - prog->setUniformValue("has_hover" , view->hoverHalo_ && (id_hover > 0) ? 1.f : 0.f); - prog->setUniformValue("has_selection", view->selectionHalo_ ? 1.f : 0.f); - prog->setUniformValue("fb_hover" , (int)sbrSrcHover); - prog->setUniformValue("fb_selection", (int)sbrSrcSelect); - prog->setUniformValue("hover_id", QVector4D(float( id_hover & 0xFF) / 255.f, - float((id_hover >> 8 ) & 0xFF) / 255.f, - float((id_hover >> 16) & 0xFF) / 255.f, - float((id_hover >> 24) & 0xFF) / 255.f)); - renderQuad(prog, quad, view->camera()); - } - - fbo_selection.release(); - } -} - - -void Renderer::renderSelectionFrame() { - QOpenGLShaderProgram * prog = 0; - if (bindShader(srSelectionFrame, &prog)) { - QMatrix4x4 mat; - double mrx = mouse_rect.x(), mrw = mouse_rect.width() , vw = view->width(); - double mry = mouse_rect.y(), mrh = mouse_rect.height(), vh = view->height(); - mat.translate(-1. + (mrw + mrx*2) / vw, 1. - (mrh + mry*2) / vh, 0.); - mat.scale(mrw / vw, mrh / vh, 0.); - initQuad(sel_frame, mat); - prog->setUniformValue("size", QVector2D(mrw / vw, mrh / vh)); - prog->setUniformValue("thickness", line_thick_); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - renderQuad(prog, sel_frame); - glDisable(GL_BLEND); - } -} - - void Renderer::renderScene() { initShaders(); QOpenGLExtraFunctions * f = view; @@ -295,7 +187,7 @@ void Renderer::renderScene() { if (scene_changed || scene.need_reload_materials) { if (scene.need_reload_materials) maps_hash = 0; - generateObjectsID(scene); + rend_selection.generateObjectsID(scene); reloadMaterials(scene); if (edit_mode) recreateMaterialThumbnails(); @@ -321,7 +213,7 @@ void Renderer::renderScene() { /// selection if (edit_mode) { - renderSelection(scene); + rend_selection.renderSelection(scene); } /// geometry pass @@ -362,20 +254,8 @@ void Renderer::renderScene() { /// apply hovers and selection frame if (edit_mode) { - if (bindShader(srSelectionApply, &prog)) { - fbo_selection.bindColorTextures(); - fbo_out.bindColorTexture(0); - prog->setUniformValue("fb_out" , 0); - prog->setUniformValue("fb_hover" , (int)sbrHovered ); - prog->setUniformValue("fb_select", (int)sbrSelected); - renderQuad(prog, quad, cam); - - if (!mouse_rect.isNull()) { - renderSelectionFrame(); - } - - rend_service.renderService(); - } + rend_selection.drawSelection(fbo_out); + rend_service.renderService(); } else { fbo_out.blit(0, 0, 0, fbo_out.rect(), QRect(QPoint(), view->size())); } diff --git a/qglengine/renderer.h b/qglengine/renderer.h index 1586581..1e7e6d9 100644 --- a/qglengine/renderer.h +++ b/qglengine/renderer.h @@ -22,6 +22,7 @@ #include "renderer_base.h" #include "renderer_material.h" #include "renderer_service.h" +#include "renderer_selection.h" #include @@ -29,6 +30,7 @@ class Renderer: public RendererBase { friend class QGLView; friend class RendererMaterial; friend class RendererService; + friend class RendererSelection; enum RenderPass { rpSolid, rpTransparent, @@ -44,7 +46,8 @@ class Renderer: public RendererBase { srSelectionFrame, // Service - srService, + srServiceFill, + srServiceFrame, // Deferred shading srGeometryPass, @@ -58,12 +61,6 @@ class Renderer: public RendererBase { dbrEmissionBitangX, dbrSpeedBitangXY, }; - enum SelectionBufferRole { - sbrSrcHover, - sbrSrcSelect, - sbrHovered, - sbrSelected - }; public: Renderer(QGLView * view_); @@ -80,22 +77,18 @@ public: void recreateMaterialThumbnails(bool force_all = false) {rend_mat.recreateMaterialThumbnails(force_all);} protected: - void generateObjectsID(Scene & scene); - void fillSelectionsBuffer(const QList & ol); void fillObjectsBuffer(const QList & ol, RenderPass pass); void reloadObjects(); void renderObjects(Scene & scene, RenderPass pass); - void renderSelection(Scene & scene); - void renderSelectionFrame(); bool bindShader(ShaderRole role, QOpenGLShaderProgram ** ret = 0); void initShaders(); void releaseShader(); private: - float exposure_, line_thick_; - bool edit_mode, proc_sel_pbo, need_init_shaders, is_camera_light; - Framebuffer fbo_selection, fbo_ds, fbo_out, fbo_hsmall; + float exposure_; + bool edit_mode, need_init_shaders, is_camera_light; + Framebuffer fbo_ds, fbo_out, fbo_hsmall; /*QOpenGLShaderProgram * shader_fxaa, * shader_ds_0, * shader_ds_1, * shader_hdr, * shader_small; QOpenGLShaderProgram * shader_bloom_0, * shader_bloom_1, * shader_motion_blur, * shader_fbo_add; QOpenGLShaderProgram * shader_shadow, * shader_ssr, * shader_ssr_blur, * shader_ssr_merge; @@ -105,12 +98,11 @@ private: RendererMaterial rend_mat; RendererService rend_service; + RendererSelection rend_selection; - Mesh * quad, * sel_frame; + Mesh * quad; Light * cam_light; - QHash ids; - uint id_hover; QPoint mouse_pos; QRect mouse_rect; QMatrix4x4 prev_view, prev_proj; diff --git a/qglengine/renderer_base.h b/qglengine/renderer_base.h index 1d2cbc2..c84f304 100644 --- a/qglengine/renderer_base.h +++ b/qglengine/renderer_base.h @@ -50,7 +50,6 @@ protected: QVector cur_materials_; QVector cur_lights_params_; QVector cur_lights_pos_; - QVector cur_selections_; Buffer buffer_materials; Buffer buffer_lights, buffer_lights_pos; Texture2DArray textures_empty, textures_maps; diff --git a/qglengine/renderer_selection.cpp b/qglengine/renderer_selection.cpp new file mode 100644 index 0000000..38fb713 --- /dev/null +++ b/qglengine/renderer_selection.cpp @@ -0,0 +1,184 @@ +/* + QGLView + Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#define GL_GLEXT_PROTOTYPES +#include +#include "renderer_selection.h" +#include "qglview.h" +#include "glmesh.h" +#include + +using namespace QGLEngineShaders; + + +RendererSelection::RendererSelection(Renderer * r_): r(r_), + fbo_selection(r->view, 4) { + sel_frame = Primitive::plane(2., 2.); + id_hover = 0; + line_thick_ = 2.; +} + + +RendererSelection::~RendererSelection() { + delete sel_frame; +} + + +void RendererSelection::init(int width, int height) { + resize(width, height); +} + + +void RendererSelection::resize(int width, int height) { + fbo_selection.enablePixelBuffer(); + fbo_selection.resize(width, height); + line_thick_ = lineThickness() + 1.; +} + + +void RendererSelection::generateObjectsID(Scene & scene) { + ids.clear(); + QMapIterator > it(scene.geometries_used); + while (it.hasNext()) { + it.next(); + foreach (ObjectBase * o, it.value()) { + uint id = qHash(o); + ids[id] = o; + o->id_ = id; + } + } + foreach (ObjectBase * o, scene.lights_used) { + uint id = qHash(o); + ids[id] = o; + o->id_ = id; + } +} + + +void RendererSelection::fillSelectionsBuffer(const QList & ol) { + cur_selections_.resize(ol.size()); + for (int i = 0; i < ol.size(); ++i) { + cur_selections_[i] = (ol[i]->isSelected(true) ? 1 : 0); + } +} + + +void RendererSelection::renderSelection(Scene & scene) { + QOpenGLShaderProgram * prog = 0; + QGLView * view = r->view; + if (r->bindShader(Renderer::srSelectionFill, &prog)) { + view->hov_objects.clear(); + id_hover = 0; + if (fbo_selection.queriedPoints() > 0) { + if (fbo_selection.queriedPoints() == 1) { + id_hover = fbo_selection.getPoint(); + view->hov_objects.resize(1); + view->hov_objects[0] = ids.value(id_hover); + //qDebug() << id_hover; + } else { + QVector points = fbo_selection.getPoints(); + QSet ids_hover; + foreach (uint i, points) + ids_hover << i; + view->hov_objects.clear(); + foreach (uint i, ids_hover) + view->hov_objects << ids.value(i); + //qDebug() << ids_hover; + } + } + + fbo_selection.bind(); + + fbo_selection.setWriteBuffers(); + glEnableDepth(); + glClearFramebuffer(QColor(0,0,0,0)); + r->setUniformCamera(prog, view->camera()); + r->renderObjects(scene, Renderer::rpSelection); + view->glClear(GL_DEPTH_BUFFER_BIT); + + RendererService & rs(r->rend_service); + rs.fillOmniObjects(); + rs.omni_mesh->loadObjects(view, rs.cur_objects); + fillSelectionsBuffer(light2objectList(scene.lights_used)); + rs.omni_mesh->loadSelections(view, cur_selections_); + rs.omni_mesh->draw(view, rs.cur_objects.size()); + + //mouse_rect = fbo_selection.rect(); + if (r->mouse_rect.isNull()) + fbo_selection.queryPoint(0, r->mouse_pos); + else + fbo_selection.queryPoints(0, r->mouse_rect); + + //qDebug() << id_hover; + fbo_selection.bindColorTextures(); + fbo_selection.setWriteBuffers(); + if (!view->hoverHalo_ && !view->selectionHalo_) + glClearFramebuffer(QColor(0,0,0,0), false); + else { + r->bindShader(Renderer::srSelectionHalo, &prog); + r->setUniformHalo(prog, "hover" , view->hoverHaloColor() , view->hoverHaloFillAlpha()); + r->setUniformHalo(prog, "selection", view->selectionHaloColor(), view->selectionHaloFillAlpha()); + prog->setUniformValue("has_hover" , view->hoverHalo_ && (id_hover > 0) ? 1.f : 0.f); + prog->setUniformValue("has_selection", view->selectionHalo_ ? 1.f : 0.f); + prog->setUniformValue("fb_hover" , (int)sbrSrcHover); + prog->setUniformValue("fb_selection", (int)sbrSrcSelect); + prog->setUniformValue("hover_id", QVector4D(float( id_hover & 0xFF) / 255.f, + float((id_hover >> 8 ) & 0xFF) / 255.f, + float((id_hover >> 16) & 0xFF) / 255.f, + float((id_hover >> 24) & 0xFF) / 255.f)); + r->renderQuad(prog, r->quad, view->camera()); + } + + fbo_selection.release(); + } +} + + +void RendererSelection::renderSelectionFrame() { + QOpenGLShaderProgram * prog = 0; + if (r->bindShader(Renderer::srSelectionFrame, &prog)) { + QMatrix4x4 mat; + double mrx = r->mouse_rect.x(), mrw = r->mouse_rect.width() , vw = r->view->width(); + double mry = r->mouse_rect.y(), mrh = r->mouse_rect.height(), vh = r->view->height(); + mat.translate(-1. + (mrw + mrx*2) / vw, 1. - (mrh + mry*2) / vh, 0.); + mat.scale(mrw / vw, mrh / vh, 0.); + r->initQuad(sel_frame, mat); + prog->setUniformValue("size", QVector2D(mrw / vw, mrh / vh)); + prog->setUniformValue("thickness", line_thick_); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + r->renderQuad(prog, sel_frame); + glDisable(GL_BLEND); + } +} + + +void RendererSelection::drawSelection(Framebuffer & fbo_out, int index_out) { + QOpenGLShaderProgram * prog = 0; + if (r->bindShader(Renderer::srSelectionApply, &prog)) { + fbo_selection.bindColorTextures(); + fbo_out.bindColorTexture(index_out); + prog->setUniformValue("fb_out" , 0); + prog->setUniformValue("fb_hover" , (int)sbrHovered ); + prog->setUniformValue("fb_select", (int)sbrSelected); + r->renderQuad(prog, r->quad, r->view->camera()); + if (!r->mouse_rect.isNull()) { + renderSelectionFrame(); + } + } +} diff --git a/qglengine/renderer_selection.h b/qglengine/renderer_selection.h new file mode 100644 index 0000000..82b5cd5 --- /dev/null +++ b/qglengine/renderer_selection.h @@ -0,0 +1,65 @@ +/* + QGLView + Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef RENDERER_SELECTION_H +#define RENDERER_SELECTION_H + +#include "renderer_service.h" +#include + + +class RendererSelection { + friend class QGLView; + friend class Renderer; + +public: + RendererSelection(Renderer * r_); + virtual ~RendererSelection(); + + void init(int width, int height); + void resize(int width, int height); + +protected: + enum SelectionBufferRole { + sbrSrcHover, + sbrSrcSelect, + sbrHovered, + sbrSelected + }; + + void generateObjectsID(Scene & scene); + void fillSelectionsBuffer(const QList & ol); + void renderSelection(Scene & scene); + void renderSelectionFrame(); + void drawSelection(Framebuffer & fbo_out, int index_out = 0); + QList light2objectList(const QList & v) {QList ret; foreach (Light*i, v) ret << (ObjectBase*)i; return ret;} + +private: + Renderer * r; + + Framebuffer fbo_selection; + Mesh * sel_frame; + float line_thick_; + + QVector cur_selections_; + QHash ids; + uint id_hover; + +}; + +#endif // RENDERER_selection_H diff --git a/qglengine/renderer_service.cpp b/qglengine/renderer_service.cpp index 0d0f471..bb5cf0a 100644 --- a/qglengine/renderer_service.cpp +++ b/qglengine/renderer_service.cpp @@ -41,13 +41,23 @@ RendererService::RendererService(Renderer * r_): r(r_) { QMatrix4x4 m; m.rotate(90., _rot[i]); m.transposed().copyDataTo(axis_objects[i].modelmatrix); } - box_vp_scale = 1.; - box_mesh = Primitive::cube(); + box_vp_scale = box_full_scale = 1.; + box_mesh = Primitive::cube(); + box_mesh_f = Primitive::cubeFrame(); + omni_mesh = Primitive::ellipsoid(2, 1); + omni_mesh_f = Primitive::ellipsoidFrame(2, 1); + omni_mesh ->scalePoints(1.5); + omni_mesh_f->scalePoints(1.5); + box_mesh ->scalePoints(1.3); + omni_mesh ->scalePoints(1.3); } RendererService::~RendererService() { delete box_mesh; + delete box_mesh_f; + delete omni_mesh; + delete omni_mesh_f; delete axis_camera; delete axis_mesh; } @@ -62,25 +72,26 @@ void RendererService::init(int width, int height) { void RendererService::resize(int width, int height) { axis_viewport = preferredIconSize(10.); line_width = lineThickness(); - box_vp_scale = 30. * appScale() / qMax(qMin(width, height), 1); + box_vp_scale = 25. * appScale() / qMax(qMin(width, height), 1); //qDebug() << axis_viewport; } -void RendererService::fillBoxObjects() { - box_objects.clear(); +void RendererService::fillOmniObjects() { + cur_objects.clear(); Object o; QList ll = r->view->scene()->lights_used; QMatrix4x4 v_mat = r->view->camera()->viewMatrix() * r->view->camera()->offsetMatrix(); - QMatrix4x4 lmat; - double vps = tan(r->view->camera()->FOV() / 2. * deg2rad) * box_vp_scale; + box_full_scale = tan(r->view->camera()->FOV() / 2. * deg2rad) * box_vp_scale; foreach (Light * l, ll) { QVector4D lpos = QVector4D(l->worldPos(), 1.); double dist = -(v_mat * lpos).z(); + QMatrix4x4 lmat; lmat.translate(lpos.toVector3D()); - lmat.scale(dist * vps); + lmat.scale(dist * box_full_scale); lmat.transposed().copyDataTo(o.modelmatrix); - box_objects << o; + o.object_id = l->id_; + cur_objects << o; } } @@ -95,32 +106,35 @@ void RendererService::setObjectsColor(QVector & ol, QColor col) { void RendererService::renderService() { QOpenGLShaderProgram * prog = 0; QOpenGLExtraFunctions * f = r->view; - if (r->bindShader(Renderer::srService, &prog)) { - f->glEnable(GL_MULTISAMPLE); - glEnableDepth(); - f->glClear(GL_DEPTH_BUFFER_BIT); - glEnableDepth(); - + f->glEnable(GL_MULTISAMPLE); + glEnableDepth(); + f->glClear(GL_DEPTH_BUFFER_BIT); + if (r->bindShader(Renderer::srServiceFrame, &prog)) { + prog->setUniformValue("qgl_ProjMatrix", r->view->camera()->projectionMatrix(r->view->aspect)); /// lights - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_CULL_FACE); r->setUniformCamera(prog, r->view->camera()); - fillBoxObjects(); + fillOmniObjects(); - setObjectsColor(box_objects, Qt::white); - glLineWidth(line_width*3); - box_mesh->loadObjects(f, box_objects); - box_mesh->draw(f, box_objects.size()); + setObjectsColor(cur_objects, Qt::white); + prog->setUniformValue("line_width", 2.f); + prog->setUniformValue("z_offset", 0.f); + omni_mesh_f->loadObjects(f, cur_objects); + omni_mesh_f->draw(f, cur_objects.size()); - setObjectsColor(box_objects, Qt::black); - glLineWidth(line_width); - box_mesh->loadObjects(f, box_objects); - box_mesh->draw(f, box_objects.size()); + setObjectsColor(cur_objects, Qt::black); + prog->setUniformValue("line_width", 1.f); + prog->setUniformValue("z_offset", -1.E-3f); + omni_mesh_f->loadObjects(f, cur_objects); + omni_mesh_f->draw(f, cur_objects.size()); glEnable(GL_CULL_FACE); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + if (r->bindShader(Renderer::srServiceFill, &prog)) { /// axis f->glViewport(0, 0, axis_viewport.width(), axis_viewport.height()); @@ -130,7 +144,6 @@ void RendererService::renderService() { axis_mesh->draw(f, axis_objects.size()); f->glViewport(0, 0, r->view->width(), r->view->height()); - - f->glDisable(GL_MULTISAMPLE); } + f->glDisable(GL_MULTISAMPLE); } diff --git a/qglengine/renderer_service.h b/qglengine/renderer_service.h index f96f41f..f698876 100644 --- a/qglengine/renderer_service.h +++ b/qglengine/renderer_service.h @@ -26,6 +26,8 @@ class RendererService { friend class QGLView; + friend class Renderer; + friend class RendererSelection; public: RendererService(Renderer * r_); @@ -34,19 +36,20 @@ public: void init(int width, int height); void resize(int width, int height); - void fillBoxObjects(); + void fillOmniObjects(); void setObjectsColor(QVector & ol, QColor col); void renderService(); private: Renderer * r; - Mesh * axis_mesh, * box_mesh; - QVector axis_objects, box_objects; + Mesh * axis_mesh, * box_mesh_f, * omni_mesh_f; + Mesh * box_mesh, * omni_mesh; + QVector axis_objects, cur_objects; Camera * axis_camera; QSize axis_viewport; int line_width; - double box_vp_scale; + double box_vp_scale, box_full_scale; }; diff --git a/qglengine/shaders/ds_light.glsl b/qglengine/shaders/ds_light.glsl index 8b3e29f..8ce3578 100644 --- a/qglengine/shaders/ds_light.glsl +++ b/qglengine/shaders/ds_light.glsl @@ -133,6 +133,7 @@ void main(void) { //calcLight(0, normal, v); qgl_FragColor.rgb = max(vec3(0), li * diffuse + si * specular + emission); + //qgl_FragColor.rgb = vec3(1); qgl_FragColor.a = 1; diff --git a/qglengine/shaders/service.glsl b/qglengine/shaders/service_fill.glsl similarity index 100% rename from qglengine/shaders/service.glsl rename to qglengine/shaders/service_fill.glsl diff --git a/qglengine/shaders/service_frame.glsl b/qglengine/shaders/service_frame.glsl new file mode 100644 index 0000000..bdf8fe0 --- /dev/null +++ b/qglengine/shaders/service_frame.glsl @@ -0,0 +1,48 @@ +// vert // + +out vec4 object_color_g; +out float mat_scale; + +void main(void) { + gl_Position = qgl_ftransform(); + object_color_g = qgl_ObjectColor; + mat_scale = pow(qgl_ModelMatrix[0][0] * qgl_ModelMatrix[1][1] * qgl_ModelMatrix[2][2], 0.3333); +} + + +// geom // + +layout (lines) in; +layout (triangle_strip, max_vertices = 4) out; + +in float mat_scale[]; +in vec4 object_color_g[]; +out vec4 object_color; + +uniform float line_width, z_offset; +uniform mat4 qgl_ProjMatrix; + +void main(void) { + object_color = object_color_g[0]; + vec2 dir = normalize(gl_in[0].gl_Position.xy - gl_in[1].gl_Position.xy); + vec2 side = cross(vec3(dir, 0), vec3(0, 0, 1)).xy; + vec4 vo = vec4(0, 0, z_offset, 0); + float dts = 0.05 * line_width * mat_scale[0]; + dir *= dts; + side *= dts; + gl_Position = gl_in[0].gl_Position + vec4((dir + side), 0, 0)*qgl_ProjMatrix + vo; EmitVertex(); + gl_Position = gl_in[0].gl_Position + vec4((dir - side), 0, 0)*qgl_ProjMatrix + vo; EmitVertex(); + gl_Position = gl_in[1].gl_Position - vec4((dir - side), 0, 0)*qgl_ProjMatrix + vo; EmitVertex(); + gl_Position = gl_in[1].gl_Position - vec4((dir + side), 0, 0)*qgl_ProjMatrix + vo; EmitVertex(); + EndPrimitive(); +} + + +// frag // + +in vec4 object_color; +uniform float scale; + +void main(void) { + qgl_FragColor = object_color; +}