-
Notifications
You must be signed in to change notification settings - Fork 7
/
Donut.cpp
168 lines (132 loc) · 4.77 KB
/
Donut.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <iostream>
#include <stdexcept>
#include "Donut.h"
#include "plane.h"
using namespace std;
using namespace glm;
Donut::Donut(int slices, int stacks, float span, float back_radius, float front_radius) : Plane(slices, stacks)
{
float full_span = pi<float>() * 2.0f;
if (span == 0)
throw std::invalid_argument("bad span value");
if (stacks < 1)
throw std::invalid_argument("bad stack value");
if (back_radius == 0.0f && front_radius == 0.0f)
throw std::invalid_argument("bad radii");
if (abs(back_radius) <= 0.00001f)
back_radius = 0.00001f;
if (abs(front_radius) <= 0.00001f)
front_radius = 0.00001f;
this->slices = abs(slices);
this->stacks = stacks;
this->fr = front_radius;
this->br = back_radius;
this->span = min<float>(full_span, abs(span));
this->is_partial_span = this->span != full_span;
}
bool Donut::PreGLInitialize()
{
// Use the Plane implementation for making a flat plane.
this->Plane::PreGLInitialize();
// Now move the vertices into the shape of a cylinder.
/*float derivative;
vec3 z_axis(0.0f, 0.0f, 1.0f);
vec4 p(this->br, 0.0f, 0.0f, 1.0f);*/
// The t coordinate marches from -0.5 to 0.5 along z.
/*float t = 1.0f;
float delta_t = 1.0f / float(this->stacks);
vec3 delta_z(0.0f, 0.0f, delta_t);*/
// How far to advance between rings.
// Rotation angle between slices.
float theta = this->span / float(this->slices);
mat4 m = translate(mat4(), vec3(0.0f, 0.0f, -0.5f));
vec3 * v = &this->data.vertices[0];
vec3 * vn = &this->data.normal_visualization_coordinates[0];
//derivative = fr - br;
//for (int ring_index = 0; ring_index < this->stacks + 1; ring_index++)
//{
// // Mix from back radius to front radius to derive
// // the x coordinate of the point used to project the
// // surface.
// p.x = mix(br, fr, t);
// // Given the slope from back to front, compute normal angle.
// float rho = atan(derivative);
// //cout << rho / pi<float>() * 180.0f << endl;
// vec4 rotated_y_axis = rotate(mat4(), -rho, vec3(0.0f, 1.0f, 0.0f)) * vec4(1.0f, 0.0f, 0.0f, 1.0f);
// t -= delta_t;
// // Reset m2 to nothing but back to front translation.
// mat4 m2 = m;
// mat4 m3;
// for (int slice_index = 0; slice_index <= this->slices; slice_index++)
// {
// vec3 n = vec3(m3 * rotated_y_axis);
// *(vn++) = *v = vec3(m2 * p);
// *(vn++) = *v + n / this->NORMAL_LENGTH_DIVISOR;
// m2 = rotate(m2, -theta, z_axis);
// m3 = rotate(m3, -theta, z_axis);
// v++;
// }
// m = translate(m, delta_z);
//}
//this->data.vbackup = this->data.vertices;
//Donut Code
vector <vec3> singleCircle;
vec4 P(fr, 0.0f, 0.0f, 1.0f);
mat4 M;
for (int i = 0; i <= stacks; i++)
{
singleCircle.push_back(vec3(M * P));
M = rotate(M, theta, vec3(0.0f, 0.0f, 1.0f));
}
mat4 T = translate(mat4(), vec3(br, 0.0, 0.0));
mat4 R;
vec3 * V = &data.vertices[0];
for (int i = 0; i <= this->slices; i++)
{
for (size_t j = 0; j < singleCircle.size(); j++)
{
*(V++) = vec3(R * T * vec4(singleCircle[j], 1.0f));
}
R = rotate(R, theta, vec3(0.0f, 1.0f, 0.0f));
}
// Finally, rely upon the ultra cool RecomputeNormals from Plane to do all the hard work
// for initially setting the normals.
this->data.vbackup = this->data.vertices;
this->RecomputeNormals();
return true;
}
void Donut::NonGLTakeDown()
{
}
void Donut::RecomputeNormals()
{
this->Plane::RecomputeNormals();
vector<vec3> & n = this->data.normals;
vector<vec3> & v = this->data.vertices;
vector<vec3> & vn = this->data.normal_visualization_coordinates;
int w = this->slices + 1;
if (!this->is_partial_span)
{
// Fix the normals of the first and last columns;
for (int ring_index = 0; ring_index < this->stacks + 1; ring_index++)
{
n[ring_index * w + this->slices] = n[ring_index * w + 0] = (n[ring_index * w + 0] + n[ring_index * w + this->slices]) / 2.0f;
vn[(ring_index * w + this->slices) * 2 + 0] = v[ring_index * w + this->slices];
vn[(ring_index * w + this->slices) * 2 + 1] = v[ring_index * w + this->slices] + n[ring_index * w + this->slices] / Shape::NORMAL_LENGTH_DIVISOR;
vn[(ring_index * w + 0) * 2 + 0] = v[ring_index * w + 0];
vn[(ring_index * w + 0) * 2 + 1] = v[ring_index * w + 0] + n[ring_index * w + 0] / Shape::NORMAL_LENGTH_DIVISOR;
}
// Fix normals of first and last row.
int h = this->stacks + 1;
for (int slice_index = 0; slice_index < this->slices + 1; slice_index++)
{
n[slice_index + w * (h - 1)] = n[slice_index] = (n[slice_index] + n[slice_index + w * (h-1)]) / 2.0f;
// Bottom
vn[slice_index * 2 + 0] = v[slice_index];
vn[slice_index * 2 + 1] = v[slice_index] + n[slice_index] / Shape::NORMAL_LENGTH_DIVISOR;
// Top
vn[(slice_index + w * (h - 1)) * 2 + 0] = v[(slice_index + w * (h - 1))];
vn[(slice_index + w * (h - 1)) * 2 + 1] = v[(slice_index + w * (h - 1))] + n[slice_index] / Shape::NORMAL_LENGTH_DIVISOR;
}
}
}