Home My Page Projects Code Snippets Project Openings 3D graphics for Standard ML
Summary Activity SCM

SCM Repository

[sml3d] Annotation of /trunk/sml3d/src/particles/particles.sml
ViewVC logotype

Annotation of /trunk/sml3d/src/particles/particles.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 463 - (view) (download)

1 : jhr 1 (* particles.sml
2 :     *
3 :     * COPYRIGHT (c) 2005 John Reppy (http://www.cs.uchicago.edu/~jhr)
4 :     * All rights reserved.
5 :     *)
6 :    
7 :     structure Particles :> PARTICLES =
8 :     struct
9 :    
10 : pavelk 429 (* Define our random generator *)
11 :     structure M = Real32.Math
12 :     structure R = Random
13 : pavelk 458 structure DB = DataBuffer
14 : pavelk 429
15 :     fun randInRange (rand, n) = R.randRange (0, n) rand
16 :     fun ranf rand = Real32.fromLarge IEEEReal.TO_NEAREST (R.randReal rand)
17 :    
18 :     val ourRand = R.rand (17, 23) (* Should this be time based?! *)
19 :    
20 :     fun printErr s = TextIO.output(TextIO.stdErr, s ^ "\n");
21 :    
22 :     (* We also probably need these types... *)
23 :     structure V = Vec3f
24 :    
25 : jhr 1 type float = GL.float
26 : pavelk 429 type vec3f = Vec3f.vec3f
27 :     type color4f = SML3dTypes.color4f
28 :     type color3f = SML3dTypes.color3f
29 :     fun unpackc4 {r, g, b, a} = (r, g, b, a)
30 :     fun packc4 (r, g, b, a) = {r=r, g=g, b=b, a=a}
31 : jhr 1
32 : pavelk 429 (* For comparing if two floats are equal. ML can't do '=' on floats *)
33 : jhr 434 val epsilon = 0.00001 : float
34 : pavelk 435
35 :     val pi = 3.14159265358979
36 : pavelk 429
37 : pavelk 437 infix xor
38 :     fun false xor true = true
39 :     | true xor false = true
40 :     | _ xor _ = false
41 :    
42 : jhr 1 (* domains *)
43 :     datatype domain
44 :     = Dpoint of vec3f
45 : pavelk 429
46 :     (* A line whose endpoints are e1 and e2. Note that this is different
47 :     * than our usual representation of a line which is a point and a
48 :     * directional vector. That's because our line is *finite*
49 :     *)
50 :     | Dline of {e1 : vec3f, e2 : vec3f}
51 :    
52 : jhr 1 | Dtriangle of (vec3f * vec3f * vec3f)
53 :     | Dplane of {pt : vec3f, n : vec3f}
54 : pavelk 429 | Drectangle of {pt : vec3f, u : vec3f, v : vec3f}
55 :     | Dbox of {min : vec3f, max : vec3f} (* axis-aligned *)
56 :     (* A cylindrical shell whose axis points are u and v, and whose outer
57 :     * radius is orad and inner radius is ir. For a solid cylinder, set irad
58 :     * to zero.
59 :     *)
60 :     | Dcylinder of {u : vec3f, v : vec3f, orad : float, irad : float}
61 :    
62 :     (* u is the apex of the cone and v is the endpoint of the axis at the
63 :     * cone's base. orad is the radius of the base of the cone. irad is the
64 :     * radius of the base of a cone to subtract from the first cone to create
65 :     * a conical shell. This is similar to the cylindrical shell, which can be
66 :     * thought of as a large cylinder with a smaller cylinder subtracted from
67 :     * the middle. Both cones share the same apex and axis, which implies that
68 :     * the thickness of the conical shell tapers to 0 at the apex.
69 :     * irad = 0 for a solid cone with no empty space in the middle.
70 :     *)
71 :     | Dcone of {u : vec3f, v : vec3f, orad : float, irad : float}
72 :    
73 :     (* The point c is the center of the sphere. orad is the outer
74 :     * radius of the spherical shell and irad is the inner radius.
75 :     *)
76 :     | Dsphere of {c : vec3f, orad : float, irad : float}
77 :    
78 :     (* The point c is the center of a normal probability density of
79 :     * standard deviation stddev. The density is radially symmetrical.
80 :     * The blob domain allows for some very natural-looking effects because
81 :     * there is no sharp, artificial-looking boundary at the edge of the
82 :     * domain.
83 :     *)
84 :     | Dblob of {c : vec3f, stddev : float}
85 :    
86 :     (* The point c is the center of a disc in the plane with normal
87 :     * n. The disc has an orad. If irad is greater than 0,
88 :     * the domain is a flat washer, rather than a disc.
89 :     *)
90 :     | Ddisc of {c : vec3f, n : vec3f, orad : float, irad : float}
91 : jhr 1
92 : pavelk 429 (* Helper functions to create domains *)
93 :     fun point(v : vec3f) = Dpoint v
94 :    
95 :     fun line(p1 : vec3f, p2 : vec3f) = Dline{e1 = p1, e2 = p2}
96 :    
97 :     fun triangle(v1 : vec3f, v2 : vec3f, v3 : vec3f) = Dtriangle(v1, v2, v3)
98 :    
99 :     fun plane(p : vec3f, norm : vec3f) = Dplane{pt = p, n = norm}
100 :    
101 :     fun rectangle(p : vec3f, w : vec3f, h : vec3f) =
102 :     Drectangle{pt = p, u = w, v = h}
103 :    
104 :     fun box(mi : vec3f, ma : vec3f) = Dbox{min = mi, max = ma}
105 :    
106 :     fun sphere(v : vec3f, or : float, ir : float) =
107 :     Dsphere{c = v, orad = or, irad = ir}
108 :    
109 :     fun cylinder(v1 : vec3f, v2 : vec3f, or : float, ir : float) =
110 :     Dcylinder{u = v1, v = v2, orad = or, irad = ir}
111 :    
112 :     fun cone(v1 : vec3f, v2 : vec3f, or : float, ir : float) =
113 :     Dcone{u = v1, v = v2, orad = or, irad = ir}
114 :    
115 :     fun blob(v : vec3f, f: float) = Dblob{c = v, stddev = f}
116 :    
117 :     fun disc(v : vec3f, norm : vec3f, or : float, ir : float) =
118 :     Ddisc{c = v, n = norm, orad = or, irad = ir}
119 :    
120 :    
121 : jhr 1 datatype particle = P of {
122 : pavelk 458 pos : vec3f,
123 : pavelk 429 size : vec3f,
124 :     vel : vec3f,
125 :     color : color4f,
126 :     age : float
127 : jhr 1 }
128 :    
129 :     (* a particle group is a container for particles that are affected by
130 :     * the same forces, geometry, etc.
131 :     *)
132 :     datatype particle_group = PG of {
133 : pavelk 429 count : int ref,
134 :     maxParticles : int,
135 : pavelk 458 (* Buffer of particle positions *)
136 :     posBuf : float DB.buffer3,
137 : pavelk 429 particles : particle list ref,
138 :     actions : action list ref,
139 : jhr 1 (* state used to create new particles *)
140 : pavelk 429 rgb : domain ref, (* RGB color domain *)
141 :     alpha : float ref, (* initial alpha *)
142 :     szD : domain ref, (* size domain *)
143 :     velD : domain ref, (* velocity domain *)
144 :     dt : float ref, (* time step *)
145 :     start : {
146 :     age : float, stdev : float
147 :     } ref (* starting age and std. deviation *)
148 : jhr 1 }
149 :    
150 :     withtype action = particle_group -> unit
151 :    
152 : pavelk 429 fun newSystem maxCount = PG{
153 :     count = ref 0,
154 :     maxParticles = maxCount,
155 : pavelk 458 posBuf = DB.new(DB.size3f, maxCount),
156 : pavelk 429 particles = ref [],
157 :     actions = ref [],
158 :     rgb = ref (point(Vec3f.pack(0.0, 0.0, 0.0))),
159 :     alpha = ref 1.0,
160 :     szD = ref (point(Vec3f.pack(0.0, 0.0, 0.0))),
161 :     velD = ref (point(Vec3f.pack(0.0, 0.0, 0.0))),
162 :     dt = ref 0.0,
163 :     start = ref {age = 0.0, stdev = 0.0}
164 :     }
165 :    
166 :     fun reset(PG{count, particles, actions, rgb, alpha, szD, velD, dt, start, ...}) = (
167 :     count := 0;
168 :     particles := [];
169 :     actions := [];
170 :     rgb := point(Vec3f.pack(0.0, 0.0, 0.0));
171 :     alpha := 1.0;
172 :     szD := point(Vec3f.pack(0.0, 0.0, 0.0));
173 :     velD := point(Vec3f.pack(0.0, 0.0, 0.0));
174 :     dt := 0.0;
175 :     start := {age = 0.0, stdev = 0.0}
176 :     )
177 :    
178 :     (* Particle group attributes *)
179 :     fun colorD(PG{rgb, alpha, ...}, d : domain, a : float) =
180 :     (rgb := d; alpha := a)
181 :     fun color(pg : particle_group, c : color4f) =
182 :     let
183 :     val (r, g, b, a) = unpackc4(c)
184 :     in
185 :     colorD(pg, point(Vec3f.pack(r, g, b)), a)
186 :     end
187 :    
188 :     fun sizeD(PG{szD, ...}, d : domain) =
189 :     (szD := d)
190 :     fun size(pg : particle_group, v : vec3f) = sizeD(pg, point(v))
191 :    
192 :     fun velocityD(PG{velD, ...}, d : domain) = velD := d
193 :     fun velocity(pg : particle_group, v : vec3f) = velocityD(pg, point(v))
194 :    
195 :     fun startingAge(PG{start, ...}, sa as {age, stdev}) = start := sa
196 :    
197 :     fun timeStep(PG{dt, ...}, f : float) = dt := f
198 : jhr 1
199 :     (* return true if the point is within the domain *)
200 : pavelk 429 fun within (d, pos : vec3f) = (case d
201 :     of Dpoint{x : float, y : float, z : float} =>
202 :     abs (x - #x pos) < epsilon andalso
203 :     abs (y - #y pos) < epsilon andalso
204 :     abs (z - #z pos) < epsilon
205 : pavelk 435
206 :     | Dline{e1 : vec3f, e2 : vec3f} =>
207 :     let
208 :     fun max(x, y) = if x > y then x else y
209 :     fun min(x, y) = if x < y then x else y
210 :     fun inRange(a, x, y) =
211 :     a <= max(x, y) andalso a >= min(x, y)
212 :     in
213 :     inRange(#x pos, #x e1, #x e2) andalso
214 :     inRange(#y pos, #y e1, #y e2) andalso
215 :     inRange(#z pos, #z e1, #z e2)
216 :     end
217 :    
218 :     | Dtriangle(v1, v2, v3) => false
219 : pavelk 437
220 :     | Dplane{pt : vec3f, n : vec3f} => Vec3f.dot(n, V.sub(pos, pt)) > 0.0
221 :    
222 : pavelk 429 | Drectangle{pt : vec3f, u : vec3f, v : vec3f} => false
223 :     | Dbox{min : vec3f, max : vec3f} => false
224 :     | Dsphere{c : vec3f, orad : float, irad : float} => false
225 :     | Dcylinder{u : vec3f, v : vec3f, orad : float, irad : float} => false
226 :     | Dcone{u : vec3f, v : vec3f, orad : float, irad : float} => false
227 :     | Dblob{c : vec3f, stddev : float} => false
228 : pavelk 438 | Ddisc{c : vec3f, n : vec3f, orad : float, irad : float} => let
229 :     val toP = V.sub(pos, c)
230 :     val toPL = M.sqrt(Vec3f.lengthSq(toP))
231 :     in
232 :     Vec3f.dot(toP, n) < 0.01 andalso toPL <= orad andalso irad <= toPL
233 :     end
234 : jhr 1 (* end case *))
235 :    
236 :     (* generate a random value uniformly distributed within the domain *)
237 : pavelk 429 fun generate (Dpoint p) = Vec3f.unpack p
238 : pavelk 435
239 :     | generate (Dline{e1, e2}) = let
240 :     val amt = ranf ourRand
241 :     in
242 :     Vec3f.unpack (Vec3f.lerp(e1, amt, e2))
243 :     end
244 :    
245 : pavelk 429 | generate (Dbox{max, min}) = let
246 :     val x = #x min + (ranf ourRand) * (#x max - #x min)
247 :     val y = #y min + (ranf ourRand) * (#y max - #y min)
248 :     val z = #z min + (ranf ourRand) * (#z max - #z min)
249 : jhr 1 in
250 :     (x, y, z)
251 :     end
252 : pavelk 429 | generate (Dtriangle(p1, p2, p3)) = Vec3f.unpack p1
253 :     | generate (Dplane{pt, n}) = Vec3f.unpack pt
254 :     | generate (Drectangle{pt, u, v}) = Vec3f.unpack pt
255 : pavelk 435
256 : pavelk 429 | generate (Dsphere{c, orad, irad}) = Vec3f.unpack c
257 : pavelk 435
258 :     (* Create a particle at the base and then scale it up *)
259 :     | generate (Dcylinder{u, v, orad, irad}) = let
260 :     val eh = ranf ourRand
261 : pavelk 438 val ht = V.sub(u, v)
262 : pavelk 435 val rp = Vec3f.pack (generate(Ddisc{c = v, n = Vec3f.normalize(ht), orad = orad, irad = irad}))
263 :     in
264 :     Vec3f.unpack (Vec3f.add (Vec3f.scale(eh, ht), rp))
265 :     end
266 :    
267 :     (* The idea here is to just generate a point on the base and
268 :     * scale it by the height based on a random value...
269 :     *)
270 :     | generate (Dcone{u, v, orad, irad}) = let
271 :     val eh = ranf ourRand (* For our height *)
272 :     val rp = Vec3f.pack (generate(Ddisc{c = v,
273 :     n = Vec3f.normalize(V.sub(v, u)),
274 :     orad = orad, irad = irad}))
275 :     in
276 :     Vec3f.unpack (Vec3f.lerp(rp, eh, u))
277 :     end
278 :    
279 : pavelk 429 | generate (Dblob{c, stddev}) = Vec3f.unpack c
280 : pavelk 435
281 :     (* Here we want to generate a vector of length R which lies
282 :     * in the plane of the disc. This is done by projecting the
283 :     * unit vector in the y-direction onto the plane specified
284 :     * by n, and then translating it to c.
285 :     *)
286 :     | generate (Ddisc{c, n, orad, irad}) = let
287 : pavelk 438 val e0 = ranf ourRand
288 : pavelk 435 in
289 : pavelk 438 let
290 :     val t = 2.0 * (pi * (ranf ourRand))
291 : pavelk 436 val v = Vec3f.normalize(Vec3f.cross(c, V.sub(c, n)))
292 :     val p = Vec3f.normalize(Vec3f.cross(v, n))
293 : pavelk 438 val r = irad + (e0 * e0 * (orad - irad))
294 : pavelk 435 in
295 : pavelk 436 Vec3f.unpack (Vec3f.add(c,
296 : pavelk 438 Vec3f.add(Vec3f.scale(r * (M.cos t), v),
297 :     Vec3f.scale(r * (M.sin t), p)
298 : pavelk 436 )
299 :     ))
300 : pavelk 435 end
301 :     end
302 : jhr 1
303 : pavelk 429 (*** Particle group state functions ***)
304 : jhr 434 fun update (pg as PG{actions, ...}) = let
305 :     fun doAction act = act(pg)
306 :     val acts = List.rev (!actions)
307 :     in
308 :     actions := [];
309 :     List.app doAction acts
310 :     end
311 : pavelk 429
312 : jhr 434 fun add (PG{count, maxParticles, particles, rgb, alpha, szD, velD, start, ...}, d : domain) =
313 :     if (!count < maxParticles)
314 :     then let
315 :     val (r, g, b) = generate(!rgb)
316 :     val a = !alpha
317 :     val color = packc4(r, g, b, a)
318 : pavelk 438 val pos = Vec3f.pack (generate(d))
319 :     val vel = Vec3f.pack (generate(!velD))
320 : jhr 434 val p = P{
321 : pavelk 438 pos = pos,
322 : jhr 434 size = Vec3f.pack (generate(!szD)),
323 : pavelk 438 vel = vel,
324 : jhr 434 color = color,
325 :     age = 0.0
326 :     }
327 :     in
328 : pavelk 438 (* printErr "\nGenerating Particle...";
329 :     printErr (Vec3f.toString (Vec3f.pack(r, g, b)));
330 :     printErr (Vec3f.toString pos);
331 :     printErr (Vec3f.toString vel);
332 :     *) count := !count+1;
333 : jhr 434 particles := p :: !particles;
334 :     true
335 :     end
336 :     else false
337 : jhr 1
338 : pavelk 429 (******** Particle group rendering ***********)
339 : pavelk 458 fun fillPosBuffer(p :: particles, posBuf, indexBuf, maxParticles, pnum) =
340 :     let val P{pos, ...} = p in
341 :     DB.set3f(!posBuf, pnum, Vec3f.unpack(pos));
342 :     DB.setus(!indexBuf, pnum, Word16.fromInt(pnum));
343 :     fillPosBuffer(particles, posBuf, indexBuf, maxParticles, pnum + 1)
344 :     end
345 :     | fillPosBuffer([], posBuf, indexBuf, maxParticles, pnum) =
346 :     if(pnum < maxParticles) then
347 :     (
348 :     DB.set3f(!posBuf, pnum, (0.0, 0.0, 0.0));
349 :     fillPosBuffer([], posBuf, indexBuf, maxParticles, pnum + 1)
350 :     )
351 :     else
352 :     ()
353 :    
354 :    
355 : pavelk 429 fun renderParticle (P{pos, size, vel, color, ...}) = (
356 :     GL.color4fv (color);
357 :     GL.vertex3fv (pos);
358 : pavelk 435 GL.vertex3fv (V.adds(pos, 0.1,vel))
359 : pavelk 429 )
360 : jhr 1
361 : jhr 463 fun render (particleGroup) = let
362 :     val PG{count, maxParticles, posBuf, particles, ...} = particleGroup
363 :     in
364 :     if (!count > 0)
365 :     then let
366 : pavelk 458 val indexBuf = DB.new(DB.sizeus, !count)
367 : jhr 463 in
368 : pavelk 458 GL.blendFunc {src=GL.SRC_ALPHA, dst=GL.ONE_MINUS_SRC_ALPHA};
369 :     GL.enable(GL.BLEND);
370 :     GL.depthMask (false);
371 :     (*GL.beginPrim (GL.LINES);
372 :     List.app renderParticle (!particles);
373 :     GL.endPrim (); *)
374 :     fillPosBuffer(!particles, ref posBuf, ref indexBuf, maxParticles, 0);
375 :     GL.enableClientState(GL.VERTEX_ARRAY);
376 :     GL.vertexArray3f(posBuf);
377 :     GL.drawElementsus(GL.POINTS, indexBuf);
378 :     GL.disable(GL.BLEND)
379 :     end
380 : jhr 463 else ()
381 :     end
382 : jhr 1
383 : pavelk 429 (******** Action list stuff *********)
384 :     fun avoid{magnitude : float,
385 :     epsilon : float,
386 :     lookAhead : float,
387 :     d : domain} : action
388 :     = fn(PG{...}) => ()
389 :    
390 :     fun bounce {
391 :     friction : float, resilience : float, cutoff : float, d : domain
392 : pavelk 438 } : action = let
393 :     fun bounceParticles(dt, [], npl) = npl
394 :     | bounceParticles(dt, p :: pl, npl) = let
395 :     val P{pos, size, vel, color, age} = p
396 :     in
397 :     if within(d, V.adds(pos, !dt, vel)) then let
398 :     (* Assume we are at the point of collision *)
399 :     val n = (case d
400 :     of Dtriangle(v1, v2, v3) => Vec3f.pack (0.0, 1.0, 0.0)
401 :    
402 :     | Dplane{pt : vec3f, n : vec3f} => n
403 :    
404 :     | Drectangle{pt : vec3f, u : vec3f, v : vec3f} => Vec3f.normalize(Vec3f.cross(u, v))
405 :     | Dbox{min : vec3f, max : vec3f} =>
406 :     (* Here we need to figure out what face we're colliding
407 :     * against... after that it's trivial.
408 :     *)
409 :     Vec3f.pack(0.0, 1.0, 0.0)
410 :    
411 :     | Dsphere{c : vec3f, orad : float, irad : float} =>
412 :    
413 :     Vec3f.normalize(V.sub(pos, c))
414 :    
415 :     | Dcylinder{u : vec3f, v : vec3f, orad : float, irad : float} =>
416 :     (* Too tricky... needs thought *)
417 :     Vec3f.pack(0.0, 1.0, 0.0)
418 :    
419 :     | Dcone{u : vec3f, v : vec3f, orad : float, irad : float} =>
420 :     (* Too tricky... needs thought *)
421 :     Vec3f.pack(0.0, 1.0, 0.0)
422 :    
423 :     | Dblob{c : vec3f, stddev : float} =>
424 :     (* Too tricky... needs thought *)
425 :     Vec3f.pack(0.0, 1.0, 0.0)
426 :    
427 :     | Ddisc{c : vec3f, n : vec3f, orad : float, irad : float} =>
428 :     if within(Dplane{pt = c, n = n}, pos) then n else Vec3f.scale(~1.0, n)
429 :    
430 :     | _ => raise Fail("Cannot bounce specified domain.")
431 :     ) (** end case **)
432 :    
433 :     val negVel = Vec3f.scale(~1.0, vel)
434 :     val norm = Vec3f.scale(Vec3f.dot(negVel, n), n)
435 :     val tang = V.sub(negVel, norm)
436 :     val newVel = if(Vec3f.lengthSq(tang) > cutoff * cutoff) then
437 :     Vec3f.add(Vec3f.scale(~1.0 * (1.0 - friction), tang), Vec3f.scale(resilience, norm))
438 :     else
439 :     Vec3f.add(Vec3f.scale(~1.0, tang), Vec3f.scale(resilience, norm))
440 :     in
441 :     (*printErr "Bouncing particle:";
442 :     printErr "Old velocity";
443 :     printErr (Vec3f.toString vel);
444 :     printErr "New velocity";
445 :     printErr (Vec3f.toString newVel);*)
446 :     bounceParticles(dt, pl, P{pos = pos, size = size, vel = newVel, color = color, age = age} :: npl)
447 :     end
448 :     else
449 :     bounceParticles(dt, pl, p :: npl)
450 :     end
451 :     in
452 :     fn(PG{particles, dt, ...}) => particles := bounceParticles(dt, !particles, [])
453 :     end
454 :    
455 :    
456 : pavelk 429 fun damping {coeff : vec3f, vlow : float, vhi : float} : action = fn(PG{...}) => ()
457 :     fun explosion {
458 :     center : vec3f, velocity : float, magnitude : float,
459 :     stdev : float, epsilon : float, age : float
460 :     } : action = fn(PG{...}) => ()
461 :     fun follow {magnitude : float, epsilon : float, maxRadius : float} : action = fn(PG{...}) => ()
462 :     fun gravitate {mag : float, epsilon : float, maxRad : float} : action = fn(PG{...}) => ()
463 : pavelk 435
464 :     fun gravity(g : vec3f) =
465 :     let
466 :     fun dampenParticles(dt, dir, [], npl) = npl
467 :     | dampenParticles (dt, dir, p :: pl, npl) = let
468 :     val P{pos, size, vel, color, age} = p
469 :     val newp = P{pos = pos, size=size, vel=V.adds(vel, !dt, dir), color = color, age = age}
470 :     in
471 :     dampenParticles (dt, dir, pl, newp :: npl)
472 :     end
473 :     in
474 :     fn(PG{particles, dt, ...}) => particles := dampenParticles(dt, g, !particles, [])
475 :     end
476 :    
477 : pavelk 429 fun jet {center : vec3f, mag : float, epsilon : float, maxRad : float} : action =
478 :     fn(PG{...}) => ()
479 :     fun killOld {ageLimit : float} : action = fn(PG{...}) => ()
480 :     fun killYoung {ageLimit : float} : action = fn(PG{...}) => ()
481 :     fun matchVelocity {mag : float, epsilon : float, maxRad : float} : action = fn(PG{...}) => ()
482 :    
483 : pavelk 435 fun move (PG{particles, dt, ...}) = let
484 :     fun createMovedParticles (dt, [], npl) = npl
485 :     | createMovedParticles (dt, p :: pl, npl) = let
486 : jhr 434 val P{pos, size, vel, color, age} = p
487 : pavelk 435 val newp = P{pos = V.adds(pos, !dt, vel), size=size, vel=vel, color = color, age = age}
488 : jhr 434 in
489 : pavelk 435 createMovedParticles (dt, pl, newp :: npl)
490 : jhr 434 end
491 :     in
492 : pavelk 435 particles := createMovedParticles (dt, !particles, [])
493 : jhr 434 end
494 : pavelk 429
495 :     fun orbitLine {p : vec3f, axis : vec3f,
496 :     mag : float, epsilon : float, maxRad : float
497 :     } : action = fn(PG{...}) => ()
498 :     fun orbitPoint {center : vec3f, mag : float, epsilon : float, maxRad : float} : action
499 :     = fn(PG{...}) => ()
500 :     fun randomAccel(domain) = fn(PG{...}) => ()
501 :     fun randomDisplace(domain) = fn(PG{...}) => ()
502 :     fun randomVelocity(domain) = fn(PG{...}) => ()
503 :     fun restore(float) = fn(PG{...}) => ()
504 :     fun shade {color : color4f, scale : float} : action = fn(PG{...}) => ()
505 :    
506 : pavelk 437 fun sink {killInside : bool, d : domain} : action = let
507 :     fun sinkParticles (count, [], npl) = npl
508 :     | sinkParticles (count, p :: pl, npl) = let
509 :     val P{pos, size, vel, color, age} = p
510 :     in
511 :     if not (within(d, pos) xor killInside) then
512 :     sinkParticles(count, pl, npl) (* kill it *)
513 :     else
514 :     (count := !count + 1;
515 :     sinkParticles (count, pl, p :: npl))
516 :     end
517 :     in
518 :     fn(PG{count, particles, ...}) => let
519 :     val newAmt = ref 0
520 :     in
521 :     particles := sinkParticles(newAmt, !particles, []);
522 :     count := !newAmt
523 :     end
524 :     end
525 :    
526 : pavelk 429
527 :     fun sinkVelocity {killInside : bool, d : domain} : action = fn(PG{...}) => ()
528 :    
529 : pavelk 438 fun source {maxNum : float, d : domain} : action =
530 : pavelk 429 let
531 :     fun addParticle(pg : particle_group, numLeft, d) =
532 :     if(numLeft > 0) andalso add(pg, d) then
533 :     addParticle(pg, numLeft - 1, d)
534 :     else ()
535 :     in
536 : pavelk 438 fn(pg : particle_group) => let
537 :     val PG{dt, ...} = pg
538 :     in
539 :     addParticle(pg, Float.roundToInt(maxNum * !dt), d)
540 :     end
541 : pavelk 429 end
542 :    
543 :    
544 :     fun speedLimit {min : float, max : float} : action = fn(PG{...}) => ()
545 :     fun targetColor {color : color4f, scale : float} : action = fn(PG{...}) => ()
546 :     fun targetSize {size : vec3f, scale : vec3f} : action = fn(PG{...}) => ()
547 :     fun targetVelocity(v : vec3f, mag : float) = fn(PG{...}) => ()
548 :     fun vertex(vec3f) = fn(PG{...}) => ()
549 :     fun vortex {
550 :     center : vec3f, axis : vec3f, mag : float,
551 :     epsilon : float, maxRad : float
552 :     } : action = fn(PG{...}) => ()
553 : jhr 1
554 :    
555 : jhr 434 fun addAction(PG{actions, ...}, a) = actions := a :: !actions
556 :    
557 : jhr 1 end

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0