1 // Computergrafik I
2 // Prof. Dr. Juergen Doellner
3 // Sommersemester 2001
4 //
5 // Programmrahmen fuer Aufgabe 4
6
7
8 // Stephan Brumme, 702544
9 // last changes: May 07, 2001
10
11
12 // ----------------------------------------------------------
13 // It might be useful to use the class "Vector" presented in
14 // the exercises
15 // ----------------------------------------------------------
16
17 #include "cgsphere.h"
18 #include <math.h>
19
20
21
22 CGSphere::CGSphere() {
23 // adjust to fit the window
24 m_fRadius = 0.95;
25 m_nTessellationLevel = 6;
26
27 m_bUseFlatShade = true;
28 m_bUseWireframe = false;
29 m_bUseTriangleTessellation = true;
30 }
31
32 CGSphere::~CGSphere() {
33 }
34
35 void CGSphere::onInit() {
36 // Set background color.
37 glClearColor(0.4, 0.4, 0.7, 0); // blue
38
39 // Set Shading
40 if (m_bUseFlatShade)
41 glShadeModel(GL_FLAT);
42 else
glShadeModel(GL_SMOOTH);
43
44 // Enable Lighting
45 GLfloat am[] = {0.5, 0.5, 0.5, 1.0};
46 GLfloat df[] = {1.0, 1.0, 1.0, 1.0};
47 GLfloat sp[] = {0.0, 0.0, 0.0, 1.0};
48 GLfloat pos[] = {1.0, 1.0, 0.0, 1.0};
49 glEnable(GL_LIGHTING);
50 glLightfv(GL_LIGHT0, GL_AMBIENT, am);
51 glLightfv(GL_LIGHT0, GL_DIFFUSE, df);
52 glLightfv(GL_LIGHT0, GL_SPECULAR, sp);
53 glLightfv(GL_LIGHT0, GL_POSITION, pos);
54 glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.2);
55 glEnable(GL_LIGHT0);
56
57 // Let OpenGL compute normals automatically
58 glEnable(GL_NORMALIZE);
59
60 glEnable(GL_DEPTH_TEST);
61 }
62
63 void CGSphere::TessellateTriangle(const Vector& v1, const Vector& v2, const Vector& v3, int nLevel)
64 {
65 if (nLevel == 1)
66 {
67 // Dreieck zeichnen (eventuell als Drahtgittermodell)
68 if (m_bUseWireframe)
69 glBegin(GL_LINE_LOOP);
70 else
glBegin(GL_TRIANGLES);
71
72 glVertex3f(v1[0], v1[1], v1[2]);
73 glVertex3f(v2[0], v2[1], v2[2]);
74 glVertex3f(v3[0], v3[1], v3[2]);
75 glEnd();
76 }
77 else
{
78 // Mittelpunkte der Seiten bestimmen
79 Vector s1((v2[0]+v3[0])/2, (v2[1]+v3[1])/2, (v2[2]+v3[2])/2);
80 Vector s2((v1[0]+v3[0])/2, (v1[1]+v3[1])/2, (v1[2]+v3[2])/2);
81 Vector s3((v2[0]+v1[0])/2, (v2[1]+v1[1])/2, (v2[2]+v1[2])/2);
82
83 // und normalisieren
84 s1.normalize();
85 s2.normalize();
86 s3.normalize();
87
88 // weiter tessellieren
89 TessellateTriangle(s1, s2, s3, nLevel-1);
90 TessellateTriangle(v1, s3, s2, nLevel-1);
91 TessellateTriangle(v2, s1, s3, nLevel-1);
92 TessellateTriangle(v3, s1, s2, nLevel-1);
93 }
94 }
95
96 void CGSphere::onDraw() {
97 // Clear framebuffer using background color.
98 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
99
100 // Set current color for drawing.
101 glColor3f (1.0, 1.0, 1.0); // white
102
103 glPushMatrix();
104
105 // Radius anpassen (da eigentlich nur Einheitskugel berechnet)
106 glScalef (m_fRadius, m_fRadius, m_fRadius);
107
108 // urgently needed ...
109 const GLfloat fPi = 3.1415926;
110
111 if (m_bUseTriangleTessellation)
112 {
113 // triangle tessellation
114
115 // Eckpunkte festlegen
116 const GLfloat fOffset = 1/sqrt(3);
117 Vector v[4] = { Vector( fOffset, fOffset, fOffset),
118 Vector(-fOffset,-fOffset, fOffset),
119 Vector(-fOffset, fOffset,-fOffset),
120 Vector( fOffset,-fOffset,-fOffset)};
121
122 // mit den 4 Seiten des Tetraeders die Tessellation beginnen
123 TessellateTriangle(v[0], v[1], v[2], m_nTessellationLevel);
124 TessellateTriangle(v[0], v[1], v[3], m_nTessellationLevel);
125 TessellateTriangle(v[0], v[2], v[3], m_nTessellationLevel);
126 TessellateTriangle(v[1], v[2], v[3], m_nTessellationLevel);
127 }
128 else
{
129 // quad tessellation
130
131 // Winkelschrittweite
132 const GLfloat fDeltaAlpha = fPi/m_nTessellationLevel;
133 const GLfloat fDeltaBeta = 2*fPi/m_nTessellationLevel;
134
135 // "Breitengrade"
136 for (GLfloat fAlpha = -fPi/2; fAlpha < fPi/2; fAlpha += fDeltaAlpha)
137 {
138 // "Längengrade"
139 for (GLfloat fBeta = 0; fBeta < 2*fPi; fBeta += fDeltaBeta)
140 {
141 // 4 Eckpunkte berechnen
142 // Formeln in Aufgabe 3 erläutert
143 Vector v1(cos(fAlpha)*sin(fBeta),
144 sin(fAlpha),
145 cos(fAlpha)*cos(fBeta));
146
147 Vector v2(cos(fAlpha+fDeltaAlpha)*sin(fBeta),
148 sin(fAlpha+fDeltaAlpha),
149 cos(fAlpha+fDeltaAlpha)*cos(fBeta));
150
151 Vector v3(cos(fAlpha+fDeltaAlpha)*sin(fBeta+fDeltaBeta),
152 sin(fAlpha+fDeltaAlpha),
153 cos(fAlpha+fDeltaAlpha)*cos(fBeta+fDeltaBeta));
154
155 Vector v4(cos(fAlpha)*sin(fBeta+fDeltaBeta),
156 sin(fAlpha),
157 cos(fAlpha)*cos(fBeta+fDeltaBeta));
158
159 // Viereck zeichnen (eventuell als Drahtgittermodell)
160 if (m_bUseWireframe)
161 glBegin(GL_LINE_LOOP);
162 else
glBegin(GL_QUADS);
163
164 glVertex3f(v1[0], v1[1], v1[2]);
165 glVertex3f(v2[0], v2[1], v2[2]);
166 glVertex3f(v3[0], v3[1], v3[2]);
167 glVertex3f(v4[0], v4[1], v4[2]);
168 glEnd();
169 }
170 }
171 }
172
173 glPopMatrix();
174
175 glFlush();
176 // Do not forget to swap front- and backbuffer!
177 swapBuffers();
178 }
179
180 void CGSphere::onKey(unsigned char key) {
181 cout << key << endl;
182 switch (key) {
183 case 'q': exit(0); break; // Quit application.
184
185 // Tessellationsgrad erhöhen
186 case '+': m_nTessellationLevel++;
187 cout << m_nTessellationLevel << endl;
188 break;
189
190 // Tessellationsgrad senken
191 case '-': if (m_nTessellationLevel > 1)
192 m_nTessellationLevel--;
193 cout << m_nTessellationLevel << endl;
194 break;
195
196 // Rotationen rückgängig machen
197 case 'r': glLoadIdentity();
198 break;
199
200 // Shadingmodell umschalten flat/smooth
201 case 's': m_bUseFlatShade = !m_bUseFlatShade;
202 if (m_bUseFlatShade)
203 glShadeModel(GL_FLAT);
204 else
glShadeModel(GL_SMOOTH);
205 break;
206
207 // Tessellationsmethode umschalten Dreieck/Viereck
208 case 't': m_bUseTriangleTessellation = !m_bUseTriangleTessellation;
209 break;
210
211 // umschalten solid/Drahtgitter
212 case 'w': m_bUseWireframe = !m_bUseWireframe;
213 break;
214
215 // um x-Achse drehen
216 case 'x': glRotated(5, 1, 0, 0);
217 break;
218 case 'X': glRotated(-5, 1, 0, 0);
219 break;
220 // um y-Achse drehen
221 case 'y': glRotated(5, 0, 1, 0);
222 break;
223 case 'Y': glRotated(-5, 0, 1, 0);
224 break;
225 // um z-Achse drehen
226 case 'z': glRotated(5, 0, 0, 1);
227 break;
228 case 'Z': glRotated(-5, 0, 0, 1);
229 break;
230 }
231
232 // Neuzeichnen erzwingen
233 glutPostRedisplay();
234 }
235
236 void CGSphere::onSize(int newWidth, int newHeight) {
237 if((newWidth > 0) && (newHeight > 0)) {
238 // Adjust OpenGL-Viewport according to new window dimensions.
239 glViewport(0, 0, newWidth - 1, newHeight - 1);
240
241 // Switch to modelview matrix stack and initialize
242 // with identity matrix.
243 glMatrixMode(GL_MODELVIEW);
244 glLoadIdentity();
245 }
246 }
247
248 // main program
249 int main(int argc, char* argv[]) {
250 // Generate an instance of the sample application.
251 CGSphere* sample = new CGSphere();
252
253 // Starts the sample application.
254 sample->start("CGSphere, Stephan Brumme, 702544");
255 return(0);
256 }
257