1 //
2 // Computergraphik II
3 // Prof. Dr. Juergen Doellner
4 // Wintersemester 2001/02
5 //
6 // Rahmenprogramm zu Aufgabenzettel 8
7 //
8
9 #include "cgtwopart.h"
10 #include <fstream.h>
11
12 typedef Vector Camera;
13 typedef Vector Color;
14
15 #ifndef PI
16 const double PI = 3.14159265358979323846;
17 #endif
18
19 const unsigned int BUF_SIZE = 1024;
20
21 //
22 // Application
23 //
24
25 CGTwoPart::CGTwoPart(char* filename) {
26 filename_ = filename;
27
28 stop_=true;
29 zoom_= 1.5;
30 mapping_ = SPHERE_INTERSECTION;
31
32 // read triangle data
33 ifstream s("triceratops.txt");
34 // ifstream s("triangle_small.txt");
35 s >> size_;
36
37 tris_ = new Triangle[size_];
38 center_ = Vector(0,0,0);
39
40 int i;
41 for (i = 0; i < size_; i++) {
42 s >> tris_[i];
43
44 // just scale object
45 tris_[i].setVertex(0, tris_[i].getVertex(0) * 0.1);
46 tris_[i].setVertex(1, tris_[i].getVertex(1) * 0.1);
47 tris_[i].setVertex(2, tris_[i].getVertex(2) * 0.1);
48
49 // add up all vectors
50 center_ += tris_[i].getVertex(0);
51 center_ += tris_[i].getVertex(1);
52 center_ += tris_[i].getVertex(2);
53 }
54
55 center_ *= 1/(3.0*size_);
56 }
57
58
59 CGTwoPart::~CGTwoPart() {
60 }
61
62
63
64 void CGTwoPart::onInit() {
65
66 // Tiefen Test aktivieren
67 glEnable(GL_DEPTH_TEST);
68
69 // Smooth Schattierung aktivieren
70 glShadeModel(GL_SMOOTH);
71
72 // Projection
73 glMatrixMode(GL_PROJECTION);
74 gluPerspective(60.0, 1.0, 2.0, 50.0);
75
76 // LookAt
77 glMatrixMode(GL_MODELVIEW);
78 gluLookAt(
79 0.0, 0.0, 4.0, // from (0,0,4)
80 0.0, 0.0, 0.0, // to (0,0,0)
81 0.0, 1.0, 0.); // up
82
83 glClearColor(0.9,0.9,0.9,1.0);
84
85 // Import texture from file
86 readImage();
87
88 glGenTextures(1, &texName_);
89 glBindTexture(GL_TEXTURE_2D, texName_);
90
91 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
92 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
93 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
94 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
95 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth_, texHeight_, 0, GL_RGB, GL_UNSIGNED_BYTE, image_);
96 }
97
98 void CGTwoPart::onSize(unsigned int newWidth,unsigned int newHeight) {
99 if((newWidth > 0) && (newHeight > 0)) {
100 // Passe den OpenGL-Viewport an die neue Fenstergroesse an:
101 glViewport(0, 0, newWidth - 1, newHeight - 1);
102
103 // Passe die OpenGL-Projektionsmatrix an die neue
104 // Fenstergroesse an:
105 glMatrixMode(GL_PROJECTION);
106 glLoadIdentity();
107 gluPerspective(40.0,float(newWidth)/float(newHeight),1.0, 10.0);
108
109 // Schalte zurueck auf die Modelview-Matrix
110 glMatrixMode(GL_MODELVIEW);
111 }
112 }
113
114 void CGTwoPart::onKey(unsigned char key) {
115 static GLfloat z = 3.;
116 switch (key) {
117 case 27: { exit(0); break; }
118 case '+': { zoom_*= 1.1; break; }
119 case '-': { zoom_*= 0.9; break; }
120 case 'l' : { glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); break; }
121 case 'f' : { glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); break; }
122 case 'c' : { if (glIsEnabled(GL_CULL_FACE)) { glDisable(GL_CULL_FACE); } else { glEnable(GL_CULL_FACE); } break; }
123 case 'q' : { mapping_ = SPHERE_INTERSECTION; break; }
124 case 'w' : { mapping_ = SPHERE_NORMAL; break; }
125 case 'e' : { mapping_ = CYLINDER_INTERSECTION; break; }
126 case 'r' : { mapping_ = CYLINDER_NORMAL; break; }
127 case ' ' : { stop_ = !stop_; break; }
128 }
129 onDraw();
130 }
131
132 void CGTwoPart::onIdle() {
133 if (!stop_) {
134 glRotatef(-2.0f,0,1,0.1);
135 onDraw();
136 }
137 }
138
139 inline double max(double x, double y) {
140 return (x<y) ? y : x;
141 }
142 inline double min(double x, double y) {
143 return (x>y) ? y : x;
144 }
145
146 Vector CGTwoPart::SphereIntersection(const Vector& point) const
147 {
148 // code taken from ray-sphere intersection of my raytracer
149
150 // ray origin
151 const Vector origin(center_);
152 const double x = origin[0];
153 const double y = origin[1];
154 const double z = origin[2];
155
156 // ray direction
157 const Vector direction(point-center_);
158 const double i = direction[0];
159 const double j = direction[1];
160 const double k = direction[2];
161
162 // sphere's center
163 const double r = 1.0;
164
165 // compute parameters a,b,c for at^2+bt+c=0
166 const double a = i*i + j*j + k*k;
167 const double b = 2*(i*x + j*y + k*z);
168 const double c = x*x+y*y+z*z - r*r;
169
170 // solve at^2+bt+c=0
171 // D = b^2-4ac
172 const double D = b*b-4*a*c;
173
174
175 // no intersection
176 if (D < 0)
177 return Vector(0,0,0);
178
179 // nearest ray intersection
180 double t;
181
182 if (D > 0)
183 {
184 // two intersections
185 // ray parameter
186 const double t1 = (-b + sqrt(D))/(2*a);
187 const double t2 = (-b - sqrt(D))/(2*a);
188 t = min(t1,t2);
189 if (t < 0)
190 t = max(t1,t2);
191 }
192 else
193 // only one intersection
194 t = -b/(2*a);
195
196 return SphereSurfaceToTexture(origin + t*direction);
197 }
198
199 Vector CGTwoPart::SphereNormal(const Vector& point) const
200 {
201 return SphereSurfaceToTexture(point.normalized());
202 }
203
204 Vector CGTwoPart::SphereSurfaceToTexture(const Vector& surface) const
205 {
206 const double x_distortion = sin(acos(surface[1]));
207
208 // first texture coordinate
209 double s = 1.0;
210 if (x_distortion != 0.0)
211 {
212 s = acos(surface[0] / x_distortion) / (2*PI);
213 if (surface[2] > 0.0)
214 s = 1-s;
215 }
216
217 // rotate by 180°
218 s += 0.5;
219 if (s > 1)
220 s -= 1;
221
222 // second texture coordinate
223 double t = acos(surface[1]) / PI;
224
225 return Vector(s,t);
226 }
227
228 Vector CGTwoPart::CylinderIntersection(const Vector& point) const
229 {
230 // radius
231 const double r = 0.5;
232
233 // origin of line
234 const double x = center_[0];
235 const double z = center_[2];
236
237 // direction
238 const double i = point[0] - x;
239 const double j = point[2] - z;
240
241 // no degenerated lines
242 if (i==0 && j==0)
243 return Vector(0,0,0);
244
245 // 0 = tē+pt+q
246 const double p = 2*(i*x+j*z) / (i*i+j*j);
247 const double q = (x*x+z*z-r*r) / (i*i+j*j);
248
249 // square root
250 const double D = (p*p/4)-q;
251 // no solution
252 if (D < 0)
253 return Vector(0,0,0);
254
255 // t1 may be equal to t2 but that doesn't matter
256 const double t1 = -p/2 + sqrt(D);
257 const double t2 = -p/2 - sqrt(D);
258
259 // nearest intersetion
260 double intersect = min(t1,t2);
261 if (intersect < 0)
262 intersect = max(t1,t2);
263
264 // move point to the cylinder's surface and get texture coordinates
265 return CylinderSurfaceToTexture(center_ + intersect*(point-center_));
266 }
267
268 Vector CGTwoPart::CylinderNormal(const Vector& point) const
269 {
270 // distance to y axis
271 const double distance_to_y_axis = sqrt(point[0]*point[0] + point[2]*point[2]);
272 const double radius = 0.5;
273
274 // move point to the cylinder's surface
275 const Vector surface(point[0] / (distance_to_y_axis/radius),
276 point[1],
277 point[2] / (distance_to_y_axis/radius));
278
279 // get texture s,t
280 return CylinderSurfaceToTexture(surface);
281 }
282
283 Vector CGTwoPart::CylinderSurfaceToTexture(const Vector& surface) const
284 {
285 const double radius = 0.5;
286 // determine rotation angle
287 double s = acos(surface[0]/radius) / (2*PI);
288 if (surface[2] > 0.0)
289 s = 1-s;
290
291 // rotate again by 180°
292 s += 0.5;
293 if (s > 1)
294 s -= 1;
295
296 // t comes from da height
297 double t = 1 - (surface[1] + 0.5);
298 if (t < 0)
299 t = 0;
300 if (t > 1)
301 t = 1;
302
303 return Vector(s,t);
304 }
305
306 void CGTwoPart::handleVertex(const Vector& v) const{
307 // texturing ...
308 Vector texCoord;
309
310 switch (mapping_)
311 {
312 case SPHERE_INTERSECTION: texCoord = SphereIntersection(v);
313 break;
314 case SPHERE_NORMAL: texCoord = SphereNormal(v);
315 break;
316 case CYLINDER_INTERSECTION: texCoord = CylinderIntersection(v);
317 break;
318 case CYLINDER_NORMAL: texCoord = CylinderNormal(v);
319 break;
320 }
321 glTexCoord2d(texCoord[0], texCoord[1]);
322
323 glVertex3dv(v.rep());
324 }
325
326 void CGTwoPart::onDraw() {
327 // Loesche den Farb- und Tiefenspeicher
328 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
329
330
331 glPushMatrix();
332 // glRotatef(-30,0,1,0);
333 glScaled(zoom_, zoom_, zoom_);
334
335 glEnable(GL_TEXTURE_2D);
336 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
337 glBindTexture(GL_TEXTURE_2D, texName_);
338
339 glBegin(GL_TRIANGLES);
340 for (int i=0; i<size_; i++) {
341 for (int k = 0; k < 3; k++) {
342 handleVertex(tris_[i].getVertex(k));
343 }
344 }
345 glEnd();
346 glDisable(GL_TEXTURE_2D);
347
348 glPopMatrix();
349
350 // Nicht vergessen! Front- und Back-Buffer tauschen:
351 swapBuffers();
352 }
353
354 void CGTwoPart::readImage() {
355
356 char buf[BUF_SIZE];
357
358 // create input stream
359 ifstream in(filename_);
360 if(!in) {
361 cerr << "no ppm image" << endl;
362 exit(-1);
363 }
364
365 cout << "Reading image from file \"" << filename_ << "\" " << endl;
366
367 // PPM header
368 #ifdef _MSC_VER
369 in >> binary;
370 #endif
371
372 // Read "P6"
373 char ppm;
374 in >> ppm; if(!in.good() || ppm != 'P') { cerr << "ppm format error" << endl; }
375 in >> ppm; if(!in.good() || ppm != '6') { cerr << "ppm format error" << endl; }
376
377 // forward to next line
378 in.getline(buf, BUF_SIZE);
379
380 // normally read comments, but we assume that no comments are there
381 // in.getline(buf, BUF_SIZE);
382 // while (buf[0] == '#')
383 // in.getline(buf, BUF_SIZE);
384
385 // Read width and height
386 in >> texWidth_; if(!in.good()) { cerr << "ppm format error" << endl; }
387 in >> texHeight_; if(!in.good()) { cerr << "ppm format error" << endl; }
388
389 // Read 255
390 unsigned int res;
391 in >> res; if(!in.good() || res != 255) { cerr << "ppm format error" << endl; }
392
393 // forward to next line
394 in.getline(buf, BUF_SIZE);
395
396 image_ = new GLubyte [3 * texWidth_ * texHeight_];
397 in.read(image_, 3 * texWidth_ * texHeight_);
398 if(!in.good()) { cerr << "ppm format error" << endl; }
399
400 // for creating an image with an alpha channel - but we don't need this?
401 /*
unsigned char rgba[4];
rgba[3] = 255; // alpha value
for(int i=0; i<texWidth_; i++)
for(int j=0; j<texHeight_; j++) {
in.read(rgba, 3);
if(!in.good()) { cerr << "ppm format error" << endl; }
for (int k=0; k<4; k++) {
image_[k + j*4 + i*(4*texHeight_)] = rgba[k];
}
}
*/
402 in.close();
403 }
404
405 // Hauptprogramm
406 int main(int argc, char* argv[]) {
407 // Erzeuge eine Instanz der Beispiel-Anwendung:
408 CGTwoPart sample("map.ppm");
409 // CGTwoPart sample("church_spiral.ppm");
410
411 cout << "Tastenbelegung:" << endl
412 << "ESC Programm beenden" << endl
413 << "Leertaste Objekt drehen" << endl
414 << "+ Hineinzoomen" << endl
415 << "- Herauszoomen" << endl
416 << "q Kugel-Intersektions-Mapping" << endl
417 << "w Kugel-Normalen-Mapping" << endl
418 << "e Zylinder-Intersektions-Mapping" << endl
419 << "r Zylinder-Normalen-Mapping" << endl
420 << "l Drahtgittermodell" << endl
421 << "f Texturieren" << endl
422 << "c Verdeckte Flaechen zeichnen an/aus" << endl;
423
424 // Starte die Beispiel-Anwendung:
425 sample.start("Stephan Brumme, 702544", true, 512, 512);
426 return(0);
427 }
428