Fix interpolation in title screen replays
[neverball] / share / solid_vary.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 <stdlib.h>
16
17 #include "solid_vary.h"
18 #include "common.h"
19 #include "vec3.h"
20
21 /*---------------------------------------------------------------------------*/
22
23 int sol_load_vary(struct s_vary *fp, const struct s_base *base)
24 {
25     int i;
26
27     memset(fp, 0, sizeof (*fp));
28
29     fp->base = base;
30
31     if (fp->base->pc)
32     {
33         fp->pv = calloc(fp->base->pc, sizeof (*fp->pv));
34         fp->pc = fp->base->pc;
35
36         for (i = 0; i < fp->base->pc; i++)
37         {
38             struct v_path *pp = fp->pv + i;
39             struct b_path *pq = fp->base->pv + i;
40
41             pp->base = pq;
42             pp->f    = pq->f;
43         }
44     }
45
46     if (fp->base->bc)
47     {
48         fp->bv = calloc(fp->base->bc, sizeof (*fp->bv));
49         fp->bc = fp->base->bc;
50
51         for (i = 0; i < fp->base->bc; i++)
52         {
53             struct v_body *bp = fp->bv + i;
54             struct b_body *bq = fp->base->bv + i;
55
56             bp->base = bq;
57             bp->pi   = bq->pi;
58         }
59     }
60
61     if (fp->base->hc)
62     {
63         fp->hv = calloc(fp->base->hc, sizeof (*fp->hv));
64         fp->hc = fp->base->hc;
65
66         for (i = 0; i < fp->base->hc; i++)
67         {
68             struct v_item *hp = fp->hv + i;
69             struct b_item *hq = fp->base->hv + i;
70
71             v_cpy(hp->p, hq->p);
72
73             hp->t = hq->t;
74             hp->n = hq->n;
75         }
76     }
77
78     if (fp->base->xc)
79     {
80         fp->xv = calloc(fp->base->xc, sizeof (*fp->xv));
81         fp->xc = fp->base->xc;
82
83         for (i = 0; i < fp->base->xc; i++)
84         {
85             struct v_swch *xp = fp->xv + i;
86             struct b_swch *xq = fp->base->xv + i;
87
88             xp->base = xq;
89             xp->t    = xq->t;
90             xp->tm   = xq->tm;
91             xp->f    = xq->f;
92         }
93     }
94
95     if (fp->base->uc)
96     {
97         fp->uv = calloc(fp->base->uc, sizeof (*fp->uv));
98         fp->uc = fp->base->uc;
99
100         for (i = 0; i < fp->base->uc; i++)
101         {
102             struct v_ball *up = fp->uv + i;
103             struct b_ball *uq = fp->base->uv + i;
104
105             v_cpy(up->p, uq->p);
106
107             up->r = uq->r;
108
109             up->E[0][0] = up->e[0][0] = 1.0f;
110             up->E[0][1] = up->e[0][1] = 0.0f;
111             up->E[0][2] = up->e[0][2] = 0.0f;
112
113             up->E[1][0] = up->e[1][0] = 0.0f;
114             up->E[1][1] = up->e[1][1] = 1.0f;
115             up->E[1][2] = up->e[1][2] = 0.0f;
116
117             up->E[2][0] = up->e[2][0] = 0.0f;
118             up->E[2][1] = up->e[2][1] = 0.0f;
119             up->E[2][2] = up->e[2][2] = 1.0f;
120         }
121     }
122
123     return 1;
124 }
125
126 void sol_free_vary(struct s_vary *fp)
127 {
128     if (fp->pv) free(fp->pv);
129     if (fp->bv) free(fp->bv);
130     if (fp->hv) free(fp->hv);
131     if (fp->xv) free(fp->xv);
132     if (fp->uv) free(fp->uv);
133
134     memset(fp, 0, sizeof (*fp));
135 }
136
137 /*---------------------------------------------------------------------------*/
138
139 #define CURR 0
140 #define PREV 1
141
142 int sol_lerp_cmd(struct s_lerp *fp, struct cmd_state *cs, const union cmd *cmd)
143 {
144     struct l_ball (*uv)[2];
145     struct l_ball *up;
146
147     int i, rc = 0;
148
149     switch (cmd->type)
150     {
151     case CMD_MAKE_BALL:
152         if ((uv = realloc(fp->uv, sizeof (*uv) * (fp->uc + 1))))
153         {
154             struct v_ball *up;
155
156             fp->uv = uv;
157             fp->uc++;
158
159             /* Sync the main structure. */
160
161             if ((up = realloc(fp->vary->uv, sizeof (*up) * fp->uc)))
162             {
163                 fp->vary->uv = up;
164                 fp->vary->uc = fp->uc;
165
166                 cs->curr_ball = fp->uc - 1;
167                 rc = 1;
168             }
169         }
170         break;
171
172     case CMD_BODY_PATH:
173         fp->bv[cmd->bodypath.bi][CURR].pi = cmd->bodypath.pi;
174         break;
175
176     case CMD_BODY_TIME:
177         fp->bv[cmd->bodytime.bi][CURR].t = cmd->bodytime.t;
178         break;
179
180     case CMD_BALL_RADIUS:
181         fp->uv[cs->curr_ball][CURR].r = cmd->ballradius.r;
182         break;
183
184     case CMD_CLEAR_BALLS:
185         free(fp->uv);
186         fp->uv = NULL;
187         fp->uc = 0;
188
189         free(fp->vary->uv);
190         fp->vary->uv = NULL;
191         fp->vary->uc = 0;
192         break;
193
194     case CMD_BALL_POSITION:
195         up = &fp->uv[cs->curr_ball][CURR];
196         v_cpy(up->p, cmd->ballpos.p);
197         break;
198
199     case CMD_BALL_BASIS:
200         up = &fp->uv[cs->curr_ball][CURR];
201         v_cpy(up->e[0], cmd->ballbasis.e[0]);
202         v_cpy(up->e[1], cmd->ballbasis.e[1]);
203         v_crs(up->e[2], up->e[0], up->e[1]);
204         break;
205
206     case CMD_BALL_PEND_BASIS:
207         up = &fp->uv[cs->curr_ball][CURR];
208         v_cpy(up->E[0], cmd->ballpendbasis.E[0]);
209         v_cpy(up->E[1], cmd->ballpendbasis.E[1]);
210         v_crs(up->E[2], up->E[0], up->E[1]);
211         break;
212
213     case CMD_STEP_SIMULATION:
214         /*
215          * Simulate body motion.
216          *
217          * This is done on the client side due to replay file size
218          * concerns and isn't done as part of CMD_END_OF_UPDATE to
219          * match the server state as closely as possible.  Body time
220          * is still synchronized with the server on a semi-regular
221          * basis and path indices are handled through CMD_BODY_PATH,
222          * thus this code doesn't need to be as sophisticated as
223          * sol_body_step.
224          */
225
226         for (i = 0; i < fp->bc; i++)
227         {
228             struct l_body *bp = &fp->bv[i][CURR];
229             struct v_path *pp = &fp->vary->pv[bp->pi];
230
231             if (bp->pi >= 0 && pp->f)
232                 bp->t += cmd->stepsim.dt;
233         }
234         break;
235
236     default:
237         break;
238     }
239
240     return rc;
241 }
242
243 void sol_lerp_copy(struct s_lerp *fp)
244 {
245     int i;
246
247     for (i = 0; i < fp->bc; i++)
248         fp->bv[i][PREV] = fp->bv[i][CURR];
249
250     for (i = 0; i < fp->uc; i++)
251         fp->uv[i][PREV] = fp->uv[i][CURR];
252 }
253
254 void sol_lerp_apply(struct s_lerp *fp, float a)
255 {
256     int i;
257
258     for (i = 0; i < fp->bc; i++)
259     {
260         if (fp->bv[i][PREV].pi == fp->bv[i][CURR].pi)
261             fp->vary->bv[i].t = (fp->bv[i][PREV].t * (1.0f - a) +
262                                  fp->bv[i][CURR].t * a);
263         else
264             fp->vary->bv[i].t = fp->bv[i][CURR].t * a;
265
266         fp->vary->bv[i].pi = fp->bv[i][CURR].pi;
267     }
268
269     for (i = 0; i < fp->uc; i++)
270     {
271         e_lerp(fp->vary->uv[i].e, fp->uv[i][PREV].e, fp->uv[i][CURR].e, a);
272         v_lerp(fp->vary->uv[i].p, fp->uv[i][PREV].p, fp->uv[i][CURR].p, a);
273         e_lerp(fp->vary->uv[i].E, fp->uv[i][PREV].E, fp->uv[i][CURR].E, a);
274
275         fp->vary->uv[i].r = (fp->uv[i][PREV].r * (1.0f - a) +
276                              fp->uv[i][CURR].r * a);
277     }
278 }
279
280 int sol_load_lerp(struct s_lerp *fp, struct s_vary *vary)
281 {
282     int i;
283
284     fp->vary = vary;
285
286     if (fp->vary->bc)
287     {
288         fp->bv = calloc(fp->vary->bc, sizeof (*fp->bv));
289         fp->bc = fp->vary->bc;
290
291         for (i = 0; i < fp->vary->bc; i++)
292             fp->bv[i][CURR].pi = fp->vary->bv[i].pi;
293     }
294
295     if (fp->vary->uc)
296     {
297         fp->uv = calloc(fp->vary->uc, sizeof (*fp->uv));
298         fp->uc = fp->vary->uc;
299
300         for (i = 0; i < fp->vary->uc; i++)
301         {
302             e_cpy(fp->uv[i][CURR].e, fp->vary->uv[i].e);
303             v_cpy(fp->uv[i][CURR].p, fp->vary->uv[i].p);
304             e_cpy(fp->uv[i][CURR].E, fp->vary->uv[i].E);
305
306             fp->uv[i][CURR].r = fp->vary->uv[i].r;
307         }
308     }
309
310     sol_lerp_copy(fp);
311
312     return 1;
313 }
314
315 void sol_free_lerp(struct s_lerp *fp)
316 {
317     if (fp->bv) free(fp->bv);
318     if (fp->uv) free(fp->uv);
319
320     memset(fp, 0, sizeof (*fp));
321 }
322
323 /*---------------------------------------------------------------------------*/