| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #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 , |
| | 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++) { |
| | |
| | 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; |
| |
|
| | |
| | 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) { |
| | |
| | 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; |
| | *numIndices = nProfilePoints * 2 * 3; |
| | 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]; |
| |
|
| | |
| | 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; |
| |
|
| | |
| | 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}; |
| |
|
| | |
| | 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++) { |
| | |
| | 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]; |
| |
|
| | |
| | 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}; |
| |
|
| | |
| | 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) |
| | { |
| | |
| |
|
| | |
| | glGenBuffers(1, &vbo); |
| | GLClearError(); |
| | glBindBuffer(GL_ARRAY_BUFFER, vbo); |
| | GLLogError(); |
| | glBufferData(GL_ARRAY_BUFFER, numVerts * sizeof(Vertex), vbuffer, GL_STATIC_DRAW); |
| |
|
| | |
| | glGenBuffers(1, &ibo); |
| | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); |
| | glBufferData(GL_ELEMENT_ARRAY_BUFFER, nIndices * sizeof(GLushort), ibuffer, GL_STATIC_DRAW); |
| |
|
| | |
| | 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) |
| | { |
| | CurrentShader->UpdateModelMat(modelMat, normallMat); |
| | Render(); |
| | } |
| |
|
| | void Shape::FreeResources() |
| | { |
| | glBindVertexArray(0); |
| | GLDELETE_BUFFER(vbo); |
| | GLDELETE_BUFFER(ibo); |
| | GLDELETE_VERTEXARRAY(vao); |
| | } |
| |
|
| | Shape::~Shape() |
| | { |
| | FreeResources(); |
| | } |
| |
|