Download src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 15.9 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp
-
curl -L -o GuiDisplay.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp
15.9 kB
| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * Copyright (c) 2024 Shai Seger <shaise at gmail> * | |
| * * | |
| * This file is part of the FreeCAD CAx development system. * | |
| * * | |
| * This library is free software; you can redistribute it and/or * | |
| * modify it under the terms of the GNU Library General Public * | |
| * License as published by the Free Software Foundation; either * | |
| * version 2 of the License, or (at your option) any later version. * | |
| * * | |
| * This library is distributed in the hope that it will be useful, * | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
| * GNU Library General Public License for more details. * | |
| * * | |
| * You should have received a copy of the GNU Library General Public * | |
| * License along with this library; see the file COPYING.LIB. If not, * | |
| * write to the Free Software Foundation, Inc., 59 Temple Place, * | |
| * Suite 330, Boston, MA 02111-1307, USA * | |
| * * | |
| ***************************************************************************/ | |
| using namespace MillSim; | |
| // clang-format off | |
| // NOLINTBEGIN(*-magic-numbers) | |
| GuiItem guiItems[] = { | |
| {.name=eGuiItemSlider, .vbo=0, .vao=0, .sx=28, .sy=-80, .actionKey=0, .hidden=false, .flags=0}, | |
| {.name=eGuiItemThumb, .vbo=0, .vao=0, .sx=328, .sy=-94, .actionKey=1, .hidden=false, .flags=0}, | |
| {.name=eGuiItemPause, .vbo=0, .vao=0, .sx=28, .sy=-50, .actionKey='P', .hidden=true, .flags=0}, | |
| {.name=eGuiItemPlay, .vbo=0, .vao=0, .sx=28, .sy=-50, .actionKey='S', .hidden=false, .flags=0}, | |
| {.name=eGuiItemSingleStep, .vbo=0, .vao=0, .sx=68, .sy=-50, .actionKey='T', .hidden=false, .flags=0}, | |
| {.name=eGuiItemSlower, .vbo=0, .vao=0, .sx=113, .sy=-50, .actionKey=' ', .hidden=false, .flags=0}, | |
| {.name=eGuiItemFaster, .vbo=0, .vao=0, .sx=158, .sy=-50, .actionKey='F', .hidden=false, .flags=0}, | |
| {.name=eGuiItemX, .vbo=0, .vao=0, .sx=208, .sy=-45, .actionKey=0, .hidden=false, .flags=0}, | |
| {.name=eGuiItem1, .vbo=0, .vao=0, .sx=230, .sy=-50, .actionKey=0, .hidden=false, .flags=0}, | |
| {.name=eGuiItem5, .vbo=0, .vao=0, .sx=230, .sy=-50, .actionKey=0, .hidden=true, .flags=0}, | |
| {.name=eGuiItem10, .vbo=0, .vao=0, .sx=230, .sy=-50, .actionKey=0, .hidden=true, .flags=0}, | |
| {.name=eGuiItem25, .vbo=0, .vao=0, .sx=230, .sy=-50, .actionKey=0, .hidden=true, .flags=0}, | |
| {.name=eGuiItem50, .vbo=0, .vao=0, .sx=230, .sy=-50, .actionKey=0, .hidden=true, .flags=0}, | |
| {.name=eGuiItemRotate, .vbo=0, .vao=0, .sx=-140, .sy=-50, .actionKey=' ', .hidden=false, .flags=GUIITEM_CHECKABLE}, | |
| {.name=eGuiItemPath, .vbo=0, .vao=0, .sx=-100, .sy=-50, .actionKey='L', .hidden=false, .flags=GUIITEM_CHECKABLE}, | |
| {.name=eGuiItemAmbientOclusion, .vbo=0, .vao=0, .sx=-60, .sy=-50, .actionKey='A', .hidden=false, .flags=GUIITEM_CHECKABLE}, | |
| {.name=eGuiItemView, .vbo=0, .vao=0, .sx=-180, .sy=-50, .actionKey='V', .hidden=false, .flags=0}, | |
| {.name=eGuiItemHome, .vbo=0, .vao=0, .sx=-220, .sy=-50, .actionKey='H', .hidden=false, .flags=0}, | |
| }; | |
| // NOLINTEND(*-magic-numbers) | |
| // clang-format on | |
| std::vector<std::string> guiFileNames = { | |
| "Slider.png", | |
| "Thumb.png", | |
| "Pause.png", | |
| "Play.png", | |
| "SingleStep.png", | |
| "Slower.png", | |
| "Faster.png", | |
| "x.png", | |
| "1.png", | |
| "5.png", | |
| "10.png", | |
| "25.png", | |
| "50.png", | |
| "Rotate.png", | |
| "Path.png", | |
| "AmbientOclusion.png", | |
| "View.png", | |
| "Home.png" | |
| }; | |
| void GuiDisplay::UpdateProjection() | |
| { | |
| mat4x4 projmat; | |
| // mat4x4 viewmat; | |
| mat4x4_ortho(projmat, 0, gWindowSizeW, gWindowSizeH, 0, -1, 1); | |
| mShader.Activate(); | |
| mShader.UpdateProjectionMat(projmat); | |
| mThumbMaxMotion = guiItems[eGuiItemAmbientOclusion].posx() | |
| + guiItems[eGuiItemAmbientOclusion].texItem.w | |
| - guiItems[eGuiItemSlider].posx(); // - guiItems[eGuiItemThumb].texItem.w; | |
| HStretchGlItem(&(guiItems[eGuiItemSlider]), mThumbMaxMotion, 10.0f); | |
| } | |
| bool GuiDisplay::GenerateGlItem(GuiItem* guiItem) | |
| { | |
| Vertex2D verts[4]; | |
| int x = guiItem->texItem.tx; | |
| int y = guiItem->texItem.ty; | |
| int w = guiItem->texItem.w; | |
| int h = guiItem->texItem.h; | |
| verts[0] = {0, (float)h, mTexture.getTexX(x), mTexture.getTexY(y + h)}; | |
| verts[1] = {(float)w, (float)h, mTexture.getTexX(x + w), mTexture.getTexY(y + h)}; | |
| verts[2] = {0, 0, mTexture.getTexX(x), mTexture.getTexY(y)}; | |
| verts[3] = {(float)w, 0, mTexture.getTexX(x + w), mTexture.getTexY(y)}; | |
| // vertex buffer | |
| glGenBuffers(1, &(guiItem->vbo)); | |
| glBindBuffer(GL_ARRAY_BUFFER, guiItem->vbo); | |
| glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(Vertex2D), verts, GL_STATIC_DRAW); | |
| // glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, nullptr); | |
| // vertex array | |
| glGenVertexArrays(1, &(guiItem->vao)); | |
| glBindVertexArray(guiItem->vao); | |
| glEnableVertexAttribArray(0); | |
| glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, x)); | |
| glEnableVertexAttribArray(1); | |
| glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, tx)); | |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo); | |
| glBindVertexArray(0); | |
| return true; | |
| } | |
| bool MillSim::GuiDisplay::HStretchGlItem(GuiItem* guiItem, float newWidth, float edgeWidth) | |
| { | |
| if (guiItem->vbo == 0) { | |
| return false; | |
| } | |
| DestroyGlItem(guiItem); | |
| Vertex2D verts[12]; | |
| int x = guiItem->texItem.tx; | |
| int y = guiItem->texItem.ty; | |
| int h = guiItem->texItem.h; | |
| int w = guiItem->texItem.w; | |
| // left edge | |
| verts[0] = {0, (float)h, mTexture.getTexX(x), mTexture.getTexY(y + h)}; | |
| verts[1] = {edgeWidth, (float)h, mTexture.getTexX(x + edgeWidth), mTexture.getTexY(y + h)}; | |
| verts[2] = {0, 0, mTexture.getTexX(x), mTexture.getTexY(y)}; | |
| verts[3] = {edgeWidth, 0, mTexture.getTexX(x + edgeWidth), mTexture.getTexY(y)}; | |
| // right edge | |
| float px = newWidth - edgeWidth; | |
| verts[4] = {px, (float)h, mTexture.getTexX(x + w - edgeWidth), mTexture.getTexY(y + h)}; | |
| verts[5] = {newWidth, (float)h, mTexture.getTexX(x + w), mTexture.getTexY(y + h)}; | |
| verts[6] = {px, 0, mTexture.getTexX(x + w - edgeWidth), mTexture.getTexY(y)}; | |
| verts[7] = {newWidth, 0, mTexture.getTexX(x + w), mTexture.getTexY(y)}; | |
| // center | |
| verts[8] = {edgeWidth, (float)h, mTexture.getTexX(x + edgeWidth), mTexture.getTexY(y + h)}; | |
| verts[9] = {px, (float)h, mTexture.getTexX(x + w - edgeWidth), mTexture.getTexY(y + h)}; | |
| verts[10] = {edgeWidth, 0, mTexture.getTexX(x + edgeWidth), mTexture.getTexY(y)}; | |
| verts[11] = {px, 0, mTexture.getTexX(x + w - edgeWidth), mTexture.getTexY(y)}; | |
| guiItem->flags |= GUIITEM_STRETCHED; | |
| // vertex buffer | |
| glGenBuffers(1, &(guiItem->vbo)); | |
| glBindBuffer(GL_ARRAY_BUFFER, guiItem->vbo); | |
| glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(Vertex2D), verts, GL_STATIC_DRAW); | |
| glGenVertexArrays(1, &(guiItem->vao)); | |
| glBindVertexArray(guiItem->vao); | |
| glEnableVertexAttribArray(0); | |
| glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, x)); | |
| glEnableVertexAttribArray(1); | |
| glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, tx)); | |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo); | |
| glBindVertexArray(0); | |
| return true; | |
| } | |
| void GuiDisplay::DestroyGlItem(GuiItem* guiItem) | |
| { | |
| GLDELETE_BUFFER((guiItem->vbo)); | |
| GLDELETE_VERTEXARRAY((guiItem->vao)); | |
| } | |
| bool GuiDisplay::InitGui() | |
| { | |
| if (guiInitiated) { | |
| return true; | |
| } | |
| // index buffer | |
| SetupTooltips(); | |
| glGenBuffers(1, &mIbo); | |
| GLshort indices[18] = {0, 2, 3, 0, 3, 1, 4, 6, 7, 4, 7, 5, 8, 10, 11, 8, 11, 9}; | |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo); | |
| glBufferData(GL_ELEMENT_ARRAY_BUFFER, 18 * sizeof(GLushort), indices, GL_STATIC_DRAW); | |
| TextureLoader tLoader(":/gl_simulator/", guiFileNames, TEX_SIZE); | |
| unsigned int* buffer = tLoader.GetRawData(); | |
| if (buffer == nullptr) { | |
| return false; | |
| } | |
| mTexture.LoadImage(buffer, TEX_SIZE, TEX_SIZE); | |
| for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) { | |
| guiItems[i].texItem = *tLoader.GetTextureItem(i); | |
| GenerateGlItem(&(guiItems[i])); | |
| } | |
| mThumbStartX = guiItems[eGuiItemSlider].posx() - guiItems[eGuiItemThumb].texItem.w / 2; | |
| mThumbMaxMotion = (float)guiItems[eGuiItemSlider].texItem.w; | |
| // init shader | |
| mShader.CompileShader("GuiDisplay", (char*)VertShader2DTex, (char*)FragShader2dTex); | |
| mShader.UpdateTextureSlot(0); | |
| 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]); | |
| if (item->hidden) { | |
| return; | |
| } | |
| mat4x4 model; | |
| mat4x4_translate(model, (float)item->posx(), (float)item->posy(), 0); | |
| mShader.UpdateModelMat(model, nullptr); | |
| if (item == mPressedItem) { | |
| mShader.UpdateObjColor(mPressedColor); | |
| } | |
| else if (item->mouseOver) { | |
| mShader.UpdateObjColor(mHighlightColor); | |
| } | |
| else if (itemId > 1 && item->actionKey == 0) { | |
| mShader.UpdateObjColor(mTextColor); | |
| } | |
| else if (item->flags & GUIITEM_CHECKED) { | |
| mShader.UpdateObjColor(mToggleColor); | |
| } | |
| else { | |
| mShader.UpdateObjColor(mStdColor); | |
| } | |
| glBindVertexArray(item->vao); | |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo); | |
| int nTriangles = (item->flags & GUIITEM_STRETCHED) == 0 ? 6 : 18; | |
| glDrawElements(GL_TRIANGLES, nTriangles, GL_UNSIGNED_SHORT, nullptr); | |
| } | |
| void MillSim::GuiDisplay::SetupTooltips() | |
| { | |
| guiItems[eGuiItemPause].toolTip | |
| = QCoreApplication::translate("CAM:Simulator:Tooltips", "Pause simulation", nullptr); | |
| guiItems[eGuiItemPlay].toolTip | |
| = QCoreApplication::translate("CAM:Simulator:Tooltips", "Play simulation", nullptr); | |
| guiItems[eGuiItemSingleStep].toolTip | |
| = QCoreApplication::translate("CAM:Simulator:Tooltips", "Single step simulation", nullptr); | |
| guiItems[eGuiItemSlower].toolTip | |
| = QCoreApplication::translate("CAM:Simulator:Tooltips", "Decrease simulation speed", nullptr); | |
| guiItems[eGuiItemFaster].toolTip | |
| = QCoreApplication::translate("CAM:Simulator:Tooltips", "Increase simulation speed", nullptr); | |
| guiItems[eGuiItemPath].toolTip | |
| = QCoreApplication::translate("CAM:Simulator:Tooltips", "Show/Hide tool path", nullptr); | |
| guiItems[eGuiItemRotate].toolTip = QCoreApplication::translate( | |
| "CAM:Simulator:Tooltips", | |
| "Toggle turn table animation", | |
| nullptr | |
| ); | |
| guiItems[eGuiItemAmbientOclusion].toolTip | |
| = QCoreApplication::translate("CAM:Simulator:Tooltips", "Toggle ambient occlusion", nullptr); | |
| guiItems[eGuiItemView].toolTip = QCoreApplication::translate( | |
| "CAM:Simulator:Tooltips", | |
| "Toggle view simulation/model", | |
| nullptr | |
| ); | |
| guiItems[eGuiItemHome].toolTip | |
| = QCoreApplication::translate("CAM:Simulator:Tooltips", "Reset camera", nullptr); | |
| } | |
| void GuiDisplay::MouseCursorPos(int x, int y) | |
| { | |
| GuiItem* prevMouseOver = mMouseOverItem; | |
| mMouseOverItem = nullptr; | |
| for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) { | |
| GuiItem* g = &(guiItems[i]); | |
| if (g->actionKey == 0) { | |
| continue; | |
| } | |
| 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; | |
| } | |
| } | |
| if (mMouseOverItem != prevMouseOver) { | |
| if (mMouseOverItem != nullptr && !mMouseOverItem->toolTip.isEmpty()) { | |
| QPoint pos(x, y); | |
| QPoint globPos = CAMSimulator::DlgCAMSimulator::GetInstance()->mapToGlobal(pos); | |
| QToolTip::showText(globPos, mMouseOverItem->toolTip); | |
| } | |
| else { | |
| QToolTip::hideText(); | |
| } | |
| } | |
| } | |
| 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); | |
| } | |
| } | |
| void GuiDisplay::MousePressed(int button, bool isPressed, bool isSimRunning) | |
| { | |
| if (button == MS_MOUSE_LEFT) { | |
| if (isPressed) { | |
| if (mMouseOverItem != nullptr) { | |
| mPressedItem = mMouseOverItem; | |
| HandleActionItem(mPressedItem); | |
| } | |
| } | |
| else // button released | |
| { | |
| UpdatePlayState(isSimRunning); | |
| if (mPressedItem != nullptr) { | |
| MouseCursorPos(mPressedItem->posx() + 1, mPressedItem->posy() + 1); | |
| mPressedItem = nullptr; | |
| } | |
| } | |
| } | |
| } | |
| void GuiDisplay::MouseDrag(int /* buttons */, int dx, int /* dy */) | |
| { | |
| 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 != mPressedItem->posx()) { | |
| mMillSim->SetSimulationStage((float)(newx - mThumbStartX) / mThumbMaxMotion); | |
| mPressedItem->setPosx(newx); | |
| } | |
| } | |
| } | |
| void GuiDisplay::UpdatePlayState(bool isRunning) | |
| { | |
| guiItems[eGuiItemPause].hidden = !isRunning; | |
| guiItems[eGuiItemPlay].hidden = isRunning; | |
| } | |
| void MillSim::GuiDisplay::UpdateSimSpeed(int speed) | |
| { | |
| guiItems[eGuiItem1].hidden = speed != 1; | |
| guiItems[eGuiItem5].hidden = speed != 5; | |
| guiItems[eGuiItem10].hidden = speed != 10; | |
| guiItems[eGuiItem25].hidden = speed != 25; | |
| guiItems[eGuiItem50].hidden = speed != 50; | |
| } | |
| 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 == 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 (int i = 0; i < (int)NUM_GUI_ITEMS; i++) { | |
| RenderItem(i); | |
| } | |
| } | |