264 lines
7.6 KiB
C++
264 lines
7.6 KiB
C++
/*
|
|
QGLView
|
|
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "glprimitives.h"
|
|
#include "glmesh.h"
|
|
|
|
|
|
|
|
|
|
Mesh * Primitive::plane(float width, float length) {
|
|
Mesh * ret = new Mesh();
|
|
QVector<QVector3D> & v(ret->vertices ());
|
|
QVector<QVector3D> & n(ret->normals ());
|
|
QVector<QVector2D> & t(ret->texcoords());
|
|
QVector< Vector3i> & i(ret->indices ());
|
|
float hw = width / 2.f, hl = length / 2.f;
|
|
for (int j = 0; j < 4; ++j) n << QVector3D(0., 0., 1.);
|
|
t << QVector2D(0., 0.) << QVector2D(0., 1.) << QVector2D(1., 1.) << QVector2D(1., 0.);
|
|
v << QVector3D(-hw, -hl, 0.) << QVector3D(-hw, hl, 0.) << QVector3D(hw, hl, 0.) << QVector3D(hw, -hl, 0.);
|
|
i << Vector3i(0, 2, 1) << Vector3i(0, 3, 2);
|
|
return ret;
|
|
}
|
|
|
|
|
|
Mesh * Primitive::cube(float width, float length, float height) {
|
|
Mesh * ret = new Mesh();
|
|
QVector3D scale(width, length, height);
|
|
QVector<QVector3D> & v(ret->vertices ());
|
|
QVector<QVector3D> & n(ret->normals ());
|
|
QVector<QVector2D> & t(ret->texcoords());
|
|
QVector< Vector3i> & i(ret->indices ());
|
|
float hs = 0.5f;
|
|
int si = 0;
|
|
QMatrix4x4 mat;
|
|
|
|
si = v.size();
|
|
for (int j = 0; j < 4; ++j) n << QVector3D(0., -1., 0.);
|
|
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.);
|
|
v << QVector3D(-hs, -hs, -hs) << QVector3D(hs, -hs, -hs) << QVector3D(hs, -hs, hs) << QVector3D(-hs, -hs, hs);
|
|
i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
|
|
|
|
for (int r = 0; r < 3; ++r) {
|
|
si = v.size();
|
|
mat.rotate(90., 0., 0., 1.);
|
|
QVector3D cn = mat.map(n[0]);
|
|
for (int j = 0; j < 4; ++j) {
|
|
n << cn;
|
|
v << mat.map(QVector4D(v[j])).toVector3D();
|
|
}
|
|
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.);
|
|
i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
|
|
}
|
|
|
|
mat.setToIdentity();
|
|
mat.rotate(90., 1., 0.,0.);
|
|
for (int r = 0; r < 2; ++r) {
|
|
si = v.size();
|
|
mat.rotate(180., 1., 0.,0.);
|
|
QVector3D cn = mat.map(n[0]);
|
|
for (int j = 0; j < 4; ++j) {
|
|
n << cn;
|
|
v << mat.map(QVector4D(v[j])).toVector3D();
|
|
}
|
|
t << QVector2D(0., 0.) << QVector2D(1., 0.) << QVector2D(1., 1.) << QVector2D(0., 1.);
|
|
i << Vector3i(si + 0, si + 1, si + 2) << Vector3i(si + 0, si + 2, si + 3);
|
|
}
|
|
|
|
for (int i = 0; i < v.size(); ++i)
|
|
v[i] *= scale;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
Mesh * Primitive::ellipsoid(int segments_wl, int segments_h, float width, float length, float height) {
|
|
Mesh * ret = new Mesh();
|
|
QVector<QVector3D> & v(ret->vertices ());
|
|
QVector<QVector3D> & n(ret->normals ());
|
|
QVector<QVector2D> & t(ret->texcoords());
|
|
QVector< Vector3i> & ind(ret->indices());
|
|
double hh = height / 2.f;
|
|
int hseg = segments_h + 1, wlseg = segments_wl + 1;
|
|
double crw, crl, a, ch, twl;
|
|
|
|
QVector3D cp;
|
|
for (int i = 0; i <= hseg; i++) {
|
|
ch = -cos((double)i / hseg * M_PI);
|
|
cp.setZ(ch * hh);
|
|
twl = sqrt(1. - ch * ch) / 2.;
|
|
crw = twl * width;
|
|
crl = twl * length;
|
|
int cvcnt = wlseg * 2;
|
|
for (int j = 0; j < cvcnt; j++) {
|
|
a = (double)j / (cvcnt - 1) * M_2PI;
|
|
cp.setX(crl * cos(a));
|
|
cp.setY(crw * sin(a));
|
|
v << cp; t << QVector2D((double)j / (cvcnt - 1), ch/2.f + 0.5f);
|
|
int si = v.size() - 1;
|
|
if (j > 0 && i > 0) {
|
|
ind << Vector3i(si - cvcnt - 1, si, si - 1);
|
|
ind << Vector3i(si - cvcnt, si, si - cvcnt - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
n.resize(v.size());
|
|
for (int i = 0; i < v.size(); i++)
|
|
n[i] = v[i].normalized();
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
Mesh * Primitive::disc(int segments, float width, float length, bool up) {
|
|
Mesh * ret = new Mesh();
|
|
QVector<QVector3D> & v(ret->vertices ());
|
|
QVector<QVector3D> & n(ret->normals ());
|
|
QVector<QVector2D> & t(ret->texcoords());
|
|
QVector< Vector3i> & ind(ret->indices());
|
|
|
|
segments = qMax(segments + 1, 4);
|
|
QVector3D cp;
|
|
v << QVector3D();
|
|
t << QVector2D(0.5f, 0.5f);
|
|
for (int i = 0; i < segments; i++) {
|
|
double a = (double)i / (segments - 1) * M_2PI;
|
|
cp.setX(length / 2. * cos(a));
|
|
cp.setY(width / 2. * sin(a));
|
|
v << cp;
|
|
t << QVector2D(cp.x() / width + 0.5f, cp.y() / length + 0.5f);
|
|
int si = v.size() - 1;
|
|
if (i > 0) {
|
|
if (up)
|
|
ind << Vector3i(si - 1, si, 0);
|
|
else
|
|
ind << Vector3i(si, si - 1, 0);
|
|
}
|
|
}
|
|
|
|
n.resize(v.size());
|
|
for (int i = 0; i < v.size(); i++)
|
|
n[i] = QVector3D(0, 0, up ? 1 : -1);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
QVector3D coneNormal(double rx, double ry, double height, double ang) {
|
|
QVector3D norm;
|
|
norm.setX(rx * cos(ang));
|
|
norm.setY(ry * sin(ang));
|
|
norm.setZ(0.);
|
|
double rl = norm.length();
|
|
double ca = atan2(rl, height);
|
|
norm *= cos(ca);
|
|
norm.setZ(norm.length() * tan(ca));
|
|
return norm.normalized();
|
|
}
|
|
Mesh * Primitive::cone(int segments, float width, float length, float height) {
|
|
Mesh * ret = new Mesh();
|
|
QVector<QVector3D> & v(ret->vertices ());
|
|
QVector<QVector3D> & n(ret->normals ());
|
|
QVector<QVector2D> & t(ret->texcoords());
|
|
QVector< Vector3i> & ind(ret->indices());
|
|
|
|
int seg = qMax(segments + 1, 4);
|
|
double rx = width / 2., ry = length / 2.;
|
|
QVector3D cp;
|
|
for (int i = 0; i < seg; i++) {
|
|
double a = (double)i / (seg - 1) * M_2PI;
|
|
cp.setX(ry * cos(a));
|
|
cp.setY(rx * sin(a));
|
|
if (i > 0) {
|
|
v << QVector3D(0, 0, height);
|
|
t << QVector2D((double)(i - 1) / (seg - 1), 1.f);
|
|
double ta = ((double)i - 0.5) / (seg - 1) * M_2PI;
|
|
n << coneNormal(rx, ry, height, ta);
|
|
}
|
|
v << cp;
|
|
t << QVector2D((double)i / (seg - 1), 0.f);
|
|
n << coneNormal(rx, ry, height, a);
|
|
int si = v.size() - 1;
|
|
if (i > 0)
|
|
ind << Vector3i(si - 1, si - 2, si);
|
|
}
|
|
|
|
Mesh * cap = Primitive::disc(segments, width, length, false);
|
|
ret->append(cap);
|
|
delete cap;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
Mesh * Primitive::cylinder(int segments, float width, float length, float height) {
|
|
Mesh * ret = new Mesh();
|
|
QVector<QVector3D> & v(ret->vertices ());
|
|
QVector<QVector3D> & n(ret->normals ());
|
|
QVector<QVector2D> & t(ret->texcoords());
|
|
QVector< Vector3i> & ind(ret->indices());
|
|
|
|
int seg = qMax(segments + 1, 4);
|
|
double rx = width / 2., ry = length / 2.;
|
|
QVector3D cp, norm;
|
|
for (int i = 0; i < seg; i++) {
|
|
double a = (double)i / (seg - 1) * M_2PI;
|
|
cp.setX(ry * cos(a));
|
|
cp.setY(rx * sin(a));
|
|
cp.setZ(0.);
|
|
norm = cp.normalized();
|
|
v << cp;
|
|
cp.setZ(height);
|
|
v << cp;
|
|
t << QVector2D((double)i / (seg - 1), 0.f);
|
|
t << QVector2D((double)i / (seg - 1), 1.f);
|
|
n << norm; n << norm;
|
|
int si = v.size() - 1;
|
|
if (i > 0) {
|
|
ind << Vector3i(si - 2, si - 1, si);
|
|
ind << Vector3i(si - 1, si - 2, si - 3);
|
|
}
|
|
}
|
|
|
|
Mesh * cap = Primitive::disc(segments, width, length, false);
|
|
ret->append(cap);
|
|
delete cap;
|
|
cap = Primitive::disc(segments, width, length, true);
|
|
cap->translatePoints(QVector3D(0., 0., height));
|
|
ret->append(cap);
|
|
delete cap;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
Mesh * Primitive::arrow(int segments, float thick, float angle) {
|
|
double cone_d = 3. * thick;
|
|
double cone_h = cone_d / tan(angle * deg2rad);
|
|
Mesh * ret = new Mesh();
|
|
Mesh * m = Primitive::cylinder(segments, thick, thick, 1. - cone_h);
|
|
ret->append(m);
|
|
delete m;
|
|
m = Primitive::cone(segments, cone_d, cone_d, cone_h);
|
|
m->translatePoints(QVector3D(0., 0., 1. - cone_h));
|
|
ret->append(m);
|
|
delete m;
|
|
return ret;
|
|
}
|