diff --git a/src/controls/CMakeLists.txt b/src/controls/CMakeLists.txt index 9dd8a4b..46a430b 100644 --- a/src/controls/CMakeLists.txt +++ b/src/controls/CMakeLists.txt @@ -2,13 +2,11 @@ set(SRC src/controls_plugin.cpp src/application_p.cpp src/flatmesh.cpp - src/flatmeshnode.cpp src/icon.cpp) set(HEADERS src/controls_plugin.h src/application_p.h src/flatmesh.h - src/flatmeshnode.h src/icon.h) add_library(asteroidcontrolsplugin ${SRC} ${HEADERS} resources.qrc) diff --git a/src/controls/src/flatmesh.cpp b/src/controls/src/flatmesh.cpp index 4fc8214..8d36a7f 100644 --- a/src/controls/src/flatmesh.cpp +++ b/src/controls/src/flatmesh.cpp @@ -27,49 +27,220 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include +#include +#include + #include "flatmesh.h" -#include "flatmeshnode.h" +#include "flatmeshgeometry.h" + +// Our Adreno drivers fail to load shaders that are too long so we have to be concise and skip +// every unnecessary character such as spaces, \n, etc... This is effectively one long line! +static const char *vertexShaderSource = + // Qt dynamically injects an "attribute" before main. With GLES3, this should be "in" + "#define attribute in\n" + + // Attributes are per-vertex information, they give base coordinates and colors + "in vec4 coord;" + "in vec4 color;" + + // Uniforms are FlatMesh-wide, they give scaling information, the animation state or shifts + "uniform mat4 matrix;" + "uniform float shiftMix;" + "uniform int loopNb;" + "uniform vec2 shifts[" FLATMESH_SHIFTS_NB_STR "];" + + // This is the color vector outputted here and forwarded to the fragment shaders + // The flat keyword enables flat shading (no interpolation between the vertices of a triangle) + "flat out vec4 fragColor;" + + "void main()" + "{" + // Two vertices can have the same coordinate (if they give different colors to 2 triangles) + // However, they need to move in sync, so we hash their coordinates as an index for shifts + "int shiftIndex = loopNb+floatBitsToInt(coord.x)+floatBitsToInt(coord.y);" + + // Interpolate between (coord + shiftA) and (coord + shiftB) in the [-0.5, 0.5] domain + "vec2 pos = coord.xy + mix(shifts[(shiftIndex)%" FLATMESH_SHIFTS_NB_STR "]," + "shifts[(shiftIndex+1)%" FLATMESH_SHIFTS_NB_STR "]," + "shiftMix);" -FlatMesh::FlatMesh(QQuickItem *parent) : QQuickItem(parent) + // Apply scene graph transformations (FlatMesh position and size) to get the final coords + "gl_Position = matrix * vec4(pos, 0, 1);" + + // Forward the color in the vertex attribute to the fragment shaders + "fragColor = color;" + "}"; + +static const char *fragmentShaderSource = + "#ifdef GL_ES\n" + "precision mediump float;" + "\n#endif\n" + + // The flat keyword disables interpolation in triangles + // Each pixel gets the color of the last vertex of the triangle it belongs to + "flat in vec4 fragColor;" + "out vec4 color;" + + // Just keep the provided color + "void main()" + "{" + "color = fragColor;" + "}"; + +static QByteArray versionedShaderCode(const char *src) { - m_timer.setInterval(90); - m_timer.setSingleShot(false); - connect(&m_timer, SIGNAL(timeout()), this, SLOT(update())); - m_timer.start(); + return (QOpenGLContext::currentContext()->isOpenGLES() + ? QByteArrayLiteral("#version 300 es\n") + : QByteArrayLiteral("#version 330\n")) + + src; +} - m_centerColor = QColor("#ffaa39"); - m_outerColor = QColor("#df4829"); +// This class wraps the FlatMesh vertex and fragment shaders +class SGFlatMeshMaterialShader : public QSGMaterialShader +{ +public: + SGFlatMeshMaterialShader() {} + const char *vertexShader() const override { + return versionedShaderCode(vertexShaderSource); + } + const char *fragmentShader() const override { + return versionedShaderCode(fragmentShaderSource); + } + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override { + // On every run, update the animation state uniforms + SGFlatMeshMaterial *material = static_cast(newEffect); + program()->setUniformValue(m_shiftMix_id, material->shiftMix()); + program()->setUniformValue(m_loopNb_id, material->loopNb()); + + if (state.isMatrixDirty()) { + // Vertices coordinates are always in the [-0.5, 0.5] range, modify QtQuick's projection matrix to do the scaling for us + QMatrix4x4 combinedMatrix = state.combinedMatrix(); + combinedMatrix.scale(material->width(), material->height()); + combinedMatrix.translate(0.5, 0.5); + combinedMatrix.scale(material->screenScaleFactor()); + program()->setUniformValue(m_matrix_id, combinedMatrix); + } + // Enable a mode such that 0xFF indices mean "restart a strip" + m_glFuncs->glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); + } + char const *const *attributeNames() const override { + // Map attribute numbers to attribute names in the vertex shader + static const char *const attr[] = { "coord", "color", nullptr }; + return attr; + } + void deactivate() override { + m_glFuncs->glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX); + } +private: + void initialize() override { + // Seed the array of shifts with pre-randomized shifts + program()->setUniformValueArray("shifts", flatmesh_shifts, flatmesh_shifts_nb, 2); + // Get the ids of the uniforms we regularly update + m_matrix_id = program()->uniformLocation("matrix"); + m_shiftMix_id = program()->uniformLocation("shiftMix"); + m_loopNb_id = program()->uniformLocation("loopNb"); + // Retrieve OpenGL functions available on all platforms + m_glFuncs = QOpenGLContext::currentContext()->functions(); + } + int m_matrix_id; + int m_shiftMix_id; + int m_loopNb_id; + QOpenGLFunctions *m_glFuncs; +}; +QSGMaterialShader *SGFlatMeshMaterial::createShader() const +{ + return new SGFlatMeshMaterialShader; +} + +FlatMesh::FlatMesh(QQuickItem *parent) : QQuickItem(parent), m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), flatmesh_vertices_sz, flatmesh_indices_sz) +{ + // Dilate the FlatMesh more or less on squared or round screens + QSettings machineConf("/etc/asteroid/machine.conf", QSettings::IniFormat); + m_material.setScreenScaleFactor(machineConf.value("Display/ROUND", false).toBool() ? 1.2 : 1.7); + + // Iterate over all vertices and assign them the coordinates of their base point from flatmesh_vertices + QSGGeometry::ColoredPoint2D *vertices = m_geometry.vertexDataAsColoredPoint2D(); + for (int i = 0; i < flatmesh_vertices_sz; i++) { + vertices[i].x = flatmesh_vertices[i].x(); + vertices[i].y = flatmesh_vertices[i].y(); + } + // Copy the indices buffer (already in the right format) + memcpy(m_geometry.indexData(), flatmesh_indices, sizeof(flatmesh_indices)); + + // Give initial colors to the vertices + setColors(QColor("#ffaa39"), QColor("#df4829")); + + + // m_animation interpolates the shiftMix, a float between 0.0 and 1.0 + // This is used by the vertex shader as the mix ratio between two shifts + m_animation.setStartValue(0.0); + m_animation.setEndValue(1.0); + m_animation.setDuration(4000); + m_animation.setLoopCount(-1); + m_animation.setEasingCurve(QEasingCurve::InOutQuad); + QObject::connect(&m_animation, &QVariantAnimation::currentLoopChanged, [this]() { + m_material.incrementLoopNb(); + }); + QObject::connect(&m_animation, &QVariantAnimation::valueChanged, [this](const QVariant& value) { + m_material.setShiftMix(value.toFloat()); + update(); + }); + + // Run m_animation depending on the item's visibility connect(this, SIGNAL(visibleChanged()), this, SLOT(maybeEnableAnimation())); + setAnimated(true); + // Tell QtQuick we have graphic content and that updatePaintNode() needs to run setFlag(ItemHasContents); - setAnimated(true); } -void FlatMesh::setCenterColor(QColor c) +void FlatMesh::updateColors() { - if (c == m_centerColor) + // Iterate over all vertices and give them the rgb values of the triangle they represent + // In the flat shading model we use, each triangle is colored by its last vertex + QSGGeometry::ColoredPoint2D *vertices = m_geometry.vertexDataAsColoredPoint2D(); + for (int i = 0; i < flatmesh_vertices_sz; i++) { + // Ratios are pre-calculated to save some computation, we just need to do the mix + // We do the color blending on the CPU because center and outer colors change rarely + // and it would be a waste of GPU time to re-calculate that in every vertex shader + float ratio = flatmesh_vertices[i].z(); + float inverse_ratio = 1-ratio; + vertices[i].r = m_centerColor.red()*inverse_ratio + m_outerColor.red()*ratio; + vertices[i].g = m_centerColor.green()*inverse_ratio + m_outerColor.green()*ratio; + vertices[i].b = m_centerColor.blue()*inverse_ratio + m_outerColor.blue()*ratio; + } + m_geometryDirty = true; +} + +void FlatMesh::setColors(QColor center, QColor outer) +{ + if (center == m_centerColor && outer == m_outerColor) return; - m_centerColor = c; + m_centerColor = center; + m_outerColor = outer; + updateColors(); update(); } +void FlatMesh::setCenterColor(QColor c) +{ + setColors(c, m_outerColor); +} + void FlatMesh::setOuterColor(QColor c) { - if (c == m_outerColor) - return; - m_outerColor = c; - update(); + setColors(m_centerColor, c); } void FlatMesh::maybeEnableAnimation() { - if (isVisible() && m_animated) { - m_timer.start(); - } else { - m_timer.stop(); - } - update(); + // Only run the animation if the item is visible. No point running the shaders if this is hidden + if (isVisible() && m_animated) + m_animation.start(); + else + m_animation.pause(); } void FlatMesh::setAnimated(bool animated) @@ -81,16 +252,32 @@ void FlatMesh::setAnimated(bool animated) maybeEnableAnimation(); } +void FlatMesh::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + // On resizes, tell the vertex shader about the new size so the transformation matrix compensates it + m_material.setSize(newGeometry.width(), newGeometry.height()); + + QQuickItem::geometryChanged(newGeometry, oldGeometry); +} + +// Called by the SceneGraph on every update() QSGNode *FlatMesh::updatePaintNode(QSGNode *old, UpdatePaintNodeData *) { - FlatMeshNode *n = static_cast(old); - if (!n) - n = new FlatMeshNode(window(), boundingRect()); - - n->setAnimated(m_animated); - n->setRect(boundingRect()); - n->setCenterColor(m_centerColor); - n->setOuterColor(m_outerColor); + // On the first update(), create a scene graph node for the mesh + QSGGeometryNode *n = static_cast(old); + if (!n) { + n = new QSGGeometryNode; + n->setOpaqueMaterial(&m_material); + n->setGeometry(&m_geometry); + } + + // On every update(), mark the material dirty so the shaders run again + n->markDirty(QSGNode::DirtyMaterial); + // And if colors changed, mark the geometry dirty so the new vertex attributes are sent to the GPU + if (m_geometryDirty) { + n->markDirty(QSGNode::DirtyGeometry); + m_geometryDirty = false; + } return n; } diff --git a/src/controls/src/flatmesh.h b/src/controls/src/flatmesh.h index 3014ac2..fdccae4 100644 --- a/src/controls/src/flatmesh.h +++ b/src/controls/src/flatmesh.h @@ -33,8 +33,39 @@ #include #include #include -#include +#include +#include +// This is the scene graph material used by FlatMesh. It just creates the Shader object and holds values for some of the uniforms +class SGFlatMeshMaterial : public QSGMaterial +{ +public: + // Start the animation at a random point. Disable SceneGraph optimizations that assume our vertex coordinates to be in pixels + SGFlatMeshMaterial() : m_loopNb(random()) { setFlag(QSGMaterial::RequiresFullMatrix); } + int compare(const QSGMaterial *other) const override { return 0; } + void setScreenScaleFactor(float screenScaleFactor) { m_screenScaleFactor = screenScaleFactor; } + float screenScaleFactor() { return m_screenScaleFactor; } + void setShiftMix(float shiftMix) { m_shiftMix = shiftMix; } + float shiftMix() { return m_shiftMix; } + void setSize(float width, float height) { m_width = width; m_height = height; } + float width() { return m_width; } + float height() { return m_height; } + void incrementLoopNb() { m_loopNb++; } + int loopNb() { return m_loopNb; } +protected: + QSGMaterialType *type() const override { static QSGMaterialType type; return &type; } + QSGMaterialShader *createShader() const override; +private: + float m_screenScaleFactor; + float m_shiftMix; + float m_width; + float m_height; + int m_loopNb; +}; + +struct FlatMeshVertex; + +// The QtQuick item per-se, this is the highest level construct that exposes properties to QML class FlatMesh : public QQuickItem { Q_OBJECT @@ -48,6 +79,10 @@ class FlatMesh : public QQuickItem bool getAnimated() const { return m_animated; } void setAnimated(bool animated); + // As an optimization for color animations, make it possible to change the two colors + // on one call. Then, updateColors() will only run once saving some CPU cycles + Q_INVOKABLE void setColors(QColor center, QColor outer); + QColor getCenterColor() const { return m_centerColor; } void setCenterColor(QColor c); @@ -59,14 +94,25 @@ class FlatMesh : public QQuickItem protected: QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; private slots: void maybeEnableAnimation(); + void updateColors(); private: QColor m_centerColor, m_outerColor; bool m_animated; - QTimer m_timer; + QVariantAnimation m_animation; + // Note: the Qt documentation says "It is crucial that [...] interaction with the scene + // graph happens exclusively on the render thread, primarily during the updatePaintNode() + // call. The rule of thumb is to only use classes with the "QSG" prefix inside the + // QQuickItem::updatePaintNode() function." + // However, no hell broke loose for instantiating these in the FlatMesh constructor so... + // It doesn't look like we're doing anything nasty here but let's keep an eye on it. + SGFlatMeshMaterial m_material; + QSGGeometry m_geometry; + bool m_geometryDirty; }; #endif // FLATMESH_H diff --git a/src/controls/src/flatmeshgeometry.h b/src/controls/src/flatmeshgeometry.h new file mode 100644 index 0000000..2423685 --- /dev/null +++ b/src/controls/src/flatmeshgeometry.h @@ -0,0 +1,569 @@ +// Do not modify manually! This file is generated by generate_flatmeshgeometry.py + +static const QVector3D flatmesh_vertices[] = { + QVector3D(-0.07590353228766045, -0.448504906868135, 1.0), + QVector3D(-0.062224940488613, -0.35930409318402756, 0.9061733334183945), + QVector3D(-0.1629414816089452, -0.424697623338794, 1.0), + QVector3D(-0.15027899526611474, -0.3353552884089378, 0.9075174446281145), + QVector3D(-0.24356755120684306, -0.38417814318053056, 1.0), + QVector3D(-0.23090506486401255, -0.2948358082506744, 0.921521610515689), + QVector3D(-0.31460903971810106, -0.3285409408676378, 1.0), + QVector3D(-0.25951141051372995, -0.2078667893854162, 0.8770518376594514), + QVector3D(-0.3732704068345872, -0.25997538552732274, 0.983261036334784), + QVector3D(-0.3434807221115272, -0.1747992970094667, 0.8920861036693435), + QVector3D(-0.4298739640827997, -0.14874936202309635, 1.0), + QVector3D(-0.3641174376320337, -0.0869555872538635, 0.945253439027785), + QVector3D(-0.4508623386256416, -0.06032120150344015, 1.0), + QVector3D(-0.3845775789108305, 0.00092941709814545, 0.9441538209381701), + QVector3D(-0.4505726347395617, 0.0624683801805993, 1.0), + QVector3D(-0.31914905303085206, 0.0630703808199446, 0.8822652687763839), + QVector3D(-0.42937666241189487, 0.1501788249872798, 0.9734756956158577), + QVector3D(-0.3391457840919671, 0.15106198336229185, 0.8640739101149884), + QVector3D(-0.3912843694651375, 0.2319796109808104, 1.0), + QVector3D(-0.27332862605861374, 0.2127911748320783, 0.890127295771891), + QVector3D(-0.32144975135481846, 0.28912431751157197, 0.9718710782503599), + QVector3D(-0.2238771660764429, 0.288269280775012, 0.8522461888204537), + QVector3D(-0.2719982913726476, 0.36460242345450566, 0.9961237618777129), + QVector3D(-0.1946769303112335, 0.41111907095528116, 1.0), + QVector3D(0.09820876379176866, -0.42192652852178536, 1.0), + QVector3D(0.0278142706527945, -0.3654729484155787, 0.8428009938830104), + QVector3D(0.0141212827157268, -0.454663157813563, 0.9999238494308663), + QVector3D(0.18810955777419616, -0.4141651747461811, 1.0), + QVector3D(0.10520039266732495, -0.31906411853749217, 0.9591445378112252), + QVector3D(-0.00118433127347995, -0.28002429449158506, 0.6538012733845537), + QVector3D(-0.062224940488613, -0.35930409318402756, 0.6906408936098238), + QVector3D(-0.0905735272994765, -0.26769696692528216, 0.5938746244033252), + QVector3D(-0.15027899526611474, -0.3353552884089378, 0.6947577500788529), + QVector3D(-0.1711995968973743, -0.22717748676701874, 0.601418176088109), + QVector3D(-0.23090506486401255, -0.2948358082506744, 0.7076285541603962), + QVector3D(-0.25951141051372995, -0.2078667893854162, 0.6670897418730211), + QVector3D(0.2633504907004984, -0.2649712148677251, 1.0), + QVector3D(0.2227806334425657, -0.1843464495257893, 0.7126913588122905), + QVector3D(0.1547060506695305, -0.2436215496730266, 0.6202710385866826), + QVector3D(0.1336269904007723, -0.15588293451819854, 0.444613885490116), + QVector3D(0.06801810442391025, -0.21783916177917895, 0.3848657789315288), + QVector3D(0.0472593634161869, -0.12974819939131274, 0.2566417303154027), + QVector3D(-0.0185577946171664, -0.1914773908610992, 0.2458889308205983), + QVector3D(-0.0391082635683985, -0.1036134642644269, 0.15975554893883206), + QVector3D(-0.10506055127802755, -0.16579052654982404, 0.20263932082321262), + QVector3D(-0.1254758905529839, -0.0774787291375411, 0.1690617375016782), + QVector3D(-0.19129304858633725, -0.1392079206073276, 0.2627102108614229), + QVector3D(-0.21184351753756936, -0.0513439940106553, 0.2812221434118502), + QVector3D(-0.2776606755709227, -0.11307318548044175, 0.4152880511856543), + QVector3D(-0.29821114452215475, -0.0252092588837695, 0.4784939259424734), + QVector3D(-0.3641174376320337, -0.0869555872538635, 0.6459086579808486), + QVector3D(-0.3845775789108305, 0.00092941709814545, 0.7468618883321203), + QVector3D(0.19528840283181184, -0.3242159915662338, 0.934981911653232), + QVector3D(0.10520039266732495, -0.31906411853749217, 0.6807003449785606), + QVector3D(0.06801810442391025, -0.21783916177917895, 0.5156052571365449), + QVector3D(-0.00118433127347995, -0.28002429449158506, 0.5034809606882725), + QVector3D(-0.0185577946171664, -0.1914773908610992, 0.36508742191134325), + QVector3D(-0.0905735272994765, -0.26769696692528216, 0.41713662399322), + QVector3D(-0.10506055127802755, -0.16579052654982404, 0.3382245576678877), + QVector3D(-0.1711995968973743, -0.22717748676701874, 0.42503321058944654), + QVector3D(-0.19129304858633725, -0.1392079206073276, 0.3808173279430114), + QVector3D(-0.25951141051372995, -0.2078667893854162, 0.5155447906229977), + QVector3D(-0.2776606755709227, -0.11307318548044175, 0.5312439809450881), + QVector3D(-0.3434807221115272, -0.1747992970094667, 0.6966838863053082), + QVector3D(-0.3641174376320337, -0.0869555872538635, 0.7484911886249883), + QVector3D(0.2781653886287355, -0.35991720523172854, 0.0), + QVector3D(0.10520039266732495, -0.31906411853749217, 0.8870003285059984), + QVector3D(0.1547060506695305, -0.2436215496730266, 0.7246815811358405), + QVector3D(0.34982112161129786, -0.29076310043255477, 0.0), + QVector3D(0.3138619937615597, -0.19019836264438564, 0.9196157275606832), + QVector3D(0.289204641387069, -0.1033974044412577, 0.6318611680464125), + QVector3D(0.19944414843412564, -0.09415374304841205, 0.4757192778533415), + QVector3D(0.26865417243583684, -0.01553347784458545, 0.45513270392578115), + QVector3D(0.17889367948289356, -0.0062898164517398, 0.3353175670430853), + QVector3D(0.28165886490790315, 0.073759687318309, 0.40176025302696283), + QVector3D(0.1583432105316615, 0.08157411014493245, 0.3175513491619195), + QVector3D(0.22416036856501484, 0.1433033016147189, 0.3991108048083323), + QVector3D(0.1377927415804294, 0.1694380367416047, 0.33145020078782655), + QVector3D(0.20360989961378276, 0.23116722821139116, 0.45312245781512656), + QVector3D(0.11724227262919736, 0.25730196333827693, 0.470268003937791), + QVector3D(0.1830594306625507, 0.31903115480806343, 0.6292240441081979), + QVector3D(0.10300355013507664, 0.3606658442397353, 0.7078676992691899), + QVector3D(0.16882070816842995, 0.42239503570952175, 0.9227723446941978), + QVector3D(0.07860246081920055, 0.44803381926336405, 1.0), + QVector3D(0.4003326246723591, -0.21599024820921525, 0.0), + QVector3D(0.3138619937615597, -0.19019836264438564, 1.0), + QVector3D(0.379433737327603, -0.1282085423767802, 0.9558178208636355), + QVector3D(0.289204641387069, -0.1033974044412577, 0.7667701732247899), + QVector3D(0.35513000763583585, -0.04130790892586405, 0.7549859922750332), + QVector3D(0.26865417243583684, -0.01553347784458545, 0.6015114129877066), + QVector3D(0.3689915156374611, 0.04785626530920545, 0.6759742405964898), + QVector3D(0.28165886490790315, 0.073759687318309, 0.5998146685163432), + QVector3D(0.3474760229412565, 0.13548887878809546, 0.7204165109408786), + QVector3D(0.22416036856501484, 0.1433033016147189, 0.5974510573294286), + QVector3D(0.2899775265983682, 0.20503249308450536, 0.6705962236750833), + QVector3D(0.20360989961378276, 0.23116722821139116, 0.5966049870187571), + QVector3D(0.2694270576471361, 0.29289641968117763, 0.749945880296471), + QVector3D(0.1830594306625507, 0.31903115480806343, 0.765655743824077), + QVector3D(0.24887658869590404, 0.3807603462778499, 0.9534792247573457), + QVector3D(0.16882070816842995, 0.42239503570952175, 1.0), + QVector3D(0.44929248325579463, -0.07109333434563204, 0.0), + QVector3D(0.379433737327603, -0.1282085423767802, 1.0), + QVector3D(0.35513000763583585, -0.04130790892586405, 0.9436335066625672), + QVector3D(0.1336269904007723, -0.15588293451819854, 0.37813399589459884), + QVector3D(0.1130765214495402, -0.06801900792152625, 0.24607124096483984), + QVector3D(0.0472593634161869, -0.12974819939131274, 0.18269910245138068), + QVector3D(0.0267088944649548, -0.04188427279464045, 0.09039582674458865), + QVector3D(-0.0391082635683985, -0.1036134642644269, 0.07738429550857409), + QVector3D(-0.05965873251963055, -0.01574953766775465, 0.03590890696909567), + QVector3D(-0.1254758905529839, -0.0774787291375411, 0.08757200187501528), + QVector3D(-0.146026359504216, 0.0103851974591311, 0.11008467629063202), + QVector3D(-0.21184351753756936, -0.0513439940106553, 0.2089375138571442), + QVector3D(-0.2323939864888014, 0.0365199325860169, 0.2792880714227354), + QVector3D(-0.29821114452215475, -0.0252092588837695, 0.4134829612273475), + QVector3D(-0.31914905303085206, 0.0630703808199446, 0.5222389146126992), + QVector3D(-0.3845775789108305, 0.00092941709814545, 0.687440567002935), + QVector3D(0.1130765214495402, -0.06801900792152625, 0.22476632697223556), + QVector3D(0.09252605249830816, 0.01984491867514595, 0.13705760579493692), + QVector3D(0.0267088944649548, -0.04188427279464045, 0.06445501863002251), + QVector3D(0.0061584255137227, 0.04597965380203175, 0.020679319541762695), + QVector3D(-0.05965873251963055, -0.01574953766775465, 0.0016858497164255269), + QVector3D(-0.08020920147086265, 0.0721143889289176, 0.0331098589472019), + QVector3D(-0.146026359504216, 0.0103851974591311, 0.08519146889074841), + QVector3D(-0.16657682845544805, 0.0982491240558034, 0.16453655999424033), + QVector3D(-0.2323939864888014, 0.0365199325860169, 0.25847731788074946), + QVector3D(-0.2529444554400335, 0.1243838591826892, 0.3745748888718783), + QVector3D(-0.31914905303085206, 0.0630703808199446, 0.5037254221675496), + QVector3D(-0.3391457840919671, 0.15106198336229185, 0.6521546465256765), + QVector3D(0.09252605249830816, 0.01984491867514595, 0.16959003978167916), + QVector3D(0.07197558354707605, 0.10770884527181825, 0.13486019776839087), + QVector3D(0.0061584255137227, 0.04597965380203175, 0.061939499577595765), + QVector3D(-0.0143920434375093, 0.13384358039870406, 0.0856504882619879), + QVector3D(-0.08020920147086265, 0.0721143889289176, 0.0725022739347035), + QVector3D(-0.10075967042209474, 0.15997831552558986, 0.15332523167640522), + QVector3D(-0.16657682845544805, 0.0982491240558034, 0.19614767338593223), + QVector3D(-0.18712729740668016, 0.18611305065247566, 0.31670508565750866), + QVector3D(-0.2529444554400335, 0.1243838591826892, 0.40217938300821915), + QVector3D(-0.27332862605861374, 0.2127911748320783, 0.5557023969502217), + QVector3D(-0.3391457840919671, 0.15106198336229185, 0.6769306301522307), + QVector3D(0.454485742634088, 0.01899229951532675, 0.0), + QVector3D(0.35513000763583585, -0.04130790892586405, 1.0), + QVector3D(0.3689915156374611, 0.04785626530920545, 0.9052192549883082), + QVector3D(0.441103930715987, 0.11109418371607285, 0.0), + QVector3D(0.3689915156374611, 0.04785626530920545, 1.0), + QVector3D(0.3474760229412565, 0.13548887878809546, 0.9256077890388497), + QVector3D(0.40685859591622436, 0.2034307760089825, 0.0), + QVector3D(0.3474760229412565, 0.13548887878809546, 1.0), + QVector3D(0.2899775265983682, 0.20503249308450536, 0.9033943322033756), + QVector3D(0.051425114595844, 0.1955727718684905, 0.24012151698030998), + QVector3D(-0.0349425123887414, 0.2217075069953763, 0.3752820185834765), + QVector3D(-0.0143920434375093, 0.13384358039870406, 0.2485317921201491), + QVector3D(-0.10075967042209474, 0.15997831552558986, 0.237749406352912), + QVector3D(0.07197558354707605, 0.10770884527181825, 0.2207382011657191), + QVector3D(-0.0143920434375093, 0.13384358039870406, 0.17642262275065648), + QVector3D(0.051425114595844, 0.1955727718684905, 0.36747081014643934), + QVector3D(0.0308746456446119, 0.2834366984651628, 0.43193606682410396), + QVector3D(-0.0584485632483233, 0.312621163775509, 0.4885094067935636), + QVector3D(-0.1213101393733268, 0.2478422421222621, 0.47938243740554104), + QVector3D(-0.1463965464394275, 0.33452017213685614, 0.6300440169843945), + QVector3D(-0.2238771660764429, 0.288269280775012, 0.6841090180154307), + QVector3D(-0.1946769303112335, 0.41111907095528116, 0.9043159895450578), + QVector3D(-0.18712729740668016, 0.18611305065247566, 0.3926425398632497), + QVector3D(-0.2238771660764429, 0.288269280775012, 0.5690683361556731), + QVector3D(-0.27332862605861374, 0.2127911748320783, 0.6495543504067224), + QVector3D(0.35869783390037463, 0.2797389169452788, 1.0), + QVector3D(0.2899775265983682, 0.20503249308450536, 1.0), + QVector3D(0.2694270576471361, 0.29289641968117763, 0.9371831867970333), + QVector3D(-0.0349425123887414, 0.2217075069953763, 0.35521142631746444), + QVector3D(0.0308746456446119, 0.2834366984651628, 0.6112365490605847), + QVector3D(0.01348041341455295, 0.3719795245790143, 0.715674578859033), + QVector3D(-0.0584485632483233, 0.312621163775509, 0.6476611352091383), + QVector3D(-0.1045028917807815, 0.4144408394916967, 0.8160983620028505), + QVector3D(-0.1463965464394275, 0.33452017213685614, 0.8118217511280866), + QVector3D(-0.1946769303112335, 0.41111907095528116, 0.9901036442633289), + QVector3D(-0.32144975135481846, 0.28912431751157197, 1.0), + QVector3D(0.01348041341455295, 0.3719795245790143, 0.9285825980226923), + QVector3D(-0.0235351305104951, 0.4542731505717594, 1.0), + QVector3D(-0.1045028917807815, 0.4144408394916967, 0.9945268034598578), +}; +static const int flatmesh_vertices_sz = 178; + +static const unsigned short flatmesh_indices[] = { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 65535, + 24, + 25, + 26, + 1, + 0, + 65535, + 26, + 27, + 24, + 28, + 25, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 65535, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 65535, + 52, + 38, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65535, + 65, + 52, + 27, + 66, + 65535, + 65, + 36, + 52, + 67, + 65535, + 65, + 68, + 36, + 69, + 37, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 65535, + 68, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 65535, + 84, + 100, + 101, + 102, + 65535, + 37, + 71, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 65535, + 71, + 73, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 65535, + 73, + 75, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 65535, + 100, + 139, + 140, + 141, + 65535, + 139, + 142, + 143, + 144, + 65535, + 142, + 145, + 146, + 147, + 65535, + 148, + 149, + 150, + 151, + 65535, + 75, + 77, + 152, + 148, + 153, + 65535, + 77, + 79, + 154, + 155, + 149, + 156, + 157, + 158, + 159, + 160, + 65535, + 133, + 157, + 161, + 162, + 163, + 65535, + 145, + 164, + 165, + 166, + 65535, + 98, + 96, + 164, + 65535, + 157, + 133, + 167, + 65535, + 79, + 81, + 168, + 169, + 170, + 171, + 172, + 173, + 65535, + 22, + 18, + 174, + 65535, + 81, + 83, + 175, + 176, + 177, + 23, +}; +static const int flatmesh_indices_sz = 249; + +static const float flatmesh_shifts[] = { + -0.014455721149386655, -0.021944026100648904, + -0.0005417119668014425, -0.039969767519674536, + -0.005524899294510257, -0.010139476531081666, + 0.012758185235742632, -0.039804143287190986, + 0.016032993379478742, 0.021338958241106924, + -0.0009254513955395854, 0.028055492160101097, + 0.0004533243420474752, 0.03674686013983172, + -0.022697070664360105, -0.030363814350102606, + 0.007743521230965211, -0.019560700344122616, + -0.04334631296523202, -0.009383657661179951, + 0.03256188046993191, 0.025330835453787875, + -0.021714757037414396, 0.025152464057466416, + 0.012338141279632982, -0.02172516565176803, + 0.02508775160189217, 0.014871469887621143, + 0.010852184611772639, -0.03526544934319527, + 0.011078774776345005, 0.041682558124455774, + 0.0035375768838676394, -0.0060719508956933056, + 0.02108125222425731, -0.0037205194306797465, + -0.02161983262917156, 0.011125161684785273, + 0.021947781859247333, 0.02214987214505951, + 0.004894857911667648, 0.018081294039064028, + 0.02099854515886201, 0.017851099718312842, + -0.01982622499699757, -0.013183682802725872, + -0.036680121754048334, -0.002642264405302571, + 0.02521447679777857, 0.01953508030294833, + -0.01693167887076652, 0.014069252976717626, + -0.025844106914715094, -0.022012426782007103, + 0.04210257853677726, 0.002367042994043245, + 0.020791646218799684, -0.02627824459386542, + 0.012239808414337286, -0.0309652953716663, + 0.03599030216478599, -0.010410258709267803, + -0.023578006946172538, -0.026465287624940905, + -0.011309011546572234, -0.0407531115180364, + 0.015022118359744516, 0.04137053265491031, + 0.038489689982268656, -0.02243533716317161, + 0.02478205349145701, 0.019303614092614562, + -0.019693277099741027, -0.02693662442571409, + 0.029974181863058575, -0.0030079124966440464, + 0.004627833934675862, 0.015622344559532944, + 0.00917924949277589, 0.0026284743830412346, + 0.03253839553084739, -0.025151718686619636, + 0.0032923995101349257, 0.015154019103672324, + -0.018772053876719638, 0.026103606893666736, + 0.012255501543728734, 0.019321871743076518, + 0.008202266536389611, 0.020395010572526788, + 0.028667046535234678, 0.011693898409761561, + -0.030878915940646755, 0.008102717451669298, + -0.03811272641333141, 0.007723695569871546, + 0.024820437019682947, -0.012101951313072762, + 0.03155875764449122, 0.013031815719337321, + 0.039680689480552395, 0.010880074383769719, + 0.009130663377037737, 0.012704706856865741, + 0.01777365169239631, -0.026130854618725316, + -0.014087339817733453, 0.026895218972944657, + -0.03907189506332969, -0.00934785615327756, + -0.025841865289036075, -0.001990416616211092, + 0.005740441202764657, 0.03916075306560983, + 0.016692106164581704, -0.032664932436886056, + 0.012458530546389875, -0.01664408530008782, + 0.005350175460556124, 0.02147075445879694, + -0.012728847696550414, -0.040885766630212886, + 0.020727563524314336, -0.027189559627245403, + -0.03937889016407205, 0.00685132135573799, + -0.012459352627072663, 0.006470183072552711, + -0.007923360288363972, -0.03851489683366685, + -0.008493606579398153, -0.041275856024777145, + 0.014302511133420025, -0.02394499753493127, + 0.0009595811232725851, -0.02284333891494767, + -0.005786780813590626, 0.019446888135934474, + 0.021347205698869935, 0.009737932605521532, + -0.006320426192678588, 0.04398189335415962, + -0.011336790581631088, -0.042823619127327954, + -0.01442988854433544, 0.03731838302401159, + -0.027437202794864314, -0.02951238433261903, + 0.02940054296296972, -0.016659949044084646, + -0.018428722166114863, -0.025969164336010115, + 0.024709086286447933, 0.0013642540454152073, + -0.028170913712792317, 0.015685931001087235, + 0.00924314522353013, -0.0388742267123793, + 0.00696205950412131, 0.009621275477510339, + 0.017751295946310926, -0.033092060190639136, + -0.008261284211193763, 0.0007092181693598742, + 0.030416399135691104, 0.027551072447996004, + -0.02230527462634699, 0.016383793194602304, + 0.024600726041301275, 0.02596089182561636, + 0.011357288208597079, 0.03699123476232083, + 0.023713456790261454, 0.00113234713125188, + 0.002502185041645086, -0.02925074933009578, + -0.015337283721453971, -0.006416999939164213, + -0.03169783297426491, -0.0283394201225888, + -0.000708085318734062, -0.0018007775896010474, + 0.02950008563117916, 0.014583676624964534, + -0.0020427663974829863, 0.013199382988909799, + 0.03507639270124268, -0.025085907145944213, + -0.03122915994870905, -0.024291642921123995, + -0.005658772650946406, 0.036729372190078095, + 0.04111081065596769, 0.00225620345956127, + 0.01800701121624554, 0.03058462742023514, + -0.014742280204694801, 0.0002762920246333182, + 0.002248234532322464, 0.00861076332609133, + 0.013647490362448387, -0.006681817271052268, + -0.012296102258394247, 0.010122797006050814, + 0.020928081198451364, -0.01777445717405529, + -0.032638344817320995, 0.030339197307702227, + 0.01109615616036932, 0.042009648989523224, + -0.03373940115536797, -0.01949275900086155, + 0.018995093333682645, 0.007878765969187485, + -0.006154470295669073, 0.018875348073310257, + -0.021650550509754424, -0.020311562994237937, + -0.03585048010374008, 0.02422316055621331, + -0.028050145958904642, 0.01419119660414566, + -0.011261954203254267, -0.035069408873473734, + -0.02300749248155945, 0.03586811459781664, + 0.023144047662494484, 0.036825186135317434, + 0.016402061363406183, -0.016109727124898734, + 0.030311403022036724, -0.010363524515611294, + 0.0294962061451393, 0.027120069030887494, + -0.013816828175460552, -0.000601566903700245, + 0.0013461011466981863, -0.04138724484724674, + 0.00873627850718282, -0.04087055918195267, + 0.02297560419816168, 0.02903447862864536, + 0.018738447708033793, -0.028635634859267987, + -0.02523056933250636, 0.0069597490485832775, + 0.011196171965906457, 0.036867967229670624, + 0.011711432703440066, -0.035202075090100315, + -0.01624426543168538, 0.005429740646329734, + -0.02527642753617346, 0.014590918876976148, + 0.011474643661906448, 0.01777462183262156, +}; +static const int flatmesh_shifts_nb = 128; +#define FLATMESH_SHIFTS_NB_STR "128" \ No newline at end of file diff --git a/src/controls/src/flatmeshnode.cpp b/src/controls/src/flatmeshnode.cpp deleted file mode 100644 index e711b0d..0000000 --- a/src/controls/src/flatmeshnode.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2016 Florent Revest - * All rights reserved. - * - * You may use this file under the terms of BSD license as follows: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the author nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "flatmeshnode.h" - -#include - -#include -#include - -/* Used to compute a triangle color from its distance to the center */ -static inline QColor interpolateColors(const QColor& color1, const QColor& color2, qreal ratio) -{ - /* Linear scale is too harsh, this looks better. This is not supposed to be called very often */ - ratio = pow(ratio, 1.7); - if (ratio>1) ratio=1; - - int r = color1.red()*(1-ratio) + color2.red()*ratio; - int g = color1.green()*(1-ratio) + color2.green()*ratio; - int b = color1.blue()*(1-ratio) + color2.blue()*ratio; - - return QColor(r, g, b); -} - -FlatMeshNode::FlatMeshNode(QQuickWindow *window, QRectF boundingRect) - : QSGSimpleRectNode(boundingRect, Qt::transparent), - m_animationState(0), m_animated(true), m_window(window) -{ - connect(window, SIGNAL(afterRendering()), this, SLOT(maybeAnimate())); - - connect(window, SIGNAL(widthChanged(int)), this, SLOT(generateGrid())); - connect(window, SIGNAL(heightChanged(int)), this, SLOT(generateGrid())); - - srand(time(NULL)); - generateGrid(); - - for(int y = 0; y < NUM_POINTS_Y-1; y++) { - for(int x = 0; x < NUM_POINTS_X-1; x++) { - for(int n = 0; n < 2; n++) { - QSGGeometryNode *triangle = new QSGGeometryNode(); - - QSGFlatColorMaterial *color = new QSGFlatColorMaterial; - triangle->setOpaqueMaterial(color); - triangle->setFlag(QSGNode::OwnsMaterial); - - QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 3); - triangle->setGeometry(geometry); - triangle->setFlag(QSGNode::OwnsGeometry); - - appendChildNode(triangle); - } - } - } - - maybeAnimate(); -} - -void FlatMeshNode::updateColors() -{ - int centerX = m_unitWidth*((NUM_POINTS_X-2)/2); - int centerY = m_unitHeight*((NUM_POINTS_Y-2)/2); - int radius = rect().width()*0.6; - - QSGGeometryNode *triangle = static_cast(firstChild()); - for(int y = 0; y < NUM_POINTS_Y-1; y++) { - for(int x = 0; x < NUM_POINTS_X-1; x++) { - for(int n = 0; n < 2; n++) { - QSGFlatColorMaterial *color = static_cast(triangle->opaqueMaterial()); - color->setColor(interpolateColors(m_centerColor, m_outerColor, - sqrt(pow(m_points[y*NUM_POINTS_Y+x].centerX-centerX, 2) + pow(m_points[y*NUM_POINTS_Y+x].centerY-centerY, 2))/radius)); - triangle->setOpaqueMaterial(color); - - triangle->markDirty(QSGNode::DirtyMaterial); - triangle = static_cast(triangle->nextSibling()); - } - } - } -} - -void FlatMeshNode::setCenterColor(QColor c) -{ - if (c == m_centerColor) - return; - m_centerColor = c; - updateColors(); -} - -void FlatMeshNode::setOuterColor(QColor c) -{ - if (c == m_outerColor) - return; - m_outerColor = c; - updateColors(); -} - -/* When the size changes, regenerate a grid of points that serves as a base for further operations */ -void FlatMeshNode::generateGrid() -{ - m_unitWidth = rect().width()/(NUM_POINTS_X-2); - m_unitHeight = rect().height()/(NUM_POINTS_Y-2); - - for(int y = 0; y < NUM_POINTS_Y; y++) { - for(int x = 0; x < NUM_POINTS_X; x++) { - Point *point = &m_points[y*NUM_POINTS_Y+x]; - point->centerX = m_unitWidth*x; - point->centerY = m_unitHeight*y; - - if(x != 0 && x != (NUM_POINTS_X-1) && y != 0 && y != (NUM_POINTS_Y-1)) { - int offsetX = rand()%m_unitWidth - m_unitWidth/3; - int offsetY = rand()%m_unitHeight - m_unitHeight/3; - float normalization = ((float)m_unitWidth)/(2*(abs(offsetX)+abs(offsetY))); - offsetX*=normalization; - offsetY*=normalization; - point->animOriginX = point->centerX + offsetX; - point->animOriginY = point->centerY + offsetY; - - offsetX = rand()%m_unitWidth - m_unitWidth/3; - offsetY = rand()%m_unitHeight - m_unitHeight/3; - normalization = ((float)m_unitWidth)/(2*(abs(offsetX)+abs(offsetY))); - offsetX*=normalization; - offsetY*=normalization; - point->animEndX = point->centerX + offsetX; - point->animEndY = point->centerY + offsetY; - } - else { - point->animEndX = point->animOriginX = point->centerX; - point->animEndY = point->animOriginY = point->centerY; - } - } - } -} - -void FlatMeshNode::setAnimated(bool animated) -{ - m_animated = animated; -} - -void FlatMeshNode::maybeAnimate() -{ - static QElapsedTimer t; - bool firstFrame = false; - if(!t.isValid()) { - t.start(); - firstFrame = true; - } - if (firstFrame || (m_animated && t.elapsed() >= 80)) { - t.restart(); - m_animationState += 0.03; - - /* Interpolate all points positions according to the animationState */ - for(int i = 0; i < NUM_POINTS_X*NUM_POINTS_Y; i++) { - Point *p = &m_points[i]; - - p->currentPos.x = p->animOriginX + (p->animEndX-p->animOriginX)*m_animationState; - p->currentPos.y = p->animOriginY + (p->animEndY-p->animOriginY)*m_animationState; - } - - /* Update all triangles' geometries according to the new points position */ - qreal lastCenterX = m_unitWidth*(NUM_POINTS_X-1); - qreal lastcenterY = m_unitHeight*(NUM_POINTS_Y-1); - QSGGeometryNode *triangle = static_cast(firstChild()); - for(int i = 0; i < NUM_POINTS_X*NUM_POINTS_Y; i++) { - if(m_points[i].centerX != lastCenterX && m_points[i].centerY != lastcenterY) { - QSGGeometry::Point2D *lowerV = triangle->geometry()->vertexDataAsPoint2D(); - lowerV[0] = m_points[i].currentPos; - lowerV[1] = m_points[i+NUM_POINTS_X].currentPos; - lowerV[2] = m_points[i+NUM_POINTS_X+1].currentPos; - triangle->markDirty(QSGNode::DirtyGeometry); - triangle = static_cast(triangle->nextSibling()); - - QSGGeometry::Point2D *upperV = triangle->geometry()->vertexDataAsPoint2D(); - upperV[0] = m_points[i].currentPos; - upperV[1] = m_points[i+1].currentPos; - upperV[2] = m_points[i+NUM_POINTS_X+1].currentPos; - triangle = static_cast(triangle->nextSibling()); - } - } - - /* Regenerate a set of animation end points when the animation is finished */ - if(m_animationState >= 1.0) { - m_animationState = 0.0; - - for(int y = 0; y < NUM_POINTS_Y; y++) { - for(int x = 0; x < NUM_POINTS_X; x++) { - Point *point = &m_points[y*NUM_POINTS_Y+x]; - - if(x != 0 && x != (NUM_POINTS_X-1) && y != 0 && y != (NUM_POINTS_Y-1)) { - int offsetX = rand()%m_unitWidth - m_unitWidth/3; - int offsetY = rand()%m_unitHeight - m_unitHeight/3; - float normalization = ((float)m_unitWidth)/(2*(abs(offsetX)+abs(offsetY))); - offsetX*=normalization; - offsetY*=normalization; - - point->animOriginX = point->animEndX; - point->animEndX = point->centerX + offsetX; - - point->animOriginY = point->animEndY; - point->animEndY = point->centerY + offsetY; - } - } - } - } - } -} diff --git a/src/controls/src/flatmeshnode.h b/src/controls/src/flatmeshnode.h deleted file mode 100644 index c0d01df..0000000 --- a/src/controls/src/flatmeshnode.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2016 Florent Revest - * All rights reserved. - * - * You may use this file under the terms of BSD license as follows: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the author nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLATMESHNODE_H -#define FLATMESHNODE_H - -#include -#include -#include - -#define NUM_POINTS_X 13 -#define NUM_POINTS_Y 13 - -struct Point { - qreal centerX; - qreal centerY; - - qreal animOriginX; - qreal animOriginY; - - qreal animEndX; - qreal animEndY; - - QSGGeometry::Point2D currentPos; -}; - -class FlatMeshNode : public QObject, public QSGSimpleRectNode -{ - Q_OBJECT -public: - FlatMeshNode(QQuickWindow *window, QRectF rect); - void setAnimated(bool animated); - - void setCenterColor(QColor c); - void setOuterColor(QColor c); - -public slots: - void maybeAnimate(); - void generateGrid(); - -private: - void updateColors(); - - qreal m_animationState; - bool m_animated; - int m_unitWidth, m_unitHeight; - QColor m_centerColor, m_outerColor; - QQuickWindow *m_window; - Point m_points[NUM_POINTS_X*NUM_POINTS_Y]; -}; - - -#endif // FLATMESHNODE_H diff --git a/src/controls/src/generate_flatmeshgeometry.py b/src/controls/src/generate_flatmeshgeometry.py new file mode 100755 index 0000000..c716fe0 --- /dev/null +++ b/src/controls/src/generate_flatmeshgeometry.py @@ -0,0 +1,135 @@ +#!/usr/bin/python3 +import pandas as pd +import numpy as np +import pyvista as pv +import math +import random + +# We can choose this constant to make the FlatMesh look more or less low-poly +nb_points = 100 + +# Find the radius of nb_points packed circles from www.packomania.com +radius_table = pd.read_csv("http://hydra.nat.uni-magdeburg.de/packing/cci/txt/radius.txt", header=None, sep=' ') +radius = float(radius_table[radius_table[0]==nb_points][1]) + +# Download the coordinates of nb_points optimally packed circles +points = pd.read_csv("http://hydra.nat.uni-magdeburg.de/packing/cci/txt/cci" + str(nb_points) + ".txt", sep=' ', + skipinitialspace=True, header=None).drop(columns=0).to_numpy() + +# Import these points as a 3D points cloud in PyVista +cloud = pv.PolyData(np.hstack((points, np.zeros((points.shape[0], 1))))) + +# Generate a Delaunay triangulation of this points cloud +mesh = cloud.delaunay_2d() + +# Find a series of triangle strips (see GL_TRIANGLE_STRIP) that describes this mesh +strips = mesh.strip() + +# Coordinates can be repeated if a point at x, y needs different color mixes as the last point of different triangles +# However, we try to de-duplicate vertices as much as we can and use an index array to point back to this buffer +vertices = [] +indices = [] + +# Each vertex is represented as a tuple of: x, y (its base coordinates, before any shift) and a color mixing ratio +def add_vertex(index, mix=None): + x, y = points[index] + + # Re-use existing vertices as much as possible + for i, vertex in enumerate(vertices): + if vertex[0] == x and vertex[1] == y: + if vertex[2] == None: + vertices[i] = (x, y, mix) + + if vertices[i][2] == mix or mix == None: + indices.append(i) + return + + # If we haven't found a vertex to recycle, create a new one + indices.append(len(vertices)) + vertices.append((x, y, mix)) + +# The color mixing ratio of a triangle depends on the distance of its baricenter to the center +def triangle_color_mix(index0, index1, index2): + x0, y0 = points[index0] + x1, y1 = points[index1] + x2, y2 = points[index2] + + x = (x0+x1+x2)/3 + y = (y0+y1+y2)/3 + + distance_to_center = math.sqrt(x**2 + y**2) + # Stretch the distance a little bit to use the full [0:1] range + distance_to_center *= 1.2 + + # Add a non-linearity (power 1.7) to make the gradient more interesting + mix = distance_to_center**1.7 + return min(mix, 1.0) + +# Iterate over all the strips found by PyVista +strip_len_index = 0 +for i in range(strips.n_strips): + strip_len = strips.strips[strip_len_index] + # The first two points of the strip don't need a color mix + add_vertex(strips.strips[strip_len_index+1]) + add_vertex(strips.strips[strip_len_index+2]) + # Iterate over all the other points of the strip + for i in range(strip_len_index+3, strip_len_index+1+strip_len): + index = strips.strips[i] + add_vertex(index, triangle_color_mix(strips.strips[i-2], strips.strips[i-1], index)) + + strip_len_index = strip_len_index + 1 + strip_len + + # Start a new strip using GL_PRIMITIVE_RESTART + if not strip_len_index == len(strips.strips): + indices.append(0xffff) + +# Generate a C++ header that contains the vertices/indices/shifts +out = open("flatmeshgeometry.h", "w") +out.write("// Do not modify manually! This file is generated by generate_flatmeshgeometry.py\n\n") + +# Output the vertices and their color mix attribute (VAO in OpenGL terminology) +out.write("static const QVector3D flatmesh_vertices[] = {\n") +for vertex in vertices: + x = vertex[0] + y = vertex[1] + mix = vertex[2] if vertex[2] is not None else 0.0 + out.write(" QVector3D(" + str(x/2) + ", " + str(y/2) + ", " + str(mix) + "),\n") +out.write("};\n") +out.write("static const int flatmesh_vertices_sz = " + str(len(vertices)) + ";\n\n") + +# Output the indices (EBO in OpenGL terminology) +out.write("static const unsigned short flatmesh_indices[] = {\n") +for index in indices: + out.write(" " + str(index) + ",\n") +out.write("};\n") +out.write("static const int flatmesh_indices_sz = " + str(len(indices)) + ";\n\n") + +# Pre-calculate a bunch of random shifts to save the watch some computing (https://xkcd.com/221/) +# A power of 2 here lets the compiler implement the modulo as a cheap AND bit-mask +random_shifts_nb = 128 +out.write("static const float flatmesh_shifts[] = {\n") +for i in range(random_shifts_nb): + # This sqrt() compensates the otherwise non-uniform probability distribution + r = radius * math.sqrt(random.random()) + alpha = 2 * math.pi * random.random() + + x = r * math.cos(alpha) + y = r * math.sin(alpha) + out.write(" " + str(x/2) + ", " + str(y/2) + ",\n") +out.write("};\n") +out.write("static const int flatmesh_shifts_nb = " + str(random_shifts_nb) + ";\n") +# For use by the inlined shader code +out.write("#define FLATMESH_SHIFTS_NB_STR \"" + str(random_shifts_nb) + "\"") + +out.close() + +# Output some statistics to make GPU memory usage more tractable +vertices_bytes = len(vertices)*(2*4+3) # Each vertex takes 2 floats and 3 chars +print(str(len(vertices)) + " vertices take " + str(vertices_bytes) + " bytes") +indices_bytes = len(indices)*2 # Each index takes 1 short +print(str(len(indices)) + " indices take " + str(indices_bytes) + " bytes") +shifts_bytes = random_shifts_nb*2*4 # Each shift takes 2 floats +print(str(random_shifts_nb) + " shifts take " + str(shifts_bytes) + " bytes") + +# With a total taking less than a page (4096B), we can be satisfied +print("Total takes " + str(vertices_bytes+indices_bytes+shifts_bytes) + " bytes")