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