Files
tactileipc3d/src/glwidget.h

183 lines
5.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 <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(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; }
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);
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 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/IBOVAO: 顶点格式/绑定状态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 VBOinstance 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;
// 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