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