Files
create/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp
2024-05-23 10:12:13 +02:00

246 lines
8.6 KiB
C++

/***************************************************************************
* 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 "GuiDisplay.h"
#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, {}},
};
#define NUM_GUI_ITEMS (sizeof(guiItems) / sizeof(GuiItem))
#define TEX_SIZE 256
std::vector<std::string> guiFileNames = {"Slider.png",
"Thumb.png",
"Pause.png",
"Play.png",
"SingleStep.png",
"Faster.png",
"Rotate.png",
"X.png",
"0.png",
"1.png",
"4.png"};
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 GuiDisplay::InutGui()
{
// index buffer
glGenBuffers(1, &mIbo);
GLshort indices[6] = {0, 2, 3, 0, 3, 1};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * 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 long 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;
mThumbMaxMotion = (float)guiItems[eGuiItemSlider].texItem.w;
UpdateSimSpeed(1);
// shader
mat4x4 projmat;
// mat4x4 viewmat;
mat4x4_ortho(projmat, 0, 800, 600, 0, -1, 1);
mShader.CompileShader((char*)VertShader2DTex, (char*)FragShader2dTex);
mShader.UpdateTextureSlot(0);
mShader.UpdateProjectionMat(projmat);
return true;
}
void GuiDisplay::RenderItem(int itemId)
{
GuiItem* item = &(guiItems[itemId]);
if (item->hidden) {
return;
}
mat4x4 model;
mat4x4_translate(model, (float)item->sx, (float)item->sy, 0);
mShader.UpdateModelMat(model, nullptr);
if (itemId == mPressedItem) {
mShader.UpdateObjColor(mPressedColor);
}
else if (item->mouseOver) {
mShader.UpdateObjColor(mHighlightColor);
}
else if (itemId > 1 && item->actionKey == 0) {
mShader.UpdateObjColor(mTextColor);
}
else {
mShader.UpdateObjColor(mStdColor);
}
glBindVertexArray(item->vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
}
void GuiDisplay::MouseCursorPos(int x, int y)
{
for (unsigned long 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));
}
}
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);
}
}
}
else // button released
{
UpdatePlayState(isSimRunning);
mPressedItem = eGuiItemMax;
}
}
}
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 (newx < mThumbStartX) {
newx = mThumbStartX;
}
if (newx > ((int)mThumbMaxMotion + mThumbStartX)) {
newx = (int)mThumbMaxMotion + mThumbStartX;
}
if (newx != g->sx) {
mMillSim->SetSimulationStage((float)(newx - mThumbStartX) / mThumbMaxMotion);
g->sx = newx;
}
}
}
void GuiDisplay::UpdatePlayState(bool isRunning)
{
guiItems[eGuiItemPause].hidden = !isRunning;
guiItems[eGuiItemPlay].hidden = isRunning;
}
void MillSim::GuiDisplay::UpdateSimSpeed(int speed)
{
guiItems[eGuiItemChar0Img].hidden = speed == 1;
guiItems[eGuiItemChar1Img].hidden = speed == 40;
guiItems[eGuiItemChar4Img].hidden = speed != 40;
}
void GuiDisplay::Render(float progress)
{
if (mPressedItem != eGuiItemThumb) {
guiItems[eGuiItemThumb].sx = (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++) {
RenderItem(i);
}
}