1 //
2 // Computergraphik II
3 // Prof. Dr. Juergen Doellner
4 // Wintersemester 2001/02
5 //
6 // Rahmenprogramm zu Aufgabenzettel 5
7 //
8
9 #include "cgwave.h"
10 #include "vector.h"
11 #include <fstream.h>
12 #include <stdlib.h>
13
14 #ifndef PI
15 const double PI = 3.14159265358979323846;
16 #endif
17
18 CGWave::CGWave() {
19 run_ = false;
20 culling_ = false;
21 showNormals_ = false;
22 periodAnim_ = false;
23 lightAnim_ = false;
24 zoom_ = 1.5;
25 periode_=0;
26 list_ = NULL;
27 rot_ = 180.0;
28
29 buildPatch(40);
30 }
31
32 CGWave::~CGWave() {
33 }
34
35 static GLfloat light_position1[] = {0.0, 1.0, 0.0, 1.0}; /* Point light location. */
36
37 void CGWave::drawScene() {
38
39 glPushMatrix();
40 glRotatef(60,1,0,0);
41 glScaled(zoom_, zoom_, zoom_);
42
43
44 glLightfv(GL_LIGHT1, GL_POSITION, light_position1);
45 drawObject();
46 // Positionieren bzw. Animieren der Lichtquelle 1
47
48
49 // draw light source (yellow !)
50 glPushMatrix();
51 glDisable(GL_LIGHTING);
52
53 // draw vector from light source
54 glColor4f(1, 1, 0, 0.5);
55
56 glBegin(GL_LINES);
57 glVertex3f(light_position1[0], light_position1[1], light_position1[2]);
58 glVertex3f(light_position1[0], 0, light_position1[2]);
59 glEnd();
60 // translate sphere that represents our light source
61
62 glTranslatef(light_position1[0], light_position1[1], light_position1[2]);
63 glutSolidSphere(0.03,10,10);
64
65 glEnable(GL_LIGHTING);
66 glPopMatrix();
67
68 glPopMatrix();
69 }
70
71 Vector CGWave::WavedNormal(const Vector& v) const
72 {
73 // get distance, stretch wave length
74 double distance = abs(v)*20;
75 // add periode shift
76 distance += periode_;
77
78 // normalize to [0,2*PI[
79 // while (distance >= 2*PI)
80 // distance -= 2*PI;
81
82 // normalize point vector
83 const Vector v_norm = v.normalized();
84
85 const double cos_dist = cos(distance);
86 const double nx = v_norm[0]*cos_dist;
87 const double ny = 1; // alternative: sin(distance);
88 const double nz = v_norm[2]*cos_dist;
89
90 return Vector(nx, ny, nz).normalized();
91 }
92
93 void CGWave::handleVertex(const Vector& v) const {
94 // compute normal according to wave functions
95 glNormal3dv(WavedNormal(v).rep());
96 // send vertex
97 glVertex3dv(v.rep());
98 }
99
100 void CGWave::drawObject() {
101 // draw geometry
102 int c=0;
103 for(int j=0; j<num_; j++) {
104 glBegin(GL_TRIANGLE_STRIP); // Performance
105 // 1)
106 handleVertex(list_[c]); c++;
107 // 2)
108 handleVertex(list_[c]); c++;
109 // 3)
110 handleVertex(list_[c]); c++;
111
112 for(int i=0; i<((num_+1)*2)-3; i++) {
113 // Rest des Strips
114 handleVertex(list_[c]); c++;
115 }
116
117 glEnd();
118 }
119
120 // show normals ?
121 if(showNormals_) {
122 glDisable(GL_LIGHTING);
123
124 // lady in red
125 glColor3f(1,0,0);
126 glBegin(GL_LINES);
127
128 c = 0;
129 // process all vertices
130 for (int i=0; i<2*num_+2; i++)
131 for (int j=0; j<num_; j++)
132 {
133 // get vertex
134 Vector& v = list_[c++];
135 // beginning from surface (small offset, though) ...
136 glVertex3d (v[0], v[1]+0.01, v[2]);
137 // ... to the end which we get by adding (stretched) normal to v
138 glVertex3dv((v+(0.1*WavedNormal(v))).rep());
139 }
140
141 glEnd();
142 glEnable(GL_LIGHTING);
143 }
144 }
145
146 void CGWave::buildPatch(int detail) {
147 // In Dreiecken tessellierten Fläche
148 if(list_) delete list_;
149
150 const int points = (detail)*(4+((detail-1)*2));
151 list_ = new Vector[points];
152
153 double offset = 1.0/detail;
154
155 double x;
156 double z;
157 num_ = detail;
158 int c = 0;
159 for(int j=0; j<detail; j++) { // passend zu Triangle-Strip (s.o.)
160 x = -0.5;
161 z = 0.5 - (j+1)*offset;
162 list_[c] = Vector(x,0,z); c++;
163
164 x = -0.5;
165 z = 0.5 - j*offset;
166 list_[c] = Vector(x,0,z); c++;
167
168 x = -0.5 + offset;
169 z = 0.5 - (j+1)*offset;
170 list_[c] = Vector(x,0,z); c++;
171
172 for(int i=0; i<detail; ) {
173 if( (c%2)!=0) {
174 x = -0.5 + (i+1)*offset;
175 z = 0.5 - (j)*offset;
176 i++;
177 } else {
178 x = -0.5 + (i+1)*offset;
179 z = 0.5 - (j+1)*offset;
180 }
181 list_[c] = Vector(x,0,z); c++;
182 }
183 }
184 }
185
186 void CGWave::onInit() {
187 // OpenGL Lichtquelle 0
188 static GLfloat light_diffuse[] = {0.7, 0.8, 0.5, 1.0};
189 static GLfloat light_position[] = {0.0, 1.0, 0.0, 1.0};
190 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
191 glLightfv(GL_LIGHT0, GL_POSITION, light_position);
192 // glEnable(GL_LIGHT0); // wenn T&L nicht unterstützt
193
194 // OpenGL Lichtquelle 1
195 static GLfloat light_diffuse1[] = {0.7, 0.8, 1.0, 1.0}; /* Diffuse light. */
196 static GLfloat light_specular1[] = {0.6, 0.8, 0.6, 1.0}; /* Positional light source */
197 glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse1);
198 glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular1);
199 glLightfv(GL_LIGHT1, GL_POSITION, light_position1);
200 glEnable(GL_LIGHT1);
201
202 glEnable(GL_LIGHTING);
203
204 // OpenGL Material
205 static GLfloat mat_specular[] = {0.8, 0.8, 0.8, 1.0}; /* Material property. */
206 glMaterialf(GL_FRONT, GL_SHININESS, 32);
207 glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
208
209 // automatische Normalisierung
210 glEnable(GL_NORMALIZE);
211
212 // Tiefen Test aktivieren
213 glEnable(GL_DEPTH_TEST);
214
215 // Blending aktivieren
216 glEnable(GL_BLEND);
217 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
218
219 // Smooth Schattierung aktivieren
220 glShadeModel(GL_SMOOTH);
221 // glShadeModel(GL_FLAT);
222
223 // Projection
224 glMatrixMode(GL_PROJECTION);
225 gluPerspective(60.0, 1.0, 2.0, 50.0);
226
227 // LookAt tesselieren
228 glMatrixMode(GL_MODELVIEW);
229 gluLookAt(
230 0.0, 0.0, 4.0, // from (0,0,4)
231 0.0, 0.0, 0.0, // to (0,0,0)
232 0.0, 1.0, 0.); // up
233
234 glRotatef(-25, 0.0, 1.0, 0.0);
235 glClearColor(0.9,0.9,0.9,1.0);
236 }
237
238 void CGWave::onSize(unsigned int newWidth,unsigned int newHeight) {
239 width_ = newWidth;
240 height_ = newHeight;
241 glMatrixMode(GL_PROJECTION);
242 glViewport(0, 0, width_ - 1, height_ - 1);
243 glLoadIdentity();
244 gluPerspective(40.0,float(width_)/float(height_),2.0, 100.0);
245 glMatrixMode(GL_MODELVIEW);
246 }
247
248 void CGWave::onKey(unsigned char key) {
249 switch (key) {
250 case 27: { exit(0); break; }
251 case '+': { zoom_*= 1.1; break; }
252 case '-': { zoom_*= 0.9; break; }
253 case ' ': { run_ = !run_; break; }
254 case 'q': { glEnable(GL_LIGHT0); break; }
255 case 'Q': { glDisable(GL_LIGHT0); break; }
256 case 'c': { culling_ = !culling_; break; }
257 case 'n': { showNormals_ = !showNormals_; break; }
258 case 'p': { periodAnim_ = !periodAnim_; break; }
259 case 'y': { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;}
260 case 'x': { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;}
261 case 'l': { lightAnim_ = !lightAnim_; break; }
262 case '1': { buildPatch(1); break; }
263 case '2': { buildPatch(2); break; }
264 case '3': { buildPatch(5); break; }
265 case '4': { buildPatch(10); break; }
266 case '5': { buildPatch(20); break; }
267 case '6': { buildPatch(40); break; }
268 case '7': { buildPatch(50); break; }
269 case '8': { buildPatch(100); break; }
270 case '9': { buildPatch(200); break; } // netter Versuch
271 }
272 onDraw();
273 }
274
275 void CGWave::onIdle() {
276 if(periodAnim_)
277 { // Periodische Wellenbewegung
278 periode_ -= 0.05;
279 if (periode_ < 0 )
280 periode_ += 2*PI;
281 }
282
283 if(lightAnim_)
284 {
285 rot_+=2; // Animierte Lichtquellen
286
287 // slow down rotation
288 double slow_rot = rot_/3;
289 light_position1[0] = 0.5*cos(slow_rot*PI/180.0);
290 light_position1[1] = 0.5;
291 light_position1[2] = 0.5*sin(slow_rot*PI/180.0);
292 }
293
294 if (run_) // Simple Rotation
295 glRotatef(.5, 0.0, 1.0, 0.0);
296
297 // Redraw
298 onDraw();
299 }
300
301 void CGWave::onDraw() {
302 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
303
304 if (culling_) glEnable(GL_CULL_FACE);
305
306 drawScene();
307
308 glDisable(GL_CULL_FACE);
309
310 // Nicht vergessen! Front- und Back-Buffer tauschen:
311 swapBuffers();
312 }
313
314 // Hauptprogramm
315 int main(int argc, char* argv[]) {
316 // Erzeuge eine Instanz der Beispiel-Anwendung:
317 CGWave sample;
318
319 cout << "Tastenbelegung:" << endl
320 << "ESC Programm beenden" << endl
321 << "Leertaste Objekt drehen" << endl
322 << "+ Hineinzoomen" << endl
323 << "- Herauszoomen" << endl
324 << "n Normalen anzeigen/verbergen" << endl
325 << "p Wellen animieren an/aus" << endl
326 << "l Lichtquelle bewegen" << endl
327 << "q zweite Lichtquelle an" << endl
328 << "Q zweite Lichtquelle aus" << endl
329 << "y Drahtgittermodell" << endl
330 << "x Flaechen ausfuellen" << endl
331 << "1 bis 9 Tessellationsgrad (1 - ungenau, schnell 9 - sehr exakt, langsam)" << endl;
332
333 // Starte die Beispiel-Anwendung:
334 sample.start("Stephan Brumme, 702544", true, 512, 512);
335 return(0);
336 }
337