AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2024 Shai Seger <shaise at gmail> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "SimShapes.h"
#include "Shader.h"
#include "GlUtils.h"
#include <math.h>
#include <cstddef>
#include <vector>
using namespace MillSim;
using std::numbers::pi;
int Shape::lastNumSlices = 0;
std::vector<float> Shape::sinTable;
std::vector<float> Shape::cosTable;
void Shape::GenerateSinTable(int nSlices)
{
if (nSlices == lastNumSlices) {
return;
}
float slice = (float)(2 * pi / nSlices);
int nvals = nSlices + 1;
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;
}
void Shape::RotateProfile(
float* profPoints,
int nPoints,
float distance,
float /* deltaHeight */,
int nSlices,
bool isHalfTurn
)
{
int vidx = 0;
int iidx = 0;
int numVerts, numIndices;
int vstart;
numVerts = nPoints * 2 * (nSlices + 1);
numIndices = (nPoints - 1) * nSlices * 6;
std::vector<Vertex> vbuffer(numVerts);
std::vector<GLushort> ibuffer(numIndices);
int nsinvals = nSlices;
if (isHalfTurn) {
nsinvals *= 2;
}
GenerateSinTable(nsinvals);
for (int i = 0; i < nPoints; i++) {
int i2 = i * 2;
float prevy = i > 0 ? profPoints[i2 - 2] : 0;
float prevz = i > 0 ? profPoints[i2 - 1] : profPoints[i2 + 1];
float prevrad = fabsf(prevy);
float rad = fabsf(profPoints[i2]);
float z2 = profPoints[i2 + 1];
float diffy = profPoints[i2] - prevy;
float diffz = z2 - prevz;
float len = sqrtf(diffy * diffy + diffz * diffz);
float nz = diffy / len;
vstart = i * 2 * (nSlices + 1);
for (int j = 0; j <= nSlices; j++) {
// generate vertices
float sx = sinTable[j];
float sy = cosTable[j];
float x1 = prevrad * sx + distance;
float y1 = prevrad * sy;
float x2 = rad * sx + distance;
float y2 = rad * sy;
// generate normals
float ny = -diffz / len;
float nx = ny * sx;
ny *= sy;
vbuffer[vidx++] = {x1, y1, prevz, nx, ny, nz};
vbuffer[vidx++] = {x2, y2, z2, nx, ny, nz};
if (j != nSlices) {
// generate indices { 0, 3, 1, 0, 2, 3 }
int pos = vstart + 2 * j;
if (i < (nPoints - 1)) {
SET_TRIPLE(ibuffer, iidx, pos, pos + 3, pos + 1);
}
if (i > 0) {
SET_TRIPLE(ibuffer, iidx, pos, pos + 2, pos + 3);
}
}
}
}
SetModelData(vbuffer, ibuffer);
}
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;
*numVerts += nProfilePoints;
*ic1idx = *numIndices;
*numIndices += (nProfilePoints - 2) * 3;
}
if (capEnd) {
*vc2idx = *numVerts;
*numVerts += nProfilePoints;
*ic2idx = *numIndices;
*numIndices += (nProfilePoints - 2) * 3;
}
}
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;
int vc2start = vc2idx;
std::vector<Vertex> vbuffer(numVerts);
std::vector<GLushort> ibuffer(numIndices);
bool is_clockwise = angleRad > 0;
angleRad = (float)fabs(angleRad);
float dir = is_clockwise ? 1.0f : -1.0f;
int offs1 = is_clockwise ? -1 : 0;
int offs2 = is_clockwise ? 0 : -1;
float cosAng = cosf(angleRad);
float sinAng = sinf(angleRad);
for (int i = 0; i < nPoints; i++) {
int p1 = i * 2;
float y1 = profPoints[p1] + radius;
float z1 = profPoints[p1 + 1];
int p2 = (p1 + 2) % (nPoints * 2);
float y2 = profPoints[p2] + radius;
float z2 = profPoints[p2 + 1];
// normals
float ydiff = y2 - y1;
float zdiff = z2 - z1;
float len = sqrtf(ydiff * ydiff + zdiff * zdiff);
float ny = -zdiff / len;
float nz = ydiff / len;
float nx = -sinAng * ny;
ny *= cosAng;
// start verts
vbuffer[vidx++] = {0, y1, z1, nx, ny, nz};
vbuffer[vidx++] = {0, y2, z2, nx, ny, nz};
if (capStart) {
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;
float x2 = y2 * sinAng * dir;
y1 *= cosAng;
y2 *= cosAng;
z1 += deltaHeight;
z2 += deltaHeight;
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) {
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 2, vistart + 3);
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 3, vistart + 1);
}
else {
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 3, vistart + 2);
SET_TRIPLE(ibuffer, iidx, vistart, vistart + 1, vistart + 3);
}
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);
}
}
}
SetModelData(vbuffer, ibuffer);
}
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;
int vc2start = vc2idx;
std::vector<Vertex> vbuffer(numVerts);
std::vector<GLushort> ibuffer(numIndices);
for (int i = 0; i < nPoints; i++) {
// hollow pipe verts
int p1 = i * 2;
float y1 = profPoints[p1];
float z1 = profPoints[p1 + 1];
int p2 = (p1 + 2) % (nPoints * 2);
float y2 = profPoints[p2];
float z2 = profPoints[p2 + 1];
// nornal
float ydiff = y2 - y1;
float zdiff = z2 - z1;
float len = sqrtf(ydiff * ydiff + zdiff * zdiff);
float ny = -zdiff / len;
float nz = ydiff / len;
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) {
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) {
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);
}
}
}
SetModelData(vbuffer, ibuffer);
}
void Shape::GenerateModel(float* vbuffer, GLushort* ibuffer, int numVerts, int nIndices)
{
// GLuint vbo, ibo, vao;
// vertex buffer
glGenBuffers(1, &vbo);
GLClearError();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLLogError();
glBufferData(GL_ARRAY_BUFFER, numVerts * sizeof(Vertex), vbuffer, GL_STATIC_DRAW);
// index buffer
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, nIndices * sizeof(GLushort), ibuffer, GL_STATIC_DRAW);
// vertex array
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, x));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, nx));
numIndices = nIndices;
}
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 Shape::Render(mat4x4 modelMat, mat4x4 normallMat) // normals are rotated only
{
CurrentShader->UpdateModelMat(modelMat, normallMat);
Render();
}
void Shape::FreeResources()
{
glBindVertexArray(0);
GLDELETE_BUFFER(vbo);
GLDELETE_BUFFER(ibo);
GLDELETE_VERTEXARRAY(vao);
}
Shape::~Shape()
{
FreeResources();
}