2
* Copyright (C) 2009 Neverball contributors
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(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(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)
136
put_float(fp, &cmd->rotate.x);
137
put_float(fp, &cmd->rotate.z);
143
get_float(fp, &cmd->rotate.x);
144
get_float(fp, &cmd->rotate.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
/*---------------------------------------------------------------------------*/
548
#define PUT_CASE(t) case t: cmd_put_ ## t(fp, cmd); break
549
#define GET_CASE(t) case t: cmd_get_ ## t(fp, cmd); break
551
int cmd_put(FILE *fp, const union cmd *cmd)
556
assert(cmd->type > CMD_NONE && cmd->type < CMD_MAX);
558
fputc(cmd->type, fp);
562
PUT_CASE(CMD_END_OF_UPDATE);
563
PUT_CASE(CMD_MAKE_BALL);
564
PUT_CASE(CMD_MAKE_ITEM);
565
PUT_CASE(CMD_PICK_ITEM);
566
PUT_CASE(CMD_ROTATE);
569
PUT_CASE(CMD_STATUS);
571
PUT_CASE(CMD_JUMP_ENTER);
572
PUT_CASE(CMD_JUMP_EXIT);
573
PUT_CASE(CMD_BODY_PATH);
574
PUT_CASE(CMD_BODY_TIME);
575
PUT_CASE(CMD_GOAL_OPEN);
576
PUT_CASE(CMD_SWCH_ENTER);
577
PUT_CASE(CMD_SWCH_TOGGLE);
578
PUT_CASE(CMD_SWCH_EXIT);
579
PUT_CASE(CMD_UPDATES_PER_SECOND);
580
PUT_CASE(CMD_BALL_RADIUS);
581
PUT_CASE(CMD_CLEAR_ITEMS);
582
PUT_CASE(CMD_CLEAR_BALLS);
583
PUT_CASE(CMD_BALL_POSITION);
584
PUT_CASE(CMD_BALL_BASIS);
585
PUT_CASE(CMD_BALL_PEND_BASIS);
586
PUT_CASE(CMD_VIEW_POSITION);
587
PUT_CASE(CMD_VIEW_CENTER);
588
PUT_CASE(CMD_VIEW_BASIS);
589
PUT_CASE(CMD_CURRENT_BALL);
590
PUT_CASE(CMD_PATH_FLAG);
591
PUT_CASE(CMD_STEP_SIMULATION);
601
int cmd_get(FILE *fp, union cmd *cmd)
609
if ((type = fgetc(fp)) != EOF)
611
get_short(fp, &size);
613
/* Discard unrecognised commands. */
617
fseek(fp, size, SEEK_CUR);
625
GET_CASE(CMD_END_OF_UPDATE);
626
GET_CASE(CMD_MAKE_BALL);
627
GET_CASE(CMD_MAKE_ITEM);
628
GET_CASE(CMD_PICK_ITEM);
629
GET_CASE(CMD_ROTATE);
632
GET_CASE(CMD_STATUS);
634
GET_CASE(CMD_JUMP_ENTER);
635
GET_CASE(CMD_JUMP_EXIT);
636
GET_CASE(CMD_BODY_PATH);
637
GET_CASE(CMD_BODY_TIME);
638
GET_CASE(CMD_GOAL_OPEN);
639
GET_CASE(CMD_SWCH_ENTER);
640
GET_CASE(CMD_SWCH_TOGGLE);
641
GET_CASE(CMD_SWCH_EXIT);
642
GET_CASE(CMD_UPDATES_PER_SECOND);
643
GET_CASE(CMD_BALL_RADIUS);
644
GET_CASE(CMD_CLEAR_ITEMS);
645
GET_CASE(CMD_CLEAR_BALLS);
646
GET_CASE(CMD_BALL_POSITION);
647
GET_CASE(CMD_BALL_BASIS);
648
GET_CASE(CMD_BALL_PEND_BASIS);
649
GET_CASE(CMD_VIEW_POSITION);
650
GET_CASE(CMD_VIEW_CENTER);
651
GET_CASE(CMD_VIEW_BASIS);
652
GET_CASE(CMD_CURRENT_BALL);
653
GET_CASE(CMD_PATH_FLAG);
654
GET_CASE(CMD_STEP_SIMULATION);
666
/*---------------------------------------------------------------------------*/