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 // code taken from ray-sphere intersection of my raytracer
148
149 // ray origin
150 const Vector origin(center_);
151 const double x = origin[0];
152 const double y = origin[1];
153 const double z = origin[2];
154
155 // ray direction
156 const Vector direction(point-center_);
157 const double i = direction[0];
158 const double j = direction[1];
159 const double k = direction[2];
160
161 // sphere's center
162 const double r = 1.0;
163
164 // compute parameters a,b,c for at^2+bt+c=0
165 const double a = i*i + j*j + k*k;
166 const double b = 2*(i*x + j*y + k*z);
167 const double c = x*x+y*y+z*z - r*r;
168
169 // solve at^2+bt+c=0
170 // D = b^2-4ac
171 const double D = b*b-4*a*c;
172
173
174 // no intersection
175 if (D < 0)
176 return Vector(0,0,0);
177
178 // nearest ray intersection
179 double t;
180
181 if (D > 0)
182 {
183 // two intersections
184 // ray parameter
185 const double t1 = (-b + sqrt(D))/(2*a);
186 const double t2 = (-b - sqrt(D))/(2*a);
187 t = min(t1,t2);
188 if (t < 0)
189 t = max(t1,t2);
190 }
191 else
// only one intersection
192 t = -b/(2*a);
193
194 return SphereSurfaceToTexture(origin + t*direction);
195 }
196
197 Vector CGTwoPart::SphereNormal(const Vector& point) const
{
198 return SphereSurfaceToTexture(point.normalized());
199 }
200
201 Vector CGTwoPart::SphereSurfaceToTexture(const Vector& surface) const
{
202 const double x_distortion = sin(acos(surface[1]));
203
204 // first texture coordinate
205 double s = 1.0;
206 if (x_distortion != 0.0)
207 {
208 s = acos(surface[0] / x_distortion) / (2*PI);
209 if (surface[2] > 0.0)
210 s = 1-s;
211 }
212
213 // rotate by 180°
214 s += 0.5;
215 if (s > 1)
216 s -= 1;
217
218 // second texture coordinate
219 double t = acos(surface[1]) / PI;
220
221 return Vector(s,t);
222 }
223
224 Vector CGTwoPart::CylinderIntersection(const Vector& point) const
{
225 // radius
226 const double r = 0.5;
227
228 // origin of line
229 const double x = center_[0];
230 const double z = center_[2];
231
232 // direction
233 const double i = point[0] - x;
234 const double j = point[2] - z;
235
236 // no degenerated lines
237 if (i==0 && j==0)
238 return Vector(0,0,0);
239
240 // 0 = tē+pt+q
241 const double p = 2*(i*x+j*z) / (i*i+j*j);
242 const double q = (x*x+z*z-r*r) / (i*i+j*j);
243
244 // square root
245 const double D = (p*p/4)-q;
246 // no solution
247 if (D < 0)
248 return Vector(0,0,0);
249
250 // t1 may be equal to t2 but that doesn't matter
251 const double t1 = -p/2 + sqrt(D);
252 const double t2 = -p/2 - sqrt(D);
253
254 // nearest intersetion
255 double intersect = min(t1,t2);
256 if (intersect < 0)
257 intersect = max(t1,t2);
258
259 // move point to the cylinder's surface and get texture coordinates
260 return CylinderSurfaceToTexture(center_ + intersect*(point-center_));
261 }
262
263 Vector CGTwoPart::CylinderNormal(const Vector& point) const
{
264 // distance to y axis
265 const double distance_to_y_axis = sqrt(point[0]*point[0] + point[2]*point[2]);
266 const double radius = 0.5;
267
268 // move point to the cylinder's surface
269 const Vector surface(point[0] / (distance_to_y_axis/radius),
270 point[1],
271 point[2] / (distance_to_y_axis/radius));
272
273 // get texture s,t
274 return CylinderSurfaceToTexture(surface);
275 }
276
277 Vector CGTwoPart::CylinderSurfaceToTexture(const Vector& surface) const
{
278 const double radius = 0.5;
279 // determine rotation angle
280 double s = acos(surface[0]/radius) / (2*PI);
281 if (surface[2] > 0.0)
282 s = 1-s;
283
284 // rotate again by 180°
285 s += 0.5;
286 if (s > 1)
287 s -= 1;
288
289 // t comes from da height
290 double t = 1 - (surface[1] + 0.5);
291 if (t < 0)
292 t = 0;
293 if (t > 1)
294 t = 1;
295
296 return Vector(s,t);
297 }
298
299 void CGTwoPart::handleVertex(const Vector& v) const{
300 // texturing ...
301 Vector texCoord;
302
303 switch (mapping_)
304 {
305 case SPHERE_INTERSECTION: texCoord = SphereIntersection(v);
306 break;
307 case SPHERE_NORMAL: texCoord = SphereNormal(v);
308 break;
309 case CYLINDER_INTERSECTION: texCoord = CylinderIntersection(v);
310 break;
311 case CYLINDER_NORMAL: texCoord = CylinderNormal(v);
312 break;
313 }
314 glTexCoord2d(texCoord[0], texCoord[1]);
315
316 glVertex3dv(v.rep());
317 }
318
319 void CGTwoPart::onDraw() {
320 // Loesche den Farb- und Tiefenspeicher
321 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
322
323
324 glPushMatrix();
325 // glRotatef(-30,0,1,0);
326 glScaled(zoom_, zoom_, zoom_);
327
328 glEnable(GL_TEXTURE_2D);
329 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
330 glBindTexture(GL_TEXTURE_2D, texName_);
331
332 glBegin(GL_TRIANGLES);
333 for (int i=0; i<size_; i++) {
334 for (int k = 0; k < 3; k++) {
335 handleVertex(tris_[i].getVertex(k));
336 }
337 }
338 glEnd();
339 glDisable(GL_TEXTURE_2D);
340
341 glPopMatrix();
342
343 // Nicht vergessen! Front- und Back-Buffer tauschen:
344 swapBuffers();
345 }
346
347 void CGTwoPart::readImage() {
348
349 char buf[BUF_SIZE];
350
351 // create input stream
352 ifstream in(filename_);
353 if(!in) {
354 cerr << "no ppm image" << endl;
355 exit(-1);
356 }
357
358 cout << "Reading image from file \"" << filename_ << "===>\<===" " << endl;
359
360 // PPM header
361 #ifdef _MSC_VER
362 in >> binary;
363 #endif
364
365 // Read "P6"
366 char ppm;
367 in >> ppm; if(!in.good() || ppm != 'P') { cerr << "ppm format error" << endl; }
368 in >> ppm; if(!in.good() || ppm != '6') { cerr << "ppm format error" << endl; }
369
370 // forward to next line
371 in.getline(buf, BUF_SIZE);
372
373 // normally read comments, but we assume that no comments are there
374 // in.getline(buf, BUF_SIZE);
375 // while (buf[0] == '#')
376 // in.getline(buf, BUF_SIZE);
377
378 // Read width and height
379 in >> texWidth_; if(!in.good()) { cerr << "ppm format error" << endl; }
380 in >> texHeight_; if(!in.good()) { cerr << "ppm format error" << endl; }
381
382 // Read 255
383 unsigned int res;
384 in >> res; if(!in.good() || res != 255) { cerr << "ppm format error" << endl; }
385
386 // forward to next line
387 in.getline(buf, BUF_SIZE);
388
389 image_ = new GLubyte [3 * texWidth_ * texHeight_];
390 in.read(image_, 3 * texWidth_ * texHeight_);
391 if(!in.good()) { cerr << "ppm format error" << endl; }
392
393 // for creating an image with an alpha channel - but we don't need this?
394 /*
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];
}
}
*/
395 in.close();
396 }
397
398 // Hauptprogramm
399 int main(int argc, char* argv[]) {
400 // Erzeuge eine Instanz der Beispiel-Anwendung:
401 CGTwoPart sample("map.ppm");
402 // CGTwoPart sample("church_spiral.ppm");
403
404 cout << "Tastenbelegung:" << endl
<< "ESC Programm beenden" << endl
<< "Leertaste Objekt drehen" << endl
<< "+ Hineinzoomen" << endl
<< "- Herauszoomen" << endl
<< "q Kugel-Intersektions-Mapping" << endl
<< "w Kugel-Normalen-Mapping" << endl
<< "e Zylinder-Intersektions-Mapping" << endl
<< "r Zylinder-Normalen-Mapping" << endl
<< "l Drahtgittermodell" << endl
<< "f Texturieren" << endl
<< "c Verdeckte Flaechen zeichnen an/aus" << endl;
405
406 // Starte die Beispiel-Anwendung:
407 sample.start("Stephan Brumme, 702544", true, 512, 512);
408 return(0);
409 }
410