196 lines
5.8 KiB
C++
196 lines
5.8 KiB
C++
|
||
// Created by Lenn on 2025/12/16.
|
||
//
|
||
|
||
#ifndef TACTILEIPC3D_GLWIDGET_H
|
||
#define TACTILEIPC3D_GLWIDGET_H
|
||
|
||
#include <qopenglshaderprogram.h>
|
||
#include <QOpenGLWidget>
|
||
#include <QOpenGLFunctions>
|
||
#include <QMutex>
|
||
#include <QOpenGLShaderProgram>
|
||
#include <QOpenGLFunctions_3_3_Core>
|
||
#include <QMatrix4x4>
|
||
#include <QVector3D>
|
||
#include <QString>
|
||
#include <QColor>
|
||
#include <atomic>
|
||
#include <qtmetamacros.h>
|
||
#include <qvectornd.h>
|
||
|
||
struct Ray {
|
||
QVector3D origin;
|
||
QVector3D dir;
|
||
};
|
||
|
||
class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core {
|
||
Q_OBJECT
|
||
Q_PROPERTY(float yaw READ yaw WRITE setYaw NOTIFY yawChanged)
|
||
Q_PROPERTY(int row READ row WRITE setRow)
|
||
Q_PROPERTY(int col READ col WRITE setCol)
|
||
// Q_PROPERTY(bool showGrid READ showGrid WRITE setShowGrid NOTIFY showGridChanged)
|
||
public:
|
||
enum RenderMode {
|
||
Realistic = 0,
|
||
DataViz = 1,
|
||
};
|
||
Q_ENUM(RenderMode)
|
||
|
||
enum LabelMode {
|
||
LabelsOff = 0,
|
||
LabelsHover = 1,
|
||
LabelsAlways = 2,
|
||
};
|
||
Q_ENUM(LabelMode)
|
||
|
||
explicit GLWidget(QWidget* parent = nullptr);
|
||
~GLWidget();
|
||
|
||
// panel 的物理尺寸(单位随你:米/毫米都行,只要全程一致)
|
||
void setPanelSize(float w, float h, float d);
|
||
void setPanelThickness(float h);
|
||
// rows/cols: 传感点阵行列;pitch: 点与点的间距;dotRaius: 单个点的“显示半径”
|
||
void setSpec(int rows, int cols, float pitch, float dotRaius);
|
||
// 总点数 = 行 * 列
|
||
int dotCount() const { return m_cols * m_rows; }
|
||
|
||
// 提交一帧传感值(数量必须等于 dotCount),在 paintGL 里用 instanced 的方式绘制
|
||
void submitValues(const QVector<float>& values);
|
||
|
||
float yaw() const { return m_camYawDeg; }
|
||
|
||
bool showGrid() const { return m_showGrid; }
|
||
|
||
int row() const { return m_rows; }
|
||
int col() const { return m_cols; }
|
||
|
||
public slots:
|
||
// 值域范围,用于 shader 里把 value 映射到颜色(绿->红)
|
||
void setRange(int minV, int maxV);
|
||
void setYaw(float yawDeg);
|
||
void setRenderModeString(const QString& mode);
|
||
void setLabelModeString(const QString& mode);
|
||
void setLightMode(bool on);
|
||
void setShowBg(bool on);
|
||
void setShowGrid(bool on);
|
||
void setCol(int col);
|
||
void setRow(int row);
|
||
void setColorLow(const QColor& color);
|
||
void setColorMid(const QColor& color);
|
||
void setColorHigh(const QColor& color);
|
||
|
||
signals:
|
||
void yawChanged();
|
||
void dotClicked(int index, int row, int col, float value);
|
||
|
||
protected:
|
||
void initializeGL() override;
|
||
void resizeGL(int w, int h) override;
|
||
void paintGL() override;
|
||
void mousePressEvent(QMouseEvent *event) override;
|
||
void mouseMoveEvent(QMouseEvent *event) override;
|
||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||
void wheelEvent(QWheelEvent *event) override;
|
||
|
||
private:
|
||
void initGeometry_();
|
||
void initPanelGeometry_();
|
||
void initDotGeometry_();
|
||
void initBackgroundGeometry_();
|
||
void initPrograms_();
|
||
void initDotTexture_();
|
||
void initRoomGeometry_();
|
||
void updateInstanceBufferIfNeeded_();
|
||
void updateMatrices_();
|
||
void updateRoom_();
|
||
bool projectToScreen_(const QVector3D& world, QPointF* out) const;
|
||
int pickDotIndex_(const QPoint& pos, QVector3D* worldOut) const;
|
||
private:
|
||
// 传感值范围(用于颜色映射)
|
||
int m_min = 0;
|
||
int m_max = 1000;
|
||
|
||
// 点阵规格
|
||
int m_rows = 3;
|
||
int m_cols = 4;
|
||
|
||
// panel: 一个长方体/板子(当前只画顶面矩形)
|
||
float m_panelW = 0.25f;
|
||
float m_panelH = 0.35f;
|
||
float m_panelD = 0.05f;
|
||
|
||
// 点阵布局参数
|
||
float m_pitch = 0.1f;
|
||
float m_dotRadius = 0.03f;
|
||
|
||
// 传感数据(GUI/定时器线程提交,GL 线程绘制)
|
||
QMutex m_dataMutex;
|
||
QVector<float> m_latestValues;
|
||
bool m_valuesDirty = false;
|
||
|
||
std::atomic<bool> m_hasData{false};
|
||
|
||
// shader program(编译/链接后的可执行 GPU 程序)
|
||
QOpenGLShaderProgram* m_bgProg = nullptr;
|
||
QOpenGLShaderProgram* m_roomProg = nullptr;
|
||
QOpenGLShaderProgram* m_panelProg = nullptr;
|
||
QOpenGLShaderProgram* m_dotsProg = nullptr;
|
||
|
||
unsigned int m_dotTex = 0;
|
||
|
||
// panel 的 VAO/VBO/IBO(VAO: 顶点格式/绑定状态;VBO: 顶点数据;IBO: 索引数据)
|
||
unsigned int m_panelVao = 0;
|
||
unsigned int m_panelVbo = 0;
|
||
unsigned int m_panelIbo = 0;
|
||
int m_panelIndexCount = 0;
|
||
bool m_panelGeometryDirty = false;
|
||
|
||
// dots 的 VAO/VBO + instance VBO(instance VBO 每个点一条:offsetXZ + value)
|
||
unsigned int m_dotsVao = 0;
|
||
unsigned int m_dotsVbo = 0;
|
||
unsigned int m_instanceVbo = 0;
|
||
|
||
unsigned int room_vao = 0;
|
||
unsigned int room_vbo = 0;
|
||
unsigned int room_ibo = 0;
|
||
int room_index_count = 0;
|
||
bool m_showGrid = true;
|
||
|
||
int m_instanceCount = 0;
|
||
bool m_dotsGeometryDirty = false;
|
||
|
||
unsigned int m_bgVao = 0;
|
||
unsigned int m_bgVbo = 0;
|
||
bool m_lightMode = true;
|
||
bool m_showBg = true;
|
||
QVector3D m_colorLow{0.10f, 0.75f, 1.00f};
|
||
QVector3D m_colorMid{0.10f, 0.95f, 0.35f};
|
||
QVector3D m_colorHigh{1.00f, 0.22f, 0.10f};
|
||
|
||
// MVP = Projection * View * Model。
|
||
// 这里 panel/dots 顶点基本已经是“世界坐标”,所以我们用 proj*view 即可(model 先省略)。
|
||
QMatrix4x4 m_mvp;
|
||
QVector3D m_cameraPos{0.0f, 0.0f, 1.0f};
|
||
|
||
RenderMode m_renderMode = DataViz;
|
||
LabelMode m_labelMode = LabelsOff;
|
||
int m_hoveredIndex = -1;
|
||
|
||
// 早期/预留的矩阵数组(现在主要使用 QMatrix4x4 的 m_mvp,这些暂时保留做对照/扩展)
|
||
float m_proj[16]{};
|
||
float m_view[16]{};
|
||
float m_modelPanel[16]{};
|
||
|
||
float m_zoom_ = 45.0;
|
||
float m_camYawDeg = -90.0f;
|
||
float m_camPitchDeg = 0.0f;
|
||
|
||
std::atomic<bool> m_rightDown{false};
|
||
QPoint m_lastPos;
|
||
|
||
};
|
||
|
||
|
||
#endif //TACTILEIPC3D_GLWIDGET_H
|