Cam simulator feature update (#15597)
* remove redundant code * Improve lighting, add ambient occlusion * Add cleanup code. Dialog is now deleted when cloesd. * change back to ambient occlusion * Fix G8x drill sequence bug. issue #14369 * fix bad simulation artifacts under Linux and QT. Issue #14369 * fix merge issue * fix border artifact on buttons * support showing path lines. revise the gui. * add option for arbitrary solids. wip * use vectors instead of mallocs * Handle arbitrary stock shapes + show base shape. * Complete the base shape display feature. eliminate co-planar artifacts. * support window scaling. upstream issue #14334 * Apply lint fixes * some missing lints. * Attend pylint issues * Apply code fixes based on @kadet1090 review * fix some clang-tidy warnings. * CAM: Linter cleanup round 1 --------- Co-authored-by: Chris Hennes <chennes@gmail.com>
This commit is contained in:
@@ -135,6 +135,9 @@
|
||||
<file>gl_simulator/SingleStep.png</file>
|
||||
<file>gl_simulator/Slider.png</file>
|
||||
<file>gl_simulator/Thumb.png</file>
|
||||
<file>gl_simulator/Path.png</file>
|
||||
<file>gl_simulator/View.png</file>
|
||||
<file>gl_simulator/AmbientOclusion.png</file>
|
||||
<file>preferences/Advanced.ui</file>
|
||||
<file>preferences/PathDressupHoldingTags.ui</file>
|
||||
<file>preferences/PathJob.ui</file>
|
||||
|
||||
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/AmbientOclusion.png
Normal file
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/AmbientOclusion.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 537 B |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/Path.png
Normal file
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/Path.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/View.png
Normal file
BIN
src/Mod/CAM/Gui/Resources/gl_simulator/View.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -14,25 +14,6 @@
|
||||
<string>Path Simulator</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="textVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="topMargin">
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -20,10 +20,16 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#include "PreCompiled.h" // NOLINT
|
||||
#ifndef _PreComp_
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
#include "CAMSim.h"
|
||||
#include "DlgCAMSimulator.h"
|
||||
#include <stdio.h>
|
||||
#include <Mod/Part/App/BRepMesh.h>
|
||||
|
||||
|
||||
|
||||
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<float> toolProfilePoints,
|
||||
void CAMSim::addTool(const std::vector<float> &toolProfilePoints,
|
||||
int toolNumber,
|
||||
float diameter,
|
||||
float resolution)
|
||||
@@ -65,6 +55,15 @@ void CAMSim::addTool(const std::vector<float> 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();
|
||||
|
||||
@@ -27,10 +27,9 @@
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
#include <Mod/CAM/App/Command.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/CAM/PathGlobal.h>
|
||||
#include <Mod/Mesh/App/Mesh.h>
|
||||
#include <Mod/CAM/App/Command.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
|
||||
#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<float> toolProfilePoints,
|
||||
void addTool(const std::vector<float> &toolProfilePoints,
|
||||
int toolNumber,
|
||||
float diameter,
|
||||
float resolution);
|
||||
void SetBaseShape(const Part::TopoShape& baseShape, float resolution);
|
||||
void AddCommand(Command* cmd);
|
||||
|
||||
public:
|
||||
|
||||
@@ -35,19 +35,28 @@
|
||||
<UserDocu>
|
||||
ResetSimulation():
|
||||
|
||||
Clear the simulation and all gcode commands
|
||||
Clear the simulation and all gcode commands
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="AddTool" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
SetToolShape(shape, toolnumber, diameter, resolution):
|
||||
AddTool(shape, toolnumber, diameter, resolution):
|
||||
|
||||
Set the shape of the tool to be used for simulation
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="SetBaseShape" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
SetBaseShape(shape, resolution):
|
||||
|
||||
Set the shape of the base object of the job
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="AddCommand">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
|
||||
@@ -73,7 +73,7 @@ PyObject* CAMSimPy::BeginSimulation(PyObject* args, PyObject* kwds)
|
||||
return nullptr;
|
||||
}
|
||||
CAMSim* sim = getCAMSimPtr();
|
||||
Part::TopoShape* stock = static_cast<Part::TopoShapePy*>(pObjStock)->getTopoShapePtr();
|
||||
const Part::TopoShape& stock = *static_cast<Part::TopoShapePy*>(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<const char*, 3> 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<Part::TopoShapePy*>(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<Path::CommandPy*>(pObjCmd)->getCommandPtr();
|
||||
sim->AddCommand(cmd);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "DlgCAMSimulator.h"
|
||||
#include "MillSimulation.h"
|
||||
#include <Mod/Part/App/BRepMesh.h>
|
||||
#include <QDateTime>
|
||||
#include <QSurfaceFormat>
|
||||
#include <QPoint>
|
||||
@@ -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<float> 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<Vertex>& verts,
|
||||
std::vector<GLushort>& indices)
|
||||
{
|
||||
std::vector<int> normalCount;
|
||||
int nVerts = 0;
|
||||
for (auto& shape : tshape.getSubTopoShapes(TopAbs_FACE)) {
|
||||
std::vector<Base::Vector3d> points;
|
||||
std::vector<Data::ComplexGeoData::Facet> facets;
|
||||
shape.getFaces(points, facets, resolution);
|
||||
|
||||
std::vector<Base::Vector3d> normals(points.size());
|
||||
std::vector<int> 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<Vertex> verts;
|
||||
std::vector<GLushort> indices;
|
||||
GetMeshData(shape, resolution, verts, indices);
|
||||
mMillSimulator->SetArbitraryStock(verts, indices);
|
||||
}
|
||||
|
||||
void DlgCAMSimulator::SetBaseShape(const Part::TopoShape& tshape, float resolution)
|
||||
{
|
||||
std::vector<Vertex> verts;
|
||||
std::vector<GLushort> indices;
|
||||
GetMeshData(tshape, resolution, verts, indices);
|
||||
mMillSimulator->SetBaseObject(verts, indices);
|
||||
}
|
||||
|
||||
DlgCAMSimulator* DlgCAMSimulator::mInstance = nullptr;
|
||||
|
||||
//************************************************************************************************************
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#ifndef PATHSIMULATOR_CAMSimulatorGui_H
|
||||
#define PATHSIMULATOR_CAMSimulatorGui_H
|
||||
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <QWindow>
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <QPainter>
|
||||
@@ -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<float> 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<MillSim::Vertex>& verts,
|
||||
std::vector<GLushort>& 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;
|
||||
};
|
||||
|
||||
|
||||
@@ -35,31 +35,28 @@ EndMill::EndMill(int toolid, float diameter)
|
||||
EndMill::EndMill(const std::vector<float>& toolProfile, int toolid, float diameter)
|
||||
: EndMill(toolid, diameter)
|
||||
{
|
||||
profilePoints = nullptr;
|
||||
mHandleAllocation = false;
|
||||
profilePoints.clear();
|
||||
|
||||
int srcBuffSize = static_cast<int>(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,
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace MillSim
|
||||
class EndMill
|
||||
{
|
||||
public:
|
||||
float* profilePoints = nullptr;
|
||||
std::vector<float>profilePoints;
|
||||
float radius;
|
||||
int nPoints = 0;
|
||||
int toolId = -1;
|
||||
@@ -53,9 +53,6 @@ public:
|
||||
|
||||
protected:
|
||||
void MirrorPointBuffer();
|
||||
|
||||
private:
|
||||
bool mHandleAllocation = false;
|
||||
};
|
||||
} // namespace MillSim
|
||||
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
#endif
|
||||
|
||||
#include "GCodeParser.h"
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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);
|
||||
|
||||
@@ -45,8 +45,8 @@ public:
|
||||
|
||||
public:
|
||||
std::vector<MillMotion> 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);
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
int gWindowSizeW = 800;
|
||||
int gWindowSizeH = 600;
|
||||
|
||||
int gDebug = -1;
|
||||
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -24,23 +24,24 @@
|
||||
#include "OpenGlWrapper.h"
|
||||
#include "MillSimulation.h"
|
||||
#include <cstddef>
|
||||
#include "GlUtils.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
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<std::string> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
60
src/Mod/CAM/PathSimulator/AppGL/MillPathLine.cpp
Normal file
60
src/Mod/CAM/PathSimulator/AppGL/MillPathLine.cpp
Normal file
@@ -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
|
||||
|
||||
|
||||
34
src/Mod/CAM/PathSimulator/AppGL/MillPathLine.h
Normal file
34
src/Mod/CAM/PathSimulator/AppGL/MillPathLine.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef __millpathline_h__
|
||||
#define __millpathline_h__
|
||||
#include <vector>
|
||||
|
||||
namespace MillSim
|
||||
{
|
||||
|
||||
struct MillPathPosition
|
||||
{
|
||||
float X, Y, Z;
|
||||
int SegmentId;
|
||||
};
|
||||
|
||||
class MillPathLine
|
||||
{
|
||||
public:
|
||||
MillPathLine();
|
||||
void GenerateModel();
|
||||
void Clear();
|
||||
void Render();
|
||||
|
||||
public:
|
||||
std::vector<MillPathPosition> MillPathPointsBuffer;
|
||||
|
||||
protected:
|
||||
unsigned int mVbo;
|
||||
unsigned int mVao;
|
||||
int mNumVerts;
|
||||
};
|
||||
|
||||
} // namespace Millsim
|
||||
|
||||
#endif // !__millpathline_h__
|
||||
|
||||
@@ -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<MillPathPosition>& 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;
|
||||
|
||||
@@ -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<MillPathPosition>& 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:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 <sstream>
|
||||
#include <vector>
|
||||
|
||||
#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<Vertex>& verts, std::vector<GLushort>& indices);
|
||||
void SetBaseObject(std::vector<Vertex>& verts, std::vector<GLushort>& 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<EndMill*> mToolTable;
|
||||
Shader shader3D, shaderInv3D, shaderFlat;
|
||||
GCodeParser mCodeParser;
|
||||
GuiDisplay guiDisplay;
|
||||
SimDisplay simDisplay;
|
||||
MillPathLine millPathLine;
|
||||
std::vector<MillPathSegment*> 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
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
|
||||
556
src/Mod/CAM/PathSimulator/AppGL/SimDisplay.cpp
Normal file
556
src/Mod/CAM/PathSimulator/AppGL/SimDisplay.cpp
Normal file
@@ -0,0 +1,556 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "SimDisplay.h"
|
||||
#include "linmath.h"
|
||||
#include "OpenGlWrapper.h"
|
||||
#include <random>
|
||||
|
||||
#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<GLfloat> 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<Point3D> 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
|
||||
138
src/Mod/CAM/PathSimulator/AppGL/SimDisplay.h
Normal file
138
src/Mod/CAM/PathSimulator/AppGL/SimDisplay.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __simdisplay_h__
|
||||
#define __simdisplay_h__
|
||||
|
||||
#include "GlUtils.h"
|
||||
#include "Shader.h"
|
||||
#include "StockObject.h"
|
||||
#include "MillPathLine.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
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<Point3D> mSsaoKernel;
|
||||
unsigned int mSsaoFbo;
|
||||
unsigned int mSsaoBlurFbo;
|
||||
unsigned int mFboSsaoTexture;
|
||||
unsigned int mFboSsaoBlurTexture;
|
||||
unsigned int mFboSsaoNoiseTexture;
|
||||
};
|
||||
|
||||
} // namespace MillSim
|
||||
#endif // !__simdisplay_h__
|
||||
@@ -24,49 +24,39 @@
|
||||
#include "Shader.h"
|
||||
#include "GlUtils.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
using namespace MillSim;
|
||||
|
||||
static float* sinTable = nullptr;
|
||||
static float* cosTable = nullptr;
|
||||
static int lastNumSlices = 0;
|
||||
int Shape::lastNumSlices = 0;
|
||||
std::vector<float> Shape::sinTable;
|
||||
std::vector<float> 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<Vertex> vbuffer(numVerts);
|
||||
std::vector<GLushort> 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<Vertex> vbuffer(numVerts);
|
||||
std::vector<GLushort> 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<Vertex> vbuffer(numVerts);
|
||||
std::vector<GLushort> 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<Vertex>& vbuffer, std::vector<GLushort>& 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();
|
||||
}
|
||||
|
||||
@@ -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<Vertex>& vbuffer, std::vector<GLushort>& 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<float> sinTable;
|
||||
static std::vector<float> 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
|
||||
|
||||
79
src/Mod/CAM/PathSimulator/AppGL/SolidObject.cpp
Normal file
79
src/Mod/CAM/PathSimulator/AppGL/SolidObject.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "SolidObject.h"
|
||||
#include "Shader.h"
|
||||
#include <algorithm>
|
||||
|
||||
#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<Vertex>& verts, std::vector<GLushort>& indices)
|
||||
{
|
||||
shape.SetModelData(verts, indices);
|
||||
|
||||
// calculate object's bounding box:
|
||||
float x = 999999.0f, y = 999999.0f, z = 999999.0f;
|
||||
float l = -999999.0f, w = -999999.0f, h = -999999.0f;
|
||||
for (auto& vert : verts)
|
||||
{
|
||||
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;
|
||||
}
|
||||
53
src/Mod/CAM/PathSimulator/AppGL/SolidObject.h
Normal file
53
src/Mod/CAM/PathSimulator/AppGL/SolidObject.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __solid_object_h__
|
||||
#define __solid_object_h__
|
||||
#include "SimShapes.h"
|
||||
#include "linmath.h"
|
||||
#include <vector>
|
||||
|
||||
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<Vertex> & verts, std::vector<GLushort>& indices);
|
||||
vec3 center = {};
|
||||
vec3 size = {};
|
||||
vec3 position = {};
|
||||
bool isValid = false;
|
||||
|
||||
protected:
|
||||
mat4x4 mModelMat;
|
||||
};
|
||||
} // namespace MillSim
|
||||
|
||||
#endif
|
||||
@@ -22,34 +22,15 @@
|
||||
|
||||
#include "StockObject.h"
|
||||
#include "Shader.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
|
||||
|
||||
@@ -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
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
} // namespace MillSim
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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<std::string> 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);
|
||||
|
||||
@@ -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 <string.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user