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