root/trunk/thune/gl/particles.c

Revision 550, 11.0 kB (checked in by krobillard, 3 months ago)

Thune:

  • 8-bit string encoding is now Latin-1.
  • Now using WELL512a generator for random numbers.
  • Added hash-map datatype. List datatype can now be disabled in config.
  • Added project-point, remap.
  • Unique & fill now handle vector!.
  • File port 'read now retuns none when end of file reached.

Thune-GL:

  • Added draw-prog! & vertex-buffer! datatypes.
  • Display now accepts /fullscreen option.
  • Added particle-sim dialect.
Line 
1/*============================================================================
2    Thune OpenGL Module
3    Copyright (C) 2008  Karl Robillard
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18===========================================================================*/
19
20
21#include "gx.h"
22#include "urlan_atoms.h"
23#include "gx_atoms.h"
24#include "math3d.h"
25
26
27typedef struct
28{
29    float* pos;
30    float* prev;
31    float  dt2;
32    int    count;
33
34    UIndex crBin;
35    char*  crElem;
36    int    crBPR;
37    int    crBPE;
38    uint16_t crW;
39    uint16_t crH;
40}
41ParticleCtx;
42
43
44/*
45  Verlet integration.
46*/
47static void verlet( float* pos, float* prev, float* acc, float timeSquared )
48{
49    float temp;
50
51    temp = pos[0];
52    pos[0] += pos[0] - prev[0] + acc[0] * timeSquared;
53    prev[0] = temp;
54
55    temp = pos[1];
56    pos[1] += pos[1] - prev[1] + acc[1] * timeSquared;
57    prev[1] = temp;
58
59    temp = pos[2];
60    pos[2] += pos[2] - prev[2] + acc[2] * timeSquared;
61    prev[2] = temp;
62}
63
64
65static void verletDrag( float* pos, float* prev, float* acc,
66                        float timeSquared, float oneMinusDrag )
67{
68    float temp;
69
70    temp = pos[0];
71    pos[0] += (pos[0] - prev[0]) * oneMinusDrag + acc[0] * timeSquared;
72    prev[0] = temp;
73
74    temp = pos[1];
75    pos[1] += (pos[1] - prev[1]) * oneMinusDrag + acc[1] * timeSquared;
76    prev[1] = temp;
77
78    temp = pos[2];
79    pos[2] += (pos[2] - prev[2]) * oneMinusDrag + acc[2] * timeSquared;
80    prev[2] = temp;
81}
82
83
84static inline void vectorFrom( float* from, float* to, float* result )
85{
86    result[0] = to[0] - from[0];
87    result[1] = to[1] - from[1];
88    result[2] = to[2] - from[2];
89}
90
91
92static float* ptarget( ParticleCtx* pc, UCell* it, int idx )
93{
94    if( ur_is(it, UT_VEC3) )
95    {
96        return it->vec3.xyz;
97    }
98    else if( ur_is(it, UT_INT) )
99    {
100        return pc->pos + ((ur_int(it) - 1) * 3);
101    }
102    else if( ur_is(it, UT_SELECT) )
103    {
104        int pn = idx + ur_sel(it);
105        if( pn < 0 )
106            pn += pc->count;
107        else if( pn >= pc->count )
108            pn -= pc->count;
109        return pc->pos + (pn * 3);
110    }
111    return 0;
112}
113
114
115/*
116   \param blk  Particle program.
117   \param idx  Zero based index of current particle.
118*/
119static void particle_sim( UThread* ut, ParticleCtx* pc, UBlock* blk, int idx )
120{
121    UCell* it;
122    UCell* end;
123    float* pos;
124    float* prev;
125    float* target;
126    int idx3;
127    float acc[3];
128    float diff[3];
129
130    idx3 = idx * 3;
131    pos  = pc->pos  + idx3;
132    prev = pc->prev + idx3;
133    acc[0] = acc[1] = acc[2] = 0.0f;
134
135    it  = blk->ptr.cells;
136    end = blk->ptr.cells + blk->used;
137
138    while( it != end )
139    {
140        if( ur_is(it, UT_WORD) )
141        {
142            switch( ur_atom(it) )
143            {
144#if 0
145                case UR_ATOM_FORCE:     // force vector!
146                    if( ++it == end )
147                        return;
148                    if( ur_is(it, UT_VEC3) )
149                    {
150                        acc[0] += it->vec3.xyz[0];
151                        acc[1] += it->vec3.xyz[1];
152                        acc[2] += it->vec3.xyz[2];
153                    }
154                    break;
155#endif
156                case UR_ATOM_FALL:      // fall target decimal!
157                    if( ++it == end )
158                        return;
159                    target = ptarget( pc, it, idx );
160                    if( ! target )
161                        return;
162                    {
163                        float f;
164                        vectorFrom( pos, target, diff );
165                        if( ++it == end )
166                            return;
167                        f = ur_decimal(it) / ur_lengthSq( diff );
168                        acc[0] += diff[0] * f;
169                        acc[1] += diff[1] * f;
170                        acc[2] += diff[2] * f;
171                    }
172                    break;
173
174                case UR_ATOM_ATTACH:
175                {
176                    float cdist;
177
178                    if( ++it == end )
179                        return;
180                    target = ptarget( pc, it, idx );
181                    if( ! target )
182                        return;
183
184                    if( ++it == end )
185                        return;
186                    cdist = ur_decimal(it);
187
188                    vectorFrom( target, pos, diff );
189                    ur_normalize( diff );
190                    diff[0] = diff[0] * cdist + target[0];
191                    diff[1] = diff[1] * cdist + target[1];
192                  //diff[2] = diff[2] * cdist + target[2];
193
194                    // Fall towards ideal position.
195                    pos[0] += (diff[0] - pos[0]) * 0.1f;
196                    pos[1] += (diff[1] - pos[1]) * 0.1f;
197                  //pos[2] += (diff[2] - pos[2]) * 0.1f;
198                }
199                    break;
200
201                case UR_ATOM_CENTER:    // center target1 target2
202                {
203                    float center[3];
204                    float* t2;
205
206                    if( ++it == end )
207                        return;
208                    target = ptarget( pc, it, idx );
209                    if( ! target )
210                        return;
211
212                    if( ++it == end )
213                        return;
214                    t2 = ptarget( pc, it, idx );
215                    if( ! t2 )
216                        return;
217
218                    /*
219                    pos[0] = (target[0] + t2[0]) * 0.5f;
220                    pos[1] = (target[1] + t2[1]) * 0.5f;
221                    pos[2] = (target[2] + t2[2]) * 0.5f;
222                    */
223
224                    center[0] = (target[0] + t2[0]) * 0.5f;
225                    center[1] = (target[1] + t2[1]) * 0.5f;
226                    center[2] = (target[2] + t2[2]) * 0.5f;
227
228                    ur_lineToPoint( target, t2, pos, diff );
229
230                    /*
231                    pos[0] += center[0] - (pos[0] - diff[0]);
232                    pos[1] += center[1] - (pos[1] - diff[1]);
233                    pos[2] += center[2] - (pos[2] - diff[2]);
234                    */
235
236                    acc[0] += 0.2 * (center[0] - (pos[0] - diff[0]));
237                    acc[1] += 0.2 * (center[1] - (pos[1] - diff[1]));
238                    acc[2] += 0.2 * (center[2] - (pos[2] - diff[2]));
239                }
240                    break;
241
242                case UR_ATOM_INTEGRATE:
243                    verlet( pos, prev, acc, pc->dt2 );
244                    break;
245
246                case UR_ATOM_COLLIDE:
247                {
248                    UCell* rc;
249                    int x, y;
250
251                    if( ++it == end )
252                        return;
253
254                    if( ur_is(it, UT_WORD) )
255                    {
256                        rc = ur_wordCell( ut, it );
257                        if( ! rc )
258                            return;
259                    }
260                    else
261                        rc = it;
262
263                    if( ur_is(rc, UT_RASTER) )
264                    {
265                        if( pc->crBin != rc->series.n )
266                        {
267                            // Cache collision raster info.
268                            RasterHead* rh;
269                            pc->crBin = rc->series.n;
270                            rh = ur_rastHead(rc);
271                            pc->crElem = ur_rasterElements( rh );
272                            pc->crBPR  = ur_rasterBytesPerRow( rh );
273                            pc->crBPE  = ur_rasterElementSize( rh );
274                            pc->crW    = rh->width;
275                            pc->crH    = rh->height;
276                        }
277
278                        x = (int) pos[0];
279                        if( x < 0 || x >= pc->crW )
280                            break;
281                        y = (int) pos[1];
282                        if( y < 0 || y >= pc->crH )
283                            break;
284
285                        x = pc->crElem[ (y * pc->crBPR) + (x * pc->crBPE) ];
286                        if( x )
287                        {
288                            // Restore previous position.
289                            pos[0] = prev[0];
290                            pos[1] = prev[1];
291                            pos[2] = prev[2];
292                        }
293                    }
294                }
295                    break;
296            }
297        }
298        else if( ur_is(it, UT_SELECT) )
299        {
300            switch( ur_atom(it) )
301            {
302                case UR_ATOM_ANCHOR:
303                {
304                    unsigned int n;
305
306                    n = ur_sel(it) - (ur_selIsAtom(it) ? UR_ATOM_X : 1);
307                    if( ++it == end )
308                        return;
309                    if( n < 3 )
310                        pos[n] = ur_decimal(it);
311                }
312                    break;
313
314                case UR_ATOM_INTEGRATE:
315                    //if( ur_sel(it) == UR_ATOM_DRAG )
316                    {
317                        if( ++it == end )
318                            return;
319                        verletDrag( pos, prev, acc, pc->dt2,
320                                    1.0 - ur_decimal(it) );
321                    }
322                    break;
323            }
324        }
325        else if( ur_is(it, UT_INT) )
326        {
327            // Change current particle.
328            idx  = ur_int(it) - 1;
329            idx3 = idx * 3;
330            pos  = pc->pos  + idx3;
331            prev = pc->prev + idx3;
332            acc[0] = acc[1] = acc[2] = 0.0f;
333        }
334        else if( ur_is(it, UT_COORD) )
335        {
336            // Run block on group of particles.
337            UBlock* sblk;
338            int sn   = it->coord.elem[0] - 1;
339            int last = it->coord.elem[1];
340
341            if( ++it == end )
342                return;
343            if( ur_is(it, UT_BLOCK) )
344            {
345                sblk = ur_block(it);
346                for( ; sn < last; ++sn )
347                    particle_sim( ut, pc, sblk, sn );
348            }
349        }
350        ++it;
351    }
352}
353
354
355/*
356  (verts program delta-time -- )
357*/
358UR_CALL_PUB(uc_particle_sim)
359{
360    ParticleCtx pc;
361    UBinary* bin;
362    UCell* prog = ur_s_prev(tos);
363    UCell* vert = ur_s_prev(prog);
364
365    if( ur_is(tos, UT_DECIMAL) &&
366        ur_is(prog, UT_BLOCK) &&
367        ur_is(vert, UT_VECTOR) )
368    {
369        pc.dt2 = ur_decimal(tos);
370        pc.dt2 *= pc.dt2;
371
372        bin = ur_bin(vert);
373        pc.count = bin->used / 6;
374        pc.pos   = bin->ptr.f;
375        pc.prev  = bin->ptr.f + (pc.count * 3);
376        pc.crBin = 0;
377
378        particle_sim( ut, &pc, ur_block(prog), 0 );
379
380        UR_S_DROPN( 3 );
381        return;
382    }
383    ur_throwErr( UR_ERR_DATATYPE,
384        "particle-sim expected vector! block! decimal!" );
385}
386
387
388// EOF
Note: See TracBrowser for help on using the browser.