Merge pull request #22204 from jffmichi/camsim

CAM: integrate new simulator as MDI widget into main window
This commit is contained in:
sliptonic
2026-02-09 11:40:06 -06:00
committed by GitHub
23 changed files with 717 additions and 498 deletions

View File

@@ -38,12 +38,12 @@ TYPESYSTEM_SOURCE(CAMSimulator::CAMSim, Base::BaseClass);
void CAMSim::BeginSimulation(const Part::TopoShape& stock, float quality)
{
DlgCAMSimulator::GetInstance()->startSimulation(stock, quality);
DlgCAMSimulator::instance()->startSimulation(stock, quality);
}
void CAMSimulator::CAMSim::resetSimulation()
{
DlgCAMSimulator::GetInstance()->resetSimulation();
DlgCAMSimulator::instance()->resetSimulation();
}
void CAMSim::addTool(
@@ -53,7 +53,7 @@ void CAMSim::addTool(
float resolution
)
{
DlgCAMSimulator::GetInstance()->addTool(toolProfilePoints, toolNumber, diameter, resolution);
DlgCAMSimulator::instance()->addTool(toolProfilePoints, toolNumber, diameter, resolution);
}
void CAMSimulator::CAMSim::SetBaseShape(const Part::TopoShape& baseShape, float resolution)
@@ -62,11 +62,11 @@ void CAMSimulator::CAMSim::SetBaseShape(const Part::TopoShape& baseShape, float
return;
}
DlgCAMSimulator::GetInstance()->SetBaseShape(baseShape, resolution);
DlgCAMSimulator::instance()->setBaseShape(baseShape, resolution);
}
void CAMSim::AddCommand(Command* cmd)
{
std::string gline = cmd->toGCode();
DlgCAMSimulator::GetInstance()->addGcodeCommand(gline.c_str());
DlgCAMSimulator::instance()->addGcodeCommand(gline.c_str());
}

View File

@@ -69,9 +69,6 @@ public:
);
void SetBaseShape(const Part::TopoShape& baseShape, float resolution);
void AddCommand(Command* cmd);
public:
std::unique_ptr<SimStock> m_stock;
};
} // namespace CAMSimulator

View File

