Fix redundant glTexEnv calls
[neverball] / share / cmd.c
1 /*
2  * Copyright (C) 2009 Neverball authors
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 <assert.h>
17
18 #include "cmd.h"
19 #include "binary.h"
20 #include "base_config.h"
21 #include "common.h"
22
23 /*---------------------------------------------------------------------------*/
24
25 static int cmd_stats = 0;
26
27 /*---------------------------------------------------------------------------*/
28
29 /*
30  * Let's pretend these aren't Ridiculously Convoluted Macros from
31  * Hell, and that all this looks pretty straight-forward.  (In all
32  * fairness, the macros have paid off.)
33  *
34  * A command's "write" and "read" functions are defined by calling the
35  * PUT_FUNC or the GET_FUNC macro, respectively, with the command type
36  * as argument, followed by the body of the function (which has
37  * variables "fp" and "cmd" available), and finalised with the
38  * END_FUNC macro, which must be terminated with a semi-colon.  Before
39  * the function definitions, the BYTES macro must be redefined for
40  * each command to an expression evaluating to the number of bytes
41  * that the command will occupy in the file.  (See existing commands
42  * for examples.)
43  */
44
45 #define PUT_FUNC(t)                                                     \
46     static void cmd_put_ ## t(fs_file fp, const union cmd *cmd) {       \
47     const char *cmd_name = #t;                                          \
48                                                                         \
49     /* This is a write, so BYTES should be safe to eval already. */     \
50     short cmd_bytes = BYTES;                                            \
51                                                                         \
52     /* Write command size info (right after the command type). */       \
53     put_short(fp, cmd_bytes);                                           \
54                                                                         \
55     /* Start the stats output. */                                       \
56     if (cmd_stats) printf("put");                                       \
57
58 #define GET_FUNC(t)                                             \
59     static void cmd_get_ ## t(fs_file fp, union cmd *cmd) {     \
60     const char *cmd_name = #t;                                  \
61                                                                 \
62     /* This is a read, so we'll have to eval BYTES later. */    \
63     short cmd_bytes = -1;                                       \
64                                                                 \
65     /* Start the stats output. */                               \
66     if (cmd_stats) printf("get");
67
68 #define END_FUNC                                                        \
69     if (cmd_bytes < 0) cmd_bytes = BYTES;                               \
70                                                                         \
71     /* Finish the stats output. */                                      \
72     if (cmd_stats) printf("\t%s\t%d\n", cmd_name, cmd_bytes);           \
73     } struct dummy              /* Allows a trailing semi-colon. */
74
75 /*---------------------------------------------------------------------------*/
76
77 #undef BYTES
78 #define BYTES 0
79
80 PUT_FUNC(CMD_END_OF_UPDATE) { } END_FUNC;
81 GET_FUNC(CMD_END_OF_UPDATE) { } END_FUNC;
82
83 /*---------------------------------------------------------------------------*/
84
85 #undef BYTES
86 #define BYTES 0
87
88 PUT_FUNC(CMD_MAKE_BALL) { } END_FUNC;
89 GET_FUNC(CMD_MAKE_BALL) { } END_FUNC;
90
91 /*---------------------------------------------------------------------------*/
92
93 #undef BYTES
94 #define BYTES (ARRAY_BYTES(3) + INDEX_BYTES + INDEX_BYTES)
95
96 PUT_FUNC(CMD_MAKE_ITEM)
97 {
98     put_array(fp, cmd->mkitem.p, 3);
99     put_index(fp, cmd->mkitem.t);
100     put_index(fp, cmd->mkitem.n);
101 }
102 END_FUNC;
103
104 GET_FUNC(CMD_MAKE_ITEM)
105 {
106     get_array(fp, cmd->mkitem.p, 3);
107     get_index(fp, &cmd->mkitem.t);
108     get_index(fp, &cmd->mkitem.n);
109 }
110 END_FUNC;
111
112 /*---------------------------------------------------------------------------*/
113
114 #undef BYTES
115 #define BYTES INDEX_BYTES
116
117 PUT_FUNC(CMD_PICK_ITEM)
118 {
119     put_index(fp, cmd->pkitem.hi);
120 }
121 END_FUNC;
122
123 GET_FUNC(CMD_PICK_ITEM)
124 {
125     get_index(fp, &cmd->pkitem.hi);
126 }
127 END_FUNC;
128
129 /*---------------------------------------------------------------------------*/
130
131 #undef BYTES
132 #define BYTES (FLOAT_BYTES + FLOAT_BYTES)
133
134 PUT_FUNC(CMD_TILT_ANGLES)
135 {
136     put_float(fp, cmd->tiltangles.x);
137     put_float(fp, cmd->tiltangles.z);
138 }
139 END_FUNC;
140
141 GET_FUNC(CMD_TILT_ANGLES)
142 {
143     get_float(fp, &cmd->tiltangles.x);
144     get_float(fp, &cmd->tiltangles.z);
145 }
146 END_FUNC;
147
148 /*---------------------------------------------------------------------------*/
149
150 #undef BYTES
151 #define BYTES (STRING_BYTES(cmd->sound.n) + FLOAT_BYTES)
152
153 PUT_FUNC(CMD_SOUND)
154 {
155     put_string(fp, cmd->sound.n);
156     put_float(fp, cmd->sound.a);
157 }
158 END_FUNC;
159
160 GET_FUNC(CMD_SOUND)
161 {
162     static char buff[MAXSTR];
163
164     get_string(fp, buff, sizeof (buff));
165     get_float(fp, &cmd->sound.a);
166
167     cmd->sound.n = strdup(buff);
168 }
169 END_FUNC;
170
171 /*---------------------------------------------------------------------------*/
172
173 #undef BYTES
174 #define BYTES FLOAT_BYTES
175
176 PUT_FUNC(CMD_TIMER)
177 {
178     put_float(fp, cmd->timer.t);
179 }
180 END_FUNC;
181
182 GET_FUNC(CMD_TIMER)
183 {
184     get_float(fp, &cmd->timer.t);
185 }
186 END_FUNC;
187
188 /*---------------------------------------------------------------------------*/
189
190 #undef BYTES
191 #define BYTES INDEX_BYTES
192
193 PUT_FUNC(CMD_STATUS)
194 {
195     put_index(fp, cmd->status.t);
196 }
197 END_FUNC;
198
199 GET_FUNC(CMD_STATUS)
200 {
201     get_index(fp, &cmd->status.t);
202 }
203 END_FUNC;
204
205 /*---------------------------------------------------------------------------*/
206
207 #undef BYTES
208 #define BYTES INDEX_BYTES
209
210 PUT_FUNC(CMD_COINS)
211 {
212     put_index(fp, cmd->coins.n);
213 }
214 END_FUNC;
215
216 GET_FUNC(CMD_COINS)
217 {
218     get_index(fp, &cmd->coins.n);
219 }
220 END_FUNC;
221
222 /*---------------------------------------------------------------------------*/
223
224 #undef BYTES
225 #define BYTES 0
226
227 PUT_FUNC(CMD_JUMP_ENTER) { } END_FUNC;
228 GET_FUNC(CMD_JUMP_ENTER) { } END_FUNC;
229
230 /*---------------------------------------------------------------------------*/
231
232 #undef BYTES
233 #define BYTES 0
234
235 PUT_FUNC(CMD_JUMP_EXIT) { } END_FUNC;
236 GET_FUNC(CMD_JUMP_EXIT) { } END_FUNC;
237
238 /*---------------------------------------------------------------------------*/
239
240 #undef BYTES
241 #define BYTES (INDEX_BYTES + INDEX_BYTES)
242
243 PUT_FUNC(CMD_BODY_PATH)
244 {
245     put_index(fp, cmd->bodypath.bi);
246     put_index(fp, cmd->bodypath.pi);
247 }
248 END_FUNC;
249
250 GET_FUNC(CMD_BODY_PATH)
251 {
252     get_index(fp, &cmd->bodypath.bi);
253     get_index(fp, &cmd->bodypath.pi);
254 }
255 END_FUNC;
256
257 /*---------------------------------------------------------------------------*/
258
259 #undef BYTES
260 #define BYTES (INDEX_BYTES + FLOAT_BYTES)
261
262 PUT_FUNC(CMD_BODY_TIME)
263 {
264     put_index(fp, cmd->bodytime.bi);
265     put_float(fp, cmd->bodytime.t);
266 }
267 END_FUNC;
268
269 GET_FUNC(CMD_BODY_TIME)
270 {
271     get_index(fp, &cmd->bodytime.bi);
272     get_float(fp, &cmd->bodytime.t);
273 }
274 END_FUNC;
275
276 /*---------------------------------------------------------------------------*/
277
278 #undef BYTES
279 #define BYTES 0
280
281 PUT_FUNC(CMD_GOAL_OPEN) { } END_FUNC;
282 GET_FUNC(CMD_GOAL_OPEN) { } END_FUNC;
283
284 /*---------------------------------------------------------------------------*/
285
286 #undef BYTES
287 #define BYTES INDEX_BYTES
288
289 PUT_FUNC(CMD_SWCH_ENTER)
290 {
291     put_index(fp, cmd->swchenter.xi);
292 }
293 END_FUNC;
294
295 GET_FUNC(CMD_SWCH_ENTER)
296 {
297     get_index(fp, &cmd->swchenter.xi);
298 }
299 END_FUNC;
300
301 /*---------------------------------------------------------------------------*/
302
303 #undef BYTES
304 #define BYTES INDEX_BYTES
305
306 PUT_FUNC(CMD_SWCH_TOGGLE)
307 {
308     put_index(fp, cmd->swchenter.xi);
309 }
310 END_FUNC;
311
312 GET_FUNC(CMD_SWCH_TOGGLE)
313 {
314     get_index(fp, &cmd->swchenter.xi);
315 }
316 END_FUNC;
317
318 /*---------------------------------------------------------------------------*/
319
320 #undef BYTES
321 #define BYTES INDEX_BYTES
322
323 PUT_FUNC(CMD_SWCH_EXIT)
324 {
325     put_index(fp, cmd->swchenter.xi);
326 }
327 END_FUNC;
328
329 GET_FUNC(CMD_SWCH_EXIT)
330 {
331     get_index(fp, &cmd->swchenter.xi);
332 }
333 END_FUNC;
334
335 /*---------------------------------------------------------------------------*/
336
337 #undef BYTES
338 #define BYTES INDEX_BYTES
339
340 PUT_FUNC(CMD_UPDATES_PER_SECOND)
341 {
342     put_index(fp, cmd->ups.n);
343 }
344 END_FUNC;
345
346 GET_FUNC(CMD_UPDATES_PER_SECOND)
347 {
348     get_index(fp, &cmd->ups.n);
349 }
350 END_FUNC;
351
352 /*---------------------------------------------------------------------------*/
353
354 #undef BYTES
355 #define BYTES FLOAT_BYTES
356
357 PUT_FUNC(CMD_BALL_RADIUS)
358 {
359     put_float(fp, cmd->ballradius.r);
360 }
361 END_FUNC;
362
363 GET_FUNC(CMD_BALL_RADIUS)
364 {
365     get_float(fp, &cmd->ballradius.r);
366 }
367 END_FUNC;
368
369 /*---------------------------------------------------------------------------*/
370
371 #undef BYTES
372 #define BYTES 0
373
374 PUT_FUNC(CMD_CLEAR_ITEMS) { } END_FUNC;
375 GET_FUNC(CMD_CLEAR_ITEMS) { } END_FUNC;
376
377 /*---------------------------------------------------------------------------*/
378
379 #undef BYTES
380 #define BYTES 0
381
382 PUT_FUNC(CMD_CLEAR_BALLS) { } END_FUNC;
383 GET_FUNC(CMD_CLEAR_BALLS) { } END_FUNC;
384
385 /*---------------------------------------------------------------------------*/
386
387 #undef BYTES
388 #define BYTES ARRAY_BYTES(3)
389
390 PUT_FUNC(CMD_BALL_POSITION)
391 {
392     put_array(fp, cmd->ballpos.p, 3);
393 }
394 END_FUNC;
395
396 GET_FUNC(CMD_BALL_POSITION)
397 {
398     get_array(fp, cmd->ballpos.p, 3);
399 }
400 END_FUNC;
401
402 /*---------------------------------------------------------------------------*/
403
404 #undef BYTES
405 #define BYTES (ARRAY_BYTES(3) + ARRAY_BYTES(3))
406
407 PUT_FUNC(CMD_BALL_BASIS)
408 {
409     put_array(fp, cmd->ballbasis.e[0], 3);
410     put_array(fp, cmd->ballbasis.e[1], 3);
411 }
412 END_FUNC;
413
414 GET_FUNC(CMD_BALL_BASIS)
415 {
416     get_array(fp, cmd->ballbasis.e[0], 3);
417     get_array(fp, cmd->ballbasis.e[1], 3);
418 }
419 END_FUNC;
420
421 /*---------------------------------------------------------------------------*/
422
423 #undef BYTES
424 #define BYTES (ARRAY_BYTES(3) + ARRAY_BYTES(3))
425
426 PUT_FUNC(CMD_BALL_PEND_BASIS)
427 {
428     put_array(fp, cmd->ballpendbasis.E[0], 3);
429     put_array(fp, cmd->ballpendbasis.E[1], 3);
430 }
431 END_FUNC;
432
433 GET_FUNC(CMD_BALL_PEND_BASIS)
434 {
435     get_array(fp, cmd->ballpendbasis.E[0], 3);
436     get_array(fp, cmd->ballpendbasis.E[1], 3);
437 }
438 END_FUNC;
439
440 /*---------------------------------------------------------------------------*/
441
442 #undef BYTES
443 #define BYTES ARRAY_BYTES(3)
444
445 PUT_FUNC(CMD_VIEW_POSITION)
446 {
447     put_array(fp, cmd->viewpos.p, 3);
448 }
449 END_FUNC;
450
451 GET_FUNC(CMD_VIEW_POSITION)
452 {
453     get_array(fp, cmd->viewpos.p, 3);
454 }
455 END_FUNC;
456
457 /*---------------------------------------------------------------------------*/
458
459 #undef BYTES
460 #define BYTES ARRAY_BYTES(3)
461
462 PUT_FUNC(CMD_VIEW_CENTER)
463 {
464     put_array(fp, cmd->viewcenter.c, 3);
465 }
466 END_FUNC;
467
468 GET_FUNC(CMD_VIEW_CENTER)
469 {
470     get_array(fp, cmd->viewcenter.c, 3);
471 }
472 END_FUNC;
473
474 /*---------------------------------------------------------------------------*/
475
476 #undef BYTES
477 #define BYTES (ARRAY_BYTES(3) + ARRAY_BYTES(3))
478
479 PUT_FUNC(CMD_VIEW_BASIS)
480 {
481     put_array(fp, cmd->viewbasis.e[0], 3);
482     put_array(fp, cmd->viewbasis.e[1], 3);
483 }
484 END_FUNC;
485
486 GET_FUNC(CMD_VIEW_BASIS)
487 {
488     get_array(fp, cmd->viewbasis.e[0], 3);
489     get_array(fp, cmd->viewbasis.e[1], 3);
490 }
491 END_FUNC;
492
493 /*---------------------------------------------------------------------------*/
494
495 #undef BYTES
496 #define BYTES INDEX_BYTES
497
498 PUT_FUNC(CMD_CURRENT_BALL)
499 {
500     put_index(fp, cmd->currball.ui);
501 }
502 END_FUNC;
503
504 GET_FUNC(CMD_CURRENT_BALL)
505 {
506     get_index(fp, &cmd->currball.ui);
507 }
508 END_FUNC;
509
510 /*---------------------------------------------------------------------------*/
511
512 #undef BYTES
513 #define BYTES (INDEX_BYTES + INDEX_BYTES)
514
515 PUT_FUNC(CMD_PATH_FLAG)
516 {
517     put_index(fp, cmd->pathflag.pi);
518     put_index(fp, cmd->pathflag.f);
519 }
520 END_FUNC;
521
522 GET_FUNC(CMD_PATH_FLAG)
523 {
524     get_index(fp, &cmd->pathflag.pi);
525     get_index(fp, &cmd->pathflag.f);
526 }
527 END_FUNC;
528
529 /*---------------------------------------------------------------------------*/
530
531 #undef BYTES
532 #define BYTES FLOAT_BYTES
533
534 PUT_FUNC(CMD_STEP_SIMULATION)
535 {
536     put_float(fp, cmd->stepsim.dt);
537 }
538 END_FUNC;
539
540 GET_FUNC(CMD_STEP_SIMULATION)
541 {
542     get_float(fp, &cmd->stepsim.dt);
543 }
544 END_FUNC;
545
546 /*---------------------------------------------------------------------------*/
547
548 #undef BYTES
549 #define BYTES STRING_BYTES(cmd->map.name) + INDEX_BYTES * 2
550
551 PUT_FUNC(CMD_MAP)
552 {
553     put_string(fp, cmd->map.name);
554
555     put_index(fp, cmd->map.version.x);
556     put_index(fp, cmd->map.version.y);
557 }
558 END_FUNC;
559
560 GET_FUNC(CMD_MAP)
561 {
562     char buff[MAXSTR];
563
564     get_string(fp, buff, sizeof (buff));
565
566     cmd->map.name = strdup(buff);
567
568     get_index(fp, &cmd->map.version.x);
569     get_index(fp, &cmd->map.version.y);
570 }
571 END_FUNC;
572
573 /*---------------------------------------------------------------------------*/
574
575 #undef BYTES
576 #define BYTES ARRAY_BYTES(3) * 2
577
578 PUT_FUNC(CMD_TILT_AXES)
579 {
580     put_array(fp, cmd->tiltaxes.x, 3);
581     put_array(fp, cmd->tiltaxes.z, 3);
582 }
583 END_FUNC;
584
585 GET_FUNC(CMD_TILT_AXES)
586 {
587     get_array(fp, cmd->tiltaxes.x, 3);
588     get_array(fp, cmd->tiltaxes.z, 3);
589 }
590 END_FUNC;
591
592 /*---------------------------------------------------------------------------*/
593
594 #define PUT_CASE(t) case t: cmd_put_ ## t(fp, cmd); break
595 #define GET_CASE(t) case t: cmd_get_ ## t(fp, cmd); break
596
597 int cmd_put(fs_file fp, const union cmd *cmd)
598 {
599     if (!fp || !cmd)
600         return 0;
601
602     assert(cmd->type > CMD_NONE && cmd->type < CMD_MAX);
603
604     fs_putc(cmd->type, fp);
605
606     switch (cmd->type)
607     {
608         PUT_CASE(CMD_END_OF_UPDATE);
609         PUT_CASE(CMD_MAKE_BALL);
610         PUT_CASE(CMD_MAKE_ITEM);
611         PUT_CASE(CMD_PICK_ITEM);
612         PUT_CASE(CMD_TILT_ANGLES);
613         PUT_CASE(CMD_SOUND);
614         PUT_CASE(CMD_TIMER);
615         PUT_CASE(CMD_STATUS);
616         PUT_CASE(CMD_COINS);
617         PUT_CASE(CMD_JUMP_ENTER);
618         PUT_CASE(CMD_JUMP_EXIT);
619         PUT_CASE(CMD_BODY_PATH);
620         PUT_CASE(CMD_BODY_TIME);
621         PUT_CASE(CMD_GOAL_OPEN);
622         PUT_CASE(CMD_SWCH_ENTER);
623         PUT_CASE(CMD_SWCH_TOGGLE);
624         PUT_CASE(CMD_SWCH_EXIT);
625         PUT_CASE(CMD_UPDATES_PER_SECOND);
626         PUT_CASE(CMD_BALL_RADIUS);
627         PUT_CASE(CMD_CLEAR_ITEMS);
628         PUT_CASE(CMD_CLEAR_BALLS);
629         PUT_CASE(CMD_BALL_POSITION);
630         PUT_CASE(CMD_BALL_BASIS);
631         PUT_CASE(CMD_BALL_PEND_BASIS);
632         PUT_CASE(CMD_VIEW_POSITION);
633         PUT_CASE(CMD_VIEW_CENTER);
634         PUT_CASE(CMD_VIEW_BASIS);
635         PUT_CASE(CMD_CURRENT_BALL);
636         PUT_CASE(CMD_PATH_FLAG);
637         PUT_CASE(CMD_STEP_SIMULATION);
638         PUT_CASE(CMD_MAP);
639         PUT_CASE(CMD_TILT_AXES);
640
641     case CMD_NONE:
642     case CMD_MAX:
643         break;
644     }
645
646     return !fs_eof(fp);
647 }
648
649 int cmd_get(fs_file fp, union cmd *cmd)
650 {
651     int type;
652     short size;
653
654     if (!fp || !cmd)
655         return 0;
656
657     if ((type = fs_getc(fp)) >= 0)
658     {
659         get_short(fp, &size);
660
661         /* Discard unrecognised commands. */
662
663         if (type >= CMD_MAX)
664         {
665             fs_seek(fp, size, SEEK_CUR);
666             type = CMD_NONE;
667         }
668
669         cmd->type = type;
670
671         switch (cmd->type)
672         {
673             GET_CASE(CMD_END_OF_UPDATE);
674             GET_CASE(CMD_MAKE_BALL);
675             GET_CASE(CMD_MAKE_ITEM);
676             GET_CASE(CMD_PICK_ITEM);
677             GET_CASE(CMD_TILT_ANGLES);
678             GET_CASE(CMD_SOUND);
679             GET_CASE(CMD_TIMER);
680             GET_CASE(CMD_STATUS);
681             GET_CASE(CMD_COINS);
682             GET_CASE(CMD_JUMP_ENTER);
683             GET_CASE(CMD_JUMP_EXIT);
684             GET_CASE(CMD_BODY_PATH);
685             GET_CASE(CMD_BODY_TIME);
686             GET_CASE(CMD_GOAL_OPEN);
687             GET_CASE(CMD_SWCH_ENTER);
688             GET_CASE(CMD_SWCH_TOGGLE);
689             GET_CASE(CMD_SWCH_EXIT);
690             GET_CASE(CMD_UPDATES_PER_SECOND);
691             GET_CASE(CMD_BALL_RADIUS);
692             GET_CASE(CMD_CLEAR_ITEMS);
693             GET_CASE(CMD_CLEAR_BALLS);
694             GET_CASE(CMD_BALL_POSITION);
695             GET_CASE(CMD_BALL_BASIS);
696             GET_CASE(CMD_BALL_PEND_BASIS);
697             GET_CASE(CMD_VIEW_POSITION);
698             GET_CASE(CMD_VIEW_CENTER);
699             GET_CASE(CMD_VIEW_BASIS);
700             GET_CASE(CMD_CURRENT_BALL);
701             GET_CASE(CMD_PATH_FLAG);
702             GET_CASE(CMD_STEP_SIMULATION);
703             GET_CASE(CMD_MAP);
704             GET_CASE(CMD_TILT_AXES);
705
706         case CMD_NONE:
707         case CMD_MAX:
708             break;
709         }
710
711         return !fs_eof(fp);
712     }
713     return 0;
714 }
715
716 /*---------------------------------------------------------------------------*/
717
718 void cmd_free(union cmd *cmd)
719 {
720     if (cmd)
721     {
722         switch (cmd->type)
723         {
724         case CMD_SOUND:
725             free(cmd->sound.n);
726             break;
727
728         case CMD_MAP:
729             free(cmd->map.name);
730             break;
731
732         default:
733             break;
734         }
735
736         free(cmd);
737     }
738 }
739
740 /*---------------------------------------------------------------------------*/