70c0439379f927a74f9bacc73b712be545555d33
[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 static int curr_ball;
143
144 int sol_lerp_cmd(struct s_lerp *fp, const union cmd *cmd)
145 {
146     struct l_ball (*uv)[2];
147     struct l_ball *up;
148
149     int i, rc = 0;
150
151     switch (cmd->type)
152     {
153     case CMD_MAKE_BALL:
154         if ((uv = realloc(fp->uv, sizeof (*uv) * (fp->uc + 1))))
155         {
156             struct v_ball *up;
157
158             fp->uv = uv;
159             fp->uc++;
160
161             /* Sync the main structure. */
162
163             if ((up = realloc(fp->vary->uv, sizeof (*up) * fp->uc)))
164             {
165                 fp->vary->uv = up;
166                 fp->vary->uc = fp->uc;
167
168                 curr_ball = fp->uc - 1;
169                 rc = 1;
170             }
171         }
172         break;
173
174     case CMD_BODY_PATH:
175         fp->bv[cmd->bodypath.bi][CURR].pi = cmd->bodypath.pi;
176         break;
177
178     case CMD_BODY_TIME:
179         fp->bv[cmd->bodytime.bi][CURR].t = cmd->bodytime.t;
180         break;
181
182     case CMD_BALL_RADIUS:
183         fp->uv[curr_ball][CURR].r = cmd->ballradius.r;
184         break;
185
186     case CMD_CLEAR_BALLS:
187         free(fp->uv);
188         fp->uv = NULL;
189         fp->uc = 0;
190
191         free(fp->vary->uv);
192         fp->vary->uv = NULL;
193         fp->vary->uc = 0;
194         break;
195
196     case CMD_BALL_POSITION:
197         up = &fp->uv[curr_ball][CURR];
198         v_cpy(up->p, cmd->ballpos.p);
199         break;
200
201     case CMD_BALL_BASIS:
202         up = &fp->uv[curr_ball][CURR];
203         v_cpy(up->e[0], cmd->ballbasis.e[0]);
204         v_cpy(up->e[1], cmd->ballbasis.e[1]);
205         v_crs(up->e[2], up->e[0], up->e[1]);
206         break;
207
208     case CMD_BALL_PEND_BASIS:
209         up = &fp->uv[curr_ball][CURR];
210         v_cpy(up->E[0], cmd->ballpendbasis.E[0]);
211         v_cpy(up->E[1], cmd->ballpendbasis.E[1]);
212         v_crs(up->E[2], up->E[0], up->E[1]);
213         break;
214
215     case CMD_CURRENT_BALL:
216         curr_ball = cmd->currball.ui;
217         break;
218
219     case CMD_STEP_SIMULATION:
220         /*
221          * Simulate body motion.
222          *
223          * This is done on the client side due to replay file size
224          * concerns and isn't done as part of CMD_END_OF_UPDATE to
225          * match the server state as closely as possible.  Body time
226          * is still synchronized with the server on a semi-regular
227          * basis and path indices are handled through CMD_BODY_PATH,
228          * thus this code doesn't need to be as sophisticated as
229          * sol_body_step.
230          */
231
232         for (i = 0; i < fp->bc; i++)
233         {
234             struct l_body *bp = &fp->bv[i][CURR];
235             struct v_path *pp = &fp->vary->pv[bp->pi];
236
237             if (bp->pi >= 0 && pp->f)
238                 bp->t += cmd->stepsim.dt;
239         }
240         break;
241
242     default:
243         break;
244     }
245
246     return rc;
247 }
248
249 void sol_lerp_copy(struct s_lerp *fp)
250 {
251     int i;
252
253     for (i = 0; i < fp->bc; i++)
254         fp->bv[i][PREV] = fp->bv[i][CURR];
255
256     for (i = 0; i < fp->uc; i++)
257         fp->uv[i][PREV] = fp->uv[i][CURR];
258 }
259
260 void sol_lerp_apply(struct s_lerp *fp, float a)
261 {
262     int i;
263
264     for (i = 0; i < fp->bc; i++)
265     {
266         if (fp->bv[i][PREV].pi == fp->bv[i][CURR].pi)
267             fp->vary->bv[i].t = (fp->bv[i][PREV].t * (1.0f - a) +
268                                  fp->bv[i][CURR].t * a);
269         else
270             fp->vary->bv[i].t = fp->bv[i][CURR].t * a;
271
272         fp->vary->bv[i].pi = fp->bv[i][CURR].pi;
273     }
274
275     for (i = 0; i < fp->uc; i++)
276     {
277         e_lerp(fp->vary->uv[i].e, fp->uv[i][PREV].e, fp->uv[i][CURR].e, a);
278         v_lerp(fp->vary->uv[i].p, fp->uv[i][PREV].p, fp->uv[i][CURR].p, a);
279         e_lerp(fp->vary->uv[i].E, fp->uv[i][PREV].E, fp->uv[i][CURR].E, a);
280
281         fp->vary->uv[i].r = (fp->uv[i][PREV].r * (1.0f - a) +
282                              fp->uv[i][CURR].r * a);
283     }
284 }
285
286 int sol_load_lerp(struct s_lerp *fp, struct s_vary *vary)
287 {
288     int i;
289
290     fp->vary = vary;
291
292     if (fp->vary->bc)
293     {
294         fp->bv = calloc(fp->vary->bc, sizeof (*fp->bv));
295         fp->bc = fp->vary->bc;
296
297         for (i = 0; i < fp->vary->bc; i++)
298             fp->bv[i][CURR].pi = fp->vary->bv[i].pi;
299     }
300
301     if (fp->vary->uc)
302     {
303         fp->uv = calloc(fp->vary->uc, sizeof (*fp->uv));
304         fp->uc = fp->vary->uc;
305
306         for (i = 0; i < fp->vary->uc; i++)
307         {
308             e_cpy(fp->uv[i][CURR].e, fp->vary->uv[i].e);
309             v_cpy(fp->uv[i][CURR].p, fp->vary->uv[i].p);
310             e_cpy(fp->uv[i][CURR].E, fp->vary->uv[i].E);
311
312             fp->uv[i][CURR].r = fp->vary->uv[i].r;
313         }
314     }
315
316     sol_lerp_copy(fp);
317
318     return 1;
319 }
320
321 void sol_free_lerp(struct s_lerp *fp)
322 {
323     if (fp->bv) free(fp->bv);
324     if (fp->uv) free(fp->uv);
325
326     memset(fp, 0, sizeof (*fp));
327 }
328
329 /*---------------------------------------------------------------------------*/