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