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