1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21// LOVE
22#include "wrap_ParticleSystem.h"
23#include "common/Vector.h"
24
25#include "Image.h"
26#include "Canvas.h"
27#include "wrap_Texture.h"
28
29// C
30#include <cstring>
31
32namespace love
33{
34namespace graphics
35{
36
37ParticleSystem *luax_checkparticlesystem(lua_State *L, int idx)
38{
39 return luax_checktype<ParticleSystem>(L, idx);
40}
41
42int w_ParticleSystem_clone(lua_State *L)
43{
44 ParticleSystem *t = luax_checkparticlesystem(L, 1);
45
46 ParticleSystem *clone = nullptr;
47 luax_catchexcept(L, [&](){ clone = t->clone(); });
48
49 luax_pushtype(L, clone);
50 clone->release();
51 return 1;
52}
53
54int w_ParticleSystem_setTexture(lua_State *L)
55{
56 ParticleSystem *t = luax_checkparticlesystem(L, 1);
57 Texture *tex = luax_checktexture(L, 2);
58 luax_catchexcept(L, [&](){ t->setTexture(tex); });
59 return 0;
60}
61
62int w_ParticleSystem_getTexture(lua_State *L)
63{
64 ParticleSystem *t = luax_checkparticlesystem(L, 1);
65 Texture *tex = t->getTexture();
66
67 // FIXME: big hack right here.
68 if (dynamic_cast<Image *>(tex) != nullptr)
69 luax_pushtype(L, Image::type, tex);
70 else if (dynamic_cast<Canvas *>(tex) != nullptr)
71 luax_pushtype(L, Canvas::type, tex);
72 else
73 return luaL_error(L, "Unable to determine texture type.");
74
75 return 1;
76}
77
78int w_ParticleSystem_setBufferSize(lua_State *L)
79{
80 ParticleSystem *t = luax_checkparticlesystem(L, 1);
81 lua_Number arg1 = luaL_checknumber(L, 2);
82 if (arg1 < 1.0 || arg1 > ParticleSystem::MAX_PARTICLES)
83 return luaL_error(L, "Invalid buffer size");
84
85 luax_catchexcept(L, [&](){ t->setBufferSize((uint32) arg1); });
86 return 0;
87}
88
89int w_ParticleSystem_getBufferSize(lua_State *L)
90{
91 ParticleSystem *t = luax_checkparticlesystem(L, 1);
92 lua_pushinteger(L, t->getBufferSize());
93 return 1;
94}
95
96int w_ParticleSystem_setInsertMode(lua_State *L)
97{
98 ParticleSystem *t = luax_checkparticlesystem(L, 1);
99 ParticleSystem::InsertMode mode;
100 const char *str = luaL_checkstring(L, 2);
101 if (!ParticleSystem::getConstant(str, mode))
102 return luax_enumerror(L, "insert mode", ParticleSystem::getConstants(mode), str);
103 t->setInsertMode(mode);
104 return 0;
105}
106
107int w_ParticleSystem_getInsertMode(lua_State *L)
108{
109 ParticleSystem *t = luax_checkparticlesystem(L, 1);
110 ParticleSystem::InsertMode mode;
111 mode = t->getInsertMode();
112 const char *str;
113 if (!ParticleSystem::getConstant(mode, str))
114 return luaL_error(L, "Unknown insert mode");
115 lua_pushstring(L, str);
116 return 1;
117}
118
119int w_ParticleSystem_setEmissionRate(lua_State *L)
120{
121 ParticleSystem *t = luax_checkparticlesystem(L, 1);
122 float arg1 = (float) luaL_checknumber(L, 2);
123 luax_catchexcept(L, [&](){ t->setEmissionRate(arg1); });
124 return 0;
125}
126
127int w_ParticleSystem_getEmissionRate(lua_State *L)
128{
129 ParticleSystem *t = luax_checkparticlesystem(L, 1);
130 lua_pushnumber(L, t->getEmissionRate());
131 return 1;
132}
133
134int w_ParticleSystem_setEmitterLifetime(lua_State *L)
135{
136 ParticleSystem *t = luax_checkparticlesystem(L, 1);
137 float arg1 = (float)luaL_checknumber(L, 2);
138 t->setEmitterLifetime(arg1);
139 return 0;
140}
141
142int w_ParticleSystem_getEmitterLifetime(lua_State *L)
143{
144 ParticleSystem *t = luax_checkparticlesystem(L, 1);
145 lua_pushnumber(L, t->getEmitterLifetime());
146 return 1;
147}
148
149int w_ParticleSystem_setParticleLifetime(lua_State *L)
150{
151 ParticleSystem *t = luax_checkparticlesystem(L, 1);
152 float arg1 = (float)luaL_checknumber(L, 2);
153 float arg2 = (float)luaL_optnumber(L, 3, arg1);
154
155 if (arg1 < 0.0f || arg2 < 0.0f)
156 return luaL_error(L, "Invalid particle lifetime (must be >= 0)");
157
158 t->setParticleLifetime(arg1, arg2);
159 return 0;
160}
161
162int w_ParticleSystem_getParticleLifetime(lua_State *L)
163{
164 ParticleSystem *t = luax_checkparticlesystem(L, 1);
165 float min, max;
166 t->getParticleLifetime(min, max);
167 lua_pushnumber(L, min);
168 lua_pushnumber(L, max);
169 return 2;
170}
171
172int w_ParticleSystem_setPosition(lua_State *L)
173{
174 ParticleSystem *t = luax_checkparticlesystem(L, 1);
175 float arg1 = (float)luaL_checknumber(L, 2);
176 float arg2 = (float)luaL_checknumber(L, 3);
177 t->setPosition(arg1, arg2);
178 return 0;
179}
180
181int w_ParticleSystem_getPosition(lua_State *L)
182{
183 ParticleSystem *t = luax_checkparticlesystem(L, 1);
184 love::Vector2 pos = t->getPosition();
185 lua_pushnumber(L, pos.x);
186 lua_pushnumber(L, pos.y);
187 return 2;
188}
189
190int w_ParticleSystem_moveTo(lua_State *L)
191{
192 ParticleSystem *t = luax_checkparticlesystem(L, 1);
193 float arg1 = (float)luaL_checknumber(L, 2);
194 float arg2 = (float)luaL_checknumber(L, 3);
195 t->moveTo(arg1, arg2);
196 return 0;
197}
198
199int w_ParticleSystem_setEmissionArea(lua_State *L)
200{
201 ParticleSystem *t = luax_checkparticlesystem(L, 1);
202
203 ParticleSystem::AreaSpreadDistribution distribution = ParticleSystem::DISTRIBUTION_NONE;
204 float x = 0.f, y = 0.f;
205 float angle = 0.0f;
206 bool directionRelativeToCenter = false;
207
208 const char *str = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2);
209 if (str && !ParticleSystem::getConstant(str, distribution))
210 return luax_enumerror(L, "particle distribution", ParticleSystem::getConstants(distribution), str);
211
212 if (distribution != ParticleSystem::DISTRIBUTION_NONE)
213 {
214 x = (float) luaL_checknumber(L, 3);
215 y = (float) luaL_checknumber(L, 4);
216 if (x < 0.0f || y < 0.0f)
217 return luaL_error(L, "Invalid area spread parameters (must be >= 0)");
218
219 angle = (float) luaL_optnumber(L, 5, 0.0f);
220 directionRelativeToCenter = luax_optboolean(L, 6, false);
221 }
222
223 t->setEmissionArea(distribution, x, y, angle, directionRelativeToCenter);
224 return 0;
225}
226
227int w_ParticleSystem_getEmissionArea(lua_State *L)
228{
229 ParticleSystem *t = luax_checkparticlesystem(L, 1);
230 love::Vector2 p;
231 float angle;
232 bool directionRelativeToCenter;
233 ParticleSystem::AreaSpreadDistribution distribution = t->getEmissionArea(p, angle, directionRelativeToCenter);
234 const char *str;
235 ParticleSystem::getConstant(distribution, str);
236
237 lua_pushstring(L, str);
238 lua_pushnumber(L, p.x);
239 lua_pushnumber(L, p.y);
240 lua_pushnumber(L, angle);
241 luax_pushboolean(L, directionRelativeToCenter);
242
243 return 5;
244}
245
246int w_ParticleSystem_setDirection(lua_State *L)
247{
248 ParticleSystem *t = luax_checkparticlesystem(L, 1);
249 float arg1 = (float)luaL_checknumber(L, 2);
250 t->setDirection(arg1);
251 return 0;
252}
253
254int w_ParticleSystem_getDirection(lua_State *L)
255{
256 ParticleSystem *t = luax_checkparticlesystem(L, 1);
257 lua_pushnumber(L, t->getDirection());
258 return 1;
259}
260
261int w_ParticleSystem_setSpread(lua_State *L)
262{
263 ParticleSystem *t = luax_checkparticlesystem(L, 1);
264 float arg1 = (float)luaL_checknumber(L, 2);
265 t->setSpread(arg1);
266 return 0;
267}
268
269int w_ParticleSystem_getSpread(lua_State *L)
270{
271 ParticleSystem *t = luax_checkparticlesystem(L, 1);
272 lua_pushnumber(L, t->getSpread());
273 return 1;
274}
275
276int w_ParticleSystem_setSpeed(lua_State *L)
277{
278 ParticleSystem *t = luax_checkparticlesystem(L, 1);
279 float arg1 = (float)luaL_checknumber(L, 2);
280 float arg2 = (float)luaL_optnumber(L, 3, arg1);
281 t->setSpeed(arg1, arg2);
282 return 0;
283}
284
285int w_ParticleSystem_getSpeed(lua_State *L)
286{
287 ParticleSystem *t = luax_checkparticlesystem(L, 1);
288 float min, max;
289 t->getSpeed(min, max);
290 lua_pushnumber(L, min);
291 lua_pushnumber(L, max);
292 return 2;
293}
294
295int w_ParticleSystem_setLinearAcceleration(lua_State *L)
296{
297 ParticleSystem *t = luax_checkparticlesystem(L, 1);
298 float xmin = (float) luaL_checknumber(L, 2);
299 float ymin = (float) luaL_checknumber(L, 3);
300 float xmax = (float) luaL_optnumber(L, 4, xmin);
301 float ymax = (float) luaL_optnumber(L, 5, ymin);
302 t->setLinearAcceleration(xmin, ymin, xmax, ymax);
303 return 0;
304}
305
306int w_ParticleSystem_getLinearAcceleration(lua_State *L)
307{
308 ParticleSystem *t = luax_checkparticlesystem(L, 1);
309 love::Vector2 min, max;
310 t->getLinearAcceleration(min, max);
311 lua_pushnumber(L, min.x);
312 lua_pushnumber(L, min.y);
313 lua_pushnumber(L, max.x);
314 lua_pushnumber(L, max.y);
315 return 4;
316}
317
318int w_ParticleSystem_setRadialAcceleration(lua_State *L)
319{
320 ParticleSystem *t = luax_checkparticlesystem(L, 1);
321 float arg1 = (float)luaL_checknumber(L, 2);
322 float arg2 = (float)luaL_optnumber(L, 3, arg1);
323 t->setRadialAcceleration(arg1, arg2);
324 return 0;
325}
326
327int w_ParticleSystem_getRadialAcceleration(lua_State *L)
328{
329 ParticleSystem *t = luax_checkparticlesystem(L, 1);
330 float min, max;
331 t->getRadialAcceleration(min, max);
332 lua_pushnumber(L, min);
333 lua_pushnumber(L, max);
334 return 2;
335}
336
337int w_ParticleSystem_setTangentialAcceleration(lua_State *L)
338{
339 ParticleSystem *t = luax_checkparticlesystem(L, 1);
340 float arg1 = (float)luaL_checknumber(L, 2);
341 float arg2 = (float)luaL_optnumber(L, 3, arg1);
342 t->setTangentialAcceleration(arg1, arg2);
343 return 0;
344}
345
346int w_ParticleSystem_getTangentialAcceleration(lua_State *L)
347{
348 ParticleSystem *t = luax_checkparticlesystem(L, 1);
349 float min, max;
350 t->getTangentialAcceleration(min, max);
351 lua_pushnumber(L, min);
352 lua_pushnumber(L, max);
353 return 2;
354}
355
356int w_ParticleSystem_setLinearDamping(lua_State *L)
357{
358 ParticleSystem *t = luax_checkparticlesystem(L, 1);
359 float arg1 = (float)luaL_checknumber(L, 2);
360 float arg2 = (float)luaL_optnumber(L, 3, arg1);
361 t->setLinearDamping(arg1, arg2);
362 return 0;
363}
364
365int w_ParticleSystem_getLinearDamping(lua_State *L)
366{
367 ParticleSystem *t = luax_checkparticlesystem(L, 1);
368 float min, max;
369 t->getLinearDamping(min, max);
370 lua_pushnumber(L, min);
371 lua_pushnumber(L, max);
372 return 2;
373}
374
375int w_ParticleSystem_setSizes(lua_State *L)
376{
377 ParticleSystem *t = luax_checkparticlesystem(L, 1);
378 size_t nSizes = lua_gettop(L) - 1;
379
380 if (nSizes > 8)
381 return luaL_error(L, "At most eight (8) sizes may be used.");
382
383 if (nSizes <= 1)
384 {
385 float size = luax_checkfloat(L, 2);
386 t->setSize(size);
387 }
388 else
389 {
390 std::vector<float> sizes(nSizes);
391 for (size_t i = 0; i < nSizes; ++i)
392 sizes[i] = luax_checkfloat(L, (int) (1 + i + 1));
393
394 t->setSizes(sizes);
395 }
396 return 0;
397}
398
399int w_ParticleSystem_getSizes(lua_State *L)
400{
401 ParticleSystem *t = luax_checkparticlesystem(L, 1);
402 const std::vector<float> &sizes = t->getSizes();
403
404 for (size_t i = 0; i < sizes.size(); i++)
405 lua_pushnumber(L, sizes[i]);
406
407 return (int) sizes.size();
408}
409
410int w_ParticleSystem_setSizeVariation(lua_State *L)
411{
412 ParticleSystem *t = luax_checkparticlesystem(L, 1);
413 float arg1 = (float)luaL_checknumber(L, 2);
414 if (arg1 < 0.0f || arg1 > 1.0f)
415 return luaL_error(L, "Size variation has to be between 0 and 1, inclusive.");
416
417 t->setSizeVariation(arg1);
418 return 0;
419}
420
421int w_ParticleSystem_getSizeVariation(lua_State *L)
422{
423 ParticleSystem *t = luax_checkparticlesystem(L, 1);
424 lua_pushnumber(L, t->getSizeVariation());
425 return 1;
426}
427
428int w_ParticleSystem_setRotation(lua_State *L)
429{
430 ParticleSystem *t = luax_checkparticlesystem(L, 1);
431 float arg1 = (float)luaL_checknumber(L, 2);
432 float arg2 = (float)luaL_optnumber(L, 3, arg1);
433 t->setRotation(arg1, arg2);
434 return 0;
435}
436
437int w_ParticleSystem_getRotation(lua_State *L)
438{
439 ParticleSystem *t = luax_checkparticlesystem(L, 1);
440 float min, max;
441 t->getRotation(min, max);
442 lua_pushnumber(L, min);
443 lua_pushnumber(L, max);
444 return 2;
445}
446
447int w_ParticleSystem_setSpin(lua_State *L)
448{
449 ParticleSystem *t = luax_checkparticlesystem(L, 1);
450 float arg1 = (float)luaL_checknumber(L, 2);
451 float arg2 = (float)luaL_optnumber(L, 3, arg1);
452 t->setSpin(arg1, arg2);
453 return 0;
454}
455
456int w_ParticleSystem_getSpin(lua_State *L)
457{
458 ParticleSystem *t = luax_checkparticlesystem(L, 1);
459 float start, end;
460 t->getSpin(start, end);
461 lua_pushnumber(L, start);
462 lua_pushnumber(L, end);
463 return 2;
464}
465
466int w_ParticleSystem_setSpinVariation(lua_State *L)
467{
468 ParticleSystem *t = luax_checkparticlesystem(L, 1);
469 float arg1 = (float)luaL_checknumber(L, 2);
470 t->setSpinVariation(arg1);
471 return 0;
472}
473
474int w_ParticleSystem_getSpinVariation(lua_State *L)
475{
476 ParticleSystem *t = luax_checkparticlesystem(L, 1);
477 lua_pushnumber(L, t->getSpinVariation());
478 return 1;
479}
480
481int w_ParticleSystem_setOffset(lua_State *L)
482{
483 ParticleSystem *t = luax_checkparticlesystem(L, 1);
484 float x = (float)luaL_checknumber(L, 2);
485 float y = (float)luaL_checknumber(L, 3);
486 t->setOffset(x, y);
487 return 0;
488}
489
490int w_ParticleSystem_getOffset(lua_State *L)
491{
492 ParticleSystem *t = luax_checkparticlesystem(L, 1);
493 love::Vector2 offset = t->getOffset();
494 lua_pushnumber(L, offset.x);
495 lua_pushnumber(L, offset.y);
496 return 2;
497}
498
499int w_ParticleSystem_setColors(lua_State *L)
500{
501 ParticleSystem *t = luax_checkparticlesystem(L, 1);
502
503 if (lua_istable(L, 2)) // setColors({r,g,b,a}, {r,g,b,a}, ...)
504 {
505 int nColors = (int) lua_gettop(L) - 1;
506
507 if (nColors > 8)
508 return luaL_error(L, "At most eight (8) colors may be used.");
509
510 std::vector<Colorf> colors(nColors);
511
512 for (int i = 0; i < nColors; i++)
513 {
514 luaL_checktype(L, i + 2, LUA_TTABLE);
515
516 if (luax_objlen(L, i + 2) < 3)
517 return luaL_argerror(L, i + 2, "expected 4 color components");
518
519 for (int j = 0; j < 4; j++)
520 // push args[i+2][j+1] onto the stack
521 lua_rawgeti(L, i + 2, j + 1);
522
523 colors[i].r = (float) luaL_checknumber(L, -4);
524 colors[i].g = (float) luaL_checknumber(L, -3);
525 colors[i].b = (float) luaL_checknumber(L, -2);
526 colors[i].a = (float) luaL_optnumber(L, -1, 1.0);
527
528 // pop the color components from the stack
529 lua_pop(L, 4);
530 }
531
532 t->setColor(colors);
533 }
534 else // setColors(r,g,b,a, r,g,b,a, ...)
535 {
536 int cargs = lua_gettop(L) - 1;
537 int nColors = (cargs + 3) / 4; // nColors = ceil(color_args / 4)
538
539 if (cargs != 3 && (cargs % 4 != 0 || cargs == 0))
540 return luaL_error(L, "Expected red, green, blue, and alpha. Only got %d of 4 components.", cargs % 4);
541
542 if (nColors > 8)
543 return luaL_error(L, "At most eight (8) colors may be used.");
544
545 std::vector<Colorf> colors(nColors);
546
547 for (int i = 0; i < nColors; ++i)
548 {
549 colors[i].r = (float) luaL_checknumber(L, 1 + i*4 + 1);
550 colors[i].g = (float) luaL_checknumber(L, 1 + i*4 + 2);
551 colors[i].b = (float) luaL_checknumber(L, 1 + i*4 + 3);
552 colors[i].a = (float) luaL_checknumber(L, 1 + i*4 + 4);
553 }
554
555 t->setColor(colors);
556 }
557
558 return 0;
559}
560
561int w_ParticleSystem_getColors(lua_State *L)
562{
563 ParticleSystem *t = luax_checkparticlesystem(L, 1);
564
565 const std::vector<Colorf> &colors =t->getColor();
566
567 for (size_t i = 0; i < colors.size(); i++)
568 {
569 lua_createtable(L, 4, 0);
570
571 lua_pushnumber(L, colors[i].r);
572 lua_rawseti(L, -2, 1);
573 lua_pushnumber(L, colors[i].g);
574 lua_rawseti(L, -2, 2);
575 lua_pushnumber(L, colors[i].b);
576 lua_rawseti(L, -2, 3);
577 lua_pushnumber(L, colors[i].a);
578 lua_rawseti(L, -2, 4);
579 }
580
581 return (int) colors.size();
582}
583
584int w_ParticleSystem_setQuads(lua_State *L)
585{
586 ParticleSystem *t = luax_checkparticlesystem(L, 1);
587 std::vector<Quad *> quads;
588
589 if (lua_istable(L, 2))
590 {
591 for (int i = 1; i <= (int) luax_objlen(L, 2); i++)
592 {
593 lua_rawgeti(L, 2, i);
594
595 Quad *q = luax_checktype<Quad>(L, -1);
596 quads.push_back(q);
597
598 lua_pop(L, 1);
599 }
600 }
601 else
602 {
603 for (int i = 2; i <= lua_gettop(L); i++)
604 {
605 Quad *q = luax_checktype<Quad>(L, i);
606 quads.push_back(q);
607 }
608 }
609
610 t->setQuads(quads);
611 return 0;
612}
613
614int w_ParticleSystem_getQuads(lua_State *L)
615{
616 ParticleSystem *t = luax_checkparticlesystem(L, 1);
617 const std::vector<Quad *> quads = t->getQuads();
618
619 lua_createtable(L, (int) quads.size(), 0);
620
621 for (int i = 0; i < (int) quads.size(); i++)
622 {
623 luax_pushtype(L, quads[i]);
624 lua_rawseti(L, -2, i + 1);
625 }
626
627 return 1;
628}
629
630int w_ParticleSystem_setRelativeRotation(lua_State *L)
631{
632 ParticleSystem *t = luax_checkparticlesystem(L, 1);
633 t->setRelativeRotation(luax_checkboolean(L, 2));
634 return 0;
635}
636
637int w_ParticleSystem_hasRelativeRotation(lua_State *L)
638{
639 ParticleSystem *t = luax_checkparticlesystem(L, 1);
640 luax_pushboolean(L, t->hasRelativeRotation());
641 return 1;
642}
643
644int w_ParticleSystem_getCount(lua_State *L)
645{
646 ParticleSystem *t = luax_checkparticlesystem(L, 1);
647 lua_pushnumber(L, t->getCount());
648 return 1;
649}
650
651int w_ParticleSystem_start(lua_State *L)
652{
653 ParticleSystem *t = luax_checkparticlesystem(L, 1);
654 t->start();
655 return 0;
656}
657
658int w_ParticleSystem_stop(lua_State *L)
659{
660 ParticleSystem *t = luax_checkparticlesystem(L, 1);
661 t->stop();
662 return 0;
663}
664
665int w_ParticleSystem_pause(lua_State *L)
666{
667 ParticleSystem *t = luax_checkparticlesystem(L, 1);
668 t->pause();
669 return 0;
670}
671
672int w_ParticleSystem_reset(lua_State *L)
673{
674 ParticleSystem *t = luax_checkparticlesystem(L, 1);
675 t->reset();
676 return 0;
677}
678
679int w_ParticleSystem_emit(lua_State *L)
680{
681 ParticleSystem *t = luax_checkparticlesystem(L, 1);
682 int num = (int) luaL_checkinteger(L, 2);
683 t->emit(num);
684 return 0;
685}
686
687int w_ParticleSystem_isActive(lua_State *L)
688{
689 ParticleSystem *t = luax_checkparticlesystem(L, 1);
690 luax_pushboolean(L, t->isActive());
691 return 1;
692}
693
694int w_ParticleSystem_isPaused(lua_State *L)
695{
696 ParticleSystem *t = luax_checkparticlesystem(L, 1);
697 luax_pushboolean(L, t->isPaused());
698 return 1;
699}
700
701int w_ParticleSystem_isStopped(lua_State *L)
702{
703 ParticleSystem *t = luax_checkparticlesystem(L, 1);
704 luax_pushboolean(L, t->isStopped());
705 return 1;
706}
707
708int w_ParticleSystem_update(lua_State *L)
709{
710 ParticleSystem *t = luax_checkparticlesystem(L, 1);
711 float dt = (float)luaL_checknumber(L, 2);
712 t->update(dt);
713 return 0;
714}
715
716// Deprecated functions.
717
718int w_ParticleSystem_setAreaSpread(lua_State *L)
719{
720 luax_markdeprecated(L, "ParticleSystem:setAreaSpread", API_METHOD, DEPRECATED_REPLACED, "ParticleSystem:setEmissionArea");
721
722 ParticleSystem *t = luax_checkparticlesystem(L, 1);
723
724 ParticleSystem::AreaSpreadDistribution distribution = ParticleSystem::DISTRIBUTION_NONE;
725 float x = 0.f, y = 0.f;
726
727 const char *str = lua_isnoneornil(L, 2) ? 0 : luaL_checkstring(L, 2);
728 if (str && !ParticleSystem::getConstant(str, distribution))
729 return luax_enumerror(L, "particle distribution", ParticleSystem::getConstants(distribution), str);
730
731 if (distribution != ParticleSystem::DISTRIBUTION_NONE)
732 {
733 x = (float) luaL_checknumber(L, 3);
734 y = (float) luaL_checknumber(L, 4);
735 if (x < 0.0f || y < 0.0f)
736 return luaL_error(L, "Invalid area spread parameters (must be >= 0)");
737 }
738
739 t->setEmissionArea(distribution, x, y, 0.0f, false);
740 return 0;
741}
742
743int w_ParticleSystem_getAreaSpread(lua_State *L)
744{
745 luax_markdeprecated(L, "ParticleSystem:getAreaSpread", API_METHOD, DEPRECATED_REPLACED, "ParticleSystem:getEmissionArea");
746
747 ParticleSystem *t = luax_checkparticlesystem(L, 1);
748 love::Vector2 p;
749 float angle;
750 bool unused;
751 ParticleSystem::AreaSpreadDistribution distribution = t->getEmissionArea(p, angle, unused);
752 const char *str;
753 ParticleSystem::getConstant(distribution, str);
754
755 lua_pushstring(L, str);
756 lua_pushnumber(L, p.x);
757 lua_pushnumber(L, p.y);
758
759 return 3;
760}
761
762static const luaL_Reg w_ParticleSystem_functions[] =
763{
764 { "clone", w_ParticleSystem_clone },
765 { "setTexture", w_ParticleSystem_setTexture },
766 { "getTexture", w_ParticleSystem_getTexture },
767 { "setBufferSize", w_ParticleSystem_setBufferSize },
768 { "getBufferSize", w_ParticleSystem_getBufferSize },
769 { "setInsertMode", w_ParticleSystem_setInsertMode },
770 { "getInsertMode", w_ParticleSystem_getInsertMode },
771 { "setEmissionRate", w_ParticleSystem_setEmissionRate },
772 { "getEmissionRate", w_ParticleSystem_getEmissionRate },
773 { "setEmitterLifetime", w_ParticleSystem_setEmitterLifetime },
774 { "getEmitterLifetime", w_ParticleSystem_getEmitterLifetime },
775 { "setParticleLifetime", w_ParticleSystem_setParticleLifetime },
776 { "getParticleLifetime", w_ParticleSystem_getParticleLifetime },
777 { "setPosition", w_ParticleSystem_setPosition },
778 { "getPosition", w_ParticleSystem_getPosition },
779 { "moveTo", w_ParticleSystem_moveTo },
780 { "setEmissionArea", w_ParticleSystem_setEmissionArea },
781 { "getEmissionArea", w_ParticleSystem_getEmissionArea },
782 { "setDirection", w_ParticleSystem_setDirection },
783 { "getDirection", w_ParticleSystem_getDirection },
784 { "setSpread", w_ParticleSystem_setSpread },
785 { "getSpread", w_ParticleSystem_getSpread },
786 { "setSpeed", w_ParticleSystem_setSpeed },
787 { "getSpeed", w_ParticleSystem_getSpeed },
788 { "setLinearAcceleration", w_ParticleSystem_setLinearAcceleration },
789 { "getLinearAcceleration", w_ParticleSystem_getLinearAcceleration },
790 { "setRadialAcceleration", w_ParticleSystem_setRadialAcceleration },
791 { "getRadialAcceleration", w_ParticleSystem_getRadialAcceleration },
792 { "setTangentialAcceleration", w_ParticleSystem_setTangentialAcceleration },
793 { "getTangentialAcceleration", w_ParticleSystem_getTangentialAcceleration },
794 { "setLinearDamping", w_ParticleSystem_setLinearDamping },
795 { "getLinearDamping", w_ParticleSystem_getLinearDamping },
796 { "setSizes", w_ParticleSystem_setSizes },
797 { "getSizes", w_ParticleSystem_getSizes },
798 { "setSizeVariation", w_ParticleSystem_setSizeVariation },
799 { "getSizeVariation", w_ParticleSystem_getSizeVariation },
800 { "setRotation", w_ParticleSystem_setRotation },
801 { "getRotation", w_ParticleSystem_getRotation },
802 { "setSpin", w_ParticleSystem_setSpin },
803 { "getSpin", w_ParticleSystem_getSpin },
804 { "setSpinVariation", w_ParticleSystem_setSpinVariation },
805 { "getSpinVariation", w_ParticleSystem_getSpinVariation },
806 { "setColors", w_ParticleSystem_setColors },
807 { "getColors", w_ParticleSystem_getColors },
808 { "setQuads", w_ParticleSystem_setQuads },
809 { "getQuads", w_ParticleSystem_getQuads },
810 { "setOffset", w_ParticleSystem_setOffset },
811 { "getOffset", w_ParticleSystem_getOffset },
812 { "setRelativeRotation", w_ParticleSystem_setRelativeRotation },
813 { "hasRelativeRotation", w_ParticleSystem_hasRelativeRotation },
814 { "getCount", w_ParticleSystem_getCount },
815 { "start", w_ParticleSystem_start },
816 { "stop", w_ParticleSystem_stop },
817 { "pause", w_ParticleSystem_pause },
818 { "reset", w_ParticleSystem_reset },
819 { "emit", w_ParticleSystem_emit },
820 { "isActive", w_ParticleSystem_isActive },
821 { "isPaused", w_ParticleSystem_isPaused },
822 { "isStopped", w_ParticleSystem_isStopped },
823 { "update", w_ParticleSystem_update },
824
825 // Deprecated.
826 { "setAreaSpread", w_ParticleSystem_setAreaSpread },
827 { "getAreaSpread", w_ParticleSystem_getAreaSpread },
828
829 { 0, 0 }
830};
831
832extern "C" int luaopen_particlesystem(lua_State *L)
833{
834 return luax_register_type(L, &ParticleSystem::type, w_ParticleSystem_functions, nullptr);
835}
836
837} // graphics
838} // love
839