]> git.saurik.com Git - wxWidgets.git/blob - samples/opengl/penguin/lw.cpp
patch fix for a constant definition under OS/2 VA V4.0
[wxWidgets.git] / samples / opengl / penguin / lw.cpp
1 /*
2 * Copyright (C) 1998 Janne Löf <jlof@mail.student.oulu.fi>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifdef __WXMSW__
20 #include <windows.h>
21 #endif
22
23 #include "lw.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <math.h>
27
28 #if !defined(__WXMAC__) || defined(__DARWIN__)
29 // these must be defined in the precompiled headers under CodeWarrior
30 #define wxInt32 int
31 #define wxUint32 unsigned int
32 #endif
33
34 #ifndef FALSE
35 #define FALSE 0
36 #endif
37
38 #ifndef TRUE
39 #define TRUE 1
40 #endif
41
42 #define MK_ID(a,b,c,d) ((((wxUint32)(a))<<24)| \
43 (((wxUint32)(b))<<16)| \
44 (((wxUint32)(c))<< 8)| \
45 (((wxUint32)(d)) ))
46
47 #define ID_FORM MK_ID('F','O','R','M')
48 #define ID_LWOB MK_ID('L','W','O','B')
49 #define ID_PNTS MK_ID('P','N','T','S')
50 #define ID_SRFS MK_ID('S','R','F','S')
51 #define ID_SURF MK_ID('S','U','R','F')
52 #define ID_POLS MK_ID('P','O','L','S')
53 #define ID_COLR MK_ID('C','O','L','R')
54
55 static wxInt32 read_char(FILE *f)
56 {
57 int c = fgetc(f);
58 return c;
59 }
60
61 static wxInt32 read_short(FILE *f)
62 {
63 // the execution path was not always correct
64 // when using the direct evaluation in the return statement
65 wxInt32 first = read_char(f) ;
66 wxInt32 second = read_char(f) ;
67
68 return (first<<8) | second ;
69 }
70
71 static wxInt32 read_long(FILE *f)
72 {
73 // the execution path was not always correct
74 // when using the direct evaluation in the return statement
75 wxInt32 first = read_char(f) ;
76 wxInt32 second = read_char(f) ;
77 wxInt32 third = read_char(f) ;
78 wxInt32 fourth = read_char(f) ;
79 return (first<<24) | (second<<16) | (third<<8) | fourth ;
80 }
81
82 static GLfloat read_float(FILE *f)
83 {
84 wxInt32 x = read_long(f);
85 return *(GLfloat*)&x;
86 }
87
88 static int read_string(FILE *f, char *s)
89 {
90 int c;
91 int cnt = 0;
92 do {
93 c = read_char(f);
94 if (cnt < LW_MAX_NAME_LEN)
95 s[cnt] = c;
96 else
97 s[LW_MAX_NAME_LEN-1] = 0;
98 cnt++;
99 } while (c != 0);
100 /* if length of string (including \0) is odd skip another byte */
101 if (cnt%2) {
102 read_char(f);
103 cnt++;
104 }
105 return cnt;
106 }
107
108 static void read_srfs(FILE *f, int nbytes, lwObject *lwo)
109 {
110 int guess_cnt = lwo->material_cnt;
111
112 while (nbytes > 0) {
113 lwMaterial *material;
114
115 /* allocate more memory for materials if needed */
116 if (guess_cnt <= lwo->material_cnt) {
117 guess_cnt += guess_cnt/2 + 4;
118 lwo->material = (lwMaterial*) realloc(lwo->material, sizeof(lwMaterial)*guess_cnt);
119 }
120 material = lwo->material + lwo->material_cnt++;
121
122 /* read name */
123 nbytes -= read_string(f,material->name);
124
125 /* defaults */
126 material->r = 0.7;
127 material->g = 0.7;
128 material->b = 0.7;
129 }
130 lwo->material = (lwMaterial*) realloc(lwo->material, sizeof(lwMaterial)*lwo->material_cnt);
131 }
132
133
134 static void read_surf(FILE *f, int nbytes, lwObject *lwo)
135 {
136 int i;
137 char name[LW_MAX_NAME_LEN];
138 lwMaterial *material = NULL;
139
140 /* read surface name */
141 nbytes -= read_string(f,name);
142
143 /* find material */
144 for (i=0; i< lwo->material_cnt; i++) {
145 if (strcmp(lwo->material[i].name,name) == 0) {
146 material = &lwo->material[i];
147 break;
148 }
149 }
150
151 /* read values */
152 while (nbytes > 0) {
153 int id = read_long(f);
154 int len = read_short(f);
155 nbytes -= 6 + len + (len%2);
156
157 switch (id) {
158 case ID_COLR:
159 material->r = read_char(f) / 255.0;
160 material->g = read_char(f) / 255.0;
161 material->b = read_char(f) / 255.0;
162 read_char(f); /* dummy */
163 break;
164 default:
165 fseek(f, len+(len%2), SEEK_CUR);
166 }
167 }
168 }
169
170
171 static void read_pols(FILE *f, int nbytes, lwObject *lwo)
172 {
173 int guess_cnt = lwo->face_cnt;
174
175 while (nbytes > 0) {
176 lwFace *face;
177 int i;
178
179 /* allocate more memory for polygons if necessary */
180 if (guess_cnt <= lwo->face_cnt) {
181 guess_cnt += guess_cnt + 4;
182 lwo->face = (lwFace*) realloc((void*) lwo->face, sizeof(lwFace)*guess_cnt);
183 }
184 face = lwo->face + lwo->face_cnt++;
185
186 /* number of points in this face */
187 face->index_cnt = read_short(f);
188 nbytes -= 2;
189
190 /* allocate space for points */
191 face->index = (int*) calloc(sizeof(int)*face->index_cnt,1);
192
193 /* read points in */
194 for (i=0; i<face->index_cnt; i++) {
195 face->index[i] = read_short(f);
196 nbytes -= 2;
197 }
198
199 /* read surface material */
200 face->material = read_short(f);
201 nbytes -= 2;
202
203 /* skip over detail polygons */
204 if (face->material < 0) {
205 int det_cnt;
206 face->material = -face->material;
207 det_cnt = read_short(f);
208 nbytes -= 2;
209 while (det_cnt-- > 0) {
210 int cnt = read_short(f);
211 fseek(f, cnt*2+2, SEEK_CUR);
212 nbytes -= cnt*2+2;
213 }
214 }
215 face->material -= 1;
216 }
217 /* readjust to true size */
218 lwo->face = (lwFace*) realloc(lwo->face, sizeof(lwFace)*lwo->face_cnt);
219 }
220
221
222
223 static void read_pnts(FILE *f, int nbytes, lwObject *lwo)
224 {
225 int i;
226 lwo->vertex_cnt = nbytes / 12;
227 lwo->vertex = (float*) calloc(sizeof(GLfloat)*lwo->vertex_cnt*3, 1);
228 for (i=0; i<lwo->vertex_cnt; i++) {
229 lwo->vertex[i*3+0] = read_float(f);
230 lwo->vertex[i*3+1] = read_float(f);
231 lwo->vertex[i*3+2] = read_float(f);
232 }
233 }
234
235
236
237
238
239
240 int lw_is_lwobject(const char *lw_file)
241 {
242 FILE *f = fopen(lw_file, "rb");
243 if (f) {
244 wxInt32 form = read_long(f);
245 wxInt32 nlen = read_long(f);
246 wxInt32 lwob = read_long(f);
247 fclose(f);
248 if (form == ID_FORM && nlen != 0 && lwob == ID_LWOB)
249 return TRUE;
250 }
251 return FALSE;
252 }
253
254
255 lwObject *lw_object_read(const char *lw_file)
256 {
257 FILE *f = NULL;
258 lwObject *lw_object = NULL;
259
260 wxInt32 form_bytes = 0;
261 wxInt32 read_bytes = 0;
262
263 /* open file */
264 f = fopen(lw_file, "rb");
265 if (f == NULL) {
266 return NULL;
267 }
268
269 /* check for headers */
270 if (read_long(f) != ID_FORM) {
271 fclose(f);
272 return NULL;
273 }
274 form_bytes = read_long(f);
275 read_bytes += 4;
276
277 if (read_long(f) != ID_LWOB) {
278 fclose(f);
279 return NULL;
280 }
281
282 /* create new lwObject */
283 lw_object = (lwObject*) calloc(sizeof(lwObject),1);
284
285 /* read chunks */
286 while (read_bytes < form_bytes) {
287 wxInt32 id = read_long(f);
288 wxInt32 nbytes = read_long(f);
289 read_bytes += 8 + nbytes + (nbytes%2);
290
291 switch (id) {
292 case ID_PNTS:
293 read_pnts(f, nbytes, lw_object);
294 break;
295 case ID_POLS:
296 read_pols(f, nbytes, lw_object);
297 break;
298 case ID_SRFS:
299 read_srfs(f, nbytes, lw_object);
300 break;
301 case ID_SURF:
302 read_surf(f, nbytes, lw_object);
303 break;
304 default:
305 fseek(f, nbytes + (nbytes%2), SEEK_CUR);
306 }
307 }
308
309 fclose(f);
310 return lw_object;
311 }
312
313
314
315 void lw_object_free(lwObject *lw_object)
316 {
317 if (lw_object->face) {
318 int i;
319 for (i=0; i<lw_object->face_cnt; i++)
320 free(lw_object->face[i].index);
321 free(lw_object->face);
322 }
323 free(lw_object->material);
324 free(lw_object->vertex);
325 free(lw_object);
326 }
327
328
329
330
331
332 #define PX(i) (lw_object->vertex[face->index[i]*3+0])
333 #define PY(i) (lw_object->vertex[face->index[i]*3+1])
334 #define PZ(i) (lw_object->vertex[face->index[i]*3+2])
335 void lw_object_show(const lwObject *lw_object)
336 {
337 int i,j;
338 int prev_index_cnt = -1;
339 int prev_material = -1;
340 GLfloat prev_nx = 0;
341 GLfloat prev_ny = 0;
342 GLfloat prev_nz = 0;
343
344 for (i=0; i<lw_object->face_cnt; i++) {
345 GLfloat ax,ay,az,bx,by,bz,nx,ny,nz,r;
346 const lwFace *face = lw_object->face+i;
347
348 /* ignore faces with less than 3 points */
349 if (face->index_cnt < 3)
350 continue;
351
352 /* calculate normal */
353 ax = PX(1) - PX(0);
354 ay = PY(1) - PY(0);
355 az = PZ(1) - PZ(0);
356
357 bx = PX(face->index_cnt-1) - PX(0);
358 by = PY(face->index_cnt-1) - PY(0);
359 bz = PZ(face->index_cnt-1) - PZ(0);
360
361 nx = ay * bz - az * by;
362 ny = az * bx - ax * bz;
363 nz = ax * by - ay * bx;
364
365 r = sqrt(nx*nx + ny*ny + nz*nz);
366 if (r < 0.000001) /* avoid division by zero */
367 continue;
368 nx /= r;
369 ny /= r;
370 nz /= r;
371
372 /* glBegin/glEnd */
373 if (prev_index_cnt != face->index_cnt || prev_index_cnt > 4) {
374 if (prev_index_cnt > 0) glEnd();
375 prev_index_cnt = face->index_cnt;
376 switch (face->index_cnt) {
377 case 3:
378 glBegin(GL_TRIANGLES);
379 break;
380 case 4:
381 glBegin(GL_QUADS);
382 break;
383 default:
384 glBegin(GL_POLYGON);
385 }
386 }
387
388 /* update material if necessary */
389 if (prev_material != face->material) {
390 prev_material = face->material;
391 glColor3f(lw_object->material[face->material].r,
392 lw_object->material[face->material].g,
393 lw_object->material[face->material].b);
394 }
395
396 /* update normal if necessary */
397 if (nx != prev_nx || ny != prev_ny || nz != prev_nz) {
398 prev_nx = nx;
399 prev_ny = ny;
400 prev_nz = nz;
401 glNormal3f(nx,ny,nz);
402 }
403
404 /* draw polygon/triangle/quad */
405 for (j=0; j<face->index_cnt; j++)
406 glVertex3f(PX(j),PY(j),PZ(j));
407
408 }
409
410 /* if glBegin was called call glEnd */
411 if (prev_index_cnt > 0)
412 glEnd();
413 }
414
415
416 GLfloat lw_object_radius(const lwObject *lwo)
417 {
418 int i;
419 double max_radius = 0.0;
420
421 for (i=0; i<lwo->vertex_cnt; i++) {
422 GLfloat *v = &lwo->vertex[i*3];
423 double r = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
424 if (r > max_radius)
425 max_radius = r;
426 }
427 return sqrt(max_radius);
428 }
429
430 void lw_object_scale(lwObject *lwo, GLfloat scale)
431 {
432 int i;
433
434 for (i=0; i<lwo->vertex_cnt; i++) {
435 lwo->vertex[i*3+0] *= scale;
436 lwo->vertex[i*3+1] *= scale;
437 lwo->vertex[i*3+2] *= scale;
438 }
439 }
440
441