2 * Copyright (C) 2009 Neverball authors
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.
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.
20 #include "base_config.h"
23 /*---------------------------------------------------------------------------*/
25 static int cmd_stats = 0;
27 /*---------------------------------------------------------------------------*/
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.)
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
46 static void cmd_put_ ## t(fs_file fp, const union cmd *cmd) { \
47 const char *cmd_name = #t; \
49 /* This is a write, so BYTES should be safe to eval already. */ \
50 short cmd_bytes = BYTES; \
52 /* Write command size info (right after the command type). */ \
53 put_short(fp, cmd_bytes); \
55 /* Start the stats output. */ \
56 if (cmd_stats) printf("put"); \
59 static void cmd_get_ ## t(fs_file fp, union cmd *cmd) { \
60 const char *cmd_name = #t; \
62 /* This is a read, so we'll have to eval BYTES later. */ \
63 short cmd_bytes = -1; \
65 /* Start the stats output. */ \
66 if (cmd_stats) printf("get");
69 if (cmd_bytes < 0) cmd_bytes = BYTES; \
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. */
75 /*---------------------------------------------------------------------------*/
80 PUT_FUNC(CMD_END_OF_UPDATE) { } END_FUNC;
81 GET_FUNC(CMD_END_OF_UPDATE) { } END_FUNC;
83 /*---------------------------------------------------------------------------*/
88 PUT_FUNC(CMD_MAKE_BALL) { } END_FUNC;
89 GET_FUNC(CMD_MAKE_BALL) { } END_FUNC;
91 /*---------------------------------------------------------------------------*/
94 #define BYTES (ARRAY_BYTES(3) + INDEX_BYTES + INDEX_BYTES)
96 PUT_FUNC(CMD_MAKE_ITEM)
98 put_array(fp, cmd->mkitem.p, 3);
99 put_index(fp, cmd->mkitem.t);
100 put_index(fp, cmd->mkitem.n);
104 GET_FUNC(CMD_MAKE_ITEM)
106 get_array(fp, cmd->mkitem.p, 3);
107 get_index(fp, &cmd->mkitem.t);
108 get_index(fp, &cmd->mkitem.n);
112 /*---------------------------------------------------------------------------*/
115 #define BYTES INDEX_BYTES
117 PUT_FUNC(CMD_PICK_ITEM)
119 put_index(fp, cmd->pkitem.hi);
123 GET_FUNC(CMD_PICK_ITEM)
125 get_index(fp, &cmd->pkitem.hi);
129 /*---------------------------------------------------------------------------*/
132 #define BYTES (FLOAT_BYTES + FLOAT_BYTES)
134 PUT_FUNC(CMD_TILT_ANGLES)
136 put_float(fp, cmd->tiltangles.x);
137 put_float(fp, cmd->tiltangles.z);
141 GET_FUNC(CMD_TILT_ANGLES)
143 get_float(fp, &cmd->tiltangles.x);
144 get_float(fp, &cmd->tiltangles.z);
148 /*---------------------------------------------------------------------------*/
151 #define BYTES (STRING_BYTES(cmd->sound.n) + FLOAT_BYTES)
155 put_string(fp, cmd->sound.n);
156 put_float(fp, cmd->sound.a);
162 static char buff[MAXSTR];
164 get_string(fp, buff, sizeof (buff));
165 get_float(fp, &cmd->sound.a);
167 cmd->sound.n = strdup(buff);
171 /*---------------------------------------------------------------------------*/
174 #define BYTES FLOAT_BYTES
178 put_float(fp, cmd->timer.t);
184 get_float(fp, &cmd->timer.t);
188 /*---------------------------------------------------------------------------*/
191 #define BYTES INDEX_BYTES
195 put_index(fp, cmd->status.t);
201 get_index(fp, &cmd->status.t);
205 /*---------------------------------------------------------------------------*/
208 #define BYTES INDEX_BYTES
212 put_index(fp, cmd->coins.n);
218 get_index(fp, &cmd->coins.n);
222 /*---------------------------------------------------------------------------*/
227 PUT_FUNC(CMD_JUMP_ENTER) { } END_FUNC;
228 GET_FUNC(CMD_JUMP_ENTER) { } END_FUNC;
230 /*---------------------------------------------------------------------------*/
235 PUT_FUNC(CMD_JUMP_EXIT) { } END_FUNC;
236 GET_FUNC(CMD_JUMP_EXIT) { } END_FUNC;
238 /*---------------------------------------------------------------------------*/
241 #define BYTES (INDEX_BYTES + INDEX_BYTES)
243 PUT_FUNC(CMD_BODY_PATH)
245 put_index(fp, cmd->bodypath.bi);
246 put_index(fp, cmd->bodypath.pi);
250 GET_FUNC(CMD_BODY_PATH)
252 get_index(fp, &cmd->bodypath.bi);
253 get_index(fp, &cmd->bodypath.pi);
257 /*---------------------------------------------------------------------------*/
260 #define BYTES (INDEX_BYTES + FLOAT_BYTES)
262 PUT_FUNC(CMD_BODY_TIME)
264 put_index(fp, cmd->bodytime.bi);
265 put_float(fp, cmd->bodytime.t);
269 GET_FUNC(CMD_BODY_TIME)
271 get_index(fp, &cmd->bodytime.bi);
272 get_float(fp, &cmd->bodytime.t);
276 /*---------------------------------------------------------------------------*/
281 PUT_FUNC(CMD_GOAL_OPEN) { } END_FUNC;
282 GET_FUNC(CMD_GOAL_OPEN) { } END_FUNC;
284 /*---------------------------------------------------------------------------*/
287 #define BYTES INDEX_BYTES
289 PUT_FUNC(CMD_SWCH_ENTER)
291 put_index(fp, cmd->swchenter.xi);
295 GET_FUNC(CMD_SWCH_ENTER)
297 get_index(fp, &cmd->swchenter.xi);
301 /*---------------------------------------------------------------------------*/
304 #define BYTES INDEX_BYTES
306 PUT_FUNC(CMD_SWCH_TOGGLE)
308 put_index(fp, cmd->swchenter.xi);
312 GET_FUNC(CMD_SWCH_TOGGLE)
314 get_index(fp, &cmd->swchenter.xi);
318 /*---------------------------------------------------------------------------*/
321 #define BYTES INDEX_BYTES
323 PUT_FUNC(CMD_SWCH_EXIT)
325 put_index(fp, cmd->swchenter.xi);
329 GET_FUNC(CMD_SWCH_EXIT)
331 get_index(fp, &cmd->swchenter.xi);
335 /*---------------------------------------------------------------------------*/
338 #define BYTES INDEX_BYTES
340 PUT_FUNC(CMD_UPDATES_PER_SECOND)
342 put_index(fp, cmd->ups.n);
346 GET_FUNC(CMD_UPDATES_PER_SECOND)
348 get_index(fp, &cmd->ups.n);
352 /*---------------------------------------------------------------------------*/
355 #define BYTES FLOAT_BYTES
357 PUT_FUNC(CMD_BALL_RADIUS)
359 put_float(fp, cmd->ballradius.r);
363 GET_FUNC(CMD_BALL_RADIUS)
365 get_float(fp, &cmd->ballradius.r);
369 /*---------------------------------------------------------------------------*/
374 PUT_FUNC(CMD_CLEAR_ITEMS) { } END_FUNC;
375 GET_FUNC(CMD_CLEAR_ITEMS) { } END_FUNC;
377 /*---------------------------------------------------------------------------*/
382 PUT_FUNC(CMD_CLEAR_BALLS) { } END_FUNC;
383 GET_FUNC(CMD_CLEAR_BALLS) { } END_FUNC;
385 /*---------------------------------------------------------------------------*/
388 #define BYTES ARRAY_BYTES(3)
390 PUT_FUNC(CMD_BALL_POSITION)
392 put_array(fp, cmd->ballpos.p, 3);
396 GET_FUNC(CMD_BALL_POSITION)
398 get_array(fp, cmd->ballpos.p, 3);
402 /*---------------------------------------------------------------------------*/
405 #define BYTES (ARRAY_BYTES(3) + ARRAY_BYTES(3))
407 PUT_FUNC(CMD_BALL_BASIS)
409 put_array(fp, cmd->ballbasis.e[0], 3);
410 put_array(fp, cmd->ballbasis.e[1], 3);
414 GET_FUNC(CMD_BALL_BASIS)
416 get_array(fp, cmd->ballbasis.e[0], 3);
417 get_array(fp, cmd->ballbasis.e[1], 3);
421 /*---------------------------------------------------------------------------*/
424 #define BYTES (ARRAY_BYTES(3) + ARRAY_BYTES(3))
426 PUT_FUNC(CMD_BALL_PEND_BASIS)
428 put_array(fp, cmd->ballpendbasis.E[0], 3);
429 put_array(fp, cmd->ballpendbasis.E[1], 3);
433 GET_FUNC(CMD_BALL_PEND_BASIS)
435 get_array(fp, cmd->ballpendbasis.E[0], 3);
436 get_array(fp, cmd->ballpendbasis.E[1], 3);
440 /*---------------------------------------------------------------------------*/
443 #define BYTES ARRAY_BYTES(3)
445 PUT_FUNC(CMD_VIEW_POSITION)
447 put_array(fp, cmd->viewpos.p, 3);
451 GET_FUNC(CMD_VIEW_POSITION)
453 get_array(fp, cmd->viewpos.p, 3);
457 /*---------------------------------------------------------------------------*/
460 #define BYTES ARRAY_BYTES(3)
462 PUT_FUNC(CMD_VIEW_CENTER)
464 put_array(fp, cmd->viewcenter.c, 3);
468 GET_FUNC(CMD_VIEW_CENTER)
470 get_array(fp, cmd->viewcenter.c, 3);
474 /*---------------------------------------------------------------------------*/
477 #define BYTES (ARRAY_BYTES(3) + ARRAY_BYTES(3))
479 PUT_FUNC(CMD_VIEW_BASIS)
481 put_array(fp, cmd->viewbasis.e[0], 3);
482 put_array(fp, cmd->viewbasis.e[1], 3);
486 GET_FUNC(CMD_VIEW_BASIS)
488 get_array(fp, cmd->viewbasis.e[0], 3);
489 get_array(fp, cmd->viewbasis.e[1], 3);
493 /*---------------------------------------------------------------------------*/
496 #define BYTES INDEX_BYTES
498 PUT_FUNC(CMD_CURRENT_BALL)
500 put_index(fp, cmd->currball.ui);
504 GET_FUNC(CMD_CURRENT_BALL)
506 get_index(fp, &cmd->currball.ui);
510 /*---------------------------------------------------------------------------*/
513 #define BYTES (INDEX_BYTES + INDEX_BYTES)
515 PUT_FUNC(CMD_PATH_FLAG)
517 put_index(fp, cmd->pathflag.pi);
518 put_index(fp, cmd->pathflag.f);
522 GET_FUNC(CMD_PATH_FLAG)
524 get_index(fp, &cmd->pathflag.pi);
525 get_index(fp, &cmd->pathflag.f);
529 /*---------------------------------------------------------------------------*/
532 #define BYTES FLOAT_BYTES
534 PUT_FUNC(CMD_STEP_SIMULATION)
536 put_float(fp, cmd->stepsim.dt);
540 GET_FUNC(CMD_STEP_SIMULATION)
542 get_float(fp, &cmd->stepsim.dt);
546 /*---------------------------------------------------------------------------*/
549 #define BYTES STRING_BYTES(cmd->map.name) + INDEX_BYTES * 2
553 put_string(fp, cmd->map.name);
555 put_index(fp, cmd->map.version.x);
556 put_index(fp, cmd->map.version.y);
564 get_string(fp, buff, sizeof (buff));
566 cmd->map.name = strdup(buff);
568 get_index(fp, &cmd->map.version.x);
569 get_index(fp, &cmd->map.version.y);
573 /*---------------------------------------------------------------------------*/
576 #define BYTES ARRAY_BYTES(3) * 2
578 PUT_FUNC(CMD_TILT_AXES)
580 put_array(fp, cmd->tiltaxes.x, 3);
581 put_array(fp, cmd->tiltaxes.z, 3);
585 GET_FUNC(CMD_TILT_AXES)
587 get_array(fp, cmd->tiltaxes.x, 3);
588 get_array(fp, cmd->tiltaxes.z, 3);
592 /*---------------------------------------------------------------------------*/
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
597 int cmd_put(fs_file fp, const union cmd *cmd)
602 assert(cmd->type > CMD_NONE && cmd->type < CMD_MAX);
604 fs_putc(cmd->type, fp);
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);
615 PUT_CASE(CMD_STATUS);
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);
639 PUT_CASE(CMD_TILT_AXES);
649 int cmd_get(fs_file fp, union cmd *cmd)
657 if ((type = fs_getc(fp)) >= 0)
659 get_short(fp, &size);
661 /* Discard unrecognised commands. */
665 fs_seek(fp, size, SEEK_CUR);
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);
680 GET_CASE(CMD_STATUS);
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);
704 GET_CASE(CMD_TILT_AXES);
716 /*---------------------------------------------------------------------------*/
718 void cmd_free(union cmd *cmd)
740 /*---------------------------------------------------------------------------*/