1 //
2 // Computergraphik II
3 // Prof. Dr. Juergen Doellner
4 // Wintersemester 2001/02
5 //
6 // Rahmenprogramm zu Aufgabenzettel 9
7 //
8
9 #include "cgtexture.h"
10 #include "vector.h"
11 #include "noise.h"
12
13 #include <fstream.h>
14 #include <stdio.h>
15 #include "glext.h"
16
17 #ifndef APIENTRY
18 #define WIN32_LEAN_AND_MEAN 1
19 #include <windows.h>
20 #endif /*APIENTRY*/
21
22 #ifdef _WIN32
23
24 /* This has already been done by glext.h */
25 /*typedef void (APIENTRY* PFNGLTEXIMAGE3DEXTPROC)(GLenum target, GLint level, GLenum internalFormat,
GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLenum format, GLenum type,
const GLvoid *image);*/
26
27 PFNGLTEXIMAGE3DPROC glTexImage3D;
28
29 #endif _WIN32*/
30
31 int isExtensionSupported(const char *extension) {
32 const GLubyte *extensions = NULL;
33 const GLubyte *start;
34 GLubyte *where, *terminator;
35
36 /* Extension names should not have spaces. */
37 where = (GLubyte*) strchr(extension, ' ');
38 if (where || *extension == '\0')
39 return 0;
40
41 extensions = glGetString(GL_EXTENSIONS);
42 /* It takes a bit of care to bew fol-proof about parsing the
OpenGL extensions string. Donn't be fooled by sub-strings,
etc. */
43 start = extensions;
44 for(;;) {
45 where = (GLubyte*) strstr((const char*) start, extension);
46 if (!where)
47 break;
48 terminator = where + strlen(extension);
49 if (where == start ||*(where-1)==' ')
50 if (*terminator == ' ' || *terminator == '\0')
51 return 1;
52 start = terminator;
53 }
54 return 0;
55 }
56
57 void buildAvailableExtensions() {
58 // Beispiel zum Abfragen des Extensionstrings ing OpenGL:
59 // int hasImaging = isExtensionSupported("GL_ARB_imaging");
60 #ifdef _WIN32
61 glTexImage3D = (PFNGLTEXIMAGE3DPROC)
62 wglGetProcAddress("glTexImage3D");
63 #endif
64 };
65
66
67 #ifndef PI
68 const double PI = 3.14159265358979323846;
69 #endif
70
71
72 CGTexture::CGTexture() {
73 run_ = false;
74 zoom_ = 1.0;
75 usetorus_ = true;
76
77 texWidth_ = texHeight_ = texDepth_ = 64;
78 }
79
80 CGTexture::~CGTexture() {
81 }
82
83 void CGTexture::drawScene() {
84
85 glPushMatrix();
86 glRotatef(200, 0.0, 1.0, 0.0);
87 glRotatef(55,1,0,0);
88 glScaled(zoom_, zoom_, zoom_);
89
90 glEnable(GL_TEXTURE_3D);
91
92 if (usetorus_)
93 {
94 // our oopy-doopy torus
95 drawObject();
96 }
97 else
98 {
99 // a simple quad to test the 3D texture
100 static float depth = 0;
101 static float increment = 0.01;
102 glDisable(GL_LIGHTING);
103 glBegin(GL_QUADS);
104 glTexCoord3f(0,0,depth); glVertex3f(-1,-1,0);
105 glTexCoord3f(1,0,depth); glVertex3f(+1,-1,0);
106 glTexCoord3f(1,1,depth); glVertex3f(+1,+1,0);
107 glTexCoord3f(0,1,depth); glVertex3f(-1,+1,0);
108 glEnd();
109 glEnable(GL_LIGHTING);
110
111 depth += increment;
112 if (depth < 0 || depth > 1)
113 {
114 increment = -increment;
115 depth += increment;
116 }
117 }
118
119 glDisable(GL_TEXTURE_3D);
120 glPopMatrix();
121 }
122
123 void CGTexture::drawObject() {
124 // draw torus
125 glCallList(torus_);
126 }
127
128 void CGTexture::buildPatch(int detail) {
129 if (glIsList(torus_)) glDeleteLists(torus_, 1);
130 GLint i, j;
131 float theta1, phi1, theta2, phi2, rings, sides;
132 float v0[03], v1[3], v2[3], v3[3];
133 float t0[03], t1[3], t2[3], t3[3];
134 float n0[3], n1[3], n2[3], n3[3];
135 float innerRadius=0.4;
136 float outerRadius=0.8;
137 float scalFac;
138
139 rings = detail;
140 sides = 10;
141 scalFac=1/((outerRadius+innerRadius)*2);
142
143 glNewList(torus_, GL_COMPILE);
144 glBegin(GL_QUADS);
145
146 for (i = 0; i < rings; i++) {
147 theta1 = (float)i * 2.0 * PI / rings;
148 theta2 = (float)(i + 1) * 2.0 * PI / rings;
149 for (j = 0; j < sides; j++) {
150 phi1 = (float)j * 2.0 * PI / sides;
151 phi2 = (float)(j + 1) * 2.0 * PI / sides;
152
153 v0[0] = cos(theta1) * (outerRadius + innerRadius * cos(phi1));
154 v0[1] = -sin(theta1) * (outerRadius + innerRadius * cos(phi1));
155 v0[2] = innerRadius * sin(phi1);
156
157 v1[0] = cos(theta2) * (outerRadius + innerRadius * cos(phi1));
158 v1[1] = -sin(theta2) * (outerRadius + innerRadius * cos(phi1));
159 v1[2] = innerRadius * sin(phi1);
160 v2[0] = cos(theta2) * (outerRadius + innerRadius * cos(phi2));
161 v2[1] = -sin(theta2) * (outerRadius + innerRadius * cos(phi2));
162 v2[2] = innerRadius * sin(phi2);
163
164 v3[0] = cos(theta1) * (outerRadius + innerRadius * cos(phi2));
165 v3[1] = -sin(theta1) * (outerRadius + innerRadius * cos(phi2));
166 v3[2] = innerRadius * sin(phi2);
167
168 n0[0] = cos(theta1) * (cos(phi1));
169 n0[1] = -sin(theta1) * (cos(phi1));
170 n0[2] = sin(phi1);
171
172 n1[0] = cos(theta2) * (cos(phi1));
173 n1[1] = -sin(theta2) * (cos(phi1));
174 n1[2] = sin(phi1);
175
176 n2[0] = cos(theta2) * (cos(phi2));
177 n2[1] = -sin(theta2) * (cos(phi2));
178 n2[2] = sin(phi2);
179
180 n3[0] = cos(theta1) * (cos(phi2));
181 n3[1] = -sin(theta1) * (cos(phi2));
182 n3[2] = sin(phi2);
183
184 t0[0] = v0[0]*scalFac + 0.5;
185 t0[1] = v0[1]*scalFac + 0.5;
186 t0[2] = v0[2]*scalFac + 0.5;
187
188 t1[0] = v1[0]*scalFac + 0.5;
189 t1[1] = v1[1]*scalFac + 0.5;
190 t1[2] = v1[2]*scalFac + 0.5;
191
192 t2[0] = v2[0]*scalFac + 0.5;
193 t2[1] = v2[1]*scalFac + 0.5;
194 t2[2] = v2[2]*scalFac + 0.5;
195
196 t3[0] = v3[0]*scalFac + 0.5;
197 t3[1] = v3[1]*scalFac + 0.5;
198 t3[2] = v3[2]*scalFac + 0.5;
199
200 glNormal3fv(n3); glTexCoord3fv(t3); glVertex3fv(v3);
201 glNormal3fv(n2); glTexCoord3fv(t2); glVertex3fv(v2);
202 glNormal3fv(n1); glTexCoord3fv(t1); glVertex3fv(v1);
203 glNormal3fv(n0); glTexCoord3fv(t0); glVertex3fv(v0);
204 }
205 }
206 glEnd();
207 glEndList();
208 }
209
210 //
211 // Einige nützliche Funktionen:
212 //
213
214 // distance from a point
215 inline float distance(float x, float y, float z, float cx, float cy, float cz) {
216 float dx = x-cx;
217 float dy = y-cy;
218 float dz = y-cz;
219 return sqrt(dx*dx + dy*dy + dz*dz);
220 }
221
222 // clamp x to be between a and b
223 inline float clamp(float x, float a, float b) {
224 return (x < a ? a : (x > b ? b : x));
225 }
226
227 inline float smoothstep(float a, float b, float x) {
228 if(x<=a) return 0.0;
229 if(x>=b) return 1.0;
230 x = (x-a)/(b-a); // normalized interval [0,1]
231 return x*x*(3-2*x);
232 }
233
234 // Spline Interpolation
235 Vector spline(float x, int nknots, Vector* knot) {
236 int span;
237 int nspans = nknots-3;
238
239 Vector c0,c1,c2,c3;
240
241 if(nspans<1) {
242 cout << "Error in spline function" << endl;
243 return NULL;
244 }
245
246 x=clamp(x,0,1)*nspans;
247 span = (int) x;
248 if(span >= nknots-3) span = nknots-3;
249 x-=span;
250
251 // Horner
252 c3 = -0.5 * knot[span] + 1.5 * knot[1+span] - 1.5 * knot[2+span] + 0.5 * knot[3+span];
253 c2 = 1.0 * knot[span] - 2.5 * knot[1+span] + 2.0 * knot[2+span] - 0.5 * knot[3+span];
254 c1 = -0.5 * knot[span] + 0.0 * knot[1+span] + 0.5 * knot[2+span] + 0.0 * knot[3+span];
255 c0 = 0.0 * knot[span] + 1.0 * knot[1+span] + 0.0 * knot[2+span] + 0.0 * knot[3+span];
256
257 return ((c3*x + c2)*x + c1)*x + c0;
258 }
259
260 Vector mix(const Vector& color1, const Vector& color2, const float alpha)
261 {
262 return (1-alpha)*color1 + alpha*color2;
263 }
264
265
266 static Vector dark = Vector(0.10, 0.10, 0.15);
267 static Vector bright = Vector(0.95, 0.95, 0.95);
268 static Vector brown = Vector(0.80, 0.65, 0.35);
269
270 void CGTexture::createNoiseTexture3D() {
271
272 int w = texWidth_;
273 int h = texHeight_;
274 int d = texDepth_;
275
276 // Notwendiger Aufruf zur Initialisierung der Hashtable-Struktur:
277 Noise::init();
278
279 GLubyte *img1 = new GLubyte[w * h * d * 3]; // 3D Textur I
280 GLubyte *img2 = new GLubyte[w * h * d * 3]; // 3D Textur II
281 GLubyte *img3 = new GLubyte[w * h * d * 3]; // 3D Textur III
282
283 //
284 // Generieren Sie eine 3D-Textur, die Marmor oder eine Steinstruktur simuliert
285 //
286 // Benutzen Sie die Perlin-Noise-Funktion: Noise::noise3(point) (!)
287 // ...
288 //
289 // Lassen Sie Ihrer Kreativitaet freien Lauf!
290 //
291
292 cout << endl
293 <<"3x 3D Textures ("<<w<<"x"<<h<<"x"<<d<<" Texels, "<<w*h*d*3*3/1024<<" KBytes) "
294 << endl;
295
296 for (int x=0; x<w; x++)
297 {
298 for (int y=0; y<h; y++)
299 for (int z=0; z<d; z++)
300 {
301 // texture offset
302 const int baseoffset = 3 * (x*h*d + y*d +z);
303
304 // little noise
305 float point1[3];
306 point1[0] = (4.0*x)/w;
307 point1[1] = (4.0*y)/h;
308 point1[2] = (4.0*z)/d;
309
310 // little noise (differs from first one)
311 float point2[3];
312 point2[1] = (4.0*x)/w;
313 point2[2] = (4.0*y)/h;
314 point2[0] = (4.0*z)/d;
315
316 // really noisy
317 float point3[3];
318 point3[1] = (16.0*x)/w;
319 point3[2] = (16.0*y)/h;
320 point3[0] = (16.0*z)/d;
321
322 float persistence1 = 0.25;
323 float persistence2 = 0.25;
324 float noise1 = 0.0;
325 float noise2 = 0.0;
326
327 // 4 octaves
328 for (int octave = 0; octave<4; octave++)
329 {
330 // brown marble's noise
331 // shift point
332 point1[0] += 0.4*cos(noise1);
333 point1[1] += 0.4*sin(noise1+PI/2);
334 // get noise
335 float currentnoise1 = (Noise::noise3(point1)+0.5) * persistence1;
336 noise1 += currentnoise1;
337 // add a bit of noisy noise (?!)
338 noise1 += 0.2 * Noise::noise3(point3) * persistence1;
339
340 // dark marble's noise
341 point2[0] += 0.4*cos(noise2);
342 point2[1] += 0.4*sin(noise2+PI/2);
343 // get noise
344 float currentnoise2 = (Noise::noise3(point2)+0.5) * persistence2;
345 noise2 += currentnoise2;
346 // add a bit of noisy noise (?!)
347 noise2 += 0.2 * Noise::noise3(point3) * persistence2;
348 }
349
350 // clamp noises
351 if (noise1 < 0) noise1 = 0;
352 if (noise1 > 1) noise1 = 1;
353 if (noise2 < 0) noise2 = 0;
354 if (noise2 > 1) noise2 = 1;
355
356 // color
357 Vector color(0,0,0);
358
359 // brown marble
360 color = mix(bright, brown, smoothstep(0.55, 0.60, noise1));
361 color = mix(color, bright, smoothstep(0.65, 0.68, noise1));
362
363 // texture III: brown marble
364 img3[baseoffset+0] = color[0]*255;
365 img3[baseoffset+1] = color[1]*255;
366 img3[baseoffset+2] = color[2]*255;
367
368 // dark marble
369 if (noise2 <= 0.55)
370 color = mix(color, dark, smoothstep(0.50, 0.52, noise2));
371 if (noise2 >= 0.52)
372 color = mix(dark, color, smoothstep(0.52, 0.55, noise2));
373
374 // texture I: combined
375 img1[baseoffset+0] = color[0]*255;
376 img1[baseoffset+1] = color[1]*255;
377 img1[baseoffset+2] = color[2]*255;
378
379 // dark marble (for texture II)
380 color = mix(bright, dark, smoothstep(0.50, 0.52, noise2));
381 color = mix(color, bright, smoothstep(0.52, 0.55, noise2));
382
383 // texture II: dark marble
384 img2[baseoffset+0] = color[0]*255;
385 img2[baseoffset+1] = color[1]*255;
386 img2[baseoffset+2] = color[2]*255;
387 }
388
389 // show progress (1 point = ca. 10%)
390 if (x % 7 == 0)
391 {
392 cout << ".";
393 cout.flush();
394 }
395 }
396
397 // Textur parameter
398 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
399
400 glGenTextures(1, &texName1_);
401 glGenTextures(2, &texName2_);
402 glGenTextures(3, &texName3_);
403
404 // texture I
405 glBindTexture(GL_TEXTURE_3D, texName1_);
406
407 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
408 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
409 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
410 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
411 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
412 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
413
414 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, w, h, d, 0, GL_RGB, GL_UNSIGNED_BYTE, img1);
415
416 // texture II
417 glBindTexture(GL_TEXTURE_3D, texName2_);
418
419 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
420 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
421 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
422 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
423 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
424 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
425
426 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, w, h, d, 0, GL_RGB, GL_UNSIGNED_BYTE, img2);
427
428 // texture III
429 glBindTexture(GL_TEXTURE_3D, texName3_);
430
431 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
432 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
433 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
434 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
435 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
436 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
437
438 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, w, h, d, 0, GL_RGB, GL_UNSIGNED_BYTE, img3);
439
440 // activate texture I
441 glBindTexture(GL_TEXTURE_3D, texName1_);
442
443 delete[] img1;
444 delete[] img2;
445 delete[] img3;
446 }
447
448 void CGTexture::onInit() {
449 buildAvailableExtensions();
450 torus_ = glGenLists(1);
451 buildPatch(32);
452
453 // Prozedurale 3D Textur
454 createNoiseTexture3D();
455
456
457 /* init light */
458 GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
459 GLfloat mat_shininess[] = { 25.0 };
460 GLfloat gray[] = { 0.6, 0.6, 0.6, 0.0 };
461 GLfloat white[] = { 1.0, 1.0, 1.0, 0.0 };
462 GLfloat light_position[] = { 0.0, 3.0, 3.0, 0.0 };
463
464 glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
465 glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
466 glLightfv(GL_LIGHT0, GL_POSITION, light_position);
467 glLightfv(GL_LIGHT0, GL_AMBIENT, gray);
468 glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
469 glLightfv(GL_LIGHT0, GL_SPECULAR, white);
470 glColorMaterial(GL_FRONT, GL_DIFFUSE);
471 glEnable(GL_COLOR_MATERIAL);
472 glEnable(GL_LIGHTING);
473 glEnable(GL_LIGHT0);
474
475 // Tiefen Test aktivieren
476 glEnable(GL_DEPTH_TEST);
477
478 // Smooth Schattierung aktivieren
479 glShadeModel(GL_SMOOTH);
480
481 // Projection
482 glMatrixMode(GL_PROJECTION);
483 gluPerspective(60.0, 1.0, 2.0, 50.0);
484
485 // LookAt
486 glMatrixMode(GL_MODELVIEW);
487 gluLookAt(
488 0.0, 0.0, 4.0, // from (0,0,4)
489 0.0, 0.0, 0.0, // to (0,0,0)
490 0.0, 1.0, 0.); // up
491
492 glClearColor(1, 1, 1, 1);
493 }
494
495 void CGTexture::onSize(unsigned int newWidth,unsigned int newHeight) {
496 width_ = newWidth;
497 height_ = newHeight;
498 glMatrixMode(GL_PROJECTION);
499 glViewport(0, 0, width_ - 1, height_ - 1);
500 glLoadIdentity();
501 gluPerspective(40.0,float(width_)/float(height_),2.0, 100.0);
502 glMatrixMode(GL_MODELVIEW);
503 }
504
505 void CGTexture::onKey(unsigned char key) {
506 switch (key) {
507 case 27: { exit(0); break; }
508 case '+': { zoom_*= 1.1; break; }
509 case '-': { zoom_*= 0.9; break; }
510 case ' ': { run_ = !run_; break; }
511 case '1': { buildPatch(4); break; }
512 case '2': { buildPatch(8); break; }
513 case '3': { buildPatch(16); break; }
514 case '4': { buildPatch(32); break; }
515 case '5': { buildPatch(64); break; }
516 case '6': { buildPatch(128); break; }
517 case 't': { usetorus_ = !usetorus_; break; }
518 case 'q': { glBindTexture(GL_TEXTURE_3D, texName1_); break; }
519 case 'w': { glBindTexture(GL_TEXTURE_3D, texName2_); break; }
520 case 'e': { glBindTexture(GL_TEXTURE_3D, texName3_); break; }
521 }
522
523 onDraw();
524 }
525
526 void CGTexture::onIdle() {
527 if (run_) {
528 glRotatef(.5, 0.0, 1.0, 0.0);
529 }
530 onDraw();
531 }
532
533 void CGTexture::onDraw() {
534 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
535
536 drawScene();
537 swapBuffers();
538 }
539
540 // Hauptprogramm
541 int main(int argc, char* argv[]) {
542 // Erzeuge eine Instanz der Beispiel-Anwendung:
543 CGTexture sample;
544
545 cout << "Tastenbelegung:" << endl
546 << "ESC Programm beenden" << endl
547 << "Leertaste Objekt drehen" << endl
548 << "+ Hineinzoomen" << endl
549 << "- Herauszoomen" << endl
550 << "t Torus oder Quadrat zeichnen" << endl
551 << "q gemischter Marmor" << endl
552 << "w schwarzer Marmor" << endl
553 << "e brauner Marmor" << endl
554 << "1-6 Tessellationsgrad des Torus (max=6)" << endl;
555
556 // Starte die Beispiel-Anwendung:
557 sample.start("Stephan Brumme, 702544", true, 256, 256);
558 return(0);
559 }
560