diff --git a/src/Mod/CAM/Gui/Resources/Path.qrc b/src/Mod/CAM/Gui/Resources/Path.qrc
index 18c1ed1234..07cf8cedf0 100644
--- a/src/Mod/CAM/Gui/Resources/Path.qrc
+++ b/src/Mod/CAM/Gui/Resources/Path.qrc
@@ -135,6 +135,9 @@
gl_simulator/SingleStep.png
gl_simulator/Slider.png
gl_simulator/Thumb.png
+ gl_simulator/Path.png
+ gl_simulator/View.png
+ gl_simulator/AmbientOclusion.png
preferences/Advanced.ui
preferences/PathDressupHoldingTags.ui
preferences/PathJob.ui
diff --git a/src/Mod/CAM/Gui/Resources/gl_simulator/AmbientOclusion.png b/src/Mod/CAM/Gui/Resources/gl_simulator/AmbientOclusion.png
new file mode 100644
index 0000000000..8a64fa6a1e
Binary files /dev/null and b/src/Mod/CAM/Gui/Resources/gl_simulator/AmbientOclusion.png differ
diff --git a/src/Mod/CAM/Gui/Resources/gl_simulator/Path.png b/src/Mod/CAM/Gui/Resources/gl_simulator/Path.png
new file mode 100644
index 0000000000..20f8eb6778
Binary files /dev/null and b/src/Mod/CAM/Gui/Resources/gl_simulator/Path.png differ
diff --git a/src/Mod/CAM/Gui/Resources/gl_simulator/View.png b/src/Mod/CAM/Gui/Resources/gl_simulator/View.png
new file mode 100644
index 0000000000..40266c80c4
Binary files /dev/null and b/src/Mod/CAM/Gui/Resources/gl_simulator/View.png differ
diff --git a/src/Mod/CAM/Gui/Resources/panels/TaskCAMSimulator.ui b/src/Mod/CAM/Gui/Resources/panels/TaskCAMSimulator.ui
index ab70e91cd7..916cdd0497 100644
--- a/src/Mod/CAM/Gui/Resources/panels/TaskCAMSimulator.ui
+++ b/src/Mod/CAM/Gui/Resources/panels/TaskCAMSimulator.ui
@@ -14,25 +14,6 @@
Path Simulator
- -
-
-
-
- 0
- 0
-
-
-
-
- 16777215
- 5
-
-
-
- false
-
-
-
-
diff --git a/src/Mod/CAM/Path/Main/Gui/SimulatorGL.py b/src/Mod/CAM/Path/Main/Gui/SimulatorGL.py
index e711858e9c..5b8cf7dbb3 100644
--- a/src/Mod/CAM/Path/Main/Gui/SimulatorGL.py
+++ b/src/Mod/CAM/Path/Main/Gui/SimulatorGL.py
@@ -19,20 +19,22 @@
# * USA *
# * *
# ***************************************************************************
+"""
+Command and task window handler for the OpenGL based CAM simulator
+"""
+
-import FreeCAD
-import Path
-import Path.Base.Util as PathUtil
-import Path.Dressup.Utils as PathDressup
-import PathScripts.PathUtils as PathUtils
-import Path.Main.Job as PathJob
-import PathGui
-import CAMSimulator
import math
import os
+import FreeCAD
+import Path.Base.Util as PathUtil
+import Path.Dressup.Utils as PathDressup
+import Path.Main.Job as PathJob
+from PathScripts import PathUtils
+import CAMSimulator
+
+from FreeCAD import Vector
-from FreeCAD import Vector, Base
-from PySide.QtGui import QDialogButtonBox
# lazily loaded modules
from lazy_loader.lazy_loader import LazyLoader
@@ -43,37 +45,52 @@ Part = LazyLoader("Part", globals(), "Part")
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtGui, QtCore
+ from PySide.QtGui import QDialogButtonBox
_filePath = os.path.dirname(os.path.abspath(__file__))
def IsSame(x, y):
+ """ Check if two floats are the same within an epsilon
+ """
return abs(x - y) < 0.0001
def RadiusAt(edge, p):
+ """ Find the tool radius within a point on its circumference
+ """
x = edge.valueAt(p).x
y = edge.valueAt(p).y
return math.sqrt(x * x + y * y)
class CAMSimTaskUi:
+ """ Handles the simulator task panel
+ """
def __init__(self, parent):
# this will create a Qt widget from our ui file
self.form = FreeCADGui.PySideUic.loadUi(":/panels/TaskCAMSimulator.ui")
self.parent = parent
- def getStandardButtons(self, *args):
+ def getStandardButtons(self, *_args):
+ """ Task panel needs only Close button
+ """
return QDialogButtonBox.Close
def reject(self):
+ """ User Pressed the Close button
+ """
self.parent.cancel()
FreeCADGui.Control.closeDialog()
def TSError(msg):
+ """ Display error message
+ """
QtGui.QMessageBox.information(None, "Path Simulation", msg)
class CAMSimulation:
+ """ Handles and prepares CAM jobs for simulation
+ """
def __init__(self):
self.debug = False
self.stdrot = FreeCAD.Rotation(Vector(0, 0, 1), 0)
@@ -83,12 +100,26 @@ class CAMSimulation:
self.quality = 10
self.resetSimulation = False
self.jobs = []
+ self.initdone = False
+ self.taskForm = None
+ self.disableAnim = False
+ self.firstDrill = True
+ self.millSim = None
+ self.job = None
+ self.activeOps = []
+ self.ioperation = 0
+ self.stock = None
+ self.busy = False
+ self.operations = []
+ self.baseShape = None
def Connect(self, but, sig):
+ """ Connect task panel buttons """
QtCore.QObject.connect(but, QtCore.SIGNAL("clicked()"), sig)
- ## Convert tool shape to tool profile needed by GL simulator
def FindClosestEdge(self, edges, px, pz):
+ """ Convert tool shape to tool profile needed by GL simulator
+ """
for edge in edges:
p1 = edge.FirstParameter
p2 = edge.LastParameter
@@ -109,6 +140,8 @@ class CAMSimulation:
return None, 0.0, 0.0
def FindTopMostEdge(self, edges):
+ """ Examine tool solid edges and find the top most one
+ """
maxz = -99999999.0
topedge = None
top_p1 = 0.0
@@ -130,16 +163,17 @@ class CAMSimulation:
maxz = z
return topedge, top_p1, top_p2
- #the algo is based on locating the side edge that OCC creates on any revolved object
def GetToolProfile(self, tool, resolution):
+ """ Get the edge profile of a tool solid. Basically locating the
+ side edge that OCC creates on any revolved object
+ """
shape = tool.Shape
sideEdgeList = []
- for i in range(len(shape.Edges)):
- edge = shape.Edges[i]
+ for _i, edge in enumerate(shape.Edges):
if not edge.isClosed():
- v1 = edge.firstVertex()
- v2 = edge.lastVertex()
- tp = "arc" if type(edge.Curve) is Part.Circle else "line"
+ # v1 = edge.firstVertex()
+ # v2 = edge.lastVertex()
+ # tp = "arc" if type(edge.Curve) is Part.Circle else "line"
sideEdgeList.append(edge)
# sort edges as a single 3d line on the x-z plane
@@ -151,12 +185,11 @@ class CAMSimulation:
# one by one find all connecting edges
while edge is not None:
sideEdgeList.remove(edge)
- if type(edge.Curve) is Part.Circle:
+ if isinstance(edge.Curve, Part.Circle):
# if edge is curved, approximate it with lines based on resolution
nsegments = int(edge.Length / resolution) + 1
step = (p2 - p1) / nsegments
location = p1 + step
- print (edge.Length, nsegments, step)
while nsegments > 0:
endrad = RadiusAt(edge, location)
endz = edge.valueAt(location).z
@@ -169,7 +202,7 @@ class CAMSimulation:
endz = edge.valueAt(p2).z
profile.append(endrad)
profile.append(endz)
- edge, p1, p2 = self.FindClosestEdge(sideEdgeList, endrad, endz)
+ edge, p1, p2 = self.FindClosestEdge(sideEdgeList, endrad, endz)
if edge is None:
break
startrad = RadiusAt(edge, p1)
@@ -181,6 +214,8 @@ class CAMSimulation:
return profile
def Activate(self):
+ """ Invoke the simulator task panel
+ """
self.initdone = False
self.taskForm = CAMSimTaskUi(self)
form = self.taskForm.form
@@ -200,7 +235,8 @@ class CAMSimulation:
# self.SetupSimulation()
def _populateJobSelection(self, form):
- # Make Job selection combobox
+ """ Make Job selection combobox
+ """
setJobIdx = 0
jobName = ""
jIdx = 0
@@ -236,6 +272,8 @@ class CAMSimulation:
form.comboJobs.setCurrentIndex(0)
def SetupSimulation(self):
+ """ Prepare all selected job operations for simulation
+ """
form = self.taskForm.form
self.activeOps = []
self.numCommands = 0
@@ -250,6 +288,8 @@ class CAMSimulation:
self.busy = False
def onJobChange(self):
+ """ When a new job is selected from the drop-down, update job operation list
+ """
form = self.taskForm.form
j = self.jobs[form.comboJobs.currentIndex()]
self.job = j
@@ -262,18 +302,26 @@ class CAMSimulation:
listItem.setCheckState(QtCore.Qt.CheckState.Checked)
self.operations.append(op)
form.listOperations.addItem(listItem)
+ if len(j.Model.OutList) > 0:
+ self.baseShape = j.Model.OutList[0].Shape
+ else:
+ self.baseShape = None
def onAccuracyBarChange(self):
+ """ Update simulation quality
+ """
form = self.taskForm.form
self.quality = form.sliderAccuracy.value()
qualText = QtCore.QT_TRANSLATE_NOOP("CAM_Simulator", "High")
- if (self.quality < 4):
+ if self.quality < 4:
qualText = QtCore.QT_TRANSLATE_NOOP("CAM_Simulator", "Low")
- elif (self.quality < 9):
+ elif self.quality < 9:
qualText = QtCore.QT_TRANSLATE_NOOP("CAM_Simulator", "Medium")
form.labelAccuracy.setText(qualText)
def onOperationItemChange(self, _item):
+ """ Check if at least one operation is selected to enable the Play button
+ """
playvalid = False
form = self.taskForm.form
for i in range(form.listOperations.count()):
@@ -283,6 +331,8 @@ class CAMSimulation:
form.toolButtonPlay.setEnabled(playvalid)
def SimPlay(self):
+ """ Activate the simulation
+ """
self.SetupSimulation()
self.millSim.ResetSimulation()
for op in self.activeOps:
@@ -294,14 +344,20 @@ class CAMSimulation:
for cmd in opCommands:
self.millSim.AddCommand(cmd)
self.millSim.BeginSimulation(self.stock, self.quality)
+ if self.baseShape is not None:
+ self.millSim.SetBaseShape(self.baseShape, 1)
def cancel(self):
- #self.EndSimulation()
- pass
+ """ Cancel the simulation
+ """
class CommandCAMSimulate:
+ """ FreeCAD invoke simulation task panel command
+ """
def GetResources(self):
+ """ Command info
+ """
return {
"Pixmap": "CAM_SimulatorGL",
"MenuText": QtCore.QT_TRANSLATE_NOOP("CAM_Simulator", "New CAM Simulator"),
@@ -312,6 +368,8 @@ class CommandCAMSimulate:
}
def IsActive(self):
+ """ Command is active if at least one CAM job exists
+ """
if FreeCAD.ActiveDocument is not None:
for o in FreeCAD.ActiveDocument.Objects:
if o.Name[:3] == "Job":
@@ -319,6 +377,8 @@ class CommandCAMSimulate:
return False
def Activated(self):
+ """ Activate the simulation
+ """
CamSimulation = CAMSimulation()
CamSimulation.Activate()
diff --git a/src/Mod/CAM/PathSimulator/AppGL/CAMSim.cpp b/src/Mod/CAM/PathSimulator/AppGL/CAMSim.cpp
index 24f1ff2f83..e5665c735d 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/CAMSim.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/CAMSim.cpp
@@ -20,10 +20,16 @@
* *
***************************************************************************/
-#include "PreCompiled.h"
+#include "PreCompiled.h" // NOLINT
+#ifndef _PreComp_
+#include
+#include
+#endif
+
#include "CAMSim.h"
#include "DlgCAMSimulator.h"
-#include
+#include
+
using namespace Base;
@@ -31,25 +37,9 @@ using namespace CAMSimulator;
TYPESYSTEM_SOURCE(CAMSimulator::CAMSim, Base::BaseClass);
-#define MAX_GCODE_LINE_LEN 120
-
-CAMSim::CAMSim()
-{}
-
-CAMSim::~CAMSim()
-{}
-
-void CAMSim::BeginSimulation(Part::TopoShape* stock, float quality)
+void CAMSim::BeginSimulation(const Part::TopoShape& stock, float quality)
{
- Base::BoundBox3d bbox = stock->getBoundBox();
- SimStock stk = {(float)bbox.MinX,
- (float)bbox.MinY,
- (float)bbox.MinZ,
- (float)bbox.LengthX(),
- (float)bbox.LengthY(),
- (float)bbox.LengthZ(),
- quality};
- DlgCAMSimulator::GetInstance()->startSimulation(&stk, quality);
+ DlgCAMSimulator::GetInstance()->startSimulation(stock, quality);
}
void CAMSimulator::CAMSim::resetSimulation()
@@ -57,7 +47,7 @@ void CAMSimulator::CAMSim::resetSimulation()
DlgCAMSimulator::GetInstance()->resetSimulation();
}
-void CAMSim::addTool(const std::vector toolProfilePoints,
+void CAMSim::addTool(const std::vector &toolProfilePoints,
int toolNumber,
float diameter,
float resolution)
@@ -65,6 +55,15 @@ void CAMSim::addTool(const std::vector toolProfilePoints,
DlgCAMSimulator::GetInstance()->addTool(toolProfilePoints, toolNumber, diameter, resolution);
}
+void CAMSimulator::CAMSim::SetBaseShape(const Part::TopoShape& baseShape, float resolution)
+{
+ if (baseShape.isNull()) {
+ return;
+ }
+
+ DlgCAMSimulator::GetInstance()->SetBaseShape(baseShape, resolution);
+}
+
void CAMSim::AddCommand(Command* cmd)
{
std::string gline = cmd->toGCode();
diff --git a/src/Mod/CAM/PathSimulator/AppGL/CAMSim.h b/src/Mod/CAM/PathSimulator/AppGL/CAMSim.h
index 9fd1d67ab3..2fb85b655d 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/CAMSim.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/CAMSim.h
@@ -27,10 +27,9 @@
#include
#include
-#include
#include
#include
-#include
+#include
#include "DlgCAMSimulator.h"
@@ -46,25 +45,25 @@ class CAMSimulatorExport CAMSim: public Base::BaseClass
// TYPESYSTEM_HEADER();
public:
- static Base::Type getClassTypeId(void);
- virtual Base::Type getTypeId(void) const;
- static void init(void);
- static void* create(void);
+ static Base::Type getClassTypeId();
+ Base::Type getTypeId() const override;
+ static void init();
+ static void* create();
private:
static Base::Type classTypeId;
public:
- CAMSim();
- ~CAMSim();
+ CAMSim() = default;
- void BeginSimulation(Part::TopoShape* stock, float resolution);
+ void BeginSimulation(const Part::TopoShape& stock, float resolution);
void resetSimulation();
- void addTool(const std::vector toolProfilePoints,
+ void addTool(const std::vector &toolProfilePoints,
int toolNumber,
float diameter,
float resolution);
+ void SetBaseShape(const Part::TopoShape& baseShape, float resolution);
void AddCommand(Command* cmd);
public:
diff --git a/src/Mod/CAM/PathSimulator/AppGL/CAMSimPy.xml b/src/Mod/CAM/PathSimulator/AppGL/CAMSimPy.xml
index 85f3e3f382..fe3117b3a7 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/CAMSimPy.xml
+++ b/src/Mod/CAM/PathSimulator/AppGL/CAMSimPy.xml
@@ -35,19 +35,28 @@
ResetSimulation():
- Clear the simulation and all gcode commands
+ Clear the simulation and all gcode commands
- SetToolShape(shape, toolnumber, diameter, resolution):
+ AddTool(shape, toolnumber, diameter, resolution):
Set the shape of the tool to be used for simulation
+
+
+
+ SetBaseShape(shape, resolution):
+
+ Set the shape of the base object of the job
+
+
+
diff --git a/src/Mod/CAM/PathSimulator/AppGL/CAMSimPyImp.cpp b/src/Mod/CAM/PathSimulator/AppGL/CAMSimPyImp.cpp
index 5ce3560537..5932b7aaed 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/CAMSimPyImp.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/CAMSimPyImp.cpp
@@ -73,7 +73,7 @@ PyObject* CAMSimPy::BeginSimulation(PyObject* args, PyObject* kwds)
return nullptr;
}
CAMSim* sim = getCAMSimPtr();
- Part::TopoShape* stock = static_cast(pObjStock)->getTopoShapePtr();
+ const Part::TopoShape& stock = *static_cast(pObjStock)->getTopoShapePtr();
sim->BeginSimulation(stock, resolution);
Py_IncRef(Py_None);
return Py_None;
@@ -102,6 +102,28 @@ PyObject* CAMSimPy::AddTool(PyObject* args, PyObject* kwds)
CAMSim* sim = getCAMSimPtr();
sim->addTool(toolProfile, toolNumber, diameter, resolution);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* CAMSimPy::SetBaseShape(PyObject* args, PyObject* kwds)
+{
+ static const std::array kwlist {"shape", "resolution", nullptr};
+ PyObject* pObjBaseShape;
+ float resolution;
+ if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds,"O!f",
+ kwlist, &(Part::TopoShapePy::Type), &pObjBaseShape, &resolution)) {
+ return nullptr;
+ }
+ if (!PyArg_ParseTuple(args, "O!f", &(Part::TopoShapePy::Type), &pObjBaseShape, &resolution)) {
+ return nullptr;
+ }
+ CAMSim* sim = getCAMSimPtr();
+ const Part::TopoShape& baseShape =
+ static_cast(pObjBaseShape)->getTopoShapePtr()->getShape();
+ sim->SetBaseShape(baseShape, resolution);
+
+ Py_IncRef(Py_None);
return Py_None;
}
@@ -114,6 +136,8 @@ PyObject* CAMSimPy::AddCommand(PyObject* args)
CAMSim* sim = getCAMSimPtr();
Path::Command* cmd = static_cast(pObjCmd)->getCommandPtr();
sim->AddCommand(cmd);
+
+ Py_INCREF(Py_None);
return Py_None;
}
diff --git a/src/Mod/CAM/PathSimulator/AppGL/CMakeLists.txt b/src/Mod/CAM/PathSimulator/AppGL/CMakeLists.txt
index a397dcd666..d2d5e3d99a 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/CMakeLists.txt
+++ b/src/Mod/CAM/PathSimulator/AppGL/CMakeLists.txt
@@ -53,6 +53,8 @@ SET(CAMSimulator_SRCS_Core
GuiDisplay.h
linmath.h
MillMotion.h
+ MillPathLine.cpp
+ MillPathLine.h
MillPathSegment.cpp
MillPathSegment.h
MillSimulation.cpp
@@ -60,10 +62,14 @@ SET(CAMSimulator_SRCS_Core
OpenGlWrapper.h
Shader.cpp
Shader.h
+ SimDisplay.cpp
+ SimDisplay.h
SimShapes.cpp
SimShapes.h
StockObject.cpp
StockObject.h
+ SolidObject.cpp
+ SolidObject.h
Texture.cpp
Texture.h
TextureLoader.cpp
diff --git a/src/Mod/CAM/PathSimulator/AppGL/DlgCAMSimulator.cpp b/src/Mod/CAM/PathSimulator/AppGL/DlgCAMSimulator.cpp
index c1474d3b4e..55e81b9521 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/DlgCAMSimulator.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/DlgCAMSimulator.cpp
@@ -24,6 +24,7 @@
#include "DlgCAMSimulator.h"
#include "MillSimulation.h"
+#include
#include
#include
#include
@@ -64,8 +65,9 @@ bool DlgCAMSimulator::event(QEvent* event)
renderNow();
return true;
default:
- return QWindow::event(event);
+ break;
}
+ return QWindow::event(event);
}
void DlgCAMSimulator::exposeEvent(QExposeEvent* event)
@@ -99,7 +101,6 @@ void DlgCAMSimulator::wheelEvent(QWheelEvent* ev)
void DlgCAMSimulator::resetSimulation()
{
- mMillSimulator->Clear();
}
void DlgCAMSimulator::addGcodeCommand(const char* cmd)
@@ -122,35 +123,107 @@ void DlgCAMSimulator::addTool(const std::vector toolProfilePoints,
void DlgCAMSimulator::hideEvent(QHideEvent* ev)
{
- Q_UNUSED(ev)
+ mMillSimulator->Clear();
+ doGlCleanup();
mAnimating = false;
+ QWindow::hideEvent(ev);
+ close();
+ mInstance = nullptr;
}
-void DlgCAMSimulator::startSimulation(const SimStock* stock, float quality)
+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, newWidth * retinaScale, newHeight * retinaScale);
+}
+
+void DlgCAMSimulator::GetMeshData(const Part::TopoShape& tshape,
+ float resolution,
+ std::vector& verts,
+ std::vector& indices)
+{
+ std::vector normalCount;
+ int nVerts = 0;
+ for (auto& shape : tshape.getSubTopoShapes(TopAbs_FACE)) {
+ std::vector points;
+ std::vector facets;
+ shape.getFaces(points, facets, resolution);
+
+ std::vector normals(points.size());
+ std::vector normalCount(points.size());
+
+ // 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);
+
+ // calculate normal
+ Base::Vector3d vAB = points[face.I2] - points[face.I1];
+ Base::Vector3d vAC = points[face.I3] - points[face.I1];
+ Base::Vector3d vNorm = vAB.Cross(vAC).Normalize();
+
+ normals[face.I1] += vNorm;
+ normals[face.I2] += vNorm;
+ normals[face.I3] += vNorm;
+
+ normalCount[face.I1]++;
+ normalCount[face.I2]++;
+ normalCount[face.I3]++;
+ }
+
+ // copy points and set normals
+ for (unsigned int i = 0; i < points.size(); i++) {
+ Base::Vector3d& point = points[i];
+ 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));
+ }
+
+ nVerts = verts.size();
+ }
+}
+
+void DlgCAMSimulator::startSimulation(const Part::TopoShape& stock, float quality)
{
- mStock = *stock;
mQuality = quality;
mNeedsInitialize = true;
show();
+ checkInitialization();
+ SetStockShape(stock, 1);
setAnimating(true);
}
void DlgCAMSimulator::initialize()
{
- mMillSimulator
- ->SetBoxStock(mStock.mPx, mStock.mPy, mStock.mPz, mStock.mLx, mStock.mLy, mStock.mLz);
mMillSimulator->InitSimulation(mQuality);
const qreal retinaScale = devicePixelRatio();
glViewport(0, 0, width() * retinaScale, height() * retinaScale);
+ glEnable(GL_MULTISAMPLE);
}
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;
}
@@ -164,6 +237,17 @@ void DlgCAMSimulator::checkInitialization()
}
}
+void DlgCAMSimulator::doGlCleanup()
+{
+ if (mLastContext != nullptr) {
+ mLastContext->makeCurrent(this);
+ }
+ if (mContext != nullptr) {
+ mContext->deleteLater();
+ mContext = nullptr;
+ }
+}
+
void DlgCAMSimulator::renderNow()
{
static unsigned int lastTime = 0;
@@ -213,13 +297,30 @@ DlgCAMSimulator* DlgCAMSimulator::GetInstance()
format.setStencilBufferSize(8);
mInstance = new DlgCAMSimulator();
mInstance->setFormat(format);
- mInstance->resize(800, 600);
+ mInstance->resize(MillSim::gWindowSizeW, MillSim::gWindowSizeH);
mInstance->setModality(Qt::ApplicationModal);
- mInstance->show();
+ mInstance->setMinimumWidth(700);
+ mInstance->setMinimumHeight(400);
}
return mInstance;
}
+void DlgCAMSimulator::SetStockShape(const Part::TopoShape& shape, float resolution)
+{
+ std::vector verts;
+ std::vector indices;
+ GetMeshData(shape, resolution, verts, indices);
+ mMillSimulator->SetArbitraryStock(verts, indices);
+}
+
+void DlgCAMSimulator::SetBaseShape(const Part::TopoShape& tshape, float resolution)
+{
+ std::vector verts;
+ std::vector indices;
+ GetMeshData(tshape, resolution, verts, indices);
+ mMillSimulator->SetBaseObject(verts, indices);
+}
+
DlgCAMSimulator* DlgCAMSimulator::mInstance = nullptr;
//************************************************************************************************************
diff --git a/src/Mod/CAM/PathSimulator/AppGL/DlgCAMSimulator.h b/src/Mod/CAM/PathSimulator/AppGL/DlgCAMSimulator.h
index a60b434860..50dda37f0c 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/DlgCAMSimulator.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/DlgCAMSimulator.h
@@ -23,6 +23,7 @@
#ifndef PATHSIMULATOR_CAMSimulatorGui_H
#define PATHSIMULATOR_CAMSimulatorGui_H
+#include
#include
#include
#include
@@ -33,7 +34,9 @@
namespace MillSim
{
-class MillSimulation; // use short declaration as using 'include' causes a header loop
+// use short declaration as using 'include' causes a header loop
+class MillSimulation;
+struct Vertex;
}
namespace CAMSimulator
@@ -63,11 +66,13 @@ public:
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:
+ public: // slots:
void renderLater();
void renderNow();
- void startSimulation(const SimStock* stock, float quality);
+ void startSimulation(const Part::TopoShape& stock, float quality);
void resetSimulation();
void addGcodeCommand(const char* cmd);
void addTool(const std::vector toolProfilePoints,
@@ -77,23 +82,28 @@ public: // slots:
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& verts,
+ std::vector& indices);
private:
bool mAnimating = false;
bool mNeedsInitialize = false;
QOpenGLContext* mContext = nullptr;
+ QOpenGLContext* mLastContext = nullptr;
MillSim::MillSimulation* mMillSimulator = nullptr;
static DlgCAMSimulator* mInstance;
- SimStock mStock = {0, 0, 0, 1, 1, 1, 1};
float mQuality = 10;
};
diff --git a/src/Mod/CAM/PathSimulator/AppGL/EndMill.cpp b/src/Mod/CAM/PathSimulator/AppGL/EndMill.cpp
index 039d5d27f9..a6f078d98c 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/EndMill.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/EndMill.cpp
@@ -35,31 +35,28 @@ EndMill::EndMill(int toolid, float diameter)
EndMill::EndMill(const std::vector& toolProfile, int toolid, float diameter)
: EndMill(toolid, diameter)
{
- profilePoints = nullptr;
- mHandleAllocation = false;
+ profilePoints.clear();
- int srcBuffSize = static_cast(toolProfile.size());
+ int srcBuffSize = toolProfile.size();
nPoints = srcBuffSize / 2;
if (nPoints < 2) {
return;
}
// make sure last point is at 0,0 else, add it
- bool missingCenterPoint = fabs(toolProfile[nPoints * 2 - 2]) > 0.0001F;
+ bool missingCenterPoint = fabs(toolProfile[nPoints * 2 - 2]) > 0.0001f;
if (missingCenterPoint) {
nPoints++;
}
int buffSize = PROFILE_BUFFER_SIZE(nPoints);
- profilePoints = new float[buffSize];
- if (profilePoints == nullptr) {
- return;
- }
+ profilePoints.resize(buffSize);
// copy profile points
- mHandleAllocation = true;
- for (int i = 0; i < srcBuffSize; i++) {
- profilePoints[i] = toolProfile[i] + 0.01F; // add some width to reduce simulation artifacts
+ for (int i = 0; i < srcBuffSize; i += 2) {
+ // add some width to reduce simulation artifacts
+ profilePoints[i] = toolProfile[i] + diameter * 0.01f;
+ profilePoints[i + 1] = toolProfile[i + 1] - diameter * 0.01f;
}
if (missingCenterPoint) {
profilePoints[srcBuffSize] = 0.0F;
@@ -74,9 +71,6 @@ EndMill::~EndMill()
toolShape.FreeResources();
halfToolShape.FreeResources();
pathShape.FreeResources();
- if (mHandleAllocation) {
- delete[] profilePoints;
- }
}
void EndMill::GenerateDisplayLists(float quality)
@@ -91,21 +85,21 @@ void EndMill::GenerateDisplayLists(float quality)
}
// full tool
- toolShape.RotateProfile(profilePoints, nPoints, 0, nslices, false);
+ toolShape.RotateProfile(profilePoints.data(), nPoints, 0, 0, nslices, false);
// half tool
- halfToolShape.RotateProfile(profilePoints, nPoints, 0, nslices / 2, true);
+ halfToolShape.RotateProfile(profilePoints.data(), nPoints, 0, 0, nslices / 2, true);
// unit path
int nFullPoints = PROFILE_BUFFER_POINTS(nPoints);
- pathShape.ExtrudeProfileLinear(profilePoints, nFullPoints, 0, 1, 0, 0, true, false);
+ pathShape.ExtrudeProfileLinear(profilePoints.data(), nFullPoints, 0, 1, 0, 0, true, false);
}
unsigned int
EndMill::GenerateArcSegmentDL(float radius, float angleRad, float zShift, Shape* retShape)
{
int nFullPoints = PROFILE_BUFFER_POINTS(nPoints);
- retShape->ExtrudeProfileRadial(profilePoints,
+ retShape->ExtrudeProfileRadial(profilePoints.data(),
nFullPoints,
radius,
angleRad,
diff --git a/src/Mod/CAM/PathSimulator/AppGL/EndMill.h b/src/Mod/CAM/PathSimulator/AppGL/EndMill.h
index f60a2d81e4..66db2a2eb9 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/EndMill.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/EndMill.h
@@ -35,7 +35,7 @@ namespace MillSim
class EndMill
{
public:
- float* profilePoints = nullptr;
+ std::vectorprofilePoints;
float radius;
int nPoints = 0;
int toolId = -1;
@@ -53,9 +53,6 @@ public:
protected:
void MirrorPointBuffer();
-
-private:
- bool mHandleAllocation = false;
};
} // namespace MillSim
diff --git a/src/Mod/CAM/PathSimulator/AppGL/GCodeParser.cpp b/src/Mod/CAM/PathSimulator/AppGL/GCodeParser.cpp
index 4702f32838..29c177f42d 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/GCodeParser.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/GCodeParser.cpp
@@ -27,8 +27,6 @@
#endif
#include "GCodeParser.h"
-#include
-#include
using namespace MillSim;
@@ -43,7 +41,7 @@ GCodeParser::~GCodeParser()
bool GCodeParser::Parse(const char* filename)
{
Operations.clear();
- lastState = {eNop, -1, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F};
+ lastState = {eNop, -1, 0, 0, 0, 0, 0, 0, 0};
lastTool = -1;
FILE* fl;
@@ -222,6 +220,7 @@ bool GCodeParser::AddLine(const char* ptr)
Operations.push_back(lastState);
lastState.z = rPlane;
Operations.push_back(lastState);
+ lastState.cmd = eDril;
}
else {
Operations.push_back(lastState);
diff --git a/src/Mod/CAM/PathSimulator/AppGL/GCodeParser.h b/src/Mod/CAM/PathSimulator/AppGL/GCodeParser.h
index 14ab3b04c3..7632de8a25 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/GCodeParser.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/GCodeParser.h
@@ -45,8 +45,8 @@ public:
public:
std::vector Operations;
- MillMotion lastState = {eNop, 0, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F};
- MillMotion lastLastState = {eNop, 0, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F};
+ MillMotion lastState = {eNop, 0, 0, 0, 0, 0, 0, 0, 0};
+ MillMotion lastLastState = {eNop, 0, 0, 0, 0, 0, 0, 0, 0};
protected:
const char* GetNextToken(const char* ptr, GCToken* token);
diff --git a/src/Mod/CAM/PathSimulator/AppGL/GlUtils.cpp b/src/Mod/CAM/PathSimulator/AppGL/GlUtils.cpp
index 50f91983f4..a428198964 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/GlUtils.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/GlUtils.cpp
@@ -25,6 +25,8 @@
namespace MillSim
{
+int gWindowSizeW = 800;
+int gWindowSizeH = 600;
int gDebug = -1;
diff --git a/src/Mod/CAM/PathSimulator/AppGL/GlUtils.h b/src/Mod/CAM/PathSimulator/AppGL/GlUtils.h
index 255664b760..558501d1a5 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/GlUtils.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/GlUtils.h
@@ -28,6 +28,7 @@
#define PI 3.14159265f
#define PI2 (PI * 2)
+
constexpr auto EPSILON = 0.00001f;
#define EQ_FLOAT(x, y) (fabs((x) - (y)) < EPSILON)
@@ -38,16 +39,31 @@ constexpr auto EPSILON = 0.00001f;
{ \
GLClearError(); \
x; \
- if (GLLogError()) \
+ if (GLLogError()) \
__debugbreak(); \
}
#define RadToDeg(x) (x * 180.0f / PI)
+#define GLDELETE(type, x) \
+ { \
+ if (x != 0) \
+ glDelete##type(1, &x); \
+ x = 0; \
+ }
+
+#define GLDELETE_FRAMEBUFFER(x) GLDELETE(Framebuffers, x)
+#define GLDELETE_TEXTURE(x) GLDELETE(Textures, x)
+#define GLDELETE_VERTEXARRAY(x) GLDELETE(VertexArrays, x)
+#define GLDELETE_RENDERBUFFER(x) GLDELETE(Renderbuffers, x)
+#define GLDELETE_BUFFER(x) GLDELETE(Buffers, x)
+
namespace MillSim
{
void GLClearError();
bool GLLogError();
extern mat4x4 identityMat;
extern int gDebug;
+extern int gWindowSizeW;
+extern int gWindowSizeH;
} // namespace MillSim
#endif // !__glutils_h__
diff --git a/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp b/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp
index 6e2cb43ef7..b3005f41ff 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp
@@ -24,23 +24,24 @@
#include "OpenGlWrapper.h"
#include "MillSimulation.h"
#include
-#include "GlUtils.h"
-#include
using namespace MillSim;
GuiItem guiItems[] = {
- {0, 0, 360, 554, 0, false, false, {}},
- {0, 0, 448, 540, 1, false, false, {}},
- {0, 0, 170, 540, 'P', true, false, {}},
- {0, 0, 170, 540, 'S', false, false, {}},
- {0, 0, 210, 540, 'T', false, false, {}},
- {0, 0, 250, 540, 'F', false, false, {}},
- {0, 0, 290, 540, ' ', false, false, {}},
- {0, 0, 620, 540, 0, false, false, {}},
- {0, 0, 660, 540, 0, false, false, {}},
- {0, 0, 645, 540, 0, false, false, {}},
- {0, 0, 640, 540, 0, true, false, {}},
+ {eGuiItemSlider, 0, 0, 240, -36, 0},
+ {eGuiItemThumb, 0, 0, 328, -50, 1},
+ {eGuiItemPause, 0, 0, 40, -50, 'P', true},
+ {eGuiItemPlay, 0, 0, 40, -50, 'S', false},
+ {eGuiItemSingleStep, 0, 0, 80, -50, 'T'},
+ {eGuiItemFaster, 0, 0, 120, -50, 'F'},
+ {eGuiItemRotate, 0, 0, -140, -50, ' ', false, GUIITEM_CHECKABLE},
+ {eGuiItemCharXImg, 0, 0, 160, -50, 0, false, 0}, // 620
+ {eGuiItemChar0Img, 0, 0, 200, -50, 0, false, 0},
+ {eGuiItemChar1Img, 0, 0, 185, -50, 0, false, 0},
+ {eGuiItemChar4Img, 0, 0, 180, -50, 0, true, 0},
+ {eGuiItemPath, 0, 0, -100, -50, 'L', false, GUIITEM_CHECKABLE},
+ {eGuiItemAmbientOclusion, 0, 0, -60, -50, 'A', false, GUIITEM_CHECKABLE},
+ {eGuiItemView, 0, 0, -180, -50, 'V', false},
};
#define NUM_GUI_ITEMS (sizeof(guiItems) / sizeof(GuiItem))
@@ -56,7 +57,19 @@ std::vector guiFileNames = {"Slider.png",
"X.png",
"0.png",
"1.png",
- "4.png"};
+ "4.png",
+ "Path.png",
+ "AmbientOclusion.png",
+ "View.png"};
+
+void GuiDisplay::UpdateProjection()
+{
+ mat4x4 projmat;
+ // mat4x4 viewmat;
+ mat4x4_ortho(projmat, 0, gWindowSizeW, gWindowSizeH, 0, -1, 1);
+ mShader.Activate();
+ mShader.UpdateProjectionMat(projmat);
+}
bool GuiDisplay::GenerateGlItem(GuiItem* guiItem)
{
@@ -95,8 +108,17 @@ bool GuiDisplay::GenerateGlItem(GuiItem* guiItem)
return true;
}
-bool GuiDisplay::InutGui()
+void GuiDisplay::DestroyGlItem(GuiItem* guiItem)
{
+ GLDELETE_BUFFER((guiItem->vbo));
+ GLDELETE_VERTEXARRAY((guiItem->vao));
+}
+
+bool GuiDisplay::InitGui()
+{
+ if (guiInitiated) {
+ return true;
+ }
// index buffer
glGenBuffers(1, &mIbo);
GLshort indices[6] = {0, 2, 3, 0, 3, 1};
@@ -108,26 +130,35 @@ bool GuiDisplay::InutGui()
return false;
}
mTexture.LoadImage(buffer, TEX_SIZE, TEX_SIZE);
- for (unsigned long i = 0; i < NUM_GUI_ITEMS; i++) {
+ for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
guiItems[i].texItem = *tLoader.GetTextureItem(i);
GenerateGlItem(&(guiItems[i]));
}
- mThumbStartX = guiItems[eGuiItemSlider].sx - guiItems[eGuiItemThumb].texItem.w / 2;
+ mThumbStartX = guiItems[eGuiItemSlider].posx() - guiItems[eGuiItemThumb].texItem.w / 2;
mThumbMaxMotion = (float)guiItems[eGuiItemSlider].texItem.w;
- UpdateSimSpeed(1);
-
- // shader
- mat4x4 projmat;
- // mat4x4 viewmat;
- mat4x4_ortho(projmat, 0, 800, 600, 0, -1, 1);
+ // init shader
mShader.CompileShader((char*)VertShader2DTex, (char*)FragShader2dTex);
mShader.UpdateTextureSlot(0);
- mShader.UpdateProjectionMat(projmat);
+
+ UpdateSimSpeed(1);
+ UpdateProjection();
+ guiInitiated = true;
return true;
}
+void GuiDisplay::ResetGui()
+{
+ mShader.Destroy();
+ for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
+ DestroyGlItem(&(guiItems[i]));
+ }
+ mTexture.DestroyTexture();
+ GLDELETE_BUFFER(mIbo);
+ guiInitiated = false;
+}
+
void GuiDisplay::RenderItem(int itemId)
{
GuiItem* item = &(guiItems[itemId]);
@@ -135,9 +166,9 @@ void GuiDisplay::RenderItem(int itemId)
return;
}
mat4x4 model;
- mat4x4_translate(model, (float)item->sx, (float)item->sy, 0);
+ mat4x4_translate(model, (float)item->posx(), (float)item->posy(), 0);
mShader.UpdateModelMat(model, nullptr);
- if (itemId == mPressedItem) {
+ if (item == mPressedItem) {
mShader.UpdateObjColor(mPressedColor);
}
else if (item->mouseOver) {
@@ -146,6 +177,9 @@ void GuiDisplay::RenderItem(int itemId)
else if (itemId > 1 && item->actionKey == 0) {
mShader.UpdateObjColor(mTextColor);
}
+ else if (item->flags & GUIITEM_CHECKED) {
+ mShader.UpdateObjColor(mToggleColor);
+ }
else {
mShader.UpdateObjColor(mStdColor);
}
@@ -157,13 +191,32 @@ void GuiDisplay::RenderItem(int itemId)
void GuiDisplay::MouseCursorPos(int x, int y)
{
- for (unsigned long i = 0; i < NUM_GUI_ITEMS; i++) {
+ mMouseOverItem = nullptr;
+ for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
GuiItem* g = &(guiItems[i]);
if (g->actionKey == 0) {
continue;
}
- g->mouseOver =
- (x > g->sx && y > g->sy && x < (g->sx + g->texItem.w) && y < (g->sy + g->texItem.h));
+ bool mouseCursorContained =
+ x > g->posx() && x < (g->posx() + g->texItem.w) &&
+ y > g->posy() && y < (g->posy() + g->texItem.h);
+
+ g->mouseOver = !g->hidden && mouseCursorContained;
+
+ if (g->mouseOver) {
+ mMouseOverItem = g;
+ }
+ }
+}
+
+void MillSim::GuiDisplay::HandleActionItem(GuiItem* guiItem)
+{
+ if (guiItem->actionKey >= ' ') {
+ if (guiItem->flags & GUIITEM_CHECKABLE) {
+ guiItem->flags ^= GUIITEM_CHECKED;
+ }
+ bool isChecked = (guiItem->flags & GUIITEM_CHECKED) != 0;
+ mMillSim->HandleGuiAction(guiItem->name, isChecked);
}
}
@@ -171,45 +224,38 @@ void GuiDisplay::MousePressed(int button, bool isPressed, bool isSimRunning)
{
if (button == MS_MOUSE_LEFT) {
if (isPressed) {
- mPressedItem = eGuiItemMax;
- for (unsigned long i = 1; i < NUM_GUI_ITEMS; i++) {
- GuiItem* g = &(guiItems[i]);
- if (g->mouseOver && !g->hidden) {
- mPressedItem = (eGuiItems)i;
- break;
- }
- }
- if (mPressedItem != eGuiItemMax) {
- GuiItem* g = &(guiItems[mPressedItem]);
- if (g->actionKey >= 32) {
- mMillSim->HandleKeyPress(g->actionKey);
- }
+ if (mMouseOverItem != nullptr) {
+ mPressedItem = mMouseOverItem;
+ HandleActionItem(mPressedItem);
}
}
else // button released
{
UpdatePlayState(isSimRunning);
- mPressedItem = eGuiItemMax;
+ if (mPressedItem != nullptr) {
+ MouseCursorPos(mPressedItem->posx() + 1, mPressedItem->posy() + 1);
+ mPressedItem = nullptr;
+ }
}
}
}
-void GuiDisplay::MouseDrag(int buttons, int dx, int dy)
+void GuiDisplay::MouseDrag(int /* buttons */, int dx, int /* dy */)
{
- (void)buttons;
- (void)dy;
- if (mPressedItem == eGuiItemThumb) {
- GuiItem* g = &(guiItems[eGuiItemThumb]);
- int newx = g->sx + dx;
+ if (mPressedItem == nullptr) {
+ return;
+ }
+ if (mPressedItem->name == eGuiItemThumb) {
+ int newx = mPressedItem->posx() + dx;
if (newx < mThumbStartX) {
newx = mThumbStartX;
}
if (newx > ((int)mThumbMaxMotion + mThumbStartX)) {
newx = (int)mThumbMaxMotion + mThumbStartX;
}
- if (newx != g->sx) {
+ if (newx != mPressedItem->posx()) {
mMillSim->SetSimulationStage((float)(newx - mThumbStartX) / mThumbMaxMotion);
- g->sx = newx;
+ mPressedItem->setPosx(newx);
}
}
}
@@ -227,19 +273,40 @@ void MillSim::GuiDisplay::UpdateSimSpeed(int speed)
guiItems[eGuiItemChar4Img].hidden = speed != 40;
}
+void MillSim::GuiDisplay::HandleKeyPress(int key)
+{
+ for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) {
+ GuiItem* g = &(guiItems[i]);
+ if (g->actionKey == key) {
+ HandleActionItem(g);
+ }
+ }
+}
+
+bool MillSim::GuiDisplay::IsChecked(eGuiItems item)
+{
+ return (guiItems[item].flags & GUIITEM_CHECKED) != 0;
+}
+
+void MillSim::GuiDisplay::UpdateWindowScale()
+{
+ UpdateProjection();
+}
+
void GuiDisplay::Render(float progress)
{
- if (mPressedItem != eGuiItemThumb) {
- guiItems[eGuiItemThumb].sx = (int)(mThumbMaxMotion * progress) + mThumbStartX;
+ if (mPressedItem == nullptr || mPressedItem->name != eGuiItemThumb) {
+ guiItems[eGuiItemThumb].setPosx((int)(mThumbMaxMotion * progress) + mThumbStartX);
}
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
+
mTexture.Activate();
mShader.Activate();
mShader.UpdateTextureSlot(0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- for (unsigned long i = 0; i < NUM_GUI_ITEMS; i++) {
+ for (int i = 0; i < (int)NUM_GUI_ITEMS; i++) {
RenderItem(i);
}
}
diff --git a/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.h b/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.h
index 0d9574e4d2..d98c2f1c64 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.h
@@ -26,27 +26,12 @@
#include "Texture.h"
#include "Shader.h"
#include "TextureLoader.h"
+#include "GlUtils.h"
namespace MillSim
{
class MillSimulation;
-struct GuiItem
-{
- unsigned int vbo, vao;
- int sx, sy; // screen location
- int actionKey; // action key when item pressed
- bool hidden; // is item hidden
- bool mouseOver;
- TextureItem texItem;
-};
-
-struct Vertex2D
-{
- float x, y;
- float tx, ty;
-};
-
enum eGuiItems
{
eGuiItemSlider,
@@ -60,17 +45,58 @@ enum eGuiItems
eGuiItemChar0Img,
eGuiItemChar1Img,
eGuiItemChar4Img,
+ eGuiItemPath,
+ eGuiItemAmbientOclusion,
+ eGuiItemView,
eGuiItemMax
};
+struct GuiItem
+{
+ eGuiItems name;
+ unsigned int vbo, vao;
+ int sx, sy; // screen location
+ int actionKey; // action key when item pressed
+ bool hidden {}; // is item hidden
+ unsigned int flags {};
+ bool mouseOver {};
+ TextureItem texItem {};
+
+ 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;
+ }
+};
+
+#define GUIITEM_CHECKABLE 0x01
+#define GUIITEM_CHECKED 0x02
+
+
+struct Vertex2D
+{
+ float x, y;
+ float tx, ty;
+};
class GuiDisplay
{
public:
// GuiDisplay() {};
- bool InutGui();
+ bool InitGui();
+ void ResetGui();
void Render(float progress);
void MouseCursorPos(int x, int y);
+ void HandleActionItem(GuiItem* guiItem);
void MousePressed(int button, bool isPressed, bool isRunning);
void MouseDrag(int buttons, int dx, int dy);
void SetMillSimulator(MillSimulation* millSim)
@@ -79,19 +105,29 @@ public:
}
void UpdatePlayState(bool isRunning);
void UpdateSimSpeed(int speed);
+ void HandleKeyPress(int key);
+ bool IsChecked(eGuiItems item);
+ void UpdateWindowScale();
+
+public:
+ bool guiInitiated = false;
private:
+ void UpdateProjection();
bool GenerateGlItem(GuiItem* guiItem);
+ void DestroyGlItem(GuiItem* guiItem);
void RenderItem(int itemId);
vec3 mStdColor = {0.8f, 0.8f, 0.4f};
+ vec3 mToggleColor = {0.9f, 0.6f, 0.2f};
vec3 mHighlightColor = {1.0f, 1.0f, 0.9f};
vec3 mPressedColor = {1.0f, 0.5f, 0.0f};
vec3 mTextColor = {1.0f, 0.5f, 0.0f};
Shader mShader;
Texture mTexture;
- eGuiItems mPressedItem = eGuiItemMax;
+ GuiItem* mPressedItem = nullptr;
+ GuiItem* mMouseOverItem = nullptr;
MillSimulation* mMillSim = nullptr;
unsigned int mIbo = 0;
int mThumbStartX = 0;
diff --git a/src/Mod/CAM/PathSimulator/AppGL/MillPathLine.cpp b/src/Mod/CAM/PathSimulator/AppGL/MillPathLine.cpp
new file mode 100644
index 0000000000..c35976de9a
--- /dev/null
+++ b/src/Mod/CAM/PathSimulator/AppGL/MillPathLine.cpp
@@ -0,0 +1,60 @@
+#include "MillPathLine.h"
+#include "OpenGlWrapper.h"
+#include "GlUtils.h"
+#include "Shader.h"
+
+namespace MillSim
+{
+
+
+MillPathLine::MillPathLine()
+{
+ mVao = mVbo = 0;
+}
+
+void MillPathLine::GenerateModel()
+{
+ mNumVerts = MillPathPointsBuffer.size();
+ void* vbuffer = MillPathPointsBuffer.data();
+
+ // vertex array
+ glGenVertexArrays(1, &mVao);
+ glBindVertexArray(mVao);
+
+ // vertex buffer
+ glGenBuffers(1, &mVbo);
+ glBindBuffer(GL_ARRAY_BUFFER, mVbo);
+ glBufferData(GL_ARRAY_BUFFER, mNumVerts * sizeof(MillPathPosition), vbuffer, GL_STATIC_DRAW);
+
+ // vertex attribs
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MillPathPosition),
+ (void*)offsetof(MillPathPosition, X));
+ glEnableVertexAttribArray(1);
+ glVertexAttribIPointer(1, 1, GL_INT, sizeof(MillPathPosition),
+ (void*)offsetof(MillPathPosition, SegmentId));
+
+ // unbind and free
+ glBindVertexArray(0);
+ MillPathPointsBuffer.clear();
+
+}
+
+void MillPathLine::Clear()
+{
+ MillPathPointsBuffer.clear();
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ GLDELETE_BUFFER(mVbo);
+ GLDELETE_VERTEXARRAY(mVao);
+}
+
+void MillPathLine::Render()
+{
+ glBindVertexArray(mVao);
+ glDrawArrays(GL_LINE_STRIP, 0, mNumVerts);
+}
+
+} // namespace Millsim
+
+
diff --git a/src/Mod/CAM/PathSimulator/AppGL/MillPathLine.h b/src/Mod/CAM/PathSimulator/AppGL/MillPathLine.h
new file mode 100644
index 0000000000..c62d486a36
--- /dev/null
+++ b/src/Mod/CAM/PathSimulator/AppGL/MillPathLine.h
@@ -0,0 +1,34 @@
+#ifndef __millpathline_h__
+#define __millpathline_h__
+#include
+
+namespace MillSim
+{
+
+struct MillPathPosition
+{
+ float X, Y, Z;
+ int SegmentId;
+};
+
+class MillPathLine
+{
+public:
+ MillPathLine();
+ void GenerateModel();
+ void Clear();
+ void Render();
+
+public:
+ std::vector MillPathPointsBuffer;
+
+protected:
+ unsigned int mVbo;
+ unsigned int mVao;
+ int mNumVerts;
+};
+
+} // namespace Millsim
+
+#endif // !__millpathline_h__
+
diff --git a/src/Mod/CAM/PathSimulator/AppGL/MillPathSegment.cpp b/src/Mod/CAM/PathSimulator/AppGL/MillPathSegment.cpp
index fbd126b851..310363b959 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/MillPathSegment.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/MillPathSegment.cpp
@@ -56,11 +56,8 @@ float MillPathSegment::mResolution = 1;
float MillPathSegment::mSmallRadStep = (PI / 8);
MillPathSegment::MillPathSegment(EndMill* _endmill, MillMotion* from, MillMotion* to)
- : mShearMat {{1.0F, 0.0F, 0.0F, 0.0F},
- {0.0F, 1.0F, 0.0F, 0.0F},
- {0.0F, 0.0F, 1.0F, 0.0F},
- {0.0F, 0.0F, 0.0F, 1.0F}}
{
+ mat4x4_identity(mShearMat);
MotionPosToVec(mStartPos, from);
MotionPosToVec(mDiff, to);
vec3_sub(mDiff, mDiff, mStartPos);
@@ -142,6 +139,32 @@ MillPathSegment::~MillPathSegment()
}
+void MillPathSegment::AppendPathPoints(std::vector& pointsBuffer)
+{
+ MillPathPosition mpPos;
+ if (mMotionType == MTCurved) {
+ float ang = mStartAngRad;
+ float z = mStartPos[PZ];
+ float zStep = mDiff[PZ] / numSimSteps;
+ for (int i = 1; i < numSimSteps; i++) {
+ ang -= mStepAngRad;
+ z += zStep;
+ mpPos.X = mCenter[PX] - sinf(ang) * mRadius;
+ mpPos.Y = mCenter[PY] + cosf(ang) * mRadius;
+ mpPos.Z = z;
+ mpPos.SegmentId = segmentIndex;
+ pointsBuffer.push_back(mpPos);
+ }
+ }
+ else {
+ mpPos.X = mStartPos[PX] + mDiff[PX];
+ mpPos.Y = mStartPos[PY] + mDiff[PY];
+ mpPos.Z = mStartPos[PZ] + mDiff[PZ];
+ mpPos.SegmentId = segmentIndex;
+ pointsBuffer.push_back(mpPos);
+ }
+}
+
void MillPathSegment::render(int step)
{
mStepNumber = step;
diff --git a/src/Mod/CAM/PathSimulator/AppGL/MillPathSegment.h b/src/Mod/CAM/PathSimulator/AppGL/MillPathSegment.h
index 43369cb5f7..09c670e4b1 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/MillPathSegment.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/MillPathSegment.h
@@ -27,6 +27,7 @@
#include "MillMotion.h"
#include "EndMill.h"
#include "linmath.h"
+#include "MillPathLine.h"
namespace MillSim
{
@@ -38,7 +39,6 @@ enum MotionType
MTCurved
};
-
bool IsVerticalMotion(MillMotion* m1, MillMotion* m2);
@@ -55,7 +55,7 @@ public:
virtual ~MillPathSegment();
- /// Calls the display list.
+ virtual void AppendPathPoints(std::vector& pointsBuffer);
virtual void render(int substep);
virtual void GetHeadPosition(vec3 headPos);
static float SetQuality(float quality, float maxStockDimension); // 1 minimum, 10 maximum
@@ -65,6 +65,7 @@ public:
bool isMultyPart;
int numSimSteps;
int indexInArray;
+ int segmentIndex;
protected:
diff --git a/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.cpp b/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.cpp
index e0f7556949..09f9bc5ca5 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.cpp
@@ -25,580 +25,609 @@
#include
#include
-namespace MillSim {
+namespace MillSim
+{
- MillSimulation::MillSimulation()
- {
- mCurMotion = { eNop, -1, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F };
- guiDisplay.SetMillSimulator(this);
+MillSimulation::MillSimulation()
+{
+ mCurMotion = {eNop, -1, 0, 0, 0, 0, 0, 0, 0};
+ guiDisplay.SetMillSimulator(this);
+}
+
+MillSimulation::~MillSimulation()
+{
+ Clear();
+}
+
+void MillSimulation::ClearMillPathSegments()
+{
+ for (unsigned int i = 0; i < MillPathSegments.size(); i++) {
+ delete MillPathSegments[i];
+ }
+ MillPathSegments.clear();
+}
+
+void MillSimulation::Clear()
+{
+ mCodeParser.Operations.clear();
+ for (unsigned int i = 0; i < mToolTable.size(); i++) {
+ delete mToolTable[i];
+ }
+ ClearMillPathSegments();
+ mStockObject.~StockObject();
+ mToolTable.clear();
+ guiDisplay.ResetGui();
+ simDisplay.CleanGL();
+ mCurStep = 0;
+ mPathStep = -1;
+ mNTotalSteps = 0;
+}
+
+
+void MillSimulation::SimNext()
+{
+ static int simDecim = 0;
+
+ simDecim++;
+ if (simDecim < 1) {
+ return;
}
- void MillSimulation::ClearMillPathSegments() {
- //for (std::vector::const_iterator i = MillPathSegments.begin(); i != MillPathSegments.end(); ++i) {
- // MillSim::MillPathSegment* p = *i;
- // delete p;
- //}
- for (std::size_t i = 0; i < MillPathSegments.size(); i++) {
- delete MillPathSegments[i];
- }
- MillPathSegments.clear();
+ simDecim = 0;
+
+ if (mCurStep < mNTotalSteps) {
+ mCurStep += mSimSpeed;
+ CalcSegmentPositions();
+ simDisplay.updateDisplay = true;
}
+}
- void MillSimulation::Clear()
- {
- mCodeParser.Operations.clear();
- for (std::size_t i = 0; i < mToolTable.size(); i++) {
- delete mToolTable[i];
- }
- mToolTable.clear();
- mCurStep = 0;
- mPathStep = -1;
- mNTotalSteps = 0;
- }
+void MillSimulation::InitSimulation(float quality)
+{
+ ClearMillPathSegments();
+ millPathLine.Clear();
+ simDisplay.applySSAO = guiDisplay.IsChecked(eGuiItemAmbientOclusion);
-
-
- void MillSimulation::SimNext()
- {
- static int simDecim = 0;
-
- simDecim++;
- if (simDecim < 1)
- return;
-
- simDecim = 0;
-
- if (mCurStep < mNTotalSteps)
- {
- mCurStep += mSimSpeed;
- CalcSegmentPositions();
+ mDestMotion = mZeroPos;
+ // gDestPos = curMillOperation->startPos;
+ mCurStep = 0;
+ mPathStep = -1;
+ mNTotalSteps = 0;
+ mSimPlaying = false;
+ mSimSpeed = 1;
+ MillPathSegment::SetQuality(quality, simDisplay.maxFar);
+ int nOperations = (int)mCodeParser.Operations.size();
+ int segId = 0;
+ for (int i = 0; i < nOperations; i++) {
+ mCurMotion = mDestMotion;
+ mDestMotion = mCodeParser.Operations[i];
+ EndMill* tool = GetTool(mDestMotion.tool);
+ if (tool != nullptr) {
+ MillSim::MillPathSegment* segment =
+ new MillSim::MillPathSegment(tool, &mCurMotion, &mDestMotion);
+ segment->indexInArray = i;
+ segment->segmentIndex = segId++;
+ mNTotalSteps += segment->numSimSteps;
+ MillPathSegments.push_back(segment);
+ segment->AppendPathPoints(millPathLine.MillPathPointsBuffer);
}
}
+ mNPathSteps = (int)MillPathSegments.size();
+ millPathLine.GenerateModel();
+ InitDisplay(quality);
+}
- void MillSimulation::InitSimulation(float quality)
- {
- ClearMillPathSegments();
-
- mDestMotion = mZeroPos;
- //gDestPos = curMillOperation->startPos;
- mCurStep = 0;
- mPathStep = -1;
- mNTotalSteps = 0;
- MillPathSegment::SetQuality(quality, mMaxFar);
- int nOperations = (int)mCodeParser.Operations.size();;
- for (int i = 0; i < nOperations; i++)
- {
- mCurMotion = mDestMotion;
- mDestMotion = mCodeParser.Operations[i];
- EndMill* tool = GetTool(mDestMotion.tool);
- if (tool != nullptr)
- {
- MillSim::MillPathSegment* segment = new MillSim::MillPathSegment(tool, &mCurMotion, &mDestMotion);
- segment->indexInArray = i;
- mNTotalSteps += segment->numSimSteps;
- MillPathSegments.push_back(segment);
- }
- }
- mNPathSteps = (int)MillPathSegments.size();
- InitDisplay(quality);
- }
-
- EndMill* MillSimulation::GetTool(int toolId)
- {
- for (std::size_t i = 0; i < mToolTable.size(); i++)
- {
- if (mToolTable[i]->toolId == toolId)
- {
- return mToolTable[i];
- }
- }
- return nullptr;
- }
-
- void MillSimulation::RemoveTool(int toolId)
- {
- EndMill* tool;
- if ((tool = GetTool(toolId)) != nullptr) {
- auto it = std::find(mToolTable.begin(), mToolTable.end(), tool);
- if (it != mToolTable.end()) {
- mToolTable.erase(it);
- }
- delete tool;
+EndMill* MillSimulation::GetTool(int toolId)
+{
+ for (unsigned int i = 0; i < mToolTable.size(); i++) {
+ if (mToolTable[i]->toolId == toolId) {
+ return mToolTable[i];
}
}
+ return nullptr;
+}
- void MillSimulation::AddTool(EndMill* tool)
- {
- // if we have another tool with same id, remove it
- RemoveTool(tool->toolId);
- mToolTable.push_back(tool);
- }
-
- void
- MillSimulation::AddTool(const std::vector& toolProfile, int toolid, float diameter)
- {
- // if we have another tool with same id, remove it
- RemoveTool(toolid);
- EndMill* tool = new EndMill(toolProfile, toolid, diameter);
- mToolTable.push_back(tool);
- }
-
- void MillSimulation::GlsimStart()
- {
- glEnable(GL_CULL_FACE);
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_STENCIL_TEST);
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- }
-
- void MillSimulation::GlsimToolStep1(void)
- {
- glCullFace(GL_BACK);
- glDepthFunc(GL_LESS);
- glStencilFunc(GL_ALWAYS, 1, 0xFF);
- glStencilOp(GL_ZERO, GL_ZERO, GL_REPLACE);
- glDepthMask(GL_FALSE);
- }
-
-
- void MillSimulation::GlsimToolStep2(void)
- {
- glStencilFunc(GL_EQUAL, 1, 0xFF);
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glDepthFunc(GL_GREATER);
- glCullFace(GL_FRONT);
- glDepthMask(GL_TRUE);
- }
-
- void MillSimulation::GlsimClipBack(void)
- {
- glStencilFunc(GL_ALWAYS, 1, 0xFF);
- glStencilOp(GL_REPLACE, GL_REPLACE, GL_ZERO);
- glDepthFunc(GL_LESS);
- glCullFace(GL_FRONT);
- glDepthMask(GL_FALSE);
- }
-
-
- void MillSimulation::GlsimRenderStock(void)
- {
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glEnable(GL_STENCIL_TEST);
- glStencilFunc(GL_EQUAL, 1, 0xFF);
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glDepthFunc(GL_EQUAL);
- glCullFace(GL_BACK);
- }
-
- void MillSimulation::GlsimRenderTools(void)
- {
- glCullFace(GL_FRONT);
- }
-
- void MillSimulation::GlsimEnd(void)
- {
- glCullFace(GL_BACK);
- glStencilFunc(GL_ALWAYS, 1, 0xFF);
- glDisable(GL_STENCIL_TEST);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glDepthMask(GL_TRUE);
- glDepthFunc(GL_LESS);
- }
-
- void MillSimulation::renderSegmentForward(int iSeg)
- {
- MillSim::MillPathSegment* p = MillPathSegments.at(iSeg);
- int step = iSeg == mPathStep ? mSubStep : p->numSimSteps;
- int start = p->isMultyPart ? 1 : step;
- for (int i = start; i <= step; i++)
- {
- GlsimToolStep1();
- p->render(i);
- GlsimToolStep2();
- p->render(i);
+void MillSimulation::RemoveTool(int toolId)
+{
+ EndMill* tool;
+ if ((tool = GetTool(toolId)) != nullptr) {
+ auto it = std::find(mToolTable.begin(), mToolTable.end(), tool);
+ if (it != mToolTable.end()) {
+ mToolTable.erase(it);
}
+ delete tool;
}
+}
- void MillSimulation::renderSegmentReversed(int iSeg)
- {
- MillSim::MillPathSegment* p = MillPathSegments.at(iSeg);
- int step = iSeg == mPathStep ? mSubStep : p->numSimSteps;
- int end = p->isMultyPart ? 1 : step;
- for (int i = step; i >= end; i--)
- {
- GlsimToolStep1();
- p->render(i);
- GlsimToolStep2();
- p->render(i);
- }
- }
- void MillSimulation::CalcSegmentPositions()
- {
- mSubStep = mCurStep;
- for (mPathStep = 0; mPathStep < mNPathSteps; mPathStep++)
- {
- MillSim::MillPathSegment* p = MillPathSegments[mPathStep];
- if (mSubStep < p->numSimSteps)
- break;
- mSubStep -= p->numSimSteps;
- }
- if (mPathStep >= mNPathSteps)
- {
- mPathStep = mNPathSteps - 1;
- mSubStep = MillPathSegments[mPathStep]->numSimSteps;
- }
- else
- mSubStep++;
- }
+void MillSimulation::AddTool(EndMill* tool)
+{
+ // if we have another tool with same id, remove it
+ RemoveTool(tool->toolId);
+ mToolTable.push_back(tool);
+}
- void MillSimulation::Render()
- {
- mat4x4 matLookAt, model;
- mat4x4_identity(model);
- mat4x4_look_at(matLookAt, eye, target, upvec);
+void MillSimulation::AddTool(const std::vector& toolProfile, int toolid, float diameter)
+{
+ // if we have another tool with same id, remove it
+ RemoveTool(toolid);
+ EndMill* tool = new EndMill(toolProfile, toolid, diameter);
+ mToolTable.push_back(tool);
+}
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+void MillSimulation::GlsimStart()
+{
+ glDisable(GL_BLEND);
+ glEnable(GL_STENCIL_TEST);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+}
- mat4x4_translate_in_place(matLookAt, mEyeX * mEyeXZFactor, 0, mEyeZ * mEyeXZFactor);
- mat4x4_rotate_X(matLookAt, matLookAt, mEyeInclination);
- mat4x4_rotate_Z(matLookAt, matLookAt, mEyeRoration);
- mat4x4_translate_in_place(matLookAt, -mStockObject.center[0], -mStockObject.center[1], -mStockObject.center[2]);
+void MillSimulation::GlsimToolStep1(void)
+{
+ glCullFace(GL_BACK);
+ glDepthFunc(GL_LESS);
+ glStencilFunc(GL_ALWAYS, 1, 0xFF);
+ glStencilOp(GL_ZERO, GL_ZERO, GL_REPLACE);
+ glDepthMask(GL_FALSE);
+}
- shaderFlat.Activate();
- shaderFlat.UpdateViewMat(matLookAt);
- GlsimStart();
- mStockObject.render();
+void MillSimulation::GlsimToolStep2(void)
+{
+ glStencilFunc(GL_EQUAL, 1, 0xFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glDepthFunc(GL_GREATER);
+ glCullFace(GL_FRONT);
+ glDepthMask(GL_TRUE);
+}
+void MillSimulation::GlsimClipBack(void)
+{
+ glStencilFunc(GL_ALWAYS, 1, 0xFF);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_ZERO);
+ glDepthFunc(GL_LESS);
+ glCullFace(GL_FRONT);
+ glDepthMask(GL_FALSE);
+}
+
+
+void MillSimulation::GlsimRenderStock(void)
+{
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glEnable(GL_STENCIL_TEST);
+ glStencilFunc(GL_EQUAL, 1, 0xFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glDepthFunc(GL_EQUAL);
+ glCullFace(GL_BACK);
+}
+
+void MillSimulation::GlsimRenderTools(void)
+{
+ glCullFace(GL_FRONT);
+}
+
+void MillSimulation::GlsimEnd(void)
+{
+ glCullFace(GL_BACK);
+ glStencilFunc(GL_ALWAYS, 1, 0xFF);
+ glDisable(GL_STENCIL_TEST);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_TRUE);
+ glDepthFunc(GL_LESS);
+}
+
+void MillSimulation::renderSegmentForward(int iSeg)
+{
+ MillSim::MillPathSegment* p = MillPathSegments.at(iSeg);
+ int step = iSeg == mPathStep ? mSubStep : p->numSimSteps;
+ int start = p->isMultyPart ? 1 : step;
+ for (int i = start; i <= step; i++) {
+ GlsimToolStep1();
+ p->render(i);
GlsimToolStep2();
-
- for (int i = 0; i <= mPathStep; i++)
- renderSegmentForward(i);
-
- for (int i = mPathStep; i >= 0; i--)
- renderSegmentForward(i);
-
- for (int i = 0; i < mPathStep; i++)
- renderSegmentReversed(i);
-
- for (int i = mPathStep; i >= 0; i--)
- renderSegmentReversed(i);
-
- GlsimClipBack();
- mStockObject.render();
-
- // start coloring
- shader3D.Activate();
- shader3D.UpdateViewMat(matLookAt);
- shader3D.UpdateObjColor(stockColor);
- GlsimRenderStock();
- mStockObject.render();
- GlsimRenderTools();
-
- // render cuts (back faces of tools)
-
- shaderInv3D.Activate();
- shaderInv3D.UpdateViewMat(matLookAt);
- shaderInv3D.UpdateObjColor(cutColor);
- for (int i = 0; i <= mPathStep; i++)
- {
- MillSim::MillPathSegment* p = MillPathSegments.at(i);
- int step = (i == mPathStep) ? mSubStep : p->numSimSteps;
- int start = p->isMultyPart ? 1 : step;
- for (int j = start; j <= step; j++)
- MillPathSegments.at(i)->render(j);
- }
-
- GlsimEnd();
-
- glEnable(GL_CULL_FACE);
-
- if (mPathStep >= 0)
- {
- vec3 toolPos;
- MotionPosToVec(toolPos, &mDestMotion);
- MillSim::MillPathSegment* p = MillPathSegments.at(mPathStep);
- p->GetHeadPosition(toolPos);
- mat4x4 tmat;
- mat4x4_translate(tmat, toolPos[0], toolPos[1], toolPos[2]);
- //mat4x4_translate(tmat, toolPos.x, toolPos.y, toolPos.z);
- shader3D.Activate();
- shader3D.UpdateObjColor(toolColor);
- p->endmill->toolShape.Render(tmat, identityMat);
- }
-
- shaderFlat.Activate();
- shaderFlat.UpdateObjColor(lightColor);
- mlightObject.render();
-
- if (mDebug > 0)
- {
- mat4x4 test;
- mat4x4_dup(test, model);
- mat4x4_translate_in_place(test, 20, 20, 3);
- mat4x4_rotate_Z(test, test, 30.f * 3.14f / 180.f);
- int dpos = mNPathSteps - mDebug2;
- MillSim::MillPathSegment* p = MillPathSegments.at(dpos);
- if (mDebug > p->numSimSteps)
- mDebug = 1;
- p->render(mDebug);
- }
- float progress = (float)mCurStep / mNTotalSteps;
- guiDisplay.Render(progress);
+ p->render(i);
}
+}
- void MillSimulation::ProcessSim(unsigned int time_ms) {
-
- static int ancient = 0;
- static unsigned int last = 0;
- static unsigned int msec = 0xFFFFFFFF;
- static int fps = 0;
- static int renderTime = 0;
-
- last = msec == 0xFFFFFFFF ? time_ms : msec;
- msec = time_ms;
- if (mIsRotate) {
- mEyeRoration += (msec - last) / 4600.0f;
- while (mEyeRoration >= PI2)
- mEyeRoration -= PI2;
- }
-
- if (last / 1000 != msec / 1000) {
- float calcFps = 1000.0f * fps / (msec - ancient);
- mFpsStream.str("");
- mFpsStream << "fps: " << calcFps << " rendertime:" << renderTime << " zpos:" << mDestMotion.z << std::ends;
- ancient = msec;
- fps = 0;
- }
-
- if (mSimPlaying || mSingleStep)
- {
- SimNext();
- mSingleStep = false;
- }
-
- Render();
-
- ++fps;
+void MillSimulation::renderSegmentReversed(int iSeg)
+{
+ MillSim::MillPathSegment* p = MillPathSegments.at(iSeg);
+ int step = iSeg == mPathStep ? mSubStep : p->numSimSteps;
+ int end = p->isMultyPart ? 1 : step;
+ for (int i = step; i >= end; i--) {
+ GlsimToolStep1();
+ p->render(i);
+ GlsimToolStep2();
+ p->render(i);
}
+}
- void MillSimulation::HandleKeyPress(int key)
- {
- switch (key) {
- case ' ':
- mIsRotate = !mIsRotate;
+void MillSimulation::CalcSegmentPositions()
+{
+ mSubStep = mCurStep;
+ for (mPathStep = 0; mPathStep < mNPathSteps; mPathStep++) {
+ MillSim::MillPathSegment* p = MillPathSegments[mPathStep];
+ if (mSubStep < p->numSimSteps) {
break;
+ }
+ mSubStep -= p->numSimSteps;
+ }
+ if (mPathStep >= mNPathSteps) {
+ mPathStep = mNPathSteps - 1;
+ mSubStep = MillPathSegments[mPathStep]->numSimSteps;
+ }
+ else {
+ mSubStep++;
+ }
+}
- case 'S':
+void MillSimulation::RenderSimulation()
+{
+ if ((mViewItems & VIEWITEM_SIMULATION) == 0) {
+ return;
+ }
+
+ simDisplay.StartDepthPass();
+
+ GlsimStart();
+ mStockObject.render();
+
+ GlsimToolStep2();
+
+ for (int i = 0; i <= mPathStep; i++) {
+ renderSegmentForward(i);
+ }
+
+ for (int i = mPathStep; i >= 0; i--) {
+ renderSegmentForward(i);
+ }
+
+ for (int i = 0; i < mPathStep; i++) {
+ renderSegmentReversed(i);
+ }
+
+ for (int i = mPathStep; i >= 0; i--) {
+ renderSegmentReversed(i);
+ }
+
+ GlsimClipBack();
+ mStockObject.render();
+
+ // start coloring
+ simDisplay.StartGeometryPass(stockColor, false);
+ GlsimRenderStock();
+ mStockObject.render();
+
+ // render cuts (back faces of tools)
+ simDisplay.StartGeometryPass(cutColor, true);
+ GlsimRenderTools();
+ for (int i = 0; i <= mPathStep; i++) {
+ MillSim::MillPathSegment* p = MillPathSegments.at(i);
+ int step = (i == mPathStep) ? mSubStep : p->numSimSteps;
+ int start = p->isMultyPart ? 1 : step;
+ for (int j = start; j <= step; j++) {
+ MillPathSegments.at(i)->render(j);
+ }
+ }
+
+ GlsimEnd();
+}
+
+void MillSimulation::RenderTool()
+{
+ if (mPathStep < 0) {
+ return;
+ }
+
+ vec3 toolPos;
+ MotionPosToVec(toolPos, &mDestMotion);
+ MillSim::MillPathSegment* p = MillPathSegments.at(mPathStep);
+ p->GetHeadPosition(toolPos);
+ mat4x4 tmat;
+ mat4x4_translate(tmat, toolPos[0], toolPos[1], toolPos[2]);
+ // mat4x4_translate(tmat, toolPos.x, toolPos.y, toolPos.z);
+ simDisplay.StartGeometryPass(toolColor, false);
+ p->endmill->toolShape.Render(tmat, identityMat);
+}
+
+void MillSimulation::RenderPath()
+{
+ if (!guiDisplay.IsChecked(eGuiItemPath)) {
+ return;
+ }
+ simDisplay.SetupLinePathPass(mPathStep, false);
+ millPathLine.Render();
+ simDisplay.SetupLinePathPass(mPathStep, true);
+ millPathLine.Render();
+ glDepthMask(GL_TRUE);
+}
+
+void MillSimulation::RenderBaseShape()
+{
+ if ((mViewItems & VIEWITEM_BASE_SHAPE) == 0) {
+ return;
+ }
+ simDisplay.StartDepthPass();
+ glPolygonOffset(0, -2);
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ simDisplay.StartGeometryPass(baseShapeColor, false);
+ mBaseShape.render();
+ glDisable(GL_POLYGON_OFFSET_FILL);
+}
+
+void MillSimulation::Render()
+{
+ // set background
+ glClearColor(bgndColor[0], bgndColor[1], bgndColor[2], 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ simDisplay.PrepareDisplay(mStockObject.center);
+
+ // render the simulation offscreen in an FBO
+ if (simDisplay.updateDisplay) {
+ simDisplay.PrepareFrameBuffer();
+ RenderSimulation();
+ RenderTool();
+ RenderBaseShape();
+ RenderPath();
+ simDisplay.updateDisplay = false;
+ }
+
+ simDisplay.RenderResult();
+
+ /* if (mDebug > 0) {
+ mat4x4 test;
+ mat4x4_identity(test);
+ mat4x4_translate_in_place(test, 20, 20, 3);
+ mat4x4_rotate_Z(test, test, 30.f * 3.14f / 180.f);
+ int dpos = mNPathSteps - mDebug2;
+ MillSim::MillPathSegment* p = MillPathSegments.at(dpos);
+ if (mDebug > p->numSimSteps) {
+ mDebug = 1;
+ }
+ p->render(mDebug);
+ }*/
+
+ float progress = (float)mCurStep / mNTotalSteps;
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ guiDisplay.Render(progress);
+}
+
+void MillSimulation::ProcessSim(unsigned int time_ms)
+{
+
+ static int ancient = 0;
+ static unsigned int last = 0;
+ static unsigned int msec = 0xFFFFFFFF;
+ static int fps = 0;
+ static int renderTime = 0;
+
+ last = msec == 0xFFFFFFFF ? time_ms : msec;
+ msec = time_ms;
+ if (guiDisplay.IsChecked(eGuiItemRotate)) {
+ simDisplay.RotateEye((msec - last) / 4600.0f);
+ }
+
+ if (last / 1000 != msec / 1000) {
+ float calcFps = 1000.0f * fps / (msec - ancient);
+ mFpsStream.str("");
+ mFpsStream << "fps: " << calcFps << " rendertime:" << renderTime
+ << " zpos:" << mDestMotion.z << std::ends;
+ ancient = msec;
+ fps = 0;
+ }
+
+ if (mSimPlaying || mSingleStep) {
+ SimNext();
+ mSingleStep = false;
+ }
+
+ Render();
+
+ ++fps;
+}
+
+void MillSimulation::HandleKeyPress(int key)
+{
+ if (key >= '1' && key <= '9') {
+ mSimSpeed = key - '0';
+ }
+ else if (key == 'D') {
+ mDebug++;
+ }
+ else if (key == 'K') {
+ mDebug2++;
+ gDebug = mNPathSteps - mDebug2;
+ }
+ else {
+ guiDisplay.HandleKeyPress(key);
+ }
+}
+
+void MillSimulation::HandleGuiAction(eGuiItems actionItem, bool checked)
+{
+ switch (actionItem) {
+ case eGuiItemPlay:
mSimPlaying = true;
break;
- case 'P':
+ case eGuiItemPause:
mSimPlaying = false;
break;
- case 'T':
+ case eGuiItemSingleStep:
mSimPlaying = false;
mSingleStep = true;
break;
- case'D':
- mDebug++;
- break;
-
- case'K':
- mDebug2++;
- gDebug = mNPathSteps - mDebug2;
- break;
-
- case 'F':
- if (mSimSpeed == 1) mSimSpeed = 10;
- else if (mSimSpeed == 10) mSimSpeed = 40;
- else mSimSpeed = 1;
+ case eGuiItemFaster:
+ if (mSimSpeed == 1) {
+ mSimSpeed = 10;
+ }
+ else if (mSimSpeed == 10) {
+ mSimSpeed = 40;
+ }
+ else {
+ mSimSpeed = 1;
+ }
guiDisplay.UpdateSimSpeed(mSimSpeed);
break;
- default:
- if (key >= '1' && key <= '9')
- mSimSpeed = key - '0';
+ case eGuiItemPath:
+ simDisplay.updateDisplay = true;
break;
- }
- guiDisplay.UpdatePlayState(mSimPlaying);
- }
- void MillSimulation::UpdateEyeFactor(float factor)
- {
- mEyeDistFactor = factor;
- mEyeXZFactor = factor * mMaxFar * 0.005f;
- eye[1] = -factor * mMaxFar;
- }
+ case eGuiItemAmbientOclusion:
+ simDisplay.applySSAO = checked;
+ simDisplay.updateDisplay = true;
+ break;
- void MillSimulation::TiltEye(float tiltStep)
- {
- mEyeInclination += tiltStep;
- if (mEyeInclination > PI / 2)
- mEyeInclination = PI / 2;
- else if (mEyeInclination < -PI / 2)
- mEyeInclination = -PI / 2;
- }
-
- void MillSimulation::RotateEye(float rotStep)
- {
- mEyeRoration += rotStep;
- if (mEyeRoration > PI2)
- mEyeRoration -= PI2;
- else if (mEyeRoration < 0)
- mEyeRoration += PI2;
- }
-
- void MillSimulation::MoveEye(float x, float z)
- {
- mEyeX += x;
- if (mEyeX > 100) mEyeX = 100;
- else if (mEyeX < -100) mEyeX = -100;
- mEyeZ += z;
- if (mEyeZ > 100) mEyeZ = 100;
- else if (mEyeZ < -100) mEyeZ = -100;
- }
-
- void MillSimulation::UpdateProjection()
- {
- // Setup projection
- mat4x4 projmat;
- mat4x4_perspective(projmat, 0.7f, 4.0f / 3.0f, 1.0f, mMaxFar);
- //mat4x4_perspective(projmat, 0.7f, 4.0f / 3.0f, 1, 100);
- shader3D.Activate();
- shader3D.UpdateProjectionMat(projmat);
- shaderInv3D.Activate();
- shaderInv3D.UpdateProjectionMat(projmat);
- shaderFlat.Activate();
- shaderFlat.UpdateProjectionMat(projmat);
- }
-
- void MillSimulation::InitDisplay(float quality)
- {
- // gray background
- glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
- mEyeRoration = 0.0;
-
- // use shaders
- // standard diffuse shader
- shader3D.CompileShader((char*)VertShader3DNorm, (char*)FragShaderNorm);
- shader3D.UpdateEnvColor(lightPos, lightColor, ambientCol);
-
- // invarted normal diffuse shader for inner mesh
- shaderInv3D.CompileShader((char*)VertShader3DInvNorm, (char*)FragShaderNorm);
- shaderInv3D.UpdateEnvColor(lightPos, lightColor, ambientCol);
-
- // null shader to calculate meshes only (simulation stage)
- shaderFlat.CompileShader((char*)VertShader3DNorm, (char*)FragShaderFlat);
- UpdateProjection();
-
- // setup light object and generate tools
- mlightObject.GenerateBoxStock(-0.5f, -0.5f, -0.5f, 1, 1, 1);
- for (std::size_t i = 0; i < mToolTable.size(); i++) {
- mToolTable[i]->GenerateDisplayLists(quality);
- }
-
- // init gui elements
- guiDisplay.InutGui();
-
- }
-
- void MillSimulation::SetBoxStock(float x, float y, float z, float l, float w, float h)
- {
- mStockObject.GenerateBoxStock(x, y, z, l, w, h);
- mMaxStockDim = fmaxf(w, l);
- mMaxFar = mMaxStockDim * 4;
- UpdateProjection();
- vec3_set(eye, 0, 0, 0);
- UpdateEyeFactor(0.4f);
- vec3_set(lightPos, x, y, h + mMaxStockDim / 3);
- mlightObject.SetPosition(lightPos);
- }
-
- void MillSimulation::MouseDrag(int buttons, int dx, int dy)
- {
- if (buttons == (MS_MOUSE_MID | MS_MOUSE_LEFT))
- {
- TiltEye((float)dy / 100.0f);
- RotateEye((float)dx / 100.0f);
- }
- else if (buttons == MS_MOUSE_MID)
- {
- MoveEye(dx, -dy);
- }
- guiDisplay.MouseDrag(buttons, dx, dy);
- }
-
- void MillSimulation::MouseMove(int px, int py)
- {
- if (mMouseButtonState > 0)
- {
- int dx = px - mLastMouseX;
- int dy = py - mLastMouseY;
- if (dx != 0 || dy != 0)
- {
- MouseDrag(mMouseButtonState, dx, dy);
- mLastMouseX = px;
- mLastMouseY = py;
+ case eGuiItemView:
+ mViewItems++;
+ if (mViewItems >= VIEWITEM_MAX) {
+ mViewItems = VIEWITEM_SIMULATION;
}
- }
- else
- MouseHover(px, py);
+ simDisplay.updateDisplay = true;
+ break;
+
+ default:
+ break;
+
+ }
+ guiDisplay.UpdatePlayState(mSimPlaying);
+}
+
+
+void MillSimulation::InitDisplay(float quality)
+{
+ // generate tools
+ for (unsigned int i = 0; i < mToolTable.size(); i++) {
+ mToolTable[i]->GenerateDisplayLists(quality);
}
- void MillSimulation::MouseScroll(float dy)
- {
- float f = mEyeDistFactor;
- f += 0.05f * dy;
- if (f > 0.6f) f = 0.6f;
- else if (f < 0.05f) f = 0.05f;
- UpdateEyeFactor(f);
+ // init 3d display
+ simDisplay.InitGL();
+
+ // init gui elements
+ guiDisplay.InitGui();
+}
+
+void MillSimulation::SetBoxStock(float x, float y, float z, float l, float w, float h)
+{
+ mStockObject.GenerateBoxStock(x, y, z, l, w, h);
+ simDisplay.ScaleViewToStock(&mStockObject);
+}
+
+void MillSimulation::SetArbitraryStock(std::vector& verts, std::vector& indices)
+{
+ mStockObject.GenerateSolid(verts, indices);
+ simDisplay.ScaleViewToStock(&mStockObject);
+}
+
+void MillSimulation::SetBaseObject(std::vector& verts, std::vector& indices)
+{
+ mBaseShape.GenerateSolid(verts, indices);
+}
+
+void MillSimulation::MouseDrag(int buttons, int dx, int dy)
+{
+ if (buttons == (MS_MOUSE_MID | MS_MOUSE_LEFT)) {
+ simDisplay.TiltEye((float)dy / 100.0f);
+ simDisplay.RotateEye((float)dx / 100.0f);
}
-
-
- void MillSimulation::MouseHover(int px, int py)
- {
- guiDisplay.MouseCursorPos(px, py);
+ else if (buttons == MS_MOUSE_MID) {
+ simDisplay.MoveEye(dx, -dy);
}
+ guiDisplay.MouseDrag(buttons, dx, dy);
+}
- void MillSimulation::MousePress(int button, bool isPressed, int px, int py)
- {
- if (isPressed)
- mMouseButtonState |= button;
- else
- mMouseButtonState &= ~button;
-
- if (mMouseButtonState > 0)
- {
+void MillSimulation::MouseMove(int px, int py)
+{
+ if (mMouseButtonState > 0) {
+ int dx = px - mLastMouseX;
+ int dy = py - mLastMouseY;
+ if (dx != 0 || dy != 0) {
+ MouseDrag(mMouseButtonState, dx, dy);
mLastMouseX = px;
mLastMouseY = py;
}
- guiDisplay.MousePressed(button, isPressed, mSimPlaying);
}
-
-
- bool MillSimulation::LoadGCodeFile(const char* fileName)
- {
- if (mCodeParser.Parse(fileName))
- {
- std::cout << "GCode file loaded successfully" << std::endl;
- return true;
- }
- return false;
+ else {
+ MouseHover(px, py);
}
-
- bool MillSimulation::AddGcodeLine(const char* line)
- {
- return mCodeParser.AddLine(line);
- }
-
- void MillSimulation::SetSimulationStage(float stage)
- {
- mCurStep = (int)((float)mNTotalSteps * stage);
- CalcSegmentPositions();
- }
-
}
+
+void MillSimulation::MouseScroll(float dy)
+{
+ float f = simDisplay.GetEyeFactor();
+ f += 0.05f * dy;
+ if (f > 0.6f) {
+ f = 0.6f;
+ }
+ else if (f < 0.05f) {
+ f = 0.05f;
+ }
+ simDisplay.UpdateEyeFactor(f);
+}
+
+
+void MillSimulation::MouseHover(int px, int py)
+{
+ guiDisplay.MouseCursorPos(px, py);
+}
+
+void MillSimulation::MousePress(int button, bool isPressed, int px, int py)
+{
+ if (isPressed) {
+ mMouseButtonState |= button;
+ }
+ else {
+ mMouseButtonState &= ~button;
+ }
+
+ if (mMouseButtonState > 0) {
+ mLastMouseX = px;
+ mLastMouseY = py;
+ }
+ guiDisplay.MousePressed(button, isPressed, mSimPlaying);
+}
+
+void MillSimulation::UpdateWindowScale(int width, int height)
+{
+ if (width == gWindowSizeW && height == gWindowSizeH) {
+ return;
+ }
+ gWindowSizeW = width;
+ gWindowSizeH = height;
+ simDisplay.UpdateWindowScale();
+ guiDisplay.UpdateWindowScale();
+ simDisplay.updateDisplay = true;
+}
+
+
+bool MillSimulation::LoadGCodeFile(const char* fileName)
+{
+ if (mCodeParser.Parse(fileName)) {
+ std::cout << "GCode file loaded successfully" << std::endl;
+ return true;
+ }
+ return false;
+}
+
+bool MillSimulation::AddGcodeLine(const char* line)
+{
+ return mCodeParser.AddLine(line);
+}
+
+void MillSimulation::SetSimulationStage(float stage)
+{
+ int newStep = (int)((float)mNTotalSteps * stage);
+ if (newStep == mCurStep) {
+ return;
+ }
+ mCurStep = newStep;
+ simDisplay.updateDisplay = true;
+ mSingleStep = true;
+ CalcSegmentPositions();
+}
+
+} // namespace MillSim
diff --git a/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.h b/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.h
index 765ea8add9..42c9df4f62 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.h
@@ -30,10 +30,17 @@
#include "GlUtils.h"
#include "StockObject.h"
#include "MillPathSegment.h"
+#include "SimDisplay.h"
#include "GuiDisplay.h"
+#include "MillPathLine.h"
+#include "SolidObject.h"
#include
#include
+#define VIEWITEM_SIMULATION 1
+#define VIEWITEM_BASE_SHAPE 2
+#define VIEWITEM_MAX 4
+
namespace MillSim
{
@@ -41,6 +48,7 @@ class MillSimulation
{
public:
MillSimulation();
+ ~MillSimulation();
void ClearMillPathSegments();
void Clear();
void SimNext();
@@ -51,23 +59,27 @@ public:
{
return GetTool(toolid) != nullptr;
}
+ void RenderSimulation();
+ void RenderTool();
+ void RenderPath();
+ void RenderBaseShape();
void Render();
void ProcessSim(unsigned int time_ms);
void HandleKeyPress(int key);
- void UpdateEyeFactor(float factor);
- void TiltEye(float tiltStep);
- void RotateEye(float rotStep);
- void MoveEye(float x, float y);
- void UpdateProjection();
+ void HandleGuiAction(eGuiItems actionItem, bool checked);
bool LoadGCodeFile(const char* fileName);
bool AddGcodeLine(const char* line);
void SetSimulationStage(float stage);
void SetBoxStock(float x, float y, float z, float l, float w, float h);
+ void SetArbitraryStock(std::vector& verts, std::vector& indices);
+ void SetBaseObject(std::vector& verts, std::vector& indices);
void MouseDrag(int buttons, int dx, int dy);
void MouseMove(int px, int py);
void MouseScroll(float dy);
void MouseHover(int px, int py);
void MousePress(int button, bool isPressed, int px, int py);
+ void UpdateWindowScale(int width, int height);
+
protected:
@@ -88,44 +100,25 @@ protected:
protected:
std::vector mToolTable;
- Shader shader3D, shaderInv3D, shaderFlat;
GCodeParser mCodeParser;
GuiDisplay guiDisplay;
+ SimDisplay simDisplay;
+ MillPathLine millPathLine;
std::vector MillPathSegments;
std::ostringstream mFpsStream;
- MillMotion mZeroPos = {eNop, -1, 0.0F, 0.0F, 100.0F, 0.0F, 0.0F, 0.0F, 0.0F};
- MillMotion mCurMotion = {eNop, -1, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F};
- MillMotion mDestMotion = {eNop, -1, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F};
+ MillMotion mZeroPos = {eNop, -1, 0, 0, 100, 0, 0, 0, 0};
+ MillMotion mCurMotion = {eNop, -1, 0, 0, 0, 0, 0, 0, 0};
+ MillMotion mDestMotion = {eNop, -1, 0, 0, 0, 0, 0, 0, 0};
StockObject mStockObject;
- StockObject mlightObject;
-
- vec3 lightColor = {0.8f, 0.9f, 1.0f};
- vec3 lightPos = {20.0f, 20.0f, 10.0f};
- vec3 ambientCol = {0.3f, 0.3f, 0.5f};
-
- vec3 eye = {0, 100, 40};
- vec3 target = {0, 0, -10};
- vec3 upvec = {0, 0, 1};
-
- vec3 stockColor = {0.7f, 0.7f, 0.7f};
- vec3 cutColor = {0.4f, 0.7f, 0.4f};
- vec3 toolColor = {0.4f, 0.4f, 0.7f};
-
- float mEyeDistance = 30;
- float mEyeRoration = 0;
- float mEyeInclination = PI / 6; // 30 degree
- float mEyeStep = PI / 36; // 5 degree
-
- float mMaxStockDim = 100;
- float mMaxFar = 100;
- float mEyeDistFactor = 0.4f;
- float mEyeXZFactor = 0.01f;
- float mEyeXZScale = 0;
- float mEyeX = 0.0f;
- float mEyeZ = 0.0f;
+ SolidObject mBaseShape;
+ vec3 bgndColor = {0.1f, 0.2f, 0.3f};
+ vec3 stockColor = {0.7f, 0.75f, 0.9f};
+ vec3 cutColor = {0.85f, 0.95f, 0.85f};
+ vec3 toolColor = {0.5f, 0.4f, 0.3f};
+ vec3 baseShapeColor = {0.7f, 0.6f, 0.5f};
int mCurStep = 0;
int mNTotalSteps = 0;
@@ -136,14 +129,15 @@ protected:
int mDebug1 = 0;
int mDebug2 = 12;
int mSimSpeed = 1;
+ int mViewItems = VIEWITEM_SIMULATION;
int mLastMouseX = 0, mLastMouseY = 0;
int mMouseButtonState = 0;
bool mIsInStock = false;
- bool mIsRotate = true;
bool mSimPlaying = false;
bool mSingleStep = false;
+
};
} // namespace MillSim
#endif
diff --git a/src/Mod/CAM/PathSimulator/AppGL/OpenGlWrapper.h b/src/Mod/CAM/PathSimulator/AppGL/OpenGlWrapper.h
index 92ad6483de..415036ec24 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/OpenGlWrapper.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/OpenGlWrapper.h
@@ -22,9 +22,7 @@
#ifndef __openglwrapper_h__
#define __openglwrapper_h__
-#ifdef CAM_SIM_USE_GLEW
-#include "GL/glew.h"
-#else
+
#include "DlgCAMSimulator.h"
extern QOpenGLContext* gOpenGlContext;
#define gSimWindow CAMSimulator::DlgCAMSimulator::GetInstance()
@@ -40,6 +38,8 @@ extern QOpenGLContext* gOpenGlContext;
#define glVertexAttribPointer gSimWindow->glVertexAttribPointer
#define glShaderSource gSimWindow->glShaderSource
#define glCompileShader gSimWindow->glCompileShader
+#define glDeleteShader gSimWindow->glDeleteShader
+#define glDeleteProgram gSimWindow->glDeleteProgram
#define glAttachShader gSimWindow->glAttachShader
#define glLinkProgram gSimWindow->glLinkProgram
#define glGetProgramiv gSimWindow->glGetProgramiv
@@ -69,6 +69,21 @@ extern QOpenGLContext* gOpenGlContext;
#define glTexParameteri gSimWindow->glTexParameteri
#define glTexImage2D gSimWindow->glTexImage2D
#define glDeleteTextures gSimWindow->glDeleteTextures
-#endif // HAVE_OPENGL_EXT
+#define glPolygonOffset gSimWindow->glPolygonOffset
+#define glBindFramebuffer gSimWindow->glBindFramebuffer
+#define glUniform1f gSimWindow->glUniform1f
+#define glGenFramebuffers gSimWindow->glGenFramebuffers
+#define glFramebufferTexture2D gSimWindow->glFramebufferTexture2D
+#define glDrawBuffers gSimWindow->glDrawBuffers
+#define glGenRenderbuffers gSimWindow->glGenRenderbuffers
+#define glBindRenderbuffer gSimWindow->glBindRenderbuffer
+#define glRenderbufferStorage gSimWindow->glRenderbufferStorage
+#define glFramebufferRenderbuffer gSimWindow->glFramebufferRenderbuffer
+#define glCheckFramebufferStatus gSimWindow->glCheckFramebufferStatus
+#define glDeleteFramebuffers gSimWindow->glDeleteFramebuffers
+#define glDeleteRenderbuffers gSimWindow->glDeleteRenderbuffers
+#define glVertexAttribIPointer gSimWindow->glVertexAttribIPointer
+#define glUniform4fv gSimWindow->glUniform4fv
+#define glLineWidth gSimWindow->glLineWidth
#endif // !__openglwrapper_h__
diff --git a/src/Mod/CAM/PathSimulator/AppGL/Shader.cpp b/src/Mod/CAM/PathSimulator/AppGL/Shader.cpp
index ddaa5acc07..c03d6449f0 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/Shader.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/Shader.cpp
@@ -29,6 +29,11 @@ namespace MillSim
Shader* CurrentShader = nullptr;
+Shader::~Shader()
+{
+ Destroy();
+}
+
void Shader::UpdateModelMat(mat4x4 tmat, mat4x4 nmat)
{
if (mModelPos >= 0) {
@@ -49,13 +54,11 @@ void Shader::UpdateProjectionMat(mat4x4 mat)
void Shader::UpdateViewMat(mat4x4 mat)
{
if (mViewPos >= 0) {
- if (mViewPos >= 0) {
- glUniformMatrix4fv(mViewPos, 1, GL_FALSE, (GLfloat*)mat);
- }
+ glUniformMatrix4fv(mViewPos, 1, GL_FALSE, (GLfloat*)mat);
}
}
-void Shader::UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient)
+void Shader::UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient, float linearity)
{
if (mLightPosPos >= 0) {
glUniform3fv(mLightPosPos, 1, lightPos);
@@ -63,8 +66,11 @@ void Shader::UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient)
if (mLightColorPos >= 0) {
glUniform3fv(mLightColorPos, 1, lightColor);
}
- if (mAmbientPos >= 0) {
- glUniform3fv(mAmbientPos, 1, ambient);
+ if (mLightAmbientPos >= 0) {
+ glUniform3fv(mLightAmbientPos, 1, ambient);
+ }
+ if (mLightLinearPos >= 0) {
+ glUniform1f(mLightLinearPos, linearity);
}
}
@@ -75,6 +81,20 @@ void Shader::UpdateObjColor(vec3 objColor)
}
}
+void Shader::UpdateObjColorAlpha(vec4 objColor)
+{
+ if (mObjectColorAlphaPos >= 0) {
+ glUniform4fv(mObjectColorAlphaPos, 1, objColor);
+ }
+}
+
+void Shader::UpdateNormalState(bool isInverted)
+{
+ if (mInvertedNormalsPos >= 0) {
+ glUniform1i(mInvertedNormalsPos, isInverted);
+ }
+}
+
void Shader::UpdateTextureSlot(int slot)
{
if (mTexSlotPos >= 0) {
@@ -82,12 +102,61 @@ void Shader::UpdateTextureSlot(int slot)
}
}
-bool CheckCompileResult(int shader)
+void Shader::UpdateAlbedoTexSlot(int albedoSlot)
{
+ if (mAlbedoPos >= 0) {
+ glUniform1i(mAlbedoPos, albedoSlot);
+ }
+}
+
+void Shader::UpdatePositionTexSlot(int positionSlot)
+{
+ if (mPositionPos >= 0) {
+ glUniform1i(mPositionPos, positionSlot);
+ }
+}
+
+void Shader::UpdateNormalTexSlot(int normalSlot)
+{
+ if (mNormalPos >= 0) {
+ glUniform1i(mNormalPos, normalSlot);
+ }
+}
+
+void Shader::UpdateNoiseTexSlot(int noiseSlot)
+{
+ if (mNoisePos >= 0) {
+ glUniform1i(mAlbedoPos, noiseSlot);
+ }
+}
+
+void Shader::UpdateSsaoTexSlot(int ssaoSlot)
+{
+ if (mSsaoPos >= 0) {
+ glUniform1i(mSsaoPos, ssaoSlot);
+ }
+}
+
+void Shader::UpdateKernelVals(int nVals, float *vals)
+{
+ glUniform3fv(mSamplesPos, nVals, vals);
+}
+
+void Shader::UpdateCurSegment(int curSeg)
+{
+ if (mCurSegmentPos >= 0) {
+ glUniform1i(mCurSegmentPos, curSeg);
+ }
+}
+
+
#ifdef QT_OPENGL_LIB
- (void)shader;
+bool CheckCompileResult(int /* shader */)
+{
return false;
#else
+bool CheckCompileResult(int shader)
+{
char log[1024];
int res = 0;
GLsizei len;
@@ -105,7 +174,7 @@ bool CheckCompileResult(int shader)
#endif
}
-unsigned int Shader::CompileShader(char* _vertShader, char* _fragShader)
+unsigned int Shader::CompileShader(const char* _vertShader, const char* _fragShader)
{
vertShader = _vertShader;
fragShader = _fragShader;
@@ -114,6 +183,7 @@ unsigned int Shader::CompileShader(char* _vertShader, char* _fragShader)
glShaderSource(vertex_shader, 1, &vertShader, NULL);
glCompileShader(vertex_shader);
if (CheckCompileResult(vertex_shader)) {
+ glDeleteShader(vertex_shader);
return 0xdeadbeef;
}
@@ -121,6 +191,8 @@ unsigned int Shader::CompileShader(char* _vertShader, char* _fragShader)
glShaderSource(fragment_shader, 1, &fragShader, NULL);
glCompileShader(fragment_shader);
if (CheckCompileResult(fragment_shader)) {
+ glDeleteShader(fragment_shader);
+ glDeleteShader(vertex_shader);
return 0xdeadbeef;
}
@@ -131,6 +203,7 @@ unsigned int Shader::CompileShader(char* _vertShader, char* _fragShader)
glGetProgramiv(shaderId, GL_LINK_STATUS, &res);
if (res == 0) {
+ Destroy();
return 0xdeadbeef;
}
@@ -141,9 +214,21 @@ unsigned int Shader::CompileShader(char* _vertShader, char* _fragShader)
mViewPos = glGetUniformLocation(shaderId, "view");
mLightPosPos = glGetUniformLocation(shaderId, "lightPos");
mLightColorPos = glGetUniformLocation(shaderId, "lightColor");
- mAmbientPos = glGetUniformLocation(shaderId, "ambient");
+ mLightLinearPos = glGetUniformLocation(shaderId, "lightLinear");
+ mLightAmbientPos = glGetUniformLocation(shaderId, "lightAmbient");
mObjectColorPos = glGetUniformLocation(shaderId, "objectColor");
+ mObjectColorAlphaPos = glGetUniformLocation(shaderId, "objectColorAlpha");
mTexSlotPos = glGetUniformLocation(shaderId, "texSlot");
+ mInvertedNormalsPos = glGetUniformLocation(shaderId, "invertedNormals");
+ mSsaoSamplesPos = glGetUniformLocation(shaderId, "ssaoSamples");
+ mAlbedoPos = glGetUniformLocation(shaderId, "texAlbedo");
+ mPositionPos = glGetUniformLocation(shaderId, "texPosition");
+ mNormalPos = glGetUniformLocation(shaderId, "texNormal");
+ mSsaoPos = glGetUniformLocation(shaderId, "texSsao");
+ mNoisePos = glGetUniformLocation(shaderId, "texNoise");
+ mSamplesPos = glGetUniformLocation(shaderId, "ssaoSamples");
+ mCurSegmentPos = glGetUniformLocation(shaderId, "curSegment");
+
Activate();
return shaderId;
}
@@ -156,118 +241,418 @@ void Shader::Activate()
CurrentShader = this;
}
-
-const char* VertShader3DNorm =
- "#version 330 core \n"
-
- "layout(location = 0) in vec3 aPosition; \n"
- "layout(location = 1) in vec3 aNormal; \n"
-
- "out vec3 Normal; \n"
- "out vec3 FragPos; \n"
-
- "uniform mat4 model; \n"
- "uniform mat4 view; \n"
- "uniform mat4 projection; \n"
- "uniform mat4 normalRot; \n"
-
- "void main(void) \n"
- "{ \n"
- " gl_Position = projection * view * model * vec4(aPosition, 1.0); \n"
- " FragPos = vec3(model * vec4(aPosition, 1.0)); \n"
- " Normal = vec3(normalRot * vec4(aNormal, 1.0)); \n"
- "} \n";
-
-const char* VertShader3DInvNorm =
- "#version 330 core \n"
-
- "layout(location = 0) in vec3 aPosition; \n"
- "layout(location = 1) in vec3 aNormal; \n"
-
- "out vec3 Normal; \n"
- "out vec3 FragPos; \n"
-
- "uniform mat4 model; \n"
- "uniform mat4 view; \n"
- "uniform mat4 projection; \n"
- "uniform mat4 normalRot; \n"
-
- "void main(void) \n"
- "{ \n"
- " gl_Position = projection * view * model * vec4(aPosition, 1.0); \n"
- " FragPos = vec3(model * vec4(aPosition, 1.0)); \n"
- " Normal = -vec3(normalRot * vec4(aNormal, 1.0)); \n"
- "} \n";
+void Shader::Destroy()
+{
+ if (shaderId == 0) {
+ return;
+ }
+ glDeleteProgram(shaderId);
+ shaderId = 0;
+}
-const char* VertShader2DTex =
- "#version 330 core \n" // -----> add long remark for a uniform auto formatting
+const char* VertShader3DNorm = R"(
+ #version 330 core
- "layout(location = 0) in vec2 aPosition; \n"
- "layout(location = 1) in vec2 aTexCoord; \n"
+ layout(location = 0) in vec3 aPosition;
+ layout(location = 1) in vec3 aNormal;
- "out vec2 texCoord; \n"
+ out vec3 Normal;
+ out vec3 FragPos;
- "uniform mat4 projection; \n"
- "uniform mat4 model; \n"
+ uniform mat4 model;
+ uniform mat4 view;
+ uniform mat4 projection;
+ uniform mat4 normalRot;
- "void main(void) \n"
- "{ \n"
- " gl_Position = projection * model * vec4(aPosition, 0.0, 1.0); \n"
- " texCoord = aTexCoord; \n"
- "} \n";
+ void main(void)
+ {
+ vec4 viewPos = view * model * vec4(aPosition, 1.0);
+ FragPos = vec3(model * vec4(aPosition, 1.0));
+ Normal = vec3(normalRot * vec4(aNormal, 1.0));
+ gl_Position = projection * viewPos;
+ }
+)";
-const char* FragShader2dTex =
- "#version 330\n" // -----> add long remark for a uniform auto formatting
+const char* VertShader3DInvNorm = R"(
+ #version 330 core
- "out vec4 FragColor; \n"
- "in vec2 texCoord; \n"
+ layout(location = 0) in vec3 aPosition;
+ layout(location = 1) in vec3 aNormal;
- "uniform vec3 objectColor; \n"
- "uniform sampler2D texSlot; \n"
+ out vec3 Normal;
+ out vec3 FragPos;
- "void main() \n"
- "{ \n"
- " vec4 texColor = texture(texSlot, texCoord); \n"
- " FragColor = vec4(objectColor, 1.0) * texColor; \n"
- "} \n";
+ uniform mat4 model;
+ uniform mat4 view;
+ uniform mat4 projection;
+ uniform mat4 normalRot;
+
+ void main(void)
+ {
+ gl_Position = projection * view * model * vec4(aPosition, 1.0);
+ FragPos = vec3(model * vec4(aPosition, 1.0));
+ Normal = -vec3(normalRot * vec4(aNormal, 1.0));
+ }
+)";
-const char* FragShaderNorm =
- "#version 330\n" // -----> add long remark for a uniform auto formatting
+const char* VertShader2DTex = R"(
+ #version 330 core
- "out vec4 FragColor; \n"
+ layout(location = 0) in vec2 aPosition;
+ layout(location = 1) in vec2 aTexCoord;
- "in vec3 Normal; \n"
- "in vec3 FragPos; \n"
+ out vec2 texCoord;
- "uniform vec3 lightPos; \n"
- "uniform vec3 lightColor; \n"
- "uniform vec3 objectColor; \n"
- "uniform vec3 ambient; \n"
+ uniform mat4 projection;
+ uniform mat4 model;
- "void main() \n"
- "{ \n"
- " vec3 norm = normalize(Normal); \n"
- " vec3 lightDir = normalize(lightPos - FragPos); \n"
- " float diff = max(dot(norm, lightDir), 0.0); \n"
- " vec3 diffuse = diff * lightColor; \n"
- " vec3 result = (ambient + diffuse) * objectColor; \n"
- " FragColor = vec4(result, 1.0); \n"
- "} \n";
+ void main(void)
+ {
+ gl_Position = projection * model * vec4(aPosition, 0.0, 1.0);
+ texCoord = aTexCoord;
+ }
+)";
-const char* FragShaderFlat =
- "#version 330\n" // -----> add long remark for a uniform auto formatting
+const char* FragShader2dTex = R"(
+ #version 330
- "out vec4 FragColor; \n"
+ out vec4 FragColor;
+ in vec2 texCoord;
- "in vec3 Normal; \n"
- "in vec3 FragPos; \n"
- "uniform vec3 objectColor; \n"
+ uniform vec3 objectColor;
+ uniform sampler2D texSlot;
- "void main() \n"
- "{ \n"
- " FragColor = vec4(objectColor, 1.0); \n"
- "} \n";
+ void main()
+ {
+ vec4 texColor = texture(texSlot, texCoord);
+ FragColor = vec4(objectColor, 1.0) * texColor;
+ }
+)";
+
+
+const char* FragShaderNorm = R"(
+ #version 330
+
+ out vec4 FragColor;
+
+ in vec3 Normal;
+ in vec3 FragPos;
+
+ uniform vec3 lightPos;
+ uniform vec3 lightColor;
+ uniform vec3 objectColor;
+ uniform vec3 lightAmbient;
+
+ void main()
+ {
+ vec3 norm = normalize(Normal);
+ vec3 lightDir = normalize(lightPos - FragPos);
+ float diff = max(dot(norm, lightDir), 0.0);
+ vec3 diffuse = diff * lightColor;
+ vec3 result = (lightAmbient + diffuse) * objectColor;
+ FragColor = vec4(result, 1.0);
+ }
+)";
+
+const char* FragShaderFlat = R"(
+ #version 330
+
+ out vec4 FragColor;
+
+ in vec3 Normal;
+ in vec3 FragPos;
+ uniform vec3 objectColor;
+
+ void main()
+ {
+ FragColor = vec4(objectColor, 1.0);
+ }
+)";
+
+
+ const char* VertShader2DFbo = R"(
+ #version 330 core
+
+ layout(location = 0) in vec2 aPosition;
+ layout(location = 1) in vec2 aTexCoord;
+
+ out vec2 texCoord;
+
+ void main(void)
+ {
+ gl_Position = vec4(aPosition.x, aPosition.y, 0.0, 1.0);
+ texCoord = aTexCoord;
+ }
+)";
+
+ const char* FragShader2dFbo = R"(
+ #version 330
+
+ out vec4 FragColor;
+ in vec2 texCoord;
+
+ uniform sampler2D texSlot;
+
+ void main()
+ {
+ vec4 tc = texture(texSlot, texCoord);
+ FragColor = tc;
+ }
+)";
+
+const char* VertShaderGeom = R"(
+ #version 330 core
+ layout (location = 0) in vec3 aPos;
+ layout (location = 1) in vec3 aNormal;
+
+ out vec3 FragPos;
+ out vec3 Normal;
+
+ uniform bool invertedNormals;
+
+ uniform mat4 model;
+ uniform mat4 view;
+ uniform mat4 projection;
+
+ void main()
+ {
+ vec4 viewPos = view * model * vec4(aPos, 1.0);
+ FragPos = viewPos.xyz;
+
+ mat3 normalMatrix = transpose(inverse(mat3(view * model)));
+ Normal = normalMatrix * (invertedNormals ? -aNormal : aNormal);
+
+ gl_Position = projection * viewPos;
+ }
+)";
+
+const char* FragShaderGeom = R"(
+ #version 330 core
+ layout (location = 0) out vec4 texAlbedo;
+ layout (location = 1) out vec3 texPosition;
+ layout (location = 2) out vec3 texNormal;
+
+ in vec3 FragPos;
+ in vec3 Normal;
+
+ uniform vec3 objectColor;
+
+ void main()
+ {
+ // store the fragment position vector in the first gbuffer texture
+ texPosition = FragPos;
+ // also store the per-fragment normals into the gbuffer
+ texNormal = normalize(Normal);
+ // and the diffuse per-fragment color
+ texAlbedo = vec4(objectColor, 1.0f);
+ }
+)";
+
+const char* FragShaderSSAO = R"(
+ #version 330 core
+ out vec4 FragColor;
+
+ in vec2 texCoord;
+
+ uniform sampler2D texNoise;
+ uniform sampler2D texPosition;
+ uniform sampler2D texNormal;
+
+ uniform vec3 ssaoSamples[64];
+
+ // parameters (you'd probably want to use them as uniforms to more easily tweak the effect)
+ int kernelSize = 64;
+ float radius = 2.5f;
+ float bias = 0.025;
+
+ // tile noise texture over screen based on screen dimensions divided by noise size
+ const vec2 noiseScale = vec2(800.0/4.0, 600.0/4.0);
+
+ uniform mat4 projection;
+
+ void main()
+ {
+ // get input for SSAO algorithm
+ vec3 fragPos = texture(texPosition, texCoord).xyz;
+ vec3 normal = normalize(texture(texNormal, texCoord).rgb);
+ vec3 randomVec = normalize(texture(texNoise, texCoord * noiseScale).xyz);
+ // create TBN change-of-basis matrix: from tangent-space to view-space
+ vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
+ vec3 bitangent = cross(normal, tangent);
+ mat3 TBN = mat3(tangent, bitangent, normal);
+ // iterate over the sample kernel and calculate occlusion factor
+ float occlusion = 0.0;
+ for(int i = 0; i < kernelSize; ++i)
+ {
+ // get sample position
+ vec3 samplePos = TBN * ssaoSamples[i]; // from tangent to view-space
+ samplePos = fragPos + samplePos * radius;
+
+ // project sample position (to sample texture) (to get position on screen/texture)
+ vec4 offset = vec4(samplePos, 1.0);
+ offset = projection * offset; // from view to clip-space
+ offset.xyz /= offset.w; // perspective divide
+ offset.xyz = offset.xyz * 0.5 + 0.5; // transform to range 0.0 - 1.0
+
+ // get sample depth
+ float sampleDepth = texture(texPosition, offset.xy).z; // get depth value of kernel
+ // sample
+
+ // range check & accumulate
+ float rangeCheck = smoothstep(0.0, 1.0, radius * 0.1f / abs(sampleDepth - fragPos.z));
+ occlusion += (sampleDepth >= samplePos.z + bias ? 1.0 : 0.0) * rangeCheck;
+ }
+ occlusion = 1.0 - (occlusion / kernelSize);
+ FragColor = vec4(pow(occlusion, 2), 0, 0, 1);
+ }
+)";
+
+const char* FragShaderSSAOLighting = R"(
+ #version 330 core
+ out vec4 FragColor;
+
+ in vec2 texCoord;
+
+ uniform sampler2D texSsao;
+ uniform sampler2D texAlbedo;
+ uniform sampler2D texPosition;
+ uniform sampler2D texNormal;
+
+ uniform vec3 lightPos;
+ uniform vec3 lightColor;
+ uniform vec3 lightAmbient;
+
+ uniform float lightLinear;
+
+ void main()
+ {
+ // retrieve data from gbuffer
+ vec4 DiffuseA = texture(texAlbedo, texCoord);
+ vec3 Diffuse = DiffuseA.rgb;
+ vec3 FragPos = texture(texPosition, texCoord).rgb;
+ vec3 Normal = texture(texNormal, texCoord).rgb;
+ float AmbientOcclusion = texture(texSsao, texCoord).r;
+
+ // then calculate lighting as usual
+ vec3 lighting = lightAmbient * Diffuse * AmbientOcclusion;
+ vec3 viewDir = normalize(-FragPos); // viewpos is (0.0.0)
+ // diffuse
+ vec3 lightDir = normalize(lightPos - FragPos);
+ vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * lightColor;
+ // specular
+ vec3 halfwayDir = normalize(lightDir + viewDir);
+ float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0);
+ vec3 specular = lightColor * spec;
+ // attenuation
+ float distance = length(lightPos - FragPos);
+ float attenuation = 1.0 / (1.0 + lightLinear * distance);
+ lighting += (diffuse + specular * 0.3) * attenuation;
+
+ FragColor = vec4(lighting, DiffuseA.a);
+ }
+)";
+
+const char* FragShaderStdLighting = R"(
+ #version 330 core
+ out vec4 FragColor;
+
+ in vec2 texCoord;
+
+ uniform sampler2D texAlbedo;
+ uniform sampler2D texPosition;
+ uniform sampler2D texNormal;
+
+ uniform vec3 lightPos;
+ uniform vec3 lightColor;
+ uniform float lightLinear;
+ uniform vec3 lightAmbient;
+
+ void main()
+ {
+ // retrieve data from gbuffer
+ vec4 DiffuseA = texture(texAlbedo, texCoord);
+ vec3 Diffuse = DiffuseA.rgb;
+ vec3 FragPos = texture(texPosition, texCoord).rgb;
+ vec3 Normal = texture(texNormal, texCoord).rgb;
+
+ // then calculate lighting as usual
+ vec3 lighting = lightAmbient * Diffuse;
+ vec3 viewDir = normalize(-FragPos); // viewpos is (0.0.0)
+ // diffuse
+ vec3 lightDir = normalize(lightPos - FragPos);
+ vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * lightColor;
+ // specular
+ vec3 halfwayDir = normalize(lightDir + viewDir);
+ float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0);
+ vec3 specular = lightColor * spec;
+ // attenuation
+ float distance = length(lightPos - FragPos);
+ float attenuation = 1.0 / (1.0 + lightLinear * distance);
+ lighting += (diffuse + specular * 0.3) * attenuation;
+
+ FragColor = vec4(lighting, DiffuseA.a);
+ }
+)";
+
+const char* FragShaderSSAOBlur = R"(
+ #version 330 core
+ out vec4 FragColor;
+
+ in vec2 texCoord;
+
+ uniform sampler2D texSsao;
+
+ void main()
+ {
+ vec2 texelSize = 1.0 / vec2(textureSize(texSsao, 0));
+ float result = 0.0;
+ for (int x = -2; x <= 1; ++x)
+ {
+ for (int y = -2; y <= 1; ++y)
+ {
+ vec2 offset = vec2(float(x), float(y)) * texelSize;
+ result += texture(texSsao, texCoord + offset).r;
+ }
+ }
+ FragColor = vec4(result / (4.0 * 4.0), 0, 0, 1);
+ }
+)";
+
+
+const char* VertShader3DLine = R"(
+ #version 330 core
+
+ layout(location = 0) in vec3 aPosition;
+ layout(location = 1) in int aIndex;
+ flat out int Index;
+
+ uniform mat4 view;
+ uniform mat4 projection;
+
+ void main(void)
+ {
+ gl_Position = projection * view * vec4(aPosition, 1.0);
+ Index = aIndex;
+ }
+)";
+
+const char* FragShader3DLine = R"(
+ #version 330
+
+ out vec4 FragColor;
+
+ flat in int Index;
+ uniform vec4 objectColorAlpha;
+ uniform vec3 objectColor;
+ uniform int curSegment;
+
+ void main()
+ {
+ if (Index > curSegment) FragColor = objectColorAlpha;
+ else FragColor = vec4(objectColor, objectColorAlpha.a);
+ }
+)";
} // namespace MillSim
diff --git a/src/Mod/CAM/PathSimulator/AppGL/Shader.h b/src/Mod/CAM/PathSimulator/AppGL/Shader.h
index 3b11ec3a5c..c808ee9dc1 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/Shader.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/Shader.h
@@ -33,17 +33,28 @@ class Shader
public:
Shader()
{}
+ ~Shader();
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);
+ void UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient, float linearity);
void UpdateObjColor(vec3 objColor);
+ void UpdateObjColorAlpha(vec4 objColor);
+ void UpdateNormalState(bool isInverted);
void UpdateTextureSlot(int slot);
- unsigned int CompileShader(char* vertShader, char* fragShader);
+ void UpdateAlbedoTexSlot(int albedoSlot);
+ void UpdatePositionTexSlot(int positionSlot);
+ void UpdateNormalTexSlot(int normalSlot);
+ void UpdateNoiseTexSlot(int noiseSlot);
+ void UpdateSsaoTexSlot(int ssaoSlot);
+ void UpdateKernelVals(int nVals, float *vals);
+ void UpdateCurSegment(int curSeg);
+ unsigned int CompileShader(const char* vertShader, const char* fragShader);
void Activate();
+ void Destroy();
bool IsValid()
{
return shaderId > 0;
@@ -57,9 +68,20 @@ protected:
int mViewPos = -1;
int mLightPosPos = -1;
int mLightColorPos = -1;
- int mAmbientPos = -1;
+ int mLightLinearPos = -1;
+ int mLightAmbientPos = -1;
int mObjectColorPos = -1;
+ int mObjectColorAlphaPos = -1;
int mTexSlotPos = -1;
+ int mInvertedNormalsPos = -1;
+ int mSsaoSamplesPos = -1;
+ int mAlbedoPos = -1;
+ int mPositionPos = -1;
+ int mNormalPos = -1;
+ int mSsaoPos = -1;
+ int mNoisePos = -1;
+ int mSamplesPos = -1;
+ int mCurSegmentPos = -1;
const char* vertShader = nullptr;
const char* fragShader = nullptr;
@@ -73,5 +95,17 @@ extern const char* VertShader3DNorm;
extern const char* VertShader3DInvNorm;
extern const char* VertShader2DTex;
extern const char* FragShader2dTex;
+extern const char* VertShader2DFbo;
+extern const char* FragShader2dFbo;
+extern const char* VertShaderGeom;
+extern const char* FragShaderGeom;
+extern const char* FragShaderSSAO;
+extern const char* FragShaderSSAOLighting;
+extern const char* FragShaderStdLighting;
+extern const char* FragShaderSSAOBlur;
+extern const char* VertShader3DLine;
+extern const char* FragShader3DLine;
+
+
} // namespace MillSim
#endif // !__shader_h__
diff --git a/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.cpp b/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.cpp
new file mode 100644
index 0000000000..6940650032
--- /dev/null
+++ b/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.cpp
@@ -0,0 +1,556 @@
+/***************************************************************************
+ * Copyright (c) 2024 Shai Seger *
+ * *
+ * 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 "SimDisplay.h"
+#include "linmath.h"
+#include "OpenGlWrapper.h"
+#include
+
+#define GL_UBYTE GL_UNSIGNED_BYTE
+
+
+namespace MillSim
+{
+
+void SimDisplay::InitShaders()
+{
+ // use shaders
+ // standard diffuse shader
+ shader3D.CompileShader(VertShader3DNorm, FragShaderNorm);
+ shader3D.UpdateEnvColor(lightPos, lightColor, ambientCol, 0.0f);
+
+ // invarted normal diffuse shader for inner mesh
+ shaderInv3D.CompileShader(VertShader3DInvNorm, FragShaderNorm);
+ shaderInv3D.UpdateEnvColor(lightPos, lightColor, ambientCol, 0.0f);
+
+ // null shader to calculate meshes only (simulation stage)
+ shaderFlat.CompileShader(VertShader3DNorm, FragShaderFlat);
+
+ // texture shader to render Simulator FBO
+ shaderSimFbo.CompileShader(VertShader2DFbo, FragShader2dFbo);
+ shaderSimFbo.UpdateTextureSlot(0);
+
+ // geometric shader - generate texture with all geometric info for further processing
+ shaderGeom.CompileShader(VertShaderGeom, FragShaderGeom);
+ shaderGeomCloser.CompileShader(VertShaderGeom, FragShaderGeom);
+
+ // lighting shader - apply standard lighting based on geometric buffers
+ shaderLighting.CompileShader(VertShader2DFbo, FragShaderStdLighting);
+ shaderLighting.UpdateAlbedoTexSlot(0);
+ shaderLighting.UpdatePositionTexSlot(1);
+ shaderLighting.UpdateNormalTexSlot(2);
+ shaderLighting.UpdateEnvColor(lightPos, lightColor, ambientCol, 0.01f);
+
+ // SSAO shader - generate SSAO info and embed in texture buffer
+ shaderSSAO.CompileShader(VertShader2DFbo, FragShaderSSAO);
+ shaderSSAO.UpdateNoiseTexSlot(0);
+ shaderSSAO.UpdatePositionTexSlot(1);
+ shaderSSAO.UpdateNormalTexSlot(2);
+
+ // SSAO blur shader - smooth generated SSAO texture
+ shaderSSAOBlur.CompileShader(VertShader2DFbo, FragShaderSSAOBlur);
+ shaderSSAOBlur.UpdateSsaoTexSlot(0);
+
+ // SSAO lighting shader - apply lightig modified by SSAO calculations
+ shaderSSAOLighting.CompileShader(VertShader2DFbo, FragShaderSSAOLighting);
+ shaderSSAOLighting.UpdateAlbedoTexSlot(0);
+ shaderSSAOLighting.UpdatePositionTexSlot(1);
+ shaderSSAOLighting.UpdateNormalTexSlot(2);
+ shaderSSAOLighting.UpdateSsaoTexSlot(3);
+ shaderSSAOLighting.UpdateEnvColor(lightPos, lightColor, ambientCol, 0.01f);
+
+ // Mill Path Line Shader
+ shaderLinePath.CompileShader(VertShader3DLine, FragShader3DLine);
+
+}
+
+void SimDisplay::CreateFboQuad()
+{
+ float quadVertices[] = {// a quad that fills the entire screen in Normalized Device Coordinates.
+ // positions // texCoords
+ -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f};
+
+ glGenVertexArrays(1, &mFboQuadVAO);
+ glGenBuffers(1, &mFboQuadVBO);
+ glBindVertexArray(mFboQuadVAO);
+ glBindBuffer(GL_ARRAY_BUFFER, mFboQuadVBO);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices[0], GL_STATIC_DRAW);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
+}
+
+void SimDisplay::CreateDisplayFbos()
+{
+ // setup frame buffer for simulation
+ glGenFramebuffers(1, &mFbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+
+ // a color texture for the frame buffer
+ glGenTextures(1, &mFboColTexture);
+ glBindTexture(GL_TEXTURE_2D, mFboColTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, gWindowSizeW, gWindowSizeH, 0, GL_RGBA, GL_UBYTE, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFboColTexture, 0);
+
+ // a position texture for the frame buffer
+ glGenTextures(1, &mFboPosTexture);
+ glBindTexture(GL_TEXTURE_2D, mFboPosTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, gWindowSizeW, gWindowSizeH, 0, GL_RGBA, GL_FLOAT, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mFboPosTexture, 0);
+
+ // a normal texture for the frame buffer
+ glGenTextures(1, &mFboNormTexture);
+ glBindTexture(GL_TEXTURE_2D, mFboNormTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, gWindowSizeW, gWindowSizeH, 0, GL_RGBA, GL_FLOAT, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, mFboNormTexture, 0);
+
+
+ unsigned int attachments[3] = {GL_COLOR_ATTACHMENT0,
+ GL_COLOR_ATTACHMENT1,
+ GL_COLOR_ATTACHMENT2};
+ glDrawBuffers(3, attachments);
+
+ glGenRenderbuffers(1, &mRboDepthStencil);
+ glBindRenderbuffer(GL_RENDERBUFFER, mRboDepthStencil);
+ glRenderbufferStorage(
+ GL_RENDERBUFFER,
+ GL_DEPTH24_STENCIL8,
+ gWindowSizeW,
+ gWindowSizeH); // use a single renderbuffer object for both a depth AND stencil buffer.
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+ GL_DEPTH_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER,
+ mRboDepthStencil); // now actually attach it
+
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ return;
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+
+void SimDisplay::CreateSsaoFbos()
+{
+
+ mSsaoValid = true;
+
+ // setup framebuffer for SSAO processing
+ glGenFramebuffers(1, &mSsaoFbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, mSsaoFbo);
+ // SSAO color buffer
+ glGenTextures(1, &mFboSsaoTexture);
+ glBindTexture(GL_TEXTURE_2D, mFboSsaoTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, gWindowSizeW, gWindowSizeH, 0, GL_RED, GL_FLOAT, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFboSsaoTexture, 0);
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ mSsaoValid = false;
+ return;
+ }
+
+ // setup framebuffer for SSAO blur processing
+ glGenFramebuffers(1, &mSsaoBlurFbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, mSsaoBlurFbo);
+ glGenTextures(1, &mFboSsaoBlurTexture);
+ glBindTexture(GL_TEXTURE_2D, mFboSsaoBlurTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, gWindowSizeW, gWindowSizeH, 0, GL_RED, GL_FLOAT, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ mFboSsaoBlurTexture,
+ 0);
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ mSsaoValid = false;
+ return;
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // generate sample kernel
+ std::uniform_real_distribution randomFloats(0.0, 1.0);
+ std::default_random_engine generator;
+ for (unsigned int i = 0; i < 64; ++i) {
+ vec3 sample;
+ vec3_set(sample,
+ randomFloats(generator) * 2.0f - 1.0f,
+ randomFloats(generator) * 2.0f - 1.0f,
+ randomFloats(generator));// * 2.0f - 1.0f);
+ vec3_norm(sample, sample);
+ vec3_scale(sample, sample, randomFloats(generator));
+ float scale = float(i) / 64.0f;
+
+ // scale samples s.t. they're more aligned to center of kernel
+ scale = Lerp(0.1f, 1.0f, scale * scale);
+ vec3_scale(sample, sample, scale);
+ mSsaoKernel.push_back(*(Point3D*)sample);
+ }
+ shaderSSAO.Activate();
+ shaderSSAO.UpdateKernelVals(mSsaoKernel.size(), &mSsaoKernel[0].x);
+
+ // generate noise texture
+ std::vector ssaoNoise;
+ for (unsigned int i = 0; i < 16; i++) {
+ vec3 noise;
+ vec3_set(noise,
+ randomFloats(generator) * 2.0f - 1.0f,
+ randomFloats(generator) * 2.0f - 1.0f,
+ 0.0f); // rotate around z-axis (in tangent space)
+ ssaoNoise.push_back(*(Point3D*)noise);
+ }
+ glGenTextures(1, &mFboSsaoNoiseTexture);
+ glBindTexture(GL_TEXTURE_2D, mFboSsaoNoiseTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 4, 4, 0, GL_RGB, GL_FLOAT, &ssaoNoise[0]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+}
+
+
+SimDisplay::~SimDisplay()
+{
+ CleanGL();
+}
+
+void SimDisplay::InitGL()
+{
+ if (displayInitiated) {
+ return;
+ }
+
+ // setup light object
+ mlightObject.GenerateBoxStock(-0.5f, -0.5f, -0.5f, 1, 1, 1);
+
+ InitShaders();
+ CreateDisplayFbos();
+ CreateSsaoFbos();
+ CreateFboQuad();
+
+ UpdateProjection();
+ displayInitiated = true;
+}
+
+void SimDisplay::CleanFbos()
+{
+ // cleanup frame buffers
+ GLDELETE_FRAMEBUFFER(mFbo);
+ GLDELETE_FRAMEBUFFER(mSsaoFbo);
+ GLDELETE_FRAMEBUFFER(mSsaoBlurFbo);
+
+ // cleanup fbo textures
+ GLDELETE_TEXTURE(mFboColTexture);
+ GLDELETE_TEXTURE(mFboPosTexture);
+ GLDELETE_TEXTURE(mFboNormTexture);
+ GLDELETE_TEXTURE(mFboSsaoTexture);
+ GLDELETE_TEXTURE(mFboSsaoBlurTexture);
+ GLDELETE_TEXTURE(mFboSsaoNoiseTexture);
+ GLDELETE_RENDERBUFFER(mRboDepthStencil);
+}
+
+void SimDisplay::CleanGL()
+{
+ CleanFbos();
+
+ // cleanup geometry
+ GLDELETE_VERTEXARRAY(mFboQuadVAO);
+ GLDELETE_BUFFER(mFboQuadVBO);
+
+ // cleanup shaders
+ shader3D.Destroy();
+ shaderInv3D.Destroy();
+ shaderFlat.Destroy();
+ shaderSimFbo.Destroy();
+ shaderGeom.Destroy();
+ shaderSSAO.Destroy();
+ shaderLighting.Destroy();
+ shaderSSAOLighting.Destroy();
+ shaderSSAOBlur.Destroy();
+
+ displayInitiated = false;
+}
+
+void SimDisplay::PrepareDisplay(vec3 objCenter)
+{
+ mat4x4_look_at(mMatLookAt, eye, target, upvec);
+ mat4x4_translate_in_place(mMatLookAt, mEyeX * mEyeXZFactor, 0, mEyeZ * mEyeXZFactor);
+ mat4x4_rotate_X(mMatLookAt, mMatLookAt, mEyeInclination);
+ mat4x4_rotate_Z(mMatLookAt, mMatLookAt, mEyeRoration);
+ mat4x4_translate_in_place(mMatLookAt, -objCenter[0], -objCenter[1], -objCenter[2]);
+}
+
+void SimDisplay::PrepareFrameBuffer()
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+}
+
+void SimDisplay::StartDepthPass()
+{
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glDepthMask(GL_TRUE);
+ shaderFlat.Activate();
+ shaderFlat.UpdateViewMat(mMatLookAt);
+}
+
+void SimDisplay::StartGeometryPass(vec3 objColor, bool invertNormals)
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+ shaderGeom.Activate();
+ shaderGeom.UpdateNormalState(invertNormals);
+ shaderGeom.UpdateViewMat(mMatLookAt);
+ shaderGeom.UpdateObjColor(objColor);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+}
+
+// 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)
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+ shaderGeomCloser.Activate();
+ shaderGeomCloser.UpdateNormalState(false);
+ shaderGeomCloser.UpdateViewMat(mMatLookAt);
+ shaderGeomCloser.UpdateObjColor(objColor);
+ glEnable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+}
+
+void SimDisplay::RenderLightObject()
+{
+ shaderFlat.Activate();
+ shaderFlat.UpdateObjColor(lightColor);
+ mlightObject.render();
+}
+
+void SimDisplay::ScaleViewToStock(StockObject* obj)
+{
+ mMaxStockDim = fmaxf(obj->size[0], obj->size[1]);
+ maxFar = mMaxStockDim * 4;
+ UpdateProjection();
+ vec3_set(eye, 0, 0, 0);
+ UpdateEyeFactor(0.4f);
+ vec3_set(lightPos, obj->position[0], obj->position[1], obj->position[2] + mMaxStockDim / 3);
+ mlightObject.SetPosition(lightPos);
+}
+
+void SimDisplay::RenderResult()
+{
+ if (mSsaoValid && applySSAO) {
+ RenderResultSSAO();
+ }
+ else {
+ RenderResultStandard();
+ }
+}
+
+void SimDisplay::RenderResultStandard()
+{
+ // set default frame buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // display the sim result within the FBO
+ shaderLighting.Activate();
+ // shaderSimFbo.Activate();
+ glBindVertexArray(mFboQuadVAO);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mFboColTexture);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, mFboPosTexture);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, mFboNormTexture);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+}
+
+void SimDisplay::RenderResultSSAO()
+{
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ // generate SSAO texture
+ glBindFramebuffer(GL_FRAMEBUFFER, mSsaoFbo);
+ shaderSSAO.Activate();
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mFboSsaoNoiseTexture);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, mFboPosTexture);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, mFboNormTexture);
+ glBindVertexArray(mFboQuadVAO);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // blur SSAO texture to remove noise
+ glBindFramebuffer(GL_FRAMEBUFFER, mSsaoBlurFbo);
+ glClear(GL_COLOR_BUFFER_BIT);
+ shaderSSAOBlur.Activate();
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mFboSsaoTexture);
+ glBindVertexArray(mFboQuadVAO);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // lighting pass: deferred Blinn-Phong lighting with added screen-space ambient occlusion
+ shaderSSAOLighting.Activate();
+ shaderSSAOLighting.UpdateAlbedoTexSlot(0);
+ shaderSSAOLighting.UpdatePositionTexSlot(1);
+ shaderSSAOLighting.UpdateNormalTexSlot(2);
+ shaderSSAOLighting.UpdateSsaoTexSlot(3);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mFboColTexture);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, mFboPosTexture);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, mFboNormTexture);
+ glActiveTexture(GL_TEXTURE3); // add extra SSAO texture to lighting pass
+ glBindTexture(GL_TEXTURE_2D, mFboSsaoBlurTexture);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindVertexArray(mFboQuadVAO);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+}
+
+void SimDisplay::SetupLinePathPass(int curSegment, bool isHidden)
+{
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ glDepthFunc(isHidden ? GL_GREATER : GL_LESS);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glLineWidth(2);
+ shaderLinePath.Activate();
+ pathLineColor[3] = isHidden ? 0.1f : 1.0f;
+ shaderLinePath.UpdateObjColorAlpha(pathLineColor);
+ shaderLinePath.UpdateCurSegment(curSegment);
+ shaderLinePath.UpdateViewMat(mMatLookAt);
+}
+
+void SimDisplay::TiltEye(float tiltStep)
+{
+ mEyeInclination += tiltStep;
+ if (mEyeInclination > PI / 2) {
+ mEyeInclination = PI / 2;
+ }
+ else if (mEyeInclination < -PI / 2) {
+ mEyeInclination = -PI / 2;
+ }
+}
+
+void SimDisplay::RotateEye(float rotStep)
+{
+ mEyeRoration += rotStep;
+ if (mEyeRoration > PI2) {
+ mEyeRoration -= PI2;
+ }
+ else if (mEyeRoration < 0) {
+ mEyeRoration += PI2;
+ }
+ updateDisplay = true;
+}
+
+void SimDisplay::MoveEye(float x, float z)
+{
+ mEyeX += x;
+ if (mEyeX > 100) {
+ mEyeX = 100;
+ }
+ else if (mEyeX < -100) {
+ mEyeX = -100;
+ }
+ mEyeZ += z;
+ if (mEyeZ > 100) {
+ mEyeZ = 100;
+ }
+ else if (mEyeZ < -100) {
+ mEyeZ = -100;
+ }
+ updateDisplay = true;
+}
+
+void SimDisplay::UpdateEyeFactor(float factor)
+{
+ if (mEyeDistFactor == factor) {
+ return;
+ }
+ updateDisplay = true;
+ mEyeDistFactor = factor;
+ mEyeXZFactor = factor * maxFar * 0.005f;
+ eye[1] = -factor * maxFar;
+}
+
+void SimDisplay::UpdateWindowScale()
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+ CleanFbos();
+ CreateDisplayFbos();
+ CreateSsaoFbos();
+ UpdateProjection();
+}
+
+void SimDisplay::UpdateProjection()
+{
+ // Setup projection
+ mat4x4 projmat;
+ mat4x4_perspective(projmat, 0.7f, (float)gWindowSizeW / gWindowSizeH, 1.0f, maxFar);
+ shader3D.Activate();
+ shader3D.UpdateProjectionMat(projmat);
+ shaderInv3D.Activate();
+ shaderInv3D.UpdateProjectionMat(projmat);
+ shaderFlat.Activate();
+ shaderFlat.UpdateProjectionMat(projmat);
+ shaderGeom.Activate();
+ shaderGeom.UpdateProjectionMat(projmat);
+ shaderSSAO.Activate();
+ shaderSSAO.UpdateProjectionMat(projmat);
+ shaderLinePath.Activate();
+ shaderLinePath.UpdateProjectionMat(projmat);
+ shaderLinePath.UpdateObjColor(pathLineColorPassed);
+
+ projmat[2][2] *= 0.99999;
+ shaderGeomCloser.Activate();
+ shaderGeomCloser.UpdateProjectionMat(projmat);
+}
+
+
+} // namespace MillSim
diff --git a/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.h b/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.h
new file mode 100644
index 0000000000..ecf1e7c22c
--- /dev/null
+++ b/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.h
@@ -0,0 +1,138 @@
+/***************************************************************************
+ * Copyright (c) 2024 Shai Seger *
+ * *
+ * 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 __simdisplay_h__
+#define __simdisplay_h__
+
+#include "GlUtils.h"
+#include "Shader.h"
+#include "StockObject.h"
+#include "MillPathLine.h"
+#include
+
+
+namespace MillSim
+{
+
+struct Point3D
+{
+ float x, y, z;
+};
+
+class SimDisplay
+{
+public:
+ ~SimDisplay();
+ void InitGL();
+ void CleanGL();
+ void CleanFbos();
+ void PrepareDisplay(vec3 objCenter);
+ void PrepareFrameBuffer();
+ void StartDepthPass();
+ void StartGeometryPass(vec3 objColor, bool invertNormals);
+ void StartCloserGeometryPass(vec3 objColor);
+ void RenderLightObject();
+ void ScaleViewToStock(StockObject* obj);
+ void RenderResult();
+ void RenderResultStandard();
+ void RenderResultSSAO();
+ void SetupLinePathPass(int curSegment, bool isHidden);
+ void TiltEye(float tiltStep);
+ void RotateEye(float rotStep);
+ void MoveEye(float x, float z);
+ void UpdateEyeFactor(float factor);
+ void UpdateWindowScale();
+
+ void UpdateProjection();
+ float GetEyeFactor()
+ {
+ return mEyeDistFactor;
+ }
+
+public:
+ bool applySSAO = false;
+ bool updateDisplay = false;
+ float maxFar = 100;
+ bool displayInitiated = false;
+
+protected:
+ void InitShaders();
+ void CreateDisplayFbos();
+ void CreateSsaoFbos();
+ void CreateFboQuad();
+ float Lerp(float a, float b, float f)
+ {
+ return a + f * (b - a);
+ }
+
+protected:
+ // shaders
+ Shader shader3D, shaderInv3D, shaderFlat, shaderSimFbo;
+ Shader shaderGeom, shaderSSAO, shaderLighting, shaderSSAOLighting, shaderSSAOBlur;
+ Shader shaderGeomCloser;
+ Shader shaderLinePath;
+ vec3 lightColor = {0.8f, 0.9f, 1.0f};
+ vec3 lightPos = {20.0f, 20.0f, 10.0f};
+ vec3 ambientCol = {0.6f, 0.6f, 0.7f};
+ vec4 pathLineColor = {0.0f, 0.9f, 0.0f, 1.0};
+ vec3 pathLineColorPassed = {0.9f, 0.3f, 0.3f};
+
+ vec3 eye = {0, 100, 40};
+ vec3 target = {0, 0, -10};
+ vec3 upvec = {0, 0, 1};
+
+ mat4x4 mMatLookAt;
+ StockObject mlightObject;
+
+
+ float mEyeDistance = 30;
+ float mEyeRoration = 0;
+ float mEyeInclination = PI / 6; // 30 degree
+ float mEyeStep = PI / 36; // 5 degree
+
+ float mMaxStockDim = 100;
+ float mEyeDistFactor = 0.0f;
+ float mEyeXZFactor = 0.01f;
+ float mEyeXZScale = 0;
+ float mEyeX = 0.0f;
+ 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;
+
+ // ssao frame buffers
+ bool mSsaoValid = false;
+ std::vector mSsaoKernel;
+ unsigned int mSsaoFbo;
+ unsigned int mSsaoBlurFbo;
+ unsigned int mFboSsaoTexture;
+ unsigned int mFboSsaoBlurTexture;
+ unsigned int mFboSsaoNoiseTexture;
+};
+
+} // namespace MillSim
+#endif // !__simdisplay_h__
diff --git a/src/Mod/CAM/PathSimulator/AppGL/SimShapes.cpp b/src/Mod/CAM/PathSimulator/AppGL/SimShapes.cpp
index de60e2e207..f151aa10f1 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/SimShapes.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/SimShapes.cpp
@@ -24,49 +24,39 @@
#include "Shader.h"
#include "GlUtils.h"
#include
-#include
-#include
#include
+#include
using namespace MillSim;
-static float* sinTable = nullptr;
-static float* cosTable = nullptr;
-static int lastNumSlices = 0;
+int Shape::lastNumSlices = 0;
+std::vector Shape::sinTable;
+std::vector Shape::cosTable;
-static bool GenerateSinTable(int nSlices)
+void Shape::GenerateSinTable(int nSlices)
{
- if (nSlices == lastNumSlices)
- return true;
- if (sinTable != nullptr)
- free(sinTable);
- if (cosTable != nullptr)
- free(cosTable);
- sinTable = cosTable = nullptr;
+ if (nSlices == lastNumSlices) {
+ return;
+ }
float slice = (float)(2 * PI / nSlices);
int nvals = nSlices + 1;
- sinTable = (float*)malloc(nvals * sizeof(float));
- if (sinTable == nullptr)
- return false;
- cosTable = (float*)malloc(nvals * sizeof(float));
- if (cosTable == nullptr)
- {
- free(sinTable);
- sinTable = nullptr;
- return false;
- }
- for (int i = 0; i < nvals; i++)
- {
+ sinTable.resize(nvals);
+ cosTable.resize(nvals);
+ for (int i = 0; i < nvals; i++) {
sinTable[i] = sinf(slice * i);
cosTable[i] = cosf(slice * i);
}
lastNumSlices = nvals;
- return true;
}
-void MillSim::Shape::RotateProfile(float* profPoints, int nPoints, float distance, int nSlices, bool isHalfTurn)
+void Shape::RotateProfile(float* profPoints,
+ int nPoints,
+ float distance,
+ float /* deltaHeight */,
+ int nSlices,
+ bool isHalfTurn)
{
int vidx = 0;
int iidx = 0;
@@ -76,27 +66,15 @@ void MillSim::Shape::RotateProfile(float* profPoints, int nPoints, float distanc
numVerts = nPoints * 2 * (nSlices + 1);
numIndices = (nPoints - 1) * nSlices * 6;
- float* vbuffer = (float*)malloc(numVerts * sizeof(Vertex));
- if (vbuffer == nullptr)
- return;
- GLushort* ibuffer = (GLushort*)malloc(numIndices * sizeof(GLushort));
- if (ibuffer == nullptr)
- {
- free(vbuffer);
- return;
- }
+ std::vector vbuffer(numVerts);
+ std::vector ibuffer(numIndices);
int nsinvals = nSlices;
- if (isHalfTurn)
+ if (isHalfTurn) {
nsinvals *= 2;
- if (GenerateSinTable(nsinvals) == false)
- {
- free(vbuffer);
- free(ibuffer);
- return;
}
+ GenerateSinTable(nsinvals);
- for (int i = 0; i < nPoints; i++)
- {
+ for (int i = 0; i < nPoints; i++) {
int i2 = i * 2;
float prevy = i > 0 ? profPoints[i2 - 2] : 0;
@@ -110,8 +88,7 @@ void MillSim::Shape::RotateProfile(float* profPoints, int nPoints, float distanc
float nz = diffy / len;
vstart = i * 2 * (nSlices + 1);
- for (int j = 0; j <= nSlices; j++)
- {
+ for (int j = 0; j <= nSlices; j++) {
// generate vertices
float sx = sinTable[j];
float sy = cosTable[j];
@@ -125,69 +102,77 @@ void MillSim::Shape::RotateProfile(float* profPoints, int nPoints, float distanc
float nx = ny * sx;
ny *= sy;
- SET_TRIPLE(vbuffer, vidx, x1, y1, prevz);
- SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
- SET_TRIPLE(vbuffer, vidx, x2, y2, z2);
- SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
+ vbuffer[vidx++] = {x1, y1, prevz, nx, ny, nz };
+ vbuffer[vidx++] = {x2, y2, z2, nx, ny, nz};
- if (j != nSlices)
- {
+ if (j != nSlices) {
// generate indices { 0, 3, 1, 0, 2, 3 }
int pos = vstart + 2 * j;
- if (i < (nPoints - 1))
+ if (i < (nPoints - 1)) {
SET_TRIPLE(ibuffer, iidx, pos, pos + 3, pos + 1);
- if (i > 0)
+ }
+ if (i > 0) {
SET_TRIPLE(ibuffer, iidx, pos, pos + 2, pos + 3);
+ }
}
}
}
- GenerateModel(vbuffer, ibuffer, numVerts, numIndices);
-
- free(vbuffer);
- free(ibuffer);
+ SetModelData(vbuffer, ibuffer);
}
-void MillSim::Shape::CalculateExtrudeBufferSizes(int nProfilePoints, bool capStart, bool capEnd,
- int* numVerts, int* numIndices, int* vc1idx, int* vc2idx, int* ic1idx, int* ic2idx)
+void Shape::CalculateExtrudeBufferSizes(int nProfilePoints,
+ bool capStart,
+ bool capEnd,
+ int* numVerts,
+ int* numIndices,
+ int* vc1idx,
+ int* vc2idx,
+ int* ic1idx,
+ int* ic2idx)
{
- *numVerts = nProfilePoints * 4; // one face per profile point times 4 vertex per face
- *numIndices = nProfilePoints * 2 * 3; // 2 triangles per face times 3 indices per triangle
- if (capStart)
- {
- *vc1idx = *numVerts * 6;
+ *numVerts = nProfilePoints * 4; // one face per profile point times 4 vertex per face
+ *numIndices = nProfilePoints * 2 * 3; // 2 triangles per face times 3 indices per triangle
+ if (capStart) {
+ *vc1idx = *numVerts;
*numVerts += nProfilePoints;
*ic1idx = *numIndices;
*numIndices += (nProfilePoints - 2) * 3;
}
- if (capEnd)
- {
- *vc2idx = *numVerts * 6;
+ if (capEnd) {
+ *vc2idx = *numVerts;
*numVerts += nProfilePoints;
*ic2idx = *numIndices;
*numIndices += (nProfilePoints - 2) * 3;
}
}
-void MillSim::Shape::ExtrudeProfileRadial(float* profPoints, int nPoints, float radius, float angleRad, float deltaHeight, bool capStart, bool capEnd)
+void Shape::ExtrudeProfileRadial(float* profPoints,
+ int nPoints,
+ float radius,
+ float angleRad,
+ float deltaHeight,
+ bool capStart,
+ bool capEnd)
{
int vidx = 0, vc1idx, vc2idx;
int iidx = 0, ic1idx, ic2idx;
int numVerts, numIndices;
- CalculateExtrudeBufferSizes(nPoints, capStart, capEnd, &numVerts, &numIndices, &vc1idx, &vc2idx, &ic1idx, &ic2idx);
- int vc1start = vc1idx / 6;
- int vc2start = vc2idx / 6;
+ CalculateExtrudeBufferSizes(nPoints,
+ capStart,
+ capEnd,
+ &numVerts,
+ &numIndices,
+ &vc1idx,
+ &vc2idx,
+ &ic1idx,
+ &ic2idx);
+ int vc1start = vc1idx;
+ int vc2start = vc2idx;
- float* vbuffer = (float*)malloc(numVerts * sizeof(Vertex));
- if (!vbuffer)
- return;
- GLushort* ibuffer = (GLushort*)malloc(numIndices * sizeof(GLushort));
- if (!ibuffer)
- {
- free(vbuffer);
- return;
- }
+ std::vector vbuffer(numVerts);
+ std::vector ibuffer(numIndices);
bool is_clockwise = angleRad > 0;
angleRad = (float)fabs(angleRad);
@@ -197,8 +182,7 @@ void MillSim::Shape::ExtrudeProfileRadial(float* profPoints, int nPoints, float
float cosAng = cosf(angleRad);
float sinAng = sinf(angleRad);
- for (int i = 0; i < nPoints; i++)
- {
+ for (int i = 0; i < nPoints; i++) {
int p1 = i * 2;
float y1 = profPoints[p1] + radius;
float z1 = profPoints[p1 + 1];
@@ -216,16 +200,14 @@ void MillSim::Shape::ExtrudeProfileRadial(float* profPoints, int nPoints, float
ny *= cosAng;
// start verts
- SET_TRIPLE(vbuffer, vidx, 0, y1, z1);
- SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
- SET_TRIPLE(vbuffer, vidx, 0, y2, z2);
- SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
+ vbuffer[vidx++] = {0, y1, z1, nx, ny, nz};
+ vbuffer[vidx++] = {0, y2, z2, nx, ny, nz};
if (capStart) {
- SET_TRIPLE(vbuffer, vc1idx, 0, y1, z1);
- SET_TRIPLE(vbuffer, vc1idx, -1 * dir, 0, 0);
- if (i > 1)
+ vbuffer[vc1idx++] = {0, y1, z1, -1 * dir, 0, 0};
+ if (i > 1) {
SET_TRIPLE(ibuffer, ic1idx, vc1start, vc1start + i + offs1, vc1start + i + offs2);
+ }
}
float x1 = y1 * sinAng * dir;
@@ -234,61 +216,60 @@ void MillSim::Shape::ExtrudeProfileRadial(float* profPoints, int nPoints, float
y2 *= cosAng;
z1 += deltaHeight;
z2 += deltaHeight;
- SET_TRIPLE(vbuffer, vidx, x1, y1, z1);
- SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
- SET_TRIPLE(vbuffer, vidx, x2, y2, z2);
- SET_TRIPLE(vbuffer, vidx, nx, ny, nz);
+ vbuffer[vidx++] = {x1, y1, z1, nx, ny, nz};
+ vbuffer[vidx++] = {x2, y2, z2, nx, ny, nz};
// face have 2 triangles { 0, 2, 3, 0, 3, 1 };
GLushort vistart = i * 4;
- if (is_clockwise)
- {
+ if (is_clockwise) {
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 2, vistart + 3);
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 3, vistart + 1);
}
- else
- {
+ else {
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 3, vistart + 2);
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 1, vistart + 3);
}
- if (capEnd)
- {
- SET_TRIPLE(vbuffer, vc2idx, x1, y1, z1);
- SET_TRIPLE(vbuffer, vc2idx, cosAng * dir, -sinAng, 0);
- if (i > 1)
+ if (capEnd) {
+ vbuffer[vc2idx++] = {x1, y1, z1, cosAng * dir, -sinAng, 0};
+ if (i > 1) {
SET_TRIPLE(ibuffer, ic2idx, vc2start, vc2start + i + offs2, vc2start + i + offs1);
+ }
}
}
- GenerateModel(vbuffer, ibuffer, numVerts, numIndices);
-
- free(vbuffer);
- free(ibuffer);
+ SetModelData(vbuffer, ibuffer);
}
-void MillSim::Shape::ExtrudeProfileLinear(float* profPoints, int nPoints, float fromX, float toX, float fromZ, float toZ, bool capStart, bool capEnd)
+void Shape::ExtrudeProfileLinear(float* profPoints,
+ int nPoints,
+ float fromX,
+ float toX,
+ float fromZ,
+ float toZ,
+ bool capStart,
+ bool capEnd)
{
int vidx = 0, vc1idx, vc2idx;
int iidx = 0, ic1idx, ic2idx;
int numVerts, numIndices;
- CalculateExtrudeBufferSizes(nPoints, capStart, capEnd, &numVerts, &numIndices, &vc1idx, &vc2idx, &ic1idx, &ic2idx);
- int vc1start = vc1idx / 6;
- int vc2start = vc2idx / 6;
+ CalculateExtrudeBufferSizes(nPoints,
+ capStart,
+ capEnd,
+ &numVerts,
+ &numIndices,
+ &vc1idx,
+ &vc2idx,
+ &ic1idx,
+ &ic2idx);
+ int vc1start = vc1idx;
+ int vc2start = vc2idx;
- float* vbuffer = (float*)malloc(numVerts * sizeof(Vertex));
- if (!vbuffer)
- return;
- GLushort* ibuffer = (GLushort*)malloc(numIndices * sizeof(GLushort));
- if (!ibuffer)
- {
- free(vbuffer);
- return;
- }
+ std::vector vbuffer(numVerts);
+ std::vector ibuffer(numIndices);
- for (int i = 0; i < nPoints; i++)
- {
+ for (int i = 0; i < nPoints; i++) {
// hollow pipe verts
int p1 = i * 2;
float y1 = profPoints[p1];
@@ -304,45 +285,36 @@ void MillSim::Shape::ExtrudeProfileLinear(float* profPoints, int nPoints, float
float ny = -zdiff / len;
float nz = ydiff / len;
- SET_TRIPLE(vbuffer, vidx, fromX, y1, z1 + fromZ);
- SET_TRIPLE(vbuffer, vidx, 0, ny, nz);
- SET_TRIPLE(vbuffer, vidx, fromX, y2, z2 + fromZ);
- SET_TRIPLE(vbuffer, vidx, 0, ny, nz);
- SET_TRIPLE(vbuffer, vidx, toX, y1, z1 + toZ);
- SET_TRIPLE(vbuffer, vidx, 0, ny, nz);
- SET_TRIPLE(vbuffer, vidx, toX, y2, z2 + toZ);
- SET_TRIPLE(vbuffer, vidx, 0, ny, nz);
+ vbuffer[vidx++] = {fromX, y1, z1 + fromZ, 0, ny, nz};
+ vbuffer[vidx++] = {fromX, y2, z2 + fromZ, 0, ny, nz};
+ vbuffer[vidx++] = {toX, y1, z1 + toZ, 0, ny, nz};
+ vbuffer[vidx++] = {toX, y2, z2 + toZ, 0, ny, nz};
// face have 2 triangles { 0, 2, 3, 0, 3, 1 };
GLushort vistart = i * 4;
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 2, vistart + 3);
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 3, vistart + 1);
- if (capStart)
- {
- SET_TRIPLE(vbuffer, vc1idx, fromX, profPoints[p1], profPoints[p1 + 1] + fromZ);
- SET_TRIPLE(vbuffer, vc1idx, -1, 0, 0);
- if (i > 1)
+ if (capStart) {
+ vbuffer[vc1idx++] = {fromX, profPoints[p1], profPoints[p1 + 1] + fromZ, -1, 0, 0};
+ if (i > 1) {
SET_TRIPLE(ibuffer, ic1idx, vc1start, vc1start + i - 1, vc1start + i);
+ }
}
- if (capEnd)
- {
- SET_TRIPLE(vbuffer, vc2idx, toX, profPoints[p1], profPoints[p1 + 1] + toZ);
- SET_TRIPLE(vbuffer, vc2idx, 1, 0, 0);
- if (i > 1)
+ if (capEnd) {
+ vbuffer[vc2idx++] = {toX, profPoints[p1], profPoints[p1 + 1] + toZ, 1, 0, 0};
+ if (i > 1) {
SET_TRIPLE(ibuffer, ic2idx, vc2start, vc2start + i, vc2start + i - 1);
+ }
}
}
- GenerateModel(vbuffer, ibuffer, numVerts, numIndices);
-
- free(vbuffer);
- free(ibuffer);
+ SetModelData(vbuffer, ibuffer);
}
-void MillSim::Shape::GenerateModel(float* vbuffer, GLushort* ibuffer, int numVerts, int nIndices)
+void Shape::GenerateModel(float* vbuffer, GLushort* ibuffer, int numVerts, int nIndices)
{
- //GLuint vbo, ibo, vao;
+ // GLuint vbo, ibo, vao;
// vertex buffer
glGenBuffers(1, &vbo);
@@ -367,32 +339,33 @@ void MillSim::Shape::GenerateModel(float* vbuffer, GLushort* ibuffer, int numVer
numIndices = nIndices;
}
-void MillSim::Shape::Render()
+void MillSim::Shape::SetModelData(std::vector& vbuffer, std::vector& ibuffer)
+{
+ GenerateModel((float*)vbuffer.data(), ibuffer.data(), (int)vbuffer.size(), (int)ibuffer.size());
+}
+
+void Shape::Render()
{
glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, nullptr);
}
-void MillSim::Shape::Render(mat4x4 modelMat, mat4x4 normallMat) // normals are rotated only
+void Shape::Render(mat4x4 modelMat, mat4x4 normallMat) // normals are rotated only
{
CurrentShader->UpdateModelMat(modelMat, normallMat);
Render();
}
-void MillSim::Shape::FreeResources()
+void Shape::FreeResources()
{
- if (vao > 0)
- {
- glBindVertexArray(vao);
- if (vbo > 0) glDeleteBuffers(1, &vbo);
- if (ibo > 0) glDeleteBuffers(1, &ibo);
- glDeleteVertexArrays(1, &vao);
- vbo = ibo = vao = 0;
- }
+ glBindVertexArray(0);
+ GLDELETE_BUFFER(vbo);
+ GLDELETE_BUFFER(ibo);
+ GLDELETE_VERTEXARRAY(vao);
}
-MillSim::Shape::~Shape()
+Shape::~Shape()
{
FreeResources();
}
diff --git a/src/Mod/CAM/PathSimulator/AppGL/SimShapes.h b/src/Mod/CAM/PathSimulator/AppGL/SimShapes.h
index 0b2821e4d8..e065250972 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/SimShapes.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/SimShapes.h
@@ -37,7 +37,6 @@
var[idx++] = z; \
}
-
#define SET_TRIPLE_OFFS(var, idx, offs, x, y, z) \
{ \
var[idx++] = x + offs; \
@@ -51,6 +50,18 @@ typedef unsigned int uint;
struct Vertex
{
+ Vertex()
+ : Vertex(0, 0, 0)
+ {}
+ Vertex(float _x, float _y, float _z, float _nx = 0, float _ny = 0, float _nz = 0)
+ {
+ x = _x;
+ y = _y;
+ z = _z;
+ nx = _nx;
+ ny = _ny;
+ nz = _nz;
+ }
float x, y, z;
float nx, ny, nz;
};
@@ -72,9 +83,11 @@ public:
void Render();
void Render(mat4x4 modelMat, mat4x4 normallMat);
void FreeResources();
+ void SetModelData(std::vector& vbuffer, std::vector& ibuffer);
void RotateProfile(float* profPoints,
int nPoints,
float distance,
+ float deltaHeight,
int nSlices,
bool isHalfTurn);
void ExtrudeProfileRadial(float* profPoints,
@@ -93,6 +106,11 @@ public:
bool capStart,
bool capEnd);
+ static void GenerateSinTable(int nSlices);
+ static std::vector sinTable;
+ static std::vector cosTable;
+ static int lastNumSlices;
+
protected:
void GenerateModel(float* vbuffer, GLushort* ibuffer, int numVerts, int numIndices);
void CalculateExtrudeBufferSizes(int nProfilePoints,
@@ -104,6 +122,7 @@ protected:
int* vc2idx,
int* ic1idx,
int* ic2idx);
+
};
} // namespace MillSim
diff --git a/src/Mod/CAM/PathSimulator/AppGL/SolidObject.cpp b/src/Mod/CAM/PathSimulator/AppGL/SolidObject.cpp
new file mode 100644
index 0000000000..263d15e167
--- /dev/null
+++ b/src/Mod/CAM/PathSimulator/AppGL/SolidObject.cpp
@@ -0,0 +1,79 @@
+/***************************************************************************
+ * Copyright (c) 2024 Shai Seger *
+ * *
+ * 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 "SolidObject.h"
+#include "Shader.h"
+#include
+
+#define NUM_PROFILE_POINTS 4
+using namespace MillSim;
+
+SolidObject::SolidObject()
+{
+ mat4x4_identity(mModelMat);
+ vec3_set(center, 0, 0, 0);
+}
+
+SolidObject::~SolidObject()
+{
+ isValid = false;
+ shape.FreeResources();
+}
+
+void MillSim::SolidObject::SetPosition(vec3 position)
+{
+ mat4x4_translate(mModelMat, position[0], position[1], position[2]);
+}
+
+void SolidObject::render()
+{
+ if (!isValid) {
+ return;
+ }
+ // UpdateObjColor(color);
+ shape.Render(mModelMat, mModelMat); // model is not rotated hence both are identity matrix
+}
+
+void SolidObject::GenerateSolid(std::vector& verts, std::vector& 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)
+ {
+ x = std::fminf(x, vert.x);
+ y = std::fminf(y, vert.y);
+ z = std::fminf(z, vert.z);
+ l = std::fmaxf(l, vert.x);
+ w = std::fmaxf(w, vert.y);
+ h = std::fmaxf(h, vert.z);
+ }
+ l -= x;
+ w -= y;
+ h -= z;
+ vec3_set(position, x, y, z);
+ vec3_set(center, x + l / 2, y + w / 2, z + h / 2);
+ vec3_set(size, l, w, h);
+ isValid = true;
+}
diff --git a/src/Mod/CAM/PathSimulator/AppGL/SolidObject.h b/src/Mod/CAM/PathSimulator/AppGL/SolidObject.h
new file mode 100644
index 0000000000..674fc77c69
--- /dev/null
+++ b/src/Mod/CAM/PathSimulator/AppGL/SolidObject.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * Copyright (c) 2024 Shai Seger *
+ * *
+ * 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 __solid_object_h__
+#define __solid_object_h__
+#include "SimShapes.h"
+#include "linmath.h"
+#include
+
+namespace MillSim
+{
+
+class SolidObject
+{
+public:
+ SolidObject();
+ virtual ~SolidObject();
+ void SetPosition(vec3 position);
+
+ /// Calls the display list.
+ virtual void render();
+ Shape shape;
+ void GenerateSolid(std::vector & verts, std::vector& indices);
+ vec3 center = {};
+ vec3 size = {};
+ vec3 position = {};
+ bool isValid = false;
+
+protected:
+ mat4x4 mModelMat;
+};
+} // namespace MillSim
+
+#endif
diff --git a/src/Mod/CAM/PathSimulator/AppGL/StockObject.cpp b/src/Mod/CAM/PathSimulator/AppGL/StockObject.cpp
index 56db4f709a..1586448f69 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/StockObject.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/StockObject.cpp
@@ -22,34 +22,15 @@
#include "StockObject.h"
#include "Shader.h"
-#include
#define NUM_PROFILE_POINTS 4
+using namespace MillSim;
-MillSim::StockObject::StockObject()
+StockObject::StockObject()
{
- mat4x4_identity(mModelMat);
- vec3_set(center, 0, 0, 0);
}
-MillSim::StockObject::~StockObject()
-{
- shape.FreeResources();
-}
-
-void MillSim::StockObject::render()
-{
- // glCallList(mDisplayListId);
- // UpdateObjColor(color);
- shape.Render(mModelMat, mModelMat); // model is not rotated hence both are identity matrix
-}
-
-void MillSim::StockObject::SetPosition(vec3 position)
-{
- mat4x4_translate(mModelMat, position[0], position[1], position[2]);
-}
-
-void MillSim::StockObject::GenerateBoxStock(float x, float y, float z, float l, float w, float h)
+void StockObject::GenerateBoxStock(float x, float y, float z, float l, float w, float h)
{
int idx = 0;
SET_DUAL(mProfile, idx, y + w, z + h);
@@ -57,6 +38,7 @@ void MillSim::StockObject::GenerateBoxStock(float x, float y, float z, float l,
SET_DUAL(mProfile, idx, y, z);
SET_DUAL(mProfile, idx, y, z + h);
+ vec3_set(position, x, y, z);
vec3_set(center, x + l / 2, y + w / 2, z + h / 2);
vec3_set(size, l, w, h);
diff --git a/src/Mod/CAM/PathSimulator/AppGL/StockObject.h b/src/Mod/CAM/PathSimulator/AppGL/StockObject.h
index 0bca595669..d6926c8237 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/StockObject.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/StockObject.h
@@ -22,31 +22,22 @@
#ifndef __stock_object_h__
#define __stock_object_h__
-#include "SimShapes.h"
+#include "SolidObject.h"
#include "linmath.h"
namespace MillSim
{
-class StockObject
+class StockObject : public SolidObject
{
public:
StockObject();
- virtual ~StockObject();
-
- /// Calls the display list.
- virtual void render();
- Shape shape;
- void SetPosition(vec3 position);
void GenerateBoxStock(float x, float y, float z, float l, float w, float h);
- vec3 center = {};
- vec3 size = {};
private:
float mProfile[8] = {};
- mat4x4 mModelMat;
};
} // namespace MillSim
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Mod/CAM/PathSimulator/AppGL/Texture.cpp b/src/Mod/CAM/PathSimulator/AppGL/Texture.cpp
index 2a5572a4b2..6a46f8950c 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/Texture.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/Texture.cpp
@@ -27,11 +27,17 @@ namespace MillSim
{
Texture::~Texture()
{
- glDeleteTextures(1, &mTextureId);
+ DestroyTexture();
+}
+
+void Texture::DestroyTexture()
+{
+ GLDELETE_TEXTURE(mTextureId);
}
bool Texture::LoadImage(unsigned int* image, int _width, int _height)
{
+ DestroyTexture();
width = _width;
height = _height;
glGenTextures(1, &mTextureId);
@@ -58,4 +64,4 @@ bool Texture::unbind()
return true;
}
-} // namespace MillSim
\ No newline at end of file
+} // namespace MillSim
diff --git a/src/Mod/CAM/PathSimulator/AppGL/Texture.h b/src/Mod/CAM/PathSimulator/AppGL/Texture.h
index c08c4c9f68..0d7def416b 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/Texture.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/Texture.h
@@ -33,6 +33,7 @@ public:
Texture()
{}
~Texture();
+ void DestroyTexture();
bool LoadImage(unsigned int* image, int x, int y);
bool Activate();
bool unbind();
@@ -51,7 +52,7 @@ public:
protected:
- unsigned int mTextureId = -1;
+ unsigned int mTextureId = 0;
};
diff --git a/src/Mod/CAM/PathSimulator/AppGL/TextureLoader.cpp b/src/Mod/CAM/PathSimulator/AppGL/TextureLoader.cpp
index c8ece95397..095db63843 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/TextureLoader.cpp
+++ b/src/Mod/CAM/PathSimulator/AppGL/TextureLoader.cpp
@@ -36,6 +36,9 @@ TextureItem texItems[] = {
{70, 50, 0, 0},
{27, 50, 0, 0},
{44, 50, 0, 0},
+ {90, 50, 0, 0},
+ {128, 50, 0, 0},
+ {168, 50, 0, 0},
};
@@ -51,7 +54,7 @@ TextureLoader::TextureLoader(std::string imgFolder, std::vector fil
if (mRawData == nullptr) {
return;
}
- memset(mRawData, 0x80, buffsize);
+ memset(mRawData, 0x00, buffsize);
for (std::size_t i = 0; i < fileNames.size(); i++) {
QImage pixmap((imgFolder + fileNames[i]).c_str());
AddImage(&(texItems[i]), pixmap, mRawData, textureSize);
diff --git a/src/Mod/CAM/PathSimulator/AppGL/linmath.h b/src/Mod/CAM/PathSimulator/AppGL/linmath.h
index 2346ff2a47..7ebdc2cfba 100644
--- a/src/Mod/CAM/PathSimulator/AppGL/linmath.h
+++ b/src/Mod/CAM/PathSimulator/AppGL/linmath.h
@@ -1,12 +1,11 @@
-/*************************************************************************************************/
-/* Taken from https://github.com/datenwolf/linmath.h under 'Do whatever you want' license */
-/*************************************************************************************************/
+//*************************************************************************************************
+//* Taken from https://github.com/datenwolf/linmath.h under 'Do whatever you want' license *
+//*************************************************************************************************
#ifndef LINMATH_H
#define LINMATH_H
#include
#include
-#include
#ifdef LINMATH_NO_INLINE
#define LINMATH_H_FUNC static
@@ -630,5 +629,4 @@ LINMATH_H_FUNC void mat4x4_arcball(mat4x4 R, mat4x4 const M, vec2 const _a, vec2
float const angle = acosf(vec3_mul_inner(a_, b_)) * s;
mat4x4_rotate(R, M, c_[0], c_[1], c_[2], angle);
}
-
#endif