├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── LICENSE ├── README.md ├── bin ├── DevIL.dll ├── OpenAL32.dll ├── SDL2.dll ├── SDL_sound.dll ├── assimp.dll ├── cef.exe ├── chipmunk.dll ├── freetype.dll ├── kazmath.dll ├── libkazmath.dylib └── physfs.dll ├── fonts └── Vera.ttf ├── game-framework ├── game-framework.cmd ├── include ├── SDL.h ├── SDL_sound.h ├── al.h ├── assimp.h ├── cef_app_capi.h ├── chipmunk.h ├── freetype.h ├── glcorearb.h ├── ilut.h ├── kazmath.h ├── opus.h └── physfs.h ├── lib ├── assimp.lua ├── cef.lua ├── chipmunk.lua ├── class.lua ├── devil.lua ├── enet.dll ├── enet.so ├── freetype.lua ├── kazmath.lua ├── lanes.lua ├── lanes │ ├── core.dll │ └── core.so ├── ltn12.lua ├── mime.lua ├── mime │ ├── core.dll │ └── core.so ├── openal.lua ├── opengl.lua ├── opus.lua ├── physicsfs.lua ├── sdl.lua ├── sdl_sound.lua ├── socket.lua ├── socket │ ├── core.dll │ ├── core.so │ ├── ftp.lua │ ├── http.lua │ ├── smtp.lua │ ├── tp.lua │ └── url.lua ├── ssl.lua └── ssl │ └── https.lua ├── lua ├── framework │ ├── audio.lua │ ├── event.lua │ ├── filesystem.lua │ ├── graphics │ │ ├── cubemap.lua │ │ ├── font.lua │ │ ├── framebuffer.lua │ │ ├── image.lua │ │ ├── init.lua │ │ ├── mesh.lua │ │ ├── model.lua │ │ ├── opengl.lua │ │ ├── primitive.lua │ │ ├── quad.lua │ │ ├── shader.lua │ │ ├── shaders │ │ │ ├── default2d.lua │ │ │ ├── default3d.lua │ │ │ ├── depth.lua │ │ │ ├── gltfpbr.lua │ │ │ └── skybox.lua │ │ ├── spritebatch.lua │ │ ├── text.lua │ │ └── transformation.lua │ ├── html │ │ ├── app.lua │ │ ├── browser.lua │ │ ├── client.lua │ │ ├── init.lua │ │ ├── lifespan.lua │ │ ├── process.lua │ │ ├── rendering.lua │ │ ├── resource.lua │ │ └── scheme.lua │ ├── init.lua │ ├── keyboard.lua │ ├── love.lua │ ├── mouse.lua │ ├── physics │ │ ├── body.lua │ │ ├── fixture.lua │ │ ├── init.lua │ │ └── space.lua │ ├── sound.lua │ ├── thread.lua │ ├── timer.lua │ └── window.lua └── jit │ ├── bc.lua │ ├── bcsave.lua │ ├── dis_arm.lua │ ├── dis_mips.lua │ ├── dis_mipsel.lua │ ├── dis_ppc.lua │ ├── dis_x64.lua │ ├── dis_x86.lua │ ├── dump.lua │ ├── v.lua │ └── vmdef.lua ├── lua51.dll ├── luajit.exe ├── main.lua ├── models └── DamagedHelmet │ ├── LICENSE.md │ └── glTF │ ├── DamagedHelmet.bin │ ├── DamagedHelmet.gltf │ ├── Default_AO.jpg │ ├── Default_albedo.jpg │ ├── Default_emissive.jpg │ ├── Default_metalRoughness.jpg │ └── Default_normal.jpg ├── public └── index.html ├── resources └── .gitignore ├── shaders ├── default.frag ├── default2d.vert ├── default3d.vert ├── depth.frag ├── depth.vert ├── pbr-frag.glsl ├── pbr-vert.glsl ├── skybox.frag └── skybox.vert ├── test ├── html │ └── main.lua └── triangle │ └── main.lua └── textures ├── brdfLUT.png └── papermill ├── diffuse ├── diffuse_back_0.jpg ├── diffuse_bottom_0.jpg ├── diffuse_front_0.jpg ├── diffuse_left_0.jpg ├── diffuse_right_0.jpg └── diffuse_top_0.jpg ├── environment ├── environment_back_0.jpg ├── environment_bottom_0.jpg ├── environment_front_0.jpg ├── environment_left_0.jpg ├── environment_right_0.jpg └── environment_top_0.jpg └── specular ├── specular_back_0.jpg ├── specular_back_1.jpg ├── specular_back_2.jpg ├── specular_back_3.jpg ├── specular_back_4.jpg ├── specular_back_5.jpg ├── specular_back_6.jpg ├── specular_back_7.jpg ├── specular_back_8.jpg ├── specular_back_9.jpg ├── specular_bottom_0.jpg ├── specular_bottom_1.jpg ├── specular_bottom_2.jpg ├── specular_bottom_3.jpg ├── specular_bottom_4.jpg ├── specular_bottom_5.jpg ├── specular_bottom_6.jpg ├── specular_bottom_7.jpg ├── specular_bottom_8.jpg ├── specular_bottom_9.jpg ├── specular_front_0.jpg ├── specular_front_1.jpg ├── specular_front_2.jpg ├── specular_front_3.jpg ├── specular_front_4.jpg ├── specular_front_5.jpg ├── specular_front_6.jpg ├── specular_front_7.jpg ├── specular_front_8.jpg ├── specular_front_9.jpg ├── specular_left_0.jpg ├── specular_left_1.jpg ├── specular_left_2.jpg ├── specular_left_3.jpg ├── specular_left_4.jpg ├── specular_left_5.jpg ├── specular_left_6.jpg ├── specular_left_7.jpg ├── specular_left_8.jpg ├── specular_left_9.jpg ├── specular_right_0.jpg ├── specular_right_1.jpg ├── specular_right_2.jpg ├── specular_right_3.jpg ├── specular_right_4.jpg ├── specular_right_5.jpg ├── specular_right_6.jpg ├── specular_right_7.jpg ├── specular_right_8.jpg ├── specular_right_9.jpg ├── specular_top_0.jpg ├── specular_top_1.jpg ├── specular_top_2.jpg ├── specular_top_3.jpg ├── specular_top_4.jpg ├── specular_top_5.jpg ├── specular_top_6.jpg ├── specular_top_7.jpg ├── specular_top_8.jpg └── specular_top_9.jpg /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/cef_sandbox.lib 2 | /bin/chrome_elf.dll 3 | /bin/d3dcompiler_43.dll 4 | /bin/d3dcompiler_47.dll 5 | /bin/icudtl.dat 6 | /bin/libEGL.dll 7 | /bin/libGLESv2.dll 8 | /bin/libcef.dll 9 | /bin/libcef.lib 10 | /bin/natives_blob.bin 11 | /bin/snapshot_blob.bin 12 | /bin/swiftshader/libEGL.dll 13 | /bin/swiftshader/libGLESv2.dll 14 | /bin/v8_context_snapshot.bin 15 | /bin/widevinecdmadapter.dll 16 | /debug.log 17 | /GPUCache 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Planimeter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Planimeter Game Framework 2 | LuaJIT FFI-based game development framework for Lua 3 | (Formerly lgf) 4 | 5 | [](https://gitter.im/Planimeter/lgameframework?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 6 | [](https://discord.gg/aR3X8Vz?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 7 | 8 | ## Install 9 | ### Windows 10 | **Microsoft Visual C++ Redistributable for Visual Studio 2017** 11 | https://go.microsoft.com/fwlink/?LinkId=746572 12 | 13 | **02/13/2018 - CEF 3.3282.1733.g9091548 / Chromium 64.0.3282.119** 14 | http://opensource.spotify.com/cefbuilds/index.html 15 | 16 | ### macOS 17 | ```bash 18 | brew install luajit physfs sdl2 devil freetype sdl_sound chipmunk assimp enet opus 19 | ``` 20 | 21 | ## Run 22 | ```bash 23 | ./game-framework 24 | ``` 25 | 26 | ## Features 27 | * SDL2 for window creation, OpenGL function loading, and event handling 28 | * Modern OpenGL (OpenGL 3.3/4.0+ Core Profile) 29 | * PhysicsFS for abstracting access to various archives 30 | * DevIL for loading a wide variety of image formats 31 | * FreeType for rendering text 32 | * SDL_sound for decoding several popular sound file formats 33 | * OpenAL for rendering 3D sound 34 | * Chipmunk for 2-dimensional real-time rigid body physics 35 | * Assimp for loading various 3D file formats 36 | * glTF 2.0 physically-based rendering reference shaders 37 | * Chromium Embedded Framework for UI 38 | * ENet for online multi-player support 39 | * Opus for in-game chat 40 | * Lua Lanes for multithreading 41 | * LuaSocket for network support 42 | * LuaSec for secure connections 43 | * [Drop-in LÖVE 11.3 support](https://github.com/Planimeter/lgf/blob/master/lua/framework/love.lua) 44 | 45 | ## Libraries 46 | * [lphysicsfs](https://github.com/Planimeter/lphysicsfs) 47 | LuaJIT FFI bindings for PhysicsFS 48 | * [lsdl](https://github.com/Planimeter/lsdl) 49 | LuaJIT FFI bindings for SDL 2.0 50 | * [lopengl](https://github.com/Planimeter/lopengl) 51 | LuaJIT FFI bindings for OpenGL 52 | * [lkazmath](https://github.com/Planimeter/lkazmath) 53 | LuaJIT FFI bindings for kazmath 54 | * [lclass](https://github.com/andrewmcwatters/lclass) 55 | Lua with Classes 56 | * [ldevil](https://github.com/Planimeter/ldevil) 57 | LuaJIT FFI bindings for DevIL 58 | * [lfreetype](https://github.com/Planimeter/lfreetype) 59 | LuaJIT FFI bindings for FreeType 60 | * [lsdl_sound](https://github.com/Planimeter/lsdl_sound) 61 | LuaJIT FFI bindings for SDL_sound 62 | * [lopenal](https://github.com/Planimeter/lopenal) 63 | LuaJIT FFI bindings for OpenAL 64 | * [lchipmunk](https://github.com/Planimeter/lchipmunk) 65 | LuaJIT FFI bindings for Chipmunk 66 | * [lassimp](https://github.com/Planimeter/lassimp) 67 | LuaJIT FFI bindings for Assimp 68 | * [lcef](https://github.com/Planimeter/lcef) 69 | LuaJIT FFI bindings for Chromium Embedded Framework 70 | * [lenet](https://github.com/Planimeter/lenet) 71 | LuaJIT FFI bindings for ENet 72 | * [lopus](https://github.com/Planimeter/lopus) 73 | LuaJIT FFI bindings for Opus 74 | 75 | ## License 76 | MIT License 77 | 78 | Copyright (c) 2022 Planimeter 79 | 80 | Permission is hereby granted, free of charge, to any person obtaining a copy 81 | of this software and associated documentation files (the "Software"), to deal 82 | in the Software without restriction, including without limitation the rights 83 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 84 | copies of the Software, and to permit persons to whom the Software is 85 | furnished to do so, subject to the following conditions: 86 | 87 | The above copyright notice and this permission notice shall be included in all 88 | copies or substantial portions of the Software. 89 | 90 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 91 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 92 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 93 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 94 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 95 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 96 | SOFTWARE. 97 | -------------------------------------------------------------------------------- /bin/DevIL.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/bin/DevIL.dll -------------------------------------------------------------------------------- /bin/OpenAL32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/bin/OpenAL32.dll -------------------------------------------------------------------------------- /bin/SDL2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/bin/SDL2.dll -------------------------------------------------------------------------------- /bin/SDL_sound.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/bin/SDL_sound.dll -------------------------------------------------------------------------------- /bin/assimp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/bin/assimp.dll -------------------------------------------------------------------------------- /bin/cef.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/bin/cef.exe -------------------------------------------------------------------------------- /bin/chipmunk.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/bin/chipmunk.dll -------------------------------------------------------------------------------- /bin/freetype.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/bin/freetype.dll -------------------------------------------------------------------------------- /bin/kazmath.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/bin/kazmath.dll -------------------------------------------------------------------------------- /bin/libkazmath.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/bin/libkazmath.dylib -------------------------------------------------------------------------------- /bin/physfs.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/bin/physfs.dll -------------------------------------------------------------------------------- /fonts/Vera.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/fonts/Vera.ttf -------------------------------------------------------------------------------- /game-framework: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 3 | luajit "$DIR/lua/framework/init.lua" "$(pwd)" "$@" 4 | -------------------------------------------------------------------------------- /game-framework.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | "%~dp0luajit.exe" "%~dp0lua\framework\init.lua" "%cd%" %* 3 | -------------------------------------------------------------------------------- /include/SDL_sound.h: -------------------------------------------------------------------------------- 1 | typedef enum 2 | { 3 | SOUND_SAMPLEFLAG_NONE = 0, 4 | 5 | 6 | SOUND_SAMPLEFLAG_CANSEEK = 1, 7 | 8 | 9 | SOUND_SAMPLEFLAG_EOF = 1 << 29, 10 | SOUND_SAMPLEFLAG_ERROR = 1 << 30, 11 | SOUND_SAMPLEFLAG_EAGAIN = 1 << 31 12 | } Sound_SampleFlags; 13 | typedef struct 14 | { 15 | Uint16 format; 16 | Uint8 channels; 17 | Uint32 rate; 18 | } Sound_AudioInfo; 19 | typedef struct 20 | { 21 | const char **extensions; 22 | const char *description; 23 | const char *author; 24 | const char *url; 25 | } Sound_DecoderInfo; 26 | typedef struct 27 | { 28 | void *opaque; 29 | const Sound_DecoderInfo *decoder; 30 | Sound_AudioInfo desired; 31 | Sound_AudioInfo actual; 32 | void *buffer; 33 | Uint32 buffer_size; 34 | Sound_SampleFlags flags; 35 | } Sound_Sample; 36 | typedef struct 37 | { 38 | int major; 39 | int minor; 40 | int patch; 41 | } Sound_Version; 42 | void Sound_GetLinkedVersion(Sound_Version *ver); 43 | int Sound_Init(void); 44 | int Sound_Quit(void); 45 | const Sound_DecoderInfo ** Sound_AvailableDecoders(void); 46 | const char * Sound_GetError(void); 47 | void Sound_ClearError(void); 48 | Sound_Sample * Sound_NewSample(SDL_RWops *rw, 49 | const char *ext, 50 | Sound_AudioInfo *desired, 51 | Uint32 bufferSize); 52 | Sound_Sample * Sound_NewSampleFromFile(const char *fname, 53 | Sound_AudioInfo *desired, 54 | Uint32 bufferSize); 55 | void Sound_FreeSample(Sound_Sample *sample); 56 | int Sound_SetBufferSize(Sound_Sample *sample, 57 | Uint32 new_size); 58 | Uint32 Sound_Decode(Sound_Sample *sample); 59 | Uint32 Sound_DecodeAll(Sound_Sample *sample); 60 | int Sound_Rewind(Sound_Sample *sample); 61 | int Sound_Seek(Sound_Sample *sample, Uint32 ms); 62 | -------------------------------------------------------------------------------- /lib/assimp.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | io.input( framework.execdir .. "include/assimp.h" ) 9 | ffi.cdef( io.read( "*all" ) ) 10 | 11 | local assimp = ffi.load( "assimp" ) 12 | local _M = {} 13 | 14 | function _M.aiPrintMatrix4( mat ) 15 | mat = ffi.cast( "struct aiMatrix4x4 *", mat ) 16 | print( 17 | mat.a1, mat.a2, mat.a3, mat.a4 .. "\n", 18 | "\r" .. mat.b1, mat.b2, mat.b3, mat.b4 .. "\n", 19 | "\r" .. mat.c1, mat.c2, mat.c3, mat.c4 .. "\n", 20 | "\r" .. mat.d1, mat.d2, mat.d3, mat.d4 21 | ) 22 | end 23 | 24 | return setmetatable( _M, { 25 | __index = function( table, key ) 26 | return assimp[ key ] 27 | end 28 | } ) 29 | -------------------------------------------------------------------------------- /lib/cef.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | io.input( framework.execdir .. "include/cef_app_capi.h" ) 9 | ffi.cdef( io.read( "*all" ) ) 10 | return ffi.load( ffi.os == "Windows" and "libcef" or "cef" ) 11 | -------------------------------------------------------------------------------- /lib/chipmunk.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | io.input( framework.execdir .. "include/chipmunk.h" ) 9 | ffi.cdef( io.read( "*all" ) ) 10 | return ffi.load( "chipmunk" ) 11 | -------------------------------------------------------------------------------- /lib/class.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- Lua with Classes 3 | -- lclass 4 | -- Author: Andrew McWatters 5 | ------------------------------------------------------------------------------- 6 | local setmetatable = setmetatable 7 | local package = package 8 | local type = type 9 | local error = error 10 | local pcall = pcall 11 | local unpack = unpack 12 | local newproxy = newproxy 13 | local string = string 14 | local rawget = rawget 15 | local ipairs = ipairs 16 | local module = module 17 | local _G = _G 18 | local _R = debug.getregistry() 19 | 20 | ------------------------------------------------------------------------------- 21 | -- new() 22 | -- Purpose: Creates an object 23 | -- Input: metatable 24 | -- Output: object 25 | ------------------------------------------------------------------------------- 26 | local function new( metatable ) 27 | local object = {} 28 | setmetatable( object, metatable ) 29 | return object 30 | end 31 | 32 | ------------------------------------------------------------------------------- 33 | -- getbaseclass() 34 | -- Purpose: Gets a base class 35 | -- Input: metatable 36 | -- Output: metatable 37 | ------------------------------------------------------------------------------- 38 | local function getbaseclass( metatable ) 39 | local base = metatable.__base 40 | return package.loaded[ base ] 41 | end 42 | 43 | _G.getbaseclass = getbaseclass 44 | 45 | ------------------------------------------------------------------------------- 46 | -- eventnames 47 | -- Purpose: Provides a list of all inheritable internal event names 48 | ------------------------------------------------------------------------------- 49 | local eventnames = { 50 | "__add", "__sub", "__mul", "__div", "__mod", 51 | "__pow", "__unm", "__len", "__lt", "__le", 52 | "__concat", "__call", 53 | "__tostring" 54 | } 55 | 56 | ------------------------------------------------------------------------------- 57 | -- metamethod() 58 | -- Purpose: Creates a placeholder metamethod for metamethod inheritance 59 | -- Input: metatable 60 | -- eventname 61 | -- Output: function 62 | ------------------------------------------------------------------------------- 63 | local function metamethod( metatable, eventname ) 64 | return function( ... ) 65 | local event = nil 66 | local base = getbaseclass( metatable ) 67 | while ( base ~= nil ) do 68 | if ( base[ eventname ] ) then 69 | event = base[ eventname ] 70 | break 71 | end 72 | base = getbaseclass( base ) 73 | end 74 | local type = type( event ) 75 | if ( type ~= "function" ) then 76 | error( "attempt to call metamethod '" .. eventname .. "' " .. 77 | "(a " .. type .. " value)", 2 ) 78 | end 79 | local returns = { pcall( event, ... ) } 80 | if ( returns[ 1 ] ~= true ) then 81 | error( returns[ 2 ], 2 ) 82 | else 83 | return unpack( returns, 2 ) 84 | end 85 | end 86 | end 87 | 88 | ------------------------------------------------------------------------------- 89 | -- setproxy() 90 | -- Purpose: Sets a proxy for __gc 91 | -- Input: object 92 | ------------------------------------------------------------------------------- 93 | local function setproxy( object ) 94 | local __newproxy = newproxy( true ) 95 | local metatable = getmetatable( __newproxy ) 96 | metatable.__gc = function() 97 | local metatable = getmetatable( object ) 98 | metatable.__gc( object ) 99 | end 100 | object.__newproxy = __newproxy 101 | end 102 | 103 | _G.setproxy = setproxy 104 | 105 | ------------------------------------------------------------------------------- 106 | -- classinit 107 | -- Purpose: Initializes a class 108 | -- Input: module 109 | ------------------------------------------------------------------------------- 110 | local function classinit( module ) 111 | module.__index = module 112 | module.__type = string.gsub( module._NAME, module._PACKAGE, "" ) 113 | module._M = nil 114 | module._NAME = nil 115 | module._PACKAGE = nil 116 | -- Create a shortcut to name() 117 | setmetatable( module, { 118 | __call = function( self, ... ) 119 | -- Create an instance of this object 120 | local object = new( self ) 121 | -- Call its constructor (function name:name( ... ) ... end) if it 122 | -- exists 123 | local constructor = rawget( self, self.__type ) 124 | if ( constructor ~= nil ) then 125 | local type = type( constructor ) 126 | if ( type ~= "function" ) then 127 | error( "attempt to call constructor '" .. name .. "' " .. 128 | "(a " .. type .. " value)", 2 ) 129 | end 130 | constructor( object, ... ) 131 | end 132 | -- Return the instance 133 | return object 134 | end 135 | } ) 136 | end 137 | 138 | ------------------------------------------------------------------------------- 139 | -- inherit 140 | -- Purpose: Sets a base class 141 | -- Input: base - Name of metatable 142 | ------------------------------------------------------------------------------- 143 | local function inherit( base ) 144 | return function( module ) 145 | -- Set our base class 146 | module.__base = base 147 | -- Overwrite our existing __index value with a metamethod which checks 148 | -- our members, metatable, and base class, in that order, a la behavior 149 | -- via the Lua 5.1 manual's illustrative code for indexing access 150 | module.__index = function( table, key ) 151 | local v = rawget( module, key ) 152 | if ( v ~= nil ) then return v end 153 | local baseclass = getbaseclass( module ) 154 | if ( baseclass == nil ) then 155 | error( "attempt to index base class '" .. base .. "' " .. 156 | "(a nil value)", 2 ) 157 | end 158 | local h = rawget( baseclass, "__index" ) 159 | if ( h == nil ) then return nil end 160 | if ( type( h ) == "function" ) then 161 | return h( table, key ) 162 | else 163 | return h[ key ] 164 | end 165 | end 166 | -- Create inheritable metamethods 167 | for _, event in ipairs( eventnames ) do 168 | module[ event ] = metamethod( module, event ) 169 | end 170 | end 171 | end 172 | 173 | ------------------------------------------------------------------------------- 174 | -- class() 175 | -- Purpose: Creates a class 176 | -- Input: modname 177 | ------------------------------------------------------------------------------- 178 | function class( modname ) 179 | local function setmodule( modname ) 180 | module( modname, classinit ) 181 | end setmodule( modname ) 182 | _R[ modname ] = package.loaded[ modname ] 183 | -- For syntactic sugar, return a function to set inheritance 184 | return function( base ) 185 | local metatable = package.loaded[ modname ] 186 | inherit( base )( metatable ) 187 | end 188 | end 189 | -------------------------------------------------------------------------------- /lib/enet.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/lib/enet.dll -------------------------------------------------------------------------------- /lib/enet.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/lib/enet.so -------------------------------------------------------------------------------- /lib/freetype.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | io.input( framework.execdir .. "include/freetype.h" ) 9 | ffi.cdef( io.read( "*all" ) ) 10 | return ffi.load( "freetype" ) 11 | -------------------------------------------------------------------------------- /lib/kazmath.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | io.input( framework.execdir .. "include/kazmath.h" ) 9 | ffi.cdef( io.read( "*all" ) ) 10 | 11 | local kazmath = ffi.load( 12 | ffi.os == "Windows" and "kazmath" or framework.execdir .. "bin/libkazmath.dylib" 13 | ) 14 | local _M = {} 15 | 16 | function _M.kmMat4Print( pOut ) 17 | local mat = pOut.mat 18 | print( 19 | mat[0], mat[1], mat[2], mat[3] .. "\n", 20 | "\r" .. mat[4], mat[5], mat[6], mat[7] .. "\n", 21 | "\r" .. mat[8], mat[9], mat[10], mat[11] .. "\n", 22 | "\r" .. mat[12], mat[13], mat[14], mat[15] 23 | ) 24 | end 25 | 26 | function _M.kmMat4ReversedZPerspectiveProjection(pOut, fovY, 27 | aspect, zNear) 28 | local r = kazmath.kmDegreesToRadians(fovY / 2) 29 | local c = math.cos(r) 30 | local tangent = 0 31 | 32 | if (c == 0 or aspect == 0) then 33 | return nil 34 | end 35 | 36 | --[[sin(r) / cos(r) = tan(r)]] 37 | tangent = math.sin(r) / c 38 | 39 | kazmath.kmMat4Identity(pOut) 40 | pOut.mat[0] = 1 / tangent / aspect 41 | pOut.mat[5] = 0 42 | pOut.mat[10] = 0 43 | pOut.mat[11] = -1 44 | pOut.mat[14] = zNear 45 | pOut.mat[15] = 0 46 | 47 | return pOut 48 | end 49 | 50 | function _M.kmMat4Transform( pOut, x, y, angle, sx, sy, ox, oy, kx, ky ) 51 | local c, s = math.cos(angle), math.sin(angle) 52 | -- matrix multiplication carried out on paper: 53 | -- |1 x| |c -s | |sx | | 1 ky | |1 -ox| 54 | -- | 1 y| |s c | | sy | |kx 1 | | 1 -oy| 55 | -- | 1 | | 1 | | 1 | | 1 | | 1 | 56 | -- | 1| | 1| | 1| | 1| | 1 | 57 | -- move rotate scale skew origin pOut.mat[10] = pOut.mat[15] = 1.0 58 | pOut.mat[0] = c * sx - ky * s * sy -- = a 59 | pOut.mat[1] = s * sx + ky * c * sy -- = b 60 | pOut.mat[4] = kx * c * sx - s * sy -- = c 61 | pOut.mat[5] = kx * s * sx + c * sy -- = d 62 | pOut.mat[12] = x - ox * pOut.mat[0] - oy * pOut.mat[4] 63 | pOut.mat[13] = y - ox * pOut.mat[1] - oy * pOut.mat[5] 64 | end 65 | 66 | return setmetatable( _M, { 67 | __index = function( table, key ) 68 | return kazmath[ key ] 69 | end 70 | } ) 71 | -------------------------------------------------------------------------------- /lib/lanes/core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/lib/lanes/core.dll -------------------------------------------------------------------------------- /lib/lanes/core.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/lib/lanes/core.so -------------------------------------------------------------------------------- /lib/mime.lua: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- MIME support for the Lua language. 3 | -- Author: Diego Nehab 4 | -- Conforming to RFCs 2045-2049 5 | -- RCS ID: $Id: mime.lua,v 1.29 2007/06/11 23:44:54 diego Exp $ 6 | ----------------------------------------------------------------------------- 7 | 8 | ----------------------------------------------------------------------------- 9 | -- Declare module and import dependencies 10 | ----------------------------------------------------------------------------- 11 | local base = _G 12 | local ltn12 = require("ltn12") 13 | local mime = require("mime.core") 14 | local io = require("io") 15 | local string = require("string") 16 | module("mime") 17 | 18 | -- encode, decode and wrap algorithm tables 19 | encodet = {} 20 | decodet = {} 21 | wrapt = {} 22 | 23 | -- creates a function that chooses a filter by name from a given table 24 | local function choose(table) 25 | return function(name, opt1, opt2) 26 | if base.type(name) ~= "string" then 27 | name, opt1, opt2 = "default", name, opt1 28 | end 29 | local f = table[name or "nil"] 30 | if not f then 31 | base.error("unknown key (" .. base.tostring(name) .. ")", 3) 32 | else return f(opt1, opt2) end 33 | end 34 | end 35 | 36 | -- define the encoding filters 37 | encodet['base64'] = function() 38 | return ltn12.filter.cycle(b64, "") 39 | end 40 | 41 | encodet['quoted-printable'] = function(mode) 42 | return ltn12.filter.cycle(qp, "", 43 | (mode == "binary") and "=0D=0A" or "\r\n") 44 | end 45 | 46 | -- define the decoding filters 47 | decodet['base64'] = function() 48 | return ltn12.filter.cycle(unb64, "") 49 | end 50 | 51 | decodet['quoted-printable'] = function() 52 | return ltn12.filter.cycle(unqp, "") 53 | end 54 | 55 | local function format(chunk) 56 | if chunk then 57 | if chunk == "" then return "''" 58 | else return string.len(chunk) end 59 | else return "nil" end 60 | end 61 | 62 | -- define the line-wrap filters 63 | wrapt['text'] = function(length) 64 | length = length or 76 65 | return ltn12.filter.cycle(wrp, length, length) 66 | end 67 | wrapt['base64'] = wrapt['text'] 68 | wrapt['default'] = wrapt['text'] 69 | 70 | wrapt['quoted-printable'] = function() 71 | return ltn12.filter.cycle(qpwrp, 76, 76) 72 | end 73 | 74 | -- function that choose the encoding, decoding or wrap algorithm 75 | encode = choose(encodet) 76 | decode = choose(decodet) 77 | wrap = choose(wrapt) 78 | 79 | -- define the end-of-line normalization filter 80 | function normalize(marker) 81 | return ltn12.filter.cycle(eol, 0, marker) 82 | end 83 | 84 | -- high level stuffing filter 85 | function stuff() 86 | return ltn12.filter.cycle(dot, 2) 87 | end 88 | -------------------------------------------------------------------------------- /lib/mime/core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/lib/mime/core.dll -------------------------------------------------------------------------------- /lib/mime/core.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/lib/mime/core.so -------------------------------------------------------------------------------- /lib/openal.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | io.input( framework.execdir .. "include/al.h" ) 9 | ffi.cdef( io.read( "*all" ) ) 10 | 11 | local AL = ffi.load( ffi.os == "Windows" and "OpenAL32" or "OpenAL.framework/OpenAL" ) 12 | local _M = { 13 | AL_INVALID = (-1), 14 | AL_NONE = 0, 15 | AL_FALSE = 0, 16 | AL_TRUE = 1, 17 | AL_SOURCE_RELATIVE = 0x202, 18 | AL_CONE_INNER_ANGLE = 0x1001, 19 | AL_CONE_OUTER_ANGLE = 0x1002, 20 | AL_PITCH = 0x1003, 21 | AL_POSITION = 0x1004, 22 | AL_DIRECTION = 0x1005, 23 | AL_VELOCITY = 0x1006, 24 | AL_LOOPING = 0x1007, 25 | AL_BUFFER = 0x1009, 26 | AL_GAIN = 0x100A, 27 | AL_MIN_GAIN = 0x100D, 28 | AL_MAX_GAIN = 0x100E, 29 | AL_ORIENTATION = 0x100F, 30 | AL_SOURCE_STATE = 0x1010, 31 | AL_INITIAL = 0x1011, 32 | AL_PLAYING = 0x1012, 33 | AL_PAUSED = 0x1013, 34 | AL_STOPPED = 0x1014, 35 | AL_BUFFERS_QUEUED = 0x1015, 36 | AL_BUFFERS_PROCESSED = 0x1016, 37 | AL_SEC_OFFSET = 0x1024, 38 | AL_SAMPLE_OFFSET = 0x1025, 39 | AL_BYTE_OFFSET = 0x1026, 40 | AL_SOURCE_TYPE = 0x1027, 41 | AL_STATIC = 0x1028, 42 | AL_STREAMING = 0x1029, 43 | AL_UNDETERMINED = 0x1030, 44 | AL_FORMAT_MONO8 = 0x1100, 45 | AL_FORMAT_MONO16 = 0x1101, 46 | AL_FORMAT_STEREO8 = 0x1102, 47 | AL_FORMAT_STEREO16 = 0x1103, 48 | AL_REFERENCE_DISTANCE = 0x1020, 49 | AL_ROLLOFF_FACTOR = 0x1021, 50 | AL_CONE_OUTER_GAIN = 0x1022, 51 | AL_MAX_DISTANCE = 0x1023, 52 | AL_FREQUENCY = 0x2001, 53 | AL_BITS = 0x2002, 54 | AL_CHANNELS = 0x2003, 55 | AL_SIZE = 0x2004, 56 | AL_UNUSED = 0x2010, 57 | AL_PENDING = 0x2011, 58 | AL_PROCESSED = 0x2012, 59 | AL_NO_ERROR = 0, 60 | AL_INVALID_NAME = 0xA001, 61 | AL_INVALID_ENUM = 0xA002, 62 | AL_INVALID_VALUE = 0xA003, 63 | AL_INVALID_OPERATION = 0xA004, 64 | AL_OUT_OF_MEMORY = 0xA005, 65 | AL_VENDOR = 0xB001, 66 | AL_VERSION = 0xB002, 67 | AL_RENDERER = 0xB003, 68 | AL_EXTENSIONS = 0xB004, 69 | AL_DOPPLER_FACTOR = 0xC000, 70 | AL_DOPPLER_VELOCITY = 0xC001, 71 | AL_SPEED_OF_SOUND = 0xC003, 72 | AL_DISTANCE_MODEL = 0xD000, 73 | AL_INVERSE_DISTANCE = 0xD001, 74 | AL_INVERSE_DISTANCE_CLAMPED = 0xD002, 75 | AL_LINEAR_DISTANCE = 0xD003, 76 | AL_LINEAR_DISTANCE_CLAMPED = 0xD004, 77 | AL_EXPONENT_DISTANCE = 0xD005, 78 | AL_EXPONENT_DISTANCE_CLAMPED = 0xD006, 79 | ALC_INVALID = 0, 80 | ALC_VERSION_0_1 = 1, 81 | ALC_FALSE = 0, 82 | ALC_TRUE = 1, 83 | ALC_FREQUENCY = 0x1007, 84 | ALC_REFRESH = 0x1008, 85 | ALC_SYNC = 0x1009, 86 | ALC_MONO_SOURCES = 0x1010, 87 | ALC_STEREO_SOURCES = 0x1011, 88 | ALC_NO_ERROR = 0, 89 | ALC_INVALID_DEVICE = 0xA001, 90 | ALC_INVALID_CONTEXT = 0xA002, 91 | ALC_INVALID_ENUM = 0xA003, 92 | ALC_INVALID_VALUE = 0xA004, 93 | ALC_OUT_OF_MEMORY = 0xA005, 94 | ALC_DEFAULT_DEVICE_SPECIFIER = 0x1004, 95 | ALC_DEVICE_SPECIFIER = 0x1005, 96 | ALC_EXTENSIONS = 0x1006, 97 | ALC_MAJOR_VERSION = 0x1000, 98 | ALC_MINOR_VERSION = 0x1001, 99 | ALC_ATTRIBUTES_SIZE = 0x1002, 100 | ALC_ALL_ATTRIBUTES = 0x1003, 101 | ALC_DEFAULT_ALL_DEVICES_SPECIFIER = 0x1012, 102 | ALC_ALL_DEVICES_SPECIFIER = 0x1013, 103 | ALC_CAPTURE_DEVICE_SPECIFIER = 0x310, 104 | ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER = 0x311, 105 | ALC_CAPTURE_SAMPLES = 0x312 106 | } 107 | return setmetatable( _M, { 108 | __index = function( table, key ) 109 | return AL[ key ] 110 | end 111 | } ) 112 | -------------------------------------------------------------------------------- /lib/opus.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | io.input( framework.execdir .. "include/opus.h" ) 9 | ffi.cdef( io.read( "*all" ) ) 10 | return ffi.load( "opus" ) 11 | -------------------------------------------------------------------------------- /lib/physicsfs.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | io.input( framework.execdir .. "include/physfs.h" ) 9 | ffi.cdef( io.read( "*all" ) ) 10 | return ffi.load( "physfs" ) 11 | -------------------------------------------------------------------------------- /lib/sdl.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | local bit = require( "bit" ) 9 | 10 | local bor = bit.bor 11 | local band = bit.band 12 | 13 | io.input( framework.execdir .. "include/SDL.h" ) 14 | ffi.cdef( io.read( "*all" ) ) 15 | 16 | local SDL = ffi.load( "SDL2" ) 17 | 18 | local function SDL_WINDOWPOS_UNDEFINED_DISPLAY(X) 19 | return (bor(0x1FFF0000,(X))) 20 | end 21 | 22 | local function SDL_WINDOWPOS_ISUNDEFINED(X) 23 | return (band((X),0xFFFF0000) == SDL_WINDOWPOS_UNDEFINED_MASK) 24 | end 25 | 26 | local _M = { 27 | --[[ 28 | * \name Audio format flags 29 | * 30 | * Defaults to LSB byte order. 31 | ]] 32 | AUDIO_U8 = 0x0008, --[[< Unsigned 8-bit samples ]] 33 | AUDIO_S8 = 0x8008, --[[< Signed 8-bit samples ]] 34 | AUDIO_U16LSB = 0x0010, --[[< Unsigned 16-bit samples ]] 35 | AUDIO_S16LSB = 0x8010, --[[< Signed 16-bit samples ]] 36 | AUDIO_U16MSB = 0x1010, --[[< As above, but big-endian byte order ]] 37 | AUDIO_S16MSB = 0x9010, --[[< As above, but big-endian byte order ]] 38 | AUDIO_U16 = 0x0010, 39 | AUDIO_S16 = 0x8010, 40 | 41 | --[[ Used as the device ID for mouse events simulated with touch input ]] 42 | SDL_TOUCH_MOUSEID = (-1), 43 | 44 | --[[ 45 | * \brief Used to indicate that you don't care what the window position is. 46 | ]] 47 | SDL_WINDOWPOS_UNDEFINED_MASK = 0x1FFF0000, 48 | SDL_WINDOWPOS_UNDEFINED_DISPLAY = SDL_WINDOWPOS_UNDEFINED_DISPLAY, 49 | SDL_WINDOWPOS_UNDEFINED = SDL_WINDOWPOS_UNDEFINED_DISPLAY(0), 50 | SDL_WINDOWPOS_ISUNDEFINED = SDL_WINDOWPOS_ISUNDEFINED, 51 | 52 | --[[ 53 | * \name SDL_INIT_* 54 | * 55 | * These are the flags which may be passed to SDL_Init(). You should 56 | * specify the subsystems which you will be using in your application. 57 | ]] 58 | SDL_INIT_TIMER = 0x00000001, 59 | SDL_INIT_AUDIO = 0x00000010, 60 | SDL_INIT_VIDEO = 0x00000020, --[[< SDL_INIT_VIDEO implies SDL_INIT_EVENTS ]] 61 | SDL_INIT_JOYSTICK = 0x00000200, --[[< SDL_INIT_JOYSTICK implies SDL_INIT_EVENTS ]] 62 | SDL_INIT_HAPTIC = 0x00001000, 63 | SDL_INIT_GAMECONTROLLER = 0x00002000, --[[< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK ]] 64 | SDL_INIT_EVENTS = 0x00004000, 65 | SDL_INIT_NOPARACHUTE = 0x00100000 --[[< compatibility; this flag is ignored. ]] 66 | } 67 | _M.SDL_INIT_EVERYTHING = bor( 68 | _M.SDL_INIT_TIMER, _M.SDL_INIT_AUDIO, _M.SDL_INIT_VIDEO, _M.SDL_INIT_EVENTS, 69 | _M.SDL_INIT_JOYSTICK, _M.SDL_INIT_HAPTIC, _M.SDL_INIT_GAMECONTROLLER 70 | ) 71 | 72 | return setmetatable( _M, { 73 | __index = function( table, key ) 74 | return SDL[ key ] 75 | end 76 | } ) 77 | -------------------------------------------------------------------------------- /lib/sdl_sound.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | io.input( framework.execdir .. "include/SDL_sound.h" ) 9 | ffi.cdef( io.read( "*all" ) ) 10 | return ffi.load( "SDL_sound" ) 11 | -------------------------------------------------------------------------------- /lib/socket.lua: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- LuaSocket helper module 3 | -- Author: Diego Nehab 4 | -- RCS ID: $Id: socket.lua,v 1.22 2005/11/22 08:33:29 diego Exp $ 5 | ----------------------------------------------------------------------------- 6 | 7 | ----------------------------------------------------------------------------- 8 | -- Declare module and import dependencies 9 | ----------------------------------------------------------------------------- 10 | local base = _G 11 | local string = require("string") 12 | local math = require("math") 13 | local socket = require("socket.core") 14 | module("socket") 15 | 16 | ----------------------------------------------------------------------------- 17 | -- Exported auxiliar functions 18 | ----------------------------------------------------------------------------- 19 | function connect(address, port, laddress, lport) 20 | local sock, err = socket.tcp() 21 | if not sock then return nil, err end 22 | if laddress then 23 | local res, err = sock:bind(laddress, lport, -1) 24 | if not res then return nil, err end 25 | end 26 | local res, err = sock:connect(address, port) 27 | if not res then return nil, err end 28 | return sock 29 | end 30 | 31 | function bind(host, port, backlog) 32 | local sock, err = socket.tcp() 33 | if not sock then return nil, err end 34 | sock:setoption("reuseaddr", true) 35 | local res, err = sock:bind(host, port) 36 | if not res then return nil, err end 37 | res, err = sock:listen(backlog) 38 | if not res then return nil, err end 39 | return sock 40 | end 41 | 42 | try = newtry() 43 | 44 | function choose(table) 45 | return function(name, opt1, opt2) 46 | if base.type(name) ~= "string" then 47 | name, opt1, opt2 = "default", name, opt1 48 | end 49 | local f = table[name or "nil"] 50 | if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) 51 | else return f(opt1, opt2) end 52 | end 53 | end 54 | 55 | ----------------------------------------------------------------------------- 56 | -- Socket sources and sinks, conforming to LTN12 57 | ----------------------------------------------------------------------------- 58 | -- create namespaces inside LuaSocket namespace 59 | sourcet = {} 60 | sinkt = {} 61 | 62 | BLOCKSIZE = 2048 63 | 64 | sinkt["close-when-done"] = function(sock) 65 | return base.setmetatable({ 66 | getfd = function() return sock:getfd() end, 67 | dirty = function() return sock:dirty() end 68 | }, { 69 | __call = function(self, chunk, err) 70 | if not chunk then 71 | sock:close() 72 | return 1 73 | else return sock:send(chunk) end 74 | end 75 | }) 76 | end 77 | 78 | sinkt["keep-open"] = function(sock) 79 | return base.setmetatable({ 80 | getfd = function() return sock:getfd() end, 81 | dirty = function() return sock:dirty() end 82 | }, { 83 | __call = function(self, chunk, err) 84 | if chunk then return sock:send(chunk) 85 | else return 1 end 86 | end 87 | }) 88 | end 89 | 90 | sinkt["default"] = sinkt["keep-open"] 91 | 92 | sink = choose(sinkt) 93 | 94 | sourcet["by-length"] = function(sock, length) 95 | return base.setmetatable({ 96 | getfd = function() return sock:getfd() end, 97 | dirty = function() return sock:dirty() end 98 | }, { 99 | __call = function() 100 | if length <= 0 then return nil end 101 | local size = math.min(socket.BLOCKSIZE, length) 102 | local chunk, err = sock:receive(size) 103 | if err then return nil, err end 104 | length = length - string.len(chunk) 105 | return chunk 106 | end 107 | }) 108 | end 109 | 110 | sourcet["until-closed"] = function(sock) 111 | local done 112 | return base.setmetatable({ 113 | getfd = function() return sock:getfd() end, 114 | dirty = function() return sock:dirty() end 115 | }, { 116 | __call = function() 117 | if done then return nil end 118 | local chunk, err, partial = sock:receive(socket.BLOCKSIZE) 119 | if not err then return chunk 120 | elseif err == "closed" then 121 | sock:close() 122 | done = 1 123 | return partial 124 | else return nil, err end 125 | end 126 | }) 127 | end 128 | 129 | 130 | sourcet["default"] = sourcet["until-closed"] 131 | 132 | source = choose(sourcet) 133 | 134 | -------------------------------------------------------------------------------- /lib/socket/core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/lib/socket/core.dll -------------------------------------------------------------------------------- /lib/socket/core.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/lib/socket/core.so -------------------------------------------------------------------------------- /lib/socket/tp.lua: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- Unified SMTP/FTP subsystem 3 | -- LuaSocket toolkit. 4 | -- Author: Diego Nehab 5 | -- RCS ID: $Id: tp.lua,v 1.22 2006/03/14 09:04:15 diego Exp $ 6 | ----------------------------------------------------------------------------- 7 | 8 | ----------------------------------------------------------------------------- 9 | -- Declare module and import dependencies 10 | ----------------------------------------------------------------------------- 11 | local base = _G 12 | local string = require("string") 13 | local socket = require("socket") 14 | local ltn12 = require("ltn12") 15 | module("socket.tp") 16 | 17 | ----------------------------------------------------------------------------- 18 | -- Program constants 19 | ----------------------------------------------------------------------------- 20 | TIMEOUT = 60 21 | 22 | ----------------------------------------------------------------------------- 23 | -- Implementation 24 | ----------------------------------------------------------------------------- 25 | -- gets server reply (works for SMTP and FTP) 26 | local function get_reply(c) 27 | local code, current, sep 28 | local line, err = c:receive() 29 | local reply = line 30 | if err then return nil, err end 31 | code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) 32 | if not code then return nil, "invalid server reply" end 33 | if sep == "-" then -- reply is multiline 34 | repeat 35 | line, err = c:receive() 36 | if err then return nil, err end 37 | current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) 38 | reply = reply .. "\n" .. line 39 | -- reply ends with same code 40 | until code == current and sep == " " 41 | end 42 | return code, reply 43 | end 44 | 45 | -- metatable for sock object 46 | local metat = { __index = {} } 47 | 48 | function metat.__index:check(ok) 49 | local code, reply = get_reply(self.c) 50 | if not code then return nil, reply end 51 | if base.type(ok) ~= "function" then 52 | if base.type(ok) == "table" then 53 | for i, v in base.ipairs(ok) do 54 | if string.find(code, v) then 55 | return base.tonumber(code), reply 56 | end 57 | end 58 | return nil, reply 59 | else 60 | if string.find(code, ok) then return base.tonumber(code), reply 61 | else return nil, reply end 62 | end 63 | else return ok(base.tonumber(code), reply) end 64 | end 65 | 66 | function metat.__index:command(cmd, arg) 67 | if arg then 68 | return self.c:send(cmd .. " " .. arg.. "\r\n") 69 | else 70 | return self.c:send(cmd .. "\r\n") 71 | end 72 | end 73 | 74 | function metat.__index:sink(snk, pat) 75 | local chunk, err = c:receive(pat) 76 | return snk(chunk, err) 77 | end 78 | 79 | function metat.__index:send(data) 80 | return self.c:send(data) 81 | end 82 | 83 | function metat.__index:receive(pat) 84 | return self.c:receive(pat) 85 | end 86 | 87 | function metat.__index:getfd() 88 | return self.c:getfd() 89 | end 90 | 91 | function metat.__index:dirty() 92 | return self.c:dirty() 93 | end 94 | 95 | function metat.__index:getcontrol() 96 | return self.c 97 | end 98 | 99 | function metat.__index:source(source, step) 100 | local sink = socket.sink("keep-open", self.c) 101 | local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step) 102 | return ret, err 103 | end 104 | 105 | -- closes the underlying c 106 | function metat.__index:close() 107 | self.c:close() 108 | return 1 109 | end 110 | 111 | -- connect with server and return c object 112 | function connect(host, port, timeout, create) 113 | local c, e = (create or socket.tcp)() 114 | if not c then return nil, e end 115 | c:settimeout(timeout or TIMEOUT) 116 | local r, e = c:connect(host, port) 117 | if not r then 118 | c:close() 119 | return nil, e 120 | end 121 | return base.setmetatable({c = c}, metat) 122 | end 123 | 124 | -------------------------------------------------------------------------------- /lib/ssl.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- LuaSec 0.7alpha 3 | -- 4 | -- Copyright (C) 2006-2017 Bruno Silvestre 5 | -- 6 | ------------------------------------------------------------------------------ 7 | 8 | local core = require("ssl.core") 9 | local context = require("ssl.context") 10 | local x509 = require("ssl.x509") 11 | local config = require("ssl.config") 12 | 13 | local unpack = table.unpack or unpack 14 | 15 | -- We must prevent the contexts to be collected before the connections, 16 | -- otherwise the C registry will be cleared. 17 | local registry = setmetatable({}, {__mode="k"}) 18 | 19 | -- 20 | -- 21 | -- 22 | local function optexec(func, param, ctx) 23 | if param then 24 | if type(param) == "table" then 25 | return func(ctx, unpack(param)) 26 | else 27 | return func(ctx, param) 28 | end 29 | end 30 | return true 31 | end 32 | 33 | -- 34 | -- 35 | -- 36 | local function newcontext(cfg) 37 | local succ, msg, ctx 38 | -- Create the context 39 | ctx, msg = context.create(cfg.protocol) 40 | if not ctx then return nil, msg end 41 | -- Mode 42 | succ, msg = context.setmode(ctx, cfg.mode) 43 | if not succ then return nil, msg end 44 | -- Load the key 45 | if cfg.key then 46 | if cfg.password and 47 | type(cfg.password) ~= "function" and 48 | type(cfg.password) ~= "string" 49 | then 50 | return nil, "invalid password type" 51 | end 52 | succ, msg = context.loadkey(ctx, cfg.key, cfg.password) 53 | if not succ then return nil, msg end 54 | end 55 | -- Load the certificate 56 | if cfg.certificate then 57 | succ, msg = context.loadcert(ctx, cfg.certificate) 58 | if not succ then return nil, msg end 59 | if cfg.key and context.checkkey then 60 | succ = context.checkkey(ctx) 61 | if not succ then return nil, "private key does not match public key" end 62 | end 63 | end 64 | -- Load the CA certificates 65 | if cfg.cafile or cfg.capath then 66 | succ, msg = context.locations(ctx, cfg.cafile, cfg.capath) 67 | if not succ then return nil, msg end 68 | end 69 | -- Set SSL ciphers 70 | if cfg.ciphers then 71 | succ, msg = context.setcipher(ctx, cfg.ciphers) 72 | if not succ then return nil, msg end 73 | end 74 | -- Set the verification options 75 | succ, msg = optexec(context.setverify, cfg.verify, ctx) 76 | if not succ then return nil, msg end 77 | -- Set SSL options 78 | succ, msg = optexec(context.setoptions, cfg.options, ctx) 79 | if not succ then return nil, msg end 80 | -- Set the depth for certificate verification 81 | if cfg.depth then 82 | succ, msg = context.setdepth(ctx, cfg.depth) 83 | if not succ then return nil, msg end 84 | end 85 | 86 | -- NOTE: Setting DH parameters and elliptic curves needs to come after 87 | -- setoptions(), in case the user has specified the single_{dh,ecdh}_use 88 | -- options. 89 | 90 | -- Set DH parameters 91 | if cfg.dhparam then 92 | if type(cfg.dhparam) ~= "function" then 93 | return nil, "invalid DH parameter type" 94 | end 95 | context.setdhparam(ctx, cfg.dhparam) 96 | end 97 | 98 | -- Set elliptic curves 99 | if (not config.algorithms.ec) and (cfg.curve or cfg.curveslist) then 100 | return false, "elliptic curves not supported" 101 | end 102 | if config.capabilities.curves_list and cfg.curveslist then 103 | succ, msg = context.setcurveslist(ctx, cfg.curveslist) 104 | if not succ then return nil, msg end 105 | elseif cfg.curve then 106 | succ, msg = context.setcurve(ctx, cfg.curve) 107 | if not succ then return nil, msg end 108 | end 109 | 110 | -- Set extra verification options 111 | if cfg.verifyext and ctx.setverifyext then 112 | succ, msg = optexec(ctx.setverifyext, cfg.verifyext, ctx) 113 | if not succ then return nil, msg end 114 | end 115 | 116 | return ctx 117 | end 118 | 119 | -- 120 | -- 121 | -- 122 | local function wrap(sock, cfg) 123 | local ctx, msg 124 | if type(cfg) == "table" then 125 | ctx, msg = newcontext(cfg) 126 | if not ctx then return nil, msg end 127 | else 128 | ctx = cfg 129 | end 130 | local s, msg = core.create(ctx) 131 | if s then 132 | core.setfd(s, sock:getfd()) 133 | sock:setfd(core.SOCKET_INVALID) 134 | registry[s] = ctx 135 | return s 136 | end 137 | return nil, msg 138 | end 139 | 140 | -- 141 | -- Extract connection information. 142 | -- 143 | local function info(ssl, field) 144 | local str, comp, err, protocol 145 | comp, err = core.compression(ssl) 146 | if err then 147 | return comp, err 148 | end 149 | -- Avoid parser 150 | if field == "compression" then 151 | return comp 152 | end 153 | local info = {compression = comp} 154 | str, info.bits, info.algbits, protocol = core.info(ssl) 155 | if str then 156 | info.cipher, info.protocol, info.key, 157 | info.authentication, info.encryption, info.mac = 158 | string.match(str, 159 | "^(%S+)%s+(%S+)%s+Kx=(%S+)%s+Au=(%S+)%s+Enc=(%S+)%s+Mac=(%S+)") 160 | info.export = (string.match(str, "%sexport%s*$") ~= nil) 161 | end 162 | if protocol then 163 | info.protocol = protocol 164 | end 165 | if field then 166 | return info[field] 167 | end 168 | -- Empty? 169 | return ( (next(info)) and info ) 170 | end 171 | 172 | -- 173 | -- Set method for SSL connections. 174 | -- 175 | core.setmethod("info", info) 176 | 177 | -------------------------------------------------------------------------------- 178 | -- Export module 179 | -- 180 | 181 | local _M = { 182 | _VERSION = "0.7", 183 | _COPYRIGHT = core.copyright(), 184 | loadcertificate = x509.load, 185 | newcontext = newcontext, 186 | wrap = wrap, 187 | } 188 | 189 | return _M 190 | -------------------------------------------------------------------------------- /lib/ssl/https.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaSec 0.7alpha 3 | -- Copyright (C) 2009-2017 PUC-Rio 4 | -- 5 | -- Author: Pablo Musa 6 | -- Author: Tomas Guisasola 7 | --------------------------------------------------------------------------- 8 | 9 | local socket = require("socket") 10 | local ssl = require("ssl") 11 | local ltn12 = require("ltn12") 12 | local http = require("socket.http") 13 | local url = require("socket.url") 14 | 15 | local try = socket.try 16 | 17 | -- 18 | -- Module 19 | -- 20 | local _M = { 21 | _VERSION = "0.7", 22 | _COPYRIGHT = "LuaSec 0.7alpha - Copyright (C) 2009-2017 PUC-Rio", 23 | PORT = 443, 24 | } 25 | 26 | -- TLS configuration 27 | local cfg = { 28 | protocol = "any", 29 | options = {"all", "no_sslv2", "no_sslv3"}, 30 | verify = "none", 31 | } 32 | 33 | -------------------------------------------------------------------- 34 | -- Auxiliar Functions 35 | -------------------------------------------------------------------- 36 | 37 | -- Insert default HTTPS port. 38 | local function default_https_port(u) 39 | return url.build(url.parse(u, {port = _M.PORT})) 40 | end 41 | 42 | -- Convert an URL to a table according to Luasocket needs. 43 | local function urlstring_totable(url, body, result_table) 44 | url = { 45 | url = default_https_port(url), 46 | method = body and "POST" or "GET", 47 | sink = ltn12.sink.table(result_table) 48 | } 49 | if body then 50 | url.source = ltn12.source.string(body) 51 | url.headers = { 52 | ["content-length"] = #body, 53 | ["content-type"] = "application/x-www-form-urlencoded", 54 | } 55 | end 56 | return url 57 | end 58 | 59 | -- Forward calls to the real connection object. 60 | local function reg(conn) 61 | local mt = getmetatable(conn.sock).__index 62 | for name, method in pairs(mt) do 63 | if type(method) == "function" then 64 | conn[name] = function (self, ...) 65 | return method(self.sock, ...) 66 | end 67 | end 68 | end 69 | end 70 | 71 | -- Return a function which performs the SSL/TLS connection. 72 | local function tcp(params) 73 | params = params or {} 74 | -- Default settings 75 | for k, v in pairs(cfg) do 76 | params[k] = params[k] or v 77 | end 78 | -- Force client mode 79 | params.mode = "client" 80 | -- 'create' function for LuaSocket 81 | return function () 82 | local conn = {} 83 | conn.sock = try(socket.tcp()) 84 | local st = getmetatable(conn.sock).__index.settimeout 85 | function conn:settimeout(...) 86 | return st(self.sock, ...) 87 | end 88 | -- Replace TCP's connection function 89 | function conn:connect(host, port) 90 | try(self.sock:connect(host, port)) 91 | self.sock = try(ssl.wrap(self.sock, params)) 92 | self.sock:sni(host) 93 | try(self.sock:dohandshake()) 94 | reg(self, getmetatable(self.sock)) 95 | return 1 96 | end 97 | return conn 98 | end 99 | end 100 | 101 | -------------------------------------------------------------------- 102 | -- Main Function 103 | -------------------------------------------------------------------- 104 | 105 | -- Make a HTTP request over secure connection. This function receives 106 | -- the same parameters of LuaSocket's HTTP module (except 'proxy' and 107 | -- 'redirect') plus LuaSec parameters. 108 | -- 109 | -- @param url mandatory (string or table) 110 | -- @param body optional (string) 111 | -- @return (string if url == string or 1), code, headers, status 112 | -- 113 | local function request(url, body) 114 | local result_table = {} 115 | local stringrequest = type(url) == "string" 116 | if stringrequest then 117 | url = urlstring_totable(url, body, result_table) 118 | else 119 | url.url = default_https_port(url.url) 120 | end 121 | if http.PROXY or url.proxy then 122 | return nil, "proxy not supported" 123 | elseif url.redirect then 124 | return nil, "redirect not supported" 125 | elseif url.create then 126 | return nil, "create function not permitted" 127 | end 128 | -- New 'create' function to establish a secure connection 129 | url.create = tcp(url) 130 | local res, code, headers, status = http.request(url) 131 | if res and stringrequest then 132 | return table.concat(result_table), code, headers, status 133 | end 134 | return res, code, headers, status 135 | end 136 | 137 | -------------------------------------------------------------------------------- 138 | -- Export module 139 | -- 140 | 141 | _M.request = request 142 | 143 | return _M 144 | -------------------------------------------------------------------------------- /lua/framework/audio.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "framework.sound" ) 8 | local AL = require( "openal" ) 9 | 10 | local framework = framework 11 | 12 | module( "framework.audio" ) 13 | 14 | _device = _device or AL.alcOpenDevice( nil ) 15 | _context = _context or AL.alcCreateContext( _device, nil ) 16 | AL.alcMakeContextCurrent( _context ) 17 | 18 | function newSource( filename ) 19 | local sound = framework.sound 20 | return sound( filename ) 21 | end 22 | 23 | function play( source ) 24 | source:play() 25 | end 26 | 27 | function setVolume( volume ) 28 | AL.alListenerf( AL.AL_GAIN, volume ) 29 | end 30 | 31 | function getVolume() 32 | local volume = ffi.new( "ALfloat[1]" ) 33 | AL.alGetListenerf( AL.AL_GAIN, volume[0] ) 34 | return volume 35 | end 36 | 37 | function quit() 38 | AL.alcCloseDevice( _device ) 39 | end 40 | -------------------------------------------------------------------------------- /lua/framework/event.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local SDL = require( "sdl" ) 8 | local ffi = require( "ffi" ) 9 | 10 | local framework = framework 11 | local string = string 12 | local collectgarbage = collectgarbage 13 | 14 | module( "framework.event" ) 15 | 16 | function poll() 17 | _event = _event or ffi.new( "SDL_Event" ) 18 | return SDL.SDL_PollEvent( _event ) ~= 0 and _event or nil 19 | end 20 | 21 | local function windowevent( window ) 22 | if ( window.event == ffi.C.SDL_WINDOWEVENT_SHOWN ) then 23 | framework.visible( true ) 24 | elseif ( window.event == ffi.C.SDL_WINDOWEVENT_HIDDEN ) then 25 | framework.visible( false ) 26 | elseif ( window.event == ffi.C.SDL_WINDOWEVENT_MOVED ) then 27 | framework.move( window.data1, window.data2 ) 28 | elseif ( window.event == ffi.C.SDL_WINDOWEVENT_RESIZED ) then 29 | framework.resize( window.data1, window.data2 ) 30 | elseif ( window.event == ffi.C.SDL_WINDOWEVENT_SIZE_CHANGED ) then 31 | framework.window.resize( window.data1, window.data2 ) 32 | elseif ( window.event == ffi.C.SDL_WINDOWEVENT_MINIMIZED ) then 33 | framework.minimize() 34 | elseif ( window.event == ffi.C.SDL_WINDOWEVENT_MAXIMIZED ) then 35 | framework.maximize() 36 | elseif ( window.event == ffi.C.SDL_WINDOWEVENT_RESTORED ) then 37 | framework.restore() 38 | elseif ( window.event == ffi.C.SDL_WINDOWEVENT_ENTER ) then 39 | framework.mousefocus( true ) 40 | elseif ( window.event == ffi.C.SDL_WINDOWEVENT_LEAVE ) then 41 | framework.mousefocus( false ) 42 | elseif ( window.event == ffi.C.SDL_WINDOWEVENT_FOCUS_GAINED ) then 43 | framework.focus( true ) 44 | elseif ( window.event == ffi.C.SDL_WINDOWEVENT_FOCUS_LOST ) then 45 | framework.focus( false ) 46 | end 47 | end 48 | 49 | function handle( e ) 50 | if ( e.type == ffi.C.SDL_APP_LOWMEMORY ) then 51 | framework.lowmemory() 52 | collectgarbage() 53 | collectgarbage() 54 | elseif ( e.type == ffi.C.SDL_WINDOWEVENT ) then 55 | windowevent( e.window ) 56 | elseif ( e.type == ffi.C.SDL_KEYDOWN ) then 57 | local key = SDL.SDL_GetKeyName( e.key.keysym.sym ) 58 | key = string.lower( ffi.string( key ) ) 59 | local scancode = SDL.SDL_GetScancodeName( e.key.keysym.scancode ) 60 | scancode = string.lower( ffi.string( scancode ) ) 61 | local isrepeat = e.key[ "repeat" ] == 1 and true or false 62 | framework.keypressed( key, scancode, isrepeat ) 63 | elseif ( e.type == ffi.C.SDL_KEYUP ) then 64 | local key = SDL.SDL_GetKeyName( e.key.keysym.sym ) 65 | key = string.lower( ffi.string( key ) ) 66 | local scancode = SDL.SDL_GetScancodeName( e.key.keysym.scancode ) 67 | scancode = string.lower( ffi.string( scancode ) ) 68 | framework.keyreleased( key, scancode ) 69 | elseif ( e.type == ffi.C.SDL_TEXTEDITING ) then 70 | framework.textedited( e.edit.text, e.edit.start, e.edit.length ) 71 | elseif ( e.type == ffi.C.SDL_TEXTINPUT ) then 72 | framework.textinput( ffi.string( e.text.text ) ) 73 | elseif ( e.type == ffi.C.SDL_MOUSEMOTION ) then 74 | local x = e.motion.x 75 | local y = e.motion.y 76 | local dx = e.motion.xrel 77 | local dy = e.motion.yrel 78 | local istouch = e.motion.which == SDL.SDL_TOUCH_MOUSEID 79 | framework.mousemoved( x, y, dx, dy, istouch ) 80 | elseif ( e.type == ffi.C.SDL_MOUSEBUTTONDOWN ) then 81 | local x = e.button.x 82 | local y = e.button.y 83 | local button = e.button.button 84 | if ( button == 2 ) then 85 | button = 3 86 | elseif ( button == 3 ) then 87 | button = 2 88 | end 89 | local istouch = e.button.which == SDL.SDL_TOUCH_MOUSEID 90 | framework.mousepressed( x, y, button, istouch ) 91 | elseif ( e.type == ffi.C.SDL_MOUSEBUTTONUP ) then 92 | local x = e.button.x 93 | local y = e.button.y 94 | local button = e.button.button 95 | if ( button == 2 ) then 96 | button = 3 97 | elseif ( button == 3 ) then 98 | button = 2 99 | end 100 | local istouch = e.button.which == SDL.SDL_TOUCH_MOUSEID 101 | framework.mousereleased( x, y, button, istouch ) 102 | elseif ( e.type == ffi.C.SDL_MOUSEWHEEL ) then 103 | framework.wheelmoved( e.wheel.x, e.wheel.y ) 104 | elseif ( e.type == ffi.C.SDL_JOYAXISMOTION ) then 105 | elseif ( e.type == ffi.C.SDL_JOYBALLMOTION ) then 106 | elseif ( e.type == ffi.C.SDL_JOYHATMOTION ) then 107 | elseif ( e.type == ffi.C.SDL_JOYBUTTONDOWN ) then 108 | elseif ( e.type == ffi.C.SDL_JOYBUTTONUP ) then 109 | elseif ( e.type == ffi.C.SDL_JOYDEVICEADDED ) then 110 | elseif ( e.type == ffi.C.SDL_JOYDEVICEREMOVED ) then 111 | elseif ( e.type == ffi.C.SDL_CONTROLLERAXISMOTION ) then 112 | elseif ( e.type == ffi.C.SDL_CONTROLLERBUTTONDOWN ) then 113 | elseif ( e.type == ffi.C.SDL_CONTROLLERBUTTONUP ) then 114 | elseif ( e.type == ffi.C.SDL_CONTROLLERDEVICEADDED ) then 115 | elseif ( e.type == ffi.C.SDL_CONTROLLERDEVICEREMOVED ) then 116 | elseif ( e.type == ffi.C.SDL_CONTROLLERDEVICEREMAPPED ) then 117 | elseif ( e.type == ffi.C.SDL_FINGERDOWN ) then 118 | elseif ( e.type == ffi.C.SDL_FINGERUP ) then 119 | elseif ( e.type == ffi.C.SDL_FINGERMOTION ) then 120 | elseif ( e.type == ffi.C.SDL_DOLLARGESTURE ) then 121 | elseif ( e.type == ffi.C.SDL_DOLLARRECORD ) then 122 | elseif ( e.type == ffi.C.SDL_MULTIGESTURE ) then 123 | elseif ( e.type == ffi.C.SDL_CLIPBOARDUPDATE ) then 124 | elseif ( e.type == ffi.C.SDL_DROPFILE ) then 125 | elseif ( e.type == ffi.C.SDL_DROPTEXT ) then 126 | elseif ( e.type == ffi.C.SDL_DROPBEGIN ) then 127 | elseif ( e.type == ffi.C.SDL_DROPCOMPLETE ) then 128 | elseif ( e.type == ffi.C.SDL_AUDIODEVICEADDED ) then 129 | elseif ( e.type == ffi.C.SDL_AUDIODEVICEREMOVED ) then 130 | end 131 | end 132 | -------------------------------------------------------------------------------- /lua/framework/filesystem.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local physfs = require( "physicsfs" ) 8 | local ffi = require( "ffi" ) 9 | local pcall = pcall 10 | local error = error 11 | local os = os 12 | local string = string 13 | local table = table 14 | local loadstring = loadstring 15 | 16 | module( "framework.filesystem" ) 17 | 18 | function createDirectory( dir ) 19 | return physfs.PHYSFS_mkdir( filename ) ~= 0 20 | end 21 | 22 | function doFile( filename ) 23 | local status, err = pcall( loadFile, filename ) 24 | if ( status == false ) then 25 | error( err, 2 ) 26 | end 27 | return err() 28 | end 29 | 30 | function exists( filename ) 31 | return physfs.PHYSFS_exists( filename ) ~= 0 32 | end 33 | 34 | function getAppdataDirectory() 35 | if ( ffi.os == "Windows" ) then 36 | return string.gsub( os.getenv( "APPDATA" ), "\\", "/" ) 37 | elseif ( ffi.os == "OSX" ) then 38 | return getUserDirectory() .. "/Library/Application Support" 39 | elseif ( ffi.os == "Linux" ) then 40 | local xdgdatahome = os.getenv( "XDG_DATA_HOME" ) 41 | if ( not xdgdatahome ) then 42 | return getUserDirectory() .. "/.local/share/" 43 | else 44 | return xdgdatahome 45 | end 46 | end 47 | return getUserDirectory() 48 | end 49 | 50 | function getDirectoryItems( dir ) 51 | local rc = physfs.PHYSFS_enumerateFiles( dir ) 52 | local i = 0 53 | local v = nil 54 | local t = {} 55 | repeat 56 | v = rc[ i ] 57 | if ( v ~= nil ) then 58 | table.insert( t, ffi.string( v ) ) 59 | end 60 | i = i + 1 61 | until ( v == nil ) 62 | physfs.PHYSFS_freeList( rc ) 63 | return t 64 | end 65 | 66 | function getLastModified( filename ) 67 | return physfs.PHYSFS_getLastModTime( filename ) 68 | end 69 | 70 | function getUserDirectory() 71 | return ffi.string( physfs.PHYSFS_getUserDir() ) 72 | end 73 | 74 | function getWorkingDirectory() 75 | return ffi.string( physfs.PHYSFS_getBaseDir() ) 76 | end 77 | 78 | function init( argv0 ) 79 | return physfs.PHYSFS_init( argv0 ) ~= 0 80 | end 81 | 82 | function isDirectory( filename ) 83 | return physfs.PHYSFS_isDirectory( filename ) ~= 0 84 | end 85 | 86 | function isFile( file ) 87 | return exists( file ) and not isDirectory( file ) 88 | end 89 | 90 | function lines( filename ) 91 | local buffer, length = read( filename ) 92 | if ( buffer == nil ) then 93 | error( length, 2 ) 94 | end 95 | local lines = string.split( buffer, "\r?\n" ) 96 | local i = 0 97 | return function() 98 | i = i + 1 99 | return lines[ i ] 100 | end 101 | end 102 | 103 | function loadFile( filename ) 104 | local buffer, length = read( filename ) 105 | if ( buffer == nil ) then 106 | error( length, 2 ) 107 | end 108 | return loadstring( buffer, filename ) 109 | end 110 | 111 | function mount( newDir, mountPoint, appendToPath ) 112 | appendToPath = appendToPath and 1 or 0 113 | return physfs.PHYSFS_mount( newDir, mountPoint, appendToPath ) ~= 0 114 | end 115 | 116 | function read( filename ) 117 | local file = physfs.PHYSFS_openRead( filename ) 118 | if ( file == nil ) then 119 | return nil, ffi.string( physfs.PHYSFS_getLastError() ) 120 | end 121 | local length = physfs.PHYSFS_fileLength( file ) 122 | local buffer = ffi.new( "char[?]", length ) 123 | physfs.PHYSFS_read( file, buffer, 1, length ) 124 | physfs.PHYSFS_close( file ) 125 | return ffi.string( buffer, length ), length 126 | end 127 | 128 | function write( filename, buffer, len ) 129 | local file = physfs.PHYSFS_openWrite( filename ) 130 | if ( file == nil ) then 131 | return false, ffi.string( physfs.PHYSFS_getLastError() ) 132 | end 133 | local bytes = physfs.PHYSFS_write( file, buffer, 1, len ) 134 | physfs.PHYSFS_close( file ) 135 | if ( bytes <= len ) then 136 | return false, ffi.string( physfs.PHYSFS_getLastError() ) 137 | end 138 | return true 139 | end 140 | -------------------------------------------------------------------------------- /lua/framework/graphics/cubemap.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local IL = require( "devil" ) 9 | local ffi = require( "ffi" ) 10 | local GL = require( "opengl" ) 11 | 12 | IL.ilInit() 13 | 14 | class( "framework.graphics.cubemap" ) 15 | 16 | local cubemap = framework.graphics.cubemap 17 | 18 | local faces = { 19 | right = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X, 20 | left = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 21 | top = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 22 | bottom = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 23 | front = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 24 | back = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 25 | } 26 | 27 | function cubemap:cubemap( type, filenames ) 28 | if ( type == "diffuse" ) then 29 | framework.graphics.setActiveTexture( 1 ) 30 | elseif ( type == "specular" ) then 31 | framework.graphics.setActiveTexture( 2 ) 32 | elseif ( type == "environment" ) then 33 | framework.graphics.setActiveTexture( 0 ) 34 | end 35 | 36 | self.images = ffi.new( "ILuint[?]", #filenames ) 37 | IL.ilGenImages( #filenames, self.images ) 38 | 39 | self.texture = ffi.new( "GLuint[1]" ) 40 | GL.glGenTextures( 1, self.texture ) 41 | GL.glBindTexture( GL.GL_TEXTURE_CUBE_MAP, self.texture[0] ) 42 | 43 | local mipmapLevels = #filenames / 6 44 | if ( mipmapLevels < 2 ) then 45 | GL.glTexParameteri( GL.GL_TEXTURE_CUBE_MAP, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR ) 46 | GL.glTexParameteri( GL.GL_TEXTURE_CUBE_MAP, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR ) 47 | else 48 | GL.glTexParameteri( GL.GL_TEXTURE_CUBE_MAP, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR ) 49 | GL.glTexParameteri( GL.GL_TEXTURE_CUBE_MAP, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR ) 50 | end 51 | 52 | self.pixels = {} 53 | 54 | for i, face in ipairs( filenames ) do 55 | IL.ilBindImage( self.images[i - 1] ) 56 | 57 | local target = face[ 1 ] 58 | local filename = face[ 2 ] 59 | local level = math.ceil( i / 6 ) - 1 60 | local buffer, length = framework.filesystem.read( filename ) 61 | if ( buffer == nil ) then 62 | error( length, 3 ) 63 | end 64 | IL.ilLoadL( IL.IL_TYPE_UNKNOWN, buffer, length ) 65 | IL.ilConvertImage( IL.IL_RGBA, IL.IL_UNSIGNED_BYTE ) 66 | local width = IL.ilGetInteger( IL.IL_IMAGE_WIDTH ) 67 | local height = IL.ilGetInteger( IL.IL_IMAGE_HEIGHT ) 68 | local pixels = IL.ilGetData() 69 | self.pixels[ i ] = pixels 70 | 71 | GL.glTexImage2D( 72 | faces[ target ], 73 | level, 74 | GL.GL_RGBA, 75 | width, 76 | height, 77 | 0, 78 | GL.GL_RGBA, 79 | GL.GL_UNSIGNED_BYTE, 80 | pixels 81 | ) 82 | end 83 | 84 | framework.graphics.setActiveTexture( 0 ) 85 | 86 | setproxy( self ) 87 | end 88 | 89 | function cubemap:__gc() 90 | GL.glDeleteTextures( 1, self.texture ) 91 | IL.ilDeleteImages( #self.pixels, self.images ) 92 | end 93 | -------------------------------------------------------------------------------- /lua/framework/graphics/font.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local FT = require( "freetype" ) 9 | local ffi = require( "ffi" ) 10 | local GL = require( "opengl" ) 11 | 12 | local ft = ffi.new( "FT_Library[1]" ) 13 | FT.FT_Init_FreeType( ft ) 14 | 15 | class( "framework.graphics.font" ) 16 | 17 | local font = framework.graphics.font 18 | 19 | function font:font( filename, size ) 20 | size = size or 16 21 | 22 | self.face = ffi.new( "FT_Face[1]" ) 23 | self.buffer, self.length = framework.filesystem.read( filename ) 24 | if ( self.buffer == nil ) then 25 | FT.FT_Done_Face( self.face ) 26 | error( self.length, 3 ) 27 | end 28 | FT.FT_New_Memory_Face( ft[0], self.buffer, self.length, 0, self.face ) 29 | 30 | self.size = size 31 | size = size * framework.window.getPixelScale() 32 | FT.FT_Set_Pixel_Sizes( self.face[0], 0, size ) 33 | 34 | self.texture = ffi.new( "GLuint[1]" ) 35 | GL.glGenTextures( 1, self.texture ) 36 | GL.glBindTexture( GL.GL_TEXTURE_2D, self.texture[0] ) 37 | 38 | GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_BASE_LEVEL, 0 ) 39 | GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAX_LEVEL, 0 ) 40 | local o = GL.GL_ONE 41 | local r = GL.GL_RED 42 | local mask = ffi.new( "GLint[4]", o, o, o, r ) 43 | GL.glTexParameteriv( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_SWIZZLE_RGBA, mask ) 44 | 45 | local s = self.face[0].size.metrics; 46 | self.advance = bit.rshift( tonumber( s.max_advance ), 6 ) 47 | self.ascent = bit.rshift( tonumber( s.ascender ), 6 ) 48 | self.descent = bit.rshift( tonumber( s.descender ), 6 ) 49 | self.height = bit.rshift( tonumber( s.height ), 6 ) 50 | 51 | setproxy( self ) 52 | end 53 | 54 | function font:getWidth( text ) 55 | local width = 0 56 | local face = self.face[0] 57 | for i = 1, #text do 58 | local char = string.sub( text, i, i ) 59 | if ( FT.FT_Load_Char( face, string.byte( char ), 4 ) == 0 ) then 60 | local g = face.glyph 61 | width = width + ( g.advance.x / 64 ) 62 | else 63 | error( "Could not load character '" .. char .. "'", 3 ) 64 | end 65 | end 66 | return tonumber( width ) 67 | end 68 | 69 | function font:getHeight() 70 | return math.floor( self.height / framework.window.getPixelScale() + 0.5 ) 71 | end 72 | 73 | function font:getWrap() 74 | -- TODO: Implement me. 75 | return 0, {} 76 | end 77 | 78 | function font:print( text, x, y, r, sx, sy, ox, oy, kx, ky ) 79 | local defaultVBO = framework.graphics._defaultVBO 80 | local shader = framework.graphics.getShader() 81 | local position = GL.glGetAttribLocation( shader, "position" ) 82 | local stride = 4 * ffi.sizeof( "GLfloat" ) 83 | local texcoord = GL.glGetAttribLocation( shader, "texcoord" ) 84 | local pointer = ffi.cast( "GLvoid *", 2 * ffi.sizeof( "GLfloat" ) ) 85 | GL.glBindBuffer( GL.GL_ARRAY_BUFFER, defaultVBO[0] ) 86 | GL.glVertexAttribPointer( position, 2, GL.GL_FLOAT, 0, stride, nil ) 87 | GL.glEnableVertexAttribArray( texcoord ) 88 | GL.glVertexAttribPointer( texcoord, 2, GL.GL_FLOAT, 0, stride, pointer ) 89 | framework.graphics.updateTransformations() 90 | 91 | GL.glBindTexture( GL.GL_TEXTURE_2D, self.texture[0] ) 92 | GL.glPixelStorei( GL.GL_UNPACK_ALIGNMENT, 1 ) 93 | 94 | local face = self.face[0] 95 | 96 | local _x = x 97 | for i = 1, #text do 98 | local char = string.sub( text, i, i ) 99 | if ( FT.FT_Load_Char( face, string.byte( char ), 4 ) == 0 ) then 100 | if ( char == "\n" ) then 101 | x = _x 102 | y = y + self:getHeight() 103 | else 104 | local g = face.glyph 105 | local gx = x + g.bitmap_left 106 | local gy = y + face.size.metrics.ascender / 64 - g.bitmap_top 107 | local width = g.bitmap.width 108 | local height = g.bitmap.rows 109 | local vertices = { 110 | -- vertex -- texcoord 111 | gx, gy + height, 0.0, 1.0, 112 | gx + width, gy + height, 1.0, 1.0, 113 | gx, gy, 0.0, 0.0, 114 | gx + width, gy + height, 1.0, 1.0, 115 | gx + width, gy, 1.0, 0.0, 116 | gx, gy, 0.0, 0.0 117 | } 118 | local pVertices = ffi.new( "GLfloat[?]", #vertices, vertices ) 119 | local size = ffi.sizeof( pVertices ) 120 | GL.glBufferData( 121 | GL.GL_ARRAY_BUFFER, 122 | size, 123 | pVertices, 124 | GL.GL_STREAM_DRAW 125 | ) 126 | GL.glTexImage2D( 127 | GL.GL_TEXTURE_2D, 128 | 0, 129 | GL.GL_RED, 130 | g.bitmap.width, 131 | g.bitmap.rows, 132 | 0, 133 | GL.GL_RED, 134 | GL.GL_UNSIGNED_BYTE, 135 | g.bitmap.buffer 136 | ) 137 | framework.graphics.drawArrays( GL.GL_TRIANGLES, 0, #vertices / 4 ) 138 | x = x + ( g.advance.x / 64 ) 139 | y = y + ( g.advance.y / 64 ) 140 | end 141 | else 142 | error( "Could not load character '" .. char .. "'", 3 ) 143 | end 144 | end 145 | 146 | GL.glPixelStorei( GL.GL_UNPACK_ALIGNMENT, 4 ) 147 | end 148 | 149 | function font:__gc() 150 | GL.glDeleteTextures( 1, self.texture ) 151 | FT.FT_Done_Face( self.face[0] ) 152 | end 153 | -------------------------------------------------------------------------------- /lua/framework/graphics/framebuffer.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | require( "framework.graphics.image" ) 9 | local GL = require( "opengl" ) 10 | local ffi = require( "ffi" ) 11 | local kazmath = require( "kazmath" ) 12 | 13 | local image = framework.graphics.image 14 | 15 | class( "framework.graphics.framebuffer" ) 16 | 17 | local framebuffer = framework.graphics.framebuffer 18 | 19 | function framebuffer:framebuffer( type, width, height ) 20 | local size = { framework.graphics.getSize() } 21 | width = width or size[ 1 ] 22 | height = height or size[ 2 ] 23 | 24 | local format = GL.GL_RGBA 25 | local dataType = GL.GL_UNSIGNED_BYTE 26 | local attachment = GL.GL_COLOR_ATTACHMENT0 27 | if ( type == "depth" ) then 28 | format = GL.GL_DEPTH_COMPONENT 29 | dataType = GL.GL_FLOAT 30 | attachment = GL.GL_DEPTH_ATTACHMENT 31 | end 32 | 33 | self.width = width 34 | self.height = height 35 | 36 | self.framebuffer = ffi.new( "GLuint[1]" ) 37 | GL.glGenFramebuffers( 1, self.framebuffer ) 38 | local framebuffer = framework.graphics.getFramebuffer() 39 | framework.graphics.setFramebuffer( self ) 40 | 41 | self.texture = ffi.new( "GLuint[1]" ) 42 | GL.glGenTextures( 1, self.texture ) 43 | GL.glBindTexture( GL.GL_TEXTURE_2D, self.texture[0] ) 44 | 45 | GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_BASE_LEVEL, 0 ) 46 | GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAX_LEVEL, 0 ) 47 | GL.glTexImage2D( 48 | GL.GL_TEXTURE_2D, 49 | 0, 50 | format, 51 | width, 52 | height, 53 | 0, 54 | format, 55 | dataType, 56 | nil 57 | ) 58 | 59 | if ( type == "depth" ) then 60 | GL.glDrawBuffer( GL.GL_NONE ) 61 | GL.glReadBuffer( GL.GL_NONE ) 62 | end 63 | 64 | GL.glFramebufferTexture2D( 65 | GL.GL_FRAMEBUFFER, 66 | attachment, 67 | GL.GL_TEXTURE_2D, 68 | self.texture[0], 69 | 0 70 | ) 71 | 72 | framework.graphics.clear() 73 | framework.graphics.setFramebuffer( framebuffer ) 74 | 75 | setproxy( self ) 76 | end 77 | 78 | function framebuffer:draw( x, y, r, sx, sy, ox, oy, kx, ky ) 79 | image.draw( self, x, y, r, sx, sy, ox, oy, kx, ky ) 80 | end 81 | 82 | function framebuffer:renderTo( func ) 83 | end 84 | 85 | function framebuffer:setFilter( min, mag ) 86 | -- TODO: Implement me. 87 | end 88 | 89 | function framebuffer:__gc() 90 | GL.glDeleteTextures( 1, self.texture ) 91 | GL.glDeleteFramebuffers( 1, self.framebuffer ) 92 | end 93 | -------------------------------------------------------------------------------- /lua/framework/graphics/image.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local IL = require( "devil" ) 9 | local ffi = require( "ffi" ) 10 | local GL = require( "opengl" ) 11 | 12 | IL.ilInit() 13 | 14 | class( "framework.graphics.image" ) 15 | 16 | local image = framework.graphics.image 17 | 18 | function image:image( filename, params ) 19 | self.image = ffi.new( "ILuint[1]" ) 20 | IL.ilGenImages( 1, self.image ) 21 | IL.ilBindImage( self.image[0] ) 22 | 23 | self.texture = ffi.new( "GLuint[1]" ) 24 | GL.glGenTextures( 1, self.texture ) 25 | GL.glBindTexture( GL.GL_TEXTURE_2D, self.texture[0] ) 26 | 27 | local buffer, length = framework.filesystem.read( filename ) 28 | if ( buffer == nil ) then 29 | error( length, 3 ) 30 | end 31 | IL.ilLoadL( IL.IL_TYPE_UNKNOWN, buffer, length ) 32 | IL.ilConvertImage( IL.IL_RGBA, IL.IL_UNSIGNED_BYTE ) 33 | local width = IL.ilGetInteger( IL.IL_IMAGE_WIDTH ) 34 | local height = IL.ilGetInteger( IL.IL_IMAGE_HEIGHT ) 35 | local pixels = IL.ilGetData() 36 | self.width = width 37 | self.height = height 38 | self.pixels = pixels 39 | 40 | GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_BASE_LEVEL, 0 ) 41 | GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAX_LEVEL, 0 ) 42 | 43 | if ( params ) then 44 | for i, v in ipairs( params ) do 45 | GL.glTexParameteri( GL.GL_TEXTURE_2D, v[ 1 ], v[ 2 ] ) 46 | end 47 | end 48 | 49 | GL.glTexImage2D( 50 | GL.GL_TEXTURE_2D, 51 | 0, 52 | GL.GL_RGBA, 53 | width, 54 | height, 55 | 0, 56 | GL.GL_RGBA, 57 | GL.GL_UNSIGNED_BYTE, 58 | pixels 59 | ) 60 | 61 | setproxy( self ) 62 | end 63 | 64 | function image:draw( x, y, r, sx, sy, ox, oy, kx, ky ) 65 | local defaultVBO = framework.graphics._defaultVBO 66 | local width = self.width 67 | local height = self.height 68 | local vertices = { 69 | -- position -- texcoord 70 | x, y + height, 0.0, 1.0, 71 | x + width, y + height, 1.0, 1.0, 72 | x, y, 0.0, 0.0, 73 | x + width, y + height, 1.0, 1.0, 74 | x + width, y, 1.0, 0.0, 75 | x, y, 0.0, 0.0 76 | } 77 | local pVertices = ffi.new( "GLfloat[?]", #vertices, vertices ) 78 | local size = ffi.sizeof( pVertices ) 79 | local shader = framework.graphics.getShader() 80 | local position = GL.glGetAttribLocation( shader, "position" ) 81 | local stride = 4 * ffi.sizeof( "GLfloat" ) 82 | local texcoord = GL.glGetAttribLocation( shader, "texcoord" ) 83 | local pointer = ffi.cast( "GLvoid *", 2 * ffi.sizeof( "GLfloat" ) ) 84 | GL.glBindBuffer( GL.GL_ARRAY_BUFFER, defaultVBO[0] ) 85 | GL.glBufferData( GL.GL_ARRAY_BUFFER, size, pVertices, GL.GL_STREAM_DRAW ) 86 | GL.glVertexAttribPointer( position, 2, GL.GL_FLOAT, 0, stride, nil ) 87 | GL.glEnableVertexAttribArray( texcoord ) 88 | GL.glVertexAttribPointer( texcoord, 2, GL.GL_FLOAT, 0, stride, pointer ) 89 | framework.graphics.updateTransformations() 90 | GL.glBindTexture( GL.GL_TEXTURE_2D, self.texture[0] ) 91 | framework.graphics.drawArrays( GL.GL_TRIANGLES, 0, #vertices / 4 ) 92 | end 93 | 94 | function image:getWidth() 95 | return self.width 96 | end 97 | 98 | function image:getHeight() 99 | return self.height 100 | end 101 | 102 | function image:setFilter( min, mag ) 103 | -- TODO: Implement me. 104 | end 105 | 106 | function image:__gc() 107 | GL.glDeleteTextures( 1, self.texture ) 108 | IL.ilDeleteImages( 1, self.image ) 109 | end 110 | -------------------------------------------------------------------------------- /lua/framework/graphics/init.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "framework.graphics.opengl" ) 8 | require( "framework.graphics.primitive" ) 9 | require( "framework.graphics.shader" ) 10 | require( "framework.graphics.transformation" ) 11 | local GL = require( "opengl" ) 12 | local ffi = require( "ffi" ) 13 | local SDL = require( "sdl" ) 14 | local kazmath = require( "kazmath" ) 15 | local bit = require( "bit" ) 16 | 17 | local unpack = unpack 18 | local framework = framework 19 | local require = require 20 | local tostring = tostring 21 | 22 | module( "framework.graphics" ) 23 | 24 | _backgroundColor = _backgroundColor or { 0, 0, 0, 0 } 25 | 26 | _viewport = _viewport or { 27 | x = 0, 28 | y = 0, 29 | width = 800, 30 | height = 600 31 | } 32 | 33 | function draw( drawable, x, y, r, sx, sy, ox, oy, kx, ky ) 34 | x = x or 0 35 | y = y or 0 36 | r = r or 0 37 | sx = sx or 1 38 | sy = sy or sx 39 | ox = ox or 0 40 | oy = oy or 0 41 | kx = kx or 0 42 | ky = ky or 0 43 | drawable:draw( x, y, r, sx, sy, ox, oy, kx, ky ) 44 | end 45 | 46 | function getBackgroundColor() 47 | return unpack( _backgroundColor ) 48 | end 49 | 50 | function getFont() 51 | return _font 52 | end 53 | 54 | function getFramebuffer() 55 | return _framebuffer 56 | end 57 | 58 | function getPolygonMode() 59 | local mode = ffi.new( "GLint[1]" ) 60 | GL.glGetIntegerv( GL.GL_POLYGON_MODE, mode ) 61 | if ( mode[0] == GL.GL_LINE ) then 62 | return "line" 63 | elseif( mode[0] == GL.GL_FILL ) then 64 | return "fill" 65 | end 66 | end 67 | 68 | function getSize() 69 | local width = ffi.new( "int[1]" ) 70 | local height = ffi.new( "int[1]" ) 71 | SDL.SDL_GL_GetDrawableSize( framework.window._window, width, height ) 72 | return width[0], height[0] 73 | end 74 | 75 | function newCubemap( type, filenames ) 76 | require( "framework.graphics.cubemap" ) 77 | local cubemap = framework.graphics.cubemap 78 | return cubemap( type, filenames ) 79 | end 80 | 81 | function newFont( filename, size ) 82 | require( "framework.graphics.font" ) 83 | local font = framework.graphics.font 84 | return font( filename, size ) 85 | end 86 | 87 | function newFramebuffer( type, width, height ) 88 | require( "framework.graphics.framebuffer" ) 89 | local framebuffer = framework.graphics.framebuffer 90 | return framebuffer( type, width, height ) 91 | end 92 | 93 | function newImage( filename, params ) 94 | require( "framework.graphics.image" ) 95 | local image = framework.graphics.image 96 | return image( filename, params ) 97 | end 98 | 99 | function newModel( filename ) 100 | require( "framework.graphics.model" ) 101 | local model = framework.graphics.model 102 | return model( filename ) 103 | end 104 | 105 | function newText( font, textstring ) 106 | require( "framework.graphics.text" ) 107 | local text = framework.graphics.text 108 | return text( font, textstring ) 109 | end 110 | 111 | function newQuad( x, y, width, height, sw, sh ) 112 | require( "framework.graphics.quad" ) 113 | return quad( x, y, width, height, sw, sh ) 114 | end 115 | 116 | function newSpriteBatch( image, maxSprites ) 117 | require( "framework.graphics.spritebatch" ) 118 | local spritebatch = framework.graphics.spritebatch 119 | return spritebatch( image, maxSprites ) 120 | end 121 | 122 | function print( text, x, y, r, sx, sy, ox, oy, kx, ky ) 123 | text = tostring( text ) 124 | x = x or 0 125 | y = y or 0 126 | local font = getFont() 127 | font:print( text, x, y, r, sx, sy, ox, oy, kx, ky ) 128 | end 129 | 130 | function setBackgroundColor( color ) 131 | _backgroundColor[ 1 ] = color[ 1 ] 132 | _backgroundColor[ 2 ] = color[ 2 ] 133 | _backgroundColor[ 3 ] = color[ 3 ] 134 | _backgroundColor[ 4 ] = color[ 4 ] 135 | end 136 | 137 | function setFont( font ) 138 | _font = font 139 | end 140 | 141 | function setFramebuffer( framebuffer ) 142 | if ( framebuffer ) then 143 | GL.glBindFramebuffer( GL.GL_FRAMEBUFFER, framebuffer.framebuffer[0] ) 144 | local mode = framework.graphics.getMatrixMode() 145 | framework.graphics.setMatrixMode( "projection" ) 146 | local mat4 = framework.graphics.getTransformation() 147 | local width = framebuffer.width 148 | local height = framebuffer.height 149 | kazmath.kmMat4OrthographicProjection( 150 | mat4, 0, width, 0, height, -1.0, 1.0 151 | ) 152 | framework.graphics.setMatrixMode( mode ) 153 | framework.graphics.updateTransformations() 154 | 155 | local dpiScale = framework.window.getPixelScale() 156 | setViewport( 0, 0, width * dpiScale, height * dpiScale ) 157 | else 158 | GL.glBindFramebuffer( GL.GL_FRAMEBUFFER, 0 ) 159 | framework.graphics.setOrthographicProjection( width, height ) 160 | 161 | local width, height = getSize() 162 | setViewport( 0, 0, width, height ) 163 | end 164 | 165 | _framebuffer = framebuffer 166 | end 167 | 168 | function setPolygonMode( mode ) 169 | if ( mode == "line" ) then 170 | mode = GL.GL_LINE 171 | elseif ( mode == "fill" ) then 172 | mode = GL.GL_FILL 173 | end 174 | GL.glPolygonMode( GL.GL_FRONT_AND_BACK, mode ) 175 | end 176 | 177 | function setScissor( x, y, width, height ) 178 | if ( _framebuffer ~= nil ) then 179 | GL.glScissor( x, y, width, height ) 180 | else 181 | GL.glScissor( x, _viewport.height - ( y + height ), width, height ) 182 | end 183 | end 184 | 185 | function setViewport( x, y, width, height ) 186 | GL.glViewport( x, y, width, height ) 187 | _viewport.x = x 188 | _viewport.y = y 189 | _viewport.width = width 190 | _viewport.height = height 191 | end 192 | 193 | function setVSync( vsync ) 194 | SDL.SDL_GL_SetSwapInterval( vsync and 1 or 0 ) 195 | end 196 | 197 | function clear( r, g, b, a ) 198 | r = r or 0 199 | g = g or 0 200 | b = b or 0 201 | a = a or 0 202 | GL.glClearColor( r, g, b, a ) 203 | GL.glClear( bit.bor( GL.GL_COLOR_BUFFER_BIT, GL.GL_DEPTH_BUFFER_BIT ) ) 204 | end 205 | -------------------------------------------------------------------------------- /lua/framework/graphics/mesh.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local GL = require( "opengl" ) 9 | local ffi = require( "ffi" ) 10 | local kazmath = require( "kazmath" ) 11 | 12 | class( "framework.graphics.mesh" ) 13 | 14 | local mesh = framework.graphics.mesh 15 | 16 | function mesh:mesh( vertices, count, textures, transformation ) 17 | self.vbo = ffi.new( "GLuint[1]" ) 18 | GL.glGenBuffers( 1, self.vbo ) 19 | GL.glBindBuffer( GL.GL_ARRAY_BUFFER, self.vbo[0] ) 20 | 21 | local size = ffi.sizeof( vertices ) 22 | GL.glBufferData( GL.GL_ARRAY_BUFFER, size, vertices, GL.GL_STATIC_DRAW ) 23 | self.vertices = vertices 24 | self.count = count 25 | 26 | for type, filename in pairs( textures ) do 27 | textures[ type ] = framework.graphics.newImage( filename ) 28 | end 29 | self.textures = textures 30 | 31 | transformation = ffi.new( "kmMat4", transformation ) 32 | self.transformation = ffi.new( "kmMat4" ) 33 | kazmath.kmMat4Transpose( self.transformation, transformation ) 34 | 35 | setproxy( self ) 36 | end 37 | 38 | local textureUnits = { 39 | environmentEnvSampler = 0, 40 | diffuseEnvSampler = 1, 41 | specularEnvSampler = 2, 42 | diffuse = 3, 43 | metallicRoughness = 4, 44 | normals = 5, 45 | brdfLUT = 6, 46 | emissive = 7, 47 | lightmap = 8 48 | } 49 | 50 | function mesh:draw( x, y, r, sx, sy, ox, oy, kx, ky ) 51 | local shader = framework.graphics.getShader() 52 | local position = GL.glGetAttribLocation( shader, "position" ) 53 | local stride = ( 3 + 3 + 3 + 3 + 2 ) * ffi.sizeof( "GLfloat" ) 54 | local pointer = ffi.cast( "GLvoid *", 3 * ffi.sizeof( "GLfloat" ) ) 55 | local normal = GL.glGetAttribLocation( shader, "normal" ) 56 | local tangent = GL.glGetAttribLocation( shader, "tangent" ) 57 | local bitangent = GL.glGetAttribLocation( shader, "bitangent" ) 58 | local texcoord = GL.glGetAttribLocation( shader, "texcoord" ) 59 | GL.glBindBuffer( GL.GL_ARRAY_BUFFER, self.vbo[0] ) 60 | GL.glVertexAttribPointer( position, 3, GL.GL_FLOAT, 0, stride, nil ) 61 | GL.glVertexAttribPointer( normal, 3, GL.GL_FLOAT, 0, stride, pointer ) 62 | pointer = ffi.cast( "GLvoid *", ( 3 + 3 ) * ffi.sizeof( "GLfloat" ) ) 63 | GL.glVertexAttribPointer( tangent, 3, GL.GL_FLOAT, 0, stride, pointer ) 64 | pointer = ffi.cast( "GLvoid *", ( 3 + 3 + 3 ) * ffi.sizeof( "GLfloat" ) ) 65 | GL.glVertexAttribPointer( bitangent, 2, GL.GL_FLOAT, 0, stride, pointer ) 66 | pointer = ffi.cast( "GLvoid *", ( 3 + 3 + 3 + 3 ) * ffi.sizeof( "GLfloat" ) ) 67 | GL.glVertexAttribPointer( texcoord, 2, GL.GL_FLOAT, 0, stride, pointer ) 68 | framework.graphics.updateTransformations() 69 | for type, image in pairs( self.textures ) do 70 | local textureUnit = textureUnits[ type ] 71 | if ( textureUnit ) then 72 | framework.graphics.setActiveTexture( textureUnit ) 73 | GL.glBindTexture( GL.GL_TEXTURE_2D, image.texture[0] ) 74 | end 75 | end 76 | framework.graphics.setActiveTexture( 0 ) 77 | framework.graphics.drawArrays( GL.GL_TRIANGLES, 0, self.count ) 78 | end 79 | 80 | function mesh:__gc() 81 | GL.glDeleteBuffers( 1, self.vbo ) 82 | end 83 | -------------------------------------------------------------------------------- /lua/framework/graphics/opengl.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | local GL = require( "opengl" ) 9 | 10 | module( "framework.graphics" ) 11 | 12 | _drawCalls = _drawCalls or 0 13 | 14 | function createDefaultVAO() 15 | _defaultVAO = ffi.new( "GLuint[1]" ) 16 | GL.glGenVertexArrays( 1, _defaultVAO ) 17 | GL.glBindVertexArray( _defaultVAO[0] ) 18 | end 19 | 20 | function createDefaultVBO() 21 | _defaultVBO = ffi.new( "GLuint[1]" ) 22 | GL.glGenBuffers( 1, _defaultVBO ) 23 | GL.glBindBuffer( GL.GL_ARRAY_BUFFER, _defaultVBO[0] ) 24 | end 25 | 26 | function drawArrays( mode, first, count ) 27 | GL.glDrawArrays( mode, first, count ) 28 | _drawCalls = _drawCalls + 1 29 | end 30 | 31 | function getDrawCalls() 32 | return _drawCalls 33 | end 34 | 35 | function getOpenGLVersion() 36 | local version = ffi.new( "GLint[2]" ) 37 | GL.glGetIntegerv( GL.GL_MAJOR_VERSION, version ) 38 | GL.glGetIntegerv( GL.GL_MINOR_VERSION, version + 1 ) 39 | return version[0] + version[1] / 10 40 | end 41 | -------------------------------------------------------------------------------- /lua/framework/graphics/primitive.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local GL = require( "opengl" ) 8 | local ffi = require( "ffi" ) 9 | local math = math 10 | 11 | local framework = framework 12 | 13 | module( "framework.graphics" ) 14 | 15 | function line( ... ) 16 | local vertices = { ... } 17 | local defaultVBO = framework.graphics._defaultVBO 18 | local pVertices = ffi.new( "GLfloat[?]", #vertices, vertices ) 19 | local size = ffi.sizeof( pVertices ) 20 | local shader = framework.graphics.getShader() 21 | local position = GL.glGetAttribLocation( shader, "position" ) 22 | local texcoord = GL.glGetAttribLocation( shader, "texcoord" ) 23 | local defaultTexture = framework.graphics.getDefaultTexture() 24 | GL.glBindBuffer( GL.GL_ARRAY_BUFFER, defaultVBO[0] ) 25 | GL.glBufferData( GL.GL_ARRAY_BUFFER, size, pVertices, GL.GL_STREAM_DRAW ) 26 | GL.glVertexAttribPointer( position, 2, GL.GL_FLOAT, 0, 0, nil ) 27 | GL.glDisableVertexAttribArray( texcoord ) 28 | framework.graphics.updateTransformations() 29 | GL.glBindTexture( GL.GL_TEXTURE_2D, defaultTexture[0] ) 30 | framework.graphics.drawArrays( GL.GL_LINES, 0, #vertices / 2 ) 31 | end 32 | 33 | function polygon( mode, vertices ) 34 | if ( mode == "line" ) then 35 | mode = GL.GL_LINE_LOOP 36 | elseif ( mode == "fill" ) then 37 | mode = GL.GL_TRIANGLES 38 | end 39 | local defaultVBO = framework.graphics._defaultVBO 40 | local pVertices = ffi.new( "GLfloat[?]", #vertices, vertices ) 41 | local size = ffi.sizeof( pVertices ) 42 | local shader = framework.graphics.getShader() 43 | local position = GL.glGetAttribLocation( shader, "position" ) 44 | local texcoord = GL.glGetAttribLocation( shader, "texcoord" ) 45 | local defaultTexture = framework.graphics.getDefaultTexture() 46 | GL.glBindBuffer( GL.GL_ARRAY_BUFFER, defaultVBO[0] ) 47 | GL.glBufferData( GL.GL_ARRAY_BUFFER, size, pVertices, GL.GL_STREAM_DRAW ) 48 | GL.glVertexAttribPointer( position, 2, GL.GL_FLOAT, 0, 0, nil ) 49 | GL.glDisableVertexAttribArray( texcoord ) 50 | framework.graphics.updateTransformations() 51 | GL.glBindTexture( GL.GL_TEXTURE_2D, defaultTexture[0] ) 52 | framework.graphics.drawArrays( mode, 0, #vertices / 2 ) 53 | end 54 | 55 | local function roundedRectangle( mode, x, y, width, height, r ) 56 | local segments = math.floor( r * math.pi * 2 / 4 ) 57 | local vertices = { 58 | x + width / 2, 59 | y + height / 2 60 | } 61 | local angleDelta = 1 / segments * math.pi / 2 62 | local cornerVertices = { 63 | x + width - r, y + height - r, 64 | x + r, y + height - r, 65 | x + r, y + r, 66 | x + width - r, y + r 67 | } 68 | for corner = 0, 3 do 69 | local angle = corner * math.pi / 2 70 | local cornerCenterX = cornerVertices[ corner * 2 + 1 ] 71 | local cornerCenterY = cornerVertices[ corner * 2 + 2 ] 72 | for i = 1, segments do 73 | vertices[ #vertices+1 ] = cornerCenterX + math.cos( angle ) * r 74 | vertices[ #vertices+1 ] = cornerCenterY + math.sin( angle ) * r 75 | angle = angle + angleDelta 76 | end 77 | end 78 | vertices[ #vertices+1 ] = x + width 79 | vertices[ #vertices+1 ] = y + height - r 80 | mode = mode == "fill" and GL.GL_TRIANGLE_FAN or mode 81 | polygon( mode, vertices ) 82 | end 83 | 84 | function rectangle( mode, x, y, width, height, r ) 85 | if ( r and r > 0 ) then 86 | roundedRectangle( mode, x, y, width, height, r ) 87 | return 88 | end 89 | local vertices = { 90 | x, y + height, 91 | x + width, y + height, 92 | x, y, 93 | x + width, y + height, 94 | x + width, y, 95 | x, y 96 | } 97 | if ( mode == "line" ) then 98 | vertices = { 99 | x, y + height, 100 | x + width, y + height, 101 | x + width, y, 102 | x, y, 103 | } 104 | end 105 | polygon( mode, vertices ) 106 | end 107 | 108 | function skybox( cubemap ) 109 | local vertices = { 110 | -1.0, 1.0, -1.0, 111 | -1.0, -1.0, -1.0, 112 | 1.0, -1.0, -1.0, 113 | 1.0, -1.0, -1.0, 114 | 1.0, 1.0, -1.0, 115 | -1.0, 1.0, -1.0, 116 | 117 | -1.0, -1.0, 1.0, 118 | -1.0, -1.0, -1.0, 119 | -1.0, 1.0, -1.0, 120 | -1.0, 1.0, -1.0, 121 | -1.0, 1.0, 1.0, 122 | -1.0, -1.0, 1.0, 123 | 124 | 1.0, -1.0, -1.0, 125 | 1.0, -1.0, 1.0, 126 | 1.0, 1.0, 1.0, 127 | 1.0, 1.0, 1.0, 128 | 1.0, 1.0, -1.0, 129 | 1.0, -1.0, -1.0, 130 | 131 | -1.0, -1.0, 1.0, 132 | -1.0, 1.0, 1.0, 133 | 1.0, 1.0, 1.0, 134 | 1.0, 1.0, 1.0, 135 | 1.0, -1.0, 1.0, 136 | -1.0, -1.0, 1.0, 137 | 138 | -1.0, 1.0, -1.0, 139 | 1.0, 1.0, -1.0, 140 | 1.0, 1.0, 1.0, 141 | 1.0, 1.0, 1.0, 142 | -1.0, 1.0, 1.0, 143 | -1.0, 1.0, -1.0, 144 | 145 | -1.0, -1.0, -1.0, 146 | -1.0, -1.0, 1.0, 147 | 1.0, -1.0, -1.0, 148 | 1.0, -1.0, -1.0, 149 | -1.0, -1.0, 1.0, 150 | 1.0, -1.0, 1.0 151 | } 152 | local defaultVBO = framework.graphics._defaultVBO 153 | local pVertices = ffi.new( "GLfloat[?]", #vertices, vertices ) 154 | local size = ffi.sizeof( pVertices ) 155 | local shader = framework.graphics.getShader() 156 | local position = GL.glGetAttribLocation( shader, "position" ) 157 | local defaultTexture = framework.graphics.getDefaultTexture() 158 | GL.glBindBuffer( GL.GL_ARRAY_BUFFER, defaultVBO[0] ) 159 | GL.glBufferData( GL.GL_ARRAY_BUFFER, size, pVertices, GL.GL_STREAM_DRAW ) 160 | GL.glVertexAttribPointer( position, 3, GL.GL_FLOAT, 0, 0, nil ) 161 | framework.graphics.updateTransformations() 162 | GL.glBindTexture( GL.GL_TEXTURE_CUBE_MAP, cubemap.texture[0] ) 163 | GL.glDepthMask( GL.GL_FALSE ) 164 | framework.graphics.drawArrays( GL.GL_TRIANGLES, 0, #vertices / 3 ) 165 | GL.glDepthMask( GL.GL_TRUE ) 166 | end 167 | 168 | function setLineStyle( style ) 169 | if ( style == "smooth" ) then 170 | GL.glEnable( GL.GL_LINE_SMOOTH ) 171 | else 172 | GL.glDisable( GL.GL_LINE_SMOOTH ) 173 | end 174 | end 175 | 176 | function setLineWidth( width ) 177 | GL.glLineWidth( width ) 178 | _lineWidth = width 179 | end 180 | 181 | function getLineWidth() 182 | return _lineWidth 183 | end 184 | -------------------------------------------------------------------------------- /lua/framework/graphics/quad.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | 9 | class( "framework.graphics.quad" ) 10 | 11 | local quad = framework.graphics.quad 12 | 13 | function quad:quad( x, y, width, height, sw, sh ) 14 | self.x = x 15 | self.y = y 16 | self.width = width 17 | self.height = height 18 | self.sw = sw 19 | self.sh = sh 20 | end 21 | 22 | function quad:setViewport( x, y, width, height ) 23 | self.x = x 24 | self.y = y 25 | self.width = width 26 | self.height = height 27 | end 28 | -------------------------------------------------------------------------------- /lua/framework/graphics/shader.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local GL = require( "opengl" ) 8 | local ffi = require( "ffi" ) 9 | local kazmath = require( "kazmath" ) 10 | 11 | local error = error 12 | local type = type 13 | local framework = framework 14 | 15 | module( "framework.graphics" ) 16 | 17 | _shaders = _shaders or {} 18 | _shaders.loaded = _shaders.loaded or {} 19 | 20 | local function getShaderCompileStatus( shader ) 21 | local status = ffi.new( "GLint[1]" ) 22 | GL.glGetShaderiv( shader, GL.GL_COMPILE_STATUS, status ) 23 | if ( status[0] ~= GL.GL_FALSE ) then 24 | return 25 | end 26 | 27 | local length = ffi.new( "GLint[1]" ) 28 | GL.glGetShaderiv( shader, GL.GL_INFO_LOG_LENGTH, length ) 29 | local buffer = ffi.new( "char[?]", length[0] ) 30 | GL.glGetShaderInfoLog( shader, length[0], nil, buffer ) 31 | GL.glDeleteShader( shader ) 32 | error( ffi.string( buffer, length[0] ), 4 ) 33 | end 34 | 35 | local function createShader( type, source ) 36 | local shader = GL.glCreateShader( type ) 37 | source = ffi.new( "char[?]", #source, source ) 38 | local string = ffi.new( "const char *[1]", source ) 39 | GL.glShaderSource( shader, 1, string, nil ) 40 | GL.glCompileShader( shader ) 41 | 42 | getShaderCompileStatus( shader ) 43 | return shader 44 | end 45 | 46 | function newShader( fragSource, vertSource ) 47 | local fragShader = createShader( GL.GL_FRAGMENT_SHADER, fragSource ) 48 | local vertShader = createShader( GL.GL_VERTEX_SHADER, vertSource ) 49 | local shaderProgram = GL.glCreateProgram() 50 | GL.glAttachShader( shaderProgram, vertShader ) 51 | GL.glAttachShader( shaderProgram, fragShader ) 52 | return shaderProgram 53 | end 54 | 55 | function linkShader( shader ) 56 | GL.glLinkProgram( shader ) 57 | end 58 | 59 | function setShader( shader ) 60 | if ( type( shader ) == "string" ) then 61 | if ( not _shaders.loaded[ shader ] ) then 62 | local dir = "lua/framework/graphics/shaders/" 63 | local filename = dir .. shader .. ".lua" 64 | _shaders.loaded[ shader ] = framework.filesystem.doFile( filename )() 65 | end 66 | shader = _shaders.loaded[ shader ] 67 | end 68 | 69 | GL.glUseProgram( shader ) 70 | _shader = shader 71 | end 72 | 73 | function getShader() 74 | return _shader 75 | end 76 | 77 | function setActiveTexture( texture ) 78 | GL.glActiveTexture( GL[ "GL_TEXTURE" .. texture ] ) 79 | end 80 | 81 | function getActiveTexture() 82 | local texture = ffi.new( "GLint[1]" ) 83 | GL.glGetIntegerv( GL.GL_ACTIVE_TEXTURE, texture ) 84 | return texture[0] 85 | end 86 | 87 | function setDefaultTexture() 88 | _defaultTexture = ffi.new( "GLuint[1]" ) 89 | GL.glGenTextures( 1, _defaultTexture ) 90 | GL.glBindTexture( GL.GL_TEXTURE_2D, _defaultTexture[0] ) 91 | 92 | local pixels = ffi.new( "GLfloat[4]", 1.0, 1.0, 1.0, 1.0 ) 93 | GL.glTexImage2D( 94 | GL.GL_TEXTURE_2D, 95 | 0, 96 | GL.GL_RGBA, 97 | 1, 98 | 1, 99 | 0, 100 | GL.GL_RGBA, 101 | GL.GL_FLOAT, 102 | pixels 103 | ) 104 | end 105 | 106 | function getDefaultTexture() 107 | return _defaultTexture 108 | end 109 | 110 | function setColor( color ) 111 | local pColor = ffi.new( "GLfloat[4]", 112 | ( color[ 1 ] or 0 ), 113 | ( color[ 2 ] or 0 ), 114 | ( color[ 3 ] or 0 ), 115 | ( color[ 4 ] or 0 ) 116 | ) 117 | local index = GL.glGetUniformLocation( getShader(), "color" ) 118 | GL.glUniform4fv( index, 1, pColor ) 119 | _color = color 120 | end 121 | 122 | function getColor() 123 | return _color 124 | end 125 | 126 | function setLightDirection( direction ) 127 | local pDirection = ffi.new( "GLfloat[3]", direction ) 128 | local index = GL.glGetUniformLocation( getShader(), "u_LightDirection" ) 129 | GL.glUniform3fv( index, 1, pDirection ) 130 | _lightDirection = direction 131 | end 132 | 133 | function getLightDirection() 134 | return _lightDirection 135 | end 136 | 137 | function setLightColor( color ) 138 | local pColor = ffi.new( "GLfloat[3]", 139 | ( color[ 1 ] or 0 ), 140 | ( color[ 2 ] or 0 ), 141 | ( color[ 3 ] or 0 ) 142 | ) 143 | local index = GL.glGetUniformLocation( getShader(), "u_LightColor" ) 144 | GL.glUniform3fv( index, 1, pColor ) 145 | _lightColor = color 146 | end 147 | 148 | function getLightColor() 149 | return _lightColor 150 | end 151 | 152 | function setBrdfLUT( filename ) 153 | _brdfLUT = framework.graphics.newImage( filename, { 154 | { GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE }, 155 | { GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE } 156 | } ) 157 | setActiveTexture( 6 ) 158 | GL.glBindTexture( GL.GL_TEXTURE_2D, _brdfLUT.texture[0] ) 159 | setActiveTexture( 0 ) 160 | end 161 | 162 | function getBrdfLUT() 163 | return _brdfLUT 164 | end 165 | 166 | function setNormalScale( normalScale ) 167 | local pNormalScale = ffi.new( "GLfloat[1]", normalScale ) 168 | local index = GL.glGetUniformLocation( getShader(), "u_NormalScale" ) 169 | GL.glUniform1fv( index, 1, pNormalScale ) 170 | _normalScale = normalScale 171 | end 172 | 173 | function getNormalScale() 174 | return _normalScale 175 | end 176 | 177 | function setEmissiveFactor( emissiveFactor ) 178 | local pEmissiveFactor = ffi.new( "GLfloat[3]", emissiveFactor ) 179 | local index = GL.glGetUniformLocation( getShader(), "u_EmissiveFactor" ) 180 | GL.glUniform3fv( index, 1, pEmissiveFactor ) 181 | _emissiveFactor = emissiveFactor 182 | end 183 | 184 | function getEmissiveFactor() 185 | return _emissiveFactor 186 | end 187 | 188 | function setOcclusionStrength( occlusionStrength ) 189 | local pOcclusionStrength = ffi.new( "GLfloat[1]", occlusionStrength ) 190 | local index = GL.glGetUniformLocation( getShader(), "u_OcclusionStrength" ) 191 | GL.glUniform1fv( index, 1, pOcclusionStrength ) 192 | _occlusionStrength = occlusionStrength 193 | end 194 | 195 | function getOcclusionStrength() 196 | return _occlusionStrength 197 | end 198 | 199 | function setMetallicRoughnessValues( metallicRoughnessValues ) 200 | local pMetallicRoughnessValues = ffi.new( "GLfloat[2]", 201 | ( metallicRoughnessValues[ 1 ] or 1 ), 202 | ( metallicRoughnessValues[ 2 ] or 1 ) 203 | ) 204 | local index = GL.glGetUniformLocation( 205 | getShader(), "u_MetallicRoughnessValues" 206 | ) 207 | GL.glUniform2fv( index, 1, pMetallicRoughnessValues ) 208 | _metallicRoughnessValues = metallicRoughnessValues 209 | end 210 | 211 | function getMetallicRoughnessValues() 212 | return _metallicRoughnessValues 213 | end 214 | 215 | function setCameraPosition( cameraPosition ) 216 | local pCamera = ffi.new( "GLfloat[3]", cameraPosition ) 217 | local index = GL.glGetUniformLocation( getShader(), "u_Camera" ) 218 | GL.glUniform3fv( index, 1, pCamera ) 219 | _cameraPosition = cameraPosition 220 | end 221 | 222 | function getCameraPosition() 223 | return _cameraPosition 224 | end 225 | -------------------------------------------------------------------------------- /lua/framework/graphics/shaders/default2d.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local GL = require( "opengl" ) 8 | local ffi = require( "ffi" ) 9 | local kazmath = require( "kazmath" ) 10 | 11 | return function() 12 | -- shader 13 | local fragSource = framework.filesystem.read( "shaders/default.frag" ) 14 | local vertSource = framework.filesystem.read( "shaders/default2d.vert" ) 15 | local shader = framework.graphics.newShader( fragSource, vertSource ) 16 | GL.glBindFragDataLocation( shader, 0, "FragColor" ) 17 | framework.graphics.linkShader( shader ) 18 | framework.graphics.setShader( shader ) 19 | 20 | -- default.frag 21 | -- uniforms 22 | -- tex 23 | framework.graphics.setDefaultTexture() 24 | 25 | -- color 26 | framework.graphics.setColor( { 1, 1, 1, 1 } ) 27 | 28 | -- default2d.vert 29 | -- attribs 30 | -- position 31 | local position = GL.glGetAttribLocation( shader, "position" ) 32 | local stride = ( 2 + 2 ) * ffi.sizeof( "GLfloat" ) 33 | GL.glEnableVertexAttribArray( position ) 34 | GL.glVertexAttribPointer( position, 2, GL.GL_FLOAT, 0, stride, nil ) 35 | 36 | -- texcoord 37 | local texcoord = GL.glGetAttribLocation( shader, "texcoord" ) 38 | GL.glEnableVertexAttribArray( texcoord ) 39 | local pointer = ffi.cast( "GLvoid *", 2 * ffi.sizeof( "GLfloat" ) ) 40 | GL.glVertexAttribPointer( texcoord, 2, GL.GL_FLOAT, 0, stride, pointer ) 41 | 42 | -- uniforms 43 | -- model 44 | local model = GL.glGetUniformLocation( shader, "model" ) 45 | local mat4 = ffi.new( "kmMat4" ) 46 | kazmath.kmMat4Identity( mat4 ) 47 | GL.glUniformMatrix4fv( model, 1, GL.GL_FALSE, mat4.mat ) 48 | 49 | -- view 50 | local view = GL.glGetUniformLocation( shader, "view" ) 51 | GL.glUniformMatrix4fv( view, 1, GL.GL_FALSE, mat4.mat ) 52 | 53 | -- projection 54 | local width, height = framework.graphics.getSize() 55 | framework.graphics.setOrthographicProjection( width, height ) 56 | 57 | return shader 58 | end 59 | -------------------------------------------------------------------------------- /lua/framework/graphics/shaders/default3d.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local GL = require( "opengl" ) 8 | local ffi = require( "ffi" ) 9 | local kazmath = require( "kazmath" ) 10 | 11 | return function() 12 | -- shader 13 | local fragSource = framework.filesystem.read( "shaders/default.frag" ) 14 | local vertSource = framework.filesystem.read( "shaders/default3d.vert" ) 15 | local shader = framework.graphics.newShader( fragSource, vertSource ) 16 | GL.glBindFragDataLocation( shader, 0, "FragColor" ) 17 | framework.graphics.linkShader( shader ) 18 | framework.graphics.setShader( shader ) 19 | 20 | -- default.frag 21 | -- uniforms 22 | -- tex 23 | framework.graphics.setDefaultTexture() 24 | 25 | -- color 26 | framework.graphics.setColor( { 1, 1, 1, 1 } ) 27 | 28 | -- default3d.vert 29 | -- attribs 30 | -- position 31 | local position = GL.glGetAttribLocation( shader, "position" ) 32 | local stride = ( 3 + 3 + 3 + 2 ) * ffi.sizeof( "GLfloat" ) 33 | GL.glEnableVertexAttribArray( position ) 34 | GL.glVertexAttribPointer( position, 3, GL.GL_FLOAT, 0, stride, nil ) 35 | 36 | -- normal 37 | local normal = GL.glGetAttribLocation( shader, "normal" ) 38 | GL.glEnableVertexAttribArray( normal ) 39 | local pointer = ffi.cast( "GLvoid *", 3 * ffi.sizeof( "GLfloat" ) ) 40 | GL.glVertexAttribPointer( normal, 3, GL.GL_FLOAT, 0, stride, pointer ) 41 | 42 | -- tangent 43 | local tangent = GL.glGetAttribLocation( shader, "tangent" ) 44 | GL.glEnableVertexAttribArray( tangent ) 45 | pointer = ffi.cast( "GLvoid *", ( 3 + 3 ) * ffi.sizeof( "GLfloat" ) ) 46 | GL.glVertexAttribPointer( tangent, 3, GL.GL_FLOAT, 0, stride, pointer ) 47 | 48 | -- texcoord 49 | local texcoord = GL.glGetAttribLocation( shader, "texcoord" ) 50 | GL.glEnableVertexAttribArray( texcoord ) 51 | pointer = ffi.cast( "GLvoid *", ( 3 + 3 + 3 ) * ffi.sizeof( "GLfloat" ) ) 52 | GL.glVertexAttribPointer( texcoord, 2, GL.GL_FLOAT, 0, stride, pointer ) 53 | 54 | -- uniforms 55 | -- model 56 | local model = GL.glGetUniformLocation( shader, "model" ) 57 | local mat4 = ffi.new( "kmMat4" ) 58 | kazmath.kmMat4Identity( mat4 ) 59 | GL.glUniformMatrix4fv( model, 1, GL.GL_FALSE, mat4.mat ) 60 | 61 | -- view 62 | local view = GL.glGetUniformLocation( shader, "view" ) 63 | GL.glUniformMatrix4fv( view, 1, GL.GL_FALSE, mat4.mat ) 64 | 65 | -- projection 66 | local width, height = framework.graphics.getSize() 67 | framework.graphics.setOrthographicProjection( width, height ) 68 | 69 | return shader 70 | end 71 | -------------------------------------------------------------------------------- /lua/framework/graphics/shaders/depth.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local GL = require( "opengl" ) 8 | local ffi = require( "ffi" ) 9 | local kazmath = require( "kazmath" ) 10 | 11 | return function() 12 | -- shader 13 | local fragSource = framework.filesystem.read( "shaders/depth.frag" ) 14 | local vertSource = framework.filesystem.read( "shaders/depth.vert" ) 15 | local shader = framework.graphics.newShader( fragSource, vertSource ) 16 | GL.glBindFragDataLocation( shader, 0, "FragDepth" ) 17 | framework.graphics.linkShader( shader ) 18 | framework.graphics.setShader( shader ) 19 | 20 | -- depth.vert 21 | -- attribs 22 | -- position 23 | local position = GL.glGetAttribLocation( shader, "position" ) 24 | local stride = 3 * ffi.sizeof( "GLfloat" ) 25 | GL.glEnableVertexAttribArray( position ) 26 | GL.glVertexAttribPointer( position, 3, GL.GL_FLOAT, 0, stride, nil ) 27 | 28 | -- uniforms 29 | -- model 30 | local model = GL.glGetUniformLocation( shader, "model" ) 31 | local mat4 = ffi.new( "kmMat4" ) 32 | kazmath.kmMat4Identity( mat4 ) 33 | GL.glUniformMatrix4fv( model, 1, GL.GL_FALSE, mat4.mat ) 34 | 35 | -- view 36 | local view = GL.glGetUniformLocation( shader, "view" ) 37 | GL.glUniformMatrix4fv( view, 1, GL.GL_FALSE, mat4.mat ) 38 | 39 | -- projection 40 | local width, height = framework.graphics.getSize() 41 | framework.graphics.setOrthographicProjection( width, height ) 42 | 43 | return shader 44 | end 45 | -------------------------------------------------------------------------------- /lua/framework/graphics/shaders/gltfpbr.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local GL = require( "opengl" ) 8 | local ffi = require( "ffi" ) 9 | local kazmath = require( "kazmath" ) 10 | 11 | return function() 12 | -- shader 13 | local fragSource = framework.filesystem.read( "shaders/pbr-frag.glsl" ) 14 | local vertSource = framework.filesystem.read( "shaders/pbr-vert.glsl" ) 15 | local shader = framework.graphics.newShader( fragSource, vertSource ) 16 | GL.glBindFragDataLocation( shader, 0, "FragColor" ) 17 | framework.graphics.linkShader( shader ) 18 | framework.graphics.setShader( shader ) 19 | 20 | -- pbr-frag.glsl 21 | -- uniforms 22 | -- u_LightDirection 23 | framework.graphics.setLightDirection( { 0, 0, 0 } ) 24 | -- u_LightColor 25 | framework.graphics.setLightColor( { 1, 1, 1 } ) 26 | 27 | -- u_DiffuseEnvSampler 28 | local u_DiffuseEnvSampler = GL.glGetUniformLocation( 29 | shader, "u_DiffuseEnvSampler" 30 | ) 31 | GL.glUniform1i( u_DiffuseEnvSampler, 1 ) 32 | -- u_SpecularEnvSampler 33 | local u_SpecularEnvSampler = GL.glGetUniformLocation( 34 | shader, "u_SpecularEnvSampler" 35 | ) 36 | GL.glUniform1i( u_SpecularEnvSampler, 2 ) 37 | 38 | -- tex 39 | local tex = GL.glGetUniformLocation( 40 | shader, "tex" 41 | ) 42 | GL.glUniform1i( tex, 3 ) 43 | framework.graphics.setActiveTexture( 3 ) 44 | framework.graphics.setDefaultTexture() 45 | framework.graphics.setActiveTexture( 0 ) 46 | 47 | -- u_MetallicRoughnessSampler 48 | local u_MetallicRoughnessSampler = GL.glGetUniformLocation( 49 | shader, "u_MetallicRoughnessSampler" 50 | ) 51 | GL.glUniform1i( u_MetallicRoughnessSampler, 4 ) 52 | 53 | -- u_NormalSampler 54 | local u_NormalSampler = GL.glGetUniformLocation( 55 | shader, "u_NormalSampler" 56 | ) 57 | GL.glUniform1i( u_NormalSampler, 5 ) 58 | -- u_NormalScale 59 | framework.graphics.setNormalScale( 1 ) 60 | 61 | -- u_brdfLUT 62 | local u_brdfLUT = GL.glGetUniformLocation( 63 | shader, "u_brdfLUT" 64 | ) 65 | GL.glUniform1i( u_brdfLUT, 6 ) 66 | -- u_brdfLUT 67 | framework.graphics.setBrdfLUT( "textures/brdfLUT.png" ) 68 | 69 | -- u_EmissiveSampler 70 | local u_EmissiveSampler = GL.glGetUniformLocation( 71 | shader, "u_EmissiveSampler" 72 | ) 73 | GL.glUniform1i( u_EmissiveSampler, 7 ) 74 | -- u_EmissiveFactor 75 | framework.graphics.setEmissiveFactor( { 1, 1, 1 } ) 76 | 77 | -- u_OcclusionSampler 78 | local u_OcclusionSampler = GL.glGetUniformLocation( 79 | shader, "u_OcclusionSampler" 80 | ) 81 | GL.glUniform1i( u_OcclusionSampler, 8 ) 82 | -- u_OcclusionStrength 83 | framework.graphics.setOcclusionStrength( 1 ) 84 | 85 | -- u_MetallicRoughnessValues 86 | framework.graphics.setMetallicRoughnessValues( { 1, 1 } ) 87 | -- color 88 | framework.graphics.setColor( { 1, 1, 1, 1 } ) 89 | 90 | -- pbr-vert.glsl 91 | -- attribs 92 | -- position 93 | local position = GL.glGetAttribLocation( shader, "position" ) 94 | local stride = ( 3 + 3 + 3 + 2 ) * ffi.sizeof( "GLfloat" ) 95 | GL.glEnableVertexAttribArray( position ) 96 | GL.glVertexAttribPointer( position, 3, GL.GL_FLOAT, 0, stride, nil ) 97 | 98 | -- normal 99 | local normal = GL.glGetAttribLocation( shader, "normal" ) 100 | GL.glEnableVertexAttribArray( normal ) 101 | local pointer = ffi.cast( "GLvoid *", 3 * ffi.sizeof( "GLfloat" ) ) 102 | GL.glVertexAttribPointer( normal, 3, GL.GL_FLOAT, 0, stride, pointer ) 103 | 104 | -- tangent 105 | local tangent = GL.glGetAttribLocation( shader, "tangent" ) 106 | GL.glEnableVertexAttribArray( tangent ) 107 | pointer = ffi.cast( "GLvoid *", ( 3 + 3 ) * ffi.sizeof( "GLfloat" ) ) 108 | GL.glVertexAttribPointer( tangent, 3, GL.GL_FLOAT, 0, stride, pointer ) 109 | 110 | -- texcoord 111 | local texcoord = GL.glGetAttribLocation( shader, "texcoord" ) 112 | GL.glEnableVertexAttribArray( texcoord ) 113 | pointer = ffi.cast( "GLvoid *", ( 3 + 3 + 3 ) * ffi.sizeof( "GLfloat" ) ) 114 | GL.glVertexAttribPointer( texcoord, 2, GL.GL_FLOAT, 0, stride, pointer ) 115 | 116 | -- uniforms 117 | -- model 118 | local model = GL.glGetUniformLocation( shader, "model" ) 119 | local mat4 = ffi.new( "kmMat4" ) 120 | kazmath.kmMat4Identity( mat4 ) 121 | GL.glUniformMatrix4fv( model, 1, GL.GL_FALSE, mat4.mat ) 122 | 123 | -- view 124 | local view = GL.glGetUniformLocation( shader, "view" ) 125 | GL.glUniformMatrix4fv( view, 1, GL.GL_FALSE, mat4.mat ) 126 | 127 | -- projection 128 | local width, height = framework.graphics.getSize() 129 | framework.graphics.setOrthographicProjection( width, height ) 130 | 131 | return shader 132 | end 133 | -------------------------------------------------------------------------------- /lua/framework/graphics/shaders/skybox.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local GL = require( "opengl" ) 8 | local ffi = require( "ffi" ) 9 | local kazmath = require( "kazmath" ) 10 | 11 | return function() 12 | -- shader 13 | local fragSource = framework.filesystem.read( "shaders/skybox.frag" ) 14 | local vertSource = framework.filesystem.read( "shaders/skybox.vert" ) 15 | local shader = framework.graphics.newShader( fragSource, vertSource ) 16 | GL.glBindFragDataLocation( shader, 0, "FragColor" ) 17 | framework.graphics.linkShader( shader ) 18 | framework.graphics.setShader( shader ) 19 | 20 | -- skybox.frag 21 | -- uniforms 22 | -- tex 23 | framework.graphics.setDefaultTexture() 24 | 25 | -- skybox.vert 26 | -- attribs 27 | -- position 28 | local position = GL.glGetAttribLocation( shader, "position" ) 29 | local stride = ( 3 + 3 ) * ffi.sizeof( "GLfloat" ) 30 | GL.glEnableVertexAttribArray( position ) 31 | GL.glVertexAttribPointer( position, 3, GL.GL_FLOAT, 0, stride, nil ) 32 | 33 | -- texcoord 34 | local texcoord = GL.glGetAttribLocation( shader, "texcoord" ) 35 | GL.glEnableVertexAttribArray( texcoord ) 36 | local pointer = ffi.cast( "GLvoid *", ( 3 + 3 ) * ffi.sizeof( "GLfloat" ) ) 37 | GL.glVertexAttribPointer( texcoord, 3, GL.GL_FLOAT, 0, stride, pointer ) 38 | 39 | -- uniforms 40 | -- view 41 | local view = GL.glGetUniformLocation( shader, "view" ) 42 | local mat4 = ffi.new( "kmMat4" ) 43 | kazmath.kmMat4Identity( mat4 ) 44 | GL.glUniformMatrix4fv( view, 1, GL.GL_FALSE, mat4.mat ) 45 | 46 | -- projection 47 | local width, height = framework.graphics.getSize() 48 | framework.graphics.setOrthographicProjection( width, height ) 49 | 50 | return shader 51 | end 52 | -------------------------------------------------------------------------------- /lua/framework/graphics/spritebatch.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local GL = require( "opengl" ) 9 | local ffi = require( "ffi" ) 10 | 11 | class( "framework.graphics.spritebatch" ) 12 | 13 | local spritebatch = framework.graphics.spritebatch 14 | 15 | function spritebatch:spritebatch( image, maxsprites ) 16 | self.image = image 17 | 18 | setproxy( self ) 19 | end 20 | 21 | function spritebatch:add( quad ) 22 | end 23 | 24 | function spritebatch:draw( x, y, r, sx, sy, ox, oy, kx, ky ) 25 | image.draw( self, x, y, r, sx, sy, ox, oy, kx, ky ) 26 | end 27 | 28 | function spritebatch:__gc() 29 | end 30 | -------------------------------------------------------------------------------- /lua/framework/graphics/text.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local GL = require( "opengl" ) 9 | 10 | class( "framework.graphics.text" ) 11 | 12 | local text = framework.graphics.text 13 | 14 | function text:text( font, textstring ) 15 | self.font = font 16 | self.textstring = textstring or "" 17 | end 18 | 19 | function text:draw( x, y, r, sx, sy, ox, oy, kx, ky ) 20 | local font = self.font 21 | font:print( self.textstring, x, y, r, sx, sy, ox, oy, kx, ky ) 22 | end 23 | 24 | function text:getFont() 25 | return self.font 26 | end 27 | 28 | function text:set( textstring ) 29 | self.textstring = textstring 30 | end 31 | 32 | function text:setFont( font ) 33 | self.font = font 34 | end 35 | -------------------------------------------------------------------------------- /lua/framework/graphics/transformation.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local kazmath = require( "kazmath" ) 8 | local ffi = require( "ffi" ) 9 | local GL = require( "opengl" ) 10 | 11 | local ipairs = ipairs 12 | local framework = framework 13 | local table = table 14 | 15 | module( "framework.graphics" ) 16 | 17 | local transformations = { 18 | "model", 19 | "view", 20 | "projection" 21 | } 22 | 23 | _matrixMode = _matrixMode or "model" 24 | _stack = _stack or {} 25 | 26 | for _, transformation in ipairs( transformations ) do 27 | local mat4 = ffi.new( "kmMat4" ) 28 | kazmath.kmMat4Identity( mat4 ) 29 | _stack[ transformation ] = _stack[ transformation ] or { mat4 } 30 | end 31 | 32 | local mat4 = ffi.new( "kmMat4" ) 33 | kazmath.kmMat4Identity( mat4 ) 34 | _normalMatrix = _normalMatrix or mat4 35 | 36 | function setMatrixMode( mode ) 37 | _matrixMode = mode 38 | end 39 | 40 | function getMatrixMode() 41 | return _matrixMode 42 | end 43 | 44 | function getNormalMatrix() 45 | return _normalMatrix 46 | end 47 | 48 | function getTransformation() 49 | local mode = getMatrixMode() 50 | local stack = _stack[ mode ] 51 | return stack[ #stack ] 52 | end 53 | 54 | function push() 55 | local mode = getMatrixMode() 56 | local top = ffi.new( "kmMat4" ) 57 | kazmath.kmMat4Assign( top, getTransformation() ) 58 | table.insert( _stack[ mode ], top ) 59 | end 60 | 61 | function pop() 62 | local mode = getMatrixMode() 63 | local stack = _stack[ mode ] 64 | if ( #stack == 1 ) then return end 65 | table.remove( stack, #stack ) 66 | end 67 | 68 | function setPerspectiveProjection( fov, aspect, near, far ) 69 | local mode = getMatrixMode() 70 | setMatrixMode( "projection" ) 71 | local mat4 = getTransformation() 72 | kazmath.kmMat4PerspectiveProjection( mat4, fov, aspect, near, far ) 73 | setMatrixMode( mode ) 74 | updateTransformations() 75 | end 76 | 77 | function setReversedZPerspectiveProjection( fov, aspect, near ) 78 | local mode = getMatrixMode() 79 | setMatrixMode( "projection" ) 80 | local mat4 = getTransformation() 81 | kazmath.kmMat4ReversedZPerspectiveProjection( mat4, fov, aspect, near ) 82 | GL.glDepthFunc( GL.GL_GEQUAL ) 83 | setMatrixMode( mode ) 84 | updateTransformations() 85 | end 86 | 87 | function setOrthographicProjection( width, height ) 88 | if ( not width and not height ) then 89 | width, height = framework.graphics.getSize() 90 | end 91 | 92 | local mode = getMatrixMode() 93 | setMatrixMode( "projection" ) 94 | local mat4 = getTransformation() 95 | kazmath.kmMat4OrthographicProjection( 96 | mat4, 0, width, height, 0, -1.0, 1.0 97 | ) 98 | setMatrixMode( mode ) 99 | updateTransformations() 100 | end 101 | 102 | function lookAt( eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ ) 103 | local mode = getMatrixMode() 104 | setMatrixMode( "view" ) 105 | local mat4 = getTransformation() 106 | local eye = ffi.new( "kmVec3", eyeX, eyeY, eyeZ ) 107 | local center = ffi.new( "kmVec3", centerX, centerY, centerZ ) 108 | local up = ffi.new( "kmVec3", upX, upY, upZ ) 109 | kazmath.kmMat4LookAt( mat4, eye, center, up ) 110 | setMatrixMode( mode ) 111 | updateTransformations() 112 | end 113 | 114 | function origin() 115 | kazmath.kmMat4Identity( getTransformation() ) 116 | end 117 | 118 | function rotate( angle ) 119 | local rotation = ffi.new( "kmMat4" ) 120 | kazmath.kmMat4RotationZ( rotation, angle ) 121 | local mat4 = getTransformation() 122 | kazmath.kmMat4Multiply( mat4, mat4, rotation ) 123 | end 124 | 125 | function rotateX( angle ) 126 | local rotation = ffi.new( "kmMat4" ) 127 | kazmath.kmMat4RotationX( rotation, angle ) 128 | local mat4 = getTransformation() 129 | kazmath.kmMat4Multiply( mat4, mat4, rotation ) 130 | end 131 | 132 | function rotateY( angle ) 133 | local rotation = ffi.new( "kmMat4" ) 134 | kazmath.kmMat4RotationY( rotation, angle ) 135 | local mat4 = getTransformation() 136 | kazmath.kmMat4Multiply( mat4, mat4, rotation ) 137 | end 138 | 139 | rotateZ = rotate 140 | 141 | function scale( x, y, z ) 142 | y = y or x 143 | z = z or 1 144 | local scaling = ffi.new( "kmMat4" ) 145 | kazmath.kmMat4Scaling( scaling, x, y, z ) 146 | local mat4 = getTransformation() 147 | kazmath.kmMat4Multiply( mat4, mat4, scaling ) 148 | end 149 | 150 | function translate( x, y, z ) 151 | z = z or 0 152 | local translation = ffi.new( "kmMat4" ) 153 | kazmath.kmMat4Translation( translation, x, y, z ) 154 | local mat4 = getTransformation() 155 | kazmath.kmMat4Multiply( mat4, mat4, translation ) 156 | end 157 | 158 | local function updateNormalMatrix() 159 | local mode = getMatrixMode() 160 | -- local modelView = ffi.new( "kmMat4" ) 161 | setMatrixMode( "model" ) 162 | local model = getTransformation() 163 | -- setMatrixMode( "view" ) 164 | -- local view = getTransformation() 165 | setMatrixMode( mode ) 166 | -- kazmath.kmMat4Multiply( modelView, model, view ) 167 | -- local inverseModelView = ffi.new( "kmMat4" ) 168 | -- kazmath.kmMat4Inverse( inverseModelView, modelView ) 169 | -- kazmath.kmMat4Transpose( _normalMatrix, inverseModelView ) 170 | local inverseModel = ffi.new( "kmMat4" ) 171 | kazmath.kmMat4Inverse( inverseModel, model ) 172 | kazmath.kmMat4Transpose( _normalMatrix, inverseModel ) 173 | end 174 | 175 | function updateTransformations() 176 | local mode = getMatrixMode() 177 | local shader = framework.graphics.getShader() 178 | for _, transformation in ipairs( transformations ) do 179 | local uniform = GL.glGetUniformLocation( shader, transformation ) 180 | setMatrixMode( transformation ) 181 | local mat4 = getTransformation() 182 | GL.glUniformMatrix4fv( uniform, 1, GL.GL_FALSE, mat4.mat ) 183 | end 184 | 185 | updateNormalMatrix() 186 | local uniform = GL.glGetUniformLocation( shader, "normalMatrix" ) 187 | local normalMatrix = getNormalMatrix() 188 | GL.glUniformMatrix4fv( uniform, 1, GL.GL_FALSE, normalMatrix.mat ) 189 | 190 | setMatrixMode( mode ) 191 | end 192 | -------------------------------------------------------------------------------- /lua/framework/html/app.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local ffi = require( "ffi" ) 9 | 10 | class( "framework.html.browser" ) 11 | 12 | local browser = framework.html.browser 13 | local toutf16 = framework.html.toutf16 14 | 15 | local function on_register_custom_schemes( self, registrar ) 16 | registrar.add_custom_scheme( 17 | registrar, 18 | toutf16( "client" ), 19 | 1, 20 | 1, 21 | 1, 22 | 1, 23 | 1, 24 | 1 25 | ) 26 | end 27 | 28 | jit.off( on_register_custom_schemes, true ) 29 | 30 | local function get_browser_process_handler( self ) 31 | local func = function( app ) 32 | return self.processHandler 33 | end 34 | jit.off( func, true ) 35 | return func 36 | end 37 | 38 | function browser:initializeApp() 39 | local app = ffi.new( "cef_app_t" ) 40 | app.base.size = ffi.sizeof( app ) 41 | app.on_register_custom_schemes = on_register_custom_schemes 42 | app.get_browser_process_handler = get_browser_process_handler( self ) 43 | self.app = app 44 | end 45 | -------------------------------------------------------------------------------- /lua/framework/html/browser.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | require( "framework.graphics.image" ) 9 | local ffi = require( "ffi" ) 10 | local cef = require( "cef" ) 11 | local GL = require( "opengl" ) 12 | 13 | local image = framework.graphics.image 14 | 15 | class( "framework.html.browser" ) 16 | 17 | local browser = framework.html.browser 18 | 19 | local function toutf16( s ) 20 | local value = ffi.new( "cef_string_t" ) 21 | cef.cef_string_utf8_to_utf16( s, string.len( s ), value ) 22 | return value 23 | end 24 | 25 | framework.html.toutf16 = toutf16 26 | 27 | local function toutf8( s ) 28 | local value = ffi.new( "cef_string_utf8_t[1]" ) 29 | cef.cef_string_utf16_to_utf8( s.str, s.length, value[0] ) 30 | return ffi.string( value[0].str, value[0].length ) 31 | end 32 | 33 | framework.html.toutf8 = toutf8 34 | 35 | function browser:browser( url, width, height ) 36 | if ( not width and not height ) then 37 | width, height = framework.graphics.getSize() 38 | end 39 | 40 | require( "framework.html.app" ) 41 | require( "framework.html.process" ) 42 | require( "framework.html.scheme" ) 43 | require( "framework.html.resource" ) 44 | require( "framework.html.client" ) 45 | require( "framework.html.lifespan" ) 46 | require( "framework.html.rendering" ) 47 | 48 | self.mainArgs = ffi.new( "cef_main_args_t" ) 49 | 50 | self:initializeApp() 51 | self:initializeProcessHandler() 52 | self:initializeSchemeHandler() 53 | self:initializeResourceHandler() 54 | 55 | local settings = ffi.new( "cef_settings_t" ) 56 | settings.size = ffi.sizeof( settings ) 57 | settings.log_severity = ffi.C.LOGSEVERITY_WARNING 58 | settings.no_sandbox = 1 59 | self.settings = settings 60 | 61 | local browser_subprocess_path = "bin\\cef.exe" 62 | settings.browser_subprocess_path = toutf16( browser_subprocess_path ) 63 | 64 | local cwd = framework.filesystem.getWorkingDirectory() 65 | local resources_dir_path = cwd .. "resources" 66 | settings.resources_dir_path = toutf16( resources_dir_path ) 67 | 68 | local locales_dir_path = cwd .. "resources\\locales" 69 | settings.locales_dir_path = toutf16( locales_dir_path ) 70 | 71 | cef.cef_initialize( self.mainArgs, self.settings, self.app, nil ) 72 | 73 | local windowInfo = ffi.new( "cef_window_info_t" ) 74 | windowInfo.width = 0x80000000 75 | windowInfo.height = 0x80000000 76 | windowInfo.windowless_rendering_enabled = 1 77 | self.windowInfo = windowInfo 78 | 79 | local browserSettings = ffi.new( "cef_browser_settings_t" ) 80 | browserSettings.size = ffi.sizeof( browserSettings ) 81 | browserSettings.windowless_frame_rate = 60 82 | self.browserSettings = browserSettings 83 | 84 | self:initializeClient() 85 | self:initializeLifeSpanHandler() 86 | 87 | self.texture = ffi.new( "GLuint[1]" ) 88 | GL.glGenTextures( 1, self.texture ) 89 | GL.glBindTexture( GL.GL_TEXTURE_2D, self.texture[0] ) 90 | GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_BASE_LEVEL, 0 ) 91 | GL.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAX_LEVEL, 0 ) 92 | 93 | self.width = width 94 | self.height = height 95 | self:initializeRenderHandler() 96 | 97 | self.browser = cef.cef_browser_host_create_browser_sync( 98 | self.windowInfo, self.client, toutf16( url ), self.browserSettings, nil 99 | ) 100 | 101 | setproxy( self ) 102 | end 103 | 104 | browser.draw = image.draw 105 | 106 | function browser:resize( width, height ) 107 | self.width = width 108 | self.height = height 109 | 110 | local host = self:getHost() 111 | host.was_resized( host ) 112 | end 113 | 114 | function browser:keypressed( key, scancode, isrepeat ) 115 | local host = self:getHost() 116 | local event = ffi.new( "cef_key_event_t", { 117 | type = ffi.C.KEYEVENT_KEYDOWN 118 | } ) 119 | host.send_key_event( host, event ) 120 | end 121 | 122 | function browser:keyreleased( key, scancode ) 123 | local host = self:getHost() 124 | local event = ffi.new( "cef_key_event_t", { 125 | type = ffi.C.KEYEVENT_KEYUP 126 | } ) 127 | host.send_key_event( host, event ) 128 | end 129 | 130 | function browser:mousemoved( x, y, dx, dy, istouch ) 131 | local host = self:getHost() 132 | local event = ffi.new( "cef_mouse_event_t", { 133 | x = x, 134 | y = y 135 | } ) 136 | host.send_mouse_move_event( host, event, 0 ) 137 | end 138 | 139 | function browser:mousepressed( x, y, button, istouch ) 140 | if ( button == 1 ) then 141 | button = ffi.C.MBT_LEFT 142 | elseif ( button == 2 ) then 143 | button = ffi.C.MBT_RIGHT 144 | elseif ( button == 3 ) then 145 | button = ffi.C.MBT_MIDDLE 146 | end 147 | 148 | local host = self:getHost() 149 | local event = ffi.new( "cef_mouse_event_t", { 150 | x = x, 151 | y = y 152 | } ) 153 | host.send_mouse_click_event( host, event, button, 0, 1 ) 154 | end 155 | 156 | function browser:mousereleased( x, y, button, istouch ) 157 | if ( button == 1 ) then 158 | button = ffi.C.MBT_LEFT 159 | elseif ( button == 2 ) then 160 | button = ffi.C.MBT_RIGHT 161 | elseif ( button == 3 ) then 162 | button = ffi.C.MBT_MIDDLE 163 | end 164 | 165 | local host = self:getHost() 166 | local event = ffi.new( "cef_mouse_event_t", { 167 | x = x, 168 | y = y 169 | } ) 170 | host.send_mouse_click_event( host, event, button, 1, 0 ) 171 | end 172 | 173 | function browser:wheelmoved( x, y ) 174 | local host = self:getHost() 175 | local _x, _y = framework.mouse.getPosition() 176 | local event = ffi.new( "cef_mouse_event_t", { 177 | x = _x, 178 | y = _y 179 | } ) 180 | host.send_mouse_wheel_event( host, event, x, y ) 181 | end 182 | 183 | function browser:getHost() 184 | local browser = self.browser 185 | local host = browser.get_host( browser ) 186 | return host 187 | end 188 | 189 | function browser:__gc() 190 | GL.glDeleteTextures( 1, self.texture ) 191 | end 192 | -------------------------------------------------------------------------------- /lua/framework/html/client.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local ffi = require( "ffi" ) 9 | 10 | class( "framework.html.browser" ) 11 | 12 | local browser = framework.html.browser 13 | 14 | local function get_life_span_handler( self ) 15 | local func = function( client ) 16 | return self.lifeSpanHandler 17 | end 18 | jit.off( func, true ) 19 | return func 20 | end 21 | 22 | local function get_render_handler( self ) 23 | local func = function( client ) 24 | return self.renderHandler 25 | end 26 | jit.off( func, true ) 27 | return func 28 | end 29 | 30 | function browser:initializeClient() 31 | local client = ffi.new( "cef_client_t" ) 32 | client.base.size = ffi.sizeof( client ) 33 | client.get_life_span_handler = get_life_span_handler( self ) 34 | client.get_render_handler = get_render_handler( self ) 35 | self.client = client 36 | end 37 | -------------------------------------------------------------------------------- /lua/framework/html/init.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local cef = require( "cef" ) 8 | 9 | local require = require 10 | local framework = framework 11 | 12 | module( "framework.html" ) 13 | 14 | function newBrowser( url ) 15 | require( "framework.html.browser" ) 16 | local browser = framework.html.browser 17 | return browser( url ) 18 | end 19 | 20 | function update( dt ) 21 | cef.cef_do_message_loop_work() 22 | end 23 | 24 | function quit() 25 | cef.cef_shutdown() 26 | end 27 | -------------------------------------------------------------------------------- /lua/framework/html/lifespan.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local ffi = require( "ffi" ) 9 | local cef = require( "cef" ) 10 | 11 | class( "framework.html.browser" ) 12 | 13 | local browser = framework.html.browser 14 | 15 | local function on_before_close( self, browser ) 16 | cef.cef_quit_message_loop() 17 | end 18 | 19 | function browser:initializeLifeSpanHandler() 20 | local handler = ffi.new( "cef_life_span_handler_t" ) 21 | handler.base.size = ffi.sizeof( handler ) 22 | handler.on_before_close = on_before_close 23 | self.lifeSpanHandler = handler 24 | end 25 | -------------------------------------------------------------------------------- /lua/framework/html/process.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local ffi = require( "ffi" ) 9 | local cef = require( "cef" ) 10 | 11 | class( "framework.html.browser" ) 12 | 13 | local browser = framework.html.browser 14 | local toutf16 = framework.html.toutf16 15 | 16 | local function on_context_initialized( self ) 17 | local func = function( handler ) 18 | cef.cef_register_scheme_handler_factory( 19 | toutf16( "client" ), toutf16( "lgf" ), self.schemeHandler 20 | ) 21 | end 22 | jit.off( func, true ) 23 | return func 24 | end 25 | 26 | function browser:initializeProcessHandler() 27 | local handler = ffi.new( "cef_browser_process_handler_t" ) 28 | handler.base.size = ffi.sizeof( handler ) 29 | handler.on_context_initialized = on_context_initialized( self ) 30 | self.processHandler = handler 31 | end 32 | -------------------------------------------------------------------------------- /lua/framework/html/rendering.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local ffi = require( "ffi" ) 9 | local cef = require( "cef" ) 10 | local GL = require( "opengl" ) 11 | 12 | class( "framework.html.browser" ) 13 | 14 | local browser = framework.html.browser 15 | 16 | local function get_view_rect( self ) 17 | local func = function( handler, browser, rect ) 18 | rect[0] = ffi.new( "cef_rect_t", 0, 0, self.width, self.height ) 19 | return 1 20 | end 21 | jit.off( func, true ) 22 | return func 23 | end 24 | 25 | local function on_paint( self ) 26 | local func = function( 27 | handler, 28 | browser, 29 | type, 30 | dirtyRectsCount, 31 | dirtyRects, 32 | buffer, 33 | width, 34 | height 35 | ) 36 | assert( cef.cef_currently_on( ffi.C.TID_UI ) ) 37 | 38 | GL.glBindTexture( GL.GL_TEXTURE_2D, self.texture[0] ) 39 | GL.glTexImage2D( 40 | GL.GL_TEXTURE_2D, 41 | 0, 42 | GL.GL_RGBA, 43 | width, 44 | height, 45 | 0, 46 | GL.GL_BGRA, 47 | GL.GL_UNSIGNED_INT_8_8_8_8_REV, 48 | buffer 49 | ) 50 | end 51 | jit.off( func, true ) 52 | return func 53 | end 54 | 55 | function browser:initializeRenderHandler() 56 | local handler = ffi.new( "cef_render_handler_t" ) 57 | handler.base.size = ffi.sizeof( handler ) 58 | handler.get_view_rect = get_view_rect( self ) 59 | handler.on_paint = on_paint( self ) 60 | self.renderHandler = handler 61 | end 62 | -------------------------------------------------------------------------------- /lua/framework/html/resource.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local ffi = require( "ffi" ) 9 | local cef = require( "cef" ) 10 | 11 | class( "framework.html.browser" ) 12 | 13 | local browser = framework.html.browser 14 | local toutf8 = framework.html.toutf8 15 | 16 | local function process_request( self, request, callback ) 17 | local tmp = request.get_url( request ) 18 | local url = toutf8( tmp ) 19 | url = string.gsub( url, "client://lgf/", "" ) 20 | ffi.C.printf( "%s\n", url ) 21 | cef.cef_string_userfree_utf16_free( tmp ) 22 | return 0 23 | end 24 | 25 | jit.off( process_request, true ) 26 | 27 | function browser:initializeResourceHandler() 28 | local handler = ffi.new( "cef_resource_handler_t" ) 29 | handler.base.size = ffi.sizeof( handler ) 30 | handler.process_request = process_request 31 | self.resourceHandler = handler 32 | end 33 | -------------------------------------------------------------------------------- /lua/framework/html/scheme.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local ffi = require( "ffi" ) 9 | 10 | class( "framework.html.browser" ) 11 | 12 | local browser = framework.html.browser 13 | local toutf16 = framework.html.toutf16 14 | 15 | local function create( self ) 16 | local func = function( handler, browser, frame, scheme_name, request ) 17 | return self.resourceHandler 18 | end 19 | jit.off( func, true ) 20 | return func 21 | end 22 | 23 | function browser:initializeSchemeHandler() 24 | local handler = ffi.new( "cef_scheme_handler_factory_t" ) 25 | handler.base.size = ffi.sizeof( handler ) 26 | handler.create = create( self ) 27 | self.schemeHandler = handler 28 | end 29 | -------------------------------------------------------------------------------- /lua/framework/init.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | 9 | local execdir = "./" 10 | local gsub = string.gsub 11 | local gamedir = arg[ 2 ] 12 | 13 | local framework = {} 14 | _G.framework = framework 15 | 16 | if ( jit.os == "Windows" ) then 17 | execdir = ".\\" 18 | 19 | -- Declare `SetDllDirectoryA` 20 | ffi.cdef[[ 21 | int __stdcall SetDllDirectoryA(const char* lpPathName); 22 | ]] 23 | 24 | -- Get working directory 25 | execdir = gsub( arg[ 0 ], "\\lua\\framework\\init%.lua$", "\\" ) 26 | framework.execdir = execdir 27 | 28 | -- Set DLL directory 29 | ffi.C.SetDllDirectoryA( execdir .. "bin" ) 30 | 31 | -- Add `lib' 32 | package.path = package.path .. ";" .. execdir .. "lib\\?.lua;" 33 | package.cpath = package.cpath .. ";" .. execdir .. "lib\\?.dll;" 34 | package.cpath = package.cpath .. execdir .. "lib\\loadall.dll" 35 | 36 | -- Add `./?/init.lua' 37 | if ( gamedir ) then 38 | package.path = gsub( 39 | package.path, 40 | "^%.\\%?%.lua;", 41 | gamedir .. "\\?.lua;" .. gamedir .. "\\?\\init.lua;" 42 | ) 43 | else 44 | package.path = gsub( 45 | package.path, 46 | "^%.\\%?%.lua;", 47 | execdir .. "?.lua;" 48 | ) 49 | end 50 | else 51 | -- Get working directory 52 | execdir = gsub( arg[ 0 ], "/lua/framework/init%.lua$", "/" ) 53 | framework.execdir = execdir 54 | 55 | -- Add Windows LUA_LDIR paths 56 | local ldir = "./?.lua;!lua/?.lua;!lua/?/init.lua;" 57 | package.path = gsub( package.path, "^%./%?%.lua;", ldir ) 58 | package.path = gsub( package.path, "!", execdir ) 59 | 60 | -- Add `lib' 61 | package.path = package.path .. ";" .. execdir .. "lib/?.lua" 62 | package.cpath = package.cpath .. ";" .. execdir .. "lib/?.so;" 63 | package.cpath = package.cpath .. execdir .. "lib/loadall.so" 64 | 65 | -- Add `./?/init.lua' 66 | if ( gamedir ) then 67 | package.path = gsub( 68 | package.path, 69 | "^%./%?%.lua;", 70 | gamedir .. "/?.lua;" .. gamedir .. "/?/init.lua;" 71 | ) 72 | else 73 | package.path = gsub( 74 | package.path, 75 | "^%./%?%.lua;", 76 | execdir .. "?.lua;" 77 | ) 78 | end 79 | end 80 | 81 | local arg = arg 82 | local require = require 83 | local pairs = pairs 84 | 85 | module( "framework" ) 86 | 87 | function main() 88 | init() 89 | load( arg ) 90 | 91 | require( "framework.event" ) 92 | 93 | while ( true ) do 94 | local e = nil 95 | repeat 96 | e = framework.event.poll() 97 | if ( e ) then 98 | if ( e.type == ffi.C.SDL_QUIT or 99 | e.type == ffi.C.SDL_APP_TERMINATING ) then 100 | if ( quit() ) then 101 | if ( framework.audio and framework.audio.quit ) then 102 | framework.audio.quit() 103 | end 104 | 105 | return 106 | end 107 | end 108 | 109 | framework.event.handle( e ) 110 | end 111 | until ( e == nil ) 112 | 113 | local dt = 0 114 | if ( framework.timer ) then 115 | dt = framework.timer.step() 116 | end 117 | 118 | update( dt ) 119 | 120 | if ( framework.graphics ) then 121 | framework.graphics.origin() 122 | framework.graphics.clear( framework.graphics.getBackgroundColor() ) 123 | draw() 124 | framework.window.swap() 125 | end 126 | 127 | if ( framework.timer ) then 128 | framework.timer.sleep( 0.001 ) 129 | end 130 | end 131 | end 132 | 133 | function init() 134 | require( "framework.filesystem" ) 135 | framework.filesystem.init( arg[ -1 ] ) 136 | framework.filesystem.mount( gamedir, nil, false ) 137 | framework.filesystem.mount( execdir, nil, false ) 138 | 139 | local c = { 140 | modules = { 141 | event = true, 142 | keyboard = true, 143 | mouse = true, 144 | timer = true, 145 | graphics = true, 146 | audio = true, 147 | physics = true, 148 | sound = true, 149 | window = true 150 | }, 151 | window = { 152 | title = "", 153 | x = nil, 154 | y = nil, 155 | width = 800, 156 | height = 600, 157 | resizable = false, 158 | msaa = 0 159 | } 160 | } 161 | 162 | -- LÖVE compatibility 163 | require( "framework.love" ) 164 | 165 | if ( framework.filesystem.isFile( "conf.lua" ) ) then 166 | require( "conf" ) 167 | end 168 | 169 | if ( framework.conf ) then 170 | framework.conf( c ) 171 | end 172 | 173 | for k, v in pairs( c.modules ) do 174 | if ( v ) then require( "framework." .. k ) end 175 | end 176 | 177 | if ( c.modules.window ) then 178 | local title = c.window.title 179 | local x = c.window.x 180 | local y = c.window.y 181 | local width = c.window.width 182 | local height = c.window.height 183 | local bit = require( "bit" ) 184 | local flags = 0 185 | local glattrs = nil 186 | if ( c.window.resizable ) then 187 | flags = bit.bor( flags, ffi.C.SDL_WINDOW_RESIZABLE ) 188 | end 189 | if ( c.window.highdpi ) then 190 | flags = bit.bor( flags, ffi.C.SDL_WINDOW_ALLOW_HIGHDPI ) 191 | end 192 | if ( c.window.msaa > 0 ) then 193 | glattrs = { 194 | SDL_GL_MULTISAMPLEBUFFERS = 1, 195 | SDL_GL_MULTISAMPLESAMPLES = c.window.msaa 196 | } 197 | end 198 | framework.window.createWindow( 199 | title, x, y, width, height, flags, glattrs 200 | ) 201 | end 202 | 203 | if ( framework.filesystem.isFile( "main.lua" ) ) then 204 | require( "main" ) 205 | end 206 | end 207 | 208 | function load() 209 | end 210 | 211 | function quit() 212 | return true 213 | end 214 | 215 | function lowmemory() 216 | end 217 | 218 | function visible( visible ) 219 | end 220 | 221 | function move( x, y ) 222 | end 223 | 224 | function resize( width, height ) 225 | end 226 | 227 | function minimize() 228 | end 229 | 230 | function maximize() 231 | end 232 | 233 | function restore() 234 | end 235 | 236 | function mousefocus( focus ) 237 | end 238 | 239 | function focus( focus ) 240 | end 241 | 242 | function keypressed( key, scancode, isrepeat ) 243 | end 244 | 245 | function keyreleased( key, scancode ) 246 | end 247 | 248 | function textedited( text, start, length ) 249 | end 250 | 251 | function textinput( text ) 252 | end 253 | 254 | function mousemoved( x, y, dx, dy, istouch ) 255 | end 256 | 257 | function mousepressed( x, y, button, istouch ) 258 | end 259 | 260 | function mousereleased( x, y, button, istouch ) 261 | end 262 | 263 | function wheelmoved( x, y ) 264 | end 265 | 266 | function update( dt ) 267 | end 268 | 269 | function draw() 270 | end 271 | 272 | main() 273 | -------------------------------------------------------------------------------- /lua/framework/keyboard.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local SDL = require( "sdl" ) 8 | 9 | local ipairs = ipairs 10 | 11 | module( "framework.keyboard" ) 12 | 13 | _keyRepeat = _keyRepeat or false 14 | 15 | function isPressed( ... ) 16 | local state = SDL.SDL_GetKeyboardState( nil ) 17 | for _, key in ipairs( { ... } ) do 18 | key = SDL.SDL_GetKeyFromName( key ) 19 | key = SDL.SDL_GetScancodeFromKey( key ) 20 | if ( state[ key ] ) then return true end 21 | end 22 | return false 23 | end 24 | 25 | function isScancodePressed( ... ) 26 | local state = SDL.SDL_GetKeyboardState( nil ) 27 | for key in ipairs( { ... } ) do 28 | key = SDL.SDL_GetScancodeFromName( key ) 29 | if ( state[ key ] ) then return true end 30 | end 31 | return false 32 | end 33 | 34 | function setTextInput( enable ) 35 | if ( enable ) then 36 | SDL.SDL_StartTextInput() 37 | else 38 | SDL.SDL_StopTextInput() 39 | end 40 | end 41 | 42 | function setKeyRepeat( enable ) 43 | _keyRepeat = enable 44 | end 45 | -------------------------------------------------------------------------------- /lua/framework/mouse.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | local SDL = require( "sdl" ) 9 | 10 | local framework = framework 11 | 12 | module( "framework.mouse" ) 13 | 14 | function getPosition() 15 | local x = ffi.new( "int[1]" ) 16 | local y = ffi.new( "int[1]" ) 17 | SDL.SDL_GetMouseState( x, y ) 18 | return x[0], y[0] 19 | end 20 | 21 | function getSystemCursor( id ) 22 | if ( id == "arrow" ) then 23 | id = ffi.C.SDL_SYSTEM_CURSOR_ARROW 24 | elseif ( id == "ibeam" ) then 25 | id = ffi.C.SDL_SYSTEM_CURSOR_IBEAM 26 | elseif ( id == "wait" ) then 27 | id = ffi.C.SDL_SYSTEM_CURSOR_WAIT 28 | elseif ( id == "crosshair" ) then 29 | id = ffi.C.SDL_SYSTEM_CURSOR_CROSSHAIR 30 | elseif ( id == "waitarrow" ) then 31 | id = ffi.C.SDL_SYSTEM_CURSOR_WAITARROW 32 | elseif ( id == "sizenwse" ) then 33 | id = ffi.C.SDL_SYSTEM_CURSOR_SIZENWSE 34 | elseif ( id == "sizenesw" ) then 35 | id = ffi.C.SDL_SYSTEM_CURSOR_SIZENESW 36 | elseif ( id == "sizewe" ) then 37 | id = ffi.C.SDL_SYSTEM_CURSOR_SIZEWE 38 | elseif ( id == "sizens" ) then 39 | id = ffi.C.SDL_SYSTEM_CURSOR_SIZENS 40 | elseif ( id == "sizeall" ) then 41 | id = ffi.C.SDL_SYSTEM_CURSOR_SIZEALL 42 | elseif ( id == "no" ) then 43 | id = ffi.C.SDL_SYSTEM_CURSOR_NO 44 | elseif ( id == "hand" ) then 45 | id = ffi.C.SDL_SYSTEM_CURSOR_HAND 46 | end 47 | return SDL.SDL_CreateSystemCursor( id ) 48 | end 49 | 50 | function isVisible() 51 | return SDL.SDL_ShowCursor( -1 ) == 1 52 | end 53 | 54 | function setCursor( cursor ) 55 | if ( cursor ) then 56 | SDL.SDL_SetCursor( cursor ) 57 | else 58 | SDL.SDL_SetCursor( SDL.SDL_GetDefaultCursor() ) 59 | end 60 | end 61 | 62 | function setPosition( x, y ) 63 | SDL.SDL_WarpMouseInWindow( framework.window._window, x, y ) 64 | end 65 | 66 | function setVisible( visible ) 67 | SDL.SDL_ShowCursor( visible and 1 or 0 ) 68 | end 69 | -------------------------------------------------------------------------------- /lua/framework/physics/body.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local chipmunk = require( "chipmunk" ) 9 | local ffi = require( "ffi" ) 10 | 11 | class( "framework.physics.body" ) 12 | 13 | local body = framework.physics.body 14 | 15 | function body:body( world, x, y, type ) 16 | self._body = chipmunk.cpBodyAlloc() 17 | self._world = world 18 | self:setPosition( x, y ) 19 | setproxy( self ) 20 | end 21 | 22 | function body:applyLinearImpulse() 23 | end 24 | 25 | function body:getFixtureList() 26 | local t = {} 27 | return t 28 | end 29 | 30 | function body:getLinearVelocity() 31 | local linearVelocity = chipmunk.cpBodyGetVelocity( self._body ) 32 | return linearVelocity.x, linearVelocity.y 33 | end 34 | 35 | function body:getMass() 36 | return 0 37 | end 38 | 39 | function body:getPosition() 40 | local position = chipmunk.cpBodyGetPosition( self._body ) 41 | return position.x, position.y 42 | end 43 | 44 | function body:setFixedRotation() 45 | chipmunk.cpBodySetMoment( self._body, math.huge ) 46 | end 47 | 48 | function body:setLinearDamping( n ) 49 | end 50 | 51 | function body:setPosition( x, y ) 52 | chipmunk.cpBodySetPosition( self._body, ffi.new( "cpVect", x, y ) ) 53 | end 54 | 55 | function body:setUserData( userdata ) 56 | self._userdata = userdata 57 | end 58 | 59 | function body:__gc() 60 | end 61 | -------------------------------------------------------------------------------- /lua/framework/physics/fixture.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local chipmunk = require( "chipmunk" ) 9 | local ffi = require( "ffi" ) 10 | 11 | class( "framework.physics.fixture" ) 12 | 13 | local fixture = framework.physics.fixture 14 | 15 | function fixture:fixture( body, shape, density ) 16 | self.body = body 17 | self.shape = shape 18 | self.density = density or 1 19 | setproxy( self ) 20 | end 21 | 22 | function fixture:setFilterData( categories, mask, group ) 23 | end 24 | 25 | function fixture:setUserData( userdata ) 26 | self.userdata = userdata 27 | end 28 | 29 | function fixture:__gc() 30 | end 31 | -------------------------------------------------------------------------------- /lua/framework/physics/init.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local chipmunk = require( "chipmunk" ) 8 | 9 | local framework = framework 10 | local require = require 11 | 12 | module( "framework.physics" ) 13 | 14 | function newSpace() 15 | require( "framework.physics.space" ) 16 | local space = framework.physics.space 17 | return space() 18 | end 19 | 20 | function newBody( world, x, y, type ) 21 | require( "framework.physics.body" ) 22 | local body = framework.physics.body 23 | return body( world, x, y, type ) 24 | end 25 | 26 | function newRectangleShape( width, height ) 27 | end 28 | 29 | function newFixture( body, shape, density ) 30 | require( "framework.physics.fixture" ) 31 | local fixture = framework.physics.fixture 32 | return fixture( body, shape, density ) 33 | end 34 | -------------------------------------------------------------------------------- /lua/framework/physics/space.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local chipmunk = require( "chipmunk" ) 9 | local ffi = require( "ffi" ) 10 | 11 | class( "framework.physics.space" ) 12 | 13 | local space = framework.physics.space 14 | 15 | function space:space() 16 | self._space = chipmunk.cpSpaceNew() 17 | setproxy( self ) 18 | end 19 | 20 | function space:update( dt ) 21 | chipmunk.cpSpaceStep( self._space, dt ) 22 | end 23 | 24 | function space:__gc() 25 | end 26 | -------------------------------------------------------------------------------- /lua/framework/sound.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | require( "class" ) 8 | local SDL_sound = require( "sdl_sound" ) 9 | local AL = require( "openal" ) 10 | local SDL = require( "sdl" ) 11 | local ffi = require( "ffi" ) 12 | 13 | -- dyld: lazy symbol binding failed: Symbol not found: _Timidity_Init 14 | -- SDL_sound.Sound_Init() 15 | 16 | class( "framework.sound" ) 17 | 18 | local sound = framework.sound 19 | 20 | function sound.getAvailableDecoders() 21 | local i = 0 22 | local v = nil 23 | local decoders = SDL_sound.Sound_AvailableDecoders() 24 | local t = {} 25 | repeat 26 | v = decoders[ i ] 27 | if ( v ~= nil ) then 28 | table.insert( t, v ) 29 | end 30 | i = i + 1 31 | until ( v == nil ) 32 | return t 33 | end 34 | 35 | local function getFormat( channels, type ) 36 | local format = AL.AL_NONE 37 | 38 | if ( type == SDL.AUDIO_U8 ) then 39 | if ( channels == 1 ) then 40 | format = AL.AL_FORMAT_MONO8 41 | elseif ( channels == 2 ) then 42 | format = AL.AL_FORMAT_STEREO8 43 | end 44 | elseif ( type == SDL.AUDIO_S16LSB or type == SDL.AUDIO_S16MSB ) then 45 | if ( channels == 1 ) then 46 | format = AL.AL_FORMAT_MONO16 47 | elseif ( channels == 2 ) then 48 | format = AL.AL_FORMAT_STEREO16 49 | end 50 | end 51 | 52 | return format 53 | end 54 | 55 | function sound:sound( filename ) 56 | self.source = ffi.new( "ALuint[1]" ) 57 | AL.alGenSources( 1, self.source ) 58 | 59 | self.buffer = ffi.new( "ALuint[1]" ) 60 | AL.alGenBuffers( 1, self.buffer ) 61 | 62 | local buffer, length = framework.filesystem.read( filename ) 63 | if ( buffer == nil ) then 64 | error( length, 3 ) 65 | end 66 | local rw = SDL.SDL_RWFromMem( buffer, length ) 67 | local sample = SDL_sound.Sound_NewSample( rw, nil, nil, 10240 ) 68 | if ( sample == nil ) then 69 | error( "Could not load sound '" .. filename .. "'", 3 ) 70 | end 71 | self.sample = sample 72 | 73 | local info = sample.actual 74 | local format = getFormat( info.channels, info.format ) 75 | local size = SDL_sound.Sound_DecodeAll( sample ) 76 | local data = sample.buffer 77 | local freq = info.rate 78 | AL.alBufferData( self.buffer[0], format, data, size, freq ) 79 | 80 | setproxy( self ) 81 | end 82 | 83 | function sound:play() 84 | AL.alSourcei( self.source[0], AL.AL_BUFFER, self.buffer[0] ) 85 | AL.alSourcePlay( self.source[0] ) 86 | end 87 | 88 | function sound:stop() 89 | AL.alSourceStop( self.source[0] ) 90 | end 91 | 92 | function sound:__gc() 93 | SDL_sound.Sound_FreeSample( self.sample ) 94 | AL.alDeleteBuffers( 1, self.buffer ) 95 | AL.alDeleteSources( 1, self.source ) 96 | end 97 | -------------------------------------------------------------------------------- /lua/framework/thread.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local ffi = require( "ffi" ) 8 | 9 | module( "framework.thread" ) 10 | 11 | CriticalSection = CriticalSection or ffi.new( "CRITICAL_SECTION[1]" ) 12 | ffi.C.InitializeCriticalSection( CriticalSection[0] ) 13 | 14 | function lock() 15 | ffi.C.EnterCriticalSection( CriticalSection[0] ) 16 | end 17 | 18 | function unlock() 19 | ffi.C.LeaveCriticalSection( CriticalSection[0] ) 20 | end 21 | -------------------------------------------------------------------------------- /lua/framework/timer.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local SDL = require( "sdl" ) 8 | 9 | module( "framework.timer" ) 10 | 11 | _frames = _frames or 0 12 | _dt = _dt or 0 13 | _lastTime = _lastTime or 0 14 | _fps = _fps or 0 15 | _averageDelta = _averageDelta or 0 16 | _nextFPSUpdate = _nextFPSUpdate or 0 17 | _lastFPSUpdate = _lastFPSUpdate or 0 18 | 19 | function getAverageDelta() 20 | return _averageDelta 21 | end 22 | 23 | function getDelta() 24 | return _dt 25 | end 26 | 27 | function getFPS() 28 | return _fps 29 | end 30 | 31 | function getTime() 32 | return SDL.SDL_GetTicks() / 1000 33 | end 34 | 35 | function sleep( seconds ) 36 | SDL.SDL_Delay( seconds * 1000 ) 37 | end 38 | 39 | function step() 40 | _frames = _frames + 1 41 | 42 | local time = getTime() 43 | _dt = time - _lastTime 44 | _lastTime = time 45 | 46 | if ( _nextFPSUpdate <= time ) then 47 | _fps = _frames 48 | _averageDelta = ( ( time - _lastFPSUpdate ) / _frames ) 49 | _nextFPSUpdate = time + 1 50 | _lastFPSUpdate = time 51 | _frames = 0 52 | end 53 | 54 | return _dt 55 | end 56 | -------------------------------------------------------------------------------- /lua/framework/window.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local SDL = require( "sdl" ) 8 | local ffi = require( "ffi" ) 9 | local bit = require( "bit" ) 10 | local GL = require( "opengl" ) 11 | 12 | local pairs = pairs 13 | local framework = framework 14 | 15 | module( "framework.window" ) 16 | 17 | function createWindow( title, x, y, width, height, flags, glattrs ) 18 | x = x or SDL.SDL_WINDOWPOS_UNDEFINED 19 | y = y or SDL.SDL_WINDOWPOS_UNDEFINED 20 | 21 | local defaultFlags = bit.bor( 22 | ffi.C.SDL_WINDOW_OPENGL 23 | ) 24 | flags = bit.bor( defaultFlags, flags or 0 ) 25 | 26 | SDL.SDL_InitSubSystem( SDL.SDL_INIT_VIDEO ) 27 | SDL.SDL_GL_SetAttribute( 28 | ffi.C.SDL_GL_CONTEXT_PROFILE_MASK, 29 | ffi.C.SDL_GL_CONTEXT_PROFILE_CORE 30 | ) 31 | 32 | if ( glattrs ) then 33 | for k, v in pairs( glattrs ) do 34 | SDL.SDL_GL_SetAttribute( ffi.C[ k ], v ) 35 | end 36 | end 37 | 38 | _window = SDL.SDL_CreateWindow( title, x, y, width, height, flags ) 39 | _context = SDL.SDL_GL_CreateContext( _window ) 40 | 41 | width, height = framework.graphics.getSize() 42 | framework.graphics.setViewport( 0, 0, width, height ) 43 | GL.glEnable( GL.GL_DEPTH_TEST ) 44 | GL.glDepthFunc( GL.GL_LEQUAL ) 45 | GL.glEnable( GL.GL_BLEND ) 46 | GL.glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA ) 47 | GL.glEnable( GL.GL_TEXTURE_CUBE_MAP_SEAMLESS ) 48 | 49 | framework.graphics.createDefaultVAO() 50 | framework.graphics.createDefaultVBO() 51 | framework.graphics.setShader( "default2d" ) 52 | 53 | local font = framework.graphics.newFont( "fonts/Vera.ttf" ) 54 | framework.graphics.setFont( font ) 55 | end 56 | 57 | function getPixelScale() 58 | local gw = framework.graphics.getSize() 59 | local ww = getSize() 60 | return gw / ww 61 | end 62 | 63 | function getSize() 64 | local width = ffi.new( "int[1]" ) 65 | local height = ffi.new( "int[1]" ) 66 | SDL.SDL_GetWindowSize( framework.window._window, width, height ) 67 | return width[0], height[0] 68 | end 69 | 70 | function hasFocus() 71 | return _window and SDL.SDL_GetKeyboardFocus() == _window 72 | end 73 | 74 | function resize( width, height ) 75 | framework.graphics.setViewport( 0, 0, width, height ) 76 | framework.graphics.setOrthographicProjection( width, height ) 77 | end 78 | 79 | local fullScreenFlags = { 80 | exclusive = ffi.C.SDL_WINDOW_FULLSCREEN, 81 | desktop = ffi.C.SDL_WINDOW_FULLSCREEN_DESKTOP 82 | } 83 | 84 | function setFullscreen( fullscreen, type ) 85 | type = type or "desktop" 86 | return SDL.SDL_SetWindowFullscreen( 87 | framework.window._window, fullscreen and fullScreenFlags[ type ] or 0 88 | ) == 0 89 | end 90 | 91 | function swap() 92 | SDL.SDL_GL_SwapWindow( _window ) 93 | framework.graphics._drawCalls = 0 94 | end 95 | 96 | function toPixels( n ) 97 | return n * getPixelScale() 98 | end 99 | -------------------------------------------------------------------------------- /lua/jit/bc.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT bytecode listing module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- 8 | -- This module lists the bytecode of a Lua function. If it's loaded by -jbc 9 | -- it hooks into the parser and lists all functions of a chunk as they 10 | -- are parsed. 11 | -- 12 | -- Example usage: 13 | -- 14 | -- luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)' 15 | -- luajit -jbc=- foo.lua 16 | -- luajit -jbc=foo.list foo.lua 17 | -- 18 | -- Default output is to stderr. To redirect the output to a file, pass a 19 | -- filename as an argument (use '-' for stdout) or set the environment 20 | -- variable LUAJIT_LISTFILE. The file is overwritten every time the module 21 | -- is started. 22 | -- 23 | -- This module can also be used programmatically: 24 | -- 25 | -- local bc = require("jit.bc") 26 | -- 27 | -- local function foo() print("hello") end 28 | -- 29 | -- bc.dump(foo) --> -- BYTECODE -- [...] 30 | -- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello" 31 | -- 32 | -- local out = { 33 | -- -- Do something with each line: 34 | -- write = function(t, ...) io.write(...) end, 35 | -- close = function(t) end, 36 | -- flush = function(t) end, 37 | -- } 38 | -- bc.dump(foo, out) 39 | -- 40 | ------------------------------------------------------------------------------ 41 | 42 | -- Cache some library functions and objects. 43 | local jit = require("jit") 44 | assert(jit.version_num == 20004, "LuaJIT core/library version mismatch") 45 | local jutil = require("jit.util") 46 | local vmdef = require("jit.vmdef") 47 | local bit = require("bit") 48 | local sub, gsub, format = string.sub, string.gsub, string.format 49 | local byte, band, shr = string.byte, bit.band, bit.rshift 50 | local funcinfo, funcbc, funck = jutil.funcinfo, jutil.funcbc, jutil.funck 51 | local funcuvname = jutil.funcuvname 52 | local bcnames = vmdef.bcnames 53 | local stdout, stderr = io.stdout, io.stderr 54 | 55 | ------------------------------------------------------------------------------ 56 | 57 | local function ctlsub(c) 58 | if c == "\n" then return "\\n" 59 | elseif c == "\r" then return "\\r" 60 | elseif c == "\t" then return "\\t" 61 | else return format("\\%03d", byte(c)) 62 | end 63 | end 64 | 65 | -- Return one bytecode line. 66 | local function bcline(func, pc, prefix) 67 | local ins, m = funcbc(func, pc) 68 | if not ins then return end 69 | local ma, mb, mc = band(m, 7), band(m, 15*8), band(m, 15*128) 70 | local a = band(shr(ins, 8), 0xff) 71 | local oidx = 6*band(ins, 0xff) 72 | local op = sub(bcnames, oidx+1, oidx+6) 73 | local s = format("%04d %s %-6s %3s ", 74 | pc, prefix or " ", op, ma == 0 and "" or a) 75 | local d = shr(ins, 16) 76 | if mc == 13*128 then -- BCMjump 77 | return format("%s=> %04d\n", s, pc+d-0x7fff) 78 | end 79 | if mb ~= 0 then 80 | d = band(d, 0xff) 81 | elseif mc == 0 then 82 | return s.."\n" 83 | end 84 | local kc 85 | if mc == 10*128 then -- BCMstr 86 | kc = funck(func, -d-1) 87 | kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub)) 88 | elseif mc == 9*128 then -- BCMnum 89 | kc = funck(func, d) 90 | if op == "TSETM " then kc = kc - 2^52 end 91 | elseif mc == 12*128 then -- BCMfunc 92 | local fi = funcinfo(funck(func, -d-1)) 93 | if fi.ffid then 94 | kc = vmdef.ffnames[fi.ffid] 95 | else 96 | kc = fi.loc 97 | end 98 | elseif mc == 5*128 then -- BCMuv 99 | kc = funcuvname(func, d) 100 | end 101 | if ma == 5 then -- BCMuv 102 | local ka = funcuvname(func, a) 103 | if kc then kc = ka.." ; "..kc else kc = ka end 104 | end 105 | if mb ~= 0 then 106 | local b = shr(ins, 24) 107 | if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end 108 | return format("%s%3d %3d\n", s, b, d) 109 | end 110 | if kc then return format("%s%3d ; %s\n", s, d, kc) end 111 | if mc == 7*128 and d > 32767 then d = d - 65536 end -- BCMlits 112 | return format("%s%3d\n", s, d) 113 | end 114 | 115 | -- Collect branch targets of a function. 116 | local function bctargets(func) 117 | local target = {} 118 | for pc=1,1000000000 do 119 | local ins, m = funcbc(func, pc) 120 | if not ins then break end 121 | if band(m, 15*128) == 13*128 then target[pc+shr(ins, 16)-0x7fff] = true end 122 | end 123 | return target 124 | end 125 | 126 | -- Dump bytecode instructions of a function. 127 | local function bcdump(func, out, all) 128 | if not out then out = stdout end 129 | local fi = funcinfo(func) 130 | if all and fi.children then 131 | for n=-1,-1000000000,-1 do 132 | local k = funck(func, n) 133 | if not k then break end 134 | if type(k) == "proto" then bcdump(k, out, true) end 135 | end 136 | end 137 | out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined)) 138 | local target = bctargets(func) 139 | for pc=1,1000000000 do 140 | local s = bcline(func, pc, target[pc] and "=>") 141 | if not s then break end 142 | out:write(s) 143 | end 144 | out:write("\n") 145 | out:flush() 146 | end 147 | 148 | ------------------------------------------------------------------------------ 149 | 150 | -- Active flag and output file handle. 151 | local active, out 152 | 153 | -- List handler. 154 | local function h_list(func) 155 | return bcdump(func, out) 156 | end 157 | 158 | -- Detach list handler. 159 | local function bclistoff() 160 | if active then 161 | active = false 162 | jit.attach(h_list) 163 | if out and out ~= stdout and out ~= stderr then out:close() end 164 | out = nil 165 | end 166 | end 167 | 168 | -- Open the output file and attach list handler. 169 | local function bcliston(outfile) 170 | if active then bclistoff() end 171 | if not outfile then outfile = os.getenv("LUAJIT_LISTFILE") end 172 | if outfile then 173 | out = outfile == "-" and stdout or assert(io.open(outfile, "w")) 174 | else 175 | out = stderr 176 | end 177 | jit.attach(h_list, "bc") 178 | active = true 179 | end 180 | 181 | -- Public module functions. 182 | module(...) 183 | 184 | line = bcline 185 | dump = bcdump 186 | targets = bctargets 187 | 188 | on = bcliston 189 | off = bclistoff 190 | start = bcliston -- For -j command line option. 191 | 192 | -------------------------------------------------------------------------------- /lua/jit/dis_mipsel.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT MIPSEL disassembler wrapper module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- This module just exports the little-endian functions from the 8 | -- MIPS disassembler module. All the interesting stuff is there. 9 | ------------------------------------------------------------------------------ 10 | 11 | local require = require 12 | 13 | module(...) 14 | 15 | local dis_mips = require(_PACKAGE.."dis_mips") 16 | 17 | create = dis_mips.create_el 18 | disass = dis_mips.disass_el 19 | regname = dis_mips.regname 20 | 21 | -------------------------------------------------------------------------------- /lua/jit/dis_x64.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT x64 disassembler wrapper module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- This module just exports the 64 bit functions from the combined 8 | -- x86/x64 disassembler module. All the interesting stuff is there. 9 | ------------------------------------------------------------------------------ 10 | 11 | local require = require 12 | 13 | module(...) 14 | 15 | local dis_x86 = require(_PACKAGE.."dis_x86") 16 | 17 | create = dis_x86.create64 18 | disass = dis_x86.disass64 19 | regname = dis_x86.regname64 20 | 21 | -------------------------------------------------------------------------------- /lua/jit/v.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- Verbose mode of the LuaJIT compiler. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- 8 | -- This module shows verbose information about the progress of the 9 | -- JIT compiler. It prints one line for each generated trace. This module 10 | -- is useful to see which code has been compiled or where the compiler 11 | -- punts and falls back to the interpreter. 12 | -- 13 | -- Example usage: 14 | -- 15 | -- luajit -jv -e "for i=1,1000 do for j=1,1000 do end end" 16 | -- luajit -jv=myapp.out myapp.lua 17 | -- 18 | -- Default output is to stderr. To redirect the output to a file, pass a 19 | -- filename as an argument (use '-' for stdout) or set the environment 20 | -- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the 21 | -- module is started. 22 | -- 23 | -- The output from the first example should look like this: 24 | -- 25 | -- [TRACE 1 (command line):1 loop] 26 | -- [TRACE 2 (1/3) (command line):1 -> 1] 27 | -- 28 | -- The first number in each line is the internal trace number. Next are 29 | -- the file name ('(command line)') and the line number (':1') where the 30 | -- trace has started. Side traces also show the parent trace number and 31 | -- the exit number where they are attached to in parentheses ('(1/3)'). 32 | -- An arrow at the end shows where the trace links to ('-> 1'), unless 33 | -- it loops to itself. 34 | -- 35 | -- In this case the inner loop gets hot and is traced first, generating 36 | -- a root trace. Then the last exit from the 1st trace gets hot, too, 37 | -- and triggers generation of the 2nd trace. The side trace follows the 38 | -- path along the outer loop and *around* the inner loop, back to its 39 | -- start, and then links to the 1st trace. Yes, this may seem unusual, 40 | -- if you know how traditional compilers work. Trace compilers are full 41 | -- of surprises like this -- have fun! :-) 42 | -- 43 | -- Aborted traces are shown like this: 44 | -- 45 | -- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50] 46 | -- 47 | -- Don't worry -- trace aborts are quite common, even in programs which 48 | -- can be fully compiled. The compiler may retry several times until it 49 | -- finds a suitable trace. 50 | -- 51 | -- Of course this doesn't work with features that are not-yet-implemented 52 | -- (NYI error messages). The VM simply falls back to the interpreter. This 53 | -- may not matter at all if the particular trace is not very high up in 54 | -- the CPU usage profile. Oh, and the interpreter is quite fast, too. 55 | -- 56 | -- Also check out the -jdump module, which prints all the gory details. 57 | -- 58 | ------------------------------------------------------------------------------ 59 | 60 | -- Cache some library functions and objects. 61 | local jit = require("jit") 62 | assert(jit.version_num == 20004, "LuaJIT core/library version mismatch") 63 | local jutil = require("jit.util") 64 | local vmdef = require("jit.vmdef") 65 | local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo 66 | local type, format = type, string.format 67 | local stdout, stderr = io.stdout, io.stderr 68 | 69 | -- Active flag and output file handle. 70 | local active, out 71 | 72 | ------------------------------------------------------------------------------ 73 | 74 | local startloc, startex 75 | 76 | local function fmtfunc(func, pc) 77 | local fi = funcinfo(func, pc) 78 | if fi.loc then 79 | return fi.loc 80 | elseif fi.ffid then 81 | return vmdef.ffnames[fi.ffid] 82 | elseif fi.addr then 83 | return format("C:%x", fi.addr) 84 | else 85 | return "(?)" 86 | end 87 | end 88 | 89 | -- Format trace error message. 90 | local function fmterr(err, info) 91 | if type(err) == "number" then 92 | if type(info) == "function" then info = fmtfunc(info) end 93 | err = format(vmdef.traceerr[err], info) 94 | end 95 | return err 96 | end 97 | 98 | -- Dump trace states. 99 | local function dump_trace(what, tr, func, pc, otr, oex) 100 | if what == "start" then 101 | startloc = fmtfunc(func, pc) 102 | startex = otr and "("..otr.."/"..oex..") " or "" 103 | else 104 | if what == "abort" then 105 | local loc = fmtfunc(func, pc) 106 | if loc ~= startloc then 107 | out:write(format("[TRACE --- %s%s -- %s at %s]\n", 108 | startex, startloc, fmterr(otr, oex), loc)) 109 | else 110 | out:write(format("[TRACE --- %s%s -- %s]\n", 111 | startex, startloc, fmterr(otr, oex))) 112 | end 113 | elseif what == "stop" then 114 | local info = traceinfo(tr) 115 | local link, ltype = info.link, info.linktype 116 | if ltype == "interpreter" then 117 | out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n", 118 | tr, startex, startloc)) 119 | elseif link == tr or link == 0 then 120 | out:write(format("[TRACE %3s %s%s %s]\n", 121 | tr, startex, startloc, ltype)) 122 | elseif ltype == "root" then 123 | out:write(format("[TRACE %3s %s%s -> %d]\n", 124 | tr, startex, startloc, link)) 125 | else 126 | out:write(format("[TRACE %3s %s%s -> %d %s]\n", 127 | tr, startex, startloc, link, ltype)) 128 | end 129 | else 130 | out:write(format("[TRACE %s]\n", what)) 131 | end 132 | out:flush() 133 | end 134 | end 135 | 136 | ------------------------------------------------------------------------------ 137 | 138 | -- Detach dump handlers. 139 | local function dumpoff() 140 | if active then 141 | active = false 142 | jit.attach(dump_trace) 143 | if out and out ~= stdout and out ~= stderr then out:close() end 144 | out = nil 145 | end 146 | end 147 | 148 | -- Open the output file and attach dump handlers. 149 | local function dumpon(outfile) 150 | if active then dumpoff() end 151 | if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end 152 | if outfile then 153 | out = outfile == "-" and stdout or assert(io.open(outfile, "w")) 154 | else 155 | out = stderr 156 | end 157 | jit.attach(dump_trace, "trace") 158 | active = true 159 | end 160 | 161 | -- Public module functions. 162 | module(...) 163 | 164 | on = dumpon 165 | off = dumpoff 166 | start = dumpon -- For -j command line option. 167 | 168 | -------------------------------------------------------------------------------- /lua51.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/lua51.dll -------------------------------------------------------------------------------- /luajit.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/luajit.exe -------------------------------------------------------------------------------- /main.lua: -------------------------------------------------------------------------------- 1 | --=========== Copyright © 2020, Planimeter, All rights reserved. ===========-- 2 | -- 3 | -- Purpose: 4 | -- 5 | --==========================================================================-- 6 | 7 | local kazmath = require( "kazmath" ) 8 | local ffi = require( "ffi" ) 9 | 10 | local faces = { 11 | "right", 12 | "left", 13 | "top", 14 | "bottom", 15 | "front", 16 | "back" 17 | } 18 | 19 | local function getCubemap( filename, mipmapLevels ) 20 | local t = {} 21 | for i = 0, mipmapLevels - 1 do 22 | for j = 1, #faces do 23 | local face = faces[ j ] 24 | local filename = string.format( filename, face, i ) 25 | table.insert( t, { faces[ j ], filename } ) 26 | end 27 | end 28 | return t 29 | end 30 | 31 | function framework.load( arg ) 32 | -- Set glTF 2.0 physically-based rendering shader 33 | framework.graphics.setShader( "gltfpbr" ) 34 | 35 | -- Create cube maps 36 | diffuseCubemap = framework.graphics.newCubemap( 37 | "diffuse", 38 | getCubemap( "textures/papermill/diffuse/diffuse_%s_%u.jpg", 1 ) 39 | ) 40 | 41 | specularCubemap = framework.graphics.newCubemap( 42 | "specular", 43 | getCubemap( "textures/papermill/specular/specular_%s_%u.jpg", 10 ) 44 | ) 45 | 46 | -- View matrix 47 | framework.graphics.lookAt( 48 | 0, 0, 4, 49 | 0, 0, 0, 50 | 0, 1, 0 51 | ) 52 | 53 | -- Load scene 54 | helmet = framework.graphics.newModel( 55 | "models/DamagedHelmet/gltf/DamagedHelmet.gltf" 56 | ) 57 | 58 | -- Set background color 59 | framework.graphics.setBackgroundColor( { 51, 51, 51, 1 } ) 60 | 61 | -- Light 62 | local rotation = math.rad( 75 ) 63 | local pitch = math.rad( 40 ) 64 | framework.graphics.setLightDirection( { 65 | math.sin( rotation ) * math.cos( pitch ), 66 | math.sin( pitch ), 67 | math.cos( rotation ) * math.cos( pitch ) 68 | } ) 69 | end 70 | 71 | function framework.update( dt ) 72 | end 73 | 74 | --[[ ***** Mouse Controls ***** ]] 75 | local mouseDown = false 76 | local roll = math.pi 77 | local pitch = 0 78 | local translate = 4 79 | 80 | function framework.draw() 81 | local width, height = framework.graphics.getSize() 82 | framework.graphics.setPerspectiveProjection( 45, width / height, 0.01, 100 ) 83 | 84 | -- set up the camera position and view matrix 85 | framework.graphics.setCameraPosition( { 86 | -translate * math.sin( roll ) * math.cos( -pitch ), 87 | -translate * math.sin( -pitch ), 88 | translate * math.cos( roll ) * math.cos( -pitch ) 89 | } ) 90 | 91 | -- Update view matrix 92 | -- roll, pitch and translate are all globals. 93 | local xRotation = ffi.new( "kmMat4" ) 94 | kazmath.kmMat4RotationY( xRotation, roll ) 95 | local yRotation = ffi.new( "kmMat4" ) 96 | kazmath.kmMat4RotationX( yRotation, pitch ) 97 | local mode = framework.graphics.getMatrixMode() 98 | framework.graphics.setMatrixMode( "view" ) 99 | framework.graphics.push() 100 | local mat4 = framework.graphics.getTransformation() 101 | kazmath.kmMat4Multiply( mat4, yRotation, xRotation ) 102 | mat4.mat[14] = -translate 103 | framework.graphics.draw( helmet ) 104 | framework.graphics.pop() 105 | framework.graphics.setMatrixMode( mode ) 106 | end 107 | 108 | function framework.mousepressed( x, y, button, istouch ) 109 | mouseDown = true 110 | end 111 | 112 | function framework.mousereleased( x, y, button, istouch ) 113 | mouseDown = false 114 | end 115 | 116 | function framework.mousemoved( x, y, dx, dy, istouch ) 117 | if ( not mouseDown ) then 118 | return 119 | end 120 | roll = roll + ( dx / 100 ) 121 | pitch = pitch + ( dy / 100 ) 122 | end 123 | 124 | local wheelSpeed = 1.04 125 | function framework.wheelmoved( x, y ) 126 | if ( y > 0 ) then 127 | translate = translate * wheelSpeed 128 | else 129 | translate = translate / wheelSpeed 130 | end 131 | end 132 | -------------------------------------------------------------------------------- /models/DamagedHelmet/LICENSE.md: -------------------------------------------------------------------------------- 1 | Battle Damaged Sci-fi Helmet - PBR by [theblueturtle_](https://sketchfab.com/theblueturtle_), published under 2 | a Creative Commons Attribution-NonCommercial license 3 | 4 | https://sketchfab.com/models/b81008d513954189a063ff901f7abfe4 5 | -------------------------------------------------------------------------------- /models/DamagedHelmet/glTF/DamagedHelmet.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/models/DamagedHelmet/glTF/DamagedHelmet.bin -------------------------------------------------------------------------------- /models/DamagedHelmet/glTF/DamagedHelmet.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "accessors" : [ 3 | { 4 | "bufferView" : 0, 5 | "componentType" : 5123, 6 | "count" : 46356, 7 | "max" : [ 8 | 14358 9 | ], 10 | "min" : [ 11 | 0 12 | ], 13 | "type" : "SCALAR" 14 | }, 15 | { 16 | "bufferView" : 1, 17 | "componentType" : 5126, 18 | "count" : 14359, 19 | "max" : [ 20 | 0.9449769854545593, 21 | 1.0, 22 | 0.9009739756584167 23 | ], 24 | "min" : [ 25 | -0.9449769854545593, 26 | -1.0, 27 | -0.9009950160980225 28 | ], 29 | "type" : "VEC3" 30 | }, 31 | { 32 | "bufferView" : 2, 33 | "componentType" : 5126, 34 | "count" : 14359, 35 | "max" : [ 36 | 1.0, 37 | 1.0, 38 | 1.0 39 | ], 40 | "min" : [ 41 | -1.0, 42 | -1.0, 43 | -1.0 44 | ], 45 | "type" : "VEC3" 46 | }, 47 | { 48 | "bufferView" : 3, 49 | "componentType" : 5126, 50 | "count" : 14359, 51 | "max" : [ 52 | 0.9999759793281555, 53 | 1.998665988445282 54 | ], 55 | "min" : [ 56 | 0.002448640065267682, 57 | 1.0005531199858524 58 | ], 59 | "type" : "VEC2" 60 | } 61 | ], 62 | "asset" : { 63 | "generator" : "Khronos Blender glTF 2.0 exporter", 64 | "version" : "2.0" 65 | }, 66 | "bufferViews" : [ 67 | { 68 | "buffer" : 0, 69 | "byteLength" : 92712, 70 | "byteOffset" : 0, 71 | "target" : 34963 72 | }, 73 | { 74 | "buffer" : 0, 75 | "byteLength" : 172308, 76 | "byteOffset" : 92712, 77 | "target" : 34962 78 | }, 79 | { 80 | "buffer" : 0, 81 | "byteLength" : 172308, 82 | "byteOffset" : 265020, 83 | "target" : 34962 84 | }, 85 | { 86 | "buffer" : 0, 87 | "byteLength" : 114872, 88 | "byteOffset" : 437328, 89 | "target" : 34962 90 | } 91 | ], 92 | "buffers" : [ 93 | { 94 | "byteLength" : 552200, 95 | "uri" : "DamagedHelmet.bin" 96 | } 97 | ], 98 | "images" : [ 99 | { 100 | "uri" : "Default_albedo.jpg" 101 | }, 102 | { 103 | "uri" : "Default_normal.jpg" 104 | }, 105 | { 106 | "uri" : "Default_metalRoughness.jpg" 107 | }, 108 | { 109 | "uri" : "Default_emissive.jpg" 110 | }, 111 | { 112 | "uri" : "Default_AO.jpg" 113 | } 114 | ], 115 | "materials" : [ 116 | { 117 | "emissiveFactor" : [ 118 | 1.0, 119 | 1.0, 120 | 1.0 121 | ], 122 | "emissiveTexture" : { 123 | "index" : 3 124 | }, 125 | "name" : "glTF Material", 126 | "normalTexture" : { 127 | "index" : 1 128 | }, 129 | "occlusionTexture" : { 130 | "index" : 4 131 | }, 132 | "pbrMetallicRoughness" : { 133 | "baseColorTexture" : { 134 | "index" : 0 135 | }, 136 | "metallicRoughnessTexture" : { 137 | "index" : 2 138 | } 139 | } 140 | } 141 | ], 142 | "meshes" : [ 143 | { 144 | "name" : "mesh_helmet_LP_13930damagedHelmet", 145 | "primitives" : [ 146 | { 147 | "attributes" : { 148 | "NORMAL" : 2, 149 | "POSITION" : 1, 150 | "TEXCOORD_0" : 3 151 | }, 152 | "indices" : 0, 153 | "material" : 0 154 | } 155 | ] 156 | } 157 | ], 158 | "nodes" : [ 159 | { 160 | "mesh" : 0, 161 | "name" : "node_damagedHelmet_-6514", 162 | "rotation" : [ 163 | 0.7071068286895752, 164 | 0.0, 165 | -0.0, 166 | 0.7071068286895752 167 | ] 168 | } 169 | ], 170 | "samplers" : [ 171 | {} 172 | ], 173 | "scene" : 0, 174 | "scenes" : [ 175 | { 176 | "name" : "Scene", 177 | "nodes" : [ 178 | 0 179 | ] 180 | } 181 | ], 182 | "textures" : [ 183 | { 184 | "sampler" : 0, 185 | "source" : 0 186 | }, 187 | { 188 | "sampler" : 0, 189 | "source" : 1 190 | }, 191 | { 192 | "sampler" : 0, 193 | "source" : 2 194 | }, 195 | { 196 | "sampler" : 0, 197 | "source" : 3 198 | }, 199 | { 200 | "sampler" : 0, 201 | "source" : 4 202 | } 203 | ] 204 | } 205 | -------------------------------------------------------------------------------- /models/DamagedHelmet/glTF/Default_AO.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/models/DamagedHelmet/glTF/Default_AO.jpg -------------------------------------------------------------------------------- /models/DamagedHelmet/glTF/Default_albedo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/models/DamagedHelmet/glTF/Default_albedo.jpg -------------------------------------------------------------------------------- /models/DamagedHelmet/glTF/Default_emissive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/models/DamagedHelmet/glTF/Default_emissive.jpg -------------------------------------------------------------------------------- /models/DamagedHelmet/glTF/Default_metalRoughness.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/models/DamagedHelmet/glTF/Default_metalRoughness.jpg -------------------------------------------------------------------------------- /models/DamagedHelmet/glTF/Default_normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Planimeter/game-framework/aec431ec8877e96e3e3ee70769b9e3471e232fa3/models/DamagedHelmet/glTF/Default_normal.jpg -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |