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