├── .gitattributes ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── examples ├── box2d_joints.yue ├── core_3d_camera_first_person.yue ├── gui_controls.yue ├── models_mesh_picking.yue └── resources │ ├── LICENSE.md │ └── models │ └── obj │ ├── turret.obj │ └── turret_diffuse.png ├── lib ├── box2d │ ├── Body.yue │ ├── Contact.yue │ ├── Fixture.yue │ ├── JointType.yue │ ├── ShapeType.yue │ ├── World.yue │ ├── _scale.yue │ ├── draw.yue │ ├── init.yue │ ├── joints.yue │ └── shapes.yue ├── core │ ├── debug.yue │ └── init.yue ├── gl │ └── init.yue ├── math │ ├── Matrix.yue │ ├── Quaternion.yue │ ├── RNG.yue │ ├── Vector2.yue │ ├── Vector3.yue │ ├── easings.yue │ ├── funcs.yue │ ├── init.yue │ ├── noise2d.yue │ └── noise3d.yue ├── ray │ ├── BoundingBox.yue │ ├── Camera2D.yue │ ├── Camera3D.yue │ ├── Color.yue │ ├── Font.yue │ ├── Image.yue │ ├── Material.yue │ ├── Mesh.yue │ ├── Model.yue │ ├── NPatchInfo.yue │ ├── Rectangle.yue │ ├── RenderTexture.yue │ ├── Shader.yue │ ├── Texture2D.yue │ ├── audio.yue │ ├── collision.yue │ ├── config.yue │ ├── data.yue │ ├── draw.yue │ ├── filesystem.yue │ ├── gui.yue │ ├── init.yue │ ├── input.yue │ ├── lights.yue │ ├── log.yue │ ├── text.yue │ ├── time.yue │ ├── util.yue │ └── window.yue └── util │ ├── Pool.yue │ ├── Stack.yue │ ├── ptr.yue │ └── table.yue ├── main.lua └── src ├── box2dc ├── box2dc.cpp ├── box2dc.h ├── contact.cpp ├── joints.cpp ├── shapes.cpp ├── util.h └── world.cpp └── yuema ├── .gitignore ├── LuaVM.cpp ├── LuaVM.h ├── main.cpp └── tools ├── cparser.lua └── generate_ffi.lua /.gitattributes: -------------------------------------------------------------------------------- 1 | # linguist doesn not support yuescript (yet); use MoonScript as a fallback 2 | *.yue linguist-language=MoonScript 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.sublime* 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/LuaJIT"] 2 | path = src/LuaJIT 3 | url = https://github.com/LuaJIT/LuaJIT 4 | [submodule "src/raylib"] 5 | path = src/raylib 6 | url = https://github.com/raysan5/raylib.git 7 | [submodule "src/raygui"] 8 | path = src/raygui 9 | url = https://github.com/raysan5/raygui 10 | [submodule "src/Yuescript"] 11 | path = src/Yuescript 12 | url = https://github.com/pigpigyyy/Yuescript.git 13 | [submodule "src/luautf8"] 14 | path = src/luautf8 15 | url = https://github.com/starwing/luautf8.git 16 | [submodule "src/box2d"] 17 | path = src/box2d 18 | url = https://github.com/erincatto/box2d.git 19 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | if(DEFINED CMAKE_BUILD_TYPE) 4 | set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Build type") 5 | else() 6 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type") 7 | endif() 8 | 9 | project(yuema) 10 | set(CMAKE_CXX_STANDARD 17) 11 | set(CMAKE_CXX_STANDARD_REQUIRED False) 12 | 13 | set(YUEMA_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src/yuema) 14 | 15 | if(WIN32) 16 | set(LINKER_OPTS "-Wl,-subsystem,windows -static") 17 | set(EXE_SUFFIX ".exe") 18 | else() 19 | set(LINKER_OPTS "-ldl") 20 | set(EXE_SUFFIX "") 21 | endif() 22 | 23 | ### LuaJIT 24 | set(LUAJIT_PROJECT_DIR ${PROJECT_SOURCE_DIR}/src/LuaJIT) 25 | set(LUAJIT_SOURCE_DIR ${LUAJIT_PROJECT_DIR}/src) 26 | 27 | add_custom_target(luajit-bin ALL 28 | WORKING_DIRECTORY ${LUAJIT_PROJECT_DIR} 29 | COMMAND make BUILDMODE=static CFLAGS=-DLUAJIT_ENABLE_LUA52COMPAT=1 -j 30 | ) 31 | add_library(luajit STATIC IMPORTED) 32 | add_dependencies(luajit luajit-bin) 33 | set_property(TARGET luajit PROPERTY IMPORTED_LOCATION ${LUAJIT_SOURCE_DIR}/libluajit.a) 34 | ### 35 | 36 | function(generate_ffi source target prefix defines) 37 | add_custom_command( 38 | OUTPUT ${target} 39 | COMMAND ${LUAJIT_SOURCE_DIR}/luajit${EXE_SUFFIX} generate_ffi.lua ${source} ${target} ${prefix} ${defines} 40 | DEPENDS ${source} 41 | DEPENDS luajit 42 | DEPENDS ${YUEMA_SOURCE_DIR}/tools/generate_ffi.lua 43 | WORKING_DIRECTORY ${YUEMA_SOURCE_DIR}/tools 44 | ) 45 | endfunction() 46 | 47 | ### raylib 48 | set(RAYLIB_PROJECT_DIR ${PROJECT_SOURCE_DIR}/src/raylib) 49 | set(RAYLIB_SOURCE_DIR ${RAYLIB_PROJECT_DIR}/src) 50 | set(CUSTOMIZE_BUILD ON CACHE BOOL "Customize raylib build") 51 | set(SUPPORT_FILEFORMAT_JPG ON CACHE BOOL "Enable JPG support") 52 | #set(GRAPHICS GRAPHICS_API_OPENGL_43 CACHE STRING "OpenGL version") 53 | add_subdirectory(${RAYLIB_PROJECT_DIR}) 54 | generate_ffi(${RAYLIB_SOURCE_DIR}/raylib.h ${YUEMA_SOURCE_DIR}/raylib_ffi.h RAYLIB "") 55 | generate_ffi(${RAYLIB_SOURCE_DIR}/rlgl.h ${YUEMA_SOURCE_DIR}/rlgl_ffi.h RLGL "RL_MATRIX_TYPE RLGL_ENABLE_OPENGL_DEBUG_CONTEXT") 56 | ### 57 | 58 | ### raygui 59 | set(RAYGUI_PROJECT_DIR ${PROJECT_SOURCE_DIR}/src/raygui) 60 | set(RAYGUI_SOURCE_DIR ${RAYGUI_PROJECT_DIR}/src) 61 | generate_ffi(${RAYGUI_SOURCE_DIR}/raygui.h ${YUEMA_SOURCE_DIR}/raygui_ffi.h RAYGUI "") 62 | ### 63 | 64 | ### box2d 65 | set(BOX2D_PROJECT_DIR ${PROJECT_SOURCE_DIR}/src/box2d) 66 | set(BOX2D_SOURCE_DIR ${BOX2D_PROJECT_DIR}/src) 67 | set(BOX2D_INCLUDE_DIR ${BOX2D_PROJECT_DIR}/include/box2d) 68 | option(BOX2D_BUILD_UNIT_TESTS OFF) 69 | option(BOX2D_BUILD_TESTBED OFF) 70 | add_subdirectory(${BOX2D_PROJECT_DIR}) 71 | ### 72 | 73 | ### box2dc 74 | set(BOX2DC_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src/box2dc) 75 | add_library(box2dc OBJECT 76 | ${BOX2DC_SOURCE_DIR}/box2dc.cpp 77 | ${BOX2DC_SOURCE_DIR}/world.cpp 78 | ${BOX2DC_SOURCE_DIR}/shapes.cpp 79 | ${BOX2DC_SOURCE_DIR}/joints.cpp 80 | ${BOX2DC_SOURCE_DIR}/contact.cpp 81 | ) 82 | add_dependencies(box2dc box2d) 83 | target_include_directories(box2dc PRIVATE ${BOX2D_INCLUDE_DIR} ${RAYLIB_SOURCE_DIR}) 84 | generate_ffi(${BOX2DC_SOURCE_DIR}/box2dc.h ${YUEMA_SOURCE_DIR}/box2dc_ffi.h BOX2DC "") 85 | ### 86 | 87 | ### Yuescript 88 | set(YUE_SOURCE_DIR src/Yuescript/src) 89 | 90 | add_library(yue STATIC 91 | ${YUE_SOURCE_DIR}/yuescript/ast.cpp 92 | ${YUE_SOURCE_DIR}/yuescript/parser.cpp 93 | ${YUE_SOURCE_DIR}/yuescript/yue_parser.cpp 94 | ${YUE_SOURCE_DIR}/yuescript/yue_compiler.cpp 95 | ${YUE_SOURCE_DIR}/yuescript/yuescript.cpp 96 | ) 97 | add_dependencies(yue luajit) 98 | target_include_directories(yue PRIVATE ${YUE_SOURCE_DIR} ${LUAJIT_SOURCE_DIR}) 99 | ### 100 | 101 | add_executable(yuema 102 | ${PROJECT_SOURCE_DIR}/src/luautf8/lutf8lib.c 103 | ${YUEMA_SOURCE_DIR}/raylib_ffi.h 104 | ${YUEMA_SOURCE_DIR}/raygui_ffi.h 105 | ${YUEMA_SOURCE_DIR}/box2dc_ffi.h 106 | ${YUEMA_SOURCE_DIR}/rlgl_ffi.h 107 | ${YUEMA_SOURCE_DIR}/LuaVM.cpp 108 | ${YUEMA_SOURCE_DIR}/main.cpp 109 | $ 110 | ) 111 | 112 | target_include_directories(yuema PRIVATE ${RAYLIB_SOURCE_DIR} ${RAYGUI_SOURCE_DIR} ${LUAJIT_SOURCE_DIR} ${BOX2D_INCLUDE_DIR} ${BOX2DC_SOURCE_DIR}) 113 | set_target_properties(yuema PROPERTIES LINK_FLAGS_RELEASE -s) 114 | target_link_libraries(yuema ${LINKER_OPTS} -lpthread raylib luajit box2d yue) 115 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 megagrump 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean debug release 2 | 3 | .ONESHELL: 4 | 5 | default: release 6 | 7 | build/Makefile: 8 | cmake -S . -B build -DCMAKE_BUILD_TYPE=${BUILDMODE} 9 | 10 | clean: 11 | rm -rf build 12 | cd src/LuaJIT && make clean 13 | 14 | debug: BUILDMODE:=Debug 15 | debug: build/Makefile 16 | cmake --build build -j 17 | 18 | release: BUILDMODE:=Release 19 | release: build/Makefile 20 | cmake --build build -j 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yuema 2 | 3 | Yuema is a Lua-based programming framework combining [raylib](https://github.com/raysan5/raylib) (and some of its accompanying libraries), [Box2D](https://github.com/erincatto/box2d), [LuaJIT](https://github.com/LuaJIT/LuaJIT) and [Yuescript](https://github.com/pigpigyyy/Yuescript) into a stand-alone executable with minimal external dependencies. 4 | 5 | You can use it to write 2D and 3D games in [Lua](https://www.lua.org/) or [Yuescript](http://yuescript.org), a [MoonScript](https://moonscript.org/) derivative that compiles to Lua. Yuescript integration is seamless with no extra compilation step required. 6 | 7 | ![yuema1](https://user-images.githubusercontent.com/31128870/152654645-fc42539f-b09d-4257-a525-11d3f9058327.png) 8 | 9 | ![yuema2](https://user-images.githubusercontent.com/31128870/152654647-da90a5d0-3904-466e-b0c0-e11e906c9c14.png) 10 | 11 | ![yuema3](https://user-images.githubusercontent.com/31128870/152654649-9f07a8c1-67a5-494c-8514-f79bb51ff2be.png) 12 | 13 | ![yuema_box2d](https://user-images.githubusercontent.com/31128870/153551507-26d94ece-6d52-4757-abeb-7d2d6fcc4ebb.png) 14 | 15 | ## Work in progress! 16 | 17 | The API is not stable and will change frequently. 18 | 19 | ## How to build 20 | 21 | Make sure you clone with submodules: 22 | 23 | git clone --recurse-submodules git@github.com:megagrump/yuema.git 24 | 25 | ### Linux 26 | 27 | #### 1. Install dependencies 28 | 29 | Debian based (Ubuntu, etc.) 30 | 31 | sudo apt install libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev 32 | 33 | RedHat based (Fedora, etc.) 34 | 35 | sudo dnf install alsa-lib-devel mesa-libGL-devel libX11-devel libXrandr-devel libXi-devel libXcursor-devel libXinerama-devel 36 | 37 | CMake is required also. 38 | 39 | #### 2. Build 40 | 41 | ``` 42 | mkdir build 43 | cd build 44 | cmake .. 45 | make 46 | ``` 47 | 48 | ### Windows 49 | 50 | The [MSYS](https://www.msys2.org/) MinGW compiler suite is used to create binaries for Windows. Additionally, `mingw-w64-x86_64-cmake` is required to build the project. 51 | The `/mingw64/bin` directory is expected to be in your `$PATH`. 52 | 53 | ``` 54 | mkdir build 55 | cd build 56 | cmake -G "MSYS Makefiles" .. 57 | make 58 | ``` 59 | 60 | ### Other platforms/compilers 61 | 62 | No one has tried yet. 63 | 64 | ## Examples 65 | 66 | Some examples can be found in the `examples` directory. 67 | 68 | ``` 69 | ./build/yuema examples/gui_controls.yue 70 | ./build/yuema examples/core_3d_camera_first_person.yue 71 | ./build/yuema examples/models_mesh_picking.yue 72 | ./build/yuema examples/box2d_joints.yue 73 | ``` 74 | 75 | You **must** run the examples from the project root. 76 | 77 | # How to make your own game with yuema 78 | 79 | You currently have to manually bootstrap new projects, but it's simple: 80 | 81 | 1. Build yuema or download a binary release. 82 | 2. Create a new directory for your project, for example `/home/alice/myproject` or `C:\projects\myproject`. 83 | 3. Copy the yuema executable (`yuema` or `yuema.exe` on Windows) to the project directory and rename it, for example `myproject` (or `myproject.exe`). 84 | 4. Copy the `lib` directory to the project directory. 85 | 5. Create a `main.lua` or `main.yue` file in the project directory. This is your project's entry point. 86 | ``` 87 | myproject <-- project directory 88 | /lib <-- library code 89 | main.yue <-- code entry point 90 | myproject(.exe) <-- executable 91 | ``` 92 | You can run your project by starting `myproject` from the project directory. 93 | 94 | ## Code and libraries used in this project 95 | 96 | * raylib: https://github.com/raysan5/raylib Copyright (c) 2013-2022 Ramon Santamaria 97 | * raygui: https://github.com/raysan5/raygui Copyright (c) 2014-2022 Ramon Santamaria 98 | * Box2D: https://github.com/erincatto/box2d Copyright (c) 2019 Erin Catto 99 | * LuaJIT: https://github.com/LuaJIT/LuaJIT Copyright (C) 2005-2022 Mike Pall 100 | * Yuescript: https://github.com/pigpigyyy/Yuescript Copyright (c) 2021 Li Jin 101 | * luautf8: https://github.com/starwing/luautf8 Copyright (c) 2018 Xavier Wang 102 | * CParser: https://github.com/facebookresearch/CParser Copyright (c) Facebook, Inc. and its affiliates. 103 | -------------------------------------------------------------------------------- /examples/box2d_joints.yue: -------------------------------------------------------------------------------- 1 | import 'lib.ray' as { 2 | :window 3 | :draw 4 | :util 5 | :time 6 | :input 7 | :Color 8 | } 9 | import 'lib.box2d' 10 | 11 | world = box2d.World(0, 300) 12 | text = {} 13 | 14 | do -- revolute 15 | x, y = 10, 20 16 | text.revolute = { x + 80, y + 5 } 17 | walls = with world::createBody(x, y, 'static') 18 | ::createFixture(box2d.ChainShape({ 0, 0, 0, 320, 200, 320, 200, 0 })) 19 | 20 | spinner = with world::createBody(x + 100, y + 210) 21 | ::createFixture(box2d.PolygonShape.createBox(180, 10)) 22 | 23 | BALLCOLORS = { Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW } 24 | 25 | for i = 0, 20 26 | bx = i % 7 + 1 27 | by = 30 + (i / 7) * 26 28 | with world::createBody(x + bx * 26, y + by) 29 | ::createFixture(box2d.CircleShape(12), .1) 30 | ::setRestitution(.5) 31 | ::setUserData(BALLCOLORS[math.random(#BALLCOLORS)]) 32 | 33 | with box2d.RevoluteJoint(walls, spinner, spinner::getPosition!) 34 | ::setMotorSpeed(3) 35 | ::setMaxMotorTorque(100000) 36 | ::enableMotor(true) 37 | 38 | do -- distance joint 39 | x, y = 220, 20 40 | text.distance = { x + 30, y + 5 } 41 | 42 | world::createBody(x, y, 'static')::createFixture(box2d.ChainShape({ 0, 0, 0, 100, 100, 100, 100, 0 })) 43 | 44 | ball1 = with world::createBody(x + 20, y + 20) 45 | ::createFixture(box2d.CircleShape(10), .1) 46 | ::setRestitution(.5) 47 | 48 | ball2 = with world::createBody(x + 50, y + 20) 49 | ::createFixture(box2d.CircleShape(10)) 50 | ::setRestitution(1) 51 | 52 | x1, y1 = ball1::getPosition! 53 | x2, y2 = ball2::getPosition! 54 | joint = with box2d.DistanceJoint(ball1, ball2, x1, y1, x2, y2, true) 55 | ::setStiffness(1000) 56 | 57 | prismatic = nil 58 | do -- prismatic joint 59 | x, y = 330, 20 60 | text.prismatic = { x + 28, y + 5 } 61 | 62 | world::createBody(x, y, 'static')::createFixture(box2d.ChainShape({ 0, 0, 0, 100, 100, 100, 100, 0 })) 63 | 64 | ball1 = with world::createBody(x + 20, y + 20) 65 | ::createFixture(box2d.CircleShape(10)) 66 | ::setRestitution(.5) 67 | ::setUserData(Color.BLUE) 68 | 69 | ball2 = with world::createBody(x + 20, y + 20) 70 | ::createFixture(box2d.CircleShape(10)) 71 | ::setUserData(Color.YELLOW) 72 | 73 | prismatic = with box2d.PrismaticJoint(ball1, ball2, x + 20, y + 20, 1, 0) 74 | ::setLimits(20, 70) 75 | ::enableLimit(true) 76 | ::setMaxMotorForce(10) 77 | ::enableMotor(true) 78 | 79 | pulley = nil 80 | do -- pulley joint 81 | x, y = 440, 20 82 | text.pulley = { x + 35, y + 5 } 83 | world::createBody(x, y, 'static')::createFixture(box2d.ChainShape({ 0, 0, 0, 100, 100, 100, 100, 0 })) 84 | 85 | bodyA = with world::createBody(x + 20, y + 50) 86 | ::createFixture(box2d.PolygonShape.createBox(20, 20)) 87 | ::setSleepingAllowed(false) 88 | 89 | bodyB = with world::createBody(x + 80, y + 50) 90 | ::createFixture(box2d.PolygonShape.createBox(20, 20)) 91 | ::setSleepingAllowed(false) 92 | 93 | ox1, oy1 = bodyA::getPosition! 94 | ox2, oy2 = bodyB::getPosition! 95 | pulley = box2d.PulleyJoint(bodyA, bodyB, x + 20, y - 10, x + 80, y - 10, ox1, oy1, ox2, oy2) 96 | 97 | mouseJoint = nil 98 | do -- mouse joint 99 | x, y = 220, 130 100 | text.mouse = { x + 35, y + 5 } 101 | 102 | world::createBody(x, y, 'static')::createFixture(box2d.ChainShape({ 0, 0, 0, 100, 100, 100, 100, 0 })) 103 | 104 | bodyA = with world::createBody(x + 20, y + 50) 105 | ::createFixture(box2d.PolygonShape.createBox(20, 20)) 106 | ::setRestitution(.7) 107 | 108 | bodyB = with world::createBody(x + 80, y + 50) 109 | ::createFixture(box2d.PolygonShape.createBox(20, 20)) 110 | ::setSleepingAllowed(false) 111 | 112 | mouseJoint = with box2d.MouseJoint(bodyB, bodyB::getPosition!) 113 | ::setStiffness(1000) 114 | ::setMaxForce(1000) 115 | 116 | do -- gear joint 117 | x, y = 330, 130 118 | text.gear = { x + 40, y + 5 } 119 | 120 | world::createBody(x, y, 'static')::createFixture(box2d.ChainShape({ 0, 0, 0, 100, 100, 100, 100, 0 })) 121 | 122 | bodyA = with world::createBody(x + 20, y + 50) 123 | ::createFixture(box2d.CircleShape(20)) 124 | 125 | joint1 = with box2d.RevoluteJoint(world::getGroundBody!, bodyA, bodyA::getPosition!) 126 | ::setMotorSpeed(3) 127 | ::setMaxMotorTorque(100) 128 | ::enableMotor(true) 129 | 130 | bodyB = with world::createBody(x + 70, y + 50) 131 | ::createFixture(box2d.CircleShape(30)) 132 | 133 | joint2 = box2d.RevoluteJoint(world::getGroundBody!, bodyB, bodyB::getPosition!) 134 | 135 | box2d.GearJoint(joint1, joint2, 30 / 20) 136 | 137 | wheel = do -- wheel joint 138 | x, y = 440, 130 139 | text.wheel = { x + 35, y + 5 } 140 | 141 | world::createBody(x, y, 'static')::createFixture(box2d.ChainShape({ 0, 0, 0, 100, 100, 100, 100, 0 })) 142 | 143 | box = with world::createBody(x + 50, y + 50, 'static') 144 | ::createFixture(box2d.PolygonShape.createBox(10, 50)) 145 | 146 | wheel = with world::createBody(x + 50, y + 50) 147 | ::createFixture(box2d.CircleShape(20)) 148 | 149 | with box2d.WheelJoint(box, wheel, x + 50, y + 50, 0, 1) 150 | ::setStiffness(10) 151 | ::setLimits(-20, 20) 152 | ::enableLimit(true) 153 | ::setMotorSpeed(3) 154 | ::setMaxMotorTorque(1000) 155 | ::enableMotor(true) 156 | 157 | wheel 158 | 159 | weld = do -- weld joint 160 | x, y = 220, 240 161 | text.weld = { x + 40, y + 5 } 162 | 163 | world::createBody(x, y, 'static')::createFixture(box2d.ChainShape({ 0, 0, 0, 100, 100, 100, 100, 0 })) 164 | 165 | bodyA = with world::createBody(x + 20, y + 20) 166 | ::createFixture(box2d.CircleShape(10)) 167 | ::setRestitution(.5) 168 | ::setUserData(Color.RED) 169 | 170 | bodyB = with world::createBody(x + 50, y + 20) 171 | ::createFixture(box2d.CircleShape(20)) 172 | ::setRestitution(.5) 173 | ::setUserData(Color.GREEN) 174 | 175 | box2d.WeldJoint(bodyA, bodyB, bodyB::getPosition!) 176 | bodyB 177 | 178 | motor = do -- motor joint 179 | x, y = 330, 240 180 | text.motor = { x + 35, y + 5 } 181 | 182 | world::createBody(x, y, 'static')::createFixture(box2d.ChainShape({ 0, 0, 0, 100, 100, 100, 100, 0 })) 183 | 184 | bodyA = with world::createBody(x + 50, y + 50, 'static') 185 | ::createFixture(box2d.CircleShape(5)) 186 | 187 | bodyB = with world::createBody(x + 50, y + 50) 188 | ::createFixture(box2d.PolygonShape.createBox(85, 10)) 189 | 190 | box2d.MotorJoint(bodyA, bodyB) 191 | ::setMaxForce(200) 192 | bodyB 193 | 194 | drawFixture = do 195 | vertices = {} 196 | (body, fixture, color) -> 197 | shape = fixture::getShape! 198 | switch shape::getType! 199 | when 'circle' 200 | x, y = body::getWorldPoint(shape::getPosition!) 201 | draw.circle(x, y, shape::getRadius!, body::getUserData! or Color.GRAY) 202 | vx, vy = body::getWorldVector(1, 0) 203 | r = shape::getRadius! 204 | draw.line(x, y, x + vx * r, y + vy * r, Color.BLACK) 205 | 206 | when 'polygon' 207 | verts = body::getWorldPoints(shape::getVertices(vertices)) 208 | count = shape::getVertexCount! * 2 209 | for i = 1, count, 2 210 | n = (i + 1) % count + 1 211 | x1, y1 = verts[i], verts[i + 1] 212 | x2, y2 = verts[n], verts[n + 1] 213 | draw.line(x1, y1, x2, y2, color) 214 | 215 | when 'edge' 216 | verts = body::getWorldPoints(shape::getVertices(vertices)) 217 | x1, y1 = verts[1], verts[2] 218 | x2, y2 = verts[3], verts[4] 219 | draw.line(x1, y1, x2, y2, color) 220 | 221 | when 'chain' 222 | verts = body::getWorldPoints(shape::getVertices(vertices)) 223 | x1, y1 = body::getWorldPoint(shape::getPrevVertex!) 224 | x2, y2 = verts[1], verts[2] 225 | draw.line(x1, y1, x2, y2, color) 226 | 227 | n = shape::getVertexCount! * 2 228 | for i = 1, n - 2, 2 229 | x1, y1, x2, y2 = verts[i], verts[i + 1], verts[i + 2], verts[i + 3] 230 | draw.line(x1, y1, x2, y2, color) 231 | 232 | x1, y1 = verts[n - 1], verts[n] 233 | x2, y2 = body::getWorldPoint(shape::getNextVertex!) 234 | draw.line(x1, y1, x2, y2, color) 235 | 236 | drawJoint = (joint, colorA, colorB) -> 237 | x1, y1 = joint::getAnchorA! 238 | x2, y2 = joint::getAnchorB! 239 | draw.circle(x1, y1, 2, colorA) 240 | draw.circle(x2, y2, 2, colorB) 241 | 242 | switch joint::getType! 243 | when 'pulley' 244 | gx1, gy1 = joint::getGroundAnchorA! 245 | gx2, gy2 = joint::getGroundAnchorB! 246 | draw.line(gx1, gy1, x1, y1, colorA) 247 | draw.line(gx2, gy2, x2, y2, colorB) 248 | when 'gear' 249 | nil 250 | else 251 | draw.line(x1, y1, x2, y2, colorA) 252 | 253 | drawWorld = -> 254 | body = world::getBodyList! 255 | while body 256 | fixture = body::getFixtureList! 257 | while fixture 258 | drawFixture(body, fixture, Color.BLACK) 259 | fixture = fixture::getNext! 260 | body = body::getNext! 261 | 262 | joint = world::getJointList! 263 | while joint 264 | drawJoint(joint, Color.RED, Color.GREEN) 265 | joint = joint::getNext! 266 | 267 | accum = 1 / 60 268 | stepWorld = -> 269 | dt = math.min(1 / 30, time.getFrameTime!) 270 | accum += dt 271 | while accum >= 1 / 60 272 | world::step(1 / 60) 273 | accum -= 1 / 60 274 | 275 | window.init(550, 360, "Yuema example: Box2D joints") 276 | time.setTargetFPS(60) 277 | 278 | while not window.shouldClose! 279 | stepWorld! 280 | do 281 | prismatic::setMotorSpeed(math.sin(time.getTime! * 4) * 20) 282 | pullDensity = .5 + math.floor(time.getTime!) % 2 283 | with pulley::getBodyA! 284 | ::getFixtureList!::setDensity(pullDensity) 285 | ::resetMassData! 286 | with pulley::getBodyB! 287 | ::getFixtureList!::setDensity(2 - pullDensity) 288 | ::resetMassData! 289 | 290 | wheel::applyForceToCenter(0, -150) if (time.getTime! % 1) > .5 291 | motor::applyLinearImpulseToCenter(0, -70) unless motor::isAwake! 292 | weld::applyLinearImpulseToCenter(0, -50) unless weld::isAwake! 293 | 294 | mx, my = input.mouse.getX!, input.mouse.getY! 295 | if mx >= 220 and my >= 130 and mx < 320 and my < 230 296 | mouseJoint::setTarget(mx, my) 297 | 298 | with draw 299 | .beginDrawing! 300 | .clearBackground(Color.RAYWHITE) 301 | .fps(455, 280) 302 | drawWorld! 303 | .text(k, v[1], v[2], 10, Color.BLACK) for k, v in pairs(text) 304 | .endDrawing! 305 | 306 | world::destroy! 307 | window.close! 308 | -------------------------------------------------------------------------------- /examples/core_3d_camera_first_person.yue: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------------------- 2 | -- 3 | -- raylib [core] example - 3d camera first person 4 | -- 5 | -- raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) 6 | -- 7 | -- Copyright (c) 2015 Ramon Santamaria (@raysan5) 8 | -- 9 | -- Adapted for Yuema by megagrump@pm.me 10 | -- 11 | ---------------------------------------------------------------------------------------------/ 12 | import 'lib.ray' as { 13 | :window 14 | :draw 15 | :util 16 | :time 17 | :Camera3D 18 | :Color 19 | } 20 | 21 | import 'lib.math' 22 | import getRandomValue from util 23 | import Vector2, Vector3 from math 24 | 25 | MAX_COLUMNS = 20 26 | 27 | window.init(800, 450, "raylib [core] example - 3d camera first person") 28 | time.setTargetFPS(60) 29 | 30 | camera = with Camera3D! 31 | .position = Vector3(4, 2, 4) 32 | .target = Vector3(0, 1.8, 0) 33 | .up = Vector3(0, 1, 0) 34 | .fovy = 60 35 | .projection = Camera3D.PERSPECTIVE 36 | ::setMode(Camera3D.FIRST_PERSON) 37 | 38 | heights, positions, colors = {}, {}, {} 39 | 40 | for i = 1, MAX_COLUMNS 41 | heights[i] = getRandomValue(1, 12) 42 | positions[i] = Vector3(getRandomValue(-15, 15), heights[i]/2, getRandomValue(-15, 15)) 43 | colors[i] = Color(getRandomValue(20, 255), getRandomValue(10, 55), 30, 255) 44 | 45 | while not window.shouldClose! 46 | camera::update! 47 | 48 | with draw 49 | .beginDrawing! 50 | .clearBackground(Color.RAYWHITE) 51 | 52 | .beginMode3D(camera) 53 | 54 | .plane(Vector3(0, 0, 0), Vector2(32, 32), Color.LIGHTGRAY) 55 | .cube(Vector3(-16, 2.5, 0), 1, 5, 32, Color.BLUE) 56 | .cube(Vector3(16, 2.5, 0), 1, 5, 32, Color.LIME) 57 | .cube(Vector3(0, 2.5, 16), 32, 5, 1, Color.GOLD) 58 | 59 | for i = 1, MAX_COLUMNS 60 | draw.cube(positions[i], 2, heights[i], 2, colors[i]) 61 | draw.cubeWires(positions[i], 2, heights[i], 2, Color.MAROON) 62 | 63 | .endMode3D! 64 | 65 | .rectangle(10, 10, 220, 70, Color.fade(Color.SKYBLUE, 0.5)) 66 | .rectangleLines(10, 10, 220, 70, Color.BLUE) 67 | 68 | .text("First person camera default controls:", 20, 20, 10, Color.BLACK) 69 | .text("- Move with keys: W, A, S, D", 40, 40, 10, Color.DARKGRAY) 70 | .text("- Mouse move to look around", 40, 60, 10, Color.DARKGRAY) 71 | 72 | .endDrawing! 73 | 74 | window.close! 75 | -------------------------------------------------------------------------------- /examples/gui_controls.yue: -------------------------------------------------------------------------------- 1 | --******************************************************************************************* 2 | -- 3 | -- raygui - controls test suite 4 | -- 5 | -- TEST CONTROLS: 6 | -- - GuiDropdownBox() 7 | -- - GuiCheckBox() 8 | -- - GuiSpinner() 9 | -- - GuiValueBox() 10 | -- - GuiTextBox() 11 | -- - GuiButton() 12 | -- - GuiComboBox() 13 | -- - GuiListView() 14 | -- - GuiToggleGroup() 15 | -- - GuiTextBoxMulti() 16 | -- - GuiColorPicker() 17 | -- - GuiSlider() 18 | -- - GuiSliderBar() 19 | -- - GuiProgressBar() 20 | -- - GuiColorBarAlpha() 21 | -- - GuiScrollPanel() 22 | -- 23 | -- LICENSE: zlib/libpng 24 | -- 25 | -- Copyright (c) 2016-2022 Ramon Santamaria (@raysan5) 26 | -- 27 | -- Adapted for yuema by megagrump@pm.me 28 | -- 29 | --*********************************************************************************************/ 30 | import 'lib.ray' as { 31 | :window 32 | :draw 33 | :input 34 | :time 35 | :filesystem 36 | :gui 37 | :Color 38 | :Rectangle 39 | } 40 | 41 | import 'lib.math.Vector2' 42 | import keyboard from input 43 | 44 | screenWidth = 690 45 | screenHeight = 560 46 | 47 | window.init(screenWidth, screenHeight, "raygui - controls test suite") 48 | keyboard.setExitKey(0) 49 | 50 | dropdownBox000Active = { 0 } 51 | dropDown000EditMode = false 52 | 53 | dropdownBox001Active = { 0 } 54 | dropDown001EditMode = false 55 | 56 | spinner001Value = { 0 } 57 | spinnerEditMode = false 58 | 59 | valueBox002Value = { 0 } 60 | valueBoxEditMode = false 61 | 62 | textBoxText = { "Text box" } 63 | textBoxEditMode = false 64 | 65 | listViewScrollIndex = { 0 } 66 | listViewActive = -1 67 | 68 | listViewExScrollIndex = { 0 } 69 | listViewExActive = 2 70 | listViewExFocus = { -1 } 71 | 72 | listViewExList = { "This", "is", "a", "list view", "with", "disable", "elements", "amazing!" } 73 | 74 | multiTextBoxText = { "Multi text box" } 75 | multiTextBoxEditMode = false 76 | colorPickerValue = Color.RED 77 | 78 | sliderValue = 50 79 | sliderBarValue = 60 80 | progressValue = 0.4 81 | 82 | forceSquaredChecked = false 83 | 84 | alphaValue = 0.5 85 | 86 | comboBoxActive = 1 87 | 88 | toggleGroupActive = 0 89 | 90 | viewScroll = Vector2! 91 | 92 | -- Custom GUI font loading 93 | -- Font font = LoadFontEx("fonts/rainyhearts16.ttf", 12, 0, 0) 94 | -- GuiSetFont(font) 95 | 96 | exitWindow = false 97 | showMessageBox = false 98 | 99 | textInput = { "" } 100 | showTextInputBox = false 101 | 102 | textInputFileName = "" 103 | 104 | time.setTargetFPS(60) 105 | 106 | while not exitWindow 107 | exitWindow = window.shouldClose! 108 | 109 | if keyboard.isPressed(keyboard.ESCAPE) 110 | showMessageBox = not showMessageBox 111 | 112 | if keyboard.isDown(keyboard.LEFT_CONTROL) and keyboard.isPressed(keyboard.S) 113 | showTextInputBox = true 114 | 115 | if (filesystem.isFileDropped!) 116 | droppedFiles = filesystem.getDroppedFiles! 117 | if #droppedFiles > 0 and filesystem.isExtension(droppedFiles[1], ".rgs") 118 | gui.loadStyle(droppedFiles[1]) 119 | 120 | with draw 121 | .beginDrawing! 122 | 123 | .clearBackground(Color.fromInt(gui.getStyle(gui.DEFAULT, gui.BACKGROUND_COLOR))) 124 | 125 | if dropDown000EditMode or dropDown001EditMode 126 | gui.lock! 127 | elseif not dropDown000EditMode and not dropDown001EditMode 128 | gui.unlock! 129 | 130 | forceSquaredChecked = gui.checkBox(Rectangle(25, 108, 15, 15), "FORCE CHECK!", forceSquaredChecked) 131 | 132 | gui.setStyle(gui.TEXTBOX, gui.TEXT_ALIGNMENT, gui.TEXT_ALIGN_CENTER) 133 | if gui.spinner(Rectangle(25, 135, 125, 30), nil, spinner001Value, 0, 100, spinnerEditMode) 134 | spinnerEditMode = not spinnerEditMode 135 | 136 | if gui.valueBox(Rectangle(25, 175, 125, 30), nil, valueBox002Value, 0, 100, valueBoxEditMode) 137 | valueBoxEditMode = not valueBoxEditMode 138 | 139 | gui.setStyle(gui.TEXTBOX, gui.TEXT_ALIGNMENT, gui.TEXT_ALIGN_LEFT) 140 | if gui.textBox(Rectangle(25, 215, 125, 30), textBoxText, 64, textBoxEditMode) 141 | textBoxEditMode = not textBoxEditMode 142 | 143 | gui.setStyle(gui.BUTTON, gui.TEXT_ALIGNMENT, gui.TEXT_ALIGN_CENTER) 144 | 145 | if gui.button(Rectangle(25, 255, 125, 30), gui.iconText(gui.ICON_FILE_SAVE, "Save File")) 146 | showTextInputBox = true 147 | 148 | gui.groupBox(Rectangle(25, 310, 125, 150), "STATES") 149 | gui.setState(gui.STATE_NORMAL) 150 | gui.button(Rectangle(30, 320, 115, 30), "NORMAL") 151 | gui.setState(gui.STATE_FOCUSED) 152 | gui.button(Rectangle(30, 355, 115, 30), "FOCUSED") 153 | gui.setState(gui.STATE_PRESSED) 154 | gui.button(Rectangle(30, 390, 115, 30), "#15#PRESSED") 155 | gui.setState(gui.STATE_DISABLED) 156 | gui.button(Rectangle(30, 425, 115, 30), "DISABLED") 157 | gui.setState(gui.STATE_NORMAL) 158 | 159 | comboBoxActive = gui.comboBox(Rectangle(25, 470, 125, 30), "ONE;TWO;THREE;FOUR", comboBoxActive) 160 | 161 | gui.setStyle(gui.DROPDOWNBOX, gui.TEXT_ALIGNMENT, gui.TEXT_ALIGN_LEFT) 162 | if gui.dropdownBox(Rectangle(25, 65, 125, 30), "#01#ONE;#02#TWO;#03#THREE;#04#FOUR", dropdownBox001Active, dropDown001EditMode) 163 | dropDown001EditMode = not dropDown001EditMode 164 | 165 | gui.setStyle(gui.DROPDOWNBOX, gui.TEXT_ALIGNMENT, gui.TEXT_ALIGN_CENTER) 166 | if gui.dropdownBox(Rectangle(25, 25, 125, 30), "ONE;TWO;THREE", dropdownBox000Active, dropDown000EditMode) 167 | dropDown000EditMode = not dropDown000EditMode 168 | 169 | listViewActive = gui.listView(Rectangle(165, 25, 140, 140), "Charmander;Bulbasaur;#18#Squirtel;Pikachu;Eevee;Pidgey", listViewScrollIndex, listViewActive) 170 | listViewExActive = gui.listViewEx(Rectangle(165, 180, 140, 200), listViewExList, 8, listViewExFocus, listViewExScrollIndex, listViewExActive) 171 | 172 | toggleGroupActive = gui.toggleGroup(Rectangle(165, 400, 140, 25), "#1#ONE\n#3#TWO\n#8#THREE\n#23#", toggleGroupActive) 173 | 174 | if gui.textBoxMulti(Rectangle(320, 25, 225, 140), multiTextBoxText, 256, multiTextBoxEditMode) 175 | multiTextBoxEditMode = not multiTextBoxEditMode 176 | 177 | colorPickerValue = gui.colorPicker(Rectangle(320, 185, 196, 192), nil, colorPickerValue) 178 | 179 | sliderValue = gui.slider(Rectangle(355, 400, 165, 20), "TEST", ("%2.2f")::format(sliderValue), sliderValue, -50, 100) 180 | sliderBarValue = gui.sliderBar(Rectangle(320, 430, 200, 20), nil, ("%i")::format(sliderBarValue), sliderBarValue, 0, 100) 181 | progressValue = gui.progressBar(Rectangle(320, 460, 200, 20), nil, nil, progressValue, 0, 1) 182 | 183 | view = gui.scrollPanel(Rectangle(560, 25, 100, 160), "", Rectangle(560, 25, 200, 400), viewScroll) 184 | 185 | gui.statusBar(Rectangle(0, window.getHeight! - 20, window.getWidth!, 20), "This is a status bar") 186 | 187 | alphaValue = gui.colorBarAlpha(Rectangle(320, 490, 200, 30), nil, alphaValue) 188 | 189 | if showMessageBox 190 | .rectangle(0, 0, window.getWidth!, window.getHeight!, Color.fade(Color.RAYWHITE, 0.8)) 191 | result = gui.messageBox(Rectangle(window.getWidth!/2 - 125, window.getHeight!/2 - 50, 250, 100), gui.iconText(gui.ICON_EXIT, "Close Window"), "Do you really want to exit?", "Yes;No") 192 | 193 | if result == 0 or result == 2 194 | showMessageBox = false 195 | elseif result == 1 196 | exitWindow = true 197 | 198 | if showTextInputBox 199 | .rectangle(0, 0, window.getWidth!, window.getHeight!, Color.fade(Color.RAYWHITE, 0.8)) 200 | result = gui.textInputBox(Rectangle(window.getWidth!/2 - 120, window.getHeight!/2 - 60, 240, 140), gui.iconText(gui.ICON_FILE_SAVE, "Save file as..."), "Introduce a save file name", "Ok;Cancel", textInput) 201 | 202 | if result == 1 203 | textInputFileName = textInput[1] 204 | 205 | if result == 0 or result == 1 or result == 2 206 | showTextInputBox = false 207 | textInput[1] = "" 208 | .endDrawing! 209 | 210 | window.close! 211 | -------------------------------------------------------------------------------- /examples/models_mesh_picking.yue: -------------------------------------------------------------------------------- 1 | --******************************************************************************************* 2 | -- 3 | -- raylib [models] example - Mesh picking in 3d mode, ground plane, triangle, mesh 4 | -- 5 | -- This example has been created using raylib 1.7 (www.raylib.com) 6 | -- raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) 7 | -- 8 | -- Example contributed by Joel Davis (@joeld42) and reviewed by Ramon Santamaria (@raysan5) 9 | -- 10 | -- Copyright (c) 2017 Joel Davis (@joeld42) and Ramon Santamaria (@raysan5) 11 | -- 12 | -- Adapted for Yuema by megagrump@pm.me 13 | -- 14 | --******************************************************************************************* 15 | import 'lib.ray' as { 16 | :window 17 | :time 18 | :input 19 | :draw 20 | :collision 21 | :Color 22 | :Camera3D 23 | :Model 24 | :Texture2D 25 | :Material 26 | } 27 | 28 | import 'lib.math.Vector3' 29 | import mouse from input 30 | import RayCollision from collision 31 | 32 | window.init(800, 450, "raylib [models] example - mesh picking") 33 | 34 | camera = with Camera3D! 35 | .position = Vector3(20, 20, 20) 36 | .target = Vector3(0, 8, 0) 37 | .up = Vector3(0, 1.6, 0) 38 | .fovy = 45 39 | .projection = Camera3D.PERSPECTIVE 40 | 41 | tower = Model.load("examples/resources/models/obj/turret.obj") 42 | texture = Texture2D.load("examples/resources/models/obj/turret_diffuse.png") 43 | tower.materials[0].maps[Material.MAP_DIFFUSE].texture = texture 44 | 45 | towerPos = Vector3! 46 | towerBBox = tower.meshes[0]::getBoundingBox! 47 | 48 | g0 = Vector3(-50, 0, -50) 49 | g1 = Vector3(-50, 0, 50) 50 | g2 = Vector3(-50, 0, 50) 51 | g3 = Vector3(-50, 0, -50) 52 | 53 | ta = Vector3(-25, 0.5, 0) 54 | tb = Vector3(-4, 2.5, 1) 55 | tc = Vector3(-8, 6.5, 0) 56 | 57 | bary = Vector3! 58 | 59 | sp = Vector3(-30, 5, 5) 60 | sr = 4 61 | 62 | camera::setMode(Camera3D.FREE) 63 | 64 | time.setTargetFPS(60) 65 | 66 | coll = RayCollision! 67 | 68 | while not window.shouldClose! 69 | camera::update! 70 | 71 | hitObjectName = "None" 72 | coll.distance = math.huge 73 | coll.hit = false 74 | cursorColor = Color.WHITE 75 | 76 | ray = camera::getMouseRay(mouse.getPosition!) 77 | groundHitInfo = collision.getRayQuad(ray, g0, g1, g2, g3) 78 | 79 | if groundHitInfo.hit and groundHitInfo.distance < coll.distance 80 | coll = groundHitInfo 81 | cursorColor = Color.GREEN 82 | hitObjectName = "Ground" 83 | 84 | triHitInfo = collision.getRayTriangle(ray, ta, tb, tc) 85 | 86 | if triHitInfo.hit and triHitInfo.distance < coll.distance 87 | coll = triHitInfo 88 | cursorColor = Color.PURPLE 89 | hitObjectName = "Triangle" 90 | 91 | bary = coll.point::barycenter(ta, tb, tc) 92 | 93 | sphereHitInfo = collision.getRaySphere(ray, sp, sr) 94 | 95 | if sphereHitInfo.hit and sphereHitInfo.distance < coll.distance 96 | coll = sphereHitInfo 97 | cursorColor = Color.ORANGE 98 | hitObjectName = "Sphere" 99 | 100 | boxHitInfo = collision.getRayBox(ray, towerBBox) 101 | 102 | if boxHitInfo.hit and boxHitInfo.distance < coll.distance 103 | coll = boxHitInfo 104 | cursorColor = Color.ORANGE 105 | hitObjectName = "Box" 106 | 107 | meshHitInfo = collision.getRayModel(ray, tower) 108 | 109 | if meshHitInfo.hit 110 | coll = meshHitInfo 111 | cursorColor = Color.ORANGE 112 | hitObjectName = "Mesh" 113 | 114 | with draw 115 | .beginDrawing! 116 | .clearBackground(Color.RAYWHITE) 117 | 118 | .beginMode3D(camera) 119 | .model(tower, towerPos, 1, Color.WHITE) 120 | 121 | .line3D(ta, tb, Color.PURPLE) 122 | .line3D(tb, tc, Color.PURPLE) 123 | .line3D(tc, ta, Color.PURPLE) 124 | 125 | .sphereWires(sp, sr, 8, 8, Color.PURPLE) 126 | 127 | if boxHitInfo.hit 128 | .boundingBox(towerBBox, Color.LIME) 129 | 130 | if coll.hit 131 | .cube(coll.point, 0.3, 0.3, 0.3, cursorColor) 132 | .cubeWires(coll.point, 0.3, 0.3, 0.3, Color.RED) 133 | 134 | normalEnd = coll.point::add(coll.normal) 135 | 136 | .line3D(coll.point, normalEnd, Color.RED) 137 | 138 | .ray(ray, Color.MAROON) 139 | 140 | .grid(10, 10) 141 | 142 | .endMode3D! 143 | 144 | .text("Hit Object: %s"::format(hitObjectName), 10, 50, 10, Color.BLACK) 145 | 146 | if coll.hit 147 | ypos = 70 148 | 149 | .text("Distance: %3.2f"::format(coll.distance), 10, ypos, 10, Color.BLACK) 150 | .text("Hit Pos: %3.2f %3.2f %3.2f"::format(coll.point.x, coll.point.y, coll.point.z), 151 | 10, ypos + 15, 10, Color.BLACK) 152 | 153 | .text("Hit Norm: %3.2f %3.2f %3.2f"::format(coll.normal.x, coll.normal.y, coll.normal.z), 154 | 10, ypos + 30, 10, Color.BLACK) 155 | 156 | if triHitInfo.hit and hitObjectName == "Triangle" 157 | .text("Barycenter: %3.2f %3.2f %3.2f"::format(bary.x, bary.y, bary.z), 10, ypos + 45, 10, Color.BLACK) 158 | 159 | .text("Use Mouse to Move Camera", 10, 430, 10, Color.GRAY) 160 | .text("(c) Turret 3D model by Alberto Cano", 600, 430, 10, Color.GRAY) 161 | .fps(10, 10) 162 | 163 | .endDrawing! 164 | 165 | window.close! 166 | -------------------------------------------------------------------------------- /examples/resources/LICENSE.md: -------------------------------------------------------------------------------- 1 | | resource | author | licence | notes | 2 | | :------------------- | :---------: | :------ | :---- | 3 | | models/obj/castle.obj,
models/castle_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - | 4 | | models/obj/bridge.obj,
models/bridge_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - | 5 | | models/obj/house.obj,
models/house_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - | 6 | | models/obj/market.obj,
models/market_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - | 7 | | models/obj/turret.obj,
models/turret_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - | 8 | | models/obj/well.obj,
models/well_diffuse.png | [Alberto Cano](https://www.artstation.com/albertocano) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode) | - | 9 | | models/obj/cube.obj,
models/cube_diffuse.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - | 10 | | models/obj/plane.gltf,
models/gltf/plane/plane.bin,
models/gltf/plane/plane_diffuse.png | [GiaHanLam](https://sketchfab.com/GiaHanLam) | [CC-BY](https://creativecommons.org/licenses/by/4.0/) | Used by: [`models_yaw_pitch_roll.c`](https://github.com/raysan5/raylib/blob/master/examples/models/models_yaw_pitch_roll.c) 11 | | models/iqm/guy.iqm,
models/iqm/guyanim.iqm,
models/iqm/guytex.png,
models/iqm/guy.blend | [@culacant](https://github.com/culacant) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - | 12 | | models/iqm/vertex_colored_object.iqm | ❔ | ❔ | - | 13 | | models/gltf/... | _various_ | Check [LICENSE](https://github.com/raysan5/raylib/blob/master/examples/models/resources/models/gltf/LICENSE) | - | 14 | | models/vox/chr_knight.vox | ❔ | ❔ | - | 15 | | models/vox/chr_sword.vox | ❔ | ❔ | - | 16 | | models/vox/monu9.vox | ❔ | ❔ | - | 17 | | billboard.png | [@emegeme](https://github.com/emegeme) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - | 18 | | cubicmap.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - | 19 | | cubicmap_atlas.png | [@emegeme](https://github.com/emegeme) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - | 20 | | heightmap.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - | 21 | | dresden_square_1k.hdr | [HDRIHaven](https://hdrihaven.com/hdri/?h=dresden_square) | [CC0](https://hdrihaven.com/p/license.php) | - | 22 | | dresden_square_2k.hdr | [HDRIHaven](https://hdrihaven.com/hdri/?h=dresden_square) | [CC0](https://hdrihaven.com/p/license.php) | - | 23 | | skybox.png | ❔ | ❔ | - | -------------------------------------------------------------------------------- /examples/resources/models/obj/turret_diffuse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/megagrump/yuema/7461a967a73202d2a7e395dde65e1a388057c32e/examples/resources/models/obj/turret_diffuse.png -------------------------------------------------------------------------------- /lib/box2d/Body.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import 'lib.util.ptr' 3 | import 'lib.math.Vector2' 4 | import 'lib.box2d._scale' 5 | import B2D from yuema 6 | 7 | tempVector = Vector2! 8 | tempMassData = ffi.new('b2cMassData') 9 | 10 | scaleUp1, scaleDown1 = _scale.up1, _scale.down1 11 | scaleUp2, scaleDown2 = _scale.up2, _scale.down2 12 | 13 | Body = ffi.typeof('b2Body') 14 | 15 | BodyTypes = { 16 | [0]: 'static' 17 | [1]: 'kinematic' 18 | [2]: 'dynamic' 19 | 20 | static: 0 21 | kinematic: 1 22 | dynamic: 2 23 | } 24 | 25 | BodyMT = { 26 | __new: (world, x, y, angle, type) => 27 | t = BodyTypes[type] or error("Invalid body type #{type}") 28 | x, y = scaleDown2(x, y) 29 | B2D.b2World_CreateBody(world, x, y, angle, t) 30 | 31 | destroy: => B2D.b2World_DestroyBody(@getWorld!, @_deinit!) 32 | createFixture: (shape, density = 1) => B2D.b2Body_CreateFixture(@, shape::_downCast!, density) 33 | destroyFixture: (fixture) => B2D.b2Body_DestroyFixture(@, fixture::_deinit!) 34 | setTransform: (x, y, angle) => 35 | x, y = scaleDown2(x, y) 36 | B2D.b2Body_SetTransform(@, x, y, angle) 37 | 38 | setPosition: (x, y) => @setTransform(x, y, @getAngle!) 39 | 40 | getPosition: => 41 | { :x, :y } = B2D.b2Body_GetPosition(@, tempVector) 42 | scaleUp2(x, y) 43 | 44 | setAngle: (angle) => 45 | { :x, :y } = B2D.b2Body_GetPosition(@, tempVector) 46 | B2D.b2Body_SetTransform(@, x, y, angle) 47 | 48 | getAngle: B2D.b2Body_GetAngle 49 | getWorldCenter: => 50 | { :x, :y } = B2D.b2Body_GetWorldCenter(@, tempVector) 51 | scaleUp2(x, y) 52 | 53 | getLocalCenter: => 54 | { :x, :y } = B2D.b2Body_GetLocalCenter(@, tempVector) 55 | scaleUp2(x, y) 56 | 57 | setLinearVelocity: (x, y) => B2D.b2Body_SetLinearVelocity(@, scaleDown2(x, y)) 58 | getLinearVelocity: => 59 | { :x, :y } = B2D.b2Body_GetLinearVelocity(@, tempVector) 60 | scaleUp2(x, y) 61 | 62 | setAngularVelocity: B2D.b2Body_SetAngularVelocity 63 | getAngularVelocity: B2D.b2Body_GetAngularVelocity 64 | applyForce: (forceX, forceY, x, y, wake = true) => 65 | forceX, forceY = scaleDown2(forceX, forceY) 66 | x, y = scaleDown2(x, y) 67 | B2D.b2Body_ApplyForce(@, forceX, forceY, x, y, wake) 68 | 69 | applyForceToCenter: (forceX, forceY, wake = true) => 70 | forceX, forceY = scaleDown2(forceX, forceY) 71 | B2D.b2Body_ApplyForceToCenter(@, forceX, forceY, wake) 72 | 73 | applyTorque: (torque, wake = true) => 74 | torque = scaleDown1(scaleDown1(torque)) 75 | B2D.b2Body_ApplyTorque(@, torque, wake) 76 | 77 | applyLinearImpulse: (impulseX, impulseY, x, y, wake = true) => 78 | impulseX, impulseY = scaleDown2(impulseX, impulseY) 79 | x, y = scaleDown2(x, y) 80 | B2D.b2Body_ApplyLinearImpulse(@, impulseX, impulseY, x, y, wake) 81 | 82 | applyLinearImpulseToCenter: (impulseX, impulseY, wake = true) => 83 | impulseX, impulseY = scaleDown2(impulseX, impulseY) 84 | B2D.b2Body_ApplyLinearImpulseToCenter(@, impulseX, impulseY, wake) 85 | 86 | applyAngularImpulse: (impulse, wake = true) => B2D.b2Body_ApplyAngularImpulse(@, impulse, wake) 87 | 88 | getMass: B2D.b2Body_GetMass 89 | getInertia: => scaleUp1(scaleUp1(B2D.b2Body_GetInertia(@))) 90 | 91 | getMassData: => 92 | data = B2D.b2Body_GetMassData(@, tempMassData) 93 | x, y = scaleUp2(data.x, data.y) 94 | inertia = scaleUp1(scaleUp1(data.inertia)) 95 | x, y, data.mass, inertia 96 | 97 | setMassData: (x, y, mass, inertia) => 98 | x, y = scaleDown2(x, y) 99 | inertia = scaleDown1(scaleDown1(inertia)) 100 | B2D.b2Body_SetMassData(@, x, y, mass, inertia) 101 | 102 | resetMassData: B2D.b2Body_ResetMassData 103 | getWorldPoint: (localX, localY) => 104 | localX, localY = scaleDown2(localX, localY) 105 | { :x, :y } = B2D.b2Body_GetWorldPoint(@, localX, localY, tempVector) 106 | scaleUp2(x, y) 107 | 108 | getWorldPoints: (points, output = points) => 109 | for i = 1, #points, 2 110 | x, y = scaleDown2(points[i], points[i + 1]) 111 | B2D.b2Body_GetWorldPoint(@, x, y, tempVector) 112 | output[i], output[i + 1] = scaleUp2(tempVector.x, tempVector.y) 113 | output 114 | 115 | getWorldVector: (localX, localY) => 116 | localX, localY = scaleDown2(localX, localY) 117 | { :x, :y } = B2D.b2Body_GetWorldVector(@, localX, localY, tempVector) 118 | scaleUp2(x, y) 119 | 120 | getLocalPoint: (worldX, worldY) => 121 | worldX, worldY = scaleDown2(worldX, worldY) 122 | { :x, :y } = B2D.b2Body_GetLocalPoint(@, worldX, worldY, tempVector) 123 | scaleUp2(x, y) 124 | 125 | getLocalPoints: (points, output = points) => 126 | for i = 1, #points, 2 127 | x, y = scaleDown2(points[i], points[i + 1]) 128 | B2D.b2Body_GetLocalPoint(@, x, y, tempVector) 129 | output[i], output[i + 1] = scaleUp2(tempVector.x, tempVector.y) 130 | output 131 | 132 | getLocalVector: (worldX, worldY) => 133 | worldX, worldY = scaleDown2(worldX, worldY) 134 | { :x, :y } = B2D.b2Body_GetLocalVector(@, worldX, worldY, tempVector) 135 | scaleUp2(x, y) 136 | 137 | getLinearVelocityFromWorldPoint: (worldX, worldY) => 138 | worldX, worldY = scaleDown2(worldX, worldY) 139 | { :x, :y } = B2D.b2Body_GetLinearVelocityFromWorldPoint(@, worldX, worldY, tempVector) 140 | scaleUp2(x, y) 141 | 142 | getLinearVelocityFromLocalPoint: (localX, localY) => 143 | localX, localY = scaleDown2(localX, localY) 144 | { :x, :y } = B2D.b2Body_GetLinearVelocityFromLocalPoint(@, localX, localY, tempVector) 145 | scaleUp2(x, y) 146 | 147 | getLinearDamping: B2D.b2Body_GetLinearDamping 148 | setLinearDamping: B2D.b2Body_SetLinearDamping 149 | getAngularDamping: B2D.b2Body_GetAngularDamping 150 | setAngularDamping: B2D.b2Body_SetAngularDamping 151 | getGravityScale: B2D.b2Body_GetGravityScale 152 | setGravityScale: B2D.b2Body_SetGravityScale 153 | setType: (type) => B2D.b2Body_SetType(@, BodyTypes[type]) 154 | getType: => BodyTypes[tonumber(B2D.b2Body_GetType(@))] 155 | setBullet: B2D.b2Body_SetBullet 156 | isBullet: B2D.b2Body_IsBullet 157 | setSleepingAllowed: B2D.b2Body_SetSleepingAllowed 158 | isSleepingAllowed: B2D.b2Body_IsSleepingAllowed 159 | setAwake: B2D.b2Body_SetAwake 160 | isAwake: B2D.b2Body_IsAwake 161 | setEnabled: B2D.b2Body_SetEnabled 162 | isEnabled: B2D.b2Body_IsEnabled 163 | setFixedRotation: B2D.b2Body_SetFixedRotation 164 | isFixedRotation: B2D.b2Body_IsFixedRotation 165 | getFixtureList: => ptr(B2D.b2Body_GetFixtureList(@)) 166 | getNext: => ptr(B2D.b2Body_GetNext(@)) 167 | getUserData: => yuema.getRef(tonumber(B2D.b2Body_GetUserData(@))) 168 | setUserData: (data) => B2D.b2Body_SetUserData(@, yuema.pushRef(data, tonumber(B2D.b2Body_GetUserData(@)))) 169 | getWorld: B2D.b2Body_GetWorld 170 | dump: B2D.b2Body_Dump 171 | 172 | _deinit: => 173 | @setUserData(nil) 174 | fixture = @getFixtureList! 175 | while fixture 176 | fixture = fixture::_deinit!::getNext! 177 | @ 178 | } 179 | 180 | BodyMT.__index = BodyMT 181 | 182 | ffi.metatype(Body, BodyMT) 183 | -------------------------------------------------------------------------------- /lib/box2d/Contact.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import 'lib.box2d._scale' 3 | import 'lib.math.Vector2' 4 | import 'lib.util.ptr' 5 | import B2D from yuema 6 | 7 | scaleUp1, scaleDown1 = _scale.up1, _scale.down1 8 | scaleUp2, scaleDown2 = _scale.up2, _scale.down2 9 | 10 | Contact = ffi.typeof('b2Contact') 11 | 12 | contactPoints = ffi.new('Vector2[2]') 13 | tempVector = ffi.new('Vector2') 14 | 15 | ContactMT = { 16 | isTouching: B2D.b2Contact_IsTouching 17 | setEnabled: B2D.b2Contact_SetEnabled 18 | isEnabled: B2D.b2Contact_IsEnabled 19 | getNext: => ptr(B2D.b2Contact_GetNext(@)) 20 | getFixtureA: => ptr(B2D.b2Contact_GetFixtureA(@)) 21 | getChildIndexA: B2D.b2Contact_GetChildIndexA 22 | getFixtureB: => ptr(B2D.b2Contact_GetFixtureB(@)) 23 | getChildIndexB: B2D.b2Contact_GetChildIndexB 24 | setFriction: B2D.b2Contact_SetFriction 25 | getFriction: B2D.b2Contact_GetFriction 26 | resetFriction: B2D.b2Contact_ResetFriction 27 | setRestitution: B2D.b2Contact_SetRestitution 28 | getRestitution: B2D.b2Contact_GetRestitution 29 | resetRestitution: B2D.b2Contact_ResetRestitution 30 | setRestitutionThreshold: B2D.b2Contact_SetRestitutionThreshold 31 | getRestitutionThreshold: B2D.b2Contact_GetRestitutionThreshold 32 | resetRestitutionThreshold: B2D.b2Contact_ResetRestitutionThreshold 33 | setTangentSpeed: (speed) => B2D.b2Contact_SetTangentSpeed(@, scaleDown1(speed)) 34 | getTangentSpeed: => scaleUp1(b2Contact_GetTangentSpeed(@)) 35 | getNormal: => 36 | { :x, :y } = B2D.b2Contact_GetNormal(@, tempVector) 37 | x, y 38 | 39 | getPoints: => 40 | n = B2D.b2Contact_GetPoints(@, contactPoints) 41 | return if n == 0 42 | x1, y1 = contactPoints[0].x, contactPoints[0].y 43 | scaleUp2(x1, y1) 44 | return x1, y1 if n == 1 45 | x2, y2 = contactPoints[1].x, contactPoints[1].y 46 | scaleUp2(x2, y2) 47 | x1, y1, x2, y2 48 | } 49 | 50 | ContactMT.__index = ContactMT 51 | 52 | ffi.metatype(Contact, ContactMT) 53 | -------------------------------------------------------------------------------- /lib/box2d/Fixture.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import B2D from yuema 3 | import 'lib.util.ptr' 4 | import 'lib.ray.Rectangle' 5 | import 'lib.box2d._scale' 6 | import 'lib.box2d.ShapeType' as :TypeNames 7 | 8 | scaleUp1, scaleDown1 = _scale.up1, _scale.down1 9 | scaleUp2, scaleDown2 = _scale.up2, _scale.down2 10 | 11 | tempFilter = ffi.new('b2cFilter') 12 | tempRayCast = ffi.new('b2cRayCastOutput') 13 | tempMassData = ffi.new('b2cMassData') 14 | tempRect = Rectangle! 15 | 16 | Fixture = ffi.typeof('b2Fixture') 17 | 18 | FixtureMT = { 19 | getType: => TypeNames[B2D.b2Fixture_GetType(@)] 20 | getShape: => B2D.b2Fixture_GetShape(@)::_upCast! 21 | setSensor: B2D.b2Fixture_SetSensor 22 | isSensor: B2D.b2Fixture_IsSensor 23 | setFilterData: B2D.b2Fixture_SetFilterData 24 | getFilterData: => 25 | data = B2D.b2Fixture_GetFilterData(@, tempFilter) 26 | data.category, data.mask, data.group 27 | 28 | refilter: B2D.b2Fixture_Refilter 29 | getBody: => ptr(B2D.b2Fixture_GetBody(@)) 30 | getNext: => ptr(B2D.b2Fixture_GetNext(@)) 31 | getUserData: => yuema.getRef(tonumber(B2D.b2Fixture_GetUserData(@))) 32 | setUserData: (data) => 33 | ref = yuema.pushRef(data, tonumber(B2D.b2Fixture_GetUserData(@))) 34 | B2D.b2Fixture_SetUserData(@, ref) 35 | 36 | testPoint: B2D.b2Fixture_TestPoint 37 | rayCast: (x1, y1, x2, y2, maxFraction, childIndex) => 38 | x1, y1 = scaleDown2(x1, y1) 39 | x2, y2 = scaleDown2(x2, y2) 40 | result = B2D.b2Fixture_RayCast(@, x1, y1, x2, y2, maxFraction, childIndex, tempRayCast) 41 | result.hit, result.nx, result.ny, result.fraction 42 | 43 | getMassData: => 44 | data = B2D.b2Fixture_GetMassData(@, tempMassData) 45 | x, y = scaleUp2(data.x, data.y) 46 | inertia = scaleUp1(scaleUp1(data.inertia)) 47 | x, y, data.mass, inertia 48 | 49 | setDensity: B2D.b2Fixture_SetDensity 50 | getDensity: B2D.b2Fixture_GetDensity 51 | getFriction: B2D.b2Fixture_GetFriction 52 | setFriction: B2D.b2Fixture_SetFriction 53 | getRestitution: B2D.b2Fixture_GetRestitution 54 | setRestitution: B2D.b2Fixture_SetRestitution 55 | getRestitutionThreshold: B2D.b2Fixture_GetRestitutionThreshold 56 | setRestitutionThreshold: B2D.b2Fixture_SetRestitutionThreshold 57 | getAABB: (childIndex = 0) => 58 | aabb = B2D.b2Fixture_GetAABB(@, childIndex, tempRect) 59 | x, y = scaleUp2(aabb.x, aabb.y) 60 | w, h = scaleUp2(aabb.width, aabb.height) 61 | x, y, w, h 62 | 63 | dump: B2D.b2Fixture_Dump 64 | 65 | _deinit: => 66 | @setUserData(nil) 67 | @ 68 | } 69 | 70 | FixtureMT.__index = FixtureMT 71 | 72 | ffi.metatype(Fixture, FixtureMT) 73 | -------------------------------------------------------------------------------- /lib/box2d/JointType.yue: -------------------------------------------------------------------------------- 1 | REVOLUTE = 1 2 | PRISMATIC = 2 3 | DISTANCE = 3 4 | PULLEY = 4 5 | MOUSE = 5 6 | GEAR = 6 7 | WHEEL = 7 8 | WELD = 8 9 | FRICTION = 9 10 | MOTOR = 10 11 | 12 | TypeNames = { 13 | [REVOLUTE]: 'revolute' 14 | [PRISMATIC]: 'prismatic' 15 | [DISTANCE]: 'distance' 16 | [PULLEY]: 'pulley' 17 | [MOUSE]: 'mouse' 18 | [GEAR]: 'gear' 19 | [WHEEL]: 'wheel' 20 | [WELD]: 'weld' 21 | [FRICTION]: 'friction' 22 | [MOTOR]: 'motor' 23 | } 24 | 25 | { 26 | :REVOLUTE 27 | :PRISMATIC 28 | :DISTANCE 29 | :PULLEY 30 | :MOUSE 31 | :GEAR 32 | :WHEEL 33 | :WELD 34 | :FRICTION 35 | :MOTOR 36 | 37 | :TypeNames 38 | } 39 | -------------------------------------------------------------------------------- /lib/box2d/ShapeType.yue: -------------------------------------------------------------------------------- 1 | CIRCLE = 0 2 | EDGE = 1 3 | POLYGON = 2 4 | CHAIN = 3 5 | 6 | TypeNames = { 7 | [CIRCLE]: 'circle' 8 | [EDGE]: 'edge' 9 | [POLYGON]: 'polygon' 10 | [CHAIN]: 'chain' 11 | } 12 | 13 | { 14 | :CIRCLE 15 | :EDGE 16 | :POLYGON 17 | :CHAIN 18 | 19 | :TypeNames 20 | } 21 | -------------------------------------------------------------------------------- /lib/box2d/World.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import B2D from yuema 3 | import 'lib.util.ptr' 4 | import 'lib.math.Vector2' 5 | import 'lib.box2d._scale' 6 | import 'lib.box2d.Body' 7 | import 'lib.box2d.draw' 8 | import 'lib.box2d.joints' 9 | 10 | profile = ffi.new('b2cProfile') 11 | 12 | tempVector = Vector2! 13 | scaleUp2, scaleDown2 = _scale.up2, _scale.down2 14 | tempCount = ffi.new('size_t[1]') 15 | 16 | emptyContactFilter = -> error("Invalid filter") 17 | emptyListener = -> 18 | rayCastCallback = nil 19 | queryCallback = nil 20 | 21 | doRayCast = (x1, y1, x2, y2) => B2D.b2World_RayCast(@, x1, y1, x2, y2) 22 | jit.off(doRayCast) -- callbacks from jitted code are problematic 23 | 24 | doQuery = (minX, minY, maxX, maxY) => B2D.b2World_QueryAABB(@, minX, minY, maxX, maxY) 25 | jit.off(doQuery) -- callbacks from jitted code are problematic 26 | 27 | World = ffi.typeof('b2World') 28 | 29 | WorldMT = { 30 | __new: (gravityX, gravityY) => 31 | world = ffi.gc(B2D.b2World_New(scaleDown2(gravityX, gravityY)), => @destroy!) 32 | with B2D 33 | .b2World_SetRayCastCallback(world, world._rayCastCallback) 34 | .b2World_SetQueryCallback(world, world._queryCallback) 35 | .b2World_SetContactFilter(world, emptyContactFilter) 36 | .b2World_SetContactListener(world, emptyListener, emptyListener, emptyListener, emptyListener) 37 | world 38 | 39 | destroy: => 40 | ffi.gc(@, nil) 41 | with B2D 42 | .b2World_GetContactFilter(@)::free! 43 | .b2World_GetRayCastCallback(@)::free! 44 | .b2World_GetQueryCallback(@)::free! 45 | .b2World_GetBeginContactListener(@)::free! 46 | .b2World_GetEndContactListener(@)::free! 47 | .b2World_GetPreSolveContactListener(@)::free! 48 | .b2World_GetPostSolveContactListener(@)::free! 49 | body = @getBodyList! 50 | while body 51 | body = body::_deinit!::getNext! 52 | joint = @getJointList! 53 | while joint 54 | joint = joint::_deinit!::getNext! 55 | B2D.b2World_Destroy(@) 56 | 57 | createBody: (x, y, type = 'dynamic', angle = 0) => Body(@, x, y, angle, type) 58 | 59 | destroyJoint: (joint) => B2D.b2World_DestroyJoint(@, joint::_deinit!) 60 | step: (timeStep, velocityIterations = 8, positionIterations = 3) => B2D.b2World_Step(@, timeStep, velocityIterations, positionIterations) 61 | clearForces: => B2D.b2World_ClearForces(@) 62 | 63 | setContactListener: (beginContact, endContact, preSolve, postSolve) => 64 | with B2D 65 | .b2World_GetBeginContactListener(@)::set(beginContact or emptyListener) 66 | .b2World_GetEndContactListener(@)::set(endContact or emptyListener) 67 | .b2World_GetPreSolveContactListener(@)::set(preSolve or emptyListener) 68 | .b2World_GetPostSolveContactListener(@)::set(postSolve or emptyListener) 69 | 70 | .b2World_EnableContactListener(@, 71 | not not beginContact, 72 | not not endContact, 73 | not not preSolveContact, 74 | not not postSolveContact 75 | ) 76 | 77 | setContactFilter: (filter) => 78 | B2D.b2World_GetContactFilter(@)::set(filter or emptyContactFilter) 79 | B2D.b2World_EnableContactFilter(@, not not filter) 80 | 81 | _queryCallback: (fixture) -> queryCallback(fixture) 82 | 83 | -- query AABB with callback; this is slow - better use getFixturesFromAABB 84 | queryAABB: (minX, minY, maxX, maxY, callback) => 85 | queryCallback = callback 86 | minX, minY = scaleDown2(minX, minY) 87 | maxX, maxY = scaleDown2(maxX, maxY) 88 | doQuery(@, minX, minY, maxX, maxY) 89 | queryCallback = nil 90 | 91 | getFixturesFromAABB: (minX, minY, maxX, maxY, target = {}) => 92 | minX, minY = scaleDown2(minX, minY) 93 | maxX, maxY = scaleDown2(maxX, maxY) 94 | fixtures = B2D.b2World_GetFixturesFromAABB(@, minX, minY, maxX, maxY, tempCount) 95 | n = tonumber(tempCount[0]) 96 | target[i + 1] = fixtures[i] for i = 0, n - 1 97 | target, n 98 | 99 | _rayCastCallback: (fixture, x, y, nx, ny, fraction) -> 100 | x, y = scaleUp2(x, y) 101 | rayCastCallback(fixture, x, y, nx, ny, fraction) 102 | 103 | rayCast: (x1, y1, x2, y2, callback) => 104 | rayCastCallback = callback 105 | x1, y1 = scaleDown2(x1, y1) 106 | x2, y2 = scaleDown2(x2, y2) 107 | doRayCast(@, x1, y1, x2, y2) 108 | rayCastCallback = nil 109 | 110 | getBodyList: => ptr(B2D.b2World_GetBodyList(@)) 111 | getJointList: => ptr(B2D.b2World_GetJointList(@))?::_upCast! 112 | getGroundBody: => B2D.b2World_GetGroundBody(@) 113 | getContactList: => ptr(B2D.b2World_GetContactList(@)) 114 | setAllowSleeping: B2D.b2World_SetAllowSleeping 115 | getAllowSleeping: B2D.b2World_GetAllowSleeping 116 | setWarmStarting: B2D.b2World_SetWarmStarting 117 | getWarmStarting: B2D.b2World_GetWarmStarting 118 | setContinuousPhysics: B2D.b2World_SetContinuousPhysics 119 | getContinuousPhysics: b2World_GetContinuousPhysics 120 | setSubStepping: B2D.b2World_SetSubStepping 121 | getSubStepping: B2D.b2World_GetSubStepping 122 | getProxyCount: B2D.b2World_GetProxyCount 123 | getBodyCount: B2D.b2World_GetBodyCount 124 | getJointCount: B2D.b2World_GetJointCount 125 | getContactCount: B2D.b2World_GetContactCount 126 | getTreeHeight: B2D.b2World_GetTreeHeight 127 | getTreeBalance: B2D.b2World_GetTreeBalance 128 | getTreeQuality: B2D.b2World_GetTreeQuality 129 | setGravity: (gravityX, gravityY) => B2D.b2World_SetGravity(@, scaleDown2(gravityX, gravityY)) 130 | getGravity: => 131 | { :x, :y } = B2D.b2World_GetGravity(@, tempVector) 132 | scaleUp2(x, y) 133 | 134 | isLocked: B2D.b2World_IsLocked 135 | setAutoClearForces: B2D.b2World_SetAutoClearForces 136 | getAutoClearForces: B2D.b2World_GetAutoClearForces 137 | shiftOrigin: (x, y) => B2D.b2World_ShiftOrigin(@, scaleDown2(x, y)) 138 | getProfile: => B2D.b2World_GetProfile(@, profile) 139 | dump: B2D.b2World_Dump 140 | debugDraw: draw 141 | } 142 | 143 | jit.off(WorldMT.step) -- required to make callbacks work 144 | 145 | WorldMT.__index = WorldMT 146 | 147 | ffi.metatype(World, WorldMT) 148 | -------------------------------------------------------------------------------- /lib/box2d/_scale.yue: -------------------------------------------------------------------------------- 1 | scale = 64 2 | iscale = 1 / scale 3 | 4 | { 5 | set: (s) -> scale, iscale = s, 1 / s 6 | get: -> scale 7 | 8 | up1: (x) -> x * scale 9 | 10 | up2: (x, y) -> x * scale, y * scale 11 | 12 | down1: (x) -> x * iscale 13 | 14 | down2: (x, y) -> x * iscale, y * iscale 15 | } 16 | -------------------------------------------------------------------------------- /lib/box2d/draw.yue: -------------------------------------------------------------------------------- 1 | import B2D from yuema 2 | import 'ffi' 3 | import 'lib.ray.draw' 4 | import 'lib.ray.Color' 5 | import 'lib.box2d._scale' 6 | 7 | scaleUp1, scaleUp2 = _scale.up1, _scale.up2 8 | tempVerts = ffi.new('Vector2[8]') 9 | proxy = ffi.new('b2cDraw') 10 | 11 | colorCache = {} 12 | makeColor = (r, g, b, a) -> 13 | hash = r * 64 + g * 16 + b * 4 + a 14 | if color = colorCache[hash] 15 | return color 16 | 17 | color = Color.fromNormalized(r, g, b, a) 18 | colorCache[hash] = color 19 | color 20 | 21 | proxy.DrawPolygon = (vertices, count, r, g, b, a) -> 22 | color = makeColor(r, g, b, a) 23 | for i = 0, count - 1 24 | n = (i + 1) % count 25 | x1, y1 = scaleUp2(vertices[i].x, vertices[i].y) 26 | x2, y2 = scaleUp2(vertices[n].x, vertices[n].y) 27 | draw.line(x1, y1, x2, y2, color) 28 | 29 | proxy.DrawSolidPolygon = (vertices, count, r, g, b, a) -> 30 | color = makeColor(r, g, b, a) 31 | for i = 0, count - 1 32 | tempVerts[i].x, tempVerts[i].y = scaleUp2(vertices[i].x, vertices[i].y) 33 | draw.triangleFan(tempVerts, count, color) 34 | 35 | proxy.DrawCircle = (x, y, radius, r, g, b, a) -> 36 | x, y = scaleUp2(x, y) 37 | radius = scaleUp1(radius) 38 | draw.circleLines(x, y, radius, makeColor(r, g, b, a)) 39 | 40 | proxy.DrawSolidCircle = (x, y, radius, ax, ay, r, g, b, a) -> 41 | x, y = scaleUp2(x, y) 42 | radius = scaleUp1(radius) 43 | color = makeColor(r, g, b, a) 44 | draw.circle(x, y, radius, color) 45 | color2 = makeColor(1 - r, 1 - g, 1 - b, a) 46 | draw.line(x, y, x + ax * radius, y + ay * radius, color2) 47 | 48 | proxy.DrawSegment = (x1, y1, x2, y2, r, g, b, a) -> 49 | x1, y1 = scaleUp2(x1, y1) 50 | x2, y2 = scaleUp2(x2, y2) 51 | draw.line(x1, y1, x2, y2, makeColor(r, g, b, a)) 52 | 53 | proxy.DrawTransform = (x, y, angle) -> 54 | x, y = scaleUp2(x, y) 55 | 56 | proxy.DrawPoint = (x, y, size, r, g, b, a) -> 57 | x, y = scaleUp2(x, y) 58 | draw.circle(x, y, size, makeColor(r, g, b, a)) 59 | 60 | debugDraw = (world) -> 61 | B2D.b2Draw_Draw(world, proxy) 62 | 63 | debugDraw 64 | -------------------------------------------------------------------------------- /lib/box2d/init.yue: -------------------------------------------------------------------------------- 1 | import 'lib.box2d.World' 2 | import 'lib.box2d.Body' 3 | import 'lib.box2d.Fixture' 4 | import 'lib.box2d.Contact' 5 | import 'lib.box2d.shapes' 6 | import 'lib.box2d.joints' 7 | import 'lib.box2d._scale' 8 | 9 | { 10 | setScale: (s) -> _scale.set(s) 11 | getScale: -> _scale.get! 12 | 13 | CircleShape: shapes.CircleShape 14 | ChainShape: shapes.ChainShape 15 | PolygonShape: shapes.PolygonShape 16 | EdgeShape: shapes.EdgeShape 17 | 18 | RevoluteJoint: joints.RevoluteJoint 19 | PrismaticJoint: joints.PrismaticJoint 20 | DistanceJoint: joints.DistanceJoint 21 | PulleyJoint: joints.PulleyJoint 22 | MouseJoint: joints.MouseJoint 23 | GearJoint: joints.GearJoint 24 | WheelJoint: joints.WheelJoint 25 | WeldJoint: joints.WeldJoint 26 | FrictionJoint: joints.FrictionJoint 27 | MotorJoint: joints.MotorJoint 28 | 29 | :World 30 | :Body 31 | } 32 | -------------------------------------------------------------------------------- /lib/box2d/shapes.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import B2D from yuema 3 | import 'lib.math.Vector2' 4 | import 'lib.ray.Rectangle' 5 | import 'lib.box2d._scale' 6 | import 'lib.box2d.ShapeType' as :TypeNames 7 | 8 | shapeCast = ffi.new([[ 9 | union { 10 | b2Shape *shape; 11 | b2CircleShape *circle; 12 | b2EdgeShape *edge; 13 | b2PolygonShape *polygon; 14 | b2ChainShape *chain; 15 | } 16 | ]]) 17 | 18 | tempVector = Vector2! 19 | tempRect = Rectangle! 20 | tempMassData = ffi.new('b2cMassData') 21 | tempRayCast = ffi.new('b2cRayCastOutput') 22 | scaleUp1, scaleDown1 = _scale.up1, _scale.down1 23 | scaleUp2, scaleDown2 = _scale.up2, _scale.down2 24 | 25 | --- Shape --- 26 | 27 | Shape = ffi.typeof('b2Shape') 28 | ShapePtr = ffi.typeof('b2Shape*') 29 | 30 | ShapeMT = { 31 | __gc: => B2D.b2Shape_Destroy(@_downCast!) 32 | getType: => TypeNames[tonumber(B2D.b2Shape_GetType(@))] 33 | getChildCount: => B2D.b2Shape_GetChildCount(@_downCast!) 34 | testPoint: (tx, ty, angle, x, y) => 35 | tx, ty = scaleDown2(tx, ty) 36 | x, y = scaleDown2(x, y) 37 | B2D.b2Shape_TestPoint(@_downCast!, tx, ty, angle, x, y) 38 | 39 | rayCast: (tx, ty, angle, x1, y1, x2, y2, maxFraction, childIndex = 0) => 40 | tx, ty = scaleDown2(tx, ty) 41 | x1, y1 = scaleDown2(x1, y1) 42 | x2, y2 = scaleDown2(x2, y2) 43 | B2D.b2Shape_RayCast(@_downCast!, tx, ty, angle, x1, y1, x2, y2, maxFraction, childIndex, tempRayCast) 44 | tempRayCast.hit, tempRayCast.nx, tempRayCast.ny, tempRayCast.fraction 45 | 46 | computeAABB: (x, y, a, childIndex = 0) => 47 | x, y = scaleDown2(x, y) 48 | r = B2D.b2Shape_ComputeAABB(@_downCast!, x, y, a, childIndex, tempRect) 49 | bx, by = scaleUp2(r.x, r.y) 50 | w, h = scaleUp2(r.width, r.height) 51 | bx, by, w, h 52 | 53 | computeMass: (density) => 54 | data = b2Shape_ComputeMass(@_downCast!, density, tempMassData) 55 | x, y = scaleUp2(data.x, data.y) 56 | inertia = scaleUp1(scaleUp1(data.inertia)) 57 | x, y, data.mass, inertia 58 | 59 | _upCast: => 60 | shapeCast.shape = @ 61 | shapeCast[@getType!] 62 | } 63 | 64 | ShapeMT.__index = ShapeMT 65 | ffi.metatype(Shape, ShapeMT) 66 | 67 | --- CircleShape --- 68 | 69 | CircleShape = ffi.typeof('b2CircleShape') 70 | 71 | CircleShapeMT = { 72 | __new: (radius) => B2D.b2CircleShape_New(scaleDown1(radius)) 73 | __gc: ShapeMT.__gc 74 | 75 | setPosition: (x, y) => 76 | x, y = scaleDown2(x, y) 77 | B2D.b2CircleShape_SetPosition(@, x, y) 78 | 79 | getPosition: => 80 | { :x, :y } = B2D.b2CircleShape_GetPosition(@, tempVector) 81 | scaleUp2(x, y) 82 | 83 | setRadius: (radius) => 84 | radius = scaleDown1(radius) 85 | B2D.b2CircleShape_SetRadius(@, radius) 86 | 87 | getRadius: => scaleUp1(B2D.b2CircleShape_GetRadius(@)) 88 | 89 | getType: => 'circle' 90 | getChildCount: ShapeMT.getChildCount 91 | computeAABB: ShapeMT.computeAABB 92 | computeMass: ShapeMT.computeMass 93 | testPoint: ShapeMT.testPoint 94 | rayCast: ShapeMT.rayCast 95 | 96 | _downCast: => 97 | shapeCast.circle = @ 98 | shapeCast.shape 99 | } 100 | 101 | CircleShapeMT.__index = CircleShapeMT 102 | ffi.metatype(CircleShape, CircleShapeMT) 103 | 104 | --- EdgeShape --- 105 | 106 | EdgeShape = ffi.typeof('b2EdgeShape') 107 | 108 | EdgeShapeMT = { 109 | __new: (x0, y0, x1, y1, x2, y2, x3, y3) => 110 | x0, y0 = scaleDown2(x0, y0) 111 | x1, y1 = scaleDown2(x1, y1) 112 | shape = if x2 113 | x2, y2 = scaleDown2(x2, y2) 114 | x3, y3 = scaleDown2(x3, y3) 115 | B2D.b2EdgeShape_NewOneSided(x0, y0, x1, y1, x2, y2, x3, y3) 116 | else 117 | B2D.b2EdgeShape_NewTwoSided(x0, y0, x1, y1) 118 | shape 119 | 120 | __gc: ShapeMT.__gc 121 | 122 | setOneSided: (x0, y0, x1, y1, x2, y2, x3, y3) => 123 | x0, y0 = scaleDown2(x0, y0) 124 | x1, y1 = scaleDown2(x1, y1) 125 | x2, y2 = scaleDown2(x2, y2) 126 | x3, y3 = scaleDown2(x3, y3) 127 | B2D.b2EdgeShape_SetOneSided(@, x0, y0, x1, y1, x2, y2, x3, y3) 128 | 129 | setTwoSided: (x1, y1, x2, y2) => 130 | x0, y0 = scaleDown2(x1, y1) 131 | x1, y1 = scaleDown2(x2, y2) 132 | B2D.b2EdgeShape_SetTwoSided(@, x1, y1, x2, y2) 133 | 134 | isOneSided: B2D.b2EdgeShape_IsOneSided 135 | 136 | getVertices: (target = {}) => 137 | { :x, :y } = B2D.b2EdgeShape_GetVertex(@, 1, tempVector) 138 | target[1], target[2] = scaleUp2(x, y) 139 | { :x, :y } = B2D.b2EdgeShape_GetVertex(@, 2, tempVector) 140 | target[3], target[4] = scaleUp2(x, y) 141 | target 142 | 143 | getPreviousVertex: => 144 | { :x, :y } = B2D.b2EdgeShape_GetVertex(@, 0, tempVector) 145 | scaleUp2(x, y) 146 | 147 | getNextVertex: => 148 | { :x, :y } = B2D.b2EdgeShape_GetVertex(@, 2, tempVector) 149 | scaleUp2(x, y) 150 | 151 | getType: => 'edge' 152 | getChildCount: ShapeMT.getChildCount 153 | computeAABB: ShapeMT.computeAABB 154 | computeMass: ShapeMT.computeMass 155 | testPoint: ShapeMT.testPoint 156 | rayCast: ShapeMT.rayCast 157 | 158 | _downCast: => 159 | shapeCast.edge = @ 160 | shapeCast.shape 161 | } 162 | 163 | EdgeShapeMT.__index = EdgeShapeMT 164 | ffi.metatype(EdgeShape, EdgeShapeMT) 165 | 166 | --- PolygonShape --- 167 | 168 | PolygonShape = ffi.typeof('b2PolygonShape') 169 | 170 | convertVertices = (vertices, n) -> 171 | nverts = n / 2 172 | verts = ffi.new('Vector2[?]', nverts) 173 | j = 1 174 | for i = 0, nverts - 1 175 | verts[i].x, verts[i].y = scaleDown2(vertices[j], vertices[j + 1]) 176 | j += 2 177 | verts, nverts 178 | 179 | PolygonShapeMT = { 180 | __new: (...) => 181 | npairs = select('#', ...) 182 | assert(npairs >= 6 and npairs % 2 == 0, "Incomplete vertices for PolygonShape") 183 | assert(npairs <= 16, "Too many vertices for PolygonShape") 184 | B2D.b2PolygonShape_New(convertVertices({ ... }, npairs)) 185 | 186 | __gc: ShapeMT.__gc 187 | 188 | createBox: (width, height) -> 189 | PolygonShape( 190 | -width * .5, -height * .5, 191 | -width * .5, height * .5, 192 | width * .5, height * .5, 193 | width * .5, -height * .5 194 | ) 195 | 196 | getVertexCount: B2D.b2PolygonShape_GetVertexCount 197 | getVertices: (target = {}) => 198 | n = @getVertexCount! 199 | for i = 0, n - 1 200 | { :x, :y } = B2D.b2PolygonShape_GetVertex(@, i, tempVector) 201 | x, y = scaleUp2(x, y) 202 | target[i * 2 + 1] = x 203 | target[i * 2 + 2] = y 204 | target 205 | 206 | getNormals: (target = {}) => 207 | n = @getVertexCount! 208 | for i = 0, n - 1 209 | { :x, :y } = B2D.b2PolygonShape_GetNormal(@, i, tempVector) 210 | target[i * 2 + 1] = x 211 | target[i * 2 + 2] = y 212 | target 213 | 214 | validate: B2D.b2PolygonShape_Validate 215 | getType: => 'polygon' 216 | getChildCount: ShapeMT.getChildCount 217 | computeAABB: ShapeMT.computeAABB 218 | computeMass: ShapeMT.computeMass 219 | testPoint: ShapeMT.testPoint 220 | rayCast: ShapeMT.rayCast 221 | 222 | _downCast: => 223 | shapeCast.polygon = @ 224 | shapeCast.shape 225 | } 226 | 227 | PolygonShapeMT.__index = PolygonShapeMT 228 | ffi.metatype(PolygonShape, PolygonShapeMT) 229 | 230 | --- ChainShape --- 231 | 232 | ChainShape = ffi.typeof('b2ChainShape') 233 | 234 | ChainShapeMT = { 235 | __new: (vertices, x0, y0, x1, y1) => 236 | if x0 237 | @._createChain(vertices, x0, y0, x1, y1) 238 | else 239 | @._createLoop(vertices) 240 | 241 | __gc: ShapeMT.__gc 242 | 243 | _createLoop: (vertices) -> 244 | n = #vertices 245 | assert(n >= 6 and n % 2 == 0, "Incomplete vertices for ChainShape") 246 | B2D.b2ChainShape_NewLoop(convertVertices(vertices, n)) 247 | 248 | _createChain: (vertices, x1, y1, x2, y2) -> 249 | n = #vertices 250 | assert(n >= 4 and n % 2 == 0, "Incomplete vertices for ChainShape") 251 | verts, nverts = convertVertices(vertices, n) 252 | x1, y1 = scaleDown2(x1, y1) 253 | x2, y2 = scaleDown2(x2, y2) 254 | B2D.b2ChainShape_NewChain(verts, nverts, x1, y1, x2, y2) 255 | 256 | getVertexCount: B2D.b2ChainShape_GetVertexCount 257 | getVertices: (target = {}) => 258 | n = @getVertexCount! 259 | for i = 0, n - 1 260 | { :x, :y } = B2D.b2ChainShape_GetVertex(@, i, tempVector) 261 | x, y = scaleUp2(x, y) 262 | target[i * 2 + 1] = x 263 | target[i * 2 + 2] = y 264 | target 265 | 266 | setPrevVertex: (x, y) => 267 | x, y = scaleDown2(x, y) 268 | B2D.b2ChainShape_SetPrevVertex(@, x, y) 269 | 270 | getPrevVertex: => 271 | { :x, :y } = B2D.b2ChainShape_GetPrevVertex(@, tempVector) 272 | scaleUp2(x, y) 273 | 274 | setNextVertex: (x, y) => 275 | x, y = scaleDown2(x, y) 276 | B2D.b2ChainShape_SetNextVertex(@, x, y) 277 | 278 | getNextVertex: => 279 | { :x, :y } = B2D.b2ChainShape_GetNextVertex(@, tempVector) 280 | scaleUp2(x, y) 281 | 282 | getType: =>'chain' 283 | getChildCount: ShapeMT.getChildCount 284 | computeAABB: ShapeMT.computeAABB 285 | computeMass: ShapeMT.computeMass 286 | testPoint: ShapeMT.testPoint 287 | rayCast: ShapeMT.rayCast 288 | _downCast: => 289 | shapeCast.chain = @ 290 | shapeCast.shape 291 | } 292 | 293 | ChainShapeMT.__index = ChainShapeMT 294 | ffi.metatype(ChainShape, ChainShapeMT) 295 | 296 | { 297 | :CircleShape 298 | :ChainShape 299 | :PolygonShape 300 | :EdgeShape 301 | } 302 | -------------------------------------------------------------------------------- /lib/core/debug.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | 3 | consoleOpen = false 4 | 5 | export openConsole = -> 6 | return if consoleOpen 7 | if ffi.os == 'Windows' 8 | ffi.cdef([[ 9 | typedef struct FILE FILE; 10 | void AllocConsole(); 11 | FILE *freopen(const char*, const char*, FILE*); 12 | ]]) 13 | with ffi.C 14 | .AllocConsole! 15 | .freopen('CONIN$', 'r', io.stdin) 16 | .freopen('CONOUT$', 'w', io.stderr) 17 | .freopen('CONOUT$', 'w', io.stdout) 18 | print("Console opened.") 19 | consoleOpen = true 20 | 21 | export isConsoleOpen = -> consoleOpen 22 | -------------------------------------------------------------------------------- /lib/core/init.yue: -------------------------------------------------------------------------------- 1 | do 2 | refStore = { [0]: 0 } 3 | 4 | yuema.pushRef = (val, prevRef) -> 5 | ref = refStore[0] 6 | if prevRef and prevRef > 0 7 | refStore[prevRef] = nil 8 | if prevRef == ref 9 | while refStore[ref] == nil 10 | ref -= 1 11 | return 0 if val == nil 12 | ref += 1 13 | refStore[ref], refStore[0] = val, ref 14 | ref 15 | 16 | yuema.getRef = (ref) -> ref > 0 and refStore[ref] or nil 17 | 18 | yuema 19 | -------------------------------------------------------------------------------- /lib/gl/init.yue: -------------------------------------------------------------------------------- 1 | import RLGL from yuema 2 | import 'ffi' as :C 3 | 4 | { 5 | -- TODO: include missing relevant GL constants for custom blending etc. 6 | -- defined in raylib/src/external/glad.h 7 | FALSE: 0 8 | TRUE: 1 9 | BYTE: 0x1400 10 | SHORT: 0x1402 11 | UNSIGNED_SHORT: 0x1403 12 | INT: 0x1404 13 | UNSIGNED_INT: 0x1405 14 | HALF_FLOAT: 0x140B 15 | DOUBLE: 0x140A 16 | FIXED: 0x140C 17 | INT_2_10_10_10_REV: 0x8D9F 18 | UNSIGNED_INT_2_10_10_10_REV: 0x8368 19 | UNSIGNED_INT_10F_11F_11F_REV: 0x8C3B 20 | 21 | INVALID_VALUE: 0x0501 22 | INVALID_OPERATION: 0x0502 23 | 24 | DEFAULT_BATCH_BUFFER_ELEMENTS: C.RL_DEFAULT_BATCH_BUFFER_ELEMENTS 25 | DEFAULT_BATCH_BUFFERS: C.RL_DEFAULT_BATCH_BUFFERS 26 | DEFAULT_BATCH_DRAWCALLS: C.RL_DEFAULT_BATCH_DRAWCALLS 27 | DEFAULT_BATCH_MAX_TEXTURE_UNITS: C.RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS 28 | MAX_MATRIX_STACK_SIZE: C.RL_MAX_MATRIX_STACK_SIZE 29 | MAX_SHADER_LOCATIONS: C.RL_MAX_SHADER_LOCATIONS 30 | CULL_DISTANCE_NEAR: 0.01 31 | CULL_DISTANCE_FAR: C.RL_CULL_DISTANCE_FAR 32 | TEXTURE_WRAP_S: C.RL_TEXTURE_WRAP_S 33 | TEXTURE_WRAP_T: C.RL_TEXTURE_WRAP_T 34 | TEXTURE_MAG_FILTER: C.RL_TEXTURE_MAG_FILTER 35 | TEXTURE_MIN_FILTER: C.RL_TEXTURE_MIN_FILTER 36 | TEXTURE_FILTER_NEAREST: C.RL_TEXTURE_FILTER_NEAREST 37 | TEXTURE_FILTER_LINEAR: C.RL_TEXTURE_FILTER_LINEAR 38 | TEXTURE_FILTER_MIP_NEAREST: C.RL_TEXTURE_FILTER_MIP_NEAREST 39 | TEXTURE_FILTER_NEAREST_MIP_LINEAR: C.RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR 40 | TEXTURE_FILTER_LINEAR_MIP_NEAREST: C.RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST 41 | TEXTURE_FILTER_MIP_LINEAR: C.RL_TEXTURE_FILTER_MIP_LINEAR 42 | TEXTURE_FILTER_ANISOTROPIC: C.RL_TEXTURE_FILTER_ANISOTROPIC 43 | BLEND_ALPHA: C.RL_BLEND_ALPHA 44 | BLEND_ADDITIVE: C.RL_BLEND_ADDITIVE 45 | BLEND_MULTIPLIED: C.RL_BLEND_MULTIPLIED 46 | BLEND_ADD_COLORS: C.RL_BLEND_ADD_COLORS 47 | BLEND_SUBTRACT_COLORS: C.RL_BLEND_SUBTRACT_COLORS 48 | BLEND_ALPHA_PREMUL: C.RL_BLEND_ALPHA_PREMUL 49 | BLEND_CUSTOM: C.RL_BLEND_CUSTOM 50 | TEXTURE_WRAP_REPEAT: C.RL_TEXTURE_WRAP_REPEAT 51 | TEXTURE_WRAP_CLAMP: C.RL_TEXTURE_WRAP_CLAMP 52 | TEXTURE_WRAP_MIRROR_REPEAT: C.RL_TEXTURE_WRAP_MIRROR_REPEAT 53 | TEXTURE_WRAP_MIRROR_CLAMP: C.RL_TEXTURE_WRAP_MIRROR_CLAMP 54 | MODELVIEW: C.RL_MODELVIEW 55 | PROJECTION: C.RL_PROJECTION 56 | TEXTURE: C.RL_TEXTURE 57 | LINES: C.RL_LINES 58 | TRIANGLES: C.RL_TRIANGLES 59 | QUADS: C.RL_QUADS 60 | UNSIGNED_BYTE: C.RL_UNSIGNED_BYTE 61 | FLOAT: C.RL_FLOAT 62 | STREAM_DRAW: C.RL_STREAM_DRAW 63 | STREAM_READ: C.RL_STREAM_READ 64 | STREAM_COPY: C.RL_STREAM_COPY 65 | STATIC_DRAW: C.RL_STATIC_DRAW 66 | STATIC_READ: C.RL_STATIC_READ 67 | STATIC_COPY: C.RL_STATIC_COPY 68 | DYNAMIC_DRAW: C.RL_DYNAMIC_DRAW 69 | DYNAMIC_READ: C.RL_DYNAMIC_READ 70 | DYNAMIC_COPY: C.RL_DYNAMIC_COPY 71 | FRAGMENT_SHADER: C.RL_FRAGMENT_SHADER 72 | VERTEX_SHADER: C.RL_VERTEX_SHADER 73 | COMPUTE_SHADER: C.RL_COMPUTE_SHADER 74 | 75 | matrixMode: RLGL.rlMatrixMode 76 | pushMatrix: RLGL.rlPushMatrix 77 | popMatrix: RLGL.rlPopMatrix 78 | loadIdentity: RLGL.rlLoadIdentity 79 | translatef: RLGL.rlTranslatef 80 | rotatef: RLGL.rlRotatef 81 | scalef: RLGL.rlScalef 82 | multMatrixf: RLGL.rlMultMatrixf 83 | frustum: RLGL.rlFrustum 84 | ortho: RLGL.rlOrtho 85 | viewport: RLGL.rlViewport 86 | begin: RLGL.rlBegin 87 | end: RLGL.rlEnd 88 | done: RLGL.rlEnd 89 | vertex2i: RLGL.rlVertex2i 90 | vertex2f: RLGL.rlVertex2f 91 | vertex3f: RLGL.rlVertex3f 92 | texCoord2f: RLGL.rlTexCoord2f 93 | normal3f: RLGL.rlNormal3f 94 | color4ub: RLGL.rlColor4ub 95 | color3f: RLGL.rlColor3f 96 | color4f: RLGL.rlColor4f 97 | enableVertexArray: RLGL.rlEnableVertexArray 98 | disableVertexArray: RLGL.rlDisableVertexArray 99 | enableVertexBuffer: RLGL.rlEnableVertexBuffer 100 | disableVertexBuffer: RLGL.rlDisableVertexBuffer 101 | enableVertexBufferElement: RLGL.rlEnableVertexBufferElement 102 | disableVertexBufferElement: RLGL.rlDisableVertexBufferElement 103 | enableVertexAttribute: RLGL.rlEnableVertexAttribute 104 | disableVertexAttribute: RLGL.rlDisableVertexAttribute 105 | activeTextureSlot: RLGL.rlActiveTextureSlot 106 | enableTexture: RLGL.rlEnableTexture 107 | disableTexture: RLGL.rlDisableTexture 108 | enableTextureCubemap: RLGL.rlEnableTextureCubemap 109 | disableTextureCubemap: RLGL.rlDisableTextureCubemap 110 | textureParameters: RLGL.rlTextureParameters 111 | enableShader: RLGL.rlEnableShader 112 | disableShader: RLGL.rlDisableShader 113 | enableFramebuffer: RLGL.rlEnableFramebuffer 114 | disableFramebuffer: RLGL.rlDisableFramebuffer 115 | activeDrawBuffers: RLGL.rlActiveDrawBuffers 116 | enableColorBlend: RLGL.rlEnableColorBlend 117 | disableColorBlend: RLGL.rlDisableColorBlend 118 | enableDepthTest: RLGL.rlEnableDepthTest 119 | disableDepthTest: RLGL.rlDisableDepthTest 120 | enableDepthMask: RLGL.rlEnableDepthMask 121 | disableDepthMask: RLGL.rlDisableDepthMask 122 | enableBackfaceCulling: RLGL.rlEnableBackfaceCulling 123 | disableBackfaceCulling: RLGL.rlDisableBackfaceCulling 124 | enableScissorTest: RLGL.rlEnableScissorTest 125 | disableScissorTest: RLGL.rlDisableScissorTest 126 | scissor: RLGL.rlScissor 127 | enableWireMode: RLGL.rlEnableWireMode 128 | disableWireMode: RLGL.rlDisableWireMode 129 | setLineWidth: RLGL.rlSetLineWidth 130 | getLineWidth: RLGL.rlGetLineWidth 131 | enableSmoothLines: RLGL.rlEnableSmoothLines 132 | disableSmoothLines: RLGL.rlDisableSmoothLines 133 | enableStereoRender: RLGL.rlEnableStereoRender 134 | disableStereoRender: RLGL.rlDisableStereoRender 135 | isStereoRenderEnabled: RLGL.rlIsStereoRenderEnabled 136 | clearColor: RLGL.rlClearColor 137 | clearScreenBuffers: RLGL.rlClearScreenBuffers 138 | checkErrors: RLGL.rlCheckErrors 139 | setBlendMode: RLGL.rlSetBlendMode 140 | setBlendFactors: RLGL.rlSetBlendFactors 141 | init: RLGL.rlglInit 142 | close: RLGL.rlglClose 143 | loadExtensions: RLGL.rlLoadExtensions 144 | getVersion: RLGL.rlGetVersion 145 | getFramebufferWidth: RLGL.rlGetFramebufferWidth 146 | getFramebufferHeight: RLGL.rlGetFramebufferHeight 147 | getTextureIdDefault: RLGL.rlGetTextureIdDefault 148 | getShaderIdDefault: RLGL.rlGetShaderIdDefault 149 | getShaderLocsDefault: RLGL.rlGetShaderLocsDefault 150 | loadRenderBatch: RLGL.rlLoadRenderBatch 151 | unloadRenderBatch: RLGL.rlUnloadRenderBatch 152 | drawRenderBatch: RLGL.rlDrawRenderBatch 153 | setRenderBatchActive: RLGL.rlSetRenderBatchActive 154 | drawRenderBatchActive: RLGL.rlDrawRenderBatchActive 155 | checkRenderBatchLimit: RLGL.rlCheckRenderBatchLimit 156 | setTexture: RLGL.rlSetTexture 157 | loadVertexArray: RLGL.rlLoadVertexArray 158 | loadVertexBuffer: RLGL.rlLoadVertexBuffer 159 | loadVertexBufferElement: RLGL.rlLoadVertexBufferElement 160 | updateVertexBuffer: RLGL.rlUpdateVertexBuffer 161 | unloadVertexArray: RLGL.rlUnloadVertexArray 162 | unloadVertexBuffer: RLGL.rlUnloadVertexBuffer 163 | setVertexAttribute: RLGL.rlSetVertexAttribute 164 | setVertexAttributeDivisor: RLGL.rlSetVertexAttributeDivisor 165 | setVertexAttributeDefault: RLGL.rlSetVertexAttributeDefault 166 | drawVertexArray: RLGL.rlDrawVertexArray 167 | drawVertexArrayElements: RLGL.rlDrawVertexArrayElements 168 | drawVertexArrayInstanced: RLGL.rlDrawVertexArrayInstanced 169 | drawVertexArrayElementsInstanced: RLGL.rlDrawVertexArrayElementsInstanced 170 | loadTexture: RLGL.rlLoadTexture 171 | loadTextureDepth: RLGL.rlLoadTextureDepth 172 | loadTextureCubemap: RLGL.rlLoadTextureCubemap 173 | updateTexture: RLGL.rlUpdateTexture 174 | getGlTextureFormats: RLGL.rlGetGlTextureFormats 175 | getPixelFormatName: RLGL.rlGetPixelFormatName 176 | unloadTexture: RLGL.rlUnloadTexture 177 | genTextureMipmaps: RLGL.rlGenTextureMipmaps 178 | readTexturePixels: RLGL.rlReadTexturePixels 179 | readScreenPixels: RLGL.rlReadScreenPixels 180 | loadFramebuffer: RLGL.rlLoadFramebuffer 181 | framebufferAttach: RLGL.rlFramebufferAttach 182 | framebufferComplete: RLGL.rlFramebufferComplete 183 | unloadFramebuffer: RLGL.rlUnloadFramebuffer 184 | loadShaderCode: RLGL.rlLoadShaderCode 185 | compileShader: RLGL.rlCompileShader 186 | loadShaderProgram: RLGL.rlLoadShaderProgram 187 | unloadShaderProgram: RLGL.rlUnloadShaderProgram 188 | getLocationUniform: RLGL.rlGetLocationUniform 189 | getLocationAttrib: RLGL.rlGetLocationAttrib 190 | setUniform: RLGL.rlSetUniform 191 | setUniformMatrix: RLGL.rlSetUniformMatrix 192 | setUniformSampler: RLGL.rlSetUniformSampler 193 | setShader: RLGL.rlSetShader 194 | loadComputeShaderProgram: RLGL.rlLoadComputeShaderProgram 195 | computeShaderDispatch: RLGL.rlComputeShaderDispatch 196 | loadShaderBuffer: RLGL.rlLoadShaderBuffer 197 | unloadShaderBuffer: RLGL.rlUnloadShaderBuffer 198 | updateShaderBufferElements: RLGL.rlUpdateShaderBufferElements 199 | getShaderBufferSize: RLGL.rlGetShaderBufferSize 200 | readShaderBufferElements: RLGL.rlReadShaderBufferElements 201 | bindShaderBuffer: RLGL.rlBindShaderBuffer 202 | copyBuffersElements: RLGL.rlCopyBuffersElements 203 | bindImageTexture: RLGL.rlBindImageTexture 204 | getMatrixModelview: RLGL.rlGetMatrixModelview 205 | getMatrixProjection: RLGL.rlGetMatrixProjection 206 | getMatrixTransform: RLGL.rlGetMatrixTransform 207 | getMatrixProjectionStereo: RLGL.rlGetMatrixProjectionStereo 208 | getMatrixViewOffsetStereo: RLGL.rlGetMatrixViewOffsetStereo 209 | setMatrixProjection: RLGL.rlSetMatrixProjection 210 | setMatrixModelview: RLGL.rlSetMatrixModelview 211 | setMatrixProjectionStereo: RLGL.rlSetMatrixProjectionStereo 212 | setMatrixViewOffsetStereo: RLGL.rlSetMatrixViewOffsetStereo 213 | loadDrawCube: RLGL.rlLoadDrawCube 214 | loadDrawQuad: RLGL.rlLoadDrawQuad 215 | } 216 | -------------------------------------------------------------------------------- /lib/math/Matrix.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import sqrt, sin, cos, tan from math 3 | 4 | Matrix = ffi.typeof('Matrix') 5 | ArrayType = ffi.typeof('float[16]') 6 | 7 | macro makeResult = -> [[ 8 | if @ 9 | @set( 10 | m0, m4, m8, m12, 11 | m1, m5, m9, m13, 12 | m2, m6, m10, m14, 13 | m3, m7, m11, m15 14 | ) 15 | else 16 | Matrix( 17 | m0, m4, m8, m12, 18 | m1, m5, m9, m13, 19 | m2, m6, m10, m14, 20 | m3, m7, m11, m15 21 | ) 22 | ]] 23 | 24 | macro storeResult = -> [[ 25 | with target 26 | .m0, .m4, .m8, .m12 = m0, m4, m8, m12 27 | .m1, .m5, .m9, .m13 = m1, m5, m9, m13 28 | .m2, .m6, .m10, .m14 = m2, m6, m10, m14 29 | .m3, .m7, .m11, .m15 = m3, m7, m11, m15 30 | target 31 | ]] 32 | 33 | MatrixMT = { 34 | identity: => 35 | m0, m4, m8, m12 = 1, 0, 0, 0 36 | m1, m5, m9, m13 = 0, 1, 0, 0 37 | m2, m6, m10, m14 = 0, 0, 1, 0 38 | m3, m7, m11, m15 = 0, 0, 0, 1 39 | 40 | $makeResult! 41 | 42 | set: (@m0, @m4, @m8, @m12, @m1, @m5, @m9, @m13, @m2, @m6, @m10, @m14, @m3, @m7, @m11, @m15) => @ 43 | 44 | copy: (m) => 45 | if not m 46 | @, m = nil, @ 47 | 48 | m0, m4, m8, m12 = m.m0, m.m4, m.m8, m.m12 49 | m1, m5, m9, m13 = m.m1, m.m5, m.m9, m.m13 50 | m2, m6, m10, m14 = m.m2, m.m6, m.m10, m.m14 51 | m3, m7, m11, m15 = m.m3, m.m7, m.m11, m.m15 52 | 53 | $makeResult! 54 | 55 | translate: (x, y, z) => 56 | if type(@) ~= 'cdata' 57 | @, x, y, z = nil, @, x, y 58 | 59 | m0, m4, m8, m12 = 1, 0, 0, x 60 | m1, m5, m9, m13 = 0, 1, 0, y 61 | m2, m6, m10, m14 = 0, 0, 1, z 62 | m3, m7, m11, m15 = 0, 0, 0, 1 63 | 64 | $makeResult! 65 | 66 | rotate: (axis, angle) => 67 | if type(@) ~= 'cdata' 68 | @, axis, angle = nil, @, axis 69 | 70 | { :x, :y, :z } = axis 71 | lenSq = axis::lengthSquared! 72 | 73 | if lenSq ~= 1 and lengthSq ~= 0 74 | ilen = 1 / sqrt(lengthSq) 75 | x, y, z = x * ilen, y * ilen, z * ilen 76 | 77 | sn, cs = sin(angle), cos(angle) 78 | t = 1 - cs 79 | 80 | m0, m4, m8, m12 = x * x * t + cs, x * y * t - z * sn, x * z * t + y * sn, 0 81 | m1, m5, m9, m13 = y * x * t + z * sn, y * y * t + cs, y * z * t - x * sn, 0 82 | m2, m6, m10, m14 = z * x * t - y * sn, z * y * t + x * sn, z * z * t + cs, 0 83 | m3, m7, m11, m15 = 0, 0, 0, 1 84 | 85 | $makeResult! 86 | 87 | rotateX: (angle) => 88 | if type(@) ~= 'cdata' 89 | @, angle = nil, @ 90 | 91 | sn, cs = sin(angle), cos(angle) 92 | m0, m4, m8, m12 = 1, 0, 0, 0 93 | m1, m5, m9, m13 = 0, cs, sn, 0 94 | m2, m6, m10, m14 = 0, -sn, cs, 0 95 | m3, m7, m11, m15 = 0, 0, 0, 1 96 | 97 | $makeResult! 98 | 99 | rotateY: (angle) => 100 | if type(@) ~= 'cdata' 101 | @, angle = nil, @ 102 | 103 | sn, cs = sin(angle), cos(angle) 104 | m0, m4, m8, m12 = cs, 0, -sn, 0 105 | m1, m5, m9, m13 = 0, 1, 0, 0 106 | m2, m6, m10, m14 = sn, 0, cs, 0 107 | m3, m7, m11, m15 = 0, 0, 0, 1 108 | 109 | $makeResult! 110 | 111 | rotateZ: (angle) => 112 | if type(@) ~= 'cdata' 113 | @, angle = nil, @ 114 | 115 | sn, cs = sin(angle), cos(angle) 116 | m0, m4, m8, m12 = cs, sn, 0, 0 117 | m1, m5, m9, m13 = -sn, cs, 0, 0 118 | m2, m6, m10, m14 = 0, 0, 1, 0 119 | m3, m7, m11, m15 = 0, 0, 0, 1 120 | 121 | $makeResult! 122 | 123 | rotateXYZ: (angles) => 124 | if type(@) ~= 'cdata' 125 | @, angles = nil, @ 126 | 127 | cx, sx = cos(-angles.x), sin(-angles.x) 128 | cy, sy = cos(-angles.y), sin(-angles.y) 129 | cz, sz = cos(-angles.z), sin(-angles.z) 130 | m0, m4, m8, m12 = cz * cy, cz * sy * sx - sz * cx, cz * sy * cx + sz * sx, 0 131 | m1, m5, m9, m13 = sz * cy, sz * sy * sx + cz * cx, sz * sy * cx - cz * sx, 0 132 | m2, m6, m10, m14 = -sy, cy * sx, cy * cx, 0 133 | m3, m7, m11, m15 = 0, 0, 0, 1 134 | 135 | $makeResult! 136 | 137 | rotateZYX: (angles) => 138 | if type(@) ~= 'cdata' 139 | @, angles = nil, @ 140 | 141 | cx, sx = cos(angles.x), sin(angles.x) 142 | cy, sy = cos(angles.y), sin(angles.y) 143 | cz, sz = cos(angles.z), sin(angles.z) 144 | m0, m4, m8, m12 = cz * cy, cy * sz, -sy, 0 145 | m1, m5, m9, m13 = cz * sy * sx - cx * sz, cz * cx + sz * sy * sx, cy * sx, 0 146 | m2, m6, m10, m14 = sz * sx + cz * cx * sy, cx * sz * sy - cz * sx, cy * cx, 0 147 | m3, m7, m11, m15 = 0, 0, 0, 1 148 | 149 | $makeResult! 150 | 151 | scale: (x, y, z) => 152 | if type(@) ~= 'cdata' 153 | @, x, y, z = nil, @, x, y 154 | 155 | m0, m4, m8, m12 = x, 0, 0, 0 156 | m1, m5, m9, m13 = 0, y, 0, 0 157 | m2, m6, m10, m14 = 0, 0, z, 0 158 | m3, m7, m11, m15 = 0, 0, 0, 1 159 | 160 | $makeResult! 161 | 162 | frustum: (left, right, bottom, top, near, far) => 163 | if type(@) ~= 'cdata' 164 | @, left, right, bottom, top, near, far = nil, @, left, right, bottom, top, near 165 | 166 | rl = right - left 167 | tb = top - bottom 168 | fn = far - near 169 | m0, m4, m8, m12 = (near * 2) / rl, 0, (right + left) / rl, 0 170 | m1, m5, m9, m13 = 0, (near * 2) / tb, (top + bottom) / tb, 0 171 | m2, m6, m10, m14 = 0, 0, -(far + near) / fn, -(far * near * 2) / fn 172 | m3, m7, m11, m15 = 0, 0, -1, 0 173 | 174 | $makeResult! 175 | 176 | perspective: (fovy, aspect, near, far) => 177 | if type(@) ~= 'cdata' 178 | @, fovy, aspect, near, far = nil, @, fovy, aspect, near 179 | 180 | top = near * tan(fovy * .5) 181 | right = top * aspect 182 | Matrix.frustum(@, -right, right, -top, top, near, far) 183 | 184 | ortho: (left, right, bottom, top, near, far) => 185 | if type(@) ~= 'cdata' 186 | @, left, right, bottom, top, near, far = nil, @, left, right, bottom, top, near 187 | 188 | rl = right - left 189 | tb = top - bottom 190 | fn = far - near 191 | m0, m4, m8, m12 = 2 / rl, 0, 0, -(left + right ) / rl 192 | m1, m5, m9, m13 = 0, 2 / tb, 0, -(top + bottom ) / tb 193 | m2, m6, m10, m14 = 0, 0, -2 / fn, -(far + near ) / fn 194 | m3, m7, m11, m15 = 0, 0, 0, 1 195 | 196 | $makeResult! 197 | 198 | lookAt: (eye, target, up) => 199 | if type(@) ~= 'cdata' 200 | @, eye, target, up = nil, @, eye, target 201 | 202 | vz = eye::subtract(target)::normalize! 203 | vx = up::crossProduct(vz)::normalize! 204 | vy = vz::crossProduct(vx) 205 | ex, ey, ez = vx::dotProduct(eye), vy::dotProduct(eye), vz::dotProduct(eye) 206 | m0, m4, m8, m12 = vx.x, vx.y, vx.z, -ex 207 | m1, m5, m9, m13 = vy.x, vy.y, vy.z, -ey 208 | m2, m6, m10, m14 = vz.x, vz.y, vz.z, -ez 209 | m3, m7, m11, m15 = 0, 0, 0, 1 210 | 211 | $makeResult! 212 | 213 | affine2D: (x, y, a, sx, sy, ox, oy, kx, ky) => 214 | if type(@) ~= 'cdata' 215 | @, x, y, a, sx, sy, ox, oy, kx, ky = nil, @, x, y, a, sx, sy, ox, oy, kx 216 | 217 | cs, sn = cos(a), sin(a) 218 | m0 = cs * sx - ky * sn * sy 219 | m1 = sn * sx + ky * cs * sy 220 | m2, m3 = 0, 0 221 | m4 = kx * cs * sx - sn * sy 222 | m5 = kx * sn * sx + cs * sy 223 | m6, m7 = 0, 0 224 | m8, m9, m10, m11 = 0, 0, 1, 0 225 | m12 = x - ox * m0 - oy * m4 226 | m13 = y - ox * m1 - oy * m5 227 | m14, m15 = 0, 1 228 | 229 | $makeResult! 230 | 231 | __tostring: => 'Matrix(%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f)'::format( 232 | @m0, @m4, @m8, @m12, 233 | @m1, @m5, @m9, @m13, 234 | @m2, @m6, @m10, @m14, 235 | @m3, @m7, @m11, @m15 236 | ) 237 | 238 | add: (rhs, target = @) => 239 | m0, m4, m8, m12 = @m0 + rhs.m0, @m4 + rhs.m4, @m8 + rhs.m8, @m12 + rhs.m12 240 | m1, m5, m9, m13 = @m1 + rhs.m1, @m5 + rhs.m5, @m9 + rhs.m9, @m13 + rhs.m13 241 | m2, m6, m10, m14 = @m2 + rhs.m2, @m6 + rhs.m6, @m10 + rhs.m10, @m14 + rhs.m14 242 | m3, m7, m11, m15 = @m3 + rhs.m3, @m7 + rhs.m7, @m11 + rhs.m11, @m15 + rhs.m15 243 | 244 | $storeResult! 245 | 246 | subtract: (rhs, target = @) => 247 | m0, m4, m8, m12 = @m0 - rhs.m0, @m4 - rhs.m4, @m8 - rhs.m8, @m12 - rhs.m12 248 | m1, m5, m9, m13 = @m1 - rhs.m1, @m5 - rhs.m5, @m9 - rhs.m9, @m13 - rhs.m13 249 | m2, m6, m10, m14 = @m2 - rhs.m2, @m6 - rhs.m6, @m10 - rhs.m10, @m14 - rhs.m14 250 | m3, m7, m11, m15 = @m3 - rhs.m3, @m7 - rhs.m7, @m11 - rhs.m11, @m15 - rhs.m15 251 | 252 | $storeResult! 253 | 254 | multiply: (rhs, target = @) => 255 | m0 = rhs.m0 * @m0 + rhs.m4 * @m1 + rhs.m8 * @m2 + rhs.m12 * @m3 256 | m4 = rhs.m0 * @m4 + rhs.m4 * @m5 + rhs.m8 * @m6 + rhs.m12 * @m7 257 | m8 = rhs.m0 * @m8 + rhs.m4 * @m9 + rhs.m8 * @m10 + rhs.m12 * @m11 258 | m12 = rhs.m0 * @m12 + rhs.m4 * @m13 + rhs.m8 * @m14 + rhs.m12 * @m15 259 | m1 = rhs.m1 * @m0 + rhs.m5 * @m1 + rhs.m9 * @m2 + rhs.m13 * @m3 260 | m5 = rhs.m1 * @m4 + rhs.m5 * @m5 + rhs.m9 * @m6 + rhs.m13 * @m7 261 | m9 = rhs.m1 * @m8 + rhs.m5 * @m9 + rhs.m9 * @m10 + rhs.m13 * @m11 262 | m13 = rhs.m1 * @m12 + rhs.m5 * @m13 + rhs.m9 * @m14 + rhs.m13 * @m15 263 | m2 = rhs.m2 * @m0 + rhs.m6 * @m1 + rhs.m10 * @m2 + rhs.m14 * @m3 264 | m6 = rhs.m2 * @m4 + rhs.m6 * @m5 + rhs.m10 * @m6 + rhs.m14 * @m7 265 | m10 = rhs.m2 * @m8 + rhs.m6 * @m9 + rhs.m10 * @m10 + rhs.m14 * @m11 266 | m14 = rhs.m2 * @m12 + rhs.m6 * @m13 + rhs.m10 * @m14 + rhs.m14 * @m15 267 | m3 = rhs.m3 * @m0 + rhs.m7 * @m1 + rhs.m11 * @m2 + rhs.m15 * @m3 268 | m7 = rhs.m3 * @m4 + rhs.m7 * @m5 + rhs.m11 * @m6 + rhs.m15 * @m7 269 | m11 = rhs.m3 * @m8 + rhs.m7 * @m9 + rhs.m11 * @m10 + rhs.m15 * @m11 270 | m15 = rhs.m3 * @m12 + rhs.m7 * @m13 + rhs.m11 * @m14 + rhs.m15 * @m15 271 | 272 | $storeResult! 273 | 274 | determinant: => 275 | @m12 * @m9 * @m6 * @m3 - @m8 * @m13 * @m6 * @m3 - @m12 * @m5 * @m10 * @m3 + @m4 * @m13 * @m10 * @m3 + 276 | @m8 * @m5 * @m14 * @m3 - @m4 * @m9 * @m14 * @m3 - @m12 * @m9 * @m2 * @m7 + @m8 * @m13 * @m2 * @m7 + 277 | @m12 * @m1 * @m10 * @m7 - @m0 * @m13 * @m10 * @m7 - @m8 * @m1 * @m14 * @m7 + @m0 * @m9 * @m14 * @m7 + 278 | @m12 * @m5 * @m2 * @m11 - @m4 * @m13 * @m2 * @m11 - @m12 * @m1 * @m6 * @m11 + @m0 * @m13 * @m6 * @m11 + 279 | @m4 * @m1 * @m14 * @m11 - @m0 * @m5 * @m14 * @m11 - @m8 * @m5 * @m2 * @m15 + @m4 * @m9 * @m2 * @m15 + 280 | @m8 * @m1 * @m6 * @m15 - @m0 * @m9 * @m6 * @m15 - @m4 * @m1 * @m10 * @m15 + @m0 * @m5 * @m10 * @m15 281 | 282 | trace: => @m0 + @m5 + @m10 + @m15 283 | 284 | transpose: (target = @) => 285 | m0, m4, m8, m12 = @m0, @m1, @m2, @m3 286 | m1, m5, m9, m13 = @m4, @m5, @m6, @m7 287 | m2, m6, m10, m14 = @m8, @m9, @m10, @m11 288 | m3, m7, m11, m15 = @m12, @m13, @m14, @m15 289 | 290 | $storeResult! 291 | 292 | invert: (target = @) => 293 | b00 = @m0 * @m5 - @m1 * @m4 294 | b01 = @m0 * @m6 - @m2 * @m4 295 | b02 = @m0 * @m7 - @m3 * @m4 296 | b03 = @m1 * @m6 - @m2 * @m5 297 | b04 = @m1 * @m7 - @m3 * @m5 298 | b05 = @m2 * @m7 - @m3 * @m6 299 | b06 = @m8 * @m13 - @m9 * @m12 300 | b07 = @m8 * @m14 - @m10 * @m12 301 | b08 = @m8 * @m15 - @m11 * @m12 302 | b09 = @m9 * @m14 - @m10 * @m13 303 | b10 = @m9 * @m15 - @m11 * @m13 304 | b11 = @m10 * @m15 - @m11 * @m14 305 | 306 | invDet = 1 / (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06) 307 | 308 | m0 = ( @m5 * b11 - @m6 * b10 + @m7 * b09) * invDet 309 | m1 = ( -@m1 * b11 + @m2 * b10 - @m3 * b09) * invDet 310 | m2 = ( @m13 * b05 - @m14 * b04 + @m15 * b03) * invDet 311 | m3 = ( -@m9 * b05 + @m10 * b04 - @m11 * b03) * invDet 312 | m4 = ( -@m4 * b11 + @m6 * b08 - @m7 * b07) * invDet 313 | m5 = ( @m0 * b11 - @m2 * b08 + @m3 * b07) * invDet 314 | m6 = (-@m12 * b05 + @m14 * b02 - @m15 * b01) * invDet 315 | m7 = ( @m8 * b05 - @m10 * b02 + @m11 * b01) * invDet 316 | m8 = ( @m4 * b10 - @m5 * b08 + @m7 * b06) * invDet 317 | m9 = ( -@m0 * b10 + @m1 * b08 - @m3 * b06) * invDet 318 | m10 = ( @m12 * b04 - @m13 * b02 + @m15 * b00) * invDet 319 | m11 = ( -@m8 * b04 + @m9 * b02 - @m11 * b00) * invDet 320 | m12 = ( -@m4 * b09 + @m5 * b07 - @m6 * b06) * invDet 321 | m13 = ( @m0 * b09 - @m1 * b07 + @m2 * b06) * invDet 322 | m14 = (-@m12 * b03 + @m13 * b01 - @m14 * b00) * invDet 323 | m15 = ( @m8 * b03 - @m9 * b01 + @m10 * b00) * invDet 324 | 325 | $storeResult! 326 | 327 | normalize: => 328 | det = @m12 * @m9 * @m6 * @m3 - @m8 * @m13 * @m6 * @m3 - @m12 * @m5 * @m10 * @m3 + @m4 * @m13 * @m10 * @m3 + 329 | @m8 * @m5 * @m14 * @m3 - @m4 * @m9 * @m14 * @m3 - @m12 * @m9 * @m2 * @m7 + @m8 * @m13 * @m2 * @m7 + 330 | @m12 * @m1 * @m10 * @m7 - @m0 * @m13 * @m10 * @m7 - @m8 * @m1 * @m14 * @m7 + @m0 * @m9 * @m14 * @m7 + 331 | @m12 * @m5 * @m2 * @m11 - @m4 * @m13 * @m2 * @m11 - @m12 * @m1 * @m6 * @m11 + @m0 * @m13 * @m6 * @m11 + 332 | @m4 * @m1 * @m14 * @m11 - @m0 * @m5 * @m14 * @m11 - @m8 * @m5 * @m2 * @m15 + @m4 * @m9 * @m2 * @m15 + 333 | @m8 * @m1 * @m6 * @m15 - @m0 * @m9 * @m6 * @m15 - @m4 * @m1 * @m10 * @m15 + @m0 * @m5 * @m10 * @m15 334 | 335 | m0, m4, m8, m12 = @m0 / det, @m4 / det, @m8 / det, @m12 / det 336 | m1, m5, m9, m13 = @m1 / det, @m5 / det, @m9 / det, @m13 / det 337 | m2, m6, m10, m14 = @m2 / det, @m6 / det, @m10 / det, @m14 / det 338 | m3, m7, m11, m15 = @m3 / det, @m7 / det, @m11 / det, @m15 / det 339 | 340 | $storeResult! 341 | 342 | fromFloatV: (v) => 343 | if not v 344 | @, v = nil, @ 345 | 346 | m0, m4, m8, m12 = v[0], v[4], v[8], v[12] 347 | m1, m5, m9, m13 = v[1], v[5], v[9], v[13] 348 | m2, m6, m10, m14 = v[2], v[6], v[10], v[11] 349 | m3, m7, m11, m15 = v[3], v[7], v[11], v[15] 350 | 351 | $makeResult! 352 | 353 | toFloatV: (v) => 354 | v or= ArrayType! 355 | v[0], v[4], v[8], v[12] = @m0, @m4, @m8, @m12 356 | v[1], v[5], v[9], v[13] = @m1, @m5, @m9, @m13 357 | v[2], v[6], v[10], v[11] = @m2, @m6, @m10, @m14 358 | v[3], v[7], v[11], v[15] = @m3, @m7, @m11, @m15 359 | v 360 | } 361 | 362 | MatrixMT.__index = MatrixMT 363 | 364 | ffi.metatype(Matrix, MatrixMT) 365 | -------------------------------------------------------------------------------- /lib/math/Quaternion.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import 'lib.math.Matrix' 3 | import 'lib.math.Vector3' 4 | import sqrt, abs, acos, asin, sin, cos, atan2, min, max from math 5 | 6 | Quaternion = ffi.typeof('Quaternion') 7 | 8 | QuaternionMT = { 9 | identity: -> Quaternion(0, 0, 0, 1) 10 | 11 | fromVector3ToVector3: (v1, v2) -> 12 | cos2Theta = v1::dotProduct(v2) 13 | cross = v1:crossProduct(v2) 14 | Quaternion(cross.x, cross.y, cross.z, 1 + cos2Theta)::normalize! 15 | 16 | fromMatrix: (mat) -> 17 | if mat.m0 > mat.m5 and mat.m0 > mat.m10 18 | s = sqrt(1 + mat.m0 - mat.m5 - mat.m10) * 2 19 | return Quaternion( 20 | 0.25 * s, 21 | (mat.m4 + mat.m1) / s, 22 | (mat.m2 + mat.m8) / s, 23 | (mat.m9 - mat.m6) / s 24 | ) 25 | 26 | if mat.m5 > mat.m10 27 | s = sqrt(1 + mat.m5 - mat.m0 - mat.m10) * 2 28 | return Quaternion( 29 | (mat.m4 + mat.m1) / s, 30 | 0.25 * s, 31 | (mat.m9 + mat.m6) / s, 32 | (mat.m2 - mat.m8) / s 33 | ) 34 | 35 | s = sqrt(1 + mat.m10 - mat.m0 - mat.m5) * 2 36 | Quaternion( 37 | (mat.m2 + mat.m8) / s, 38 | (mat.m9 + mat.m6) / s, 39 | 0.25 * s, 40 | (mat.m4 - mat.m1) / s 41 | ) 42 | 43 | fromAxisAngle: (axis, angle) -> 44 | return Quaternion.identity! if axis::lengthSqr! == 0 45 | angle *= 0.5 46 | axis = axis::normalize! 47 | sn = sin(angle) 48 | Quaternion(axis.x * sn, axis.y * sn, axis.z * sn, cos(angle))::normalize! 49 | 50 | fromEuler: (pitch, yaw, roll) -> 51 | x0, x1 = cos(pitch * 0.5), sin(pitch * 0.5) 52 | y0, y1 = cos(yaw * 0.5), sin(yaw * 0.5) 53 | z0, z1 = cos(roll * 0.5), sin(roll * 0.5) 54 | Quaternion( 55 | x1 * y0 * z0 - x0 * y1 * z1, 56 | x0 * y1 * z0 + x1 * y0 * z1, 57 | x0 * y0 * z1 - x1 * y1 * z0, 58 | x0 * y0 * z0 + x1 * y1 * z1 59 | ) 60 | 61 | add: (rhs) => Quaternion(@x + rhs.x, @y + rhs.y, @z + rhs.z, @w + rhs.w) 62 | addValue: (val) => Quaternion(@x + val, @y + val, @z + val, @w + val) 63 | subtract: (rhs) => Quaternion(@x - rhs.x, @y - rhs.y, @z - rhs.z, @w - rhs.w) 64 | subtractValue: (val) => Quaternion(@x - val, @y - val, @z - val, @w - val) 65 | length: => sqrt(@x * @x + @y * @y + @z * @z + @w * @w) 66 | divide: (rhs) => Quaternion(@x / rhs.x, @y / rhs.y, @z / rhs.z, @w / rhs.w) 67 | 68 | normalize: => 69 | len = @length! 70 | len = 1 if len == 0 71 | Quaternion(@x / len, @y / len, @z / len, @w / len) 72 | 73 | invert: => 74 | x, y, z, w = @x, @y, @z, @w 75 | lenSq = x * x + y * y + z * z + w * w 76 | if lenSq ~= 0 77 | i = 1 / lenSq 78 | x, y, z, w = x * -i, y * -i, z * -i, w * i 79 | Quaternion(x, y, z, w) 80 | 81 | multiply: (rhs) => Quaternion( 82 | @x * rhs.w + @w * rhs.x + @y * rhs.z - @z * rhs.y, 83 | @y * rhs.w + @w * rhs.y + @z * rhs.x - @x * rhs.z, 84 | @z * rhs.w + @w * rhs.z + @x * rhs.y - @y * rhs.x, 85 | @w * rhs.w - @x * rhs.x - @y * rhs.y - @z * rhs.z 86 | ) 87 | 88 | scale: (rhs) => Quaternion( 89 | @x * rhs + @w * rhs + @y * rhs - @z * rhs, 90 | @y * rhs + @w * rhs + @z * rhs - @x * rhs, 91 | @z * rhs + @w * rhs + @x * rhs - @y * rhs, 92 | @w * rhs - @x * rhs - @y * rhs - @z * rhs 93 | ) 94 | 95 | lerp: (q, amount) => Quaternion( 96 | @x + amount * (q.x - @x), 97 | @y + amount * (q.y - @y), 98 | @z + amount * (q.z - @z), 99 | @w + amount * (q.w - @w) 100 | ) 101 | 102 | nlerp: (q, amount) => @lerp(q, amount)::normalize! 103 | 104 | slerp: (q, amount) => 105 | cosHalfTheta = @x * q.x + @y * q.y + @z * q.z + @w * q.w 106 | 107 | if cosHalfTheta < 0 108 | q.x, q.y, q.z, q.w = -q.x, -q.y, -q.z, -q.w 109 | cosHalfTheta = -cosHalfTheta 110 | 111 | if abs(cosHalfTheta) >= 1 112 | return Quaternion(@x, @y, @z, @w) 113 | elseif cosHalfTheta > 0.95 114 | return @nlerp(q, amount) 115 | 116 | halfTheta = acos(cosHalfTheta) 117 | sinHalfTheta = sqrt(1 - cosHalfTheta * cosHalfTheta) 118 | if abs(sinHalfTheta) < 0.001 119 | return Quaternion( 120 | @x * 0.5 + q.x * 0.5, 121 | @y * 0.5 + q.y * 0.5, 122 | @z * 0.5 + q.z * 0.5, 123 | @w * 0.5 + q.w * 0.5 124 | ) 125 | 126 | ratioA = sin((1 - amount) * halfTheta) / sinHalfTheta 127 | ratioB = sin(amount * halfTheta) / sinHalfTheta 128 | Quaternion( 129 | @x * ratioA + q.x * ratioB, 130 | @y * ratioA + q.y * ratioB, 131 | @z * ratioA + q.z * ratioB, 132 | @w * ratioA + q.w * ratioB 133 | ) 134 | 135 | transform: (mat) => Quaternion( 136 | mat.m0 * @x + mat.m4 * @y + mat.m8 * @z + mat.m12 * @w, 137 | mat.m1 * @x + mat.m5 * @y + mat.m9 * @z + mat.m13 * @w, 138 | mat.m2 * @x + mat.m6 * @y + mat.m10 * @z + mat.m14 * @w, 139 | mat.m3 * @x + mat.m7 * @y + mat.m11 * @z + mat.m15 * @w 140 | ) 141 | 142 | toMatrix: => 143 | a2, b2, c2 = @x * @x, @y * @y, @z * @z 144 | ac, ab, bc = @x * @z, @x * @y, @y * @z 145 | ad, bd, cd = @w * @x, @w * @y, @w * @z 146 | Matrix( 147 | 1 - 2 * (b2 + c2), 2 * (ab + cd), 2 * (ac - bd), 0, 148 | 2 * (ab - cd), 1 - 2 * (a2 + c2), 2 * (bc + ad), 0, 149 | 2 * (ac + bd), 2 * (bc - ad), 1 - 2 * (a2 + b2), 0, 150 | 0, 0, 0, 1 151 | ) 152 | 153 | toAxisAngle: => 154 | q = abs(@w) > 1 and @normalize! or @ 155 | angle = 2 * acos(q.w) 156 | den = sqrt(1 - q.w * q.w) 157 | if den > 0.0001 158 | return Vector3(q.x / den, q.y / den, q.z / den), angle 159 | 160 | Vector3(1, 0, 0), angle 161 | 162 | toEuler: => 163 | x = do 164 | x0 = 2 * (q.w * q.x + q.y * q.z) 165 | x1 = 1 - 2 * (q.x * q.x + q.y * q.y) 166 | atan2(x0, x1) 167 | 168 | y = do 169 | y0 = 2 * (q.w * q.y - q.z * q.x) 170 | y0 = max(-1, min(y0, 1)) 171 | asin(y0) 172 | 173 | z = do 174 | z0 = 2 * (q.w * q.z + q.x * q.y) 175 | z1 = 1 - 2 * (q.y * q.y + q.z * q.z) 176 | atan2(z0, z1) 177 | 178 | Vector3(x, y, z) 179 | 180 | __tostring: => 'Quaternion(%f, %f, %f, %f)'\format(@x, @y, @z, @w) 181 | } 182 | 183 | QuaternionMT.__index = QuaternionMT 184 | 185 | ffi.metatype(Quaternion, QuaternionMT) 186 | 187 | Quaternion 188 | -------------------------------------------------------------------------------- /lib/math/RNG.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import floor from math 3 | import 'bit' as { 4 | :lshift 5 | :rshift 6 | :bnot 7 | :bxor 8 | :bor 9 | } 10 | 11 | RNG = ffi.typeof('struct { uint64_t _seed, _state; }') 12 | 13 | -- Thomas Wang's 64-bit integer hashing function 14 | -- https://web.archive.org/web/20110807030012/http://www.cris.com/%7ETtwang/tech/inthash.htm 15 | wang = (key) -> 16 | key = bnot(key) + lshift(key, 21) 17 | key = bxor(key, rshift(key, 24)) 18 | key += lshift(key, 3) + lshift(key, 8) 19 | key = bxor(key, rshift(key, 14)) 20 | key += lshift(key, 2) + lshift(key, 4) 21 | key = bxor(key, rshift(key, 28)) 22 | key + lshift(key, 31) 23 | 24 | normalize = ffi.new('union { uint64_t i64; double d64; }') 25 | 26 | RNGMT = { 27 | __new: (seed = 0x178392ac8fe399b1ULL) => 28 | state = wang(ffi.cast('uint64_t', seed)) 29 | state = wang(state) if state == 0 30 | ffi.new(@, seed, state) 31 | 32 | random: (lo, hi) => 33 | state = @_state 34 | state = bxor(state, rshift(state, 12)) 35 | state = bxor(state, lshift(state, 25)) 36 | state = bxor(state, rshift(state, 27)) 37 | @_state = state 38 | 39 | normalize.i64 = bor(lshift(0x3ffULL, 52), rshift(state * 2685821657736338717ULL, 12)) 40 | r = normalize.d64 - 1 41 | if hi 42 | return floor(lo + r * (hi - lo + 1)) 43 | if lo 44 | return floor(1 + lo * r) 45 | r 46 | 47 | getState: => @_state 48 | 49 | setState: (@_state) => 50 | } 51 | RNGMT.__index = RNGMT 52 | 53 | ffi.metatype(RNG, RNGMT) 54 | -------------------------------------------------------------------------------- /lib/math/Vector2.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import sqrt, atan2, sin, cos from math 3 | 4 | Vector2 = ffi.typeof('Vector2') 5 | 6 | Vector2MT = { 7 | __tostring: => 'Vector2(%f, %f)'::format(@x, @y) 8 | 9 | zero: -> Vector2! 10 | one: -> Vector2(1, 1) 11 | 12 | add: (rhs) => Vector2(@x + rhs.x, @y + rhs.y) 13 | addValue: (val) => Vector2(@x + val, @y + val) 14 | subtract: (rhs) => Vector2(@x - rhs.x, @y - rhs.y) 15 | subtractValue: (val) => Vector2(@x - val, @y - val) 16 | length: => sqrt(@x * @x + @y * @y) 17 | lengthSqr: => @x * @x + @y * @y 18 | dotProduct: (rhs) => @x * rhs.x + @y * rhs.y 19 | angle: (rhs) => atan2(rhs.y, rhs.x) - atan2(@y, @x) 20 | scale: (val) => Vector2(@x * val, @y * val) 21 | multiply: (rhs) => Vector2(@x * rhs.x, @y * rhs.y) 22 | negate: => Vector2(-@x, -@y) 23 | divide: (rhs) => Vector2(@x / rhs.x, @y / rhs.y) 24 | 25 | distanceSqr: (rhs) => 26 | dx, dy = @x - rhs.x, @y - rhs.y 27 | dx * dx + dy * dy 28 | 29 | distance: (rhs) => 30 | dx, dy = @x - rhs.x, @y - rhs.y 31 | sqrt(dx * dx + dy * dy) 32 | 33 | normalize: => 34 | result = Vector2! 35 | len = sqrt(@x * @x + @y * @y) 36 | if len > 0 37 | result.x, result.y = @x / len, @y / len 38 | result 39 | 40 | transform: (mat) => Vector2( 41 | mat.m0 * @x + mat.m4 * @y + mat.m12, 42 | mat.m1 * @x + mat.m5 * @y + mat.m13 43 | ) 44 | 45 | lerp: (v, amount) => Vector2( 46 | @x + amount * (v.x - @x), 47 | @y + amount * (v.y - @y) 48 | ) 49 | 50 | reflect: (normal) => 51 | dot = @x * normal.x + @y * normal.y 52 | Vector2( 53 | @v.x - (2 * normal.x) * dot, 54 | @v.y - (2 * normal.y) * dot 55 | ) 56 | 57 | rotate: (angle) => 58 | sn, cs = sin(angle), cos(angle) 59 | Vector2( 60 | @x * cs - @y * sn, 61 | @x * sn + @y * cs 62 | ) 63 | 64 | moveTowards: (target, maxDistance) => 65 | dx, dy = target.x - @x, target.y - @y 66 | value = dx * dx + dy * dy 67 | 68 | result = Vector2(target) 69 | return result if value == 0 or (maxDistance >= 0 and value <= maxDistance * maxDistance) 70 | 71 | dist = sqrt(value) 72 | result.x, result.y = @x + dx / dist * maxDistance, @y + dy / dist * maxDistance 73 | result 74 | } 75 | 76 | Vector2MT.__index = Vector2MT 77 | 78 | ffi.metatype(Vector2, Vector2MT) 79 | -------------------------------------------------------------------------------- /lib/math/Vector3.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import sqrt, abs, atan2, min, max from math 3 | 4 | Vector3 = ffi.typeof('Vector3') 5 | 6 | Vector3MT = { 7 | __tostring: => 'Vector3(%f, %f, %f)'::format(@x, @y, @z) 8 | 9 | zero: -> Vector3! 10 | one: -> Vector3(1, 1, 1) 11 | 12 | set: (@x, @y, @z) => 13 | add: (rhs) => Vector3(@x + rhs.x, @y + rhs.y, @z + rhs.z) 14 | addValue: (val) => Vector3(@x + val, @y + val, @z + val) 15 | subtract: (rhs) => Vector3(@x - rhs.x, @y - rhs.y, @z - rhs.z) 16 | subtractValue: (val) => Vector3(@x - val, @y - val, @z - val) 17 | scale: (val) => Vector3(@x * val, @y * val, @z * val) 18 | multiply: (rhs) => Vector3(@x * rhs.x, @y * rhs.y, @z * rhs.z) 19 | divide: (rhs) => Vector3(@x / rhs.x, @y / rhs.y, @z / rhs.z) 20 | length: => sqrt(@x * @x + @y * @y + @z * @z) 21 | lengthSqr: => @x * @x + @y * @y + @z * @z 22 | dotProduct: (rhs) => @x * rhs.x + @y * rhs.y + @z * rhs.z 23 | angle: (rhs) => atan2(@crossProduct(rhs)::length!, @dotProduct(rhs)) 24 | negate: => Vector3(-@x, -@y, -@z) 25 | min: (rhs) => Vector3(min(@x, rhs.x), min(@y, rhs.y), min(@z, rhs.z)) 26 | max: (rhs) => Vector3(max(@x, rhs.x), max(@y, rhs.y), max(@z, rhs.z)) 27 | 28 | crossProduct: (rhs) => Vector3( 29 | @y * rhs.z - @z * rhs.y, 30 | @z * rhs.x - @x * rhs.z, 31 | @x * rhs.y - @y * rhs.x 32 | ) 33 | 34 | perpendicular: => 35 | cardinal = Vector3(1, 0, 0) 36 | 37 | lo = abs(@x) 38 | do 39 | ay = abs(@y) 40 | if ay < lo 41 | lo = ay 42 | cardinal::set(0, 1, 0) 43 | 44 | cardinal::set(0, 0, 1) if abs(@z) < lo 45 | 46 | @crossProduct(cardinal) 47 | 48 | distance: (rhs) => 49 | dx, dy, dy = @x - rhs.x, @y - rhs.y, @z - rhs.z 50 | sqrt(dx * dx + dy * dy + dz * dz) 51 | 52 | normalize: => 53 | len = @length! 54 | len = 1 if len == 0 55 | Vector3(@x / len, @y / len, @z / len) 56 | 57 | orthoNormalize: (rhs) => 58 | v = @normalize! 59 | vn1 = v::crossProduct(rhs)::normalize! 60 | vn2 = vn1::crossProduct(v) 61 | vn1, vn2 62 | 63 | transform: (mat) => Vector3( 64 | mat.m0 * @x + mat.m4 * @y + mat.m8 * @z + mat.m12, 65 | mat.m1 * @x + mat.m5 * @y + mat.m9 * @z + mat.m13, 66 | mat.m2 * @x + mat.m6 * @y + mat.m10 * @z + mat.m14 67 | ) 68 | 69 | rotateByQuaternion: (q) => 70 | { :x, :y, :z, :w } = q 71 | Vector3( 72 | @x * ( x * x + w * w - y * y - z * z) + @y * (2 * x * y - 2 * w * z) + @z * ( 2 * x * z + 2 * w * y), 73 | @x * ( 2 * w * z + 2 * x * y) + @y * (w * w - x * x + y * y - z * z) + @z * (-2 * w * x + 2 * y * z), 74 | @x * (-2 * w * y + 2 * x * z) + @y * (2 * w * x + 2 * y * z) + @z * ( w * w - x * x - y * y + z * z) 75 | ) 76 | 77 | lerp: (v, amount) => Vector3( 78 | @x + amount * (v.x - @x), 79 | @y + amount * (v.y - @y), 80 | @z + amount * (v.z - @z) 81 | ) 82 | 83 | reflect: (normal) => 84 | dot = @dotProduct(normal) 85 | Vector3( 86 | @x - (2 * normal.x) * dot, 87 | @y - (2 * normal.y) * dot, 88 | @z - (2 * normal.z) * dot 89 | ) 90 | 91 | barycenter: (a, b, c) => 92 | v0, v1, v2 = b::subtract(a), c::subtract(a), @subtract(a) 93 | 94 | d00 = v0::dotProduct(v0) 95 | d01 = v0::dotProduct(v1) 96 | d11 = v1::dotProduct(v1) 97 | d20 = v2::dotProduct(v0) 98 | d21 = v2::dotProduct(v1) 99 | 100 | denom = d00 * d11 - d01 * d01 101 | y = (d11 * d20 - d01 * d21) / denom 102 | z = (d00 * d21 - d01 * d20) / denom 103 | 104 | Vector3(1 - (z + y), y, z) 105 | 106 | unproject: (proj, view) => 107 | vp = view::multiply(proj)::invert! 108 | x = vp.m0 * @x + vp.m4 * @y + vp.m8 * @z + vp.m12 109 | y = vp.m1 * @x + vp.m5 * @y + vp.m9 * @z + vp.m13 110 | z = vp.m2 * @x + vp.m6 * @y + vp.m10 * @z + vp.m14 111 | w = vp.m3 * @x + vp.m7 * @y + vp.m11 * @z + vp.m15 112 | 113 | Vector3(x / w, y / w, z / w) 114 | 115 | toFloatV: => ffi.new('float[3]', @x, @y, @z) 116 | } 117 | 118 | Vector3MT.__index = Vector3MT 119 | 120 | ffi.metatype(Vector3, Vector3MT) 121 | -------------------------------------------------------------------------------- /lib/math/easings.yue: -------------------------------------------------------------------------------- 1 | -- MIT LICENSE 2 | -- 3 | -- Copyright (c) 2017 Enrique García Cota, Yuichi Tateno, Emmanuel Oga 4 | -- Copyright (c) 2021-2022 megagrump@pm.me 5 | -- 6 | -- Permission is hereby granted, free of charge, to any person obtaining a 7 | -- copy of this software and associated documentation files (the 8 | -- "Software"), to deal in the Software without restriction, including 9 | -- without limitation the rights to use, copy, modify, merge, publish, 10 | -- distribute, sublicense, and/or sell copies of the Software, and to 11 | -- permit persons to whom the Software is furnished to do so, subject to 12 | -- the following conditions: 13 | -- 14 | -- The above copyright notice and this permission notice shall be included 15 | -- in all copies or substantial portions of the Software. 16 | -- 17 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | -- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | -- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | -- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | -- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | -- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | -- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | import pow, sin, cos, pi, sqrt, abs, asin from math 26 | 27 | export linear = (t, b, c, d) -> c * t / d + b 28 | 29 | export inQuad = (t, b, c, d) -> c * pow(t / d, 2) + b 30 | 31 | export outQuad = (t, b, c, d) -> 32 | t = t / d 33 | -c * t * (t - 2) + b 34 | 35 | export inOutQuad = (t, b, c, d) -> 36 | t = t / d * 2 37 | return c / 2 * pow(t, 2) + b if t < 1 38 | -c / 2 * ((t - 1) * (t - 3) - 1) + b 39 | 40 | export outInQuad = (t, b, c, d) -> 41 | return outQuad(t * 2, b, c / 2, d) if t < d / 2 42 | inQuad((t * 2) - d, b + c / 2, c / 2, d) 43 | 44 | export inCubic = (t, b, c, d) -> c * pow(t / d, 3) + b 45 | 46 | export outCubic = (t, b, c, d) -> c * (pow(t / d - 1, 3) + 1) + b 47 | 48 | export inOutCubic = (t, b, c, d) -> 49 | t = t / d * 2 50 | return c / 2 * t * t * t + b if t < 1 51 | t = t - 2 52 | c / 2 * (t * t * t + 2) + b 53 | 54 | export outInCubic = (t, b, c, d) -> 55 | return outCubic(t * 2, b, c / 2, d) if t < d / 2 56 | inCubic((t * 2) - d, b + c / 2, c / 2, d) 57 | 58 | export inQuart = (t, b, c, d) -> c * pow(t / d, 4) + b 59 | 60 | export outQuart = (t, b, c, d) -> -c * (pow(t / d - 1, 4) - 1) + b 61 | 62 | export inOutQuart = (t, b, c, d) -> 63 | t = t / d * 2 64 | return c / 2 * pow(t, 4) + b if t < 1 65 | -c / 2 * (pow(t - 2, 4) - 2) + b 66 | 67 | export outInQuart = (t, b, c, d) -> 68 | return outQuart(t * 2, b, c / 2, d) if t < d / 2 69 | inQuart((t * 2) - d, b + c / 2, c / 2, d) 70 | 71 | export inQuint = (t, b, c, d) -> c * pow(t / d, 5) + b 72 | 73 | export outQuint = (t, b, c, d) -> c * (pow(t / d - 1, 5) + 1) + b 74 | 75 | export inOutQuint = (t, b, c, d) -> 76 | t = t / d * 2 77 | return c / 2 * pow(t, 5) + b if t < 1 78 | c / 2 * (pow(t - 2, 5) + 2) + b 79 | 80 | export outInQuint = (t, b, c, d) -> 81 | return outQuint(t * 2, b, c / 2, d) if t < d / 2 82 | inQuint((t * 2) - d, b + c / 2, c / 2, d) 83 | 84 | 85 | export inSine = (t, b, c, d) -> -c * cos(t / d * (pi / 2)) + c + b 86 | 87 | export outSine = (t, b, c, d) -> c * sin(t / d * (pi / 2)) + b 88 | 89 | export inOutSine = (t, b, c, d) -> -c / 2 * (cos(pi * t / d) - 1) + b 90 | 91 | export outInSine = (t, b, c, d) -> 92 | return outSine(t * 2, b, c / 2, d) if t < d / 2 93 | inSine((t * 2) - d, b + c / 2, c / 2, d) 94 | 95 | export inExpo = (t, b, c, d) -> 96 | return b if t == 0 97 | c * pow(2, 10 * (t / d - 1)) + b - c * 0.001 98 | 99 | export outExpo = (t, b, c, d) -> 100 | return b + c if t == d 101 | c * 1.001 * (-pow(2, -10 * t / d) + 1) + b 102 | 103 | export inOutExpo = (t, b, c, d) -> 104 | return b if t == 0 105 | return b + c if t == d 106 | t = t / d * 2 107 | return c / 2 * pow(2, 10 * (t - 1)) + b - c * 0.0005 if t < 1 108 | c / 2 * 1.0005 * (-pow(2, -10 * (t - 1)) + 2) + b 109 | 110 | export outInExpo = (t, b, c, d) -> 111 | return outExpo(t * 2, b, c / 2, d) if t < d / 2 112 | inExpo((t * 2) - d, b + c / 2, c / 2, d) 113 | 114 | export inCirc = (t, b, c, d) -> -c * (sqrt(1 - pow(t / d, 2)) - 1) + b 115 | 116 | export outCirc = (t, b, c, d) -> c * sqrt(1 - pow(t / d - 1, 2)) + b 117 | 118 | export inOutCirc = (t, b, c, d) -> 119 | t = t / d * 2 120 | return -c / 2 * (sqrt(1 - t * t) - 1) + b if t < 1 121 | t = t - 2 122 | c / 2 * (sqrt(1 - t * t) + 1) + b 123 | 124 | export outInCirc = (t, b, c, d) -> 125 | return outCirc(t * 2, b, c / 2, d) if t < d / 2 126 | inCirc((t * 2) - d, b + c / 2, c / 2, d) 127 | 128 | calculatePAS = (p, a, c, d) -> 129 | p, a = p or d * 0.3, a or 0 130 | return p, c, p / 4 if a < abs(c) 131 | p, a, p / (2 * pi) * asin(c/a) 132 | 133 | export inElastic = (t, b, c, d, a, p) -> 134 | return b if t == 0 135 | t = t / d 136 | return b + c if t == 1 137 | p, a, s = calculatePAS(p, a, c, d) 138 | t = t - 1 139 | -(a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b 140 | 141 | export outElastic = (t, b, c, d, a, p) -> 142 | return b if t == 0 143 | t = t / d 144 | return b + c if t == 1 145 | p, a, s = calculatePAS(p, a, c, d) 146 | a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p) + c + b 147 | 148 | export inOutElastic = (t, b, c, d, a, p) -> 149 | return b if t == 0 150 | t = t / d * 2 151 | return b + c if t == 2 152 | p, a, s = calculatePAS(p, a, c, d) 153 | t = t - 1 154 | return -0.5 * (a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b if t < 0 155 | a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p ) * 0.5 + c + b 156 | 157 | export outInElastic = (t, b, c, d, a, p) -> 158 | return outElastic(t * 2, b, c / 2, d, a, p) if t < d / 2 159 | inElastic((t * 2) - d, b + c / 2, c / 2, d, a, p) 160 | 161 | export inBack = (t, b, c, d, s) -> 162 | s = s or 1.70158 163 | t = t / d 164 | c * t * t * ((s + 1) * t - s) + b 165 | 166 | export outBack = (t, b, c, d, s) -> 167 | s = s or 1.70158 168 | t = t / d - 1 169 | c * (t * t * ((s + 1) * t + s) + 1) + b 170 | 171 | export inOutBack = (t, b, c, d, s) -> 172 | s = (s or 1.70158) * 1.525 173 | t = t / d * 2 174 | return c / 2 * (t * t * ((s + 1) * t - s)) + b if t < 1 175 | t = t - 2 176 | c / 2 * (t * t * ((s + 1) * t + s) + 2) + b 177 | 178 | export outInBack = (t, b, c, d, s) -> 179 | return outBack(t * 2, b, c / 2, d, s) if t < d / 2 180 | inBack((t * 2) - d, b + c / 2, c / 2, d, s) 181 | 182 | export outBounce = (t, b, c, d) -> 183 | t = t / d 184 | return c * (7.5625 * t * t) + b if t < 1 / 2.75 185 | if t < 2 / 2.75 186 | t = t - (1.5 / 2.75) 187 | return c * (7.5625 * t * t + 0.75) + b 188 | elseif t < 2.5 / 2.75 189 | t = t - (2.25 / 2.75) 190 | return c * (7.5625 * t * t + 0.9375) + b 191 | 192 | t = t - (2.625 / 2.75) 193 | c * (7.5625 * t * t + 0.984375) + b 194 | 195 | export inBounce = (t, b, c, d) -> c - outBounce(d - t, 0, c, d) + b 196 | 197 | export inOutBounce = (t, b, c, d) -> 198 | return inBounce(t * 2, 0, c, d) * 0.5 + b if t < d / 2 199 | outBounce(t * 2 - d, 0, c, d) * 0.5 + c * .5 + b 200 | 201 | export outInBounce = (t, b, c, d) -> 202 | return outBounce(t * 2, b, c / 2, d) if t < d / 2 203 | inBounce((t * 2) - d, b + c / 2, c / 2, d) 204 | -------------------------------------------------------------------------------- /lib/math/funcs.yue: -------------------------------------------------------------------------------- 1 | import pi, floor, ceil, min, max from math 2 | 3 | export tau = pi * 2 4 | 5 | export round = (n) -> n < 0 and ceil(n - .5) or floor(n + .5) 6 | 7 | export clamp = (n, lo, hi) -> min(hi, max(lo, n)) 8 | 9 | export lerp = (a, b, amount) -> a + (b - a) * amount 10 | 11 | export normalize = (value, lo, hi) -> (value - lo) / (hi - lo) 12 | 13 | export remap = (value, inLo, inHi, outLo, outHi) -> 14 | (value - inLo) / (inHi - inLo) * (outHi - outLo) + outLo 15 | 16 | export angleDirection = (frm, to) -> frm + ((to - frm + tau + pi) % tau) - pi 17 | -------------------------------------------------------------------------------- /lib/math/init.yue: -------------------------------------------------------------------------------- 1 | with { k, v for k, v in pairs(require('lib.math.funcs')) } 2 | .# = __index: math 3 | .Vector2 = require('lib.math.Vector2') 4 | .Vector3 = require('lib.math.Vector3') 5 | .Quaternion = require('lib.math.Quaternion') 6 | .Matrix = require('lib.math.Matrix') 7 | .RNG = require('lib.math.RNG') 8 | .noise2d = require('lib.math.noise2d') 9 | .noise3d = require('lib.math.noise3d') 10 | -------------------------------------------------------------------------------- /lib/math/noise2d.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import 'bit' as :band 3 | import floor, sqrt from math 4 | 5 | GRADX = ffi.new('double[12]', 1, -1, 1, -1, 1, -1, 1, -1, 0, 0, 0, 0) 6 | GRADY = ffi.new('double[12]', 1, 1, -1, -1, 0, 0, 0, 0, 1, -1, 1, -1) 7 | 8 | PERM = ffi.new('uint8_t[512]') 9 | do 10 | p = { 11 | 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 12 | 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 13 | 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 14 | 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 15 | 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 16 | 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 17 | 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 18 | 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 19 | 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 20 | 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 21 | 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 22 | 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 23 | 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 24 | 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 25 | 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 26 | 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, 27 | } 28 | PERM[i] = p[band(i, 255) + 1] for i = 0, 511 29 | 30 | G0 = .5 * (sqrt(3) - 1) 31 | G2 = (3 - sqrt(3)) / 6 32 | 33 | gradient = (i, x, y) -> GRADX[i % 12] * x + GRADY[i % 12] * y 34 | 35 | noise = (x, y) -> 36 | local x0, y0, i, j 37 | do 38 | s = (x + y) * G0 39 | i, j = floor(x + s), floor(y + s) 40 | t = (i + j) * G2 41 | x0, y0 = x - (i - t), y - (j - t) 42 | i, j = band(i, 255), band(j, 255) 43 | 44 | i1, j1 = x0 > y0 and 1 or 0, x0 > y0 and 0 or 1 45 | n = 0 46 | do 47 | t = .5 - x0 * x0 - y0 * y0 48 | if t > 0 49 | n = t * t * t * t * gradient(PERM[i + PERM[j]], x0, y0) 50 | 51 | do 52 | x1, y1 = x0 - i1 + G2, y0 - j1 + G2 53 | t = .5 - x1 * x1 - y1 * y1 54 | if t > 0 55 | n += t * t * t * t * gradient(PERM[i + i1 + PERM[j + j1]], x1, y1) 56 | 57 | do 58 | x2, y2 = x0 - 1 + 2 * G2, y0 - 1 + 2 * G2 59 | t = .5 - x2 * x2 - y2 * y2 60 | if t > 0 61 | n += t * t * t * t * gradient(PERM[i + 1 + PERM[j + 1]], x2, y2) 62 | 63 | 35 * n + .5 64 | 65 | noise 66 | -------------------------------------------------------------------------------- /lib/math/noise3d.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import 'bit' as :band 3 | import floor from math 4 | 5 | GRADX = ffi.new('double[12]', 1, -1, 1, -1, 1, -1, 1, -1, 0, 0, 0, 0) 6 | GRADY = ffi.new('double[12]', 1, 1, -1, -1, 0, 0, 0, 0, 1, -1, 1, -1) 7 | GRADZ = ffi.new('double[12]', 0, 0, 0, 0, 1, 1, -1, -1, 1, 1, -1, -1) 8 | 9 | PERM = ffi.new('uint8_t[512]') 10 | do 11 | p = { 12 | 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 13 | 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 14 | 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 15 | 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 16 | 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 17 | 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 18 | 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 19 | 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 20 | 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 21 | 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 22 | 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 23 | 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 24 | 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 25 | 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 26 | 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 27 | 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, 28 | } 29 | PERM[i] = p[band(i, 255) + 1] for i = 0, 511 30 | 31 | gradient = (i, x, y, z) -> GRADX[i % 12] * x + GRADY[i % 12] * y + GRADZ[i % 12] * z 32 | 33 | G3 = 1 / 6 34 | 35 | noise = (x, y, z) -> 36 | local i, j, k 37 | do 38 | s = (x + y + z) * (1 / 3) 39 | i, j, k = floor(x + s), floor(y + s), floor(z + s) 40 | 41 | local x0, y0, z0 42 | do 43 | t = (i + j + k) * G3 44 | X0, Y0, Z0 = i - t, j - t, k - t 45 | x0, y0, z0 = x - X0, y - Y0, z - Z0 46 | i, j, k = band(i, 255), band(j, 255), band(k, 255) 47 | 48 | i1, j1, k1, i2, j2, k2 = 0, 0, 0, 0, 0, 0 49 | if x0 >= y0 50 | i2 = 1 51 | if y0 >= z0 52 | i1, j2 = 1, 1 --XYZ 53 | elseif x0 >= z0 54 | i1, k2 = 1, 1 --XZY 55 | else 56 | k1, k2 = 1, 1 --ZXY 57 | else 58 | j2 = 1 59 | if y0 < z0 60 | k1, k2 = 1, 1 --ZYX 61 | elseif x0 < z0 62 | j1, k2 = 1, 1 --YZX 63 | else 64 | j1, i2 = 1, 1 --YXZ 65 | 66 | n = 0 67 | do 68 | t = .6 - x0 * x0 - y0 * y0 - z0 * z0 69 | if t > 0 70 | g = PERM[i + PERM[j + PERM[k]]] 71 | n = t * t * t * t * gradient(g, x0, y0, z0) 72 | 73 | do 74 | x1, y1, z1 = x0 - i1 + G3, y0 - j1 + G3, z0 - k1 + G3 75 | t = .6 - x1 * x1 - y1 * y1 - z1 * z1 76 | if t > 0 77 | g = PERM[i + i1 + PERM[j +j1 + PERM[k + k1]]] 78 | n += t * t * t * t * gradient(g, x1, y1, z1) 79 | 80 | do 81 | x2, y2, z2 = x0 - i2 + 2 * G3, y0 - j2 + 2 * G3, z0 - k2 + 2 * G3 82 | t = .6 - x2 * x2 - y2 * y2 - z2 * z2 83 | if t > 0 84 | g = PERM[i + i2 + PERM[j +j2 + PERM[k + k2]]] 85 | n += t * t * t * t * gradient(g, x2, y2, z2) 86 | 87 | do 88 | x3, y3, z3 = x0 - 1 + 3 * G3, y0 - 1 + 3 * G3, z0 - 1 + 3 * G3 89 | t = .6 - x3 * x3 - y3 * y3 - z3 * z3 90 | if t > 0 91 | g = PERM[i + 1 + PERM[j + 1 + PERM[k + 1]]] 92 | n += t * t * t * t * gradient(g, x3, y3, z3) 93 | 94 | 16 * n + .5 95 | 96 | noise 97 | -------------------------------------------------------------------------------- /lib/ray/BoundingBox.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | 3 | ffi.typeof('BoundingBox') 4 | -------------------------------------------------------------------------------- /lib/ray/Camera2D.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | 4 | Camera2D = ffi.typeof('Camera2D') 5 | 6 | Camera2DMT = { 7 | getMatrix: RL.GetCameraMatrix2D 8 | getWorldToScreen: (position) => RL.GetWorldToScreen2D(position, @) 9 | getScreenToWorld: (position) => RL.GetScreenToWorld2D(position, @) 10 | } 11 | 12 | Camera2DMT.__index = Camera2DMT 13 | 14 | ffi.metatype(Camera2D, Camera2DMT) 15 | -------------------------------------------------------------------------------- /lib/ray/Camera3D.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | import C from ffi 4 | 5 | Camera3D = ffi.typeof('Camera3D') 6 | 7 | Camera3DMT = { 8 | CUSTOM: C.CAMERA_CUSTOM 9 | FREE: C.CAMERA_FREE 10 | ORBITAL: C.CAMERA_ORBITAL 11 | FIRST_PERSON: C.CAMERA_FIRST_PERSON 12 | THIRD_PERSON: C.CAMERA_THIRD_PERSON 13 | 14 | PERSPECTIVE: C.CAMERA_PERSPECTIVE 15 | ORTHOGRAPHIC: C.CAMERA_ORTHOGRAPHIC 16 | 17 | update: RL.UpdateCamera 18 | getMouseRay: (mousePosition) => RL.GetMouseRay(mousePosition, @) 19 | getMatrix: RL.GetCameraMatrix 20 | getWorldToScreen: (position) => RL.GetWorldToScreen(position, @) 21 | getWorldToScreenEx: (position, width, height) => RL.GetWorldToScreenEx(position, @, width, height) 22 | 23 | setMode: RL.SetCameraMode 24 | setPanControl: RL.SetCameraPanControl 25 | setAltControl: RL.SetCameraAltControl 26 | setSmoothZoomControl: RL.SetCameraSmoothZoomControl 27 | setMoveControls: RL.SetCameraMoveControls 28 | } 29 | 30 | Camera3DMT.__index = Camera3DMT 31 | 32 | ffi.metatype(Camera3D, Camera3DMT) 33 | -------------------------------------------------------------------------------- /lib/ray/Color.yue: -------------------------------------------------------------------------------- 1 | import RL from yuema 2 | import 'ffi' 3 | 4 | Color = ffi.typeof('Color') 5 | tempVector = ffi.new('Vector4') 6 | 7 | ColorMT = { 8 | LIGHTGRAY: Color(200, 200, 200, 255) 9 | GRAY: Color(130, 130, 130, 255) 10 | DARKGRAY: Color( 80, 80, 80, 255) 11 | YELLOW: Color(253, 249, 0, 255) 12 | GOLD: Color(255, 203, 0, 255) 13 | ORANGE: Color(255, 161, 0, 255) 14 | PINK: Color(255, 109, 194, 255) 15 | RED: Color(230, 41, 55, 255) 16 | MAROON: Color(190, 33, 55, 255) 17 | GREEN: Color( 0, 228, 48, 255) 18 | LIME: Color( 0, 158, 47, 255) 19 | DARKGREEN: Color( 0, 117, 44, 255) 20 | SKYBLUE: Color(102, 191, 255, 255) 21 | BLUE: Color( 0, 121, 241, 255) 22 | DARKBLUE: Color( 0, 82, 172, 255) 23 | PURPLE: Color(200, 122, 255, 255) 24 | VIOLET: Color(135, 60, 190, 255) 25 | DARKPURPLE: Color(112, 31, 126, 255) 26 | BEIGE: Color(211, 176, 131, 255) 27 | BROWN: Color(127, 106, 79, 255) 28 | DARKBROWN: Color( 76, 63, 47, 255) 29 | WHITE: Color(255, 255, 255, 255) 30 | BLACK: Color( 0, 0, 0, 255) 31 | BLANK: Color( 0, 0, 0, 0) 32 | MAGENTA: Color(255, 0, 255, 255) 33 | RAYWHITE: Color(245, 245, 245, 255) 34 | 35 | fromInt: RL.GetColor 36 | fromNormalized: (r, g, b, a) -> 37 | if type(r) == 'number' 38 | tempVector.x, tempVector.y, tempVector.z, tempVector.w = r, g, b, a 39 | return RL.ColorFromNormalized(tempVector) 40 | RL.ColorFromNormalized(r) 41 | 42 | fromHSV: RL.ColorFromHSV 43 | 44 | getPixelColor: RL.GetPixelColor 45 | setPixelColor: RL.SetPixelColor 46 | 47 | -- member functions -- 48 | 49 | __tostring: => 'Color(%d, %d, %d, %d)'\format(@r, @g, @b, @a) 50 | 51 | set: (@r, @g, @b, @a) => 52 | get: => @r, @g, @b, @a 53 | fade: RL.Fade 54 | alpha: RL.ColorAlpha 55 | alphaBlend: (dst, tint) => RL.ColorAlphaBlend(dst, @, tint) 56 | normalize: RL.ColorNormalize 57 | toInt: RL.ColorToInt 58 | toHSV: RL.ColorToHSV 59 | } 60 | 61 | ColorMT.__index = ColorMT 62 | 63 | ffi.metatype(Color, ColorMT) 64 | -------------------------------------------------------------------------------- /lib/ray/Font.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | import C from ffi 4 | import 'lib.util.ptr' 5 | 6 | GlyphInfo = ffi.typeof('GlyphInfo') 7 | Font = ffi.typeof('Font') 8 | 9 | gc = => ffi.gc(@, RL.UnloadFont) 10 | 11 | FontMT = { 12 | DEFAULT: C,FONT_DEFAULT 13 | BITMAP: C,FONT_BITMAP 14 | SDF: C,FONT_SDF 15 | 16 | :GlyphInfo 17 | 18 | __gc: RL.UnloadFont 19 | 20 | load: (fileName) -> Font(RL.LoadFont(fileName)) 21 | loadEx: (fileName, fontSize, fontChars = nil, glyphCount = 0) -> 22 | Font(RL.LoadFontEx(fileName, fontSize, fontChars, glyphCount)) 23 | 24 | loadFromImage: (image, key, firstChar) -> Font(RL.LoadFontFromImage(image, key, firstChar)) 25 | 26 | loadFromMemory: (fileType, fileData, dataSize, fontSize, fontChars, glyphCount) -> 27 | Font(RL.LoadFontFromMemory(fileType, fileData, dataSize, fontSize, fontChars, glyphCount)) 28 | 29 | loadFontData: (fileData, dataSize, fontSize, fontChars, glyphCount, type) -> 30 | dataSize or= #fileData 31 | if data = ptr(RL.LoadFontData(fileData, dataSize, fontSize, fontChars, glyphCount, type)) 32 | result = [ GlyphInfo(data[i]) for i = 0, glyphCount - 1 ] 33 | RL.UnloadFontData(data, glyphCount) 34 | return result 35 | nil 36 | 37 | getDefault: RL.GetFontDefault 38 | measureText: RL.MeasureText 39 | 40 | -- member functions -- 41 | 42 | exportAsCode: RL.ExportFontAsCode 43 | measureTextEx: RL.MeasureTextEx 44 | getGlyphIndex: RL.GetGlyphIndex 45 | getGlyphInfo: RL.GetGlyphInfo 46 | getGlyphAtlasRec: RL.GetGlyphAtlasRec 47 | } 48 | 49 | FontMT.__index = FontMT 50 | 51 | ffi.metatype(Font, FontMT) 52 | -------------------------------------------------------------------------------- /lib/ray/Image.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import 'lib.ray.Color' 3 | import 'lib.util.ptr' 4 | import C from ffi 5 | import RL from yuema 6 | 7 | Image = ffi.typeof('Image') 8 | 9 | ImageMT = { 10 | UNCOMPRESSED_GRAYSCALE: C.PIXELFORMAT_UNCOMPRESSED_GRAYSCALE 11 | UNCOMPRESSED_GRAY_ALPHA: C.PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA 12 | UNCOMPRESSED_R5G6B5: C.PIXELFORMAT_UNCOMPRESSED_R5G6B5 13 | UNCOMPRESSED_R8G8B8: C.PIXELFORMAT_UNCOMPRESSED_R8G8B8 14 | UNCOMPRESSED_R5G5B5A1: C.PIXELFORMAT_UNCOMPRESSED_R5G5B5A1 15 | UNCOMPRESSED_R4G4B4A4: C.PIXELFORMAT_UNCOMPRESSED_R4G4B4A4 16 | UNCOMPRESSED_R8G8B8A8: C.PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 17 | UNCOMPRESSED_R32: C.PIXELFORMAT_UNCOMPRESSED_R32 18 | UNCOMPRESSED_R32G32B32: C.PIXELFORMAT_UNCOMPRESSED_R32G32B32 19 | UNCOMPRESSED_R32G32B32A32: C.PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 20 | COMPRESSED_DXT1_RGB: C.PIXELFORMAT_COMPRESSED_DXT1_RGB 21 | COMPRESSED_DXT1_RGBA: C.PIXELFORMAT_COMPRESSED_DXT1_RGBA 22 | COMPRESSED_DXT3_RGBA: C.PIXELFORMAT_COMPRESSED_DXT3_RGBA 23 | COMPRESSED_DXT5_RGBA: C.PIXELFORMAT_COMPRESSED_DXT5_RGBA 24 | COMPRESSED_ETC1_RGB: C.PIXELFORMAT_COMPRESSED_ETC1_RGB 25 | COMPRESSED_ETC2_RGB: C.PIXELFORMAT_COMPRESSED_ETC2_RGB 26 | COMPRESSED_ETC2_EAC_RGBA: C.PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA 27 | COMPRESSED_PVRT_RGB: C.PIXELFORMAT_COMPRESSED_PVRT_RGB 28 | COMPRESSED_PVRT_RGBA: C.PIXELFORMAT_COMPRESSED_PVRT_RGBA 29 | COMPRESSED_ASTC_4x4_RGBA: C.PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA 30 | COMPRESSED_ASTC_8x8_RGBA: C.PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA 31 | 32 | __gc: RL.UnloadImage 33 | 34 | load: (fileName) -> Image(RL.LoadImage(fileName)) 35 | loadRaw: (fileName, width, height, format, headerSize) -> Image(RL.LoadImageRaw(fileName, width, height, format, headerSize)) 36 | 37 | loadAnim: (fileName) -> 38 | frames = ffi.new('int[1]') 39 | result = Image(RL.LoadImageAnim(fileName, frames)) 40 | result, tonumber(frames[0]) 41 | 42 | loadFromMemory: (fileType, fileData, dataSize) -> Image(RL.LoadImageFromMemory(fileType, fileData, dataSize)) 43 | loadFromTexture: (texture) -> Image(RL.LoadImageFromTexture!) 44 | loadFromScreen: -> Image(RL.LoadImageFromScreen!) 45 | genColor: (width, height, color) -> Image(RL.GenImageColor(width, height, color)) 46 | genGradientV: (width, height, top, bottom) -> Image(RL.GenImageGradientV(width, height, top, bottom)) 47 | genGradientH: (width, height, left, right) -> Image(RL.GenImageGradientH(width, height, left, right)) 48 | 49 | genGradientRadial: (width, height, density, inner, outer) -> 50 | Image(RL.GenImageGradientRadial(width, height, density, inner, outer)) 51 | 52 | genChecked: (width, height, checksX, checksY, col1, col2) -> 53 | Image(RL.GenImageChecked(width, height, checksX, checksY, col1, col2)) 54 | 55 | genWhiteNoise: (width, height, factor) -> Image(RL.GenImageWhiteNoise(width, height, factor)) 56 | genCellular: (width, height, tileSize) -> Image(RL.GenImageCellular(width, height, tileSize)) 57 | 58 | genFontAtlas: (chars, glyphCount, fontSize, padding, packMethod) -> 59 | recs = ffi.new('Rectangle[?]', glyphCount) 60 | result = Image(RL.GenImageFontAtlas(chars, recs, glyphCount, fontSize, padding, packMethod)) 61 | result, recs 62 | 63 | fromImage: (image, rec) -> Image(RL.ImageFromImage(image, rec)) 64 | text: (text, fontSize, color) -> Image(RL.ImageText(text, fontSize, color)) 65 | textEx: (font, text, fontSize, spacing, tint) -> Image(RL.ImageTextEx(font, text, fontSize, spacing, tint)) 66 | 67 | -- member functions -- 68 | 69 | copy: => Image(RL.ImageCopy(@)) 70 | export: RL.ExportImage 71 | exportAsCode: RL.ExportImageAsCode 72 | format: RL.ImageFormat 73 | toPOT: RL.ImageToPOT 74 | crop: RL.ImageCrop 75 | alphaCrop: RL.ImageAlphaCrop 76 | alphaClear: RL.ImageAlphaClear 77 | alphaMask: RL.ImageAlphaMask 78 | alphaPremultiply: RL.ImageAlphaPremultiply 79 | resize: RL.ImageResize 80 | resizeNN: RL.ImageResizeNN 81 | 82 | resizeCanvas: RL.ImageResizeCanvas 83 | 84 | mipmaps: RL.ImageMipmaps 85 | dither: RL.ImageDither 86 | flipVertical: RL.ImageFlipVertical 87 | flipHorizontal: RL.ImageFlipHorizontal 88 | rotateCW: RL.ImageRotateCW 89 | rotateCCW: RL.ImageRotateCCW 90 | colorTint: RL.ImageColorTint 91 | colorInvert: RL.ImageColorInvert 92 | colorGrayscale: RL.ImageColorGrayscale 93 | colorContrast: RL.ImageColorContrast 94 | colorBrightness: RL.ImageColorBrightness 95 | colorReplace: RL.ImageColorReplace 96 | 97 | loadColors: => 98 | if colors = ptr(RL.LoadImageColors(@)) 99 | result = [ Color(colors[i].r, colors[i].g, colors[i].b, colors[i].a) for i = 0, @width * @height - 1 ] 100 | RL.UnloadImageColors(colors) 101 | return result 102 | nil 103 | 104 | loadPalette: => 105 | colorCount = ffi.new('int[1]') 106 | if colors = ptr(RL.LoadImagePalette(@, maxPaletteSize, colorCount)) 107 | result = [ Color(colors[i].r, colors[i].g, colors[i].b, colors[i].a) for i = 0, colorCount[0] - 1 ] 108 | RL.UnloadImagePalette(colors) 109 | return result, tonumber(colorCount[0]) 110 | nil, 0 111 | 112 | getAlphaBorder: RL.GetImageAlphaBorder 113 | getColor: RL.GetImageColor 114 | clearBackground: RL.ImageClearBackground 115 | drawPixel: RL.ImageDrawPixel 116 | drawPixelV: RL.ImageDrawPixelV 117 | drawLine: RL.ImageDrawLine 118 | drawLineV: RL.ImageDrawLineV 119 | drawCircle: RL.ImageDrawCircle 120 | drawCircleV: RL.ImageDrawCircleV 121 | drawRectangle: RL.ImageDrawRectangle 122 | drawRectangleV: RL.ImageDrawRectangleV 123 | drawRectangleRec: RL.ImageDrawRectangleRec 124 | drawRectangleLines: RL.ImageDrawRectangleLines 125 | draw: RL.ImageDraw 126 | drawText: RL.ImageDrawText 127 | drawTextEx: RL.ImageDrawTextEx 128 | } 129 | 130 | ImageMT.__index = ImageMT 131 | 132 | ffi.metatype(Image, ImageMT) 133 | -------------------------------------------------------------------------------- /lib/ray/Material.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | import C from ffi 4 | 5 | Material = ffi.typeof('Material') 6 | 7 | MaterialMT = { 8 | MAP_DIFFUSE: C.MATERIAL_MAP_ALBEDO 9 | MAP_SPECULAR: C.MATERIAL_MAP_METALNESS 10 | MAP_ALBEDO: C.MATERIAL_MAP_ALBEDO 11 | MAP_METALNESS: C.MATERIAL_MAP_METALNESS 12 | MAP_NORMAL: C.MATERIAL_MAP_NORMAL 13 | MAP_ROUGHNESS: C.MATERIAL_MAP_ROUGHNESS 14 | MAP_OCCLUSION: C.MATERIAL_MAP_OCCLUSION 15 | MAP_EMISSION: C.MATERIAL_MAP_EMISSION 16 | MAP_HEIGHT: C.MATERIAL_MAP_HEIGHT 17 | MAP_CUBEMAP: C.MATERIAL_MAP_CUBEMAP 18 | MAP_IRRADIANCE: C.MATERIAL_MAP_IRRADIANCE 19 | MAP_PREFILTER: C.MATERIAL_MAP_PREFILTER 20 | MAP_BRDF: C.MATERIAL_MAP_BRDF 21 | 22 | load: (fileName) -> 23 | count = ffi.new('int[1]') 24 | materials = RL.LoadMaterials(fileName, count) 25 | [ Material(materials[i]) for i = 0, count[0] - 1 ] 26 | 27 | loadDefault: -> Material(RL.LoadMaterialDefault!) 28 | 29 | -- member functions -- 30 | 31 | __gc: RL.UnloadMaterial 32 | 33 | setTexture: RL.SetMaterialTexture 34 | } 35 | 36 | MaterialMT.__index = MaterialMT 37 | 38 | ffi.metatype(Material, MaterialMT) 39 | -------------------------------------------------------------------------------- /lib/ray/Mesh.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | 4 | Mesh = ffi.typeof('Mesh') 5 | 6 | MeshMT = { 7 | genPoly: (sides, radius) -> Mesh(RL.GenMeshPoly(sides, radius)) 8 | genPlane: (width, length, resX, resZ) -> Mesh(RL.GenMeshPlane(width, length, resX, resZ)) 9 | genCube: (width, height, length) -> Mesh(RL.GenMeshCube(width, height, length)) 10 | genSphere: (radius, rings, slices) -> Mesh(RL.GenMeshSphere(radius, rings, slices)) 11 | genHemiSphere: (radius, rings, slices) -> Mesh(RL.GenMeshHemiSphere(radius, rings, slices)) 12 | genCylinder: (radius, height, slices) -> Mesh(RL.GenMeshCylinder(radius, height, slices)) 13 | genCone: (radius, height, slices) -> Mesh(RL.GenMeshCone(radius, height, slices)) 14 | genTorus: (radius, size, radSeg, sides) -> Mesh(RL.GenMeshTorus(radius, size, radSeg, sides)) 15 | genKnot: (radius, size, radSeg, sides) -> Mesh(RL.GenMeshKnot(radius, size, radSeg, sides)) 16 | genHeightmap: (heightmap, size) -> Mesh(RL.GenMeshHeightmap(heightmap, size)) 17 | genCubicmap: (cubicmap, cubeSize) -> Mesh(RL.GenMeshCubicmap(cubicmap, cubeSize)) 18 | 19 | -- member functions -- 20 | 21 | upload: RL.UploadMesh 22 | updateBuffer: RL.UpdateMeshBuffer 23 | export: RL.ExportMesh 24 | getBoundingBox: RL.GetMeshBoundingBox 25 | genTangents: RL.GenMeshTangents 26 | genBinormals: RL.GenMeshBinormals 27 | } 28 | 29 | MeshMT.__index = MeshMT 30 | 31 | ffi.metatype(Mesh, MeshMT) 32 | -------------------------------------------------------------------------------- /lib/ray/Model.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | 4 | Animation = ffi.typeof('ModelAnimation') 5 | 6 | AnimationMT = { 7 | loadAnimations: (fileName) -> 8 | count = ffi.new('unsigned int[1]') 9 | if anims = RL.LoadModelAnimations(fileName, count) 10 | result = [ Mesh(anims[i]) for i = 0, count[0] - 1 ] 11 | RL.UnloadModelAnimations(anims, count[0]) 12 | return result 13 | nil 14 | } 15 | 16 | AnimationMT.__index = AnimationMT 17 | 18 | ffi.metatype(Animation, AnimationMT) 19 | 20 | Model = ffi.typeof('Model') 21 | 22 | ModelMT = { 23 | :Animation 24 | 25 | load: (fileName) -> ffi.gc(RL.LoadModel(fileName), RL.UnloadModel) 26 | loadFromMesh: (mesh) -> ffi.gc(RL.LoadModelFromMesh(mesh), RL.UnloadModelKeepMeshes) 27 | 28 | -- member functions -- 29 | 30 | getBoundingBox: RL.GetModelBoundingBox 31 | setMeshMaterial: RL.SetModelMeshMaterial 32 | updateAnimation: RL.UpdateModelAnimation 33 | isAnimationValid: RL.IsModelAnimationValid 34 | unloadKeepMeshes: => RL.UnloadModelKeepMeshes(ffi.gc(@, nil)) 35 | } 36 | 37 | ModelMT.__index = ModelMT 38 | 39 | ffi.metatype(Model, ModelMT) 40 | -------------------------------------------------------------------------------- /lib/ray/NPatchInfo.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import C from ffi 3 | 4 | NPatchInfo = ffi.typeof('NPatchInfo') 5 | 6 | NPatchInfoMT = { 7 | NINE_PATCH: C.NPATCH_NINE_PATCH 8 | THREE_PATCH_VERTICAL: C.NPATCH_THREE_PATCH_VERTICAL 9 | THREE_PATCH_HORIZONTAL: C.NPATCH_THREE_PATCH_HORIZONTAL 10 | } 11 | 12 | NPatchInfoMT.__index = NPatchInfoMT 13 | 14 | ffi.metatype(NPatchInfo, NPatchInfoMT) 15 | -------------------------------------------------------------------------------- /lib/ray/Rectangle.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | 3 | Rectangle = ffi.typeof('Rectangle') 4 | 5 | RectangleMT = { 6 | __tostring: => 'Rectangle(%f, %f, %f, %f)'::format(@x, @y, @width, @height) 7 | } 8 | 9 | ffi.metatype(Rectangle, RectangleMT) 10 | -------------------------------------------------------------------------------- /lib/ray/RenderTexture.yue: -------------------------------------------------------------------------------- 1 | import RL from yuema 2 | import 'ffi' 3 | 4 | RenderTexture = ffi.typeof('RenderTexture') 5 | 6 | RenderTextureMT = { 7 | load: (width, height) -> RenderTexture(RL.LoadRenderTexture(width, height)) 8 | 9 | __gc: RL.UnloadRenderTexture 10 | } 11 | 12 | RenderTextureMT.__index = RenderTextureMT 13 | 14 | ffi.metatype(RenderTexture, RenderTextureMT) 15 | -------------------------------------------------------------------------------- /lib/ray/Shader.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | import C from ffi 4 | 5 | Shader = ffi.typeof('Shader') 6 | 7 | ShaderMT = { 8 | LOC_MAP_DIFFUSE: C.SHADER_LOC_MAP_ALBEDO 9 | LOC_MAP_SPECULAR: C.SHADER_LOC_MAP_METALNESS 10 | LOC_VERTEX_POSITION: C.SHADER_LOC_VERTEX_POSITION 11 | LOC_VERTEX_TEXCOORD01: C.SHADER_LOC_VERTEX_TEXCOORD01 12 | LOC_VERTEX_TEXCOORD02: C.SHADER_LOC_VERTEX_TEXCOORD02 13 | LOC_VERTEX_NORMAL: C.SHADER_LOC_VERTEX_NORMAL 14 | LOC_VERTEX_TANGENT: C.SHADER_LOC_VERTEX_TANGENT 15 | LOC_VERTEX_COLOR: C.SHADER_LOC_VERTEX_COLOR 16 | LOC_MATRIX_MVP: C.SHADER_LOC_MATRIX_MVP 17 | LOC_MATRIX_VIEW: C.SHADER_LOC_MATRIX_VIEW 18 | LOC_MATRIX_PROJECTION: C.SHADER_LOC_MATRIX_PROJECTION 19 | LOC_MATRIX_MODEL: C.SHADER_LOC_MATRIX_MODEL 20 | LOC_MATRIX_NORMAL: C.SHADER_LOC_MATRIX_NORMAL 21 | LOC_VECTOR_VIEW: C.SHADER_LOC_VECTOR_VIEW 22 | LOC_COLOR_DIFFUSE: C.SHADER_LOC_COLOR_DIFFUSE 23 | LOC_COLOR_SPECULAR: C.SHADER_LOC_COLOR_SPECULAR 24 | LOC_COLOR_AMBIENT: C.SHADER_LOC_COLOR_AMBIENT 25 | LOC_MAP_ALBEDO: C.SHADER_LOC_MAP_ALBEDO 26 | LOC_MAP_METALNESS: C.SHADER_LOC_MAP_METALNESS 27 | LOC_MAP_NORMAL: C.SHADER_LOC_MAP_NORMAL 28 | LOC_MAP_ROUGHNESS: C.SHADER_LOC_MAP_ROUGHNESS 29 | LOC_MAP_OCCLUSION: C.SHADER_LOC_MAP_OCCLUSION 30 | LOC_MAP_EMISSION: C.SHADER_LOC_MAP_EMISSION 31 | LOC_MAP_HEIGHT: C.SHADER_LOC_MAP_HEIGHT 32 | LOC_MAP_CUBEMAP: C.SHADER_LOC_MAP_CUBEMAP 33 | LOC_MAP_IRRADIANCE: C.SHADER_LOC_MAP_IRRADIANCE 34 | LOC_MAP_PREFILTER: C.SHADER_LOC_MAP_PREFILTER 35 | LOC_MAP_BRDF: C.SHADER_LOC_MAP_BRDF 36 | 37 | UNIFORM_FLOAT: C.SHADER_UNIFORM_FLOAT 38 | UNIFORM_VEC2: C.SHADER_UNIFORM_VEC2 39 | UNIFORM_VEC3: C.SHADER_UNIFORM_VEC3 40 | UNIFORM_VEC4: C.SHADER_UNIFORM_VEC4 41 | UNIFORM_INT: C.SHADER_UNIFORM_INT 42 | UNIFORM_IVEC2: C.SHADER_UNIFORM_IVEC2 43 | UNIFORM_IVEC3: C.SHADER_UNIFORM_IVEC3 44 | UNIFORM_IVEC4: C.SHADER_UNIFORM_IVEC4 45 | UNIFORM_SAMPLER2D: C.SHADER_UNIFORM_SAMPLER2D 46 | 47 | ATTRIB_FLOAT: C.SHADER_ATTRIB_FLOAT 48 | ATTRIB_VEC2: C.SHADER_ATTRIB_VEC2 49 | ATTRIB_VEC3: C.SHADER_ATTRIB_VEC3 50 | ATTRIB_VEC4: C.SHADER_ATTRIB_VEC4 51 | 52 | load: (vsFileName, fsFileName) -> Shader(RL.LoadShader(vsFileName, fsFileName)) 53 | loadFromMemory: (vsCode, fsCode) -> Shader(RL.LoadShaderFromMemory(vsCode, fsCode)) 54 | 55 | -- member functions -- 56 | 57 | __gc: RL.UnloadShader 58 | 59 | getLocation: RL.GetShaderLocation 60 | getLocationAttrib: RL.GetShaderLocationAttrib 61 | setValue: RL.SetShaderValue 62 | setValueV: RL.SetShaderValueV 63 | setValueMatrix: RL.SetShaderValueMatrix 64 | setValueTexture: RL.SetShaderValueTexture 65 | } 66 | 67 | ShaderMT.__index = ShaderMT 68 | 69 | ffi.metatype(Shader, ShaderMT) 70 | -------------------------------------------------------------------------------- /lib/ray/Texture2D.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import C from ffi 3 | import RL from yuema 4 | 5 | Texture2D = ffi.typeof('Texture2D') 6 | 7 | Texture2DMT = { 8 | FILTER_POINT: C.TEXTURE_FILTER_POINT 9 | FILTER_BILINEAR: C.TEXTURE_FILTER_BILINEAR 10 | FILTER_TRILINEAR: C.TEXTURE_FILTER_TRILINEAR 11 | FILTER_ANISOTROPIC_4X: C.TEXTURE_FILTER_ANISOTROPIC_4X 12 | FILTER_ANISOTROPIC_8X: C.TEXTURE_FILTER_ANISOTROPIC_8X 13 | FILTER_ANISOTROPIC_16X: C.TEXTURE_FILTER_ANISOTROPIC_16X 14 | 15 | WRAP_REPEAT: C.TEXTURE_WRAP_REPEAT 16 | WRAP_CLAMP: C.TEXTURE_WRAP_CLAMP 17 | WRAP_MIRROR_REPEAT: C.TEXTURE_WRAP_MIRROR_REPEAT 18 | WRAP_MIRROR_CLAMP: C.TEXTURE_WRAP_MIRROR_CLAMP 19 | 20 | LAYOUT_AUTO_DETECT: C.CUBEMAP_LAYOUT_AUTO_DETECT 21 | LAYOUT_LINE_VERTICAL: C.CUBEMAP_LAYOUT_LINE_VERTICAL 22 | LAYOUT_LINE_HORIZONTAL: C.CUBEMAP_LAYOUT_LINE_HORIZONTAL 23 | LAYOUT_CROSS_THREE_BY_FOUR: C.CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR 24 | LAYOUT_CROSS_FOUR_BY_THREE: C.CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE 25 | LAYOUT_PANORAMA: C.CUBEMAP_LAYOUT_PANORAMA 26 | 27 | load: (fileName) -> Texture2D(RL.LoadTexture(fileName)) 28 | loadFromImage: (image) -> Texture2D(RL.LoadTextureFromImage(image)) 29 | loadCubemap: (image, layout) -> Texture2D(RL.LoadTextureCubemap(image, layout)) 30 | 31 | -- member functions -- 32 | 33 | __gc: RL.UnloadTexture 34 | 35 | update: RL.UpdateTexture 36 | updateRec: RL.UpdateTextureRec 37 | genMipmaps: RL.GenTextureMipmaps 38 | setFilter: RL.SetTextureFilter 39 | setWrap: RL.SetTextureWrap 40 | } 41 | 42 | Texture2DMT.__index = Texture2DMT 43 | 44 | ffi.metatype(Texture2D, Texture2DMT) 45 | -------------------------------------------------------------------------------- /lib/ray/audio.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | 4 | -- Wave -- 5 | 6 | Wave = ffi.typeof('Wave') 7 | 8 | WaveMT = { 9 | load: (fileName) -> Wave(RL.LoadWave(fileName)) 10 | 11 | loadFromMemory: (fileType, fileData, dataSize) -> 12 | dataSize or= #fileData 13 | Wave(RL.LoadWaveFromMemory(fileType, fileData, dataSize)) 14 | 15 | -- member functions -- 16 | 17 | __gc: RL.UnloadWave 18 | 19 | export: RL.ExportWave 20 | exportAsCode: RL.ExportWaveAsCode 21 | copy: => Wave(RL.WaveCopy(@)) 22 | crop: (initSample, finalSample) => Wave(RL.WaveCrop(@, initSample, finalSample)) 23 | format: (sampleRate, sampleSize, channels) => Wave(RL.WaveFormat(@, sampleRate, sampleSize, channels)) 24 | loadSamples: => ffi.gc(RL.LoadWaveSamples(@), RL.UnloadWaveSamples) 25 | } 26 | 27 | WaveMT.__index = WaveMT 28 | 29 | ffi.metatype(Wave, WaveMT) 30 | 31 | -- Sound -- 32 | 33 | Sound = ffi.typeof('Sound') 34 | 35 | SoundMT = { 36 | load: (fileName) -> Sound(RL.LoadSound(fileName)) 37 | loadFromWave: (wave) -> Sound(RL.LoadSoundFromWave(wave)) 38 | 39 | -- member functions -- 40 | 41 | __gc: RL.UnloadSound 42 | 43 | update: RL.UpdateSound 44 | play: RL.PlaySound 45 | stop: RL.StopSound 46 | pause: RL.PauseSound 47 | resume: RL.ResumeSound 48 | playMulti: RL.PlaySoundMulti 49 | isPlaying: RL.IsSoundPlaying 50 | setVolume: RL.SetSoundVolume 51 | setPitch: RL.SetSoundPitch 52 | setPan: RL.SetSoundPan 53 | } 54 | 55 | SoundMT.__index = SoundMT 56 | 57 | ffi.metatype(Sound, SoundMT) 58 | 59 | -- Music -- 60 | 61 | Music = ffi.typeof('Music') 62 | 63 | MusicMT = { 64 | load: (fileName) -> Music(RL.LoadMusicStream(fileName)) 65 | loadFromMemory: (fileType, data, dataSize) -> Music(RL.LoadMusicStreamFromMemory(fileType, data, dataSize or #data)) 66 | 67 | -- member functions -- 68 | 69 | __gc: RL.UnloadMusicStream 70 | 71 | play: RL.PlayMusicStream 72 | isPlaying: RL.IsMusicStreamPlaying 73 | update: RL.UpdateMusicStream 74 | stop: RL.StopMusicStream 75 | pause: RL.PauseMusicStream 76 | resume: RL.ResumeMusicStream 77 | seek: RL.SeekMusicStream 78 | setVolume: RL.SetMusicVolume 79 | setPitch: RL.SetMusicPitch 80 | setPan: RL.SetMusicPan 81 | getTimeLength: RL.GetMusicTimeLength 82 | getTimePlayed: RL.GetMusicTimePlayed 83 | } 84 | 85 | MusicMT.__index = MusicMT 86 | 87 | ffi.metatype(Music, MusicMT) 88 | 89 | -- AudioStream -- 90 | 91 | Stream = ffi.typeof('AudioStream') 92 | 93 | StreamMT = { 94 | load: (sampleRate, sampleSize, channels) -> Stream(RL.LoadAudioStream(sampleRate, sampleSize, channels)) 95 | 96 | setBufferSizeDefault: RL.SetAudioStreamBufferSizeDefault 97 | 98 | -- member functions -- 99 | 100 | __gc: RL.UnloadAudioStream 101 | 102 | update: RL.UpdateAudioStream 103 | isProcessed: RL.IsAudioStreamProcessed 104 | play: RL.PlayAudioStream 105 | pause: RL.PauseAudioStream 106 | resume: RL.ResumeAudioStream 107 | isPlaying: RL.IsAudioStreamPlaying 108 | stop: RL.StopAudioStream 109 | setVolume: RL.SetAudioStreamVolume 110 | setPitch: RL.SetAudioStreamPitch 111 | setPan: RL.SetAudioStreamPan 112 | } 113 | 114 | StreamMT.__index = StreamMT 115 | 116 | ffi.metatype(Stream, StreamMT) 117 | 118 | -- audio -- 119 | 120 | { 121 | init: RL.InitAudioDevice 122 | close: RL.CloseAudioDevice 123 | isReady: RL.IsAudioDeviceReady 124 | setMasterVolume: RL.SetMasterVolume 125 | 126 | stopSoundMulti: RL.StopSoundMulti 127 | getSoundsPlaying: RL.GetSoundsPlaying 128 | 129 | :Wave 130 | :Sound 131 | :Music 132 | :Stream 133 | } 134 | -------------------------------------------------------------------------------- /lib/ray/collision.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import 'lib.math.Vector2' 3 | import RL from yuema 4 | 5 | collisionPoint = ffi.new('Vector2[1]') 6 | 7 | { 8 | Ray: ffi.typeof('Ray') 9 | RayCollision: ffi.typeof('RayCollision') 10 | 11 | checkRecs: RL.CheckCollisionRecs 12 | checkCircles: RL.CheckCollisionCircles 13 | checkCircleRec: RL.CheckCollisionCircleRec 14 | checkPointRec: RL.CheckCollisionPointRec 15 | checkPointCircle: RL.CheckCollisionPointCircle 16 | checkPointTriangle: RL.CheckCollisionPointTriangle 17 | checkPointLine: RL.CheckCollisionPointLine 18 | getRec: RL.GetCollisionRec 19 | checkSpheres: RL.CheckCollisionSpheres 20 | checkBoxes: RL.CheckCollisionBoxes 21 | checkBoxSphere: RL.CheckCollisionBoxSphere 22 | getRaySphere: RL.GetRayCollisionSphere 23 | getRayBox: RL.GetRayCollisionBox 24 | getRayModel: RL.GetRayCollisionModel 25 | getRayMesh: RL.GetRayCollisionMesh 26 | getRayTriangle: RL.GetRayCollisionTriangle 27 | getRayQuad: RL.GetRayCollisionQuad 28 | 29 | checkLines: (startPos1, endPos1, startPos2, endPos2) -> 30 | result = RL.CheckCollisionLines(startPos1, endPos1, startPos2, endPos2, collisionPoint) 31 | result, result and Vector2(collisionPoint[0]) or nil 32 | } 33 | -------------------------------------------------------------------------------- /lib/ray/config.yue: -------------------------------------------------------------------------------- 1 | import RL from yuema 2 | import 'ffi' as :C 3 | 4 | { 5 | VSYNC_HINT: C.FLAG_VSYNC_HINT 6 | FULLSCREEN_MODE: C.FLAG_FULLSCREEN_MODE 7 | WINDOW_RESIZABLE: C.FLAG_WINDOW_RESIZABLE 8 | WINDOW_UNDECORATED: C.FLAG_WINDOW_UNDECORATED 9 | WINDOW_HIDDEN: C.FLAG_WINDOW_HIDDEN 10 | WINDOW_MINIMIZED: C.FLAG_WINDOW_MINIMIZED 11 | WINDOW_MAXIMIZED: C.FLAG_WINDOW_MAXIMIZED 12 | WINDOW_UNFOCUSED: C.FLAG_WINDOW_UNFOCUSED 13 | WINDOW_TOPMOST: C.FLAG_WINDOW_TOPMOST 14 | WINDOW_ALWAYS_RUN: C.FLAG_WINDOW_ALWAYS_RUN 15 | WINDOW_TRANSPARENT: C.FLAG_WINDOW_TRANSPARENT 16 | WINDOW_HIGHDPI: C.FLAG_WINDOW_HIGHDPI 17 | MSAA_4X_HINT: C.FLAG_MSAA_4X_HINT 18 | INTERLACED_HINT: C.FLAG_INTERLACED_HINT 19 | 20 | setFlags: RL.SetConfigFlags 21 | 22 | loadVrStereoConfig: RL.LoadVrStereoConfig 23 | unloadVrStereoConfig: RL.UnloadVrStereoConfig 24 | } 25 | -------------------------------------------------------------------------------- /lib/ray/data.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | 4 | { 5 | memAlloc: RL.MemAlloc 6 | memRealloc: RL.MemRealloc 7 | memFree: RL.MemFree 8 | 9 | saveStorageValue: RL.SaveStorageValue 10 | loadStorageValue: RL.LoadStorageValue 11 | 12 | compress: (data, dataLength) -> 13 | dataLength or= #data 14 | compDataLength = ffi.new('int[1]') 15 | compData = RL.CompressData(data, dataLength, compDataLength) 16 | compData, tonumber(compDataLength[0]) 17 | 18 | decompress: (compData, compDataLength)-> 19 | compDataLength or= #compData 20 | dataLength = ffi.new('int[1]') 21 | data = RL.DecompressData(compData, compDataLength, dataLength) 22 | data, tonumber(dataLength[0]) 23 | 24 | encodeBase64: (data, dataLength) -> 25 | dataLength or= #data 26 | outputLength = ffi.new('int[1]') 27 | b64 = RL.EncodeDataBase64(data, dataLength, outputLength) 28 | ffi.string(b64, outputLength[0]) 29 | 30 | decodeBase64: (data) -> 31 | outputLength = ffi.new('int[1]') 32 | bin = RL.DecodeDataBase64(data, outputLength) 33 | bin, tonumber(outputLength[0]) 34 | } 35 | -------------------------------------------------------------------------------- /lib/ray/draw.yue: -------------------------------------------------------------------------------- 1 | import RL from yuema 2 | import 'ffi' as :C 3 | 4 | { 5 | BLEND_ALPHA: C.BLEND_ALPHA 6 | BLEND_ADDITIVE: C.BLEND_ADDITIVE 7 | BLEND_MULTIPLIED: C.BLEND_MULTIPLIED 8 | BLEND_ADD_COLORS: C.BLEND_ADD_COLORS 9 | BLEND_SUBTRACT_COLORS: C.BLEND_SUBTRACT_COLORS 10 | BLEND_ALPHA_PREMUL: C.BLEND_ALPHA_PREMUL 11 | BLEND_CUSTOM: C.BLEND_CUSTOM 12 | 13 | clearBackground: RL.ClearBackground 14 | beginDrawing: RL.BeginDrawing 15 | endDrawing: RL.EndDrawing 16 | beginMode2D: RL.BeginMode2D 17 | endMode2D: RL.EndMode2D 18 | beginMode3D: RL.BeginMode3D 19 | endMode3D: RL.EndMode3D 20 | beginTextureMode: RL.BeginTextureMode 21 | endTextureMode: RL.EndTextureMode 22 | beginShaderMode: RL.BeginShaderMode 23 | endShaderMode: RL.EndShaderMode 24 | beginBlendMode: RL.BeginBlendMode 25 | endBlendMode: RL.EndBlendMode 26 | beginScissorMode: RL.BeginScissorMode 27 | endScissorMode: RL.EndScissorMode 28 | beginVrStereoMode: RL.BeginVrStereoMode 29 | endVrStereoMode: RL.EndVrStereoMode 30 | pixel: RL.DrawPixel 31 | pixelV: RL.DrawPixelV 32 | 33 | line: RL.DrawLine 34 | lineV: RL.DrawLineV 35 | lineEx: RL.DrawLineEx 36 | lineBezier: RL.DrawLineBezier 37 | lineBezierQuad: RL.DrawLineBezierQuad 38 | lineBezierCubic: RL.DrawLineBezierCubic 39 | lineStrip: RL.DrawLineStrip 40 | 41 | circle: RL.DrawCircle 42 | circleSector: RL.DrawCircleSector 43 | circleSectorLines: RL.DrawCircleSectorLines 44 | circleGradient: RL.DrawCircleGradient 45 | 46 | circleV: RL.DrawCircleV 47 | circleLines: RL.DrawCircleLines 48 | ellipse: RL.DrawEllipse 49 | ellipseLines: RL.DrawEllipseLines 50 | 51 | ring: RL.DrawRing 52 | ringLines: RL.DrawRingLines 53 | 54 | rectangle: RL.DrawRectangle 55 | rectangleV: RL.DrawRectangleV 56 | rectangleRec: RL.DrawRectangleRec 57 | rectanglePro: RL.DrawRectanglePro 58 | rectangleGradientV: RL.DrawRectangleGradientV 59 | rectangleGradientH: RL.DrawRectangleGradientH 60 | rectangleGradientEx: RL.DrawRectangleGradientEx 61 | rectangleLines: RL.DrawRectangleLines 62 | rectangleLinesEx: RL.DrawRectangleLinesEx 63 | rectangleRounded: RL.DrawRectangleRounded 64 | rectangleRoundedLines: RL.DrawRectangleRoundedLines 65 | 66 | triangle: RL.DrawTriangle 67 | triangleLines: RL.DrawTriangleLines 68 | triangleFan: RL.DrawTriangleFan 69 | triangleStrip: RL.DrawTriangleStrip 70 | triangle3D: RL.DrawTriangle3D 71 | triangleStrip3D: RL.DrawTriangleStrip3D 72 | 73 | poly: RL.DrawPoly 74 | polyLines: RL.DrawPolyLines 75 | polyLinesEx: RL.DrawPolyLinesEx 76 | 77 | line3D: RL.DrawLine3D 78 | point3D: RL.DrawPoint3D 79 | circle3D: RL.DrawCircle3D 80 | 81 | cube: RL.DrawCube 82 | cubeV: RL.DrawCubeV 83 | cubeWires: RL.DrawCubeWires 84 | cubeWiresV: RL.DrawCubeWiresV 85 | cubeTexture: RL.DrawCubeTexture 86 | cubeTextureRec: RL.DrawCubeTextureRec 87 | 88 | sphere: RL.DrawSphere 89 | sphereEx: RL.DrawSphereEx 90 | sphereWires: RL.DrawSphereWires 91 | 92 | cylinder: RL.DrawCylinder 93 | cylinderEx: RL.DrawCylinderEx 94 | cylinderWires: RL.DrawCylinderWires 95 | cylinderWiresEx: RL.DrawCylinderWiresEx 96 | 97 | plane: RL.DrawPlane 98 | ray: RL.DrawRay 99 | grid: RL.DrawGrid 100 | 101 | texture: RL.DrawTexture 102 | textureV: RL.DrawTextureV 103 | textureEx: RL.DrawTextureEx 104 | textureRec: RL.DrawTextureRec 105 | textureQuad: RL.DrawTextureQuad 106 | textureTiled: RL.DrawTextureTiled 107 | texturePro: RL.DrawTexturePro 108 | textureNPatch: RL.DrawTextureNPatch 109 | texturePoly: RL.DrawTexturePoly 110 | 111 | fps: RL.DrawFPS 112 | text: RL.DrawText 113 | textEx: RL.DrawTextEx 114 | textPro: RL.DrawTextPro 115 | textCodepoint: RL.DrawTextCodepoint 116 | textCodepoints: RL.DrawTextCodepoints 117 | 118 | model: RL.DrawModel 119 | modelEx: RL.DrawModelEx 120 | modelWires: RL.DrawModelWires 121 | modelWiresEx: RL.DrawModelWiresEx 122 | 123 | boundingBox: RL.DrawBoundingBox 124 | billboard: RL.DrawBillboard 125 | billboardRec: RL.DrawBillboardRec 126 | billboardPro: RL.DrawBillboardPro 127 | 128 | mesh: RL.DrawMesh 129 | meshInstanced: RL.DrawMeshInstanced 130 | 131 | setShapesTexture: RL.SetShapesTexture 132 | } 133 | -------------------------------------------------------------------------------- /lib/ray/filesystem.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | import 'lib.util.ptr' 4 | 5 | { 6 | loadData: (fileName) -> 7 | read = ffi.new('unsigned int[1]') 8 | if data = ptr(RL.LoadFileData(fileName, read)) 9 | result = ffi.string(data, read[0]) 10 | RL.UnloadFileData(data) 11 | return result, tonumber(read[0]) 12 | nil, 0 13 | 14 | loadText: (fileName) -> 15 | if text = ptr(RL.LoadFileText(fileName)) 16 | result = ffi.string(text) 17 | RL.UnloadFileText(text) 18 | return result 19 | 20 | saveData: (fileName, data, bytesToWrite) -> RL.SaveFileData(fileName, data, bytesToWrite or #data) 21 | 22 | saveText: RL.SaveFileText 23 | fileExists: RL.FileExists 24 | directoryExists: RL.DirectoryExists 25 | getFileLength: RL.GetFileLength 26 | isFileExtension: RL.IsFileExtension 27 | getFileExtension: RL.GetFileExtension 28 | getFileName: RL.GetFileName 29 | getFileNameWithoutExt: RL.GetFileNameWithoutExt 30 | getDirectoryPath: RL.GetDirectoryPath 31 | getPrevDirectoryPath: RL.GetPrevDirectoryPath 32 | getWorkingDirectory: RL.GetWorkingDirectory 33 | getApplicationDirectory: RL.GetApplicationDirectory 34 | changeDirectory: RL.ChangeDirectory 35 | getModTime: RL.GetFileModTime 36 | isFileDropped: RL.IsFileDropped 37 | 38 | getDirectoryFiles: (dirPath) -> 39 | count = ffi.new('int[1]') 40 | files = RL.GetDirectoryFiles(dirPath, count) 41 | result = [ ffi.string(files[i]) for i = 0, count[0] - 1 ] 42 | RL.ClearDirectoryFiles! 43 | result 44 | 45 | getDroppedFiles: -> 46 | count = ffi.new('int[1]') 47 | files = RL.GetDroppedFiles(count) 48 | result = [ ffi.string(files[i]) for i = 0, count[0] - 1 ] 49 | RL.ClearDroppedFiles! 50 | result 51 | 52 | } 53 | -------------------------------------------------------------------------------- /lib/ray/init.yue: -------------------------------------------------------------------------------- 1 | with yuema 2 | .audio = require('lib.ray.audio') 3 | .collision = require('lib.ray.collision') 4 | .config = require('lib.ray.config') 5 | .data = require('lib.ray.data') 6 | .draw = require('lib.ray.draw') 7 | .filesystem = require('lib.ray.filesystem') 8 | .gui = require('lib.ray.gui') 9 | .input = require('lib.ray.input') 10 | .log = require('lib.ray.log') 11 | .text = require('lib.ray.text') 12 | .time = require('lib.ray.time') 13 | .util = require('lib.ray.util') 14 | .window = require('lib.ray.window') 15 | 16 | .Color = require('lib.ray.Color') 17 | .Rectangle = require('lib.ray.Rectangle') 18 | .NPatchInfo = require('lib.ray.NPatchInfo') 19 | .BoundingBox = require('lib.ray.BoundingBox') 20 | 21 | .Camera2D = require('lib.ray.Camera2D') 22 | .Camera3D = require('lib.ray.Camera3D') 23 | .Image = require('lib.ray.Image') 24 | .Texture2D = require('lib.ray.Texture2D') 25 | .RenderTexture = require('lib.ray.RenderTexture') 26 | .Font = require('lib.ray.Font') 27 | .Mesh = require('lib.ray.Mesh') 28 | .Model = require('lib.ray.Model') 29 | .Shader = require('lib.ray.Shader') 30 | .Material = require('lib.ray.Material') 31 | -------------------------------------------------------------------------------- /lib/ray/input.yue: -------------------------------------------------------------------------------- 1 | import RL from yuema 2 | import 'ffi' as :C 3 | 4 | gestures = { 5 | NONE: C.GESTURE_NONE 6 | TAP: C.GESTURE_TAP 7 | DOUBLETAP: C.GESTURE_DOUBLETAP 8 | HOLD: C.GESTURE_HOLD 9 | DRAG: C.GESTURE_DRAG 10 | SWIPE_RIGHT: C.GESTURE_SWIPE_RIGHT 11 | SWIPE_LEFT: C.GESTURE_SWIPE_LEFT 12 | SWIPE_UP: C.GESTURE_SWIPE_UP 13 | SWIPE_DOWN: C.GESTURE_SWIPE_DOWN 14 | PINCH_IN: C.GESTURE_PINCH_IN 15 | PINCH_OUT: C.GESTURE_PINCH_OUT 16 | 17 | setEnabled: RL.SetGesturesEnabled 18 | isGestureDetected: RL.IsGestureDetected 19 | getGestureDetected: RL.GetGestureDetected 20 | getHoldDuration: RL.GetGestureHoldDuration 21 | getDragVector: RL.GetGestureDragVector 22 | getDragAngle: RL.GetGestureDragAngle 23 | getPinchVector: RL.GetGesturePinchVector 24 | getPinchAngle: RL.GetGesturePinchAngle 25 | } 26 | 27 | gamepad = { 28 | BUTTON_UNKNOWN: C.GAMEPAD_BUTTON_UNKNOWN 29 | BUTTON_LEFT_FACE_UP: C.GAMEPAD_BUTTON_LEFT_FACE_UP 30 | BUTTON_LEFT_FACE_RIGHT: C.GAMEPAD_BUTTON_LEFT_FACE_RIGHT 31 | BUTTON_LEFT_FACE_DOWN: C.GAMEPAD_BUTTON_LEFT_FACE_DOWN 32 | BUTTON_LEFT_FACE_LEFT: C.GAMEPAD_BUTTON_LEFT_FACE_LEFT 33 | BUTTON_RIGHT_FACE_UP: C.GAMEPAD_BUTTON_RIGHT_FACE_UP 34 | BUTTON_RIGHT_FACE_RIGHT: C.GAMEPAD_BUTTON_RIGHT_FACE_RIGHT 35 | BUTTON_RIGHT_FACE_DOWN: C.GAMEPAD_BUTTON_RIGHT_FACE_DOWN 36 | BUTTON_RIGHT_FACE_LEFT: C.GAMEPAD_BUTTON_RIGHT_FACE_LEFT 37 | BUTTON_LEFT_TRIGGER_1: C.GAMEPAD_BUTTON_LEFT_TRIGGER_1 38 | BUTTON_LEFT_TRIGGER_2: C.GAMEPAD_BUTTON_LEFT_TRIGGER_2 39 | BUTTON_RIGHT_TRIGGER_1: C.GAMEPAD_BUTTON_RIGHT_TRIGGER_1 40 | BUTTON_RIGHT_TRIGGER_2: C.GAMEPAD_BUTTON_RIGHT_TRIGGER_2 41 | BUTTON_MIDDLE_LEFT: C.GAMEPAD_BUTTON_MIDDLE_LEFT 42 | BUTTON_MIDDLE: C.GAMEPAD_BUTTON_MIDDLE 43 | BUTTON_MIDDLE_RIGHT: C.GAMEPAD_BUTTON_MIDDLE_RIGHT 44 | BUTTON_LEFT_THUMB: C.GAMEPAD_BUTTON_LEFT_THUMB 45 | BUTTON_RIGHT_THUMB: C.GAMEPAD_BUTTON_RIGHT_THUMB 46 | 47 | AXIS_LEFT_X: C.GAMEPAD_AXIS_LEFT_X 48 | AXIS_LEFT_Y: C.GAMEPAD_AXIS_LEFT_Y 49 | AXIS_RIGHT_X: C.GAMEPAD_AXIS_RIGHT_X 50 | AXIS_RIGHT_Y: C.GAMEPAD_AXIS_RIGHT_Y 51 | AXIS_LEFT_TRIGGER: C.GAMEPAD_AXIS_LEFT_TRIGGER 52 | AXIS_RIGHT_TRIGGER: C.GAMEPAD_AXIS_RIGHT_TRIGGER 53 | 54 | isAvailable: RL.IsGamepadAvailable 55 | getName: RL.GetGamepadName 56 | isPressed: RL.IsGamepadButtonPressed 57 | isDown: RL.IsGamepadButtonDown 58 | isReleased: RL.IsGamepadButtonReleased 59 | isUp: RL.IsGamepadButtonUp 60 | getPressed: RL.GetGamepadButtonPressed 61 | getAxisCount: RL.GetGamepadAxisCount 62 | getAxisMovement: RL.GetGamepadAxisMovement 63 | getMappings: RL.SetGamepadMappings 64 | } 65 | 66 | keyboard = { 67 | NULL: C.KEY_NULL 68 | APOSTROPHE: C.KEY_APOSTROPHE 69 | COMMA: C.KEY_COMMA 70 | MINUS: C.KEY_MINUS 71 | PERIOD: C.KEY_PERIOD 72 | SLASH: C.KEY_SLASH 73 | ZERO: C.KEY_ZERO 74 | ONE: C.KEY_ONE 75 | TWO: C.KEY_TWO 76 | THREE: C.KEY_THREE 77 | FOUR: C.KEY_FOUR 78 | FIVE: C.KEY_FIVE 79 | SIX: C.KEY_SIX 80 | SEVEN: C.KEY_SEVEN 81 | EIGHT: C.KEY_EIGHT 82 | NINE: C.KEY_NINE 83 | SEMICOLON: C.KEY_SEMICOLON 84 | EQUAL: C.KEY_EQUAL 85 | A: C.KEY_A 86 | B: C.KEY_B 87 | C: C.KEY_C 88 | D: C.KEY_D 89 | E: C.KEY_E 90 | F: C.KEY_F 91 | G: C.KEY_G 92 | H: C.KEY_H 93 | I: C.KEY_I 94 | J: C.KEY_J 95 | K: C.KEY_K 96 | L: C.KEY_L 97 | M: C.KEY_M 98 | N: C.KEY_N 99 | O: C.KEY_O 100 | P: C.KEY_P 101 | Q: C.KEY_Q 102 | R: C.KEY_R 103 | S: C.KEY_S 104 | T: C.KEY_T 105 | U: C.KEY_U 106 | V: C.KEY_V 107 | W: C.KEY_W 108 | X: C.KEY_X 109 | Y: C.KEY_Y 110 | Z: C.KEY_Z 111 | LEFT_BRACKET: C.KEY_LEFT_BRACKET 112 | BACKSLASH: C.KEY_BACKSLASH 113 | RIGHT_BRACKET: C.KEY_RIGHT_BRACKET 114 | GRAVE: C.KEY_GRAVE 115 | SPACE: C.KEY_SPACE 116 | ESCAPE: C.KEY_ESCAPE 117 | ENTER: C.KEY_ENTER 118 | TAB: C.KEY_TAB 119 | BACKSPACE: C.KEY_BACKSPACE 120 | INSERT: C.KEY_INSERT 121 | DELETE: C.KEY_DELETE 122 | RIGHT: C.KEY_RIGHT 123 | LEFT: C.KEY_LEFT 124 | DOWN: C.KEY_DOWN 125 | UP: C.KEY_UP 126 | PAGE_UP: C.KEY_PAGE_UP 127 | PAGE_DOWN: C.KEY_PAGE_DOWN 128 | HOME: C.KEY_HOME 129 | END: C.KEY_END 130 | CAPS_LOCK: C.KEY_CAPS_LOCK 131 | SCROLL_LOCK: C.KEY_SCROLL_LOCK 132 | NUM_LOCK: C.KEY_NUM_LOCK 133 | PRINT_SCREEN: C.KEY_PRINT_SCREEN 134 | PAUSE: C.KEY_PAUSE 135 | F1: C.KEY_F1 136 | F2: C.KEY_F2 137 | F3: C.KEY_F3 138 | F4: C.KEY_F4 139 | F5: C.KEY_F5 140 | F6: C.KEY_F6 141 | F7: C.KEY_F7 142 | F8: C.KEY_F8 143 | F9: C.KEY_F9 144 | F10: C.KEY_F10 145 | F11: C.KEY_F11 146 | F12: C.KEY_F12 147 | LEFT_SHIFT: C.KEY_LEFT_SHIFT 148 | LEFT_CONTROL: C.KEY_LEFT_CONTROL 149 | LEFT_ALT: C.KEY_LEFT_ALT 150 | LEFT_SUPER: C.KEY_LEFT_SUPER 151 | RIGHT_SHIFT: C.KEY_RIGHT_SHIFT 152 | RIGHT_CONTROL: C.KEY_RIGHT_CONTROL 153 | RIGHT_ALT: C.KEY_RIGHT_ALT 154 | RIGHT_SUPER: C.KEY_RIGHT_SUPER 155 | KB_MENU: C.KEY_KB_MENU 156 | KP_0: C.KEY_KP_0 157 | KP_1: C.KEY_KP_1 158 | KP_2: C.KEY_KP_2 159 | KP_3: C.KEY_KP_3 160 | KP_4: C.KEY_KP_4 161 | KP_5: C.KEY_KP_5 162 | KP_6: C.KEY_KP_6 163 | KP_7: C.KEY_KP_7 164 | KP_8: C.KEY_KP_8 165 | KP_9: C.KEY_KP_9 166 | KP_DECIMAL: C.KEY_KP_DECIMAL 167 | KP_DIVIDE: C.KEY_KP_DIVIDE 168 | KP_MULTIPLY: C.KEY_KP_MULTIPLY 169 | KP_SUBTRACT: C.KEY_KP_SUBTRACT 170 | KP_ADD: C.KEY_KP_ADD 171 | KP_ENTER: C.KEY_KP_ENTER 172 | KP_EQUAL: C.KEY_KP_EQUAL 173 | BACK: C.KEY_BACK 174 | MENU: C.KEY_MENU 175 | VOLUME_UP: C.KEY_VOLUME_UP 176 | VOLUME_DOWN: C.KEY_VOLUME_DOWN 177 | 178 | isPressed: RL.IsKeyPressed 179 | isDown: RL.IsKeyDown 180 | isReleased: RL.IsKeyReleased 181 | isUp: RL.IsKeyUp 182 | setExitKey: RL.SetExitKey 183 | getPressed: RL.GetKeyPressed 184 | getCharPressed: RL.GetCharPressed 185 | } 186 | 187 | mouse = { 188 | BUTTON_LEFT: C.MOUSE_BUTTON_LEFT 189 | BUTTON_RIGHT: C.MOUSE_BUTTON_RIGHT 190 | BUTTON_MIDDLE: C.MOUSE_BUTTON_MIDDLE 191 | BUTTON_SIDE: C.MOUSE_BUTTON_SIDE 192 | BUTTON_EXTRA: C.MOUSE_BUTTON_EXTRA 193 | BUTTON_FORWARD: C.MOUSE_BUTTON_FORWARD 194 | BUTTON_BACK: C.MOUSE_BUTTON_BACK 195 | 196 | CURSOR_DEFAULT: C.MOUSE_CURSOR_DEFAULT 197 | CURSOR_ARROW: C.MOUSE_CURSOR_ARROW 198 | CURSOR_IBEAM: C.MOUSE_CURSOR_IBEAM 199 | CURSOR_CROSSHAIR: C.MOUSE_CURSOR_CROSSHAIR 200 | CURSOR_POINTING_HAND: C.MOUSE_CURSOR_POINTING_HAND 201 | CURSOR_RESIZE_EW: C.MOUSE_CURSOR_RESIZE_EW 202 | CURSOR_RESIZE_NS: C.MOUSE_CURSOR_RESIZE_NS 203 | CURSOR_RESIZE_NWSE: C.MOUSE_CURSOR_RESIZE_NWSE 204 | CURSOR_RESIZE_NESW: C.MOUSE_CURSOR_RESIZE_NESW 205 | CURSOR_RESIZE_ALL: C.MOUSE_CURSOR_RESIZE_ALL 206 | CURSOR_NOT_ALLOWED: C.MOUSE_CURSOR_NOT_ALLOWED 207 | 208 | isPressed: RL.IsMouseButtonPressed 209 | isDown: RL.IsMouseButtonDown 210 | isReleased: RL.IsMouseButtonReleased 211 | isUp: RL.IsMouseButtonUp 212 | 213 | getX: RL.GetMouseX 214 | getY: RL.GetMouseY 215 | getPosition: RL.GetMousePosition 216 | getDelta: RL.GetMouseDelta 217 | getWheelMove: RL.GetMouseWheelMove 218 | 219 | setPosition: RL.SetMousePosition 220 | setOffset: RL.SetMouseOffset 221 | setScale: RL.SetMouseScale 222 | setCursor: RL.SetMouseCursor 223 | 224 | show: RL.ShowCursor 225 | hide: RL.HideCursor 226 | isHidden: RL.IsCursorHidden 227 | enable: RL.EnableCursor 228 | disable: RL.DisableCursor 229 | isOnScreen: RL.IsCursorOnScreen 230 | } 231 | 232 | touch = { 233 | getX: RL.GetTouchX 234 | getY: RL.GetTouchY 235 | getPosition: RL.GetTouchPosition 236 | getPointId: RL.GetTouchPointId 237 | getPointCount: RL.GetTouchPointCount 238 | } 239 | 240 | { 241 | :gestures 242 | :gamepad 243 | :keyboard 244 | :mouse 245 | :touch 246 | } 247 | -------------------------------------------------------------------------------- /lib/ray/lights.yue: -------------------------------------------------------------------------------- 1 | -- TODO: WIP! terrible code! 2 | ------------------------------------------------------------------------------------------------ 3 | -- 4 | -- raylib.lights - Some useful functions to deal with lights data 5 | -- 6 | -- LICENSE: zlib/libpng 7 | -- 8 | -- Copyright (c) 2017-2020 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) 9 | -- 10 | -- Yuescript version (c) 2022 megagrump 11 | -- 12 | -- This software is provided "as-is", without any express or implied warranty. In no event 13 | -- will the authors be held liable for any damages arising from the use of this software. 14 | -- 15 | -- Permission is granted to anyone to use this software for any purpose, including commercial 16 | -- applications, and to alter it and redistribute it freely, subject to the following restrictions: 17 | -- 18 | -- 1. The origin of this software must not be misrepresented; you must not claim that you 19 | -- wrote the original software. If you use this software in a product, an acknowledgment 20 | -- in the product documentation would be appreciated but is not required. 21 | -- 22 | -- 2. Altered source versions must be plainly marked as such, and must not be misrepresented 23 | -- as being the original software. 24 | -- 25 | -- 3. This notice may not be removed or altered from any source distribution. 26 | -- 27 | ----------------------------------------------------------------------------------------------- 28 | import 'ffi' 29 | 30 | ffi.cdef([[ 31 | typedef struct { 32 | int type; 33 | Vector3 position; 34 | Vector3 target; 35 | Color color; 36 | bool enabled; 37 | 38 | // Shader locations 39 | int enabledLoc; 40 | int typeLoc; 41 | int posLoc; 42 | int targetLoc; 43 | int colorLoc; 44 | } Light; 45 | ]]) 46 | 47 | Light = ffi.typeof('Light') 48 | 49 | lightsCount = 0 50 | 51 | LightMT = { 52 | DIRECTIONAL: 0 53 | POINT: 1 54 | 55 | __new: (type, position, target, color, shader) => 56 | light = with ffi.new(@, type, position, target, color, true) 57 | .enabledLoc = shader::getLocation('lights[%d].enabled'::format(lightsCount)) 58 | .typeLoc = shader::getLocation('lights[%d].type'::format(lightsCount)) 59 | .posLoc = shader::getLocation('lights[%d].pos'::format(lightsCount)) 60 | .targetLoc = shader::getLocation('lights[%d].target'::format(lightsCount)) 61 | .colorLoc = shader::getLocation('lights[%d].color'::format(lightsCount)) 62 | 63 | lightsCount += 1 64 | light::update(shader) 65 | light 66 | 67 | update: (shader) => 68 | with shader 69 | ::setValue(@enabledLoc, @enabled, Shader.UNIFORM_INT) 70 | ::setValue(@typeLoc, @type, Shader.UNIFORM_INT) 71 | ::setValue(@posLoc, @position, Shader.UNIFORM_VEC3) 72 | ::setValue(@targetLoc, @target, Shader.UNIFORM_VEC3) 73 | ::setValue(@colorLoc, @color::normalize!, Shader.UNIFORM_VEC4) 74 | } 75 | 76 | LightMT.__index = LightMT 77 | 78 | ffi.metatype(Light, LightMT) 79 | 80 | -- void UpdateLightValues(Shader shader, Light light) 81 | -- { 82 | -- // Send to shader light enabled state and type 83 | -- SetShaderValue(shader, light.enabledLoc, &light.enabled, SHADER_UNIFORM_INT); 84 | -- SetShaderValue(shader, light.typeLoc, &light.type, SHADER_UNIFORM_INT); 85 | 86 | -- // Send to shader light position values 87 | -- float position[3] = { light.position.x, light.position.y, light.position.z }; 88 | -- SetShaderValue(shader, light.posLoc, position, SHADER_UNIFORM_VEC3); 89 | 90 | -- // Send to shader light target position values 91 | -- float target[3] = { light.target.x, light.target.y, light.target.z }; 92 | -- SetShaderValue(shader, light.targetLoc, target, SHADER_UNIFORM_VEC3); 93 | 94 | -- // Send to shader light color values 95 | -- float color[4] = { (float)light.color.r/(float)255, (float)light.color.g/(float)255, 96 | -- (float)light.color.b/(float)255, (float)light.color.a/(float)255 }; 97 | -- SetShaderValue(shader, light.colorLoc, color, SHADER_UNIFORM_VEC4); 98 | -- } 99 | -------------------------------------------------------------------------------- /lib/ray/log.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' as :C 2 | import RL from yuema 3 | 4 | log = { 5 | ALL: C.LOG_ALL 6 | TRACE: C.LOG_TRACE 7 | DEBUG: C.LOG_DEBUG 8 | INFO: C.LOG_INFO 9 | WARNING: C.LOG_WARNING 10 | ERROR: C.LOG_ERROR 11 | FATAL: C.LOG_FATAL 12 | NONE: C.LOG_NONE 13 | 14 | trace: RL.TraceLog 15 | setLevel: RL.SetTraceLogLevel 16 | } 17 | 18 | log.setLevel(log.WARNING) 19 | 20 | log 21 | -------------------------------------------------------------------------------- /lib/ray/text.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | import 'lib.ray.data' as :memFree 4 | 5 | { 6 | loadCodepoints: (text) -> 7 | count = ffi.new('int[1]') 8 | cp = RL.LoadCodepoints(text, count) 9 | cp, tonumber(count[0]) 10 | 11 | getCodepointCount: RL.GetCodepointCount 12 | 13 | getCodepoint: (text) -> 14 | bytesProcessed = ffi.new('int[1]') 15 | result = RL.GetCodepoint(text, bytesProcessed) 16 | result, tonumber(bytesProcessed[0]) 17 | 18 | codepointToUTF8: (codepoint) -> 19 | byteSize = ffi.new('int[1]') 20 | result = RL.CodepointToUTF8(codepoint, byteSize) 21 | ffi.string(result, byteSize[0]) 22 | 23 | codepointsToUTF8: (codepoints, length) -> 24 | result = RL.TextCodepointsToUTF8(codepoints, length) 25 | str = ffi.string(result) 26 | memFree(result) 27 | str 28 | } 29 | -------------------------------------------------------------------------------- /lib/ray/time.yue: -------------------------------------------------------------------------------- 1 | import RL from yuema 2 | 3 | { 4 | setTargetFPS: RL.SetTargetFPS 5 | getFPS: RL.GetFPS 6 | getFrameTime: RL.GetFrameTime 7 | getTime: RL.GetTime 8 | wait: RL.WaitTime 9 | } 10 | -------------------------------------------------------------------------------- /lib/ray/util.yue: -------------------------------------------------------------------------------- 1 | import 'ffi' 2 | import RL from yuema 3 | 4 | { 5 | setClipboardText: RL.SetClipboardText 6 | getClipboardText: -> ffi.string(RL.GetClipboardText!) 7 | 8 | openURL: RL.OpenURL 9 | 10 | takeScreenshot: RL.TakeScreenshot 11 | 12 | getPixelDataSize: RL.GetPixelDataSize 13 | 14 | getRandomValue: RL.GetRandomValue 15 | setRandomSeed: RL.SetRandomSeed 16 | } 17 | -------------------------------------------------------------------------------- /lib/ray/window.yue: -------------------------------------------------------------------------------- 1 | import RL from yuema 2 | 3 | { 4 | init: RL.InitWindow 5 | shouldClose: RL.WindowShouldClose 6 | close: RL.CloseWindow 7 | isReady: RL.IsWindowReady 8 | isFullscreen: RL.IsWindowFullscreen 9 | isHidden: RL.IsWindowHidden 10 | isMinimized: RL.IsWindowMinimized 11 | isMaximized: RL.IsWindowMaximized 12 | isFocused: RL.IsWindowFocused 13 | isResized: RL.IsWindowResized 14 | 15 | isState: RL.IsWindowState 16 | setState: RL.SetWindowState 17 | clearState: RL.ClearWindowState 18 | 19 | toggleFullscreen: RL.ToggleFullscreen 20 | maximize: RL.MaximizeWindow 21 | minimize: RL.MinimizeWindow 22 | restore: RL.RestoreWindow 23 | 24 | getPosition: RL.GetWindowPosition 25 | getScaleDPI: RL.GetWindowScaleDPI 26 | getWidth: RL.GetScreenWidth 27 | getHeight: RL.GetScreenHeight 28 | getRenderWidth: RL.GetRenderWidth 29 | getRenderHeight: RL.GetRenderHeight 30 | 31 | setIcon: RL.SetWindowIcon 32 | setTitle: RL.SetWindowTitle 33 | setPosition: RL.SetWindowPosition 34 | setMonitor: RL.SetWindowMonitor 35 | setMinSize: RL.SetWindowMinSize 36 | setSize: RL.SetWindowSize 37 | setOpacity: RL.SetWindowOpacity 38 | 39 | getHandle: RL.GetWindowHandle 40 | getCurrentMonitor: RL.GetCurrentMonitor 41 | getMonitorCount: RL.GetMonitorCount 42 | getMonitorPosition: RL.GetMonitorPosition 43 | getMonitorWidth: RL.GetMonitorWidth 44 | getMonitorHeight: RL.GetMonitorHeight 45 | getMonitorPhysicalWidth: RL.GetMonitorPhysicalWidth 46 | getMonitorPhysicalHeight: RL.GetMonitorPhysicalHeight 47 | getMonitorRefreshRate: RL.GetMonitorRefreshRate 48 | getMonitorName: RL.GetMonitorName 49 | 50 | swapScreenBuffer: RL.SwapScreenBuffer 51 | pollInputEvents: RL.PollInputEvents 52 | } 53 | -------------------------------------------------------------------------------- /lib/util/Pool.yue: -------------------------------------------------------------------------------- 1 | import 'lib.util.Stack' 2 | 3 | class Pool 4 | new: (@_construct, @_initialize, @_deinitialize) => 5 | @_stack = Stack! 6 | 7 | pop: (...) => 8 | item = @_stack::pop! 9 | unless item 10 | item = @._construct(...) 11 | elseif @_initialize 12 | @._initialize(item, ...) 13 | item 14 | 15 | push: (item) => 16 | @._deinitialize(item) if @_deinitialize 17 | @_stack::push(item) 18 | item 19 | -------------------------------------------------------------------------------- /lib/util/Stack.yue: -------------------------------------------------------------------------------- 1 | class Stack 2 | new: => 3 | @[0] = 0 4 | 5 | push: (item) => 6 | n = @[0] + 1 7 | @[0], @[n] = n, item 8 | n 9 | 10 | pop: => 11 | n = @[0] 12 | return if n == 0 13 | item = @[n] 14 | @[0], @[n] = n - 1, nil 15 | item 16 | 17 | peek: (n) => @[n] 18 | 19 | size: => @[0] 20 | -------------------------------------------------------------------------------- /lib/util/ptr.yue: -------------------------------------------------------------------------------- 1 | ptr = => @ ~= nil and @ or nil -- NULL -> nil, because NULL is a truthy value in LuaJIT 2 | 3 | ptr 4 | -------------------------------------------------------------------------------- /lib/util/table.yue: -------------------------------------------------------------------------------- 1 | require('table.new') 2 | require('table.clear') 3 | import floor from math 4 | import insert from table 5 | 6 | MAX_SORT_CHUNK = 72 7 | 8 | stablesortcmp = (a, b) -> a < b 9 | 10 | insertion_sort = (array, first, last, cmp) -> 11 | for i = first + 1, last 12 | k, v = first, array[i] 13 | for j = i, first + 1, -1 14 | if cmp(v, array[j - 1]) 15 | array[j] = array[j - 1] 16 | else 17 | k = j 18 | break 19 | array[k] = v 20 | 21 | merge = (array, workspace, low, middle, high, cmp) -> 22 | i = 1 23 | -- Copy first half of array to auxiliary array 24 | for j = low, middle 25 | workspace[i] = array[j] 26 | i += 1 27 | 28 | i, j, k = 1, middle + 1, low 29 | while true 30 | break if k >= j or j > high 31 | if cmp(array[j], workspace[i]) 32 | array[k] = array[j] 33 | j += 1 34 | else 35 | array[k] = workspace[i] 36 | i += 1 37 | k += 1 38 | 39 | -- Copy back any remaining elements of first half 40 | for k = k, j - 1 41 | array[k] = workspace[i] 42 | i += 1 43 | 44 | merge_sort = (array, workspace, low, high, cmp) -> 45 | if high - low < MAX_SORT_CHUNK 46 | insertion_sort(array, low, high, cmp) 47 | else 48 | middle = floor((low + high) / 2) 49 | merge_sort(array, workspace, low, middle, cmp) 50 | merge_sort(array, workspace, middle + 1, high, cmp) 51 | merge(array, workspace, low, middle, high, cmp) 52 | 53 | binsearchcmp = (a, b) -> b - a 54 | 55 | binsearch = (t, item, low, high, cmp) -> 56 | return if high < low 57 | mid = floor((low + high) / 2) 58 | rel = cmp(t[mid], item) 59 | return mid if rel == 0 60 | return binsearch(t, item, mid + 1, high, cmp) if rel > 0 61 | binsearch(t, item, low, mid - 1, cmp) 62 | 63 | insertsorted = (t, item, low, high, cmp) -> 64 | return low, insert(t, low, item) if high < low 65 | mid = floor((low + high) / 2) 66 | rel = cmp(t[mid], item) 67 | return mid, insert(t, mid, item) if rel == 0 68 | return insertsorted(t, item, mid + 1, high, cmp) if rel > 0 69 | insertsorted(t, item, low, mid - 1, cmp) 70 | 71 | with {} 72 | .# = __index: table 73 | 74 | .indexof = (item) => 75 | return i for i = 1, #@ when item == @[i] 76 | 77 | .keyof = (item) => 78 | return k for k, v in pairs(@) when item == v 79 | 80 | .swapout = (index) => 81 | l = #@ 82 | @[index] = @[l] 83 | @[l] = nil 84 | 85 | .binsearch = (item, cmp = binsearchcmp) => 86 | binsearch(@, item, 1, #@, cmp) 87 | 88 | .insertsorted = (item, cmp = binsearchcmp) => 89 | insertsorted(@, item, 1, #@, cmp) 90 | 91 | .stablesort = (cmp = stablesortcmp) => 92 | n = #@ 93 | return @ if n < 2 94 | 95 | h = floor((n + 1) / 2) 96 | workspace = table.new(h, 0) 97 | workspace[h] = @[1] 98 | merge_sort(@, workspace, 1, n, cmp) 99 | @ 100 | -------------------------------------------------------------------------------- /main.lua: -------------------------------------------------------------------------------- 1 | print("hello.") 2 | -------------------------------------------------------------------------------- /src/box2dc/box2dc.cpp: -------------------------------------------------------------------------------- 1 | #include "b2_world.h" 2 | #include "b2_fixture.h" 3 | #include "b2_body.h" 4 | #include "b2_collision.h" 5 | #include "b2_draw.h" 6 | #include "b2_world_callbacks.h" 7 | #include "box2dc.h" 8 | #include "util.h" 9 | 10 | // --------- b2Body --------------- 11 | 12 | b2Fixture *b2Body_CreateFixture(b2Body *body, b2Shape *shape, float density) { return body->CreateFixture(shape, density); } 13 | void b2Body_DestroyFixture(b2Body *body, b2Fixture *fixture) { body->DestroyFixture(fixture); } 14 | void b2Body_SetTransform(b2Body *body, float tx, float ty, float angle) { body->SetTransform(b2Vec2(tx, ty), angle); } 15 | 16 | Vector2 *b2Body_GetPosition(b2Body *body, Vector2 *output) { 17 | return convertVector(body->GetPosition(), output); 18 | } 19 | 20 | float b2Body_GetAngle(b2Body *body) { return body->GetAngle(); } 21 | 22 | Vector2 *b2Body_GetWorldCenter(b2Body *body, Vector2 *output) { 23 | return convertVector(body->GetWorldCenter(), output); 24 | } 25 | 26 | Vector2 *b2Body_GetLocalCenter(b2Body *body, Vector2 *output) { 27 | return convertVector(body->GetLocalCenter(), output); 28 | } 29 | 30 | void b2Body_SetLinearVelocity(b2Body *body, float x, float y) { 31 | body->SetLinearVelocity(b2Vec2(x, y)); 32 | } 33 | 34 | Vector2 *b2Body_GetLinearVelocity(b2Body *body, Vector2 *output) { 35 | return convertVector(body->GetLinearVelocity(), output); 36 | } 37 | 38 | void b2Body_SetAngularVelocity(b2Body *body, float omega) { 39 | body->SetAngularVelocity(omega); 40 | } 41 | 42 | float b2Body_GetAngularVelocity(b2Body *body) { return body->GetAngularVelocity(); } 43 | 44 | void b2Body_ApplyForce(b2Body *body, float forceX, float forceY, float x, float y, bool wake) { 45 | body->ApplyForce(b2Vec2(forceX, forceY), b2Vec2(x, y), wake); 46 | } 47 | 48 | void b2Body_ApplyForceToCenter(b2Body *body, float forceX, float forceY, bool wake) { 49 | body->ApplyForceToCenter(b2Vec2(forceX, forceY), wake); 50 | } 51 | 52 | void b2Body_ApplyTorque(b2Body *body, float torque, bool wake) { body->ApplyTorque(torque, wake); } 53 | 54 | void b2Body_ApplyLinearImpulse(b2Body *body, float impulseX, float impulseY, float x, float y, bool wake) { 55 | body->ApplyLinearImpulse(b2Vec2(impulseX, impulseY), b2Vec2(x, y), wake); 56 | } 57 | 58 | void b2Body_ApplyLinearImpulseToCenter(b2Body *body, float impulseX, float impulseY, bool wake) { 59 | body->ApplyLinearImpulseToCenter(b2Vec2(impulseX, impulseY), wake); 60 | } 61 | 62 | void b2Body_ApplyAngularImpulse(b2Body *body, float impulse, bool wake) { body->ApplyAngularImpulse(impulse, wake); } 63 | float b2Body_GetMass(b2Body *body) { return body->GetMass(); } 64 | float b2Body_GetInertia(b2Body *body) { return body->GetInertia(); } 65 | 66 | b2cMassData *b2Body_GetMassData(b2Body *body, b2cMassData *output) { 67 | b2MassData data = body->GetMassData(); 68 | output->x = data.center.x; 69 | output->y = data.center.y; 70 | output->mass = data.mass; 71 | output->inertia = data.I; 72 | return output; 73 | } 74 | 75 | void b2Body_SetMassData(b2Body *body, float x, float y, float mass, float inertia) { 76 | b2MassData data; 77 | data.mass = mass; 78 | data.center.x = x; 79 | data.center.y = y; 80 | data.I = inertia; 81 | body->SetMassData(&data); 82 | } 83 | 84 | void b2Body_ResetMassData(b2Body *body) { body->ResetMassData(); } 85 | 86 | Vector2 *b2Body_GetWorldPoint(b2Body *body, float localX, float localY, Vector2 *output) { 87 | return convertVector(body->GetWorldPoint(b2Vec2(localX, localY)), output); 88 | } 89 | 90 | Vector2 *b2Body_GetWorldVector(b2Body *body, float localX, float localY, Vector2 *output) { 91 | return convertVector(body->GetWorldVector(b2Vec2(localX, localY)), output); 92 | } 93 | 94 | Vector2 *b2Body_GetLocalPoint(b2Body *body, float worldX, float worldY, Vector2 *output) { 95 | return convertVector(body->GetLocalPoint(b2Vec2(worldX, worldY)), output); 96 | } 97 | 98 | Vector2 *b2Body_GetLocalVector(b2Body *body, float worldX, float worldY, Vector2 *output) { 99 | return convertVector(body->GetLocalVector(b2Vec2(worldX, worldY)), output); 100 | } 101 | 102 | Vector2 *b2Body_GetLinearVelocityFromWorldPoint(b2Body *body, float worldX, float worldY, Vector2 *output) { 103 | return convertVector(body->GetLinearVelocityFromWorldPoint(b2Vec2(worldX, worldY)), output); 104 | } 105 | 106 | Vector2 *b2Body_GetLinearVelocityFromLocalPoint(b2Body *body, float localX, float localY, Vector2 *output) { 107 | return convertVector(body->GetLinearVelocityFromLocalPoint(b2Vec2(localX, localY)), output); 108 | } 109 | 110 | float b2Body_GetLinearDamping(b2Body *body) { return body->GetLinearDamping(); } 111 | void b2Body_SetLinearDamping(b2Body *body, float linearDamping) { body->SetLinearDamping(linearDamping); } 112 | float b2Body_GetAngularDamping(b2Body *body) { return body->GetAngularDamping(); } 113 | void b2Body_SetAngularDamping(b2Body *body, float angularDamping) { body->SetAngularDamping(angularDamping); } 114 | float b2Body_GetGravityScale(b2Body *body) { return body->GetGravityScale(); } 115 | void b2Body_SetGravityScale(b2Body *body, float scale) { body->SetGravityScale(scale); } 116 | void b2Body_SetType(b2Body *body, int type) { body->SetType((b2BodyType)type); } 117 | int b2Body_GetType(b2Body *body) { return body->GetType(); } 118 | void b2Body_SetBullet(b2Body *body, bool flag) { body->SetBullet(flag); } 119 | bool b2Body_IsBullet(b2Body *body) { return body->IsBullet(); } 120 | void b2Body_SetSleepingAllowed(b2Body *body, bool flag) { body->SetSleepingAllowed(flag); } 121 | bool b2Body_IsSleepingAllowed(b2Body *body) { return body->IsSleepingAllowed(); } 122 | void b2Body_SetAwake(b2Body *body, bool flag) { body->SetAwake(flag); } 123 | bool b2Body_IsAwake(b2Body *body) { return body->IsAwake(); } 124 | void b2Body_SetEnabled(b2Body *body, bool flag) { body->SetEnabled(flag); } 125 | bool b2Body_IsEnabled(b2Body *body) { return body->IsEnabled(); } 126 | void b2Body_SetFixedRotation(b2Body *body, bool flag) { body->SetFixedRotation(flag); } 127 | bool b2Body_IsFixedRotation(b2Body *body) { return body->IsFixedRotation(); } 128 | b2Fixture *b2Body_GetFixtureList(b2Body *body) { return body->GetFixtureList(); } 129 | //b2JointEdge *b2Body_GetJointList(b2Body *body) { return body->GetJointList(); } 130 | //b2ContactEdge *b2Body_GetContactList(b2Body *body) { return body->GetContactList(); } 131 | b2Body *b2Body_GetNext(b2Body *body) { return body->GetNext(); } 132 | uintptr_t b2Body_GetUserData(b2Body *body) { return body->GetUserData().pointer; } 133 | void b2Body_SetUserData(b2Body *body, uintptr_t data) { body->GetUserData().pointer = data; } 134 | b2World *b2Body_GetWorld(b2Body *body) { return body->GetWorld(); } 135 | void b2Body_Dump(b2Body *body) { body->Dump(); } 136 | 137 | // --------- b2Fixture --------------- 138 | 139 | int b2Fixture_GetType(b2Fixture *fixture) { return fixture->GetType(); } 140 | b2Shape *b2Fixture_GetShape(b2Fixture *fixture) { return fixture->GetShape(); } 141 | void b2Fixture_SetSensor(b2Fixture *fixture, bool sensor) { fixture->SetSensor(sensor); } 142 | bool b2Fixture_IsSensor(b2Fixture *fixture) { return fixture->IsSensor(); } 143 | void b2Fixture_SetFilterData(b2Fixture *fixture, uint16_t category, uint16_t mask, int16_t group) { 144 | b2Filter filter; 145 | filter.categoryBits = category; 146 | filter.maskBits = mask; 147 | filter.groupIndex = group; 148 | fixture->SetFilterData(filter); 149 | } 150 | 151 | b2cFilter *b2Fixture_GetFilterData(b2Fixture *fixture, b2cFilter *output) { 152 | const b2Filter &filter = fixture->GetFilterData(); 153 | output->category = filter.categoryBits; 154 | output->mask = filter.maskBits; 155 | output->group = filter.groupIndex; 156 | return output; 157 | } 158 | 159 | void b2Fixture_Refilter(b2Fixture *fixture) { fixture->Refilter(); } 160 | b2Body *b2Fixture_GetBody(b2Fixture *fixture) { return fixture->GetBody(); } 161 | b2Fixture *b2Fixture_GetNext(b2Fixture *fixture) { return fixture->GetNext(); } 162 | uintptr_t b2Fixture_GetUserData(b2Fixture *fixture) { return fixture->GetUserData().pointer; } 163 | void b2Fixture_SetUserData(b2Fixture *fixture, uintptr_t data) { fixture->GetUserData().pointer = data; } 164 | 165 | bool b2Fixture_TestPoint(b2Fixture *fixture, float x, float y) { return fixture->TestPoint(b2Vec2(x, y)); } 166 | b2cRayCastOutput *b2Fixture_RayCast(b2Fixture *fixture, float x1, float y1, float x2, float y2, 167 | float maxFraction, int childIndex, b2cRayCastOutput *output) { 168 | b2RayCastInput ray; 169 | ray.p1.x = x1; 170 | ray.p1.y = y1; 171 | ray.p2.x = x2; 172 | ray.p2.y = y2; 173 | ray.maxFraction = maxFraction; 174 | 175 | b2RayCastOutput cast; 176 | bool hit = fixture->RayCast(&cast, ray, childIndex); 177 | output->hit = hit; 178 | output->nx = cast.normal.x; 179 | output->ny = cast.normal.y; 180 | output->fraction = cast.fraction; 181 | return output; 182 | } 183 | 184 | b2cMassData *b2Fixture_GetMassData(b2Fixture *fixture, b2cMassData *output) { 185 | b2MassData data; 186 | fixture->GetMassData(&data); 187 | output->x = data.center.x; 188 | output->y = data.center.y; 189 | output->mass = data.mass; 190 | output->inertia = data.I; 191 | return output; 192 | } 193 | 194 | void b2Fixture_SetDensity(b2Fixture *fixture, float density) { fixture->SetDensity(density); } 195 | float b2Fixture_GetDensity(b2Fixture *fixture) { return fixture->GetDensity(); } 196 | float b2Fixture_GetFriction(b2Fixture *fixture) { return fixture->GetFriction(); } 197 | void b2Fixture_SetFriction(b2Fixture *fixture, float friction) { fixture->SetFriction(friction); } 198 | float b2Fixture_GetRestitution(b2Fixture *fixture) { return fixture->GetRestitution(); } 199 | void b2Fixture_SetRestitution(b2Fixture *fixture, float restitution) { fixture->SetRestitution(restitution); } 200 | float b2Fixture_GetRestitutionThreshold(b2Fixture *fixture) { return fixture->GetRestitutionThreshold(); } 201 | void b2Fixture_SetRestitutionThreshold(b2Fixture *fixture, float threshold) { fixture->SetRestitutionThreshold(threshold); } 202 | Rectangle *b2Fixture_GetAABB(b2Fixture *fixture, int childIndex, Rectangle *output) { 203 | const b2AABB &aabb = fixture->GetAABB(childIndex); 204 | float w = aabb.upperBound.x - aabb.lowerBound.x; 205 | float h = aabb.upperBound.y - aabb.lowerBound.y; 206 | output->x = aabb.lowerBound.x; 207 | output->y = aabb.lowerBound.y; 208 | output->width = w; 209 | output->height = h; 210 | return output; 211 | } 212 | 213 | void b2Fixture_Dump(b2Fixture *fixture, int bodyIndex) { fixture->Dump(bodyIndex); } 214 | 215 | // --------- b2Draw --------------- 216 | 217 | class DrawProxy : public b2Draw { 218 | public: 219 | void setCallbacks(b2cDraw *callbacks) { m_callbacks = callbacks; } 220 | 221 | void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override { 222 | for(int i = 0; i < vertexCount; ++i) { 223 | m_vertices[i].x = vertices[i].x; 224 | m_vertices[i].y = vertices[i].y; 225 | } 226 | m_callbacks->DrawPolygon(m_vertices, vertexCount, color.r, color.g, color.b, color.a); 227 | } 228 | 229 | void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override { 230 | for(int i = 0; i < vertexCount; ++i) { 231 | m_vertices[i].x = vertices[i].x; 232 | m_vertices[i].y = vertices[i].y; 233 | } 234 | m_callbacks->DrawSolidPolygon(m_vertices, vertexCount, color.r, color.g, color.b, color.a); 235 | } 236 | 237 | void DrawCircle(const b2Vec2& center, float radius, const b2Color& color) override { 238 | m_callbacks->DrawCircle(center.x, center.y, radius, color.r, color.g, color.b, color.a); 239 | } 240 | 241 | void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color) override { 242 | m_callbacks->DrawSolidCircle(center.x, center.y, radius, axis.x, axis.y, color.r, color.g, color.b, color.a); 243 | } 244 | 245 | void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) override { 246 | m_callbacks->DrawSegment(p1.x, p1.y, p2.x, p2.y, color.r, color.g, color.b, color.a); 247 | } 248 | 249 | void DrawTransform(const b2Transform& xf) override { 250 | m_callbacks->DrawTransform(xf.p.x, xf.p.y, xf.q.GetAngle()); 251 | } 252 | 253 | void DrawPoint(const b2Vec2& p, float size, const b2Color& color) override { 254 | m_callbacks->DrawPoint(p.x, p.y, size, color.r, color.g, color.b, color.a); 255 | } 256 | private: 257 | b2cDraw *m_callbacks; 258 | Vector2 m_vertices[b2_maxPolygonVertices]; 259 | }; 260 | 261 | static DrawProxy proxy; 262 | 263 | void b2Draw_Draw(b2World *world, b2cDraw *draw) { 264 | proxy.SetFlags(0xffff); 265 | proxy.setCallbacks(draw); 266 | world->SetDebugDraw(&proxy); 267 | world->DebugDraw(); 268 | world->SetDebugDraw(nullptr); 269 | } 270 | -------------------------------------------------------------------------------- /src/box2dc/contact.cpp: -------------------------------------------------------------------------------- 1 | #include "b2_fixture.h" 2 | #include "b2_contact.h" 3 | #include "box2dc.h" 4 | #include "util.h" 5 | 6 | static b2WorldManifold worldManifold; 7 | 8 | bool b2Contact_IsTouching(b2Contact *contact) { return contact->IsTouching(); } 9 | void b2Contact_SetEnabled(b2Contact *contact, bool flag) { contact->SetEnabled(flag); } 10 | bool b2Contact_IsEnabled(b2Contact *contact) { return contact->IsEnabled(); } 11 | b2Contact *b2Contact_GetNext(b2Contact *contact) { return contact->GetNext(); } 12 | b2Fixture *b2Contact_GetFixtureA(b2Contact *contact) { return contact->GetFixtureA(); } 13 | int b2Contact_GetChildIndexA(b2Contact *contact) { return contact->GetChildIndexA(); } 14 | b2Fixture *b2Contact_GetFixtureB(b2Contact *contact) { return contact->GetFixtureB(); } 15 | int b2Contact_GetChildIndexB(b2Contact *contact) { return contact->GetChildIndexB(); } 16 | void b2Contact_SetFriction(b2Contact *contact, float friction) { contact->SetFriction(friction); } 17 | float b2Contact_GetFriction(b2Contact *contact) { return contact->GetFriction(); } 18 | void b2Contact_ResetFriction(b2Contact *contact) { contact->ResetFriction(); } 19 | void b2Contact_SetRestitution(b2Contact *contact, float restitution) { contact->SetRestitution(restitution); } 20 | float b2Contact_GetRestitution(b2Contact *contact) { return contact->GetRestitution(); } 21 | void b2Contact_ResetRestitution(b2Contact *contact) { contact->ResetRestitution(); } 22 | void b2Contact_SetRestitutionThreshold(b2Contact *contact, float threshold) { contact->SetRestitutionThreshold(threshold); } 23 | float b2Contact_GetRestitutionThreshold(b2Contact *contact) { return contact->GetRestitutionThreshold(); } 24 | void b2Contact_ResetRestitutionThreshold(b2Contact *contact) { contact->ResetRestitutionThreshold(); } 25 | void b2Contact_SetTangentSpeed(b2Contact *contact, float speed) { contact->SetTangentSpeed(speed); } 26 | float b2Contact_GetTangentSpeed(b2Contact *contact) { return contact->GetTangentSpeed(); } 27 | 28 | Vector2 *b2Contact_GetNormal(b2Contact *contact, Vector2* output) { 29 | contact->GetWorldManifold(&worldManifold); 30 | return convertVector(worldManifold.normal, output); 31 | } 32 | 33 | int b2Contact_GetPoints(b2Contact *contact, Vector2 *output) { 34 | contact->GetWorldManifold(&worldManifold); 35 | int n = contact->GetManifold()->pointCount; 36 | for(int i = 0; i < n; ++i) { 37 | output[i].x = worldManifold.points[i].x; 38 | output[i].y = worldManifold.points[i].y; 39 | } 40 | 41 | return n; 42 | } 43 | -------------------------------------------------------------------------------- /src/box2dc/shapes.cpp: -------------------------------------------------------------------------------- 1 | #include "b2_circle_shape.h" 2 | #include "b2_chain_shape.h" 3 | #include "b2_edge_shape.h" 4 | #include "b2_polygon_shape.h" 5 | #include "box2dc.h" 6 | #include "util.h" 7 | 8 | b2cMassData *b2Shape_ComputeMass(b2Shape *shape, float density, b2cMassData *output) { 9 | b2MassData data; 10 | shape->ComputeMass(&data, density); 11 | output->x = data.center.x; 12 | output->y = data.center.y; 13 | output->mass = data.mass; 14 | output->inertia = data.I; 15 | return output; 16 | } 17 | 18 | Rectangle *b2Shape_ComputeAABB(b2Shape *shape, float tx, float ty, float angle, int childIndex, Rectangle *output) { 19 | b2Transform t(b2Vec2(tx, ty), b2Rot(angle)); 20 | b2AABB box; 21 | shape->ComputeAABB(&box, t, childIndex); 22 | output->x = box.lowerBound.x; 23 | output->y = box.lowerBound.y; 24 | output->width = box.upperBound.x - box.lowerBound.x; 25 | output->height = box.upperBound.y - box.lowerBound.y; 26 | return output; 27 | } 28 | 29 | void b2Shape_Destroy(b2Shape *shape) { delete shape; } 30 | int b2Shape_GetType(b2Shape *shape) { return shape->m_type; } 31 | int b2Shape_GetChildCount(b2Shape *shape) { return shape->GetChildCount(); } 32 | bool b2Shape_TestPoint(b2Shape *shape, float tx, float ty, float angle, float x, float y) { 33 | b2Transform t(b2Vec2(tx, ty), b2Rot(angle)); 34 | b2Vec2 p = b2Vec2(x, y); 35 | return shape->TestPoint(t, p); 36 | } 37 | 38 | b2cRayCastOutput *b2Shape_RayCast(b2Shape *shape, float tx, float ty, float angle, float x1, float y1, 39 | float x2, float y2, float maxFraction, int childIndex, b2cRayCastOutput *output) { 40 | b2RayCastInput ray; 41 | ray.p1.x = x1; 42 | ray.p1.y = y1; 43 | ray.p2.x = x2; 44 | ray.p2.y = y2; 45 | ray.maxFraction = maxFraction; 46 | b2Transform t(b2Vec2(tx, ty), b2Rot(angle)); 47 | 48 | b2RayCastOutput cast; 49 | bool hit = shape->RayCast(&cast, ray, t, childIndex); 50 | output->hit = hit; 51 | output->nx = cast.normal.x; 52 | output->ny = cast.normal.y; 53 | output->fraction = cast.fraction; 54 | return output; 55 | } 56 | 57 | // --------- b2CircleShape --------------- 58 | 59 | b2CircleShape *b2CircleShape_New(float radius) { 60 | b2CircleShape *shape = new b2CircleShape(); 61 | shape->m_p = b2Vec2(0, 0); 62 | shape->m_radius = radius; 63 | return shape; 64 | } 65 | 66 | void b2CircleShape_SetPosition(b2CircleShape *shape, float x, float y) { shape->m_p = b2Vec2(x, y); } 67 | Vector2 *b2CircleShape_GetPosition(b2CircleShape *shape, Vector2 *output) { return convertVector(shape->m_p, output); } 68 | void b2CircleShape_SetRadius(b2CircleShape *shape, float radius) { shape->m_radius = radius; } 69 | float b2CircleShape_GetRadius(b2CircleShape *shape) { return shape->m_radius; } 70 | 71 | // --------- b2EdgeShape --------------- 72 | 73 | b2EdgeShape *b2EdgeShape_NewTwoSided(float x1, float y1, float x2, float y2) { 74 | b2EdgeShape *shape = new b2EdgeShape(); 75 | shape->SetTwoSided(b2Vec2(x1, y1), b2Vec2(x2, y2)); 76 | return shape; 77 | } 78 | 79 | b2EdgeShape *b2EdgeShape_NewOneSided(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) { 80 | b2EdgeShape *shape = new b2EdgeShape(); 81 | shape->SetOneSided(b2Vec2(x0, y0), b2Vec2(x1, y1), b2Vec2(x2, y2), b2Vec2(x3, y3)); 82 | return shape; 83 | } 84 | 85 | void b2EdgeShape_SetOneSided(b2EdgeShape *shape, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) { 86 | shape->SetOneSided(b2Vec2(x0, x0), b2Vec2(x1, y1), b2Vec2(x2, y2), b2Vec2(x3, y3)); 87 | } 88 | 89 | void b2EdgeShape_SetTwoSided(b2EdgeShape *shape, float x1, float y1, float x2, float y2) { 90 | shape->SetTwoSided(b2Vec2(x1, y1), b2Vec2(x2, y2)); 91 | } 92 | 93 | Vector2 *b2EdgeShape_GetVertex(b2EdgeShape *shape, int index, Vector2 *output) { 94 | switch(index) { 95 | case 0: 96 | output->x = shape->m_vertex0.x; 97 | output->y = shape->m_vertex0.y; 98 | break; 99 | case 1: 100 | output->x = shape->m_vertex1.x; 101 | output->y = shape->m_vertex1.y; 102 | break; 103 | case 2: 104 | output->x = shape->m_vertex2.x; 105 | output->y = shape->m_vertex2.y; 106 | break; 107 | case 3: 108 | output->x = shape->m_vertex3.x; 109 | output->y = shape->m_vertex3.y; 110 | break; 111 | } 112 | return output; 113 | } 114 | 115 | bool b2EdgeShape_IsOneSided(b2EdgeShape *shape) { return shape->m_oneSided; } 116 | 117 | // --------- b2PolygonShape --------------- 118 | 119 | b2PolygonShape *b2PolygonShape_New(Vector2 *vertices, int count) { 120 | b2PolygonShape *shape = new b2PolygonShape(); 121 | shape->Set(convertPolygon(vertices, count), count); 122 | return shape; 123 | } 124 | 125 | bool b2PolygonShape_Validate(b2PolygonShape *shape) { return shape->Validate(); } 126 | 127 | int b2PolygonShape_GetVertexCount(b2PolygonShape *shape) { return shape->m_count; } 128 | 129 | Vector2 *b2PolygonShape_GetVertex(b2PolygonShape *shape, int index, Vector2 *output) { 130 | return convertVector(shape->m_vertices[index], output); 131 | } 132 | 133 | Vector2 *b2PolygonShape_GetNormal(b2PolygonShape *shape, int index, Vector2 *output) { 134 | return convertVector(shape->m_normals[index], output); 135 | } 136 | 137 | // --------- b2ChainShape --------------- 138 | 139 | b2ChainShape *b2ChainShape_NewLoop(Vector2 *vertices, int count) { 140 | b2ChainShape *shape = new b2ChainShape(); 141 | shape->CreateLoop(convertPolygon(vertices, count), count); 142 | return shape; 143 | } 144 | 145 | b2ChainShape *b2ChainShape_NewChain(Vector2 *vertices, int count, float x0, float y0, float x1, float y1) { 146 | b2ChainShape *shape = new b2ChainShape(); 147 | shape->CreateChain(convertPolygon(vertices, count), count, b2Vec2(x0, y0), b2Vec2(x1, y1)); 148 | return shape; 149 | } 150 | 151 | int b2ChainShape_GetVertexCount(b2ChainShape *shape) { return shape->m_count; } 152 | 153 | Vector2 *b2ChainShape_GetVertex(b2ChainShape *shape, int index, Vector2 *output) { 154 | return convertVector(shape->m_vertices[index], output); 155 | } 156 | 157 | void b2ChainShape_SetPrevVertex(b2ChainShape *shape, float x, float y) { 158 | shape->m_prevVertex.x = x; 159 | shape->m_prevVertex.y = y; 160 | } 161 | 162 | Vector2 *b2ChainShape_GetPrevVertex(b2ChainShape *shape, Vector2 *output) { 163 | return convertVector(shape->m_prevVertex, output); 164 | } 165 | 166 | void b2ChainShape_SetNextVertex(b2ChainShape *shape, float x, float y) { 167 | shape->m_nextVertex.x = x; 168 | shape->m_nextVertex.y = y; 169 | } 170 | 171 | Vector2 *b2ChainShape_GetNextVertex(b2ChainShape *shape, Vector2 *output) { 172 | return convertVector(shape->m_nextVertex, output); 173 | } 174 | -------------------------------------------------------------------------------- /src/box2dc/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | inline Vector2 *convertVector(const b2Vec2 &v, Vector2 *output) { 4 | output->x = v.x; 5 | output->y = v.y; 6 | return output; 7 | } 8 | 9 | inline b2Vec2 *convertPolygon(const Vector2 *vertices, int count) { 10 | static b2Vec2 tempPolygon[b2_maxPolygonVertices]; 11 | for(int i = 0; i < count; ++i) { 12 | tempPolygon[i].x = vertices[i].x; 13 | tempPolygon[i].y = vertices[i].y; 14 | } 15 | return tempPolygon; 16 | } 17 | -------------------------------------------------------------------------------- /src/box2dc/world.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "b2_world.h" 3 | #include "b2_world_callbacks.h" 4 | #include "b2_body.h" 5 | #include "box2dc.h" 6 | #include "util.h" 7 | 8 | class RayCaster : public b2RayCastCallback { 9 | public: 10 | void Set(b2cRayCastCallback callback) { m_callback = callback; } 11 | b2cRayCastCallback Get() const { return m_callback; } 12 | 13 | float ReportFixture(b2Fixture *fixture, const b2Vec2 &point, const b2Vec2 &normal, float fraction) { 14 | return m_callback(fixture, point.x, point.y, normal.x, normal.y, fraction); 15 | } 16 | private: 17 | b2cRayCastCallback m_callback; 18 | }; 19 | 20 | class AABBQuery : public b2QueryCallback { 21 | public: 22 | void Set(b2cQueryCallback callback) { m_callback = callback; } 23 | b2cQueryCallback Get() const { return m_callback; } 24 | 25 | bool ReportFixture(b2Fixture *fixture) { 26 | return m_callback(fixture); 27 | } 28 | private: 29 | b2cQueryCallback m_callback; 30 | }; 31 | 32 | class AABBQueryCollector : public b2QueryCallback { 33 | public: 34 | void Reset() { m_fixtures.clear(); } 35 | size_t GetCount() const { return m_fixtures.size(); } 36 | b2Fixture **GetFixtures() { return m_fixtures.data(); } 37 | 38 | bool ReportFixture(b2Fixture *fixture) override { 39 | m_fixtures.push_back(fixture); 40 | return true; 41 | } 42 | private: 43 | std::vector m_fixtures; 44 | }; 45 | 46 | extern b2ContactFilter b2_defaultFilter; 47 | 48 | class ContactFilter : public b2ContactFilter { 49 | public: 50 | void Set(b2cContactFilter callback) { m_callback = callback; } 51 | b2cContactFilter Get() const { return m_callback; } 52 | 53 | bool ShouldCollide(b2Fixture *fixtureA, b2Fixture *fixtureB) { 54 | return m_callback(fixtureA, fixtureB); 55 | } 56 | private: 57 | b2cContactFilter m_callback; 58 | }; 59 | 60 | class ContactListener : public b2ContactListener { 61 | public: 62 | ContactListener() : b2ContactListener(), m_doBegin(false), m_doEnd(false), m_doPreSolve(false), m_doPostSolve(false) { 63 | } 64 | 65 | void Set(b2cContactListener begin, b2cContactListener end, b2cContactListener pre, b2cPostContactListener post) { 66 | m_begin = begin; 67 | m_end = end; 68 | m_preSolve = pre; 69 | m_postSolve = post; 70 | } 71 | 72 | void Enable(bool begin, bool end, bool pre, bool post) { 73 | m_doBegin = begin; 74 | m_doEnd = end; 75 | m_doPreSolve = pre; 76 | m_doPostSolve = post; 77 | } 78 | 79 | b2cContactListener GetBegin() const { return m_begin; } 80 | b2cContactListener GetEnd() const { return m_end; } 81 | b2cContactListener GetPreSolve() const { return m_preSolve; } 82 | b2cPostContactListener GetPostSolve() const { return m_postSolve; } 83 | 84 | void BeginContact(b2Contact *contact) { if(m_doBegin) m_begin(contact); } 85 | void EndContact(b2Contact *contact) { if(m_doEnd) m_end(contact); } 86 | void PreSolve(b2Contact *contact, const b2Manifold *oldManifold) { if(m_doPreSolve) m_preSolve(contact); } 87 | void PostSolve(b2Contact *contact, const b2ContactImpulse *impulse) { if(m_doPostSolve) m_postSolve(contact); } // TODO: impulse 88 | private: 89 | bool m_doBegin, m_doEnd, m_doPreSolve, m_doPostSolve; 90 | b2cContactListener m_begin, m_end, m_preSolve; 91 | b2cPostContactListener m_postSolve; 92 | }; 93 | 94 | extern b2ContactListener b2_defaultListener; 95 | 96 | class b2cWorld : public b2World { 97 | public: 98 | b2cWorld(const b2Vec2 &gravity) : b2World(gravity) { 99 | b2BodyDef def; 100 | m_groundBody = CreateBody(&def); 101 | } 102 | 103 | void RayCast(float x1, float y1, float x2, float y2) { 104 | static b2Vec2 p1, p2; 105 | p1.x = x1; 106 | p1.y = y1; 107 | p2.x = x2; 108 | p2.y = y2; 109 | b2World::RayCast(&m_rayCaster, p1, p2); 110 | } 111 | 112 | void SetRayCastCallback(b2cRayCastCallback callback) { m_rayCaster.Set(callback); } 113 | b2cRayCastCallback GetRayCastCallback() const { return m_rayCaster.Get(); } 114 | 115 | void EnableContactFilter(bool flag) { 116 | if(flag) { 117 | b2World::SetContactFilter(&m_contactFilter); 118 | } 119 | else { 120 | b2World::SetContactFilter(&b2_defaultFilter); 121 | } 122 | } 123 | 124 | void SetContactFilter(b2cContactFilter filter) { 125 | m_contactFilter.Set(filter); 126 | if(!filter) 127 | EnableContactFilter(false); 128 | } 129 | 130 | b2cContactFilter GetContactFilter() const { return m_contactFilter.Get(); } 131 | 132 | void EnableContactListener(bool begin, bool end, bool pre, bool post) { 133 | m_contactListener.Enable(begin, end, pre, post); 134 | if(begin || end || pre || post) { 135 | b2World::SetContactListener(&m_contactListener); 136 | } 137 | else { 138 | b2World::SetContactListener(nullptr); 139 | } 140 | } 141 | 142 | void SetContactListener(b2cContactListener begin, b2cContactListener end, b2cContactListener pre, b2cPostContactListener post) { 143 | m_contactListener.Set(begin, end, pre, post); 144 | if(!(begin || end || pre || post)) 145 | EnableContactListener(false, false, false, false); 146 | } 147 | 148 | const ContactListener &GetContactListener() const { return m_contactListener; } 149 | void SetQueryCallback(b2cQueryCallback callback) { m_query.Set(callback); } 150 | b2cQueryCallback GetQueryCallback() const { return m_query.Get(); } 151 | 152 | void QueryAABB(float minX, float minY, float maxX, float maxY) { 153 | static b2AABB aabb; 154 | aabb.lowerBound.x = minX; 155 | aabb.lowerBound.y = minY; 156 | aabb.upperBound.x = maxX; 157 | aabb.upperBound.y = maxY; 158 | b2World::QueryAABB(&m_query, aabb); 159 | } 160 | 161 | b2Fixture **GetFixturesFromAABB(float minX, float minY, float maxX, float maxY, size_t *count) { 162 | static b2AABB aabb; 163 | aabb.lowerBound.x = minX; 164 | aabb.lowerBound.y = minY; 165 | aabb.upperBound.x = maxX; 166 | aabb.upperBound.y = maxY; 167 | m_collector.Reset(); 168 | b2World::QueryAABB(&m_collector, aabb); 169 | *count = m_collector.GetCount(); 170 | return m_collector.GetFixtures(); 171 | } 172 | 173 | b2Body *GetGroundBody() const { return m_groundBody; } 174 | private: 175 | RayCaster m_rayCaster; 176 | AABBQuery m_query; 177 | AABBQueryCollector m_collector; 178 | ContactFilter m_contactFilter; 179 | ContactListener m_contactListener; 180 | b2Body *m_groundBody; 181 | }; 182 | 183 | b2World *b2World_New(float gravityX, float gravityY) { 184 | b2World *world = new b2cWorld(b2Vec2(gravityX, gravityY)); 185 | return world; 186 | } 187 | 188 | void b2World_Destroy(b2World *world) { 189 | delete static_cast(world); 190 | } 191 | 192 | /*void b2World_SetDestructionListener(b2World *world, b2DestructionListener *listener) { 193 | world->SetDestructionListener(listener); 194 | }*/ 195 | 196 | void b2World_SetContactFilter(b2World *world, b2cContactFilter filter) { 197 | static_cast(world)->SetContactFilter(filter); 198 | } 199 | 200 | b2cContactFilter b2World_GetContactFilter(b2World *world) { 201 | return static_cast(world)->GetContactFilter(); 202 | } 203 | 204 | void b2World_EnableContactFilter(b2World *world, bool flag) { 205 | static_cast(world)->EnableContactFilter(flag); 206 | } 207 | 208 | void b2World_SetContactListener(b2World *world, b2cContactListener begin, b2cContactListener end, b2cContactListener preSolve, b2cPostContactListener postSolve) { 209 | static_cast(world)->SetContactListener(begin, end, preSolve, postSolve); 210 | } 211 | 212 | b2cContactListener b2World_GetBeginContactListener(b2World *world) { 213 | return static_cast(world)->GetContactListener().GetBegin(); 214 | } 215 | 216 | b2cContactListener b2World_GetEndContactListener(b2World *world) { 217 | return static_cast(world)->GetContactListener().GetEnd(); 218 | } 219 | 220 | b2cContactListener b2World_GetPreSolveContactListener(b2World *world) { 221 | return static_cast(world)->GetContactListener().GetPreSolve(); 222 | } 223 | 224 | b2cPostContactListener b2World_GetPostSolveContactListener(b2World *world) { 225 | return static_cast(world)->GetContactListener().GetPostSolve(); 226 | } 227 | 228 | void b2World_EnableContactListener(b2World *world, bool begin, bool end, bool pre, bool post) { 229 | static_cast(world)->EnableContactListener(begin, end, pre, post); 230 | } 231 | 232 | void b2World_SetRayCastCallback(b2World *world, b2cRayCastCallback callback) { 233 | static_cast(world)->SetRayCastCallback(callback); 234 | } 235 | 236 | b2cRayCastCallback b2World_GetRayCastCallback(b2World *world) { 237 | return static_cast(world)->GetRayCastCallback(); 238 | } 239 | 240 | void b2World_SetQueryCallback(b2World *world, b2cQueryCallback callback) { 241 | static_cast(world)->SetQueryCallback(callback); 242 | } 243 | 244 | b2cQueryCallback b2World_GetQueryCallback(b2World *world) { 245 | return static_cast(world)->GetQueryCallback(); 246 | } 247 | 248 | b2Body *b2World_CreateBody(b2World *world, float x, float y, float angle, int type) { 249 | b2BodyDef def; 250 | def.position.x = x; 251 | def.position.y = y; 252 | def.angle = angle; 253 | def.type = (b2BodyType)type; 254 | return world->CreateBody(&def); 255 | } 256 | 257 | void b2World_DestroyBody(b2World *world, b2Body *body) { world->DestroyBody(body); } 258 | void b2World_DestroyJoint(b2World *world, b2Joint *joint) { world->DestroyJoint(joint); } 259 | void b2World_Step(b2World *world, float timeStep, int velocityIterations, int positionIterations) { 260 | world->Step(timeStep, velocityIterations, positionIterations); 261 | } 262 | 263 | void b2World_ClearForces(b2World *world) { world->ClearForces(); } 264 | void b2World_DebugDraw(b2World *world) { world->DebugDraw(); } 265 | void b2World_QueryAABB(b2World *world, float minX, float minY, float maxX, float maxY) { 266 | static_cast(world)->QueryAABB(minX, minY, maxX, maxY); 267 | } 268 | 269 | b2Fixture **b2World_GetFixturesFromAABB(b2World *world, float minX, float minY, float maxX, float maxY, size_t *count) { 270 | return static_cast(world)->GetFixturesFromAABB(minX, minY, maxX, maxY, count); 271 | } 272 | 273 | void b2World_RayCast(b2World *world, float x1, float y1, float x2, float y2) { 274 | static_cast(world)->RayCast(x1, y1, x2, y2); 275 | } 276 | 277 | b2Body *b2World_GetBodyList(b2World *world) { return world->GetBodyList(); } 278 | b2Joint *b2World_GetJointList(b2World *world) { return world->GetJointList(); } 279 | b2Contact *b2World_GetContactList(b2World *world) { return world->GetContactList(); } 280 | void b2World_SetAllowSleeping(b2World *world, bool flag) { world->SetAllowSleeping(flag); } 281 | bool b2World_GetAllowSleeping(b2World *world) { return world->GetAllowSleeping(); } 282 | void b2World_SetWarmStarting(b2World *world, bool flag) { world->SetWarmStarting(flag); } 283 | bool b2World_GetWarmStarting(b2World *world) { return world->GetWarmStarting(); } 284 | void b2World_SetContinuousPhysics(b2World *world, bool flag) { world->SetContinuousPhysics(flag); } 285 | bool b2World_GetContinuousPhysics(b2World *world) { return world->GetContinuousPhysics(); } 286 | void b2World_SetSubStepping(b2World *world, bool flag) { world->SetSubStepping(flag); } 287 | bool b2World_GetSubStepping(b2World *world) { return world->GetSubStepping(); } 288 | int b2World_GetProxyCount(b2World *world) { return world->GetProxyCount(); } 289 | int b2World_GetBodyCount(b2World *world) { return world->GetBodyCount(); } 290 | int b2World_GetJointCount(b2World *world) { return world->GetJointCount(); } 291 | int b2World_GetContactCount(b2World *world) { return world->GetContactCount(); } 292 | int b2World_GetTreeHeight(b2World *world) { return world->GetTreeHeight(); } 293 | int b2World_GetTreeBalance(b2World *world) { return world->GetTreeBalance(); } 294 | float b2World_GetTreeQuality(b2World *world) { return world->GetTreeQuality(); } 295 | void b2World_SetGravity(b2World *world, float gravityX, float gravityY) { 296 | b2Vec2 gravity = b2Vec2(gravityX, gravityY); 297 | world->SetGravity(gravity); 298 | } 299 | 300 | Vector2 *b2World_GetGravity(b2World *world, Vector2 *output) { 301 | return convertVector(world->GetGravity(), output); 302 | } 303 | 304 | bool b2World_IsLocked(b2World *world) { return world->IsLocked(); } 305 | void b2World_SetAutoClearForces(b2World *world, bool flag) { world->SetAutoClearForces(flag); } 306 | bool b2World_GetAutoClearForces(b2World *world) { return world->GetAutoClearForces(); } 307 | 308 | void b2World_ShiftOrigin(b2World *world, float x, float y) { world->ShiftOrigin(b2Vec2(x, y)); } 309 | 310 | void b2World_Dump(b2World *world) { world->Dump(); } 311 | 312 | b2cProfile *b2World_GetProfile(b2World *world, b2cProfile *output) { 313 | const b2Profile &profile = world->GetProfile(); 314 | output->step = profile.step; 315 | output->collide = profile.collide; 316 | output->solve = profile.solve; 317 | output->solveInit = profile.solveInit; 318 | output->solveVelocity = profile.solveVelocity; 319 | output->solvePosition = profile.solvePosition; 320 | output->broadphase = profile.broadphase; 321 | output->solveTOI = profile.solveTOI; 322 | return output; 323 | } 324 | 325 | b2Body *b2World_GetGroundBody(b2World *world) { return static_cast(world)->GetGroundBody(); } 326 | -------------------------------------------------------------------------------- /src/yuema/.gitignore: -------------------------------------------------------------------------------- 1 | *_ffi.h 2 | -------------------------------------------------------------------------------- /src/yuema/LuaVM.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaVM.h" 2 | #include 3 | 4 | extern "C" { 5 | #include "luajit.h" 6 | #include "lualib.h" 7 | #include "lauxlib.h" 8 | 9 | int luaopen_yue(lua_State *L); 10 | int luaopen_utf8(lua_State *L); 11 | } 12 | 13 | static const char BOOT[] = R"code( 14 | package.path = '?.lua;?/init.lua' 15 | yuema = { 16 | args = { select(2, ...) }, 17 | } 18 | 19 | do 20 | local ffi = require('ffi') 21 | local imports = (...) 22 | 23 | for i = 1, #imports, 4 do 24 | local name, type, decl, func = imports[i], imports[i + 1], imports[i + 2], imports[i + 3] 25 | ffi.cdef(decl) 26 | yuema[name] = ffi.cast(('%s*'):format(type), func) 27 | end 28 | 29 | local function boot() 30 | require('lib.core') 31 | 32 | local run = (yuema.args[2] or 'main') 33 | :gsub('%.[lL][uU][aA]$', '') 34 | :gsub('%.[yY][uU][eE]$', '') 35 | :gsub('[/\\]', '.') 36 | require(run) 37 | end 38 | 39 | local ok, err = xpcall(boot, function(err) 40 | return yue.traceback(err) 41 | end) 42 | if not ok then error(err, 2) end 43 | end 44 | )code"; 45 | 46 | void initYue(lua_State *L) { 47 | luaopen_yue(L); 48 | lua_getglobal(L, "yue"); 49 | int t = lua_gettop(L); 50 | lua_getfield(L, t, "insert_loader"); 51 | lua_pcall(L, 0, 0, 0); 52 | lua_settop(L, t - 1); 53 | } 54 | 55 | LuaVM::LuaVM() { 56 | _state = luaL_newstate(); 57 | luaL_openlibs(_state); 58 | luaopen_utf8(_state); 59 | initYue(_state); 60 | } 61 | 62 | LuaVM::~LuaVM() { 63 | lua_close(_state); 64 | } 65 | 66 | void LuaVM::run(const FFIExport* exports, int argc, char* argv[]) { 67 | int err = luaL_loadbuffer(_state, BOOT, strlen(BOOT), "@boot.lua"); 68 | switch(err) { 69 | case 0: break; 70 | case LUA_ERRSYNTAX: throw LuaError("Syntax error in boot sequence"); break; 71 | case LUA_ERRMEM: throw LuaError("Memory allocation error in boot sequence"); break; 72 | default: throw LuaError("Could not load boot sequence"); break; 73 | } 74 | 75 | int index = 1; 76 | lua_newtable(_state); 77 | for(const FFIExport *exp = exports; exp->name; ++exp) { 78 | lua_pushstring(_state, exp->name); 79 | lua_rawseti(_state, -2, index++); 80 | lua_pushstring(_state, exp->type); 81 | lua_rawseti(_state, -2, index++); 82 | lua_pushstring(_state, exp->declarations); 83 | lua_rawseti(_state, -2, index++); 84 | lua_pushlightuserdata(_state, exp->functions); 85 | lua_rawseti(_state, -2, index++); 86 | } 87 | for(int i = 0; i < argc; ++i) 88 | lua_pushstring(_state, argv[i]); 89 | 90 | int ret = lua_pcall(_state, 1 + argc, 0, 0); 91 | if(ret) 92 | throw LuaError(lua_tostring(_state, -1)); 93 | } 94 | -------------------------------------------------------------------------------- /src/yuema/LuaVM.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef std::runtime_error LuaError; 5 | 6 | struct FFIExport { 7 | const char *name; 8 | const char *type; 9 | const char *declarations; 10 | void *functions; 11 | }; 12 | 13 | class LuaVM { 14 | public: 15 | LuaVM(); 16 | ~LuaVM(); 17 | 18 | void run(const FFIExport* exports, int argc, char* argv[]); 19 | private: 20 | struct lua_State *_state; 21 | }; 22 | -------------------------------------------------------------------------------- /src/yuema/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "LuaVM.h" 7 | 8 | #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT 9 | #include "raylib.h" 10 | #include "rlgl.h" 11 | 12 | #define RAYGUI_IMPLEMENTATION 13 | #include "raygui.h" 14 | 15 | #include "box2dc.h" 16 | 17 | #include "raylib_ffi.h" 18 | #include "rlgl_ffi.h" 19 | #include "raygui_ffi.h" 20 | #include "box2dc_ffi.h" 21 | 22 | FFIExport exports[] = { 23 | { "RL", "RAYLIB_API", RAYLIB_FFI, &RAYLIB_EXPORTS }, 24 | { "RLGL", "RLGL_API", RLGL_FFI, &RLGL_EXPORTS }, 25 | { "RG", "RAYGUI_API", RAYGUI_FFI, &RAYGUI_EXPORTS }, 26 | { "B2D", "BOX2DC_API", BOX2DC_FFI, &BOX2DC_EXPORTS }, 27 | { nullptr } 28 | }; 29 | 30 | void errorHandler(const char* error) { 31 | // this is ugly but there's no other way to reset raylib's state 32 | // TODO: implement a better error display 33 | int width = 800; 34 | int height = 600; 35 | if(IsWindowReady()) { 36 | width = GetScreenWidth(); 37 | height = GetScreenHeight(); 38 | CloseWindow(); 39 | } 40 | InitWindow(width, height, "ERROR"); 41 | 42 | std::string errorMessage(error); 43 | errorMessage.erase(std::remove(errorMessage.begin(), errorMessage.end(), '\r'), errorMessage.end()); 44 | while(!WindowShouldClose()) { 45 | BeginDrawing(); 46 | ClearBackground((Color){ 32, 40, 48, 255 }); 47 | GuiDrawIcon(RAYGUI_ICON_DEMON, 20, 20, 2, RED); 48 | DrawText("ERROR", 58, 18, 40, RED); 49 | DrawText(errorMessage.c_str(), 30, 68, 10, RAYWHITE); 50 | EndDrawing(); 51 | WaitTime(15); 52 | } 53 | } 54 | 55 | int main(int argc, char* argv[]) { 56 | LuaVM lua; 57 | try { 58 | lua.run(exports, argc, argv); 59 | } 60 | catch(const LuaError& e) { 61 | std::cout << "ERROR: " << e.what() << "\n"; 62 | errorHandler(e.what()); 63 | return -1; 64 | } 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /src/yuema/tools/generate_ffi.lua: -------------------------------------------------------------------------------- 1 | require('cparser') 2 | 3 | local input, output, prefix = ... 4 | if not input or not output or not prefix then 5 | error("Usage: generate_ffi []") 6 | end 7 | 8 | local parseOptions = { 9 | silent = true 10 | } 11 | 12 | do 13 | local defs = select(4, ...) 14 | if defs then 15 | for def in defs:gmatch('%S+') do 16 | table.insert(parseOptions, ('-D%s'):format(def)) 17 | end 18 | end 19 | end 20 | 21 | local FFICODE = [[ 22 | typedef struct { 23 | %s 24 | } %s_API; 25 | 26 | %s_API %s_EXPORTS = { 27 | %s 28 | }; 29 | 30 | const char %s_FFI[] = R"ffiexports( 31 | %s 32 | %s 33 | typedef struct { 34 | %s 35 | } %s_API; 36 | )ffiexports"; 37 | ]] 38 | 39 | local function typeIs(ty,tag) 40 | assert(ty) 41 | if ty.tag == 'Qualified' then ty = ty.t end 42 | return ty.tag == tag 43 | end 44 | 45 | local function declToString(action) 46 | local tag = action and action.tag 47 | if tag == 'TypeDef' or tag == 'Definition' or tag == 'Declaration' then 48 | local n = (action.sclass == '[typetag]') and "" or action.name 49 | local s = cparser.typeToString(action.type, n) 50 | if tag == 'TypeDef' then 51 | s = 'typedef ' .. s 52 | end 53 | if action.intval then 54 | if action.sclass ~= '[enum]' then 55 | s = s .. ' = ' .. action.intval 56 | else 57 | s = '' 58 | end 59 | elseif action.init and typeIs(action.type, 'Function') then 60 | error(s) 61 | end 62 | return s 63 | end 64 | end 65 | 66 | local function getConstants() 67 | local result = {} 68 | local li = cparser.declarationIterator(parseOptions, io.lines(input), input) 69 | for action in li do 70 | if action.tag == 'CppEvent' and action.directive == 'define' then 71 | if action.intval then 72 | table.insert(result, ('static const int %s = %s;'):format(action.name, action.intval)) 73 | else 74 | print(("WARNING: can't generate ffi code for #define %s"):format(action.name)) 75 | end 76 | end 77 | end 78 | return result; 79 | end 80 | 81 | local function getDeclarations() 82 | local result = { types = {}, functions = {} } 83 | local li = cparser.declarationIterator(parseOptions, io.lines(input), input) 84 | for action in li do 85 | if action.type then 86 | local decl = declToString(action) 87 | if decl and #decl > 0 then 88 | if action.type.tag == 'Function' then 89 | table.insert(result.functions, ('%s;'):format(decl)) 90 | else 91 | table.insert(result.types, ('%s;'):format(decl)) 92 | end 93 | end 94 | end 95 | end 96 | 97 | for i, t in ipairs(result.types) do 98 | result.types[i] = t 99 | :gsub(',', ',\n\t') 100 | :gsub(';', ';\n\t') 101 | :gsub('{', '{\n\t') 102 | :gsub('}', '\n}') 103 | end 104 | 105 | return result 106 | end 107 | 108 | local function getFunctions() 109 | local result = { types = {}, names = {} } 110 | local li = cparser.declarationIterator(parseOptions, io.lines(input), input) 111 | for action in li do 112 | if action.tag == 'Declaration' and action.type.tag == 'Function' then 113 | local f = action.type 114 | local args = {} 115 | for _, pair in ipairs(f) do 116 | if pair.ellipsis then 117 | table.insert(args, '...') 118 | else 119 | table.insert(args, cparser.typeToString(pair[1], pair[2])) 120 | end 121 | end 122 | 123 | local returnType = cparser.typeToString(action.type.t, '') 124 | local funcName = action.name 125 | local argList = table.concat(args, ', ') 126 | 127 | local ptrType = ('%s (*%s)(%s);'):format(returnType, funcName, argList) 128 | table.insert(result.types, ptrType) 129 | table.insert(result.names, funcName) 130 | end 131 | end 132 | return result 133 | end 134 | 135 | local function generateCode(decls, decls, funcs, consts) 136 | local code = FFICODE:format( 137 | table.concat(funcs.types, '\n\t'), 138 | prefix, 139 | prefix, 140 | prefix, 141 | table.concat(funcs.names, ',\n\t'), 142 | 143 | prefix, 144 | table.concat(decls.types, '\n'), 145 | table.concat(consts, '\n'), 146 | table.concat(funcs.types, '\n\t'), 147 | prefix 148 | ) 149 | 150 | local file = io.open(output, 'w') 151 | file:write(code) 152 | file:close() 153 | end 154 | 155 | local decls = getDeclarations() 156 | local funcs = getFunctions() 157 | local consts = getConstants() 158 | generateCode(decls, decls, funcs, consts) 159 | --------------------------------------------------------------------------------