Fix accidental switch/teleporter behavior changes
[neverball] / share / solid.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 #include "solid.h"
20 #include "base_config.h"
21 #include "binary.h"
22 #include "fs.h"
23
24 enum
25 {
26     SOL_VER_MINIMUM = 6,
27     SOL_VER_PATH_FLAGS,
28     SOL_VER_CURRENT = SOL_VER_PATH_FLAGS
29 };
30
31 #define MAGIC (0xAF | 'S' << 8 | 'O' << 16 | 'L' << 24)
32
33 /*---------------------------------------------------------------------------*/
34
35 static int sol_version;
36
37 static int sol_file(fs_file fin)
38 {
39     int magic;
40     int version;
41
42     get_index(fin, &magic);
43     get_index(fin, &version);
44
45     if (magic != MAGIC || (version < SOL_VER_MINIMUM ||
46                            version > SOL_VER_CURRENT))
47         return 0;
48
49     sol_version = version;
50
51     return 1;
52 }
53
54 static void sol_load_mtrl(fs_file fin, struct s_mtrl *mp)
55 {
56     get_array(fin,  mp->d, 4);
57     get_array(fin,  mp->a, 4);
58     get_array(fin,  mp->s, 4);
59     get_array(fin,  mp->e, 4);
60     get_array(fin,  mp->h, 1);
61     get_index(fin, &mp->fl);
62
63     fs_read(mp->f, 1, PATHMAX, fin);
64 }
65
66 static void sol_load_vert(fs_file fin, struct s_vert *vp)
67 {
68     get_array(fin,  vp->p, 3);
69 }
70
71 static void sol_load_edge(fs_file fin, struct s_edge *ep)
72 {
73     get_index(fin, &ep->vi);
74     get_index(fin, &ep->vj);
75 }
76
77 static void sol_load_side(fs_file fin, struct s_side *sp)
78 {
79     get_array(fin,  sp->n, 3);
80     get_float(fin, &sp->d);
81 }
82
83 static void sol_load_texc(fs_file fin, struct s_texc *tp)
84 {
85     get_array(fin,  tp->u, 2);
86 }
87
88 static void sol_load_geom(fs_file fin, struct s_geom *gp)
89 {
90     get_index(fin, &gp->mi);
91     get_index(fin, &gp->ti);
92     get_index(fin, &gp->si);
93     get_index(fin, &gp->vi);
94     get_index(fin, &gp->tj);
95     get_index(fin, &gp->sj);
96     get_index(fin, &gp->vj);
97     get_index(fin, &gp->tk);
98     get_index(fin, &gp->sk);
99     get_index(fin, &gp->vk);
100 }
101
102 static void sol_load_lump(fs_file fin, struct s_lump *lp)
103 {
104     get_index(fin, &lp->fl);
105     get_index(fin, &lp->v0);
106     get_index(fin, &lp->vc);
107     get_index(fin, &lp->e0);
108     get_index(fin, &lp->ec);
109     get_index(fin, &lp->g0);
110     get_index(fin, &lp->gc);
111     get_index(fin, &lp->s0);
112     get_index(fin, &lp->sc);
113 }
114
115 static void sol_load_node(fs_file fin, struct s_node *np)
116 {
117     get_index(fin, &np->si);
118     get_index(fin, &np->ni);
119     get_index(fin, &np->nj);
120     get_index(fin, &np->l0);
121     get_index(fin, &np->lc);
122 }
123
124 static void sol_load_path(fs_file fin, struct s_path *pp)
125 {
126     get_array(fin,  pp->p, 3);
127     get_float(fin, &pp->t);
128     get_index(fin, &pp->pi);
129     get_index(fin, &pp->f);
130     get_index(fin, &pp->s);
131
132     if (sol_version >= SOL_VER_PATH_FLAGS)
133         get_index(fin, &pp->fl);
134
135     pp->e[0] = 1.0f;
136     pp->e[1] = 0.0f;
137     pp->e[2] = 0.0f;
138     pp->e[3] = 0.0f;
139
140     if (pp->fl & P_ORIENTED)
141         get_array(fin, pp->e, 4);
142 }
143
144 static void sol_load_body(fs_file fin, struct s_body *bp)
145 {
146     get_index(fin, &bp->pi);
147     get_index(fin, &bp->ni);
148     get_index(fin, &bp->l0);
149     get_index(fin, &bp->lc);
150     get_index(fin, &bp->g0);
151     get_index(fin, &bp->gc);
152 }
153
154 static void sol_load_item(fs_file fin, struct s_item *hp)
155 {
156     get_array(fin,  hp->p, 3);
157     get_index(fin, &hp->t);
158     get_index(fin, &hp->n);
159 }
160
161 static void sol_load_goal(fs_file fin, struct s_goal *zp)
162 {
163     get_array(fin,  zp->p, 3);
164     get_float(fin, &zp->r);
165 }
166
167 static void sol_load_swch(fs_file fin, struct s_swch *xp)
168 {
169     get_array(fin,  xp->p, 3);
170     get_float(fin, &xp->r);
171     get_index(fin, &xp->pi);
172     get_float(fin, &xp->t0);
173     get_float(fin, &xp->t);
174     get_index(fin, &xp->f0);
175     get_index(fin, &xp->f);
176     get_index(fin, &xp->i);
177 }
178
179 static void sol_load_bill(fs_file fin, struct s_bill *rp)
180 {
181     get_index(fin, &rp->fl);
182     get_index(fin, &rp->mi);
183     get_float(fin, &rp->t);
184     get_float(fin, &rp->d);
185     get_array(fin,  rp->w,  3);
186     get_array(fin,  rp->h,  3);
187     get_array(fin,  rp->rx, 3);
188     get_array(fin,  rp->ry, 3);
189     get_array(fin,  rp->rz, 3);
190     get_array(fin,  rp->p,  3);
191 }
192
193 static void sol_load_jump(fs_file fin, struct s_jump *jp)
194 {
195     get_array(fin,  jp->p, 3);
196     get_array(fin,  jp->q, 3);
197     get_float(fin, &jp->r);
198 }
199
200 static void sol_load_ball(fs_file fin, struct s_ball *bp)
201 {
202     get_array(fin,  bp->p, 3);
203     get_float(fin, &bp->r);
204
205     bp->e[0][0] = bp->E[0][0] = 1.0f;
206     bp->e[0][1] = bp->E[0][1] = 0.0f;
207     bp->e[0][2] = bp->E[0][2] = 0.0f;
208
209     bp->e[1][0] = bp->E[1][0] = 0.0f;
210     bp->e[1][1] = bp->E[1][1] = 1.0f;
211     bp->e[1][2] = bp->E[1][2] = 0.0f;
212
213     bp->e[2][0] = bp->E[2][0] = 0.0f;
214     bp->e[2][1] = bp->E[2][1] = 0.0f;
215     bp->e[2][2] = bp->E[2][2] = 1.0f;
216 }
217
218 static void sol_load_view(fs_file fin, struct s_view *wp)
219 {
220     get_array(fin,  wp->p, 3);
221     get_array(fin,  wp->q, 3);
222 }
223
224 static void sol_load_dict(fs_file fin, struct s_dict *dp)
225 {
226     get_index(fin, &dp->ai);
227     get_index(fin, &dp->aj);
228 }
229
230 static void sol_load_indx(fs_file fin, struct s_file *fp)
231 {
232     get_index(fin, &fp->ac);
233     get_index(fin, &fp->dc);
234     get_index(fin, &fp->mc);
235     get_index(fin, &fp->vc);
236     get_index(fin, &fp->ec);
237     get_index(fin, &fp->sc);
238     get_index(fin, &fp->tc);
239     get_index(fin, &fp->gc);
240     get_index(fin, &fp->lc);
241     get_index(fin, &fp->nc);
242     get_index(fin, &fp->pc);
243     get_index(fin, &fp->bc);
244     get_index(fin, &fp->hc);
245     get_index(fin, &fp->zc);
246     get_index(fin, &fp->jc);
247     get_index(fin, &fp->xc);
248     get_index(fin, &fp->rc);
249     get_index(fin, &fp->uc);
250     get_index(fin, &fp->wc);
251     get_index(fin, &fp->ic);
252 }
253
254 static int sol_load_file(fs_file fin, struct s_file *fp)
255 {
256     int i;
257
258     if (!sol_file(fin))
259         return 0;
260
261     sol_load_indx(fin, fp);
262
263     if (fp->ac)
264         fp->av = (char          *) calloc(fp->ac, sizeof (char));
265     if (fp->mc)
266         fp->mv = (struct s_mtrl *) calloc(fp->mc, sizeof (struct s_mtrl));
267     if (fp->vc)
268         fp->vv = (struct s_vert *) calloc(fp->vc, sizeof (struct s_vert));
269     if (fp->ec)
270         fp->ev = (struct s_edge *) calloc(fp->ec, sizeof (struct s_edge));
271     if (fp->sc)
272         fp->sv = (struct s_side *) calloc(fp->sc, sizeof (struct s_side));
273     if (fp->tc)
274         fp->tv = (struct s_texc *) calloc(fp->tc, sizeof (struct s_texc));
275     if (fp->gc)
276         fp->gv = (struct s_geom *) calloc(fp->gc, sizeof (struct s_geom));
277     if (fp->lc)
278         fp->lv = (struct s_lump *) calloc(fp->lc, sizeof (struct s_lump));
279     if (fp->nc)
280         fp->nv = (struct s_node *) calloc(fp->nc, sizeof (struct s_node));
281     if (fp->pc)
282         fp->pv = (struct s_path *) calloc(fp->pc, sizeof (struct s_path));
283     if (fp->bc)
284         fp->bv = (struct s_body *) calloc(fp->bc, sizeof (struct s_body));
285     if (fp->hc)
286         fp->hv = (struct s_item *) calloc(fp->hc, sizeof (struct s_item));
287     if (fp->zc)
288         fp->zv = (struct s_goal *) calloc(fp->zc, sizeof (struct s_goal));
289     if (fp->jc)
290         fp->jv = (struct s_jump *) calloc(fp->jc, sizeof (struct s_jump));
291     if (fp->xc)
292         fp->xv = (struct s_swch *) calloc(fp->xc, sizeof (struct s_swch));
293     if (fp->rc)
294         fp->rv = (struct s_bill *) calloc(fp->rc, sizeof (struct s_bill));
295     if (fp->uc)
296         fp->uv = (struct s_ball *) calloc(fp->uc, sizeof (struct s_ball));
297     if (fp->wc)
298         fp->wv = (struct s_view *) calloc(fp->wc, sizeof (struct s_view));
299     if (fp->dc)
300         fp->dv = (struct s_dict *) calloc(fp->dc, sizeof (struct s_dict));
301     if (fp->ic)
302         fp->iv = (int           *) calloc(fp->ic, sizeof (int));
303
304     if (fp->ac)
305         fs_read(fp->av, 1, fp->ac, fin);
306
307     for (i = 0; i < fp->dc; i++) sol_load_dict(fin, fp->dv + i);
308     for (i = 0; i < fp->mc; i++) sol_load_mtrl(fin, fp->mv + i);
309     for (i = 0; i < fp->vc; i++) sol_load_vert(fin, fp->vv + i);
310     for (i = 0; i < fp->ec; i++) sol_load_edge(fin, fp->ev + i);
311     for (i = 0; i < fp->sc; i++) sol_load_side(fin, fp->sv + i);
312     for (i = 0; i < fp->tc; i++) sol_load_texc(fin, fp->tv + i);
313     for (i = 0; i < fp->gc; i++) sol_load_geom(fin, fp->gv + i);
314     for (i = 0; i < fp->lc; i++) sol_load_lump(fin, fp->lv + i);
315     for (i = 0; i < fp->nc; i++) sol_load_node(fin, fp->nv + i);
316     for (i = 0; i < fp->pc; i++) sol_load_path(fin, fp->pv + i);
317     for (i = 0; i < fp->bc; i++) sol_load_body(fin, fp->bv + i);
318     for (i = 0; i < fp->hc; i++) sol_load_item(fin, fp->hv + i);
319     for (i = 0; i < fp->zc; i++) sol_load_goal(fin, fp->zv + i);
320     for (i = 0; i < fp->jc; i++) sol_load_jump(fin, fp->jv + i);
321     for (i = 0; i < fp->xc; i++) sol_load_swch(fin, fp->xv + i);
322     for (i = 0; i < fp->rc; i++) sol_load_bill(fin, fp->rv + i);
323     for (i = 0; i < fp->uc; i++) sol_load_ball(fin, fp->uv + i);
324     for (i = 0; i < fp->wc; i++) sol_load_view(fin, fp->wv + i);
325     for (i = 0; i < fp->ic; i++) get_index(fin, fp->iv + i);
326
327     return 1;
328 }
329
330 static int sol_load_head(fs_file fin, struct s_file *fp)
331 {
332     if (!sol_file(fin))
333         return 0;
334
335     sol_load_indx(fin, fp);
336
337     if (fp->ac)
338     {
339         fp->av = (char *) calloc(fp->ac, sizeof (char));
340         fs_read(fp->av, 1, fp->ac, fin);
341     }
342
343     if (fp->dc)
344     {
345         int i;
346
347         fp->dv = (struct s_dict *) calloc(fp->dc, sizeof (struct s_dict));
348
349         for (i = 0; i < fp->dc; i++)
350             sol_load_dict(fin, fp->dv + i);
351     }
352
353     return 1;
354 }
355
356 int sol_load_only_file(struct s_file *fp, const char *filename)
357 {
358     fs_file fin;
359     int res = 0;
360
361     if ((fin = fs_open(filename, "r")))
362     {
363         res = sol_load_file(fin, fp);
364         fs_close(fin);
365     }
366     return res;
367 }
368
369 int sol_load_only_head(struct s_file *fp, const char *filename)
370 {
371     fs_file fin;
372     int res = 0;
373
374     if ((fin = fs_open(filename, "r")))
375     {
376         res = sol_load_head(fin, fp);
377         fs_close(fin);
378     }
379     return res;
380 }
381
382 /*---------------------------------------------------------------------------*/
383
384 static void sol_stor_mtrl(fs_file fout, struct s_mtrl *mp)
385 {
386     put_array(fout,  mp->d, 4);
387     put_array(fout,  mp->a, 4);
388     put_array(fout,  mp->s, 4);
389     put_array(fout,  mp->e, 4);
390     put_array(fout,  mp->h, 1);
391     put_index(fout, &mp->fl);
392
393     fs_write(mp->f, 1, PATHMAX, fout);
394 }
395
396 static void sol_stor_vert(fs_file fout, struct s_vert *vp)
397 {
398     put_array(fout,  vp->p, 3);
399 }
400
401 static void sol_stor_edge(fs_file fout, struct s_edge *ep)
402 {
403     put_index(fout, &ep->vi);
404     put_index(fout, &ep->vj);
405 }
406
407 static void sol_stor_side(fs_file fout, struct s_side *sp)
408 {
409     put_array(fout,  sp->n, 3);
410     put_float(fout, &sp->d);
411 }
412
413 static void sol_stor_texc(fs_file fout, struct s_texc *tp)
414 {
415     put_array(fout,  tp->u, 2);
416 }
417
418 static void sol_stor_geom(fs_file fout, struct s_geom *gp)
419 {
420     put_index(fout, &gp->mi);
421     put_index(fout, &gp->ti);
422     put_index(fout, &gp->si);
423     put_index(fout, &gp->vi);
424     put_index(fout, &gp->tj);
425     put_index(fout, &gp->sj);
426     put_index(fout, &gp->vj);
427     put_index(fout, &gp->tk);
428     put_index(fout, &gp->sk);
429     put_index(fout, &gp->vk);
430 }
431
432 static void sol_stor_lump(fs_file fout, struct s_lump *lp)
433 {
434     put_index(fout, &lp->fl);
435     put_index(fout, &lp->v0);
436     put_index(fout, &lp->vc);
437     put_index(fout, &lp->e0);
438     put_index(fout, &lp->ec);
439     put_index(fout, &lp->g0);
440     put_index(fout, &lp->gc);
441     put_index(fout, &lp->s0);
442     put_index(fout, &lp->sc);
443 }
444
445 static void sol_stor_node(fs_file fout, struct s_node *np)
446 {
447     put_index(fout, &np->si);
448     put_index(fout, &np->ni);
449     put_index(fout, &np->nj);
450     put_index(fout, &np->l0);
451     put_index(fout, &np->lc);
452 }
453
454 static void sol_stor_path(fs_file fout, struct s_path *pp)
455 {
456     put_array(fout,  pp->p, 3);
457     put_float(fout, &pp->t);
458     put_index(fout, &pp->pi);
459     put_index(fout, &pp->f);
460     put_index(fout, &pp->s);
461     put_index(fout, &pp->fl);
462
463     if (pp->fl & P_ORIENTED)
464         put_array(fout, pp->e, 4);
465 }
466
467 static void sol_stor_body(fs_file fout, struct s_body *bp)
468 {
469     put_index(fout, &bp->pi);
470     put_index(fout, &bp->ni);
471     put_index(fout, &bp->l0);
472     put_index(fout, &bp->lc);
473     put_index(fout, &bp->g0);
474     put_index(fout, &bp->gc);
475 }
476
477 static void sol_stor_item(fs_file fout, struct s_item *hp)
478 {
479     put_array(fout,  hp->p, 3);
480     put_index(fout, &hp->t);
481     put_index(fout, &hp->n);
482 }
483
484 static void sol_stor_goal(fs_file fout, struct s_goal *zp)
485 {
486     put_array(fout,  zp->p, 3);
487     put_float(fout, &zp->r);
488 }
489
490 static void sol_stor_swch(fs_file fout, struct s_swch *xp)
491 {
492     put_array(fout,  xp->p, 3);
493     put_float(fout, &xp->r);
494     put_index(fout, &xp->pi);
495     put_float(fout, &xp->t0);
496     put_float(fout, &xp->t);
497     put_index(fout, &xp->f0);
498     put_index(fout, &xp->f);
499     put_index(fout, &xp->i);
500 }
501
502 static void sol_stor_bill(fs_file fout, struct s_bill *rp)
503 {
504     put_index(fout, &rp->fl);
505     put_index(fout, &rp->mi);
506     put_float(fout, &rp->t);
507     put_float(fout, &rp->d);
508     put_array(fout,  rp->w,  3);
509     put_array(fout,  rp->h,  3);
510     put_array(fout,  rp->rx, 3);
511     put_array(fout,  rp->ry, 3);
512     put_array(fout,  rp->rz, 3);
513     put_array(fout,  rp->p,  3);
514 }
515
516 static void sol_stor_jump(fs_file fout, struct s_jump *jp)
517 {
518     put_array(fout,  jp->p, 3);
519     put_array(fout,  jp->q, 3);
520     put_float(fout, &jp->r);
521 }
522
523 static void sol_stor_ball(fs_file fout, struct s_ball *bp)
524 {
525     put_array(fout,  bp->p, 3);
526     put_float(fout, &bp->r);
527 }
528
529 static void sol_stor_view(fs_file fout, struct s_view *wp)
530 {
531     put_array(fout,  wp->p, 3);
532     put_array(fout,  wp->q, 3);
533 }
534
535 static void sol_stor_dict(fs_file fout, struct s_dict *dp)
536 {
537     put_index(fout, &dp->ai);
538     put_index(fout, &dp->aj);
539 }
540
541 static void sol_stor_file(fs_file fout, struct s_file *fp)
542 {
543     int i;
544     int magic   = MAGIC;
545     int version = SOL_VER_CURRENT;
546
547     put_index(fout, &magic);
548     put_index(fout, &version);
549
550     put_index(fout, &fp->ac);
551     put_index(fout, &fp->dc);
552     put_index(fout, &fp->mc);
553     put_index(fout, &fp->vc);
554     put_index(fout, &fp->ec);
555     put_index(fout, &fp->sc);
556     put_index(fout, &fp->tc);
557     put_index(fout, &fp->gc);
558     put_index(fout, &fp->lc);
559     put_index(fout, &fp->nc);
560     put_index(fout, &fp->pc);
561     put_index(fout, &fp->bc);
562     put_index(fout, &fp->hc);
563     put_index(fout, &fp->zc);
564     put_index(fout, &fp->jc);
565     put_index(fout, &fp->xc);
566     put_index(fout, &fp->rc);
567     put_index(fout, &fp->uc);
568     put_index(fout, &fp->wc);
569     put_index(fout, &fp->ic);
570
571     fs_write(fp->av, 1, fp->ac, fout);
572
573     for (i = 0; i < fp->dc; i++) sol_stor_dict(fout, fp->dv + i);
574     for (i = 0; i < fp->mc; i++) sol_stor_mtrl(fout, fp->mv + i);
575     for (i = 0; i < fp->vc; i++) sol_stor_vert(fout, fp->vv + i);
576     for (i = 0; i < fp->ec; i++) sol_stor_edge(fout, fp->ev + i);
577     for (i = 0; i < fp->sc; i++) sol_stor_side(fout, fp->sv + i);
578     for (i = 0; i < fp->tc; i++) sol_stor_texc(fout, fp->tv + i);
579     for (i = 0; i < fp->gc; i++) sol_stor_geom(fout, fp->gv + i);
580     for (i = 0; i < fp->lc; i++) sol_stor_lump(fout, fp->lv + i);
581     for (i = 0; i < fp->nc; i++) sol_stor_node(fout, fp->nv + i);
582     for (i = 0; i < fp->pc; i++) sol_stor_path(fout, fp->pv + i);
583     for (i = 0; i < fp->bc; i++) sol_stor_body(fout, fp->bv + i);
584     for (i = 0; i < fp->hc; i++) sol_stor_item(fout, fp->hv + i);
585     for (i = 0; i < fp->zc; i++) sol_stor_goal(fout, fp->zv + i);
586     for (i = 0; i < fp->jc; i++) sol_stor_jump(fout, fp->jv + i);
587     for (i = 0; i < fp->xc; i++) sol_stor_swch(fout, fp->xv + i);
588     for (i = 0; i < fp->rc; i++) sol_stor_bill(fout, fp->rv + i);
589     for (i = 0; i < fp->uc; i++) sol_stor_ball(fout, fp->uv + i);
590     for (i = 0; i < fp->wc; i++) sol_stor_view(fout, fp->wv + i);
591     for (i = 0; i < fp->ic; i++) put_index(fout, fp->iv + i);
592 }
593
594 /*---------------------------------------------------------------------------*/
595
596 int sol_stor(struct s_file *fp, const char *filename)
597 {
598     fs_file fout;
599
600     if ((fout = fs_open(filename, "w")))
601     {
602         sol_stor_file(fout, fp);
603         fs_close(fout);
604
605         return 1;
606     }
607     return 0;
608 }
609
610 void sol_free(struct s_file *fp)
611 {
612     if (fp->av) free(fp->av);
613     if (fp->mv) free(fp->mv);
614     if (fp->vv) free(fp->vv);
615     if (fp->ev) free(fp->ev);
616     if (fp->sv) free(fp->sv);
617     if (fp->tv) free(fp->tv);
618     if (fp->gv) free(fp->gv);
619     if (fp->lv) free(fp->lv);
620     if (fp->nv) free(fp->nv);
621     if (fp->pv) free(fp->pv);
622     if (fp->bv) free(fp->bv);
623     if (fp->hv) free(fp->hv);
624     if (fp->zv) free(fp->zv);
625     if (fp->jv) free(fp->jv);
626     if (fp->xv) free(fp->xv);
627     if (fp->rv) free(fp->rv);
628     if (fp->uv) free(fp->uv);
629     if (fp->wv) free(fp->wv);
630     if (fp->dv) free(fp->dv);
631     if (fp->iv) free(fp->iv);
632
633     memset(fp, 0, sizeof (struct s_file));
634 }
635
636 /*---------------------------------------------------------------------------*/