@@ -24,6 +24,8 @@ SET(CAMSimulator_SRCS_Module
DlgCAMSimulator.cpp
DlgCAMSimulator.h
PreCompiled.h
ViewCAMSimulator.cpp
ViewCAMSimulator.h
)
SET(CAMSimulator_SRCS_Core

View File

@@ -24,15 +24,19 @@
#include "DlgCAMSimulator.h"
#include "ViewCAMSimulator.h"
#include "MillSimulation.h"
#include "Gui/View3DInventorViewer.h"
#include <Mod/Part/App/BRepMesh.h>
#include <QDateTime>
#include <QSurfaceFormat>
#include <QPoint>
#include <QTimerEvent>
#include <App/Document.h>
QOpenGLContext* gOpenGlContext;
#include <Gui/MainWindow.h>
#include <Gui/MDIView.h>
#include <QHBoxLayout>
#include <QPointer>
using namespace MillSim;
@@ -41,99 +45,125 @@ namespace CAMSimulator
static const float MouseScrollDelta = 120.0F;
DlgCAMSimulator::DlgCAMSimulator(QWindow* parent)
: QWindow(parent)
static QPointer<ViewCAMSimulator> viewCAMSimulator;
DlgCAMSimulator::DlgCAMSimulator(ViewCAMSimulator& view, QWidget* parent)
: QOpenGLWidget(parent)
, mView(view)
{
setSurfaceType(QWindow::OpenGLSurface);
mMillSimulator = new MillSimulation();
// Under certain conditions, e.g. when docking/undocking the cam simulator, we need to create a
// new widget (due to some OpenGL bug). The new widget becomes THE cam simulator.
viewCAMSimulator = &view;
QSurfaceFormat format;
format.setVersion(4, 1); // Request OpenGL 4.1 - for MacOS
format.setProfile(QSurfaceFormat::CoreProfile); // Use the core profile = for MacOS
int samples = Gui::View3DInventorViewer::getNumSamples();
if (samples > 1) {
format.setSamples(samples);
}
format.setSwapInterval(2);
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
setFormat(format);
setMouseTracking(true);
mMillSimulator.reset(new MillSimulation);
mAnimatingTimer.setInterval(0);
connect(
&mAnimatingTimer,
&QTimer::timeout,
this,
static_cast<void (DlgCAMSimulator::*)()>(&DlgCAMSimulator::update)
);
}
DlgCAMSimulator::~DlgCAMSimulator()
{
delete mMillSimulator;
makeCurrent();
mMillSimulator = nullptr;
}
void DlgCAMSimulator::render(QPainter* painter)
void DlgCAMSimulator::cloneFrom(const DlgCAMSimulator& from)
{
Q_UNUSED(painter);
mNeedsInitialize = true;
mNeedsClear = true;
setAnimating(from.mAnimating);
mQuality = from.mQuality;
mGCode = from.mGCode;
mTools = from.mTools;
mStock = from.mStock;
mStock.needsUpdate = true;
mBase = from.mBase;
mBase.needsUpdate = true;
const auto state = from.mMillSimulator->GetState();
mState = std::make_unique<MillSim::MillSimulationState>(state);
}
void DlgCAMSimulator::render()
DlgCAMSimulator* DlgCAMSimulator::instance()
{
mMillSimulator->ProcessSim((unsigned int)(QDateTime::currentMSecsSinceEpoch()));
}
if (!viewCAMSimulator) {
auto view = new ViewCAMSimulator(nullptr, nullptr);
viewCAMSimulator = view;
void DlgCAMSimulator::renderLater()
{
requestUpdate();
}
bool DlgCAMSimulator::event(QEvent* event)
{
switch (event->type()) {
case QEvent::UpdateRequest:
renderNow();
return true;
default:
break;
Gui::getMainWindow()->addWindow(view);
}
return QWindow::event(event);
return &viewCAMSimulator->dlg();
}
void DlgCAMSimulator::exposeEvent(QExposeEvent* event)
void DlgCAMSimulator::setAnimating(bool animating)
{
Q_UNUSED(event);
if (animating == mAnimating) {
return;
}
if (isExposed()) {
renderNow();
mAnimating = animating;
if (animating) {
mAnimatingTimer.start();
}
else {
mAnimatingTimer.stop();
}
}
void DlgCAMSimulator::mouseMoveEvent(QMouseEvent* ev)
void DlgCAMSimulator::startSimulation(const Part::TopoShape& stock, float quality)
{
int modifiers = (ev->modifiers() & Qt::ShiftModifier) != 0 ? MS_KBD_SHIFT : 0;
modifiers |= (ev->modifiers() & Qt::ControlModifier) != 0 ? MS_KBD_CONTROL : 0;
modifiers |= (ev->modifiers() & Qt::AltModifier) != 0 ? MS_KBD_ALT : 0;
App::Document* doc = App::GetApplication().getActiveDocument();
mView.setWindowTitle(tr("%1 - New CAM Simulator").arg(QString::fromUtf8(doc->getName())));
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QPoint pnt = ev->pos();
#else
QPoint pnt = ev->position().toPoint();
#endif
mMillSimulator->MouseMove(pnt.x(), pnt.y(), modifiers);
}
mQuality = quality;
mNeedsInitialize = true;
void DlgCAMSimulator::mousePressEvent(QMouseEvent* ev)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QPoint pnt = ev->pos();
#else
QPoint pnt = ev->position().toPoint();
#endif
mMillSimulator->MousePress(ev->button(), true, pnt.x(), pnt.y());
}
setStockShape(stock, 1);
setAnimating(true);
void DlgCAMSimulator::mouseReleaseEvent(QMouseEvent* ev)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QPoint pnt = ev->pos();
#else
QPoint pnt = ev->position().toPoint();
#endif
mMillSimulator->MousePress(ev->button(), false, pnt.x(), pnt.y());
}
void DlgCAMSimulator::wheelEvent(QWheelEvent* ev)
{
mMillSimulator->MouseScroll((float)ev->angleDelta().y() / MouseScrollDelta);
Gui::getMainWindow()->setActiveWindow(&mView);
mView.show();
}
void DlgCAMSimulator::resetSimulation()
{}
{
mNeedsClear = true;
mGCode.clear();
mTools.clear();
mStock = {};
mBase = {};
}
void DlgCAMSimulator::addGcodeCommand(const char* cmd)
{
mMillSimulator->AddGcodeLine(cmd);
mGCode.push_back(cmd);
}
void DlgCAMSimulator::addTool(
@@ -144,45 +174,16 @@ void DlgCAMSimulator::addTool(
)
{
Q_UNUSED(resolution)
std::string toolCmd = "T" + std::to_string(toolNumber);
mMillSimulator->AddGcodeLine(toolCmd.c_str());
if (!mMillSimulator->ToolExists(toolNumber)) {
mMillSimulator->AddTool(toolProfilePoints, toolNumber, diameter);
}
addGcodeCommand(toolCmd.c_str());
mTools.emplace_back(toolProfilePoints, toolNumber, diameter);
}
void DlgCAMSimulator::hideEvent(QHideEvent* ev)
static SimShape getMeshData(const Part::TopoShape& tshape, float resolution)
{
mMillSimulator->Clear();
doGlCleanup();
mAnimating = false;
QWindow::hideEvent(ev);
close();
mInstance = nullptr;
}
SimShape ret;
void DlgCAMSimulator::resizeEvent(QResizeEvent* event)
{
if (!mContext) {
return;
}
QSize newSize = event->size();
int newWidth = newSize.width();
int newHeight = newSize.height();
if (mMillSimulator != nullptr) {
mMillSimulator->UpdateWindowScale(newWidth, newHeight);
}
const qreal retinaScale = devicePixelRatio();
glViewport(0, 0, (int)(newWidth * retinaScale), (int)(newHeight * retinaScale));
}
void DlgCAMSimulator::GetMeshData(
const Part::TopoShape& tshape,
float resolution,
std::vector<Vertex>& verts,
std::vector<GLushort>& indices
)
{
std::vector<int> normalCount;
int nVerts = 0;
for (auto& shape : tshape.getSubTopoShapes(TopAbs_FACE)) {
@@ -195,9 +196,9 @@ void DlgCAMSimulator::GetMeshData(
// copy triangle indices and calculate normals
for (auto face : facets) {
indices.push_back(face.I1 + nVerts);
indices.push_back(face.I2 + nVerts);
indices.push_back(face.I3 + nVerts);
ret.indices.push_back(face.I1 + nVerts);
ret.indices.push_back(face.I2 + nVerts);
ret.indices.push_back(face.I3 + nVerts);
// calculate normal
Base::Vector3d vAB = points[face.I2] - points[face.I1];
@@ -219,162 +220,158 @@ void DlgCAMSimulator::GetMeshData(
Base::Vector3d& normal = normals[i];
int count = normalCount[i];
normal /= count;
verts.push_back(Vertex(point.x, point.y, point.z, normal.x, normal.y, normal.z));
ret.verts.push_back(Vertex(point.x, point.y, point.z, normal.x, normal.y, normal.z));
}
nVerts = verts.size();
}
}
void DlgCAMSimulator::startSimulation(const Part::TopoShape& stock, float quality)
{
mQuality = quality;
mNeedsInitialize = true;
show();
checkInitialization();
SetStockShape(stock, 1);
setAnimating(true);
}
void DlgCAMSimulator::initialize()
{
const qreal retinaScale = devicePixelRatio();
mMillSimulator->InitSimulation(mQuality, retinaScale);
glViewport(0, 0, (int)(width() * retinaScale), (int)(height() * retinaScale));
}
void DlgCAMSimulator::checkInitialization()
{
if (!mContext) {
mLastContext = QOpenGLContext::currentContext();
mContext = new QOpenGLContext(this);
mContext->setFormat(requestedFormat());
mContext->create();
QSurfaceFormat format;
format.setSamples(16);
format.setSwapInterval(2);
mContext->setFormat(format);
gOpenGlContext = mContext;
mNeedsInitialize = true;
nVerts = ret.verts.size();
}
mContext->makeCurrent(this);
ret.needsUpdate = true;
return ret;
}
void DlgCAMSimulator::setStockShape(const Part::TopoShape& shape, float resolution)
{
mStock = getMeshData(shape, resolution);
}
void DlgCAMSimulator::setBaseShape(const Part::TopoShape& tshape, float resolution)
{
mBase = getMeshData(tshape, resolution);
}
void DlgCAMSimulator::mouseMoveEvent(QMouseEvent* ev)
{
int modifiers = (ev->modifiers() & Qt::ShiftModifier) != 0 ? MS_KBD_SHIFT : 0;
modifiers |= (ev->modifiers() & Qt::ControlModifier) != 0 ? MS_KBD_CONTROL : 0;
modifiers |= (ev->modifiers() & Qt::AltModifier) != 0 ? MS_KBD_ALT : 0;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QPoint pnt = ev->pos();
#else
QPoint pnt = ev->position().toPoint();
#endif
const qreal ratio = devicePixelRatioF();
mMillSimulator->MouseMove(pnt.x() * ratio, pnt.y() * ratio, modifiers);
update();
}
void DlgCAMSimulator::mousePressEvent(QMouseEvent* ev)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QPoint pnt = ev->pos();
#else
QPoint pnt = ev->position().toPoint();
#endif
const qreal ratio = devicePixelRatioF();
mMillSimulator->MousePress(ev->button(), true, pnt.x() * ratio, pnt.y() * ratio);
update();
}
void DlgCAMSimulator::mouseReleaseEvent(QMouseEvent* ev)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QPoint pnt = ev->pos();
#else
QPoint pnt = ev->position().toPoint();
#endif
const qreal ratio = devicePixelRatioF();
mMillSimulator->MousePress(ev->button(), false, pnt.x() * ratio, pnt.y() * ratio);
update();
}
void DlgCAMSimulator::wheelEvent(QWheelEvent* ev)
{
mMillSimulator->MouseScroll((float)ev->angleDelta().y() / MouseScrollDelta);
update();
}
void DlgCAMSimulator::updateResources()
{
// clear simulator
if (mNeedsClear) {
mMillSimulator->Clear();
mLastGCode = 0;
mNeedsClear = false;
}
// update gcode
for (int i = mLastGCode; i < (int)mGCode.size(); i++) {
const std::string& cmd = mGCode[i];
mMillSimulator->AddGcodeLine(cmd.c_str());
}
mLastGCode = mGCode.size();
// update tools
for (const auto& tool : mTools) {
if (!mMillSimulator->ToolExists(tool.id)) {
mMillSimulator->AddTool(tool.profile, tool.id, tool.diameter);
}
}
// initialize simulator
if (mNeedsInitialize) {
initializeOpenGLFunctions();
initialize();
mMillSimulator->InitSimulation(mQuality);
mNeedsInitialize = false;
}
}
void DlgCAMSimulator::doGlCleanup()
{
if (mLastContext != nullptr) {
mLastContext->makeCurrent(this);
// update stock and base
if (mStock.needsUpdate) {
mMillSimulator->SetArbitraryStock(mStock.verts, mStock.indices);
mStock.needsUpdate = false;
}
if (mContext != nullptr) {
mContext->deleteLater();
mContext = nullptr;
if (mBase.needsUpdate) {
mMillSimulator->SetBaseObject(mBase.verts, mBase.indices);
mBase.needsUpdate = false;
}
// update state
if (mState) {
mMillSimulator->SetState(*mState);
mState = nullptr;
}
}
void DlgCAMSimulator::renderNow()
void DlgCAMSimulator::updateWindowScale()
{
static unsigned int lastTime = 0;
static int frameCount = 0;
static int fps = 0;
if (!isExposed()) {
return;
}
checkInitialization();
frameCount++;
unsigned int curtime = QDateTime::currentMSecsSinceEpoch();
unsigned int timediff = curtime - lastTime;
if (timediff > 10000) {
fps = frameCount * 1000 / timediff; // for debug only. not used otherwise.
lastTime = curtime;
frameCount = 0;
}
render();
mContext->swapBuffers(this);
if (mAnimating) {
renderLater();
}
(void)fps;
const qreal ratio = devicePixelRatioF();
mMillSimulator->UpdateWindowScale(width() * ratio, height() * ratio);
}
void DlgCAMSimulator::setAnimating(bool animating)
void DlgCAMSimulator::initializeGL()
{
mAnimating = animating;
if (animating) {
renderLater();
}
initializeOpenGLFunctions();
}
DlgCAMSimulator* DlgCAMSimulator::GetInstance()
void DlgCAMSimulator::paintGL()
{
if (mInstance == nullptr) {
QSurfaceFormat format;
format.setVersion(4, 1); // Request OpenGL 4.1 - for MacOS
format.setProfile(QSurfaceFormat::CoreProfile); // Use the core profile = for MacOS
int samples = Gui::View3DInventorViewer::getNumSamples();
if (samples > 1) {
format.setSamples(samples);
}
format.setSwapInterval(2);
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
mInstance = new DlgCAMSimulator();
mInstance->setFormat(format);
mInstance->resize(MillSim::gWindowSizeW, MillSim::gWindowSizeH);
mInstance->setModality(Qt::ApplicationModal);
mInstance->setMinimumWidth(700);
mInstance->setMinimumHeight(400);
updateResources();
App::Document* doc = App::GetApplication().getActiveDocument();
mInstance->setTitle(tr("%1 - New CAM Simulator").arg(QString::fromUtf8(doc->getName())));
}
return mInstance;
// We need to call updateWindowScale on every render since the devicePixelRatio we get in
// resizeGL might be wrong on the first resize.
updateWindowScale();
mMillSimulator->ProcessSim((unsigned int)(QDateTime::currentMSecsSinceEpoch()));
}
void DlgCAMSimulator::SetStockShape(const Part::TopoShape& shape, float resolution)
void DlgCAMSimulator::resizeGL(int w, int h)
{
std::vector<Vertex> verts;
std::vector<GLushort> indices;
GetMeshData(shape, resolution, verts, indices);
mMillSimulator->SetArbitraryStock(verts, indices);
(void)w, (void)h;
}
void DlgCAMSimulator::SetBaseShape(const Part::TopoShape& tshape, float resolution)
{
std::vector<Vertex> verts;
std::vector<GLushort> indices;
GetMeshData(tshape, resolution, verts, indices);
mMillSimulator->SetBaseObject(verts, indices);
}
DlgCAMSimulator* DlgCAMSimulator::mInstance = nullptr;
//************************************************************************************************************
// stock
//************************************************************************************************************
SimStock::SimStock(float px, float py, float pz, float lx, float ly, float lz, float res)
: mPx(px)
, mPy(py)
, mPz(pz + 0.005 * lz)
, mLx(lx)
, mLy(ly)
, mLz(1.01 * lz)
{
(void)res;
}
SimStock::~SimStock()
{}
} // namespace CAMSimulator

View File

@@ -29,10 +29,14 @@
# pragma warning(disable : 4251)
#endif
#include <queue>
#include <functional>
#include <Mod/Part/App/TopoShape.h>
#include <QWindow>
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QPainter>
#include <QTimer>
#include <QExposeEvent>
#include <QResizeEvent>
#include <QMouseEvent>
@@ -42,44 +46,53 @@ namespace MillSim
{
// use short declaration as using 'include' causes a header loop
class MillSimulation;
class MillSimulationState;
struct Vertex;
} // namespace MillSim
namespace Gui
{
class MDIView;
}
namespace CAMSimulator
{
struct SimStock
class ViewCAMSimulator;
struct SimShape
{
public:
SimStock(float px, float py, float pz, float lx, float ly, float lz, float res);
~SimStock();
public:
float mPx, mPy, mPz; // stock zero position
float mLx, mLy, mLz; // stock dimensions
std::vector<MillSim::Vertex> verts;
std::vector<GLushort> indices;
bool needsUpdate = false;
};
class DlgCAMSimulator: public QWindow, public QOpenGLExtraFunctions
struct SimTool
{
public:
std::vector<float> profile;
int id;
float diameter;
float resolution;
};
class DlgCAMSimulator: public QOpenGLWidget, public QOpenGLExtraFunctions
{
Q_OBJECT
public:
explicit DlgCAMSimulator(QWindow* parent = nullptr);
explicit DlgCAMSimulator(ViewCAMSimulator& view, QWidget* parent = nullptr);
~DlgCAMSimulator() override;
virtual void render(QPainter* painter);
virtual void render();
virtual void initialize();
void cloneFrom(const DlgCAMSimulator& from);
static DlgCAMSimulator* instance();
void setAnimating(bool animating);
static DlgCAMSimulator* GetInstance();
void SetStockShape(const Part::TopoShape& tshape, float resolution);
void SetBaseShape(const Part::TopoShape& tshape, float resolution);
public: // slots:
void renderLater();
void renderNow();
void startSimulation(const Part::TopoShape& stock, float quality);
void resetSimulation();
void addGcodeCommand(const char* cmd);
void addTool(
const std::vector<float>& toolProfilePoints,
@@ -88,37 +101,44 @@ public: // slots:
float resolution
);
void setStockShape(const Part::TopoShape& tshape, float resolution);
void setBaseShape(const Part::TopoShape& tshape, float resolution);
protected:
bool event(QEvent* event) override;
void checkInitialization();
void doGlCleanup();
void exposeEvent(QExposeEvent* event) override;
void mouseMoveEvent(QMouseEvent* ev) override;
void mousePressEvent(QMouseEvent* ev) override;
void mouseReleaseEvent(QMouseEvent* ev) override;
void wheelEvent(QWheelEvent* ev) override;
void hideEvent(QHideEvent* ev) override;
void resizeEvent(QResizeEvent* event) override;
void GetMeshData(
const Part::TopoShape& tshape,
float resolution,
std::vector<MillSim::Vertex>& verts,
std::vector<GLushort>& indices
);
void updateResources();
void updateWindowScale();
void initializeGL() override;
void paintGL() override;
void resizeGL(int w, int h) override;
private:
bool mAnimating = false;
bool mNeedsInitialize = false;
bool mNeedsClear = false;
bool mAnimating = false;
QTimer mAnimatingTimer;
QOpenGLContext* mContext = nullptr;
QOpenGLContext* mLastContext = nullptr;
MillSim::MillSimulation* mMillSimulator = nullptr;
static DlgCAMSimulator* mInstance;
std::unique_ptr<MillSim::MillSimulation> mMillSimulator;
float mQuality = 10;
};
std::vector<std::string> mGCode;
std::size_t mLastGCode = 0;
std::vector<SimTool> mTools;
SimShape mStock;
SimShape mBase;
ViewCAMSimulator& mView;
std::unique_ptr<MillSim::MillSimulationState> mState;
};
} // namespace CAMSimulator
#endif // PATHSIMULATOR_PathSim_H

View File

@@ -27,12 +27,8 @@
namespace MillSim
{
int gWindowSizeW = 800;
int gWindowSizeH = 600;
int gDebug = -1;
mat4x4 identityMat = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
const mat4x4 identityMat = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}};
void GLClearError()
{
@@ -50,11 +46,4 @@ bool GLLogError()
return isError;
}
typedef struct Vertex
{
vec3 pos;
vec3 col;
} Vertex;
} // namespace MillSim

