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