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