View File

@@ -24,10 +24,10 @@
#ifndef __glutils_h__
#define __glutils_h__
#include "OpenGlWrapper.h"
#include "linmath.h"
constexpr auto EPSILON = 0.00001f;
#define EQ_FLOAT(x, y) (fabs((x) - (y)) < EPSILON)
@@ -46,7 +46,6 @@ constexpr auto EPSILON = 0.00001f;
__debugbreak(); \
}
#define GLDELETE(type, x) \
{ \
if (x != 0) \
@@ -62,11 +61,12 @@ constexpr auto EPSILON = 0.00001f;
namespace MillSim
{
extern const mat4x4 identityMat;
void GLClearError();
bool GLLogError();
extern mat4x4 identityMat;
extern int gDebug;
extern int gWindowSizeW;
extern int gWindowSizeH;
} // namespace MillSim
#endif // !__glutils_h__

View File

@@ -30,12 +30,11 @@
#include <QPoint>
#include <QCoreApplication>
using namespace MillSim;
// clang-format off
// NOLINTBEGIN(*-magic-numbers)
GuiItem guiItems[] = {
static const std::vector<DefaultGuiItem> defaultGuiItems = {
{.name=eGuiItemSlider, .vbo=0, .vao=0, .sx=28, .sy=-80, .actionKey=0, .hidden=false, .flags=0},
{.name=eGuiItemThumb, .vbo=0, .vao=0, .sx=328, .sy=-94, .actionKey=1, .hidden=false, .flags=0},
{.name=eGuiItemPause, .vbo=0, .vao=0, .sx=28, .sy=-50, .actionKey='P', .hidden=true, .flags=0},
@@ -58,10 +57,9 @@ GuiItem guiItems[] = {
// NOLINTEND(*-magic-numbers)
// clang-format on
#define NUM_GUI_ITEMS (sizeof(guiItems) / sizeof(GuiItem))
#define TEX_SIZE 256
std::vector<std::string> guiFileNames = {
static const std::vector<std::string> guiFileNames = {
"Slider.png",
"Thumb.png",
"Pause.png",
@@ -82,17 +80,49 @@ std::vector<std::string> guiFileNames = {
"Home.png"
};
GuiItem::GuiItem(const DefaultGuiItem& item, GuiDisplay& d)
: DefaultGuiItem(item)
, display(d)
{}
int GuiItem::posx()
{
return sx >= 0 ? sx : display.width() + sx;
}
int GuiItem::posy()
{
return sy >= 0 ? sy : display.height() + sy;
}
void GuiItem::setPosx(int x)
{
sx = sx >= 0 ? x : x - display.width();
}
void GuiItem::setPosy(int y)
{
sy = sy >= 0 ? y : y - display.height();
}
GuiDisplay::GuiDisplay()
{
for (auto& item : defaultGuiItems) {
mItems.emplace_back(item, *this);
}
}
void GuiDisplay::UpdateProjection()
{
mat4x4 projmat;
// mat4x4 viewmat;
mat4x4_ortho(projmat, 0, gWindowSizeW, gWindowSizeH, 0, -1, 1);
mat4x4_ortho(projmat, 0, mWidth, mHeight, 0, -1, 1);
mShader.Activate();
mShader.UpdateProjectionMat(projmat);
mThumbMaxMotion = guiItems[eGuiItemAmbientOclusion].posx()
+ guiItems[eGuiItemAmbientOclusion].texItem.w
- guiItems[eGuiItemSlider].posx(); // - guiItems[eGuiItemThumb].texItem.w;
HStretchGlItem(&(guiItems[eGuiItemSlider]), mThumbMaxMotion, 10.0f);
mThumbMaxMotion = mItems[eGuiItemAmbientOclusion].posx()
+ mItems[eGuiItemAmbientOclusion].texItem.w
- mItems[eGuiItemSlider].posx(); // - guiItems[eGuiItemThumb].texItem.w;
HStretchGlItem(&(mItems[eGuiItemSlider]), mThumbMaxMotion, 10.0f);
}
bool GuiDisplay::GenerateGlItem(GuiItem* guiItem)
@@ -127,7 +157,7 @@ bool GuiDisplay::GenerateGlItem(GuiItem* guiItem)
return true;
}
bool MillSim::GuiDisplay::HStretchGlItem(GuiItem* guiItem, float newWidth, float edgeWidth)
bool GuiDisplay::HStretchGlItem(GuiItem* guiItem, float newWidth, float edgeWidth)
{
if (guiItem->vbo == 0) {
return false;
@@ -190,6 +220,7 @@ bool GuiDisplay::InitGui()
if (guiInitiated) {
return true;
}
// index buffer
SetupTooltips();
glGenBuffers(1, &mIbo);
@@ -202,29 +233,32 @@ bool GuiDisplay::InitGui()
return false;
}
mTexture.LoadImage(buffer, TEX_SIZE, TEX_SIZE);
for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
guiItems[i].texItem = *tLoader.GetTextureItem(i);
GenerateGlItem(&(guiItems[i]));
for (unsigned int i = 0; i < mItems.size(); i++) {
auto& item = mItems[i];
item.texItem = *tLoader.GetTextureItem(i);
GenerateGlItem(&item);
}
mThumbStartX = guiItems[eGuiItemSlider].posx() - guiItems[eGuiItemThumb].texItem.w / 2;
mThumbMaxMotion = (float)guiItems[eGuiItemSlider].texItem.w;
mThumbStartX = mItems[eGuiItemSlider].posx() - mItems[eGuiItemThumb].texItem.w / 2;
mThumbMaxMotion = (float)mItems[eGuiItemSlider].texItem.w;
// init shader
mShader.CompileShader("GuiDisplay", (char*)VertShader2DTex, (char*)FragShader2dTex);
mShader.UpdateTextureSlot(0);
UpdatePlayState(false);
UpdateSimSpeed(1);
UpdateProjection();
guiInitiated = true;
UpdateWindowScale(800, 600);
return true;
}
void GuiDisplay::ResetGui()
{
mShader.Destroy();
for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
DestroyGlItem(&(guiItems[i]));
for (auto& item : mItems) {
DestroyGlItem(&item);
}
mTexture.DestroyTexture();
GLDELETE_BUFFER(mIbo);
@@ -233,13 +267,13 @@ void GuiDisplay::ResetGui()
void GuiDisplay::RenderItem(int itemId)
{
GuiItem* item = &(guiItems[itemId]);
GuiItem* item = &(mItems[itemId]);
if (item->hidden) {
return;
}
mat4x4 model;
mat4x4_translate(model, (float)item->posx(), (float)item->posy(), 0);
mShader.UpdateModelMat(model, nullptr);
mShader.UpdateModelMat(model, {});
if (item == mPressedItem) {
mShader.UpdateObjColor(mPressedColor);
}
@@ -262,33 +296,33 @@ void GuiDisplay::RenderItem(int itemId)
glDrawElements(GL_TRIANGLES, nTriangles, GL_UNSIGNED_SHORT, nullptr);
}
void MillSim::GuiDisplay::SetupTooltips()
void GuiDisplay::SetupTooltips()
{
guiItems[eGuiItemPause].toolTip
mItems[eGuiItemPause].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Pause simulation", nullptr);
guiItems[eGuiItemPlay].toolTip
mItems[eGuiItemPlay].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Play simulation", nullptr);
guiItems[eGuiItemSingleStep].toolTip
mItems[eGuiItemSingleStep].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Single step simulation", nullptr);
guiItems[eGuiItemSlower].toolTip
mItems[eGuiItemSlower].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Decrease simulation speed", nullptr);
guiItems[eGuiItemFaster].toolTip
mItems[eGuiItemFaster].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Increase simulation speed", nullptr);
guiItems[eGuiItemPath].toolTip
mItems[eGuiItemPath].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Show/Hide tool path", nullptr);
guiItems[eGuiItemRotate].toolTip = QCoreApplication::translate(
mItems[eGuiItemRotate].toolTip = QCoreApplication::translate(
"CAM:Simulator:Tooltips",
"Toggle turn table animation",
nullptr
);
guiItems[eGuiItemAmbientOclusion].toolTip
mItems[eGuiItemAmbientOclusion].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Toggle ambient occlusion", nullptr);
guiItems[eGuiItemView].toolTip = QCoreApplication::translate(
mItems[eGuiItemView].toolTip = QCoreApplication::translate(
"CAM:Simulator:Tooltips",
"Toggle view simulation/model",
nullptr
);
guiItems[eGuiItemHome].toolTip
mItems[eGuiItemHome].toolTip
= QCoreApplication::translate("CAM:Simulator:Tooltips", "Reset camera", nullptr);
}
@@ -296,24 +330,25 @@ void GuiDisplay::MouseCursorPos(int x, int y)
{
GuiItem* prevMouseOver = mMouseOverItem;
mMouseOverItem = nullptr;
for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
GuiItem* g = &(guiItems[i]);
if (g->actionKey == 0) {
for (auto& item : mItems) {
if (item.actionKey == 0) {
continue;
}
bool mouseCursorContained = x > g->posx() && x < (g->posx() + g->texItem.w) && y > g->posy()
&& y < (g->posy() + g->texItem.h);
bool mouseCursorContained = x > item.posx() && x < (item.posx() + item.texItem.w)
&& y > item.posy() && y < (item.posy() + item.texItem.h);
g->mouseOver = !g->hidden && mouseCursorContained;
item.mouseOver = !item.hidden && mouseCursorContained;
if (g->mouseOver) {
mMouseOverItem = g;
if (item.mouseOver) {
mMouseOverItem = &item;
}
}
if (mMouseOverItem != prevMouseOver) {
if (mMouseOverItem != nullptr && !mMouseOverItem->toolTip.isEmpty()) {
QPoint pos(x, y);
QPoint globPos = CAMSimulator::DlgCAMSimulator::GetInstance()->mapToGlobal(pos);
const QWidget* w = CAMSimulator::DlgCAMSimulator::instance();
const float ratio = w->devicePixelRatioF();
const QPoint pos(x / ratio, y / ratio);
const QPoint globPos = w->mapToGlobal(pos);
QToolTip::showText(globPos, mMouseOverItem->toolTip);
}
else {
@@ -322,7 +357,7 @@ void GuiDisplay::MouseCursorPos(int x, int y)
}
}
void MillSim::GuiDisplay::HandleActionItem(GuiItem* guiItem)
void GuiDisplay::HandleActionItem(GuiItem* guiItem)
{
if (guiItem->actionKey >= ' ') {
if (guiItem->flags & GUIITEM_CHECKABLE) {
@@ -373,45 +408,66 @@ void GuiDisplay::MouseDrag(int /* buttons */, int dx, int /* dy */)
}
}
void GuiDisplay::SetMillSimulator(MillSimulation* millSim)
{
mMillSim = millSim;
}
void GuiDisplay::UpdatePlayState(bool isRunning)
{
guiItems[eGuiItemPause].hidden = !isRunning;
guiItems[eGuiItemPlay].hidden = isRunning;
mItems[eGuiItemPause].hidden = !isRunning;
mItems[eGuiItemPlay].hidden = isRunning;
}
void MillSim::GuiDisplay::UpdateSimSpeed(int speed)
void GuiDisplay::UpdateSimSpeed(int speed)
{
guiItems[eGuiItem1].hidden = speed != 1;
guiItems[eGuiItem5].hidden = speed != 5;
guiItems[eGuiItem10].hidden = speed != 10;
guiItems[eGuiItem25].hidden = speed != 25;
guiItems[eGuiItem50].hidden = speed != 50;
mItems[eGuiItem1].hidden = speed != 1;
mItems[eGuiItem5].hidden = speed != 5;
mItems[eGuiItem10].hidden = speed != 10;
mItems[eGuiItem25].hidden = speed != 25;
mItems[eGuiItem50].hidden = speed != 50;
}
void MillSim::GuiDisplay::HandleKeyPress(int key)
void GuiDisplay::HandleKeyPress(int key)
{
for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
GuiItem* g = &(guiItems[i]);
if (g->actionKey == key) {
HandleActionItem(g);
for (auto& item : mItems) {
if (item.actionKey == key) {
HandleActionItem(&item);
}
}
}
bool MillSim::GuiDisplay::IsChecked(eGuiItems item)
bool GuiDisplay::IsChecked(eGuiItems item)
{
return (guiItems[item].flags & GUIITEM_CHECKED) != 0;
return (mItems[item].flags & GUIITEM_CHECKED) != 0;
}
void MillSim::GuiDisplay::UpdateWindowScale()
void GuiDisplay::UpdateWindowScale(int width, int height)
{
if (!guiInitiated || (width == mWidth && height == mHeight)) {
return;
}
mWidth = width;
mHeight = height;
UpdateProjection();
}
int GuiDisplay::width() const
{
return mWidth;
}
int GuiDisplay::height() const
{
return mHeight;
}
void GuiDisplay::Render(float progress)
{
if (mPressedItem == nullptr || mPressedItem->name != eGuiItemThumb) {
guiItems[eGuiItemThumb].setPosx((int)(mThumbMaxMotion * progress) + mThumbStartX);
mItems[eGuiItemThumb].setPosx((int)(mThumbMaxMotion * progress) + mThumbStartX);
}
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
@@ -421,7 +477,7 @@ void GuiDisplay::Render(float progress)
mShader.UpdateTextureSlot(0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (int i = 0; i < (int)NUM_GUI_ITEMS; i++) {
for (int i = 0; i < (int)mItems.size(); i++) {
RenderItem(i);
}
}

View File

@@ -58,7 +58,7 @@ enum eGuiItems
eGuiItemMax // this element must be the last item always
};
struct GuiItem
struct DefaultGuiItem
{
eGuiItems name;
unsigned int vbo, vao;
@@ -66,33 +66,32 @@ struct GuiItem
int actionKey; // action key when item pressed
bool hidden {}; // is item hidden
unsigned int flags {};
};
class GuiDisplay;
class GuiItem: public DefaultGuiItem
{
public:
explicit GuiItem(const DefaultGuiItem& item, GuiDisplay& d);
int posx();
int posy();
void setPosx(int x);
void setPosy(int y);
public:
bool mouseOver {};
TextureItem texItem {};
QString toolTip {};
int posx()
{
return sx >= 0 ? sx : gWindowSizeW + sx;
}
int posy()
{
return sy >= 0 ? sy : gWindowSizeH + sy;
}
void setPosx(int x)
{
sx = sx >= 0 ? x : x - gWindowSizeW;
}
void setPosy(int y)
{
sy = sy >= 0 ? y : y - gWindowSizeH;
}
GuiDisplay& display;
};
#define GUIITEM_CHECKABLE 0x01
#define GUIITEM_CHECKED 0x02
#define GUIITEM_STRETCHED 0x04
struct Vertex2D
{
float x, y;
@@ -102,7 +101,8 @@ struct Vertex2D
class GuiDisplay
{
public:
// GuiDisplay() {};
GuiDisplay();
bool InitGui();
void ResetGui();
void Render(float progress);
@@ -110,15 +110,15 @@ public:
void HandleActionItem(GuiItem* guiItem);
void MousePressed(int button, bool isPressed, bool isRunning);
void MouseDrag(int buttons, int dx, int dy);
void SetMillSimulator(MillSimulation* millSim)
{
mMillSim = millSim;
}
void SetMillSimulator(MillSimulation* millSim);
void UpdatePlayState(bool isRunning);
void UpdateSimSpeed(int speed);
void HandleKeyPress(int key);
bool IsChecked(eGuiItems item);
void UpdateWindowScale();
void UpdateWindowScale(int width, int height);
int width() const;
int height() const;
public:
bool guiInitiated = false;
@@ -131,6 +131,11 @@ private:
void RenderItem(int itemId);
void SetupTooltips();
std::vector<GuiItem> mItems;
int mWidth = -1;
int mHeight = -1;
vec3 mStdColor = {0.8f, 0.8f, 0.4f};
vec3 mToggleColor = {0.9f, 0.6f, 0.2f};
vec3 mHighlightColor = {1.0f, 1.0f, 0.9f};

View File

@@ -55,8 +55,8 @@ struct MillMotion
float x, y, z;
float i, j, k;
float r;
char retract_mode;
float retract_z;
char retract_mode = 0;
float retract_z = NAN;
};
static inline void MotionPosToVec(vec3 vec, const MillMotion* motion)

View File

@@ -89,11 +89,11 @@ void MillSimulation::SimNext()
}
}
void MillSimulation::InitSimulation(float quality, qreal devicePixelRatio)
void MillSimulation::InitSimulation(float quality)
{
ClearMillPathSegments();
millPathLine.Clear();
simDisplay.applySSAO = guiDisplay.IsChecked(eGuiItemAmbientOclusion);
mViewSSAO = guiDisplay.IsChecked(eGuiItemAmbientOclusion);
mDestMotion = mZeroPos;
// gDestPos = curMillOperation->startPos;
@@ -121,7 +121,7 @@ void MillSimulation::InitSimulation(float quality, qreal devicePixelRatio)
}
mNPathSteps = (int)MillPathSegments.size();
millPathLine.GenerateModel();
InitDisplay(quality, devicePixelRatio);
InitDisplay(quality);
}
EndMill* MillSimulation::GetTool(int toolId)
@@ -163,6 +163,11 @@ void MillSimulation::AddTool(const std::vector<float>& toolProfile, int toolid,
mToolTable.push_back(tool);
}
bool MillSimulation::ToolExists(int toolid)
{
return GetTool(toolid) != nullptr;
}
void MillSimulation::GlsimStart()
{
glDisable(GL_BLEND);
@@ -340,7 +345,7 @@ void MillSimulation::RenderTool()
void MillSimulation::RenderPath()
{
if (!guiDisplay.IsChecked(eGuiItemPath)) {
if (!mViewPath) {
return;
}
simDisplay.SetupLinePathPass(mPathStep, false);
@@ -378,10 +383,10 @@ void MillSimulation::Render()
RenderBaseShape();
RenderPath();
simDisplay.updateDisplay = false;
simDisplay.RenderResult(true);
simDisplay.RenderResult(true, mViewSSAO);
}
else {
simDisplay.RenderResult(false);
simDisplay.RenderResult(false, mViewSSAO);
}
/* if (mDebug > 0) {
@@ -446,7 +451,6 @@ void MillSimulation::HandleKeyPress(int key)
}
else if (key == 'K') {
mDebug2++;
gDebug = mNPathSteps - mDebug2;
}
else {
guiDisplay.HandleKeyPress(key);
@@ -502,11 +506,12 @@ void MillSimulation::HandleGuiAction(eGuiItems actionItem, bool checked)
break;
case eGuiItemPath:
mViewPath = checked;
simDisplay.updateDisplay = true;
break;
case eGuiItemAmbientOclusion:
simDisplay.applySSAO = checked;
mViewSSAO = checked;
simDisplay.updateDisplay = true;
break;
@@ -529,15 +534,19 @@ void MillSimulation::HandleGuiAction(eGuiItems actionItem, bool checked)
}
void MillSimulation::InitDisplay(float quality, qreal devicePixelRatio)
void MillSimulation::InitDisplay(float quality)
{
// generate tools
for (unsigned int i = 0; i < mToolTable.size(); i++) {
mToolTable[i]->GenerateDisplayLists(quality);
}
// Make sure the next call to UpdateWindowScale will not return early.
mWidth = -1;
mHeight = -1;
// init 3d display
simDisplay.InitGL(devicePixelRatio);
simDisplay.InitGL();
// init gui elements
guiDisplay.InitGui();
@@ -549,13 +558,16 @@ void MillSimulation::SetBoxStock(float x, float y, float z, float l, float w, fl
simDisplay.ScaleViewToStock(&mStockObject);
}
void MillSimulation::SetArbitraryStock(std::vector<Vertex>& verts, std::vector<GLushort>& indices)
void MillSimulation::SetArbitraryStock(
const std::vector<Vertex>& verts,
const std::vector<GLushort>& indices
)
{
mStockObject.GenerateSolid(verts, indices);
simDisplay.ScaleViewToStock(&mStockObject);
}
void MillSimulation::SetBaseObject(std::vector<Vertex>& verts, std::vector<GLushort>& indices)
void MillSimulation::SetBaseObject(const std::vector<Vertex>& verts, const std::vector<GLushort>& indices)
{
mBaseShape.GenerateSolid(verts, indices);
}
@@ -639,13 +651,16 @@ void MillSimulation::Zoom(float factor)
void MillSimulation::UpdateWindowScale(int width, int height)
{
if (width == gWindowSizeW && height == gWindowSizeH) {
if (width == mWidth && height == mHeight) {
return;
}
gWindowSizeW = width;
gWindowSizeH = height;
simDisplay.UpdateWindowScale();
guiDisplay.UpdateWindowScale();
mWidth = width;
mHeight = height;
simDisplay.UpdateWindowScale(width, height);
guiDisplay.UpdateWindowScale(width, height);
simDisplay.updateDisplay = true;
}
@@ -676,4 +691,26 @@ void MillSimulation::SetSimulationStage(float stage)
CalcSegmentPositions();
}
void MillSimulation::SetState(const MillSimulationState& state)
{
mSimPlaying = state.mSimPlaying;
mSingleStep = state.mSingleStep;
guiDisplay.UpdatePlayState(mSimPlaying);
const float stage = (float)state.mCurStep / state.mNTotalSteps;
SetSimulationStage(stage);
mSimSpeed = state.mSimSpeed;
guiDisplay.UpdateSimSpeed(mSimSpeed);
mViewItems = state.mViewItems;
mViewPath = state.mViewPath;
mViewSSAO = state.mViewSSAO;
}
const MillSimulationState& MillSimulation::GetState() const
{
return *this;
}
} // namespace MillSim

View File

@@ -46,7 +46,23 @@
namespace MillSim
{
class MillSimulation
struct MillSimulationState
{
int mCurStep = 0;
int mNTotalSteps = 0;
int mPathStep = -1;
int mSubStep = 0;
int mNPathSteps = 0;
int mSimSpeed = 1;
int mViewItems = VIEWITEM_SIMULATION;
bool mViewPath = false;
bool mViewSSAO = false;
bool mSimPlaying = false;
bool mSingleStep = false;
};
class MillSimulation: private MillSimulationState
{
public:
MillSimulation();
@@ -54,13 +70,10 @@ public:
void ClearMillPathSegments();
void Clear();
void SimNext();
void InitSimulation(float quality, qreal devicePixelRatio);
void InitSimulation(float quality);
void AddTool(EndMill* tool);
void AddTool(const std::vector<float>& toolProfile, int toolid, float diameter);
bool ToolExists(int toolid)
{
return GetTool(toolid) != nullptr;
}
bool ToolExists(int toolid);
void RenderSimulation();
void RenderTool();
void RenderPath();
@@ -72,9 +85,11 @@ public:
bool LoadGCodeFile(const char* fileName);
bool AddGcodeLine(const char* line);
void SetSimulationStage(float stage);
void SetState(const MillSimulationState& state);
const MillSimulationState& GetState() const;
void SetBoxStock(float x, float y, float z, float l, float w, float h);
void SetArbitraryStock(std::vector<Vertex>& verts, std::vector<GLushort>& indices);
void SetBaseObject(std::vector<Vertex>& verts, std::vector<GLushort>& indices);
void SetArbitraryStock(const std::vector<Vertex>& verts, const std::vector<GLushort>& indices);
void SetBaseObject(const std::vector<Vertex>& verts, const std::vector<GLushort>& indices);
void MouseDrag(int buttons, int dx, int dy);
void MouseMove(int px, int py, int modifiers);
void MouseScroll(float dy);
@@ -83,9 +98,8 @@ public:
void Zoom(float factor);
void UpdateWindowScale(int width, int height);
protected:
void InitDisplay(float quality, qreal devicePixelRatio);
void InitDisplay(float quality);
void GlsimStart();
void GlsimToolStep1(void);
void GlsimToolStep2(void);
@@ -99,7 +113,6 @@ protected:
EndMill* GetTool(int tool);
void RemoveTool(int toolId);
protected:
std::vector<EndMill*> mToolTable;
GCodeParser mCodeParser;
@@ -115,6 +128,9 @@ protected:
MillMotion mDestMotion = {.cmd=eNop, .tool=-1, .x=0, .y=0, .z=0, .i=0, .j=0, .k=0, .r=0, .retract_mode='\0', .retract_z=0.0};
// clang-format on
int mWidth = -1;
int mHeight = -1;
StockObject mStockObject;
SolidObject mBaseShape;
@@ -124,24 +140,15 @@ protected:
vec3 toolColor = {0.5f, 0.4f, 0.3f};
vec3 baseShapeColor = {0.7f, 0.6f, 0.5f};
int mCurStep = 0;
int mNTotalSteps = 0;
int mPathStep = 0;
int mSubStep = 0;
int mNPathSteps = 0;
int mDebug = 0;
int mDebug1 = 0;
int mDebug2 = 12;
int mSimSpeed = 1;
int mViewItems = VIEWITEM_SIMULATION;
int mLastMouseX = 0, mLastMouseY = 0;
int mMouseButtonState = 0;
int mLastModifiers = 0;
bool mIsInStock = false;
bool mSimPlaying = false;
bool mSingleStep = false;
};
} // namespace MillSim
#endif

View File

@@ -26,8 +26,7 @@
#define __openglwrapper_h__
#include "DlgCAMSimulator.h"
extern QOpenGLContext* gOpenGlContext;
#define gSimWindow CAMSimulator::DlgCAMSimulator::GetInstance()
#define gSimWindow CAMSimulator::DlgCAMSimulator::instance()
#define glClearColor gSimWindow->glClearColor
#define glBlendFunc gSimWindow->glBlendFunc
#define glClear gSimWindow->glClear

View File

@@ -45,31 +45,31 @@ Shader::~Shader()
Destroy();
}
void Shader::UpdateModelMat(mat4x4 tmat, mat4x4 nmat)
void Shader::UpdateModelMat(const mat4x4& tmat, const mat4x4& nmat)
{
if (mModelPos >= 0) {
glUniformMatrix4fv(mModelPos, 1, GL_FALSE, (GLfloat*)tmat);
glUniformMatrix4fv(mModelPos, 1, GL_FALSE, (const GLfloat*)tmat);
}
if (mNormalRotPos >= 0) {
glUniformMatrix4fv(mNormalRotPos, 1, GL_FALSE, (GLfloat*)nmat);
glUniformMatrix4fv(mNormalRotPos, 1, GL_FALSE, (const GLfloat*)nmat);
}
}
void Shader::UpdateProjectionMat(mat4x4 mat)
void Shader::UpdateProjectionMat(const mat4x4& mat)
{
if (mProjectionPos >= 0) {
glUniformMatrix4fv(mProjectionPos, 1, GL_FALSE, (GLfloat*)mat);
glUniformMatrix4fv(mProjectionPos, 1, GL_FALSE, (const GLfloat*)mat);
}
}
void Shader::UpdateViewMat(mat4x4 mat)
void Shader::UpdateViewMat(const mat4x4& mat)
{
if (mViewPos >= 0) {
glUniformMatrix4fv(mViewPos, 1, GL_FALSE, (GLfloat*)mat);
glUniformMatrix4fv(mViewPos, 1, GL_FALSE, (const GLfloat*)mat);
}
}
void Shader::UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient, float linearity)
void Shader::UpdateEnvColor(const vec3& lightPos, const vec3& lightColor, const vec3& ambient, float linearity)
{
if (mLightPosPos >= 0) {
glUniform3fv(mLightPosPos, 1, lightPos);
@@ -95,14 +95,14 @@ void Shader::UpdateScreenDimension(int width, int height)
}
}
void Shader::UpdateObjColor(vec3 objColor)
void Shader::UpdateObjColor(const vec3& objColor)
{
if (mObjectColorPos >= 0) {
glUniform3fv(mObjectColorPos, 1, objColor);
}
}
void Shader::UpdateObjColorAlpha(vec4 objColor)
void Shader::UpdateObjColorAlpha(const vec4& objColor)
{
if (mObjectColorAlphaPos >= 0) {
glUniform4fv(mObjectColorAlphaPos, 1, objColor);

View File

@@ -39,13 +39,13 @@ public:
public:
unsigned int shaderId = 0;
void UpdateModelMat(mat4x4 transformMat, mat4x4 normalMat);
void UpdateProjectionMat(mat4x4 mat);
void UpdateViewMat(mat4x4 mat);
void UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient, float linearity);
void UpdateModelMat(const mat4x4& transformMat, const mat4x4& normalMat);
void UpdateProjectionMat(const mat4x4& mat);
void UpdateViewMat(const mat4x4& mat);
void UpdateEnvColor(const vec3& lightPos, const vec3& lightColor, const vec3& ambient, float linearity);
void UpdateScreenDimension(int width, int height);
void UpdateObjColor(vec3 objColor);
void UpdateObjColorAlpha(vec4 objColor);
void UpdateObjColor(const vec3& objColor);
void UpdateObjColorAlpha(const vec4& objColor);
void UpdateNormalState(bool isInverted);
void UpdateSsaoActive(bool isInverted);
void UpdateTextureSlot(int slot);

View File

@@ -131,7 +131,6 @@ void SimDisplay::UniformCircle(vec3& randVec)
randVec[2] = 0;
}
void SimDisplay::CreateDisplayFbos()
{
// setup frame buffer for simulation
@@ -178,7 +177,6 @@ void SimDisplay::CreateDisplayFbos()
void SimDisplay::CreateSsaoFbos()
{
mSsaoValid = true;
// setup framebuffer for SSAO processing
@@ -240,7 +238,7 @@ SimDisplay::~SimDisplay()
CleanGL();
}
void SimDisplay::InitGL(qreal devicePixelRatio)
void SimDisplay::InitGL()
{
if (displayInitiated) {
return;
@@ -249,16 +247,12 @@ void SimDisplay::InitGL(qreal devicePixelRatio)
// setup light object
mlightObject.GenerateBoxStock(-0.5f, -0.5f, -0.5f, 1, 1, 1);
mDevicePixelRatio = devicePixelRatio;
mWidth = (int)(gWindowSizeW * mDevicePixelRatio);
mHeight = (int)(gWindowSizeH * mDevicePixelRatio);
InitShaders();
CreateDisplayFbos();
CreateSsaoFbos();
CreateFboQuad();
UpdateProjection();
displayInitiated = true;
UpdateWindowScale(800, 600);
}
void SimDisplay::CleanFbos()
@@ -299,7 +293,7 @@ void SimDisplay::CleanGL()
displayInitiated = false;
}
void SimDisplay::PrepareDisplay(vec3 objCenter)
void SimDisplay::PrepareDisplay(const vec3& objCenter)
{
mat4x4_look_at(mMatLookAt, eye, target, upvec);
mat4x4_translate_in_place(mMatLookAt, mEyeX * mEyeXZFactor, 0, mEyeZ * mEyeXZFactor);
@@ -327,7 +321,7 @@ void SimDisplay::StartDepthPass()
shaderFlat.UpdateViewMat(mMatLookAt);
}
void SimDisplay::StartGeometryPass(vec3 objColor, bool invertNormals)
void SimDisplay::StartGeometryPass(const vec3& objColor, bool invertNormals)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
shaderGeom.Activate();
@@ -340,7 +334,7 @@ void SimDisplay::StartGeometryPass(vec3 objColor, bool invertNormals)
// A 'closer' geometry pass is similar to std geometry pass, but render the objects
// slightly closer to the camera. This mitigates overlapping faces artifacts.
void SimDisplay::StartCloserGeometryPass(vec3 objColor)
void SimDisplay::StartCloserGeometryPass(const vec3& objColor)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
shaderGeomCloser.Activate();
@@ -363,15 +357,18 @@ void SimDisplay::ScaleViewToStock(StockObject* obj)
mMaxStockDim = fmaxf(obj->size[0], obj->size[1]);
maxFar = mMaxStockDim * 16;
UpdateProjection();
vec3_set(eye, 0, 0, 0);
mEyeDistFactor = NAN;
UpdateEyeFactor(0.1f);
vec3_set(lightPos, obj->position[0], obj->position[1], obj->position[2] + mMaxStockDim / 3);
mlightObject.SetPosition(lightPos);
}
void SimDisplay::RenderResult(bool recalculate)
void SimDisplay::RenderResult(bool recalculate, bool ssao)
{
if (mSsaoValid && applySSAO) {
if (mSsaoValid && ssao) {
RenderResultSSAO(recalculate);
}
else {
@@ -549,12 +546,20 @@ void SimDisplay::UpdateEyeFactor(float factor)
eye[1] = -factor * maxFar;
}
void SimDisplay::UpdateWindowScale()
void SimDisplay::UpdateWindowScale(int width, int height)
{
mWidth = (int)(gWindowSizeW * mDevicePixelRatio);
mHeight = (int)(gWindowSizeH * mDevicePixelRatio);
glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
CleanFbos();
if (!displayInitiated || (width == mWidth && height == mHeight)) {
return;
}
mWidth = width;
mHeight = height;
if (mFbo != 0) {
glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
CleanFbos();
}
CreateDisplayFbos();
CreateSsaoFbos();
UpdateProjection();
@@ -564,7 +569,7 @@ void SimDisplay::UpdateProjection()
{
// Setup projection
mat4x4 projmat;
mat4x4_perspective(projmat, 0.7f, (float)gWindowSizeW / gWindowSizeH, 1.0f, maxFar);
mat4x4_perspective(projmat, 0.7f, (float)mWidth / mHeight, 1.0f, maxFar);
shader3D.Activate();
shader3D.UpdateProjectionMat(projmat);
shaderInv3D.Activate();
@@ -584,5 +589,9 @@ void SimDisplay::UpdateProjection()
shaderGeomCloser.UpdateProjectionMat(projmat);
}
float SimDisplay::GetEyeFactor()
{
return mEyeDistFactor;
}
} // namespace MillSim

View File

@@ -47,17 +47,17 @@ class SimDisplay
{
public:
~SimDisplay();
void InitGL(qreal devicePixelRatio);
void InitGL();
void CleanGL();
void CleanFbos();
void PrepareDisplay(vec3 objCenter);
void PrepareDisplay(const vec3& objCenter);
void PrepareFrameBuffer();
void StartDepthPass();
void StartGeometryPass(vec3 objColor, bool invertNormals);
void StartCloserGeometryPass(vec3 objColor);
void StartGeometryPass(const vec3& objColor, bool invertNormals);
void StartCloserGeometryPass(const vec3& objColor);
void RenderLightObject();
void ScaleViewToStock(StockObject* obj);
void RenderResult(bool recalculate);
void RenderResult(bool recalculate, bool ssao);
void RenderResultStandard();
void RenderResultSSAO(bool recalculate);
void SetupLinePathPass(int curSegment, bool isHidden);
@@ -66,16 +66,12 @@ public:
void MoveEye(float x, float z);
void MoveEyeCenter();
void UpdateEyeFactor(float factor);
void UpdateWindowScale();
void UpdateWindowScale(int width, int height);
void UpdateProjection();
float GetEyeFactor()
{
return mEyeDistFactor;
}
float GetEyeFactor();
public:
bool applySSAO = false;
bool updateDisplay = false;
float maxFar = 100;
bool displayInitiated = false;
@@ -108,14 +104,12 @@ protected:
mat4x4 mMatLookAt;
StockObject mlightObject;
qreal mDevicePixelRatio;
int mWidth;
int mHeight;
int mWidth = -1;
int mHeight = -1;
std::mt19937 generator;
std::uniform_real_distribution<float> distr01;
float mEyeDistance = 30;
float mEyeRoration = 0;
float mEyeInclination = pi / 6; // 30 degree
@@ -129,22 +123,23 @@ protected:
float mEyeZ = 0.0f;
// base frame buffer
unsigned int mFbo;
unsigned int mFboColTexture;
unsigned int mFboPosTexture;
unsigned int mFboNormTexture;
unsigned int mRboDepthStencil;
unsigned int mFboQuadVAO, mFboQuadVBO;
unsigned int mFbo = 0;
unsigned int mFboColTexture = 0;
unsigned int mFboPosTexture = 0;
unsigned int mFboNormTexture = 0;
unsigned int mRboDepthStencil = 0;
unsigned int mFboQuadVAO = 0, mFboQuadVBO = 0;
// ssao frame buffers
bool mSsaoValid = false;
std::vector<Point3D> mSsaoKernel;
unsigned int mSsaoFbo;
unsigned int mSsaoBlurFbo;
unsigned int mFboSsaoTexture;
unsigned int mFboSsaoBlurTexture;
unsigned int mFboRandTexture;
unsigned int mSsaoFbo = 0;
unsigned int mSsaoBlurFbo = 0;
unsigned int mFboSsaoTexture = 0;
unsigned int mFboSsaoBlurTexture = 0;
unsigned int mFboRandTexture = 0;
};
} // namespace MillSim
#endif // !__simdisplay_h__

View File

@@ -327,7 +327,7 @@ void Shape::ExtrudeProfileLinear(
SetModelData(vbuffer, ibuffer);
}
void Shape::GenerateModel(float* vbuffer, GLushort* ibuffer, int numVerts, int nIndices)
void Shape::GenerateModel(const float* vbuffer, const GLushort* ibuffer, int numVerts, int nIndices)
{
// GLuint vbo, ibo, vao;
@@ -354,9 +354,9 @@ void Shape::GenerateModel(float* vbuffer, GLushort* ibuffer, int numVerts, int n
numIndices = nIndices;
}
void MillSim::Shape::SetModelData(std::vector<Vertex>& vbuffer, std::vector<GLushort>& ibuffer)
void Shape::SetModelData(const std::vector<Vertex>& vbuffer, const std::vector<GLushort>& ibuffer)
{
GenerateModel((float*)vbuffer.data(), ibuffer.data(), (int)vbuffer.size(), (int)ibuffer.size());
GenerateModel((const float*)vbuffer.data(), ibuffer.data(), (int)vbuffer.size(), (int)ibuffer.size());
}
void Shape::Render()
@@ -366,7 +366,7 @@ void Shape::Render()
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, nullptr);
}
void Shape::Render(mat4x4 modelMat, mat4x4 normallMat) // normals are rotated only
void Shape::Render(const mat4x4& modelMat, const mat4x4& normallMat) // normals are rotated only
{
CurrentShader->UpdateModelMat(modelMat, normallMat);
Render();

View File

@@ -83,9 +83,9 @@ public:
public:
void Render();
void Render(mat4x4 modelMat, mat4x4 normallMat);
void Render(const mat4x4& modelMat, const mat4x4& normallMat);
void FreeResources();
void SetModelData(std::vector<Vertex>& vbuffer, std::vector<GLushort>& ibuffer);
void SetModelData(const std::vector<Vertex>& vbuffer, const std::vector<GLushort>& ibuffer);
void RotateProfile(
float* profPoints,
int nPoints,
@@ -120,7 +120,7 @@ public:
static int lastNumSlices;
protected:
void GenerateModel(float* vbuffer, GLushort* ibuffer, int numVerts, int numIndices);
void GenerateModel(const float* vbuffer, const GLushort* ibuffer, int numVerts, int numIndices);
void CalculateExtrudeBufferSizes(
int nProfilePoints,
bool capStart,

View File

@@ -55,14 +55,14 @@ void SolidObject::render()
shape.Render(mModelMat, mModelMat); // model is not rotated hence both are identity matrix
}
void SolidObject::GenerateSolid(std::vector<Vertex>& verts, std::vector<GLushort>& indices)
void SolidObject::GenerateSolid(const std::vector<Vertex>& verts, const std::vector<GLushort>& indices)
{
shape.SetModelData(verts, indices);
// calculate object's bounding box:
float x = 999999.0f, y = 999999.0f, z = 999999.0f;
float l = -999999.0f, w = -999999.0f, h = -999999.0f;
for (auto& vert : verts) {
for (const auto& vert : verts) {
x = std::fminf(x, vert.x);
y = std::fminf(y, vert.y);
z = std::fminf(z, vert.z);

View File

@@ -41,7 +41,7 @@ public:
/// Calls the display list.
virtual void render();
Shape shape;
void GenerateSolid(std::vector<Vertex>& verts, std::vector<GLushort>& indices);
void GenerateSolid(const std::vector<Vertex>& verts, const std::vector<GLushort>& indices);
vec3 center = {};
vec3 size = {};
vec3 position = {};

View File

@@ -0,0 +1,53 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "ViewCAMSimulator.h"
#include "DlgCAMSimulator.h"
namespace CAMSimulator
{
ViewCAMSimulator::ViewCAMSimulator(Gui::Document* pcDocument, QWidget* parent, Qt::WindowFlags wflags)
: Gui::MDIView(pcDocument, parent, wflags)
{
mDlg = new DlgCAMSimulator(*this);
setCentralWidget(mDlg);
}
ViewCAMSimulator* ViewCAMSimulator::clone()
{
auto viewCam = new ViewCAMSimulator(_pcDocument, nullptr);
viewCam->cloneFrom(*this);
viewCam->mDlg->cloneFrom(*mDlg);
return viewCam;
}
DlgCAMSimulator& ViewCAMSimulator::dlg()
{
return *mDlg;
}
} // namespace CAMSimulator

View File

@@ -0,0 +1,53 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef PATHSIMULATOR_VIEWCAMSIMULATOR_H
#define PATHSIMULATOR_VIEWCAMSIMULATOR_H
#include <Gui/MDIView.h>
namespace CAMSimulator
{
class DlgCAMSimulator;
class ViewCAMSimulator: public Gui::MDIView
{
public:
ViewCAMSimulator(
Gui::Document* pcDocument,
QWidget* parent,
Qt::WindowFlags wflags = Qt::WindowFlags()
);
ViewCAMSimulator* clone() override;
DlgCAMSimulator& dlg();
protected:
DlgCAMSimulator* mDlg;
};
} // namespace CAMSimulator
#endif /* PATHSIMULATOR_VIEWCAMSIMULATOR_H */