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