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