Compare commits
3 commits
27b6459b9a
...
d8def23e26
| Author | SHA1 | Date | |
|---|---|---|---|
| d8def23e26 | |||
| bbd3c1223e | |||
| 53ea4dd883 |
26 changed files with 2317 additions and 640 deletions
373
LICENSE
Normal file
373
LICENSE
Normal file
|
|
@ -0,0 +1,373 @@
|
||||||
|
Mozilla Public License Version 2.0
|
||||||
|
==================================
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
--------------
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
means each individual or legal entity that creates, contributes to
|
||||||
|
the creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
means the combination of the Contributions of others (if any) used
|
||||||
|
by a Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
means Source Code Form to which the initial Contributor has attached
|
||||||
|
the notice in Exhibit A, the Executable Form of such Source Code
|
||||||
|
Form, and Modifications of such Source Code Form, in each case
|
||||||
|
including portions thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
(a) that the initial Contributor has attached the notice described
|
||||||
|
in Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
(b) that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the
|
||||||
|
terms of a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
means a work that combines Covered Software with other material, in
|
||||||
|
a separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
means having the right to grant, to the maximum extent possible,
|
||||||
|
whether at the time of the initial grant or subsequently, any and
|
||||||
|
all of the rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
(a) any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered
|
||||||
|
Software; or
|
||||||
|
|
||||||
|
(b) any new file in Source Code Form that contains any Covered
|
||||||
|
Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the
|
||||||
|
License, by the making, using, selling, offering for sale, having
|
||||||
|
made, import, or transfer of either its Contributions or its
|
||||||
|
Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU
|
||||||
|
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||||
|
Public License, Version 3.0, or any later versions of those
|
||||||
|
licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that
|
||||||
|
controls, is controlled by, or is under common control with You. For
|
||||||
|
purposes of this definition, "control" means (a) the power, direct
|
||||||
|
or indirect, to cause the direction or management of such entity,
|
||||||
|
whether by contract or otherwise, or (b) ownership of more than
|
||||||
|
fifty percent (50%) of the outstanding shares or beneficial
|
||||||
|
ownership of such entity.
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
(a) under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||||
|
for sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
(a) for any code that a Contributor has removed from Covered Software;
|
||||||
|
or
|
||||||
|
|
||||||
|
(b) for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights
|
||||||
|
to grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||||
|
in Section 2.1.
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
(a) such Covered Software must also be made available in Source Code
|
||||||
|
Form, as described in Section 3.1, and You must inform recipients of
|
||||||
|
the Executable Form how they can obtain a copy of such Source Code
|
||||||
|
Form by reasonable means in a timely manner, at a charge no more
|
||||||
|
than the cost of distribution to the recipient; and
|
||||||
|
|
||||||
|
(b) You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter
|
||||||
|
the recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty,
|
||||||
|
or limitations of liability) contained within the Source Code Form of
|
||||||
|
the Covered Software, except that You may alter any license notices to
|
||||||
|
the extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this
|
||||||
|
License with respect to some or all of the Covered Software due to
|
||||||
|
statute, judicial order, or regulation then You must: (a) comply with
|
||||||
|
the terms of this License to the maximum extent possible; and (b)
|
||||||
|
describe the limitations and the code they affect. Such description must
|
||||||
|
be placed in a text file included with all distributions of the Covered
|
||||||
|
Software under this License. Except to the extent prohibited by statute
|
||||||
|
or regulation, such description must be sufficiently detailed for a
|
||||||
|
recipient of ordinary skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
--------------
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically
|
||||||
|
if You fail to comply with any of its terms. However, if You become
|
||||||
|
compliant, then the rights granted under this License from a particular
|
||||||
|
Contributor are reinstated (a) provisionally, unless and until such
|
||||||
|
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||||
|
ongoing basis, if such Contributor fails to notify You of the
|
||||||
|
non-compliance by some reasonable means prior to 60 days after You have
|
||||||
|
come back into compliance. Moreover, Your grants from a particular
|
||||||
|
Contributor are reinstated on an ongoing basis if such Contributor
|
||||||
|
notifies You of the non-compliance by some reasonable means, this is the
|
||||||
|
first time You have received notice of non-compliance with this License
|
||||||
|
from such Contributor, and You become compliant prior to 30 days after
|
||||||
|
Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||||
|
end user license agreements (excluding distributors and resellers) which
|
||||||
|
have been validly granted by You or Your distributors under this License
|
||||||
|
prior to termination shall survive termination.
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 6. Disclaimer of Warranty *
|
||||||
|
* ------------------------- *
|
||||||
|
* *
|
||||||
|
* Covered Software is provided under this License on an "as is" *
|
||||||
|
* basis, without warranty of any kind, either expressed, implied, or *
|
||||||
|
* statutory, including, without limitation, warranties that the *
|
||||||
|
* Covered Software is free of defects, merchantable, fit for a *
|
||||||
|
* particular purpose or non-infringing. The entire risk as to the *
|
||||||
|
* quality and performance of the Covered Software is with You. *
|
||||||
|
* Should any Covered Software prove defective in any respect, You *
|
||||||
|
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||||
|
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||||
|
* essential part of this License. No use of any Covered Software is *
|
||||||
|
* authorized under this License except under this disclaimer. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 7. Limitation of Liability *
|
||||||
|
* -------------------------- *
|
||||||
|
* *
|
||||||
|
* Under no circumstances and under no legal theory, whether tort *
|
||||||
|
* (including negligence), contract, or otherwise, shall any *
|
||||||
|
* Contributor, or anyone who distributes Covered Software as *
|
||||||
|
* permitted above, be liable to You for any direct, indirect, *
|
||||||
|
* special, incidental, or consequential damages of any character *
|
||||||
|
* including, without limitation, damages for lost profits, loss of *
|
||||||
|
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||||
|
* and all other commercial damages or losses, even if such party *
|
||||||
|
* shall have been informed of the possibility of such damages. This *
|
||||||
|
* limitation of liability shall not apply to liability for death or *
|
||||||
|
* personal injury resulting from such party's negligence to the *
|
||||||
|
* extent applicable law prohibits such limitation. Some *
|
||||||
|
* jurisdictions do not allow the exclusion or limitation of *
|
||||||
|
* incidental or consequential damages, so this exclusion and *
|
||||||
|
* limitation may not apply to You. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the
|
||||||
|
courts of a jurisdiction where the defendant maintains its principal
|
||||||
|
place of business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions.
|
||||||
|
Nothing in this Section shall prevent a party's ability to bring
|
||||||
|
cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides
|
||||||
|
that the language of a contract shall be construed against the drafter
|
||||||
|
shall not be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses
|
||||||
|
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular
|
||||||
|
file, then You may include the notice in a location (such as a LICENSE
|
||||||
|
file in a relevant directory) where a recipient would be likely to look
|
||||||
|
for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
defined by the Mozilla Public License, v. 2.0.
|
||||||
|
|
@ -31,3 +31,11 @@
|
||||||
@@@@@@@@@@@@@@@@@@@@@@@~ ,@@@,,0@@@@@@@@@@@@@@@@@@@
|
@@@@@@@@@@@@@@@@@@@@@@@~ ,@@@,,0@@@@@@@@@@@@@@@@@@@
|
||||||
@@@@@@@@@@@@@@@@@@@@@@@@,,@@@@@@@@@@@@@@@@@@@@@@@@@
|
@@@@@@@@@@@@@@@@@@@@@@@@,,@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
pxl8 is free, open source and permissively licensed! All code in this repository is licensed under:
|
||||||
|
|
||||||
|
- Mozilla Public License, Version 2.0 ([LICENSE](LICENSE) or https://mozilla.org/MPL/2.0/)
|
||||||
|
|
||||||
|
Third-party dependencies (SDL3, LuaJIT, Fennel, linenoise, microui, miniz) retain their original licenses.
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,24 @@
|
||||||
(var time 0)
|
(var time 0)
|
||||||
(var active-demo :logo)
|
(var active-demo :logo)
|
||||||
(var particles nil)
|
(var particles nil)
|
||||||
(var fire-init false)
|
(var fire-init? false)
|
||||||
(var rain-init false)
|
(var rain-init? false)
|
||||||
(var snow-init false)
|
(var snow-init? false)
|
||||||
(var use-famicube-palette false)
|
(var use-famicube-palette? false)
|
||||||
|
|
||||||
(var logo-x 256)
|
(var logo-x 256)
|
||||||
(var logo-y 148)
|
(var logo-y 148)
|
||||||
(var logo-dx 100)
|
(var logo-dx 100)
|
||||||
(var logo-dy 80)
|
(var logo-dy 80)
|
||||||
(var logo-sprite nil)
|
(var logo-sprite nil)
|
||||||
|
(var transition nil)
|
||||||
|
(var transition-pending nil)
|
||||||
|
|
||||||
|
(fn switch-demo [new-demo]
|
||||||
|
(set transition-pending new-demo)
|
||||||
|
(set transition (pxl8.transition_create :pixelate 0.5))
|
||||||
|
(pxl8.transition_set_color transition 0xFF000000)
|
||||||
|
(pxl8.transition_start transition))
|
||||||
|
|
||||||
(global init (fn []
|
(global init (fn []
|
||||||
(cube3d.init)
|
(cube3d.init)
|
||||||
|
|
@ -26,24 +34,30 @@
|
||||||
(global update (fn [dt]
|
(global update (fn [dt]
|
||||||
(set time (+ time dt))
|
(set time (+ time dt))
|
||||||
|
|
||||||
(when (pxl8.key_pressed "1") (set active-demo :logo))
|
(when transition
|
||||||
(when (pxl8.key_pressed "2") (set active-demo :plasma))
|
(pxl8.transition_update transition dt)
|
||||||
(when (pxl8.key_pressed "3") (set active-demo :tunnel))
|
(when (pxl8.transition_is_complete transition)
|
||||||
(when (pxl8.key_pressed "4") (set active-demo :raster))
|
(when transition-pending
|
||||||
(when (pxl8.key_pressed "5")
|
(set active-demo transition-pending)
|
||||||
(set active-demo :fire)
|
(set transition-pending nil)
|
||||||
(set fire-init false))
|
(when (= active-demo :fire) (set fire-init? false))
|
||||||
(when (pxl8.key_pressed "6")
|
(when (= active-demo :rain) (set rain-init? false))
|
||||||
(set active-demo :rain)
|
(when (= active-demo :snow) (set snow-init? false)))
|
||||||
(set rain-init false))
|
(pxl8.transition_destroy transition)
|
||||||
(when (pxl8.key_pressed "7")
|
(set transition nil)))
|
||||||
(set active-demo :snow)
|
|
||||||
(set snow-init false))
|
(when (pxl8.key_pressed "1") (switch-demo :logo))
|
||||||
(when (pxl8.key_pressed "8") (set active-demo :cube3d))
|
(when (pxl8.key_pressed "2") (switch-demo :plasma))
|
||||||
(when (pxl8.key_pressed "9") (set active-demo :worldgen))
|
(when (pxl8.key_pressed "3") (switch-demo :tunnel))
|
||||||
|
(when (pxl8.key_pressed "4") (switch-demo :raster))
|
||||||
|
(when (pxl8.key_pressed "5") (switch-demo :fire))
|
||||||
|
(when (pxl8.key_pressed "6") (switch-demo :rain))
|
||||||
|
(when (pxl8.key_pressed "7") (switch-demo :snow))
|
||||||
|
(when (pxl8.key_pressed "8") (switch-demo :cube3d))
|
||||||
|
(when (pxl8.key_pressed "9") (switch-demo :worldgen))
|
||||||
(when (pxl8.key_pressed "=")
|
(when (pxl8.key_pressed "=")
|
||||||
(set use-famicube-palette (not use-famicube-palette))
|
(set use-famicube-palette? (not use-famicube-palette?))
|
||||||
(local palette-path (if use-famicube-palette "res/palettes/famicube.ase" "res/sprites/pxl8_logo.ase"))
|
(local palette-path (if use-famicube-palette? "res/palettes/famicube.ase" "res/sprites/pxl8_logo.ase"))
|
||||||
(pxl8.load_palette palette-path))
|
(pxl8.load_palette palette-path))
|
||||||
|
|
||||||
(case active-demo
|
(case active-demo
|
||||||
|
|
@ -81,32 +95,35 @@
|
||||||
:fire (do
|
:fire (do
|
||||||
(pxl8.clr 0)
|
(pxl8.clr 0)
|
||||||
(when particles
|
(when particles
|
||||||
(when (not fire-init)
|
(when (not fire-init?)
|
||||||
(pxl8.particles_clear particles)
|
(pxl8.particles_clear particles)
|
||||||
(pxl8.vfx_fire particles 160 140 100 12)
|
(pxl8.vfx_fire particles 160 140 100 12)
|
||||||
(set fire-init true))
|
(set fire-init? true))
|
||||||
(pxl8.particles_render particles)))
|
(pxl8.particles_render particles)))
|
||||||
|
|
||||||
:rain (do
|
:rain (do
|
||||||
(pxl8.clr 0)
|
(pxl8.clr 0)
|
||||||
(when particles
|
(when particles
|
||||||
(when (not rain-init)
|
(when (not rain-init?)
|
||||||
(pxl8.particles_clear particles)
|
(pxl8.particles_clear particles)
|
||||||
(pxl8.vfx_rain particles 320 10.0)
|
(pxl8.vfx_rain particles 320 10.0)
|
||||||
(set rain-init true))
|
(set rain-init? true))
|
||||||
(pxl8.particles_render particles)))
|
(pxl8.particles_render particles)))
|
||||||
|
|
||||||
:snow (do
|
:snow (do
|
||||||
(pxl8.clr 0)
|
(pxl8.clr 0)
|
||||||
(when particles
|
(when particles
|
||||||
(when (not snow-init)
|
(when (not snow-init?)
|
||||||
(pxl8.particles_clear particles)
|
(pxl8.particles_clear particles)
|
||||||
(pxl8.vfx_snow particles 320 5.0)
|
(pxl8.vfx_snow particles 320 5.0)
|
||||||
(set snow-init true))
|
(set snow-init? true))
|
||||||
(pxl8.particles_render particles)))
|
(pxl8.particles_render particles)))
|
||||||
|
|
||||||
:cube3d (cube3d.frame)
|
:cube3d (cube3d.frame)
|
||||||
|
|
||||||
:worldgen (worldgen.frame)
|
:worldgen (worldgen.frame)
|
||||||
|
|
||||||
_ (pxl8.clr 0))))
|
_ (pxl8.clr 0))
|
||||||
|
|
||||||
|
(when transition
|
||||||
|
(pxl8.transition_render transition))))
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,20 @@
|
||||||
(var angle-x 0)
|
(var angle-x 0)
|
||||||
(var angle-y 0)
|
(var angle-y 0)
|
||||||
(var angle-z 0)
|
(var angle-z 0)
|
||||||
(var auto-rotate true)
|
(var auto-rotate? true)
|
||||||
(var orthographic true)
|
(var orthographic? true)
|
||||||
(var wireframe true)
|
(var wireframe? true)
|
||||||
(var time 0)
|
(var time 0)
|
||||||
(var zoom 5.0)
|
(var zoom 5.0)
|
||||||
(var texture-id nil)
|
(var texture-id nil)
|
||||||
(var use-texture false)
|
(var use-texture? false)
|
||||||
(var affine false)
|
(var affine? false)
|
||||||
(var cam-x 0)
|
(var cam-x 0)
|
||||||
(var cam-y 2)
|
(var cam-y 2)
|
||||||
(var cam-z 12)
|
(var cam-z 12)
|
||||||
(var cam-yaw 0)
|
(var cam-yaw 0)
|
||||||
(var cam-pitch -0.2)
|
(var cam-pitch -0.2)
|
||||||
(var show-debug-ui false)
|
(var show-debug-ui? false)
|
||||||
(var fps 0)
|
(var fps 0)
|
||||||
(var fps-accumulator 0)
|
(var fps-accumulator 0)
|
||||||
(var fps-frame-count 0)
|
(var fps-frame-count 0)
|
||||||
|
|
@ -26,19 +26,19 @@
|
||||||
(set angle-x 0)
|
(set angle-x 0)
|
||||||
(set angle-y 0)
|
(set angle-y 0)
|
||||||
(set angle-z 0)
|
(set angle-z 0)
|
||||||
(set auto-rotate true)
|
(set auto-rotate? true)
|
||||||
(set orthographic true)
|
(set orthographic? true)
|
||||||
(set wireframe true)
|
(set wireframe? true)
|
||||||
(set time 0)
|
(set time 0)
|
||||||
(set zoom 5.0)
|
(set zoom 5.0)
|
||||||
(set use-texture false)
|
(set use-texture? false)
|
||||||
(set affine false)
|
(set affine? false)
|
||||||
(set cam-x 0)
|
(set cam-x 0)
|
||||||
(set cam-y 2)
|
(set cam-y 2)
|
||||||
(set cam-z 12)
|
(set cam-z 12)
|
||||||
(set cam-yaw 0)
|
(set cam-yaw 0)
|
||||||
(set cam-pitch -0.2)
|
(set cam-pitch -0.2)
|
||||||
(set show-debug-ui false)
|
(set show-debug-ui? false)
|
||||||
(set fps 0)
|
(set fps 0)
|
||||||
(set fps-accumulator 0)
|
(set fps-accumulator 0)
|
||||||
(set fps-frame-count 0)
|
(set fps-frame-count 0)
|
||||||
|
|
@ -87,7 +87,7 @@
|
||||||
|
|
||||||
(let [wheel-y (pxl8.mouse_wheel_y)]
|
(let [wheel-y (pxl8.mouse_wheel_y)]
|
||||||
(when (and (not= wheel-y 0) (not (pxl8.ui_has_mouse_focus)))
|
(when (and (not= wheel-y 0) (not (pxl8.ui_has_mouse_focus)))
|
||||||
(if orthographic
|
(if orthographic?
|
||||||
(set zoom (math.max 0.5 (math.min (- zoom (* wheel-y 0.2)) 10.0)))
|
(set zoom (math.max 0.5 (math.min (- zoom (* wheel-y 0.2)) 10.0)))
|
||||||
(let [zoom-speed 0.5
|
(let [zoom-speed 0.5
|
||||||
forward-x (* (math.sin cam-yaw) wheel-y zoom-speed)
|
forward-x (* (math.sin cam-yaw) wheel-y zoom-speed)
|
||||||
|
|
@ -103,7 +103,7 @@
|
||||||
right-x (* (math.cos cam-yaw) move-speed dt)
|
right-x (* (math.cos cam-yaw) move-speed dt)
|
||||||
right-z (* (- (math.sin cam-yaw)) move-speed dt)]
|
right-z (* (- (math.sin cam-yaw)) move-speed dt)]
|
||||||
|
|
||||||
(if orthographic
|
(if orthographic?
|
||||||
(do
|
(do
|
||||||
(when (pxl8.key_down "w")
|
(when (pxl8.key_down "w")
|
||||||
(set zoom (math.max 0.5 (- zoom (* zoom-speed dt)))))
|
(set zoom (math.max 0.5 (- zoom (* zoom-speed dt)))))
|
||||||
|
|
@ -149,20 +149,20 @@
|
||||||
(set cam-pitch (math.max -1.5 (math.min cam-pitch 1.5))))
|
(set cam-pitch (math.max -1.5 (math.min cam-pitch 1.5))))
|
||||||
|
|
||||||
(when (pxl8.key_pressed " ")
|
(when (pxl8.key_pressed " ")
|
||||||
(set wireframe (not wireframe)))
|
(set wireframe? (not wireframe?)))
|
||||||
(when (pxl8.key_pressed "f")
|
(when (pxl8.key_pressed "f")
|
||||||
(set affine (not affine)))
|
(set affine? (not affine?)))
|
||||||
(when (pxl8.key_pressed "p")
|
(when (pxl8.key_pressed "p")
|
||||||
(set orthographic (not orthographic)))
|
(set orthographic? (not orthographic?)))
|
||||||
(when (pxl8.key_pressed "r")
|
(when (pxl8.key_pressed "r")
|
||||||
(set auto-rotate (not auto-rotate)))
|
(set auto-rotate? (not auto-rotate?)))
|
||||||
(when (pxl8.key_pressed "t")
|
(when (pxl8.key_pressed "t")
|
||||||
(set use-texture (not use-texture)))
|
(set use-texture? (not use-texture?)))
|
||||||
(when (pxl8.key_pressed "F8")
|
(when (pxl8.key_pressed "F8")
|
||||||
(set show-debug-ui (not show-debug-ui))
|
(set show-debug-ui? (not show-debug-ui?))
|
||||||
(pxl8.ui_window_set_open "Debug Menu (F8)" show-debug-ui))
|
(pxl8.ui_window_set_open "Debug Menu (F8)" show-debug-ui?))
|
||||||
|
|
||||||
(when auto-rotate
|
(when auto-rotate?
|
||||||
(set angle-x (+ angle-x (* dt 0.7)))
|
(set angle-x (+ angle-x (* dt 0.7)))
|
||||||
(set angle-y (+ angle-y (* dt 0.5)))
|
(set angle-y (+ angle-y (* dt 0.5)))
|
||||||
(set angle-z (+ angle-z (* dt 0.3)))))
|
(set angle-z (+ angle-z (* dt 0.3)))))
|
||||||
|
|
@ -178,7 +178,7 @@
|
||||||
(pxl8.set_model model))
|
(pxl8.set_model model))
|
||||||
|
|
||||||
(let [vertices (make-cube-vertices)]
|
(let [vertices (make-cube-vertices)]
|
||||||
(if (and use-texture texture-id)
|
(if (and use-texture? texture-id)
|
||||||
(let [faces (make-cube-faces-with-uvs)]
|
(let [faces (make-cube-faces-with-uvs)]
|
||||||
(each [_i face-data (ipairs faces)]
|
(each [_i face-data (ipairs faces)]
|
||||||
(let [tri-indices face-data.tri
|
(let [tri-indices face-data.tri
|
||||||
|
|
@ -206,11 +206,11 @@
|
||||||
(pxl8.clr 0)
|
(pxl8.clr 0)
|
||||||
|
|
||||||
(pxl8.clear_zbuffer)
|
(pxl8.clear_zbuffer)
|
||||||
(pxl8.set_affine_textures affine)
|
(pxl8.set_affine_textures affine?)
|
||||||
(pxl8.set_backface_culling true)
|
(pxl8.set_backface_culling true)
|
||||||
(pxl8.set_wireframe wireframe)
|
(pxl8.set_wireframe wireframe?)
|
||||||
|
|
||||||
(if orthographic
|
(if orthographic?
|
||||||
(let [size zoom
|
(let [size zoom
|
||||||
aspect (/ (pxl8.get_width) (pxl8.get_height))
|
aspect (/ (pxl8.get_width) (pxl8.get_height))
|
||||||
w (* size aspect)
|
w (* size aspect)
|
||||||
|
|
@ -233,19 +233,19 @@
|
||||||
(draw-cube [3 1 -7] 0.9 1.2)
|
(draw-cube [3 1 -7] 0.9 1.2)
|
||||||
(draw-cube [0 -2 -10] 1.1 -0.7)
|
(draw-cube [0 -2 -10] 1.1 -0.7)
|
||||||
|
|
||||||
(let [new-state (debug-ui.render {:show-debug-ui show-debug-ui
|
(let [new-state (debug-ui.render {:show-debug-ui show-debug-ui?
|
||||||
:fps fps
|
:fps fps
|
||||||
:wireframe wireframe
|
:wireframe wireframe?
|
||||||
:auto-rotate auto-rotate
|
:auto-rotate auto-rotate?
|
||||||
:orthographic orthographic
|
:orthographic orthographic?
|
||||||
:use-texture use-texture
|
:use-texture use-texture?
|
||||||
:affine affine})]
|
:affine affine?})]
|
||||||
(when (not= new-state.show-debug-ui nil) (set show-debug-ui new-state.show-debug-ui))
|
(when (not= new-state.show-debug-ui nil) (set show-debug-ui? new-state.show-debug-ui))
|
||||||
(when (not= new-state.wireframe nil) (set wireframe new-state.wireframe))
|
(when (not= new-state.wireframe nil) (set wireframe? new-state.wireframe))
|
||||||
(when (not= new-state.auto-rotate nil) (set auto-rotate new-state.auto-rotate))
|
(when (not= new-state.auto-rotate nil) (set auto-rotate? new-state.auto-rotate))
|
||||||
(when (not= new-state.orthographic nil) (set orthographic new-state.orthographic))
|
(when (not= new-state.orthographic nil) (set orthographic? new-state.orthographic))
|
||||||
(when (not= new-state.use-texture nil) (set use-texture new-state.use-texture))
|
(when (not= new-state.use-texture nil) (set use-texture? new-state.use-texture))
|
||||||
(when (not= new-state.affine nil) (set affine new-state.affine))))
|
(when (not= new-state.affine nil) (set affine? new-state.affine))))
|
||||||
|
|
||||||
{:init init
|
{:init init
|
||||||
:update update
|
:update update
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,14 @@
|
||||||
|
|
||||||
(var world nil)
|
(var world nil)
|
||||||
(var cam-x 1000)
|
(var cam-x 1000)
|
||||||
(local cam-y 64)
|
(var cam-y 64)
|
||||||
(var cam-z 1000)
|
(var cam-z 1000)
|
||||||
(var cam-yaw 0)
|
(var cam-yaw 0)
|
||||||
(var cam-pitch 0)
|
(var cam-pitch 0)
|
||||||
(var bob-time 0)
|
(var bob-time 0)
|
||||||
|
(var velocity-y 0)
|
||||||
|
(var grounded? true)
|
||||||
|
(var land-squash 0)
|
||||||
|
|
||||||
(local move-speed 200)
|
(local move-speed 200)
|
||||||
(local turn-speed 2.0)
|
(local turn-speed 2.0)
|
||||||
|
|
@ -15,6 +18,11 @@
|
||||||
(local max-pitch 1.5)
|
(local max-pitch 1.5)
|
||||||
(local cell-size 64)
|
(local cell-size 64)
|
||||||
(local grid-size 32)
|
(local grid-size 32)
|
||||||
|
(local gravity -800)
|
||||||
|
(local jump-force 175)
|
||||||
|
(local ground-y 64)
|
||||||
|
(local land-squash-amount -4)
|
||||||
|
(local land-recovery-speed 20)
|
||||||
|
|
||||||
(fn init []
|
(fn init []
|
||||||
(set world (pxl8.world_new))
|
(set world (pxl8.world_new))
|
||||||
|
|
@ -72,31 +80,28 @@
|
||||||
(var move-right 0)
|
(var move-right 0)
|
||||||
|
|
||||||
(when (pxl8.key_down "w")
|
(when (pxl8.key_down "w")
|
||||||
(set move-forward (+ move-forward 1))
|
(set move-forward (+ move-forward 1)))
|
||||||
(set moving true))
|
|
||||||
|
|
||||||
(when (pxl8.key_down "s")
|
(when (pxl8.key_down "s")
|
||||||
(set move-forward (- move-forward 1))
|
(set move-forward (- move-forward 1)))
|
||||||
(set moving true))
|
|
||||||
|
|
||||||
(when (pxl8.key_down "q")
|
(when (pxl8.key_down "q")
|
||||||
(set move-right (- move-right 1))
|
(set move-right (- move-right 1)))
|
||||||
(set moving true))
|
|
||||||
|
|
||||||
(when (pxl8.key_down "e")
|
(when (pxl8.key_down "e")
|
||||||
(set move-right (+ move-right 1))
|
(set move-right (+ move-right 1)))
|
||||||
(set moving true))
|
|
||||||
|
(set moving (or (not= move-forward 0) (not= move-right 0)))
|
||||||
|
|
||||||
(var new-x cam-x)
|
(var new-x cam-x)
|
||||||
(var new-z cam-z)
|
(var new-z cam-z)
|
||||||
|
|
||||||
(when moving
|
(when moving
|
||||||
(let [len (math.sqrt (+ (* move-forward move-forward) (* move-right move-right)))]
|
(let [len (math.sqrt (+ (* move-forward move-forward) (* move-right move-right)))
|
||||||
(when (> len 0)
|
norm-forward (/ move-forward len)
|
||||||
(let [norm-forward (/ move-forward len)
|
|
||||||
norm-right (/ move-right len)]
|
norm-right (/ move-right len)]
|
||||||
(set new-x (+ new-x (* move-delta (+ (* forward-x norm-forward) (* right-x norm-right)))))
|
(set new-x (+ new-x (* move-delta (+ (* forward-x norm-forward) (* right-x norm-right)))))
|
||||||
(set new-z (+ new-z (* move-delta (+ (* forward-z norm-forward) (* right-z norm-right)))))))))
|
(set new-z (+ new-z (* move-delta (+ (* forward-z norm-forward) (* right-z norm-right)))))))
|
||||||
|
|
||||||
(when (and (>= new-x 0) (<= new-x grid-max)
|
(when (and (>= new-x 0) (<= new-x grid-max)
|
||||||
(>= new-z 0) (<= new-z grid-max))
|
(>= new-z 0) (<= new-z grid-max))
|
||||||
|
|
@ -115,7 +120,24 @@
|
||||||
(when (pxl8.key_down "down")
|
(when (pxl8.key_down "down")
|
||||||
(set cam-pitch (math.max (- max-pitch) (- cam-pitch (* turn-speed dt)))))
|
(set cam-pitch (math.max (- max-pitch) (- cam-pitch (* turn-speed dt)))))
|
||||||
|
|
||||||
(if moving
|
(when (and (pxl8.key_pressed "space") grounded?)
|
||||||
|
(set velocity-y jump-force)
|
||||||
|
(set grounded? false))
|
||||||
|
|
||||||
|
(set velocity-y (+ velocity-y (* gravity dt)))
|
||||||
|
(set cam-y (+ cam-y (* velocity-y dt)))
|
||||||
|
|
||||||
|
(when (<= cam-y ground-y)
|
||||||
|
(when (not grounded?)
|
||||||
|
(set land-squash land-squash-amount))
|
||||||
|
(set cam-y ground-y)
|
||||||
|
(set velocity-y 0)
|
||||||
|
(set grounded? true))
|
||||||
|
|
||||||
|
(when (< land-squash 0)
|
||||||
|
(set land-squash (math.min 0 (+ land-squash (* land-recovery-speed dt)))))
|
||||||
|
|
||||||
|
(if (and moving grounded?)
|
||||||
(set bob-time (+ bob-time (* dt bob-speed)))
|
(set bob-time (+ bob-time (* dt bob-speed)))
|
||||||
(let [target-phase (* (math.floor (/ bob-time math.pi)) math.pi)]
|
(let [target-phase (* (math.floor (/ bob-time math.pi)) math.pi)]
|
||||||
(set bob-time (+ (* bob-time 0.8) (* target-phase 0.2))))))))
|
(set bob-time (+ (* bob-time 0.8) (* target-phase 0.2))))))))
|
||||||
|
|
@ -125,7 +147,7 @@
|
||||||
|
|
||||||
(when (pxl8.world_is_loaded world)
|
(when (pxl8.world_is_loaded world)
|
||||||
(let [bob-offset (* (math.sin bob-time) bob-amount)
|
(let [bob-offset (* (math.sin bob-time) bob-amount)
|
||||||
eye-y (+ cam-y bob-offset)
|
eye-y (+ cam-y bob-offset land-squash)
|
||||||
forward-x (- (math.sin cam-yaw))
|
forward-x (- (math.sin cam-yaw))
|
||||||
forward-z (- (math.cos cam-yaw))
|
forward-z (- (math.cos cam-yaw))
|
||||||
target-x (+ cam-x forward-x)
|
target-x (+ cam-x forward-x)
|
||||||
|
|
|
||||||
696
src/lua/pxl8.lua
696
src/lua/pxl8.lua
|
|
@ -1,534 +1,174 @@
|
||||||
local ffi = require("ffi")
|
local ffi = require("ffi")
|
||||||
local C = ffi.C
|
|
||||||
local game = _pxl8_game
|
local core = require("pxl8.core")
|
||||||
local gfx = _pxl8_gfx
|
local graphics = require("pxl8.graphics")
|
||||||
local input = _pxl8_input
|
local input = require("pxl8.input")
|
||||||
local ui = _pxl8_ui
|
local vfx = require("pxl8.vfx")
|
||||||
|
local particles = require("pxl8.particles")
|
||||||
|
local tilemap = require("pxl8.tilemap")
|
||||||
|
local gfx3d = require("pxl8.gfx3d")
|
||||||
|
local math3d = require("pxl8.math")
|
||||||
|
local ui = require("pxl8.ui")
|
||||||
|
local world = require("pxl8.world")
|
||||||
|
local transition = require("pxl8.transition")
|
||||||
|
local anim = require("pxl8.anim")
|
||||||
|
|
||||||
|
core.init(_pxl8_game, _pxl8_gfx, _pxl8_input, _pxl8_ui)
|
||||||
|
|
||||||
local pxl8 = {}
|
local pxl8 = {}
|
||||||
|
|
||||||
function pxl8.clr(color)
|
pxl8.get_fps = core.get_fps
|
||||||
C.pxl8_clr(gfx, color or 0)
|
pxl8.get_width = core.get_width
|
||||||
end
|
pxl8.get_height = core.get_height
|
||||||
|
pxl8.info = core.info
|
||||||
function pxl8.pixel(x, y, color)
|
pxl8.warn = core.warn
|
||||||
if color then
|
pxl8.error = core.error
|
||||||
C.pxl8_pixel(gfx, x, y, color)
|
pxl8.debug = core.debug
|
||||||
else
|
pxl8.trace = core.trace
|
||||||
return C.pxl8_get_pixel(gfx, x, y)
|
|
||||||
end
|
pxl8.clr = graphics.clr
|
||||||
end
|
pxl8.pixel = graphics.pixel
|
||||||
|
pxl8.line = graphics.line
|
||||||
function pxl8.line(x0, y0, x1, y1, color)
|
pxl8.rect = graphics.rect
|
||||||
C.pxl8_line(gfx, x0, y0, x1, y1, color)
|
pxl8.rect_fill = graphics.rect_fill
|
||||||
end
|
pxl8.circle = graphics.circle
|
||||||
|
pxl8.circle_fill = graphics.circle_fill
|
||||||
function pxl8.rect(x, y, w, h, color)
|
pxl8.text = graphics.text
|
||||||
C.pxl8_rect(gfx, x, y, w, h, color)
|
pxl8.sprite = graphics.sprite
|
||||||
end
|
pxl8.load_palette = graphics.load_palette
|
||||||
|
pxl8.load_sprite = graphics.load_sprite
|
||||||
function pxl8.rect_fill(x, y, w, h, color)
|
pxl8.create_texture = graphics.create_texture
|
||||||
C.pxl8_rect_fill(gfx, x, y, w, h, color)
|
pxl8.upload_atlas = graphics.upload_atlas
|
||||||
end
|
pxl8.gfx_color_ramp = graphics.color_ramp
|
||||||
|
pxl8.gfx_fade_palette = graphics.fade_palette
|
||||||
function pxl8.circle(x, y, r, color)
|
|
||||||
C.pxl8_circle(gfx, x, y, r, color)
|
pxl8.key_down = input.key_down
|
||||||
end
|
pxl8.key_pressed = input.key_pressed
|
||||||
|
pxl8.key_released = input.key_released
|
||||||
function pxl8.circle_fill(x, y, r, color)
|
pxl8.mouse_wheel_x = input.mouse_wheel_x
|
||||||
C.pxl8_circle_fill(gfx, x, y, r, color)
|
pxl8.mouse_wheel_y = input.mouse_wheel_y
|
||||||
end
|
pxl8.mouse_x = input.mouse_x
|
||||||
|
pxl8.mouse_y = input.mouse_y
|
||||||
function pxl8.text(str, x, y, color)
|
|
||||||
C.pxl8_text(gfx, str, x or 0, y or 0, color or 15)
|
pxl8.vfx_raster_bars = vfx.raster_bars
|
||||||
end
|
pxl8.vfx_plasma = vfx.plasma
|
||||||
|
pxl8.vfx_rotozoom = vfx.rotozoom
|
||||||
function pxl8.sprite(id, x, y, w, h, flip_x, flip_y)
|
pxl8.vfx_tunnel = vfx.tunnel
|
||||||
C.pxl8_sprite(gfx, id or 0, x or 0, y or 0, w or 16, h or 16, flip_x or false, flip_y or false)
|
pxl8.vfx_explosion = vfx.explosion
|
||||||
end
|
pxl8.vfx_fire = vfx.fire
|
||||||
|
pxl8.vfx_rain = vfx.rain
|
||||||
function pxl8.get_fps()
|
pxl8.vfx_smoke = vfx.smoke
|
||||||
return C.pxl8_game_get_fps(game)
|
pxl8.vfx_snow = vfx.snow
|
||||||
end
|
pxl8.vfx_sparks = vfx.sparks
|
||||||
|
pxl8.vfx_starfield = vfx.starfield
|
||||||
function pxl8.get_width()
|
|
||||||
return C.pxl8_gfx_get_width(gfx)
|
pxl8.particles_new = particles.new
|
||||||
end
|
pxl8.particles_destroy = particles.destroy
|
||||||
|
pxl8.particles_clear = particles.clear
|
||||||
function pxl8.get_height()
|
pxl8.particles_emit = particles.emit
|
||||||
return C.pxl8_gfx_get_height(gfx)
|
pxl8.particles_update = particles.update
|
||||||
end
|
pxl8.particles_render = particles.render
|
||||||
|
|
||||||
function pxl8.load_palette(filepath)
|
pxl8.tilesheet_new = tilemap.tilesheet_new
|
||||||
return C.pxl8_gfx_load_palette(gfx, filepath)
|
pxl8.tilesheet_destroy = tilemap.tilesheet_destroy
|
||||||
end
|
pxl8.tilesheet_load = tilemap.tilesheet_load
|
||||||
|
pxl8.tilemap_new = tilemap.new
|
||||||
function pxl8.load_sprite(filepath)
|
pxl8.tilemap_destroy = tilemap.destroy
|
||||||
local sprite_id = ffi.new("unsigned int[1]")
|
pxl8.tilemap_set_tilesheet = tilemap.set_tilesheet
|
||||||
local result = C.pxl8_gfx_load_sprite(gfx, filepath, sprite_id)
|
pxl8.tilemap_set_tile = tilemap.set_tile
|
||||||
if result == 0 then
|
pxl8.tilemap_get_tile_id = tilemap.get_tile_id
|
||||||
return sprite_id[0]
|
pxl8.tilemap_set_camera = tilemap.set_camera
|
||||||
else
|
pxl8.tilemap_render = tilemap.render
|
||||||
return nil, result
|
pxl8.tilemap_render_layer = tilemap.render_layer
|
||||||
end
|
pxl8.tilemap_is_solid = tilemap.is_solid
|
||||||
end
|
pxl8.tilemap_check_collision = tilemap.check_collision
|
||||||
|
pxl8.tilemap_get_tile_data = tilemap.get_tile_data
|
||||||
function pxl8.create_texture(pixels, width, height)
|
pxl8.tilemap_load_ase = tilemap.load_ase
|
||||||
local pixel_data = ffi.new("u8[?]", width * height)
|
pxl8.tilemap_set_tile_data = tilemap.set_tile_data
|
||||||
for i = 0, width * height - 1 do
|
pxl8.TILE_FLIP_X = tilemap.TILE_FLIP_X
|
||||||
pixel_data[i] = pixels[i + 1] or 0
|
pxl8.TILE_FLIP_Y = tilemap.TILE_FLIP_Y
|
||||||
end
|
pxl8.TILE_SOLID = tilemap.TILE_SOLID
|
||||||
local result = C.pxl8_gfx_create_texture(gfx, pixel_data, width, height)
|
pxl8.TILE_TRIGGER = tilemap.TILE_TRIGGER
|
||||||
if result < 0 then
|
|
||||||
return nil
|
pxl8.clear_zbuffer = gfx3d.clear_zbuffer
|
||||||
end
|
pxl8.set_model = gfx3d.set_model
|
||||||
return result
|
pxl8.set_view = gfx3d.set_view
|
||||||
end
|
pxl8.set_projection = gfx3d.set_projection
|
||||||
|
pxl8.set_wireframe = gfx3d.set_wireframe
|
||||||
function pxl8.upload_atlas()
|
pxl8.set_affine_textures = gfx3d.set_affine_textures
|
||||||
C.pxl8_gfx_upload_atlas(gfx)
|
pxl8.set_backface_culling = gfx3d.set_backface_culling
|
||||||
end
|
pxl8.draw_triangle_3d = gfx3d.draw_triangle
|
||||||
|
pxl8.draw_triangle_3d_textured = gfx3d.draw_triangle_textured
|
||||||
function pxl8.info(msg)
|
pxl8.draw_line_3d = gfx3d.draw_line
|
||||||
C.pxl8_lua_info(msg)
|
|
||||||
end
|
pxl8.mat4_identity = math3d.mat4_identity
|
||||||
|
pxl8.mat4_multiply = math3d.mat4_multiply
|
||||||
function pxl8.warn(msg)
|
pxl8.mat4_translate = math3d.mat4_translate
|
||||||
C.pxl8_lua_warn(msg)
|
pxl8.mat4_rotate_x = math3d.mat4_rotate_x
|
||||||
end
|
pxl8.mat4_rotate_y = math3d.mat4_rotate_y
|
||||||
|
pxl8.mat4_rotate_z = math3d.mat4_rotate_z
|
||||||
function pxl8.error(msg)
|
pxl8.mat4_scale = math3d.mat4_scale
|
||||||
C.pxl8_lua_error(msg)
|
pxl8.mat4_ortho = math3d.mat4_ortho
|
||||||
end
|
pxl8.mat4_perspective = math3d.mat4_perspective
|
||||||
|
pxl8.mat4_lookat = math3d.mat4_lookat
|
||||||
function pxl8.debug(msg)
|
pxl8.bounds = math3d.bounds
|
||||||
C.pxl8_lua_debug(msg)
|
|
||||||
end
|
pxl8.ui_button = ui.button
|
||||||
|
pxl8.ui_checkbox = ui.checkbox
|
||||||
function pxl8.trace(msg)
|
pxl8.ui_has_mouse_focus = ui.has_mouse_focus
|
||||||
C.pxl8_lua_trace(msg)
|
pxl8.ui_indent = ui.indent
|
||||||
end
|
pxl8.ui_label = ui.label
|
||||||
|
pxl8.ui_layout_row = ui.layout_row
|
||||||
function pxl8.key_down(key)
|
pxl8.ui_window_begin = ui.window_begin
|
||||||
return C.pxl8_key_down(input, key)
|
pxl8.ui_window_end = ui.window_end
|
||||||
end
|
pxl8.ui_window_set_open = ui.window_set_open
|
||||||
|
|
||||||
function pxl8.key_pressed(key)
|
pxl8.world_new = world.new
|
||||||
return C.pxl8_key_pressed(input, key)
|
pxl8.world_destroy = world.destroy
|
||||||
end
|
pxl8.world_load = world.load
|
||||||
|
pxl8.world_render = world.render
|
||||||
function pxl8.key_released(key)
|
pxl8.world_unload = world.unload
|
||||||
return C.pxl8_key_released(input, key)
|
pxl8.world_is_loaded = world.is_loaded
|
||||||
end
|
pxl8.world_generate = world.generate
|
||||||
|
pxl8.world_apply_textures = world.apply_textures
|
||||||
function pxl8.mouse_wheel_x()
|
pxl8.procgen_tex = world.procgen_tex
|
||||||
return C.pxl8_mouse_wheel_x(input)
|
pxl8.PROCGEN_CAVE = world.PROCGEN_CAVE
|
||||||
end
|
pxl8.PROCGEN_DUNGEON = world.PROCGEN_DUNGEON
|
||||||
|
pxl8.PROCGEN_TERRAIN = world.PROCGEN_TERRAIN
|
||||||
function pxl8.mouse_wheel_y()
|
|
||||||
return C.pxl8_mouse_wheel_y(input)
|
pxl8.transition_create = transition.create
|
||||||
end
|
pxl8.transition_destroy = transition.destroy
|
||||||
|
pxl8.transition_get_progress = transition.get_progress
|
||||||
function pxl8.mouse_x()
|
pxl8.transition_is_active = transition.is_active
|
||||||
return C.pxl8_mouse_x(input)
|
pxl8.transition_is_complete = transition.is_complete
|
||||||
end
|
pxl8.transition_render = transition.render
|
||||||
|
pxl8.transition_reset = transition.reset
|
||||||
function pxl8.mouse_y()
|
pxl8.transition_set_color = transition.set_color
|
||||||
return C.pxl8_mouse_y(input)
|
pxl8.transition_set_reverse = transition.set_reverse
|
||||||
end
|
pxl8.transition_start = transition.start
|
||||||
|
pxl8.transition_stop = transition.stop
|
||||||
function pxl8.vfx_raster_bars(bars, time)
|
pxl8.transition_update = transition.update
|
||||||
local c_bars = ffi.new("pxl8_raster_bar[?]", #bars)
|
|
||||||
for i, bar in ipairs(bars) do
|
pxl8.anim_create = anim.create
|
||||||
c_bars[i-1].base_y = bar.base_y or 0
|
pxl8.anim_create_from_ase = anim.create_from_ase
|
||||||
c_bars[i-1].amplitude = bar.amplitude or 10
|
pxl8.anim_destroy = anim.destroy
|
||||||
c_bars[i-1].height = bar.height or 5
|
pxl8.anim_add_state = anim.add_state
|
||||||
c_bars[i-1].speed = bar.speed or 1.0
|
pxl8.anim_get_current_frame = anim.get_current_frame
|
||||||
c_bars[i-1].phase = bar.phase or 0
|
pxl8.anim_get_current_frame_id = anim.get_current_frame_id
|
||||||
c_bars[i-1].color = bar.color or 15
|
pxl8.anim_get_state = anim.get_state
|
||||||
c_bars[i-1].fade_color = bar.fade_color or bar.color or 15
|
pxl8.anim_has_state_machine = anim.has_state_machine
|
||||||
end
|
pxl8.anim_is_complete = anim.is_complete
|
||||||
C.pxl8_vfx_raster_bars(gfx, c_bars, #bars, time)
|
pxl8.anim_is_playing = anim.is_playing
|
||||||
end
|
pxl8.anim_pause = anim.pause
|
||||||
|
pxl8.anim_play = anim.play
|
||||||
function pxl8.vfx_plasma(time, scale1, scale2, palette_offset)
|
pxl8.anim_render_sprite = anim.render_sprite
|
||||||
C.pxl8_vfx_plasma(gfx, time, scale1 or 0.05, scale2 or 0.03, palette_offset or 0)
|
pxl8.anim_reset = anim.reset
|
||||||
end
|
pxl8.anim_set_frame = anim.set_frame
|
||||||
|
pxl8.anim_set_loop = anim.set_loop
|
||||||
function pxl8.vfx_rotozoom(angle, zoom, cx, cy)
|
pxl8.anim_set_reverse = anim.set_reverse
|
||||||
C.pxl8_vfx_rotozoom(gfx, angle, zoom, cx or pxl8.get_width()/2, cy or pxl8.get_height()/2)
|
pxl8.anim_set_speed = anim.set_speed
|
||||||
end
|
pxl8.anim_set_state = anim.set_state
|
||||||
|
pxl8.anim_stop = anim.stop
|
||||||
function pxl8.vfx_tunnel(time, speed, twist)
|
pxl8.anim_update = anim.update
|
||||||
C.pxl8_vfx_tunnel(gfx, time, speed or 2.0, twist or 0.5)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.particles_new(max_count)
|
|
||||||
return C.pxl8_particles_create(max_count or 1000)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.particles_destroy(ps)
|
|
||||||
C.pxl8_particles_destroy(ps)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.particles_clear(ps)
|
|
||||||
C.pxl8_particles_clear(ps)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.particles_emit(ps, count)
|
|
||||||
C.pxl8_particles_emit(ps, count or 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.particles_update(ps, dt)
|
|
||||||
C.pxl8_particles_update(ps, dt)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.particles_render(ps)
|
|
||||||
C.pxl8_particles_render(ps, gfx)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.vfx_explosion(ps, x, y, color, force)
|
|
||||||
C.pxl8_vfx_explosion(ps, x, y, color or 15, force or 200.0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.vfx_fire(ps, x, y, width, palette_start)
|
|
||||||
C.pxl8_vfx_fire(ps, x, y, width or 50, palette_start or 64)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.vfx_rain(ps, width, wind)
|
|
||||||
C.pxl8_vfx_rain(ps, width or pxl8.get_width(), wind or 0.0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.vfx_smoke(ps, x, y, color)
|
|
||||||
C.pxl8_vfx_smoke(ps, x, y, color or 8)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.vfx_snow(ps, width, wind)
|
|
||||||
C.pxl8_vfx_snow(ps, width or pxl8.get_width(), wind or 10.0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.vfx_sparks(ps, x, y, color)
|
|
||||||
C.pxl8_vfx_sparks(ps, x, y, color or 15)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.vfx_starfield(ps, speed, spread)
|
|
||||||
C.pxl8_vfx_starfield(ps, speed or 5.0, spread or 500.0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.gfx_color_ramp(start, count, from_color, to_color)
|
|
||||||
C.pxl8_gfx_color_ramp(gfx, start, count, from_color, to_color)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.gfx_fade_palette(start, count, amount, target_color)
|
|
||||||
C.pxl8_gfx_fade_palette(gfx, start, count, amount, target_color)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilesheet_new(tile_size)
|
|
||||||
return C.pxl8_tilesheet_create(tile_size or 16)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilesheet_destroy(tilesheet)
|
|
||||||
C.pxl8_tilesheet_destroy(tilesheet)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilesheet_load(tilesheet, filepath)
|
|
||||||
return C.pxl8_tilesheet_load(tilesheet, filepath, gfx)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_new(width, height, tile_size)
|
|
||||||
return C.pxl8_tilemap_create(width, height, tile_size or 16)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_destroy(tilemap)
|
|
||||||
C.pxl8_tilemap_destroy(tilemap)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_set_tilesheet(tilemap, tilesheet)
|
|
||||||
return C.pxl8_tilemap_set_tilesheet(tilemap, tilesheet)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_set_tile(tilemap, layer, x, y, tile_id, flags)
|
|
||||||
C.pxl8_tilemap_set_tile(tilemap, layer or 0, x, y, tile_id or 0, flags or 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_get_tile_id(tilemap, layer, x, y)
|
|
||||||
return C.pxl8_tilemap_get_tile_id(tilemap, layer or 0, x, y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_set_camera(tilemap, x, y)
|
|
||||||
C.pxl8_tilemap_set_camera(tilemap, x, y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_render(tilemap)
|
|
||||||
C.pxl8_tilemap_render(tilemap, gfx)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_render_layer(tilemap, layer)
|
|
||||||
C.pxl8_tilemap_render_layer(tilemap, gfx, layer)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_is_solid(tilemap, x, y)
|
|
||||||
return C.pxl8_tilemap_is_solid(tilemap, x, y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_check_collision(tilemap, x, y, w, h)
|
|
||||||
return C.pxl8_tilemap_check_collision(tilemap, x, y, w, h)
|
|
||||||
end
|
|
||||||
|
|
||||||
local tile_data = setmetatable({}, {__mode = "k"})
|
|
||||||
|
|
||||||
function pxl8.tilemap_get_tile_data(tilemap, tile_id)
|
|
||||||
if not tilemap or tile_id == 0 then return nil end
|
|
||||||
if not tile_data[tilemap] then return nil end
|
|
||||||
return tile_data[tilemap][tile_id]
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_load_ase(tilemap, filepath, layer)
|
|
||||||
return C.pxl8_tilemap_load_ase(tilemap, filepath, layer or 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.tilemap_set_tile_data(tilemap, tile_id, data)
|
|
||||||
if not tilemap or tile_id == 0 then return end
|
|
||||||
if not tile_data[tilemap] then tile_data[tilemap] = {} end
|
|
||||||
tile_data[tilemap][tile_id] = data
|
|
||||||
end
|
|
||||||
|
|
||||||
pxl8.TILE_FLIP_X = 1
|
|
||||||
pxl8.TILE_FLIP_Y = 2
|
|
||||||
pxl8.TILE_SOLID = 4
|
|
||||||
pxl8.TILE_TRIGGER = 8
|
|
||||||
|
|
||||||
function pxl8.clear_zbuffer()
|
|
||||||
C.pxl8_3d_clear_zbuffer(gfx)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.set_model(mat)
|
|
||||||
C.pxl8_3d_set_model(gfx, mat)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.set_view(mat)
|
|
||||||
C.pxl8_3d_set_view(gfx, mat)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.set_projection(mat)
|
|
||||||
C.pxl8_3d_set_projection(gfx, mat)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.set_wireframe(wireframe)
|
|
||||||
C.pxl8_3d_set_wireframe(gfx, wireframe)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.set_affine_textures(affine)
|
|
||||||
C.pxl8_3d_set_affine_textures(gfx, affine)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.set_backface_culling(culling)
|
|
||||||
C.pxl8_3d_set_backface_culling(gfx, culling)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.draw_triangle_3d(v0, v1, v2, color)
|
|
||||||
local vec0 = ffi.new("pxl8_vec3", {x = v0[1], y = v0[2], z = v0[3]})
|
|
||||||
local vec1 = ffi.new("pxl8_vec3", {x = v1[1], y = v1[2], z = v1[3]})
|
|
||||||
local vec2 = ffi.new("pxl8_vec3", {x = v2[1], y = v2[2], z = v2[3]})
|
|
||||||
C.pxl8_3d_draw_triangle_raw(gfx, vec0, vec1, vec2, color)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.draw_triangle_3d_textured(v0, v1, v2, uv0, uv1, uv2, texture_id)
|
|
||||||
local vec0 = ffi.new("pxl8_vec3", {x = v0[1], y = v0[2], z = v0[3]})
|
|
||||||
local vec1 = ffi.new("pxl8_vec3", {x = v1[1], y = v1[2], z = v1[3]})
|
|
||||||
local vec2 = ffi.new("pxl8_vec3", {x = v2[1], y = v2[2], z = v2[3]})
|
|
||||||
C.pxl8_3d_draw_triangle_textured(gfx, vec0, vec1, vec2,
|
|
||||||
uv0[1], uv0[2], uv1[1], uv1[2], uv2[1], uv2[2], texture_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.draw_line_3d(p0, p1, color)
|
|
||||||
local vec0 = ffi.new("pxl8_vec3", {x = p0[1], y = p0[2], z = p0[3]})
|
|
||||||
local vec1 = ffi.new("pxl8_vec3", {x = p1[1], y = p1[2], z = p1[3]})
|
|
||||||
C.pxl8_3d_draw_line_3d(gfx, vec0, vec1, color)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.mat4_identity()
|
|
||||||
return C.pxl8_mat4_identity()
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.mat4_multiply(a, b)
|
|
||||||
return C.pxl8_mat4_multiply(a, b)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.mat4_translate(x, y, z)
|
|
||||||
return C.pxl8_mat4_translate(x, y, z)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.mat4_rotate_x(angle)
|
|
||||||
return C.pxl8_mat4_rotate_x(angle)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.mat4_rotate_y(angle)
|
|
||||||
return C.pxl8_mat4_rotate_y(angle)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.mat4_rotate_z(angle)
|
|
||||||
return C.pxl8_mat4_rotate_z(angle)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.mat4_scale(x, y, z)
|
|
||||||
return C.pxl8_mat4_scale(x, y, z)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.mat4_ortho(left, right, bottom, top, near, far)
|
|
||||||
return C.pxl8_mat4_ortho(left, right, bottom, top, near, far)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.mat4_perspective(fov, aspect, near, far)
|
|
||||||
return C.pxl8_mat4_perspective(fov, aspect, near, far)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.mat4_lookat(eye, center, up)
|
|
||||||
local eye_vec = ffi.new("pxl8_vec3", {x = eye[1], y = eye[2], z = eye[3]})
|
|
||||||
local center_vec = ffi.new("pxl8_vec3", {x = center[1], y = center[2], z = center[3]})
|
|
||||||
local up_vec = ffi.new("pxl8_vec3", {x = up[1], y = up[2], z = up[3]})
|
|
||||||
return C.pxl8_mat4_lookat(eye_vec, center_vec, up_vec)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.bounds(x, y, w, h)
|
|
||||||
return ffi.new("pxl8_bounds", {x = x, y = y, w = w, h = h})
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.ui_button(label)
|
|
||||||
return C.pxl8_ui_button(ui, label)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.ui_checkbox(label, state)
|
|
||||||
local state_ptr = ffi.new("bool[1]", state)
|
|
||||||
local changed = C.pxl8_ui_checkbox(ui, label, state_ptr)
|
|
||||||
return changed, state_ptr[0]
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.ui_has_mouse_focus()
|
|
||||||
return C.pxl8_ui_has_mouse_focus(ui)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.ui_indent(amount)
|
|
||||||
C.pxl8_ui_indent(ui, amount)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.ui_label(text)
|
|
||||||
C.pxl8_ui_label(ui, text)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.ui_layout_row(item_count, widths, height)
|
|
||||||
local widths_array = widths
|
|
||||||
if type(widths) == "table" then
|
|
||||||
widths_array = ffi.new("int[?]", #widths, widths)
|
|
||||||
elseif type(widths) == "number" then
|
|
||||||
widths_array = ffi.new("int[1]", widths)
|
|
||||||
end
|
|
||||||
C.pxl8_ui_layout_row(ui, item_count, widths_array, height)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.ui_window_begin(title, x, y, w, h, options)
|
|
||||||
local rect = ffi.new("pxl8_bounds", {x = x, y = y, w = w, h = h})
|
|
||||||
return C.pxl8_ui_window_begin(ui, title, rect, options or 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.ui_window_end()
|
|
||||||
C.pxl8_ui_window_end(ui)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.ui_window_set_open(title, open)
|
|
||||||
C.pxl8_ui_window_set_open(ui, title, open)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.world_new()
|
|
||||||
return C.pxl8_world_create()
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.world_destroy(world)
|
|
||||||
C.pxl8_world_destroy(world)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.world_load(world, filepath)
|
|
||||||
return C.pxl8_world_load(world, filepath)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.world_render(world, camera_pos)
|
|
||||||
local vec = ffi.new("pxl8_vec3", {x = camera_pos[1], y = camera_pos[2], z = camera_pos[3]})
|
|
||||||
C.pxl8_world_render(world, gfx, vec)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.world_unload(world)
|
|
||||||
C.pxl8_world_unload(world)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.world_is_loaded(world)
|
|
||||||
return C.pxl8_world_is_loaded(world)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.world_generate(world, params)
|
|
||||||
local c_params = ffi.new("pxl8_procgen_params")
|
|
||||||
c_params.type = params.type or C.PXL8_PROCGEN_CAVE
|
|
||||||
c_params.width = params.width or 32
|
|
||||||
c_params.height = params.height or 32
|
|
||||||
c_params.depth = params.depth or 0
|
|
||||||
c_params.seed = params.seed or 0
|
|
||||||
c_params.density = params.density or 0.45
|
|
||||||
c_params.iterations = params.iterations or 4
|
|
||||||
c_params.type_params = nil
|
|
||||||
return C.pxl8_world_generate(world, gfx, c_params)
|
|
||||||
end
|
|
||||||
|
|
||||||
pxl8.PROCGEN_CAVE = C.PXL8_PROCGEN_CAVE
|
|
||||||
pxl8.PROCGEN_DUNGEON = C.PXL8_PROCGEN_DUNGEON
|
|
||||||
pxl8.PROCGEN_TERRAIN = C.PXL8_PROCGEN_TERRAIN
|
|
||||||
|
|
||||||
function pxl8.procgen_tex(params)
|
|
||||||
local width = params.width or 64
|
|
||||||
local height = params.height or 64
|
|
||||||
local buffer = ffi.new("u8[?]", width * height)
|
|
||||||
local tex_params = ffi.new("pxl8_procgen_tex_params")
|
|
||||||
|
|
||||||
local name = params.name or ""
|
|
||||||
ffi.copy(tex_params.name, name, math.min(#name, 15))
|
|
||||||
|
|
||||||
tex_params.seed = params.seed or 0
|
|
||||||
tex_params.width = width
|
|
||||||
tex_params.height = height
|
|
||||||
tex_params.scale = params.scale or 1.0
|
|
||||||
tex_params.roughness = params.roughness or 0.0
|
|
||||||
tex_params.base_color = params.base_color or 0
|
|
||||||
tex_params.variation = params.variation or 0
|
|
||||||
|
|
||||||
C.pxl8_procgen_tex(buffer, tex_params)
|
|
||||||
|
|
||||||
local tex_id = C.pxl8_gfx_create_texture(gfx, buffer, width, height)
|
|
||||||
if tex_id < 0 then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
return tex_id
|
|
||||||
end
|
|
||||||
|
|
||||||
function pxl8.world_apply_textures(world, texture_defs)
|
|
||||||
local count = #texture_defs
|
|
||||||
local textures = ffi.new("pxl8_world_texture[?]", count)
|
|
||||||
|
|
||||||
for i, def in ipairs(texture_defs) do
|
|
||||||
local idx = i - 1
|
|
||||||
ffi.copy(textures[idx].name, def.name or "", math.min(#(def.name or ""), 15))
|
|
||||||
textures[idx].texture_id = def.texture_id or 0
|
|
||||||
|
|
||||||
if def.rule then
|
|
||||||
textures[idx].rule = ffi.cast("bool (*)(const pxl8_vec3*, const pxl8_bsp_face*, const pxl8_bsp*)",
|
|
||||||
function(normal, face, bsp)
|
|
||||||
return def.rule(normal[0], face, bsp)
|
|
||||||
end)
|
|
||||||
else
|
|
||||||
textures[idx].rule = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local result = C.pxl8_world_apply_textures(world, textures, count)
|
|
||||||
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
return pxl8
|
return pxl8
|
||||||
|
|
|
||||||
110
src/lua/pxl8/anim.lua
Normal file
110
src/lua/pxl8/anim.lua
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
local core = require("pxl8.core")
|
||||||
|
|
||||||
|
local anim = {}
|
||||||
|
|
||||||
|
function anim.create(frame_ids, frame_durations)
|
||||||
|
local frame_count = #frame_ids
|
||||||
|
local c_frame_ids = ffi.new("u32[?]", frame_count)
|
||||||
|
local c_frame_durations = nil
|
||||||
|
|
||||||
|
for i = 1, frame_count do
|
||||||
|
c_frame_ids[i-1] = frame_ids[i]
|
||||||
|
end
|
||||||
|
|
||||||
|
if frame_durations then
|
||||||
|
c_frame_durations = ffi.new("u16[?]", frame_count)
|
||||||
|
for i = 1, frame_count do
|
||||||
|
c_frame_durations[i-1] = frame_durations[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return C.pxl8_anim_create(c_frame_ids, c_frame_durations, frame_count)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.create_from_ase(filepath)
|
||||||
|
return C.pxl8_anim_create_from_ase(core.gfx, filepath)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.destroy(a)
|
||||||
|
C.pxl8_anim_destroy(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.add_state(a, name, state_anim)
|
||||||
|
return C.pxl8_anim_add_state(a, name, state_anim)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.get_current_frame(a)
|
||||||
|
return C.pxl8_anim_get_current_frame(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.get_current_frame_id(a)
|
||||||
|
return C.pxl8_anim_get_current_frame_id(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.get_state(a)
|
||||||
|
local state_name = C.pxl8_anim_get_state(a)
|
||||||
|
if state_name ~= nil then
|
||||||
|
return ffi.string(state_name)
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.has_state_machine(a)
|
||||||
|
return C.pxl8_anim_has_state_machine(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.is_complete(a)
|
||||||
|
return C.pxl8_anim_is_complete(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.is_playing(a)
|
||||||
|
return C.pxl8_anim_is_playing(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.pause(a)
|
||||||
|
C.pxl8_anim_pause(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.play(a)
|
||||||
|
C.pxl8_anim_play(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.render_sprite(a, x, y, w, h)
|
||||||
|
C.pxl8_anim_render_sprite(a, core.gfx, x, y, w, h)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.reset(a)
|
||||||
|
C.pxl8_anim_reset(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.set_frame(a, frame)
|
||||||
|
C.pxl8_anim_set_frame(a, frame)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.set_loop(a, loop)
|
||||||
|
C.pxl8_anim_set_loop(a, loop)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.set_reverse(a, reverse)
|
||||||
|
C.pxl8_anim_set_reverse(a, reverse)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.set_speed(a, speed)
|
||||||
|
C.pxl8_anim_set_speed(a, speed)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.set_state(a, name)
|
||||||
|
return C.pxl8_anim_set_state(a, name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.stop(a)
|
||||||
|
C.pxl8_anim_stop(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
function anim.update(a, dt)
|
||||||
|
C.pxl8_anim_update(a, dt)
|
||||||
|
end
|
||||||
|
|
||||||
|
return anim
|
||||||
45
src/lua/pxl8/core.lua
Normal file
45
src/lua/pxl8/core.lua
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
|
||||||
|
local core = {}
|
||||||
|
|
||||||
|
function core.init(game_ptr, gfx_ptr, input_ptr, ui_ptr)
|
||||||
|
core.game = game_ptr
|
||||||
|
core.gfx = gfx_ptr
|
||||||
|
core.input = input_ptr
|
||||||
|
core.ui = ui_ptr
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.get_fps()
|
||||||
|
return C.pxl8_game_get_fps(core.game)
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.get_width()
|
||||||
|
return C.pxl8_gfx_get_width(core.gfx)
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.get_height()
|
||||||
|
return C.pxl8_gfx_get_height(core.gfx)
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.info(msg)
|
||||||
|
C.pxl8_lua_info(msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.warn(msg)
|
||||||
|
C.pxl8_lua_warn(msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.error(msg)
|
||||||
|
C.pxl8_lua_error(msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.debug(msg)
|
||||||
|
C.pxl8_lua_debug(msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function core.trace(msg)
|
||||||
|
C.pxl8_lua_trace(msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
return core
|
||||||
56
src/lua/pxl8/gfx3d.lua
Normal file
56
src/lua/pxl8/gfx3d.lua
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
local core = require("pxl8.core")
|
||||||
|
|
||||||
|
local gfx3d = {}
|
||||||
|
|
||||||
|
function gfx3d.clear_zbuffer()
|
||||||
|
C.pxl8_3d_clear_zbuffer(core.gfx)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gfx3d.set_model(mat)
|
||||||
|
C.pxl8_3d_set_model(core.gfx, mat)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gfx3d.set_view(mat)
|
||||||
|
C.pxl8_3d_set_view(core.gfx, mat)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gfx3d.set_projection(mat)
|
||||||
|
C.pxl8_3d_set_projection(core.gfx, mat)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gfx3d.set_wireframe(wireframe)
|
||||||
|
C.pxl8_3d_set_wireframe(core.gfx, wireframe)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gfx3d.set_affine_textures(affine)
|
||||||
|
C.pxl8_3d_set_affine_textures(core.gfx, affine)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gfx3d.set_backface_culling(culling)
|
||||||
|
C.pxl8_3d_set_backface_culling(core.gfx, culling)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gfx3d.draw_triangle(v0, v1, v2, color)
|
||||||
|
local vec0 = ffi.new("pxl8_vec3", {x = v0[1], y = v0[2], z = v0[3]})
|
||||||
|
local vec1 = ffi.new("pxl8_vec3", {x = v1[1], y = v1[2], z = v1[3]})
|
||||||
|
local vec2 = ffi.new("pxl8_vec3", {x = v2[1], y = v2[2], z = v2[3]})
|
||||||
|
C.pxl8_3d_draw_triangle_raw(core.gfx, vec0, vec1, vec2, color)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gfx3d.draw_triangle_textured(v0, v1, v2, uv0, uv1, uv2, texture_id)
|
||||||
|
local vec0 = ffi.new("pxl8_vec3", {x = v0[1], y = v0[2], z = v0[3]})
|
||||||
|
local vec1 = ffi.new("pxl8_vec3", {x = v1[1], y = v1[2], z = v1[3]})
|
||||||
|
local vec2 = ffi.new("pxl8_vec3", {x = v2[1], y = v2[2], z = v2[3]})
|
||||||
|
C.pxl8_3d_draw_triangle_textured(core.gfx, vec0, vec1, vec2,
|
||||||
|
uv0[1], uv0[2], uv1[1], uv1[2], uv2[1], uv2[2], texture_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
function gfx3d.draw_line(p0, p1, color)
|
||||||
|
local vec0 = ffi.new("pxl8_vec3", {x = p0[1], y = p0[2], z = p0[3]})
|
||||||
|
local vec1 = ffi.new("pxl8_vec3", {x = p1[1], y = p1[2], z = p1[3]})
|
||||||
|
C.pxl8_3d_draw_line_3d(core.gfx, vec0, vec1, color)
|
||||||
|
end
|
||||||
|
|
||||||
|
return gfx3d
|
||||||
85
src/lua/pxl8/graphics.lua
Normal file
85
src/lua/pxl8/graphics.lua
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
local core = require("pxl8.core")
|
||||||
|
|
||||||
|
local graphics = {}
|
||||||
|
|
||||||
|
function graphics.clr(color)
|
||||||
|
C.pxl8_clr(core.gfx, color or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.pixel(x, y, color)
|
||||||
|
if color then
|
||||||
|
C.pxl8_pixel(core.gfx, x, y, color)
|
||||||
|
else
|
||||||
|
return C.pxl8_get_pixel(core.gfx, x, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.line(x0, y0, x1, y1, color)
|
||||||
|
C.pxl8_line(core.gfx, x0, y0, x1, y1, color)
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.rect(x, y, w, h, color)
|
||||||
|
C.pxl8_rect(core.gfx, x, y, w, h, color)
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.rect_fill(x, y, w, h, color)
|
||||||
|
C.pxl8_rect_fill(core.gfx, x, y, w, h, color)
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.circle(x, y, r, color)
|
||||||
|
C.pxl8_circle(core.gfx, x, y, r, color)
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.circle_fill(x, y, r, color)
|
||||||
|
C.pxl8_circle_fill(core.gfx, x, y, r, color)
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.text(str, x, y, color)
|
||||||
|
C.pxl8_text(core.gfx, str, x or 0, y or 0, color or 15)
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.sprite(id, x, y, w, h, flip_x, flip_y)
|
||||||
|
C.pxl8_sprite(core.gfx, id or 0, x or 0, y or 0, w or 16, h or 16, flip_x or false, flip_y or false)
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.load_palette(filepath)
|
||||||
|
return C.pxl8_gfx_load_palette(core.gfx, filepath)
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.load_sprite(filepath)
|
||||||
|
local sprite_id = ffi.new("unsigned int[1]")
|
||||||
|
local result = C.pxl8_gfx_load_sprite(core.gfx, filepath, sprite_id)
|
||||||
|
if result == 0 then
|
||||||
|
return sprite_id[0]
|
||||||
|
else
|
||||||
|
return nil, result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.create_texture(pixels, width, height)
|
||||||
|
local pixel_data = ffi.new("u8[?]", width * height)
|
||||||
|
for i = 0, width * height - 1 do
|
||||||
|
pixel_data[i] = pixels[i + 1] or 0
|
||||||
|
end
|
||||||
|
local result = C.pxl8_gfx_create_texture(core.gfx, pixel_data, width, height)
|
||||||
|
if result < 0 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.upload_atlas()
|
||||||
|
C.pxl8_gfx_upload_atlas(core.gfx)
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.color_ramp(start, count, from_color, to_color)
|
||||||
|
C.pxl8_gfx_color_ramp(core.gfx, start, count, from_color, to_color)
|
||||||
|
end
|
||||||
|
|
||||||
|
function graphics.fade_palette(start, count, amount, target_color)
|
||||||
|
C.pxl8_gfx_fade_palette(core.gfx, start, count, amount, target_color)
|
||||||
|
end
|
||||||
|
|
||||||
|
return graphics
|
||||||
35
src/lua/pxl8/input.lua
Normal file
35
src/lua/pxl8/input.lua
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
local core = require("pxl8.core")
|
||||||
|
|
||||||
|
local input = {}
|
||||||
|
|
||||||
|
function input.key_down(key)
|
||||||
|
return C.pxl8_key_down(core.input, key)
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.key_pressed(key)
|
||||||
|
return C.pxl8_key_pressed(core.input, key)
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.key_released(key)
|
||||||
|
return C.pxl8_key_released(core.input, key)
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.mouse_wheel_x()
|
||||||
|
return C.pxl8_mouse_wheel_x(core.input)
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.mouse_wheel_y()
|
||||||
|
return C.pxl8_mouse_wheel_y(core.input)
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.mouse_x()
|
||||||
|
return C.pxl8_mouse_x(core.input)
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.mouse_y()
|
||||||
|
return C.pxl8_mouse_y(core.input)
|
||||||
|
end
|
||||||
|
|
||||||
|
return input
|
||||||
53
src/lua/pxl8/math.lua
Normal file
53
src/lua/pxl8/math.lua
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
|
||||||
|
local math3d = {}
|
||||||
|
|
||||||
|
function math3d.mat4_identity()
|
||||||
|
return C.pxl8_mat4_identity()
|
||||||
|
end
|
||||||
|
|
||||||
|
function math3d.mat4_multiply(a, b)
|
||||||
|
return C.pxl8_mat4_multiply(a, b)
|
||||||
|
end
|
||||||
|
|
||||||
|
function math3d.mat4_translate(x, y, z)
|
||||||
|
return C.pxl8_mat4_translate(x, y, z)
|
||||||
|
end
|
||||||
|
|
||||||
|
function math3d.mat4_rotate_x(angle)
|
||||||
|
return C.pxl8_mat4_rotate_x(angle)
|
||||||
|
end
|
||||||
|
|
||||||
|
function math3d.mat4_rotate_y(angle)
|
||||||
|
return C.pxl8_mat4_rotate_y(angle)
|
||||||
|
end
|
||||||
|
|
||||||
|
function math3d.mat4_rotate_z(angle)
|
||||||
|
return C.pxl8_mat4_rotate_z(angle)
|
||||||
|
end
|
||||||
|
|
||||||
|
function math3d.mat4_scale(x, y, z)
|
||||||
|
return C.pxl8_mat4_scale(x, y, z)
|
||||||
|
end
|
||||||
|
|
||||||
|
function math3d.mat4_ortho(left, right, bottom, top, near, far)
|
||||||
|
return C.pxl8_mat4_ortho(left, right, bottom, top, near, far)
|
||||||
|
end
|
||||||
|
|
||||||
|
function math3d.mat4_perspective(fov, aspect, near, far)
|
||||||
|
return C.pxl8_mat4_perspective(fov, aspect, near, far)
|
||||||
|
end
|
||||||
|
|
||||||
|
function math3d.mat4_lookat(eye, center, up)
|
||||||
|
local eye_vec = ffi.new("pxl8_vec3", {x = eye[1], y = eye[2], z = eye[3]})
|
||||||
|
local center_vec = ffi.new("pxl8_vec3", {x = center[1], y = center[2], z = center[3]})
|
||||||
|
local up_vec = ffi.new("pxl8_vec3", {x = up[1], y = up[2], z = up[3]})
|
||||||
|
return C.pxl8_mat4_lookat(eye_vec, center_vec, up_vec)
|
||||||
|
end
|
||||||
|
|
||||||
|
function math3d.bounds(x, y, w, h)
|
||||||
|
return ffi.new("pxl8_bounds", {x = x, y = y, w = w, h = h})
|
||||||
|
end
|
||||||
|
|
||||||
|
return math3d
|
||||||
31
src/lua/pxl8/particles.lua
Normal file
31
src/lua/pxl8/particles.lua
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
local core = require("pxl8.core")
|
||||||
|
|
||||||
|
local particles = {}
|
||||||
|
|
||||||
|
function particles.new(max_count)
|
||||||
|
return C.pxl8_particles_create(max_count or 1000)
|
||||||
|
end
|
||||||
|
|
||||||
|
function particles.destroy(ps)
|
||||||
|
C.pxl8_particles_destroy(ps)
|
||||||
|
end
|
||||||
|
|
||||||
|
function particles.clear(ps)
|
||||||
|
C.pxl8_particles_clear(ps)
|
||||||
|
end
|
||||||
|
|
||||||
|
function particles.emit(ps, count)
|
||||||
|
C.pxl8_particles_emit(ps, count or 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function particles.update(ps, dt)
|
||||||
|
C.pxl8_particles_update(ps, dt)
|
||||||
|
end
|
||||||
|
|
||||||
|
function particles.render(ps)
|
||||||
|
C.pxl8_particles_render(ps, core.gfx)
|
||||||
|
end
|
||||||
|
|
||||||
|
return particles
|
||||||
82
src/lua/pxl8/tilemap.lua
Normal file
82
src/lua/pxl8/tilemap.lua
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
local core = require("pxl8.core")
|
||||||
|
|
||||||
|
local tilemap = {}
|
||||||
|
|
||||||
|
tilemap.TILE_FLIP_X = 1
|
||||||
|
tilemap.TILE_FLIP_Y = 2
|
||||||
|
tilemap.TILE_SOLID = 4
|
||||||
|
tilemap.TILE_TRIGGER = 8
|
||||||
|
|
||||||
|
local tile_data = setmetatable({}, {__mode = "k"})
|
||||||
|
|
||||||
|
function tilemap.tilesheet_new(tile_size)
|
||||||
|
return C.pxl8_tilesheet_create(tile_size or 16)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.tilesheet_destroy(tilesheet)
|
||||||
|
C.pxl8_tilesheet_destroy(tilesheet)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.tilesheet_load(tilesheet, filepath)
|
||||||
|
return C.pxl8_tilesheet_load(tilesheet, filepath, core.gfx)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.new(width, height, tile_size)
|
||||||
|
return C.pxl8_tilemap_create(width, height, tile_size or 16)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.destroy(tm)
|
||||||
|
C.pxl8_tilemap_destroy(tm)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.set_tilesheet(tm, tilesheet)
|
||||||
|
return C.pxl8_tilemap_set_tilesheet(tm, tilesheet)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.set_tile(tm, layer, x, y, tile_id, flags)
|
||||||
|
C.pxl8_tilemap_set_tile(tm, layer or 0, x, y, tile_id or 0, flags or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.get_tile_id(tm, layer, x, y)
|
||||||
|
return C.pxl8_tilemap_get_tile_id(tm, layer or 0, x, y)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.set_camera(tm, x, y)
|
||||||
|
C.pxl8_tilemap_set_camera(tm, x, y)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.render(tm)
|
||||||
|
C.pxl8_tilemap_render(tm, core.gfx)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.render_layer(tm, layer)
|
||||||
|
C.pxl8_tilemap_render_layer(tm, core.gfx, layer)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.is_solid(tm, x, y)
|
||||||
|
return C.pxl8_tilemap_is_solid(tm, x, y)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.check_collision(tm, x, y, w, h)
|
||||||
|
return C.pxl8_tilemap_check_collision(tm, x, y, w, h)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.get_tile_data(tm, tile_id)
|
||||||
|
if not tm or tile_id == 0 then return nil end
|
||||||
|
if not tile_data[tm] then return nil end
|
||||||
|
return tile_data[tm][tile_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.load_ase(tm, filepath, layer)
|
||||||
|
return C.pxl8_tilemap_load_ase(tm, filepath, layer or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tilemap.set_tile_data(tm, tile_id, data)
|
||||||
|
if not tm or tile_id == 0 then return end
|
||||||
|
if not tile_data[tm] then tile_data[tm] = {} end
|
||||||
|
tile_data[tm][tile_id] = data
|
||||||
|
end
|
||||||
|
|
||||||
|
return tilemap
|
||||||
68
src/lua/pxl8/transition.lua
Normal file
68
src/lua/pxl8/transition.lua
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
local core = require("pxl8.core")
|
||||||
|
|
||||||
|
local transition = {}
|
||||||
|
|
||||||
|
local transition_types = {
|
||||||
|
fade = 0,
|
||||||
|
wipe_left = 1,
|
||||||
|
wipe_right = 2,
|
||||||
|
wipe_up = 3,
|
||||||
|
wipe_down = 4,
|
||||||
|
circle_open = 5,
|
||||||
|
circle_close = 6,
|
||||||
|
dissolve = 7,
|
||||||
|
pixelate = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
function transition.create(type_name, duration)
|
||||||
|
local type_id = transition_types[type_name] or 0
|
||||||
|
return C.pxl8_transition_create(type_id, duration or 1.0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function transition.destroy(t)
|
||||||
|
C.pxl8_transition_destroy(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
function transition.get_progress(t)
|
||||||
|
return C.pxl8_transition_get_progress(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
function transition.is_active(t)
|
||||||
|
return C.pxl8_transition_is_active(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
function transition.is_complete(t)
|
||||||
|
return C.pxl8_transition_is_complete(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
function transition.render(t)
|
||||||
|
C.pxl8_transition_render(t, core.gfx)
|
||||||
|
end
|
||||||
|
|
||||||
|
function transition.reset(t)
|
||||||
|
C.pxl8_transition_reset(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
function transition.set_color(t, color)
|
||||||
|
C.pxl8_transition_set_color(t, color)
|
||||||
|
end
|
||||||
|
|
||||||
|
function transition.set_reverse(t, reverse)
|
||||||
|
C.pxl8_transition_set_reverse(t, reverse)
|
||||||
|
end
|
||||||
|
|
||||||
|
function transition.start(t)
|
||||||
|
C.pxl8_transition_start(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
function transition.stop(t)
|
||||||
|
C.pxl8_transition_stop(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
function transition.update(t, dt)
|
||||||
|
C.pxl8_transition_update(t, dt)
|
||||||
|
end
|
||||||
|
|
||||||
|
return transition
|
||||||
52
src/lua/pxl8/ui.lua
Normal file
52
src/lua/pxl8/ui.lua
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
local core = require("pxl8.core")
|
||||||
|
|
||||||
|
local ui = {}
|
||||||
|
|
||||||
|
function ui.button(label)
|
||||||
|
return C.pxl8_ui_button(core.ui, label)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ui.checkbox(label, state)
|
||||||
|
local state_ptr = ffi.new("bool[1]", state)
|
||||||
|
local changed = C.pxl8_ui_checkbox(core.ui, label, state_ptr)
|
||||||
|
return changed, state_ptr[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
function ui.has_mouse_focus()
|
||||||
|
return C.pxl8_ui_has_mouse_focus(core.ui)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ui.indent(amount)
|
||||||
|
C.pxl8_ui_indent(core.ui, amount)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ui.label(text)
|
||||||
|
C.pxl8_ui_label(core.ui, text)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ui.layout_row(item_count, widths, height)
|
||||||
|
local widths_array = widths
|
||||||
|
if type(widths) == "table" then
|
||||||
|
widths_array = ffi.new("int[?]", #widths, widths)
|
||||||
|
elseif type(widths) == "number" then
|
||||||
|
widths_array = ffi.new("int[1]", widths)
|
||||||
|
end
|
||||||
|
C.pxl8_ui_layout_row(core.ui, item_count, widths_array, height)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ui.window_begin(title, x, y, w, h, options)
|
||||||
|
local rect = ffi.new("pxl8_bounds", {x = x, y = y, w = w, h = h})
|
||||||
|
return C.pxl8_ui_window_begin(core.ui, title, rect, options or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ui.window_end()
|
||||||
|
C.pxl8_ui_window_end(core.ui)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ui.window_set_open(title, open)
|
||||||
|
C.pxl8_ui_window_set_open(core.ui, title, open)
|
||||||
|
end
|
||||||
|
|
||||||
|
return ui
|
||||||
65
src/lua/pxl8/vfx.lua
Normal file
65
src/lua/pxl8/vfx.lua
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
local core = require("pxl8.core")
|
||||||
|
|
||||||
|
local vfx = {}
|
||||||
|
|
||||||
|
function vfx.raster_bars(bars, time)
|
||||||
|
local c_bars = ffi.new("pxl8_raster_bar[?]", #bars)
|
||||||
|
for i, bar in ipairs(bars) do
|
||||||
|
c_bars[i-1].base_y = bar.base_y or 0
|
||||||
|
c_bars[i-1].amplitude = bar.amplitude or 10
|
||||||
|
c_bars[i-1].height = bar.height or 5
|
||||||
|
c_bars[i-1].speed = bar.speed or 1.0
|
||||||
|
c_bars[i-1].phase = bar.phase or 0
|
||||||
|
c_bars[i-1].color = bar.color or 15
|
||||||
|
c_bars[i-1].fade_color = bar.fade_color or bar.color or 15
|
||||||
|
end
|
||||||
|
C.pxl8_vfx_raster_bars(core.gfx, c_bars, #bars, time)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vfx.plasma(time, scale1, scale2, palette_offset)
|
||||||
|
C.pxl8_vfx_plasma(core.gfx, time, scale1 or 0.05, scale2 or 0.03, palette_offset or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vfx.rotozoom(angle, zoom, cx, cy)
|
||||||
|
local width = C.pxl8_gfx_get_width(core.gfx)
|
||||||
|
local height = C.pxl8_gfx_get_height(core.gfx)
|
||||||
|
C.pxl8_vfx_rotozoom(core.gfx, angle, zoom, cx or width/2, cy or height/2)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vfx.tunnel(time, speed, twist)
|
||||||
|
C.pxl8_vfx_tunnel(core.gfx, time, speed or 2.0, twist or 0.5)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vfx.explosion(ps, x, y, color, force)
|
||||||
|
C.pxl8_vfx_explosion(ps, x, y, color or 15, force or 200.0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vfx.fire(ps, x, y, width, palette_start)
|
||||||
|
C.pxl8_vfx_fire(ps, x, y, width or 50, palette_start or 64)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vfx.rain(ps, width, wind)
|
||||||
|
local w = width or C.pxl8_gfx_get_width(core.gfx)
|
||||||
|
C.pxl8_vfx_rain(ps, w, wind or 0.0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vfx.smoke(ps, x, y, color)
|
||||||
|
C.pxl8_vfx_smoke(ps, x, y, color or 8)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vfx.snow(ps, width, wind)
|
||||||
|
local w = width or C.pxl8_gfx_get_width(core.gfx)
|
||||||
|
C.pxl8_vfx_snow(ps, w, wind or 10.0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vfx.sparks(ps, x, y, color)
|
||||||
|
C.pxl8_vfx_sparks(ps, x, y, color or 15)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vfx.starfield(ps, speed, spread)
|
||||||
|
C.pxl8_vfx_starfield(ps, speed or 5.0, spread or 500.0)
|
||||||
|
end
|
||||||
|
|
||||||
|
return vfx
|
||||||
99
src/lua/pxl8/world.lua
Normal file
99
src/lua/pxl8/world.lua
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local C = ffi.C
|
||||||
|
local core = require("pxl8.core")
|
||||||
|
|
||||||
|
local world = {}
|
||||||
|
|
||||||
|
world.PROCGEN_CAVE = C.PXL8_PROCGEN_CAVE
|
||||||
|
world.PROCGEN_DUNGEON = C.PXL8_PROCGEN_DUNGEON
|
||||||
|
world.PROCGEN_TERRAIN = C.PXL8_PROCGEN_TERRAIN
|
||||||
|
|
||||||
|
function world.new()
|
||||||
|
return C.pxl8_world_create()
|
||||||
|
end
|
||||||
|
|
||||||
|
function world.destroy(w)
|
||||||
|
C.pxl8_world_destroy(w)
|
||||||
|
end
|
||||||
|
|
||||||
|
function world.load(w, filepath)
|
||||||
|
return C.pxl8_world_load(w, filepath)
|
||||||
|
end
|
||||||
|
|
||||||
|
function world.render(w, camera_pos)
|
||||||
|
local vec = ffi.new("pxl8_vec3", {x = camera_pos[1], y = camera_pos[2], z = camera_pos[3]})
|
||||||
|
C.pxl8_world_render(w, core.gfx, vec)
|
||||||
|
end
|
||||||
|
|
||||||
|
function world.unload(w)
|
||||||
|
C.pxl8_world_unload(w)
|
||||||
|
end
|
||||||
|
|
||||||
|
function world.is_loaded(w)
|
||||||
|
return C.pxl8_world_is_loaded(w)
|
||||||
|
end
|
||||||
|
|
||||||
|
function world.generate(w, params)
|
||||||
|
local c_params = ffi.new("pxl8_procgen_params")
|
||||||
|
c_params.type = params.type or C.PXL8_PROCGEN_CAVE
|
||||||
|
c_params.width = params.width or 32
|
||||||
|
c_params.height = params.height or 32
|
||||||
|
c_params.depth = params.depth or 0
|
||||||
|
c_params.seed = params.seed or 0
|
||||||
|
c_params.density = params.density or 0.45
|
||||||
|
c_params.iterations = params.iterations or 4
|
||||||
|
c_params.type_params = nil
|
||||||
|
return C.pxl8_world_generate(w, core.gfx, c_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
function world.procgen_tex(params)
|
||||||
|
local width = params.width or 64
|
||||||
|
local height = params.height or 64
|
||||||
|
local buffer = ffi.new("u8[?]", width * height)
|
||||||
|
local tex_params = ffi.new("pxl8_procgen_tex_params")
|
||||||
|
|
||||||
|
local name = params.name or ""
|
||||||
|
ffi.copy(tex_params.name, name, math.min(#name, 15))
|
||||||
|
|
||||||
|
tex_params.seed = params.seed or 0
|
||||||
|
tex_params.width = width
|
||||||
|
tex_params.height = height
|
||||||
|
tex_params.scale = params.scale or 1.0
|
||||||
|
tex_params.roughness = params.roughness or 0.0
|
||||||
|
tex_params.base_color = params.base_color or 0
|
||||||
|
tex_params.variation = params.variation or 0
|
||||||
|
|
||||||
|
C.pxl8_procgen_tex(buffer, tex_params)
|
||||||
|
|
||||||
|
local tex_id = C.pxl8_gfx_create_texture(core.gfx, buffer, width, height)
|
||||||
|
if tex_id < 0 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return tex_id
|
||||||
|
end
|
||||||
|
|
||||||
|
function world.apply_textures(w, texture_defs)
|
||||||
|
local count = #texture_defs
|
||||||
|
local textures = ffi.new("pxl8_world_texture[?]", count)
|
||||||
|
|
||||||
|
for i, def in ipairs(texture_defs) do
|
||||||
|
local idx = i - 1
|
||||||
|
ffi.copy(textures[idx].name, def.name or "", math.min(#(def.name or ""), 15))
|
||||||
|
textures[idx].texture_id = def.texture_id or 0
|
||||||
|
|
||||||
|
if def.rule then
|
||||||
|
textures[idx].rule = ffi.cast("bool (*)(const pxl8_vec3*, const pxl8_bsp_face*, const pxl8_bsp*)",
|
||||||
|
function(normal, face, bsp)
|
||||||
|
return def.rule(normal[0], face, bsp)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
textures[idx].rule = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = C.pxl8_world_apply_textures(w, textures, count)
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
return world
|
||||||
457
src/pxl8_anim.c
Normal file
457
src/pxl8_anim.c
Normal file
|
|
@ -0,0 +1,457 @@
|
||||||
|
#include "pxl8_anim.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "pxl8_ase.h"
|
||||||
|
#include "pxl8_atlas.h"
|
||||||
|
#include "pxl8_macros.h"
|
||||||
|
|
||||||
|
#define PXL8_ANIM_MAX_STATES 32
|
||||||
|
|
||||||
|
typedef struct pxl8_anim_state {
|
||||||
|
char* name;
|
||||||
|
pxl8_anim* anim;
|
||||||
|
} pxl8_anim_state;
|
||||||
|
|
||||||
|
typedef struct pxl8_anim_state_machine {
|
||||||
|
pxl8_anim_state states[PXL8_ANIM_MAX_STATES];
|
||||||
|
u16 state_count;
|
||||||
|
u16 current_state;
|
||||||
|
} pxl8_anim_state_machine;
|
||||||
|
|
||||||
|
pxl8_anim* pxl8_anim_create(const u32* frame_ids, const u16* frame_durations, u16 frame_count) {
|
||||||
|
if (!frame_ids || frame_count == 0) {
|
||||||
|
pxl8_error("Invalid animation parameters");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_anim* anim = (pxl8_anim*)calloc(1, sizeof(pxl8_anim));
|
||||||
|
if (!anim) {
|
||||||
|
pxl8_error("Failed to allocate animation");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
anim->frame_ids = (u32*)malloc(frame_count * sizeof(u32));
|
||||||
|
if (!anim->frame_ids) {
|
||||||
|
pxl8_error("Failed to allocate frame IDs");
|
||||||
|
free(anim);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(anim->frame_ids, frame_ids, frame_count * sizeof(u32));
|
||||||
|
|
||||||
|
if (frame_durations) {
|
||||||
|
anim->frame_durations = (u16*)malloc(frame_count * sizeof(u16));
|
||||||
|
if (!anim->frame_durations) {
|
||||||
|
pxl8_error("Failed to allocate frame durations");
|
||||||
|
free(anim->frame_ids);
|
||||||
|
free(anim);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(anim->frame_durations, frame_durations, frame_count * sizeof(u16));
|
||||||
|
} else {
|
||||||
|
anim->frame_durations = (u16*)calloc(frame_count, sizeof(u16));
|
||||||
|
if (!anim->frame_durations) {
|
||||||
|
pxl8_error("Failed to allocate frame durations");
|
||||||
|
free(anim->frame_ids);
|
||||||
|
free(anim);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (u16 i = 0; i < frame_count; i++) {
|
||||||
|
anim->frame_durations[i] = 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anim->frame_count = frame_count;
|
||||||
|
anim->current_frame = 0;
|
||||||
|
anim->time_accumulator = 0.0f;
|
||||||
|
anim->loop = true;
|
||||||
|
anim->playing = true;
|
||||||
|
anim->reverse = false;
|
||||||
|
anim->speed = 1.0f;
|
||||||
|
anim->state_machine = NULL;
|
||||||
|
anim->on_complete = NULL;
|
||||||
|
anim->on_frame_change = NULL;
|
||||||
|
anim->userdata = NULL;
|
||||||
|
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_anim* pxl8_anim_create_from_ase(pxl8_gfx* gfx, const char* path) {
|
||||||
|
if (!gfx || !path) {
|
||||||
|
pxl8_error("Invalid parameters for ASE animation creation");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_ase_file ase_file;
|
||||||
|
pxl8_result result = pxl8_ase_load(path, &ase_file);
|
||||||
|
if (result != PXL8_OK) {
|
||||||
|
pxl8_error("Failed to load ASE file: %s", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ase_file.frame_count == 0) {
|
||||||
|
pxl8_error("ASE file has no frames: %s", path);
|
||||||
|
pxl8_ase_destroy(&ase_file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32* frame_ids = (u32*)malloc(ase_file.frame_count * sizeof(u32));
|
||||||
|
u16* frame_durations = (u16*)malloc(ase_file.frame_count * sizeof(u16));
|
||||||
|
if (!frame_ids || !frame_durations) {
|
||||||
|
pxl8_error("Failed to allocate frame arrays");
|
||||||
|
free(frame_ids);
|
||||||
|
free(frame_durations);
|
||||||
|
pxl8_ase_destroy(&ase_file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < ase_file.frame_count; i++) {
|
||||||
|
pxl8_ase_frame* frame = &ase_file.frames[i];
|
||||||
|
result = pxl8_gfx_create_texture(gfx, frame->pixels, frame->width, frame->height);
|
||||||
|
if (result != PXL8_OK) {
|
||||||
|
pxl8_error("Failed to create texture for frame %u", i);
|
||||||
|
free(frame_ids);
|
||||||
|
free(frame_durations);
|
||||||
|
pxl8_ase_destroy(&ase_file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
frame_ids[i] = i;
|
||||||
|
frame_durations[i] = frame->duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_anim* anim = pxl8_anim_create(frame_ids, frame_durations, ase_file.frame_count);
|
||||||
|
|
||||||
|
free(frame_ids);
|
||||||
|
free(frame_durations);
|
||||||
|
pxl8_ase_destroy(&ase_file);
|
||||||
|
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_anim_destroy(pxl8_anim* anim) {
|
||||||
|
if (!anim) return;
|
||||||
|
|
||||||
|
if (anim->state_machine) {
|
||||||
|
for (u16 i = 0; i < anim->state_machine->state_count; i++) {
|
||||||
|
free(anim->state_machine->states[i].name);
|
||||||
|
pxl8_anim_destroy(anim->state_machine->states[i].anim);
|
||||||
|
}
|
||||||
|
free(anim->state_machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(anim->frame_ids);
|
||||||
|
free(anim->frame_durations);
|
||||||
|
free(anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_result pxl8_anim_add_state(pxl8_anim* anim, const char* name, pxl8_anim* state_anim) {
|
||||||
|
if (!anim || !name || !state_anim) {
|
||||||
|
return PXL8_ERROR_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anim->state_machine) {
|
||||||
|
anim->state_machine = (pxl8_anim_state_machine*)calloc(1, sizeof(pxl8_anim_state_machine));
|
||||||
|
if (!anim->state_machine) {
|
||||||
|
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anim->state_machine->state_count >= PXL8_ANIM_MAX_STATES) {
|
||||||
|
pxl8_error("Cannot add more states, maximum %d reached", PXL8_ANIM_MAX_STATES);
|
||||||
|
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 idx = anim->state_machine->state_count;
|
||||||
|
anim->state_machine->states[idx].name = strdup(name);
|
||||||
|
if (!anim->state_machine->states[idx].name) {
|
||||||
|
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
anim->state_machine->states[idx].anim = state_anim;
|
||||||
|
anim->state_machine->state_count++;
|
||||||
|
|
||||||
|
return PXL8_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 pxl8_anim_get_current_frame(const pxl8_anim* anim) {
|
||||||
|
if (!anim) return 0;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
return state_anim->current_frame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return anim->current_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 pxl8_anim_get_current_frame_id(const pxl8_anim* anim) {
|
||||||
|
if (!anim || !anim->frame_ids) return 0;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim && state_anim->frame_ids) {
|
||||||
|
return state_anim->frame_ids[state_anim->current_frame];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return anim->frame_ids[anim->current_frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* pxl8_anim_get_state(const pxl8_anim* anim) {
|
||||||
|
if (!anim || !anim->state_machine) return NULL;
|
||||||
|
|
||||||
|
if (anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
return anim->state_machine->states[anim->state_machine->current_state].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pxl8_anim_has_state_machine(const pxl8_anim* anim) {
|
||||||
|
return anim && anim->state_machine && anim->state_machine->state_count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pxl8_anim_is_complete(const pxl8_anim* anim) {
|
||||||
|
if (!anim) return true;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
return pxl8_anim_is_complete(state_anim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anim->loop) return false;
|
||||||
|
|
||||||
|
if (anim->reverse) {
|
||||||
|
return anim->current_frame == 0;
|
||||||
|
} else {
|
||||||
|
return anim->current_frame >= anim->frame_count - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pxl8_anim_is_playing(const pxl8_anim* anim) {
|
||||||
|
if (!anim) return false;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
return state_anim->playing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return anim->playing;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_anim_pause(pxl8_anim* anim) {
|
||||||
|
if (!anim) return;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
state_anim->playing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anim->playing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_anim_play(pxl8_anim* anim) {
|
||||||
|
if (!anim) return;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
state_anim->playing = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anim->playing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_anim_render_sprite(const pxl8_anim* anim, pxl8_gfx* gfx, i32 x, i32 y, i32 w, i32 h) {
|
||||||
|
if (!anim || !gfx) return;
|
||||||
|
|
||||||
|
u32 sprite_id = pxl8_anim_get_current_frame_id(anim);
|
||||||
|
pxl8_sprite(gfx, sprite_id, x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_anim_reset(pxl8_anim* anim) {
|
||||||
|
if (!anim) return;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
pxl8_anim_reset(state_anim);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anim->current_frame = anim->reverse ? anim->frame_count - 1 : 0;
|
||||||
|
anim->time_accumulator = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_anim_set_frame(pxl8_anim* anim, u16 frame) {
|
||||||
|
if (!anim) return;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
pxl8_anim_set_frame(state_anim, frame);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame < anim->frame_count) {
|
||||||
|
anim->current_frame = frame;
|
||||||
|
anim->time_accumulator = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_anim_set_loop(pxl8_anim* anim, bool loop) {
|
||||||
|
if (!anim) return;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
state_anim->loop = loop;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anim->loop = loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_anim_set_reverse(pxl8_anim* anim, bool reverse) {
|
||||||
|
if (!anim) return;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
state_anim->reverse = reverse;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anim->reverse = reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_anim_set_speed(pxl8_anim* anim, f32 speed) {
|
||||||
|
if (!anim) return;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
state_anim->speed = speed;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anim->speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_result pxl8_anim_set_state(pxl8_anim* anim, const char* name) {
|
||||||
|
if (!anim || !name) {
|
||||||
|
return PXL8_ERROR_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anim->state_machine) {
|
||||||
|
return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u16 i = 0; i < anim->state_machine->state_count; i++) {
|
||||||
|
if (strcmp(anim->state_machine->states[i].name, name) == 0) {
|
||||||
|
if (anim->state_machine->current_state != i) {
|
||||||
|
anim->state_machine->current_state = i;
|
||||||
|
pxl8_anim_reset(anim->state_machine->states[i].anim);
|
||||||
|
}
|
||||||
|
return PXL8_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_error("Animation state not found: %s", name);
|
||||||
|
return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_anim_stop(pxl8_anim* anim) {
|
||||||
|
if (!anim) return;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
pxl8_anim_stop(state_anim);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anim->playing = false;
|
||||||
|
pxl8_anim_reset(anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_anim_update(pxl8_anim* anim, f32 dt) {
|
||||||
|
if (!anim || !anim->playing) return;
|
||||||
|
|
||||||
|
if (anim->state_machine && anim->state_machine->current_state < anim->state_machine->state_count) {
|
||||||
|
pxl8_anim* state_anim = anim->state_machine->states[anim->state_machine->current_state].anim;
|
||||||
|
if (state_anim) {
|
||||||
|
pxl8_anim_update(state_anim, dt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anim->frame_count == 0 || !anim->frame_durations) return;
|
||||||
|
|
||||||
|
anim->time_accumulator += dt * anim->speed * 1000.0f;
|
||||||
|
|
||||||
|
u16 current_duration = anim->frame_durations[anim->current_frame];
|
||||||
|
if (current_duration == 0) return;
|
||||||
|
|
||||||
|
while (anim->time_accumulator >= current_duration) {
|
||||||
|
anim->time_accumulator -= current_duration;
|
||||||
|
|
||||||
|
u16 old_frame = anim->current_frame;
|
||||||
|
|
||||||
|
if (anim->reverse) {
|
||||||
|
if (anim->current_frame > 0) {
|
||||||
|
anim->current_frame--;
|
||||||
|
} else {
|
||||||
|
if (anim->loop) {
|
||||||
|
anim->current_frame = anim->frame_count - 1;
|
||||||
|
} else {
|
||||||
|
anim->playing = false;
|
||||||
|
if (anim->on_complete) {
|
||||||
|
anim->on_complete(anim->userdata);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (anim->current_frame < anim->frame_count - 1) {
|
||||||
|
anim->current_frame++;
|
||||||
|
} else {
|
||||||
|
if (anim->loop) {
|
||||||
|
anim->current_frame = 0;
|
||||||
|
} else {
|
||||||
|
anim->playing = false;
|
||||||
|
if (anim->on_complete) {
|
||||||
|
anim->on_complete(anim->userdata);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old_frame != anim->current_frame && anim->on_frame_change) {
|
||||||
|
anim->on_frame_change(anim->current_frame, anim->userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
current_duration = anim->frame_durations[anim->current_frame];
|
||||||
|
if (current_duration == 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
56
src/pxl8_anim.h
Normal file
56
src/pxl8_anim.h
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_gfx.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
typedef struct pxl8_anim_state_machine pxl8_anim_state_machine;
|
||||||
|
|
||||||
|
typedef struct pxl8_anim {
|
||||||
|
u32* frame_ids;
|
||||||
|
u16* frame_durations;
|
||||||
|
u16 frame_count;
|
||||||
|
u16 current_frame;
|
||||||
|
f32 time_accumulator;
|
||||||
|
|
||||||
|
bool loop;
|
||||||
|
bool playing;
|
||||||
|
bool reverse;
|
||||||
|
f32 speed;
|
||||||
|
|
||||||
|
pxl8_anim_state_machine* state_machine;
|
||||||
|
|
||||||
|
void (*on_complete)(void* userdata);
|
||||||
|
void (*on_frame_change)(u16 frame, void* userdata);
|
||||||
|
void* userdata;
|
||||||
|
} pxl8_anim;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pxl8_anim* pxl8_anim_create(const u32* frame_ids, const u16* frame_durations, u16 frame_count);
|
||||||
|
pxl8_anim* pxl8_anim_create_from_ase(pxl8_gfx* gfx, const char* path);
|
||||||
|
void pxl8_anim_destroy(pxl8_anim* anim);
|
||||||
|
|
||||||
|
pxl8_result pxl8_anim_add_state(pxl8_anim* anim, const char* name, pxl8_anim* state_anim);
|
||||||
|
u16 pxl8_anim_get_current_frame(const pxl8_anim* anim);
|
||||||
|
u32 pxl8_anim_get_current_frame_id(const pxl8_anim* anim);
|
||||||
|
const char* pxl8_anim_get_state(const pxl8_anim* anim);
|
||||||
|
bool pxl8_anim_has_state_machine(const pxl8_anim* anim);
|
||||||
|
bool pxl8_anim_is_complete(const pxl8_anim* anim);
|
||||||
|
bool pxl8_anim_is_playing(const pxl8_anim* anim);
|
||||||
|
void pxl8_anim_pause(pxl8_anim* anim);
|
||||||
|
void pxl8_anim_play(pxl8_anim* anim);
|
||||||
|
void pxl8_anim_render_sprite(const pxl8_anim* anim, pxl8_gfx* gfx, i32 x, i32 y, i32 w, i32 h);
|
||||||
|
void pxl8_anim_reset(pxl8_anim* anim);
|
||||||
|
void pxl8_anim_set_frame(pxl8_anim* anim, u16 frame);
|
||||||
|
void pxl8_anim_set_loop(pxl8_anim* anim, bool loop);
|
||||||
|
void pxl8_anim_set_reverse(pxl8_anim* anim, bool reverse);
|
||||||
|
void pxl8_anim_set_speed(pxl8_anim* anim, f32 speed);
|
||||||
|
pxl8_result pxl8_anim_set_state(pxl8_anim* anim, const char* name);
|
||||||
|
void pxl8_anim_stop(pxl8_anim* anim);
|
||||||
|
void pxl8_anim_update(pxl8_anim* anim, f32 dt);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -141,7 +141,7 @@ pxl8_gfx* pxl8_gfx_create(
|
||||||
i32 window_width,
|
i32 window_width,
|
||||||
i32 window_height
|
i32 window_height
|
||||||
) {
|
) {
|
||||||
pxl8_gfx* gfx = (pxl8_gfx*)calloc(1, sizeof(*gfx));
|
pxl8_gfx* gfx = (pxl8_gfx*)calloc(1, sizeof(pxl8_gfx));
|
||||||
if (!gfx) {
|
if (!gfx) {
|
||||||
pxl8_error("Failed to allocate graphics context");
|
pxl8_error("Failed to allocate graphics context");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
||||||
|
|
@ -28,26 +28,12 @@ static f32 prng_float(void) {
|
||||||
return (f32)prng_next() / (f32)0xFFFFFFFF;
|
return (f32)prng_next() / (f32)0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cave_grid* cave_grid_create(i32 width, i32 height) {
|
static bool cave_grid_init(cave_grid* grid, i32 width, i32 height) {
|
||||||
cave_grid* grid = malloc(sizeof(cave_grid));
|
|
||||||
if (!grid) return NULL;
|
|
||||||
|
|
||||||
grid->width = width;
|
grid->width = width;
|
||||||
grid->height = height;
|
grid->height = height;
|
||||||
grid->cells = calloc(width * height, sizeof(u8));
|
grid->cells = calloc(width * height, sizeof(u8));
|
||||||
|
|
||||||
if (!grid->cells) {
|
return grid->cells != NULL;
|
||||||
free(grid);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cave_grid_destroy(cave_grid* grid) {
|
|
||||||
if (!grid) return;
|
|
||||||
free(grid->cells);
|
|
||||||
free(grid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 cave_grid_get(const cave_grid* grid, i32 x, i32 y) {
|
static u8 cave_grid_get(const cave_grid* grid, i32 x, i32 y) {
|
||||||
|
|
@ -102,19 +88,19 @@ static void cave_grid_initialize(cave_grid* grid, f32 density) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cave_grid_smooth(cave_grid* grid) {
|
static void cave_grid_smooth(cave_grid* grid) {
|
||||||
cave_grid* temp = cave_grid_create(grid->width, grid->height);
|
cave_grid temp;
|
||||||
if (!temp) return;
|
if (!cave_grid_init(&temp, grid->width, grid->height)) return;
|
||||||
|
|
||||||
for (i32 y = 0; y < grid->height; y++) {
|
for (i32 y = 0; y < grid->height; y++) {
|
||||||
for (i32 x = 0; x < grid->width; x++) {
|
for (i32 x = 0; x < grid->width; x++) {
|
||||||
i32 neighbors = cave_grid_count_neighbors(grid, x, y);
|
i32 neighbors = cave_grid_count_neighbors(grid, x, y);
|
||||||
u8 value = (neighbors > 4) ? 1 : 0;
|
u8 value = (neighbors > 4) ? 1 : 0;
|
||||||
cave_grid_set(temp, x, y, value);
|
cave_grid_set(&temp, x, y, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(grid->cells, temp->cells, grid->width * grid->height);
|
memcpy(grid->cells, temp.cells, grid->width * grid->height);
|
||||||
cave_grid_destroy(temp);
|
free(temp.cells);
|
||||||
}
|
}
|
||||||
|
|
||||||
static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
||||||
|
|
@ -366,19 +352,19 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
||||||
static pxl8_result procgen_cave(pxl8_bsp* bsp, const pxl8_procgen_params* params) {
|
static pxl8_result procgen_cave(pxl8_bsp* bsp, const pxl8_procgen_params* params) {
|
||||||
prng_seed(params->seed);
|
prng_seed(params->seed);
|
||||||
|
|
||||||
cave_grid* grid = cave_grid_create(params->width, params->height);
|
cave_grid grid;
|
||||||
if (!grid) {
|
if (!cave_grid_init(&grid, params->width, params->height)) {
|
||||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
cave_grid_initialize(grid, params->density);
|
cave_grid_initialize(&grid, params->density);
|
||||||
|
|
||||||
for (i32 i = 0; i < params->iterations; i++) {
|
for (i32 i = 0; i < params->iterations; i++) {
|
||||||
cave_grid_smooth(grid);
|
cave_grid_smooth(&grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_result result = cave_to_bsp(bsp, grid);
|
pxl8_result result = cave_to_bsp(bsp, &grid);
|
||||||
cave_grid_destroy(grid);
|
free(grid.cells);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,44 @@ static const char* pxl8_ffi_cdefs =
|
||||||
"void pxl8_vfx_tunnel(pxl8_gfx* ctx, f32 time, f32 speed, f32 twist);\n"
|
"void pxl8_vfx_tunnel(pxl8_gfx* ctx, f32 time, f32 speed, f32 twist);\n"
|
||||||
"void pxl8_vfx_water_ripple(pxl8_gfx* ctx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping);\n"
|
"void pxl8_vfx_water_ripple(pxl8_gfx* ctx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping);\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"typedef struct pxl8_transition pxl8_transition;\n"
|
||||||
|
"typedef struct pxl8_anim pxl8_anim;\n"
|
||||||
|
"\n"
|
||||||
|
"pxl8_transition* pxl8_transition_create(i32 type, f32 duration);\n"
|
||||||
|
"void pxl8_transition_destroy(pxl8_transition* transition);\n"
|
||||||
|
"f32 pxl8_transition_get_progress(const pxl8_transition* transition);\n"
|
||||||
|
"bool pxl8_transition_is_active(const pxl8_transition* transition);\n"
|
||||||
|
"bool pxl8_transition_is_complete(const pxl8_transition* transition);\n"
|
||||||
|
"void pxl8_transition_render(const pxl8_transition* transition, pxl8_gfx* gfx);\n"
|
||||||
|
"void pxl8_transition_reset(pxl8_transition* transition);\n"
|
||||||
|
"void pxl8_transition_set_color(pxl8_transition* transition, u32 color);\n"
|
||||||
|
"void pxl8_transition_set_reverse(pxl8_transition* transition, bool reverse);\n"
|
||||||
|
"void pxl8_transition_start(pxl8_transition* transition);\n"
|
||||||
|
"void pxl8_transition_stop(pxl8_transition* transition);\n"
|
||||||
|
"void pxl8_transition_update(pxl8_transition* transition, f32 dt);\n"
|
||||||
|
"\n"
|
||||||
|
"pxl8_anim* pxl8_anim_create(const u32* frame_ids, const u16* frame_durations, u16 frame_count);\n"
|
||||||
|
"pxl8_anim* pxl8_anim_create_from_ase(pxl8_gfx* gfx, const char* path);\n"
|
||||||
|
"void pxl8_anim_destroy(pxl8_anim* anim);\n"
|
||||||
|
"i32 pxl8_anim_add_state(pxl8_anim* anim, const char* name, pxl8_anim* state_anim);\n"
|
||||||
|
"u16 pxl8_anim_get_current_frame(const pxl8_anim* anim);\n"
|
||||||
|
"u32 pxl8_anim_get_current_frame_id(const pxl8_anim* anim);\n"
|
||||||
|
"const char* pxl8_anim_get_state(const pxl8_anim* anim);\n"
|
||||||
|
"bool pxl8_anim_has_state_machine(const pxl8_anim* anim);\n"
|
||||||
|
"bool pxl8_anim_is_complete(const pxl8_anim* anim);\n"
|
||||||
|
"bool pxl8_anim_is_playing(const pxl8_anim* anim);\n"
|
||||||
|
"void pxl8_anim_pause(pxl8_anim* anim);\n"
|
||||||
|
"void pxl8_anim_play(pxl8_anim* anim);\n"
|
||||||
|
"void pxl8_anim_render_sprite(const pxl8_anim* anim, pxl8_gfx* gfx, i32 x, i32 y, i32 w, i32 h);\n"
|
||||||
|
"void pxl8_anim_reset(pxl8_anim* anim);\n"
|
||||||
|
"void pxl8_anim_set_frame(pxl8_anim* anim, u16 frame);\n"
|
||||||
|
"void pxl8_anim_set_loop(pxl8_anim* anim, bool loop);\n"
|
||||||
|
"void pxl8_anim_set_reverse(pxl8_anim* anim, bool reverse);\n"
|
||||||
|
"void pxl8_anim_set_speed(pxl8_anim* anim, f32 speed);\n"
|
||||||
|
"i32 pxl8_anim_set_state(pxl8_anim* anim, const char* name);\n"
|
||||||
|
"void pxl8_anim_stop(pxl8_anim* anim);\n"
|
||||||
|
"void pxl8_anim_update(pxl8_anim* anim, f32 dt);\n"
|
||||||
|
"\n"
|
||||||
"typedef struct { float x, y, z; } pxl8_vec3;\n"
|
"typedef struct { float x, y, z; } pxl8_vec3;\n"
|
||||||
"typedef struct { float x, y, z, w; } pxl8_vec4;\n"
|
"typedef struct { float x, y, z, w; } pxl8_vec4;\n"
|
||||||
"typedef struct { float m[16]; } pxl8_mat4;\n"
|
"typedef struct { float m[16]; } pxl8_mat4;\n"
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ static void* sdl3_create(pxl8_color_mode mode, pxl8_resolution resolution,
|
||||||
const char* title, i32 win_w, i32 win_h) {
|
const char* title, i32 win_w, i32 win_h) {
|
||||||
(void)mode;
|
(void)mode;
|
||||||
|
|
||||||
pxl8_sdl3_context* ctx = (pxl8_sdl3_context*)SDL_calloc(1, sizeof(*ctx));
|
pxl8_sdl3_context* ctx = (pxl8_sdl3_context*)SDL_calloc(1, sizeof(pxl8_sdl3_context));
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
pxl8_error("Failed to allocate SDL3 context");
|
pxl8_error("Failed to allocate SDL3 context");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
||||||
248
src/pxl8_transition.c
Normal file
248
src/pxl8_transition.c
Normal file
|
|
@ -0,0 +1,248 @@
|
||||||
|
#include "pxl8_transition.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "pxl8_macros.h"
|
||||||
|
#include "pxl8_math.h"
|
||||||
|
|
||||||
|
pxl8_transition* pxl8_transition_create(pxl8_transition_type type, f32 duration) {
|
||||||
|
if (duration <= 0.0f) {
|
||||||
|
pxl8_error("Invalid transition duration: %f", duration);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_transition* transition = (pxl8_transition*)calloc(1, sizeof(pxl8_transition));
|
||||||
|
if (!transition) {
|
||||||
|
pxl8_error("Failed to allocate transition");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
transition->type = type;
|
||||||
|
transition->duration = duration;
|
||||||
|
transition->time = 0.0f;
|
||||||
|
transition->active = false;
|
||||||
|
transition->reverse = false;
|
||||||
|
transition->color = 0xFF000000;
|
||||||
|
transition->on_complete = NULL;
|
||||||
|
transition->userdata = NULL;
|
||||||
|
|
||||||
|
return transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_transition_destroy(pxl8_transition* transition) {
|
||||||
|
if (!transition) return;
|
||||||
|
free(transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 pxl8_transition_get_progress(const pxl8_transition* transition) {
|
||||||
|
if (!transition) return 0.0f;
|
||||||
|
|
||||||
|
f32 t = transition->time / transition->duration;
|
||||||
|
if (t < 0.0f) t = 0.0f;
|
||||||
|
if (t > 1.0f) t = 1.0f;
|
||||||
|
|
||||||
|
return transition->reverse ? 1.0f - t : t;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pxl8_transition_is_active(const pxl8_transition* transition) {
|
||||||
|
return transition && transition->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pxl8_transition_is_complete(const pxl8_transition* transition) {
|
||||||
|
if (!transition) return true;
|
||||||
|
return transition->time >= transition->duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_transition_render(const pxl8_transition* transition, pxl8_gfx* gfx) {
|
||||||
|
if (!transition || !gfx || !transition->active) return;
|
||||||
|
|
||||||
|
f32 progress = pxl8_transition_get_progress(transition);
|
||||||
|
i32 width = pxl8_gfx_get_width(gfx);
|
||||||
|
i32 height = pxl8_gfx_get_height(gfx);
|
||||||
|
|
||||||
|
switch (transition->type) {
|
||||||
|
case PXL8_TRANSITION_FADE: {
|
||||||
|
u8 alpha = (u8)(progress * 255.0f);
|
||||||
|
u32 fade_color = (transition->color & 0x00FFFFFF) | (alpha << 24);
|
||||||
|
|
||||||
|
for (i32 y = 0; y < height; y++) {
|
||||||
|
for (i32 x = 0; x < width; x++) {
|
||||||
|
u32 bg = pxl8_get_pixel(gfx, x, y);
|
||||||
|
u32 r_bg = (bg >> 16) & 0xFF;
|
||||||
|
u32 g_bg = (bg >> 8) & 0xFF;
|
||||||
|
u32 b_bg = bg & 0xFF;
|
||||||
|
|
||||||
|
u32 r_fg = (fade_color >> 16) & 0xFF;
|
||||||
|
u32 g_fg = (fade_color >> 8) & 0xFF;
|
||||||
|
u32 b_fg = fade_color & 0xFF;
|
||||||
|
|
||||||
|
u32 r = (r_bg * (255 - alpha) + r_fg * alpha) / 255;
|
||||||
|
u32 g = (g_bg * (255 - alpha) + g_fg * alpha) / 255;
|
||||||
|
u32 b = (b_bg * (255 - alpha) + b_fg * alpha) / 255;
|
||||||
|
|
||||||
|
pxl8_pixel(gfx, x, y, 0xFF000000 | (r << 16) | (g << 8) | b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PXL8_TRANSITION_WIPE_LEFT: {
|
||||||
|
i32 wipe_x = (i32)(width * progress);
|
||||||
|
pxl8_rect_fill(gfx, 0, 0, wipe_x, height, transition->color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PXL8_TRANSITION_WIPE_RIGHT: {
|
||||||
|
i32 wipe_x = (i32)(width * (1.0f - progress));
|
||||||
|
pxl8_rect_fill(gfx, wipe_x, 0, width - wipe_x, height, transition->color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PXL8_TRANSITION_WIPE_UP: {
|
||||||
|
i32 wipe_y = (i32)(height * progress);
|
||||||
|
pxl8_rect_fill(gfx, 0, 0, width, wipe_y, transition->color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PXL8_TRANSITION_WIPE_DOWN: {
|
||||||
|
i32 wipe_y = (i32)(height * (1.0f - progress));
|
||||||
|
pxl8_rect_fill(gfx, 0, wipe_y, width, height - wipe_y, transition->color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PXL8_TRANSITION_CIRCLE_CLOSE: {
|
||||||
|
i32 center_x = width / 2;
|
||||||
|
i32 center_y = height / 2;
|
||||||
|
i32 max_radius = (i32)sqrtf((f32)(center_x * center_x + center_y * center_y));
|
||||||
|
i32 radius = (i32)(max_radius * (1.0f - progress));
|
||||||
|
|
||||||
|
for (i32 y = 0; y < height; y++) {
|
||||||
|
for (i32 x = 0; x < width; x++) {
|
||||||
|
i32 dx = x - center_x;
|
||||||
|
i32 dy = y - center_y;
|
||||||
|
i32 dist = (i32)sqrtf((f32)(dx * dx + dy * dy));
|
||||||
|
if (dist > radius) {
|
||||||
|
pxl8_pixel(gfx, x, y, transition->color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PXL8_TRANSITION_CIRCLE_OPEN: {
|
||||||
|
i32 center_x = width / 2;
|
||||||
|
i32 center_y = height / 2;
|
||||||
|
i32 max_radius = (i32)sqrtf((f32)(center_x * center_x + center_y * center_y));
|
||||||
|
i32 radius = (i32)(max_radius * progress);
|
||||||
|
|
||||||
|
for (i32 y = 0; y < height; y++) {
|
||||||
|
for (i32 x = 0; x < width; x++) {
|
||||||
|
i32 dx = x - center_x;
|
||||||
|
i32 dy = y - center_y;
|
||||||
|
i32 dist = (i32)sqrtf((f32)(dx * dx + dy * dy));
|
||||||
|
if (dist < radius) {
|
||||||
|
pxl8_pixel(gfx, x, y, transition->color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PXL8_TRANSITION_DISSOLVE: {
|
||||||
|
u32 seed = 12345;
|
||||||
|
for (i32 y = 0; y < height; y++) {
|
||||||
|
for (i32 x = 0; x < width; x++) {
|
||||||
|
seed = seed * 1103515245 + 12345;
|
||||||
|
f32 noise = (f32)((seed / 65536) % 1000) / 1000.0f;
|
||||||
|
if (noise < progress) {
|
||||||
|
pxl8_pixel(gfx, x, y, transition->color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PXL8_TRANSITION_PIXELATE: {
|
||||||
|
i32 max_block_size = 32;
|
||||||
|
i32 block_size = (i32)(max_block_size * progress);
|
||||||
|
if (block_size < 1) block_size = 1;
|
||||||
|
|
||||||
|
u8* fb = pxl8_gfx_get_framebuffer(gfx);
|
||||||
|
if (!fb) break;
|
||||||
|
|
||||||
|
for (i32 y = 0; y < height; y += block_size) {
|
||||||
|
for (i32 x = 0; x < width; x += block_size) {
|
||||||
|
u32 color_sum_r = 0, color_sum_g = 0, color_sum_b = 0;
|
||||||
|
i32 count = 0;
|
||||||
|
|
||||||
|
for (i32 by = 0; by < block_size && y + by < height; by++) {
|
||||||
|
for (i32 bx = 0; bx < block_size && x + bx < width; bx++) {
|
||||||
|
u32 color = pxl8_get_pixel(gfx, x + bx, y + by);
|
||||||
|
color_sum_r += (color >> 16) & 0xFF;
|
||||||
|
color_sum_g += (color >> 8) & 0xFF;
|
||||||
|
color_sum_b += color & 0xFF;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
u32 avg_color = 0xFF000000 |
|
||||||
|
((color_sum_r / count) << 16) |
|
||||||
|
((color_sum_g / count) << 8) |
|
||||||
|
(color_sum_b / count);
|
||||||
|
|
||||||
|
for (i32 by = 0; by < block_size && y + by < height; by++) {
|
||||||
|
for (i32 bx = 0; bx < block_size && x + bx < width; bx++) {
|
||||||
|
pxl8_pixel(gfx, x + bx, y + by, avg_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_transition_reset(pxl8_transition* transition) {
|
||||||
|
if (!transition) return;
|
||||||
|
transition->time = 0.0f;
|
||||||
|
transition->active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_transition_set_color(pxl8_transition* transition, u32 color) {
|
||||||
|
if (!transition) return;
|
||||||
|
transition->color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_transition_set_reverse(pxl8_transition* transition, bool reverse) {
|
||||||
|
if (!transition) return;
|
||||||
|
transition->reverse = reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_transition_start(pxl8_transition* transition) {
|
||||||
|
if (!transition) return;
|
||||||
|
transition->active = true;
|
||||||
|
transition->time = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_transition_stop(pxl8_transition* transition) {
|
||||||
|
if (!transition) return;
|
||||||
|
transition->active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_transition_update(pxl8_transition* transition, f32 dt) {
|
||||||
|
if (!transition || !transition->active) return;
|
||||||
|
|
||||||
|
transition->time += dt;
|
||||||
|
|
||||||
|
if (transition->time >= transition->duration) {
|
||||||
|
transition->time = transition->duration;
|
||||||
|
transition->active = false;
|
||||||
|
|
||||||
|
if (transition->on_complete) {
|
||||||
|
transition->on_complete(transition->userdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
src/pxl8_transition.h
Normal file
51
src/pxl8_transition.h
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_gfx.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
typedef enum pxl8_transition_type {
|
||||||
|
PXL8_TRANSITION_FADE,
|
||||||
|
PXL8_TRANSITION_WIPE_LEFT,
|
||||||
|
PXL8_TRANSITION_WIPE_RIGHT,
|
||||||
|
PXL8_TRANSITION_WIPE_UP,
|
||||||
|
PXL8_TRANSITION_WIPE_DOWN,
|
||||||
|
PXL8_TRANSITION_CIRCLE_OPEN,
|
||||||
|
PXL8_TRANSITION_CIRCLE_CLOSE,
|
||||||
|
PXL8_TRANSITION_DISSOLVE,
|
||||||
|
PXL8_TRANSITION_PIXELATE
|
||||||
|
} pxl8_transition_type;
|
||||||
|
|
||||||
|
typedef struct pxl8_transition {
|
||||||
|
pxl8_transition_type type;
|
||||||
|
f32 duration;
|
||||||
|
f32 time;
|
||||||
|
bool active;
|
||||||
|
bool reverse;
|
||||||
|
|
||||||
|
u32 color;
|
||||||
|
|
||||||
|
void (*on_complete)(void* userdata);
|
||||||
|
void* userdata;
|
||||||
|
} pxl8_transition;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pxl8_transition* pxl8_transition_create(pxl8_transition_type type, f32 duration);
|
||||||
|
void pxl8_transition_destroy(pxl8_transition* transition);
|
||||||
|
|
||||||
|
f32 pxl8_transition_get_progress(const pxl8_transition* transition);
|
||||||
|
bool pxl8_transition_is_active(const pxl8_transition* transition);
|
||||||
|
bool pxl8_transition_is_complete(const pxl8_transition* transition);
|
||||||
|
void pxl8_transition_render(const pxl8_transition* transition, pxl8_gfx* gfx);
|
||||||
|
void pxl8_transition_reset(pxl8_transition* transition);
|
||||||
|
void pxl8_transition_set_color(pxl8_transition* transition, u32 color);
|
||||||
|
void pxl8_transition_set_reverse(pxl8_transition* transition, bool reverse);
|
||||||
|
void pxl8_transition_start(pxl8_transition* transition);
|
||||||
|
void pxl8_transition_stop(pxl8_transition* transition);
|
||||||
|
void pxl8_transition_update(pxl8_transition* transition, f32 dt);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Loading…
Add table
Add a link
Reference in a new issue