├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── charset_cp437.h ├── charset_cp936.h ├── rogue.c └── test.lua /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "SDL"] 2 | path = SDL 3 | url = https://github.com/libsdl-org/SDL.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 云风 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | LUA_INC=-I/usr/local/include 2 | LUA_LIB=-L/usr/local/bin -llua54 3 | SDL_INC=-ISDL/include 4 | SDL_LIB=-L. -lSDL2 5 | 6 | all : rogue.dll 7 | 8 | rogue.dll : rogue.c 9 | gcc -Wall -O2 --shared -o $@ $^ $(LUA_INC) $(LUA_LIB) $(SDL_INC) $(SDL_LIB) 10 | 11 | clean : 12 | rm -f rogue.dll 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Lua Rogue 2 | ========= 3 | 4 | A small lua library for roguelike games. 5 | 6 | Build 7 | ===== 8 | 9 | Compile rogue.c and link with lua54.dll and SDL2.dll. 10 | 11 | You can download SDL2.dll from https://github.com/libsdl-org/SDL/releases, or build by yourself. 12 | 13 | How to Use 14 | ========== 15 | 16 | See test.lua 17 | 18 | Init SDL first, 19 | 20 | ```lua 21 | local c = require "rogue.core" 22 | 23 | c.init { 24 | title = "测试", 25 | width = 80, 26 | height = 25, 27 | fps = 25, 28 | resizeable = true, 29 | } 30 | ``` 31 | 32 | The mainloop could be 33 | 34 | ```lua 35 | local function dispatch(name, ...) 36 | if name then 37 | return not EVENT[name](...) 38 | else 39 | return true 40 | end 41 | end 42 | 43 | while dispatch(c.event()) do 44 | -- do something 45 | c.frame() 46 | end 47 | 48 | ``` 49 | 50 | The event can be "QUIT" , "KEY" , "MOTION", "BUTTON" . 51 | 52 | About Sprite 53 | ============ 54 | 55 | The sprite is an ascii art rectangle. You can create a sprite by 56 | 57 | ```lua 58 | local s = c.sprite { 59 | ".-----.", 60 | "| ^ ^ |", 61 | "| - |", 62 | ".-----.", 63 | color = 0xff0000, 64 | background = 0, 65 | transparency = '.', 66 | layer = 1, 67 | kx = 0, 68 | ky = 0, 69 | } 70 | ``` 71 | 72 | The layer is from 0 to 255, the larger will cover the lower. If two sprites intersected with the same layer, the behaviour is undefined. 73 | 74 | * sprite:clone([visible]) Clone a sprite 75 | * sprite:setpos(x,y) Move the sprite to (x,y) 76 | * sprite:color(color) Change the color 77 | * sprite:text(string) Replace the sprite with text. 78 | * sprite:visible(true/false) Show/Hide the sprite 79 | -------------------------------------------------------------------------------- /charset_cp437.h: -------------------------------------------------------------------------------- 1 | // From https://int10h.org/oldschool-pc-fonts 2 | // Font Px437 DOS/V re. JPN12 3 | static const uint8_t uni6x12_cp437[] = { 4 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 5 | 0x00,0x38,0x44,0x44,0x6c,0x44,0x44,0x7c,0x54,0x44,0x38,0x00, 6 | 0x00,0x38,0x7c,0x7c,0x54,0x7c,0x7c,0x44,0x6c,0x7c,0x38,0x00, 7 | 0x00,0x00,0x28,0x7c,0x7c,0x7c,0x38,0x38,0x10,0x10,0x00,0x00, 8 | 0x00,0x10,0x10,0x38,0x38,0x7c,0x7c,0x38,0x38,0x10,0x10,0x00, 9 | 0x00,0x00,0x10,0x38,0x38,0x10,0x7c,0x7c,0x54,0x10,0x38,0x00, 10 | 0x00,0x00,0x10,0x10,0x38,0x38,0x7c,0x7c,0x54,0x10,0x38,0x00, 11 | 0x00,0x00,0x00,0x00,0x30,0x78,0x78,0x30,0x00,0x00,0x00,0x00, 12 | 0xfc,0xfc,0xfc,0xfc,0xcc,0x84,0x84,0xcc,0xfc,0xfc,0xfc,0xfc, 13 | 0x00,0x00,0x00,0x00,0x30,0x48,0x48,0x30,0x00,0x00,0x00,0x00, 14 | 0xfc,0xfc,0xfc,0xfc,0xcc,0xb4,0xb4,0xcc,0xfc,0xfc,0xfc,0xfc, 15 | 0x00,0x1c,0x0c,0x14,0x10,0x38,0x44,0x44,0x44,0x44,0x38,0x00, 16 | 0x00,0x38,0x44,0x44,0x44,0x44,0x38,0x10,0x7c,0x10,0x10,0x00, 17 | 0x00,0x10,0x18,0x18,0x14,0x14,0x10,0x10,0x30,0x70,0x60,0x00, 18 | 0x00,0x30,0x2c,0x34,0x2c,0x24,0x24,0xe4,0xc4,0x1c,0x18,0x00, 19 | 0x00,0x10,0x54,0x38,0x38,0x6c,0x38,0x38,0x54,0x10,0x00,0x00, 20 | 0x00,0x00,0x40,0x60,0x70,0x78,0x7c,0x78,0x70,0x60,0x40,0x00, 21 | 0x00,0x00,0x04,0x0c,0x1c,0x3c,0x7c,0x3c,0x1c,0x0c,0x04,0x00, 22 | 0x00,0x10,0x38,0x54,0x10,0x10,0x10,0x10,0x54,0x38,0x10,0x00, 23 | 0x00,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x00,0x48,0x48,0x00, 24 | 0x00,0x3c,0x74,0x74,0x74,0x34,0x14,0x14,0x14,0x14,0x14,0x00, 25 | 0x00,0x38,0x44,0x40,0x38,0x44,0x44,0x38,0x04,0x44,0x38,0x00, 26 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x7c,0x7c, 27 | 0x00,0x10,0x38,0x54,0x10,0x10,0x10,0x10,0x54,0x38,0x10,0x7c, 28 | 0x00,0x10,0x38,0x54,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00, 29 | 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x54,0x38,0x10,0x00, 30 | 0x00,0x00,0x00,0x00,0x10,0x08,0xfc,0x08,0x10,0x00,0x00,0x00, 31 | 0x00,0x00,0x00,0x00,0x20,0x40,0xfc,0x40,0x20,0x00,0x00,0x00, 32 | 0x00,0x00,0x00,0x00,0x00,0x7c,0x40,0x40,0x00,0x00,0x00,0x00, 33 | 0x00,0x00,0x00,0x00,0x48,0x84,0xfc,0x84,0x48,0x00,0x00,0x00, 34 | 0x00,0x00,0x00,0x10,0x10,0x38,0x38,0x7c,0x7c,0x00,0x00,0x00, 35 | 0x00,0x00,0x00,0x7c,0x7c,0x38,0x38,0x10,0x10,0x00,0x00,0x00, 36 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 37 | 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x10,0x00, 38 | 0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 39 | 0x00,0x08,0x28,0x2c,0x38,0x68,0x2c,0x38,0x68,0x28,0x20,0x00, 40 | 0x10,0x10,0x38,0x54,0x50,0x30,0x18,0x14,0x54,0x38,0x10,0x10, 41 | 0x00,0x70,0x50,0x74,0x08,0x10,0x10,0x20,0x5c,0x14,0x1c,0x00, 42 | 0x00,0x30,0x48,0x48,0x30,0x30,0x54,0x48,0x48,0x4c,0x34,0x00, 43 | 0x00,0x30,0x30,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 44 | 0x00,0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x20,0x20,0x10,0x00, 45 | 0x00,0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x00, 46 | 0x00,0x00,0x00,0x10,0x54,0x38,0x10,0x38,0x54,0x10,0x00,0x00, 47 | 0x00,0x00,0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x00,0x00,0x00, 48 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x10,0x20, 49 | 0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00, 50 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00, 51 | 0x00,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00, 52 | 0x00,0x38,0x44,0x44,0x44,0x54,0x54,0x44,0x44,0x44,0x38,0x00, 53 | 0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00, 54 | 0x00,0x38,0x44,0x44,0x04,0x08,0x10,0x20,0x40,0x40,0x7c,0x00, 55 | 0x00,0x38,0x44,0x04,0x04,0x38,0x04,0x04,0x04,0x44,0x38,0x00, 56 | 0x00,0x18,0x18,0x28,0x28,0x28,0x48,0x48,0x7c,0x08,0x08,0x00, 57 | 0x00,0x7c,0x40,0x40,0x40,0x78,0x04,0x04,0x04,0x44,0x38,0x00, 58 | 0x00,0x38,0x44,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x38,0x00, 59 | 0x00,0x7c,0x04,0x04,0x08,0x08,0x08,0x10,0x10,0x20,0x20,0x00, 60 | 0x00,0x38,0x44,0x44,0x44,0x38,0x44,0x44,0x44,0x44,0x38,0x00, 61 | 0x00,0x38,0x44,0x44,0x44,0x44,0x3c,0x04,0x04,0x44,0x38,0x00, 62 | 0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x00,0x00,0x00, 63 | 0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x10,0x20,0x00, 64 | 0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00, 65 | 0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x78,0x00,0x00,0x00,0x00, 66 | 0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00, 67 | 0x00,0x38,0x44,0x44,0x08,0x10,0x10,0x10,0x00,0x10,0x10,0x00, 68 | 0x00,0x38,0x44,0x44,0x5c,0x54,0x54,0x54,0x5c,0x40,0x3c,0x00, 69 | 0x00,0x10,0x28,0x44,0x44,0x44,0x44,0x7c,0x44,0x44,0x44,0x00, 70 | 0x00,0x78,0x44,0x44,0x44,0x78,0x44,0x44,0x44,0x44,0x78,0x00, 71 | 0x00,0x38,0x44,0x44,0x40,0x40,0x40,0x40,0x44,0x44,0x38,0x00, 72 | 0x00,0x70,0x48,0x44,0x44,0x44,0x44,0x44,0x44,0x48,0x70,0x00, 73 | 0x00,0x7c,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x40,0x7c,0x00, 74 | 0x00,0x7c,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x40,0x40,0x00, 75 | 0x00,0x38,0x44,0x44,0x40,0x40,0x5c,0x44,0x44,0x44,0x3c,0x00, 76 | 0x00,0x44,0x44,0x44,0x44,0x7c,0x44,0x44,0x44,0x44,0x44,0x00, 77 | 0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00, 78 | 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x48,0x30,0x00, 79 | 0x00,0x44,0x48,0x48,0x50,0x60,0x50,0x50,0x48,0x48,0x44,0x00, 80 | 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7c,0x00, 81 | 0x00,0x44,0x44,0x6c,0x6c,0x54,0x54,0x44,0x44,0x44,0x44,0x00, 82 | 0x00,0x44,0x44,0x64,0x64,0x54,0x54,0x4c,0x4c,0x44,0x44,0x00, 83 | 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00, 84 | 0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x40,0x40,0x40,0x40,0x00, 85 | 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x54,0x4c,0x3c,0x00, 86 | 0x00,0x78,0x44,0x44,0x44,0x78,0x50,0x48,0x48,0x44,0x44,0x00, 87 | 0x00,0x38,0x44,0x44,0x40,0x30,0x08,0x04,0x44,0x44,0x38,0x00, 88 | 0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00, 89 | 0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00, 90 | 0x00,0x44,0x44,0x44,0x44,0x28,0x28,0x28,0x28,0x10,0x10,0x00, 91 | 0x00,0x44,0x44,0x54,0x54,0x54,0x54,0x54,0x28,0x28,0x28,0x00, 92 | 0x00,0x44,0x44,0x28,0x28,0x10,0x10,0x28,0x28,0x44,0x44,0x00, 93 | 0x00,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x10,0x10,0x10,0x00, 94 | 0x00,0x7c,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x7c,0x00, 95 | 0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00, 96 | 0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x00, 97 | 0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00, 98 | 0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 99 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c, 100 | 0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 101 | 0x00,0x00,0x00,0x00,0x78,0x04,0x3c,0x44,0x44,0x44,0x3c,0x00, 102 | 0x00,0x00,0x40,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x78,0x00, 103 | 0x00,0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x00, 104 | 0x00,0x04,0x04,0x04,0x3c,0x44,0x44,0x44,0x44,0x44,0x3c,0x00, 105 | 0x00,0x00,0x00,0x00,0x38,0x44,0x44,0x7c,0x40,0x44,0x38,0x00, 106 | 0x00,0x0c,0x10,0x10,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x00, 107 | 0x00,0x00,0x00,0x00,0x3c,0x44,0x44,0x44,0x3c,0x04,0x44,0x38, 108 | 0x00,0x40,0x40,0x40,0x78,0x44,0x44,0x44,0x44,0x44,0x44,0x00, 109 | 0x00,0x10,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00, 110 | 0x00,0x08,0x08,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x48,0x30, 111 | 0x00,0x40,0x40,0x40,0x44,0x48,0x50,0x70,0x48,0x48,0x44,0x00, 112 | 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x18,0x00, 113 | 0x00,0x00,0x00,0x00,0x78,0x54,0x54,0x54,0x54,0x54,0x54,0x00, 114 | 0x00,0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x44,0x00, 115 | 0x00,0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00, 116 | 0x00,0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x78,0x40,0x40, 117 | 0x00,0x00,0x00,0x00,0x3c,0x44,0x44,0x44,0x44,0x3c,0x04,0x04, 118 | 0x00,0x00,0x00,0x00,0x5c,0x60,0x40,0x40,0x40,0x40,0x40,0x00, 119 | 0x00,0x00,0x00,0x00,0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00, 120 | 0x00,0x10,0x10,0x10,0x7c,0x10,0x10,0x10,0x10,0x10,0x0c,0x00, 121 | 0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x3c,0x00, 122 | 0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x28,0x28,0x28,0x10,0x00, 123 | 0x00,0x00,0x00,0x00,0x54,0x54,0x54,0x54,0x54,0x28,0x28,0x00, 124 | 0x00,0x00,0x00,0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00, 125 | 0x00,0x00,0x00,0x00,0x44,0x44,0x28,0x28,0x10,0x10,0x20,0x20, 126 | 0x00,0x00,0x00,0x00,0x7c,0x04,0x08,0x10,0x20,0x40,0x7c,0x00, 127 | 0x00,0x08,0x10,0x10,0x10,0x10,0x20,0x10,0x10,0x10,0x10,0x08, 128 | 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 129 | 0x00,0x40,0x20,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0x40, 130 | 0x00,0x00,0x00,0x00,0x20,0x54,0x08,0x00,0x00,0x00,0x00,0x00, 131 | 0x00,0x00,0x00,0x10,0x10,0x28,0x28,0x44,0x44,0x7c,0x00,0x00, 132 | 0x00,0x38,0x44,0x44,0x40,0x40,0x40,0x40,0x44,0x44,0x38,0x70, 133 | 0x00,0x44,0x44,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x3c,0x00, 134 | 0x00,0x08,0x10,0x00,0x38,0x44,0x44,0x7c,0x40,0x44,0x38,0x00, 135 | 0x00,0x10,0x28,0x00,0x78,0x04,0x3c,0x44,0x44,0x44,0x3c,0x00, 136 | 0x00,0x48,0x48,0x00,0x78,0x04,0x3c,0x44,0x44,0x44,0x3c,0x00, 137 | 0x00,0x20,0x10,0x00,0x78,0x04,0x3c,0x44,0x44,0x44,0x3c,0x00, 138 | 0x10,0x28,0x10,0x00,0x78,0x04,0x3c,0x44,0x44,0x44,0x3c,0x00, 139 | 0x00,0x00,0x00,0x00,0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x70, 140 | 0x00,0x10,0x28,0x00,0x38,0x44,0x44,0x7c,0x40,0x44,0x38,0x00, 141 | 0x00,0x44,0x44,0x00,0x38,0x44,0x44,0x7c,0x40,0x44,0x38,0x00, 142 | 0x00,0x20,0x10,0x00,0x38,0x44,0x44,0x7c,0x40,0x44,0x38,0x00, 143 | 0x00,0x24,0x24,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00, 144 | 0x00,0x10,0x28,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00, 145 | 0x00,0x10,0x08,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00, 146 | 0x44,0x44,0x10,0x28,0x44,0x44,0x44,0x7c,0x44,0x44,0x44,0x00, 147 | 0x10,0x28,0x10,0x28,0x44,0x44,0x44,0x7c,0x44,0x44,0x44,0x00, 148 | 0x08,0x10,0x7c,0x40,0x40,0x40,0x78,0x40,0x40,0x40,0x7c,0x00, 149 | 0x00,0x00,0x00,0x00,0x68,0x14,0x34,0x5c,0x50,0x50,0x2c,0x00, 150 | 0x00,0x1c,0x30,0x50,0x50,0x5c,0x50,0x70,0x50,0x50,0x5c,0x00, 151 | 0x00,0x10,0x28,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00, 152 | 0x00,0x44,0x44,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00, 153 | 0x00,0x20,0x10,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00, 154 | 0x00,0x10,0x28,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x3c,0x00, 155 | 0x00,0x20,0x10,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x3c,0x00, 156 | 0x00,0x44,0x44,0x00,0x44,0x44,0x28,0x28,0x10,0x10,0x20,0x20, 157 | 0x44,0x44,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00, 158 | 0x44,0x44,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00, 159 | 0x00,0x10,0x10,0x38,0x54,0x50,0x50,0x54,0x38,0x10,0x10,0x00, 160 | 0x00,0x08,0x14,0x10,0x10,0x38,0x10,0x10,0x30,0x54,0x3c,0x00, 161 | 0x00,0x44,0x44,0x28,0x10,0x7c,0x10,0x7c,0x10,0x10,0x10,0x00, 162 | 0x00,0x78,0x44,0x44,0x44,0x78,0x40,0x48,0x5c,0x48,0x48,0x04, 163 | 0x00,0x08,0x14,0x10,0x10,0x7c,0x10,0x10,0x10,0x50,0x20,0x00, 164 | 0x00,0x08,0x10,0x00,0x78,0x04,0x3c,0x44,0x44,0x44,0x3c,0x00, 165 | 0x00,0x10,0x20,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00, 166 | 0x00,0x08,0x10,0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00, 167 | 0x00,0x08,0x10,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x3c,0x00, 168 | 0x00,0x34,0x58,0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x44,0x00, 169 | 0x34,0x58,0x00,0x44,0x64,0x64,0x54,0x54,0x4c,0x4c,0x44,0x00, 170 | 0x00,0x78,0x04,0x3c,0x44,0x3c,0x00,0x7c,0x00,0x00,0x00,0x00, 171 | 0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x7c,0x00,0x00,0x00,0x00, 172 | 0x00,0x10,0x10,0x00,0x10,0x10,0x10,0x20,0x44,0x44,0x38,0x00, 173 | 0x00,0x00,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00,0x7c,0x00, 174 | 0x00,0x00,0x00,0x00,0x00,0x7c,0x04,0x04,0x00,0x00,0x00,0x00, 175 | 0x00,0x20,0x20,0x24,0x28,0x10,0x38,0x44,0x08,0x10,0x1c,0x00, 176 | 0x00,0x20,0x20,0x24,0x28,0x10,0x24,0x4c,0x14,0x1c,0x04,0x00, 177 | 0x00,0x00,0x10,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 178 | 0x00,0x00,0x00,0x00,0x14,0x28,0x50,0x28,0x14,0x00,0x00,0x00, 179 | 0x00,0x00,0x00,0x00,0x50,0x28,0x14,0x28,0x50,0x00,0x00,0x00, 180 | 0x24,0x90,0x48,0x24,0x90,0x48,0x24,0x90,0x48,0x24,0x90,0x48, 181 | 0xa8,0x54,0xa8,0x54,0xa8,0x54,0xa8,0x54,0xa8,0x54,0xa8,0x54, 182 | 0xd8,0x6c,0xb4,0xd8,0x6c,0xb4,0xd8,0x6c,0xb4,0xd8,0x6c,0xb4, 183 | 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 184 | 0x10,0x10,0x10,0x10,0x10,0xf0,0x10,0x10,0x10,0x10,0x10,0x10, 185 | 0x10,0x10,0x10,0x10,0xf0,0x10,0xf0,0x10,0x10,0x10,0x10,0x10, 186 | 0x28,0x28,0x28,0x28,0x28,0xe8,0x28,0x28,0x28,0x28,0x28,0x28, 187 | 0x00,0x00,0x00,0x00,0x00,0xf8,0x28,0x28,0x28,0x28,0x28,0x28, 188 | 0x00,0x00,0x00,0x00,0xf0,0x10,0xf0,0x10,0x10,0x10,0x10,0x10, 189 | 0x28,0x28,0x28,0x28,0xe8,0x08,0xe8,0x28,0x28,0x28,0x28,0x28, 190 | 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28, 191 | 0x00,0x00,0x00,0x00,0xf8,0x08,0xe8,0x28,0x28,0x28,0x28,0x28, 192 | 0x28,0x28,0x28,0x28,0xe8,0x08,0xf8,0x00,0x00,0x00,0x00,0x00, 193 | 0x28,0x28,0x28,0x28,0x28,0xf8,0x00,0x00,0x00,0x00,0x00,0x00, 194 | 0x10,0x10,0x10,0x10,0xf0,0x10,0xf0,0x00,0x00,0x00,0x00,0x00, 195 | 0x00,0x00,0x00,0x00,0x00,0xf0,0x10,0x10,0x10,0x10,0x10,0x10, 196 | 0x10,0x10,0x10,0x10,0x10,0x1c,0x00,0x00,0x00,0x00,0x00,0x00, 197 | 0x10,0x10,0x10,0x10,0x10,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 198 | 0x00,0x00,0x00,0x00,0x00,0xfc,0x10,0x10,0x10,0x10,0x10,0x10, 199 | 0x10,0x10,0x10,0x10,0x10,0x1c,0x10,0x10,0x10,0x10,0x10,0x10, 200 | 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 201 | 0x10,0x10,0x10,0x10,0x10,0xfc,0x10,0x10,0x10,0x10,0x10,0x10, 202 | 0x10,0x10,0x10,0x10,0x1c,0x10,0x1c,0x10,0x10,0x10,0x10,0x10, 203 | 0x28,0x28,0x28,0x28,0x28,0x2c,0x28,0x28,0x28,0x28,0x28,0x28, 204 | 0x28,0x28,0x28,0x28,0x2c,0x20,0x3c,0x00,0x00,0x00,0x00,0x00, 205 | 0x00,0x00,0x00,0x00,0x3c,0x20,0x2c,0x28,0x28,0x28,0x28,0x28, 206 | 0x28,0x28,0x28,0x28,0xec,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 207 | 0x00,0x00,0x00,0x00,0xfc,0x00,0xec,0x28,0x28,0x28,0x28,0x28, 208 | 0x28,0x28,0x28,0x28,0x2c,0x20,0x2c,0x28,0x28,0x28,0x28,0x28, 209 | 0x00,0x00,0x00,0x00,0xfc,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 210 | 0x28,0x28,0x28,0x28,0xec,0x00,0xec,0x28,0x28,0x28,0x28,0x28, 211 | 0x10,0x10,0x10,0x10,0xfc,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 212 | 0x28,0x28,0x28,0x28,0x28,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 213 | 0x00,0x00,0x00,0x00,0xfc,0x00,0xfc,0x10,0x10,0x10,0x10,0x10, 214 | 0x00,0x00,0x00,0x00,0x00,0xfc,0x28,0x28,0x28,0x28,0x28,0x28, 215 | 0x28,0x28,0x28,0x28,0x28,0x3c,0x00,0x00,0x00,0x00,0x00,0x00, 216 | 0x10,0x10,0x10,0x10,0x1c,0x10,0x1c,0x00,0x00,0x00,0x00,0x00, 217 | 0x00,0x00,0x00,0x00,0x1c,0x10,0x1c,0x10,0x10,0x10,0x10,0x10, 218 | 0x00,0x00,0x00,0x00,0x00,0x3c,0x28,0x28,0x28,0x28,0x28,0x28, 219 | 0x28,0x28,0x28,0x28,0x28,0xec,0x28,0x28,0x28,0x28,0x28,0x28, 220 | 0x10,0x10,0x10,0x10,0xfc,0x00,0xfc,0x10,0x10,0x10,0x10,0x10, 221 | 0x10,0x10,0x10,0x10,0x10,0xf0,0x00,0x00,0x00,0x00,0x00,0x00, 222 | 0x00,0x00,0x00,0x00,0x00,0x1c,0x10,0x10,0x10,0x10,0x10,0x10, 223 | 0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, 224 | 0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, 225 | 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, 226 | 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, 227 | 0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0x00,0x00,0x00,0x00,0x00,0x00, 228 | 0x00,0x00,0x00,0x00,0x34,0x48,0x48,0x48,0x48,0x48,0x34,0x00, 229 | 0x00,0x30,0x48,0x48,0x48,0x50,0x48,0x44,0x44,0x54,0x58,0x00, 230 | 0x00,0x7c,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00, 231 | 0x00,0x00,0x00,0x00,0x7c,0x28,0x28,0x28,0x28,0x28,0x28,0x00, 232 | 0x00,0x7c,0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x40,0x7c,0x00, 233 | 0x00,0x00,0x00,0x04,0x3c,0x48,0x48,0x48,0x48,0x48,0x30,0x00, 234 | 0x00,0x00,0x00,0x00,0x48,0x48,0x48,0x48,0x48,0x48,0x74,0xc0, 235 | 0x00,0x00,0x00,0x00,0x34,0x58,0x10,0x10,0x10,0x10,0x10,0x00, 236 | 0x00,0x7c,0x10,0x38,0x54,0x54,0x54,0x54,0x38,0x10,0x7c,0x00, 237 | 0x00,0x38,0x44,0x44,0x44,0x7c,0x44,0x44,0x44,0x44,0x38,0x00, 238 | 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x28,0x28,0x6c,0x00, 239 | 0x00,0x1c,0x20,0x10,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00, 240 | 0x00,0x00,0x00,0x00,0x28,0x54,0x54,0x54,0x28,0x00,0x00,0x00, 241 | 0x00,0x04,0x04,0x38,0x4c,0x54,0x54,0x64,0x38,0x40,0x40,0x00, 242 | 0x00,0x1c,0x20,0x40,0x40,0x78,0x40,0x40,0x40,0x20,0x1c,0x00, 243 | 0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x7c,0x00,0x00,0x00, 244 | 0x00,0x00,0x00,0x20,0x54,0x08,0x20,0x54,0x08,0x00,0x00,0x00, 245 | 0x00,0x00,0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x7c,0x00,0x00, 246 | 0x00,0x00,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x00,0x7c,0x00, 247 | 0x00,0x00,0x00,0x7c,0x00,0x00,0x7c,0x00,0x00,0x7c,0x00,0x00, 248 | 0x00,0x08,0x14,0x14,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 249 | 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x50,0x50,0x20,0x00, 250 | 0x00,0x00,0x00,0x10,0x10,0x00,0x7c,0x00,0x10,0x10,0x00,0x00, 251 | 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x00, 252 | 0x20,0x50,0x50,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 253 | 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00, 254 | 0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x00,0x00, 255 | 0x00,0x1c,0x10,0x10,0x10,0x10,0x50,0x50,0x30,0x30,0x10,0x00, 256 | 0x00,0x70,0x48,0x48,0x48,0x48,0x00,0x00,0x00,0x00,0x00,0x00, 257 | 0x00,0x70,0x08,0x30,0x40,0x78,0x00,0x00,0x00,0x00,0x00,0x00, 258 | 0x00,0x00,0x00,0x00,0x78,0x78,0x78,0x78,0x00,0x00,0x00,0x00, 259 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 260 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 261 | }; -------------------------------------------------------------------------------- /rogue.c: -------------------------------------------------------------------------------- 1 | #define LUA_LIB 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "SDL.h" 9 | #include "charset_cp437.h" 10 | #include "charset_cp936.h" 11 | 12 | #define FRAMESEC 1000 13 | #define PIXELWIDTH 6 14 | #define PIXELHEIGHT 12 15 | #define TABSIZE 8 16 | #define UNICACHE 1024 17 | #define BACKLAYER 255 18 | 19 | struct slot { 20 | uint16_t background; // 565 RGB 21 | uint16_t color; // 565 RGB 22 | uint32_t code:23; // for unicode 23 | uint32_t rightpart:1; 24 | uint32_t layer:8; 25 | }; 26 | 27 | struct sprite { 28 | struct sprite *prev; 29 | struct sprite *next; 30 | unsigned w; 31 | unsigned h; 32 | int x; 33 | int y; 34 | int kx; 35 | int ky; 36 | int background; 37 | struct slot s[1]; 38 | }; 39 | 40 | struct unicode_cache { 41 | int unicode[UNICACHE]; 42 | uint16_t index[UNICACHE]; 43 | }; 44 | 45 | struct context { 46 | SDL_Renderer *renderer; 47 | SDL_Window *window; 48 | SDL_Surface *surface; 49 | uint64_t tick; 50 | int frame; 51 | int fps; 52 | int x; 53 | int y; 54 | int width; // grid 55 | int height; 56 | int w; // pixel 57 | int h; 58 | int mousex; 59 | int mousey; 60 | struct slot *s; 61 | struct sprite *spr; 62 | uint8_t layer[256]; 63 | struct unicode_cache u; 64 | }; 65 | 66 | static inline int 67 | inthash(int p) { 68 | int h = (2654435761 * p) % UNICACHE; 69 | return h; 70 | } 71 | 72 | static int 73 | search_cp437(int unicode) { 74 | static const uint16_t cp437_unicode[] = { 75 | 0x00a0,0x00a1,0x00a2,0x00a3,0x00a5,0x00a7,0x00aa,0x00ab,0x00ac,0x00b0,0x00b1,0x00b2,0x00b5,0x00b6,0x00b7,0x00ba, 76 | 0x00bb,0x00bc,0x00bd,0x00bf,0x00c4,0x00c5,0x00c6,0x00c7,0x00c9,0x00d1,0x00d6,0x00dc,0x00df,0x00e0,0x00e1,0x00e2, 77 | 0x00e4,0x00e5,0x00e6,0x00e7,0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,0x00f1,0x00f2,0x00f3,0x00f4, 78 | 0x00f6,0x00f7,0x00f9,0x00fa,0x00fb,0x00fc,0x00ff,0x0192,0x0393,0x0398,0x03a3,0x03a6,0x03a9,0x03b1,0x03b4,0x03b5, 79 | 0x03c0,0x03c3,0x03c4,0x03c6,0x2022,0x203c,0x207f,0x20a7,0x2190,0x2191,0x2192,0x2193,0x2194,0x2195,0x21a8,0x2219, 80 | 0x221a,0x221e,0x221f,0x2229,0x2248,0x2261,0x2264,0x2265,0x2310,0x2320,0x2321,0x2500,0x2502,0x250c,0x2510,0x2514, 81 | 0x2518,0x251c,0x2524,0x252c,0x2534,0x253c,0x2550,0x2551,0x2552,0x2553,0x2554,0x2555,0x2556,0x2557,0x2558,0x2559, 82 | 0x255a,0x255b,0x255c,0x255d,0x255e,0x255f,0x2560,0x2561,0x2562,0x2563,0x2564,0x2565,0x2566,0x2567,0x2568,0x2569, 83 | 0x256a,0x256b,0x256c,0x2580,0x2584,0x2588,0x258c,0x2590,0x2591,0x2592,0x2593,0x25a0,0x25ac,0x25b2,0x25ba,0x25bc, 84 | 0x25c4,0x25cb,0x25d8,0x25d9,0x263a,0x263b,0x263c,0x2640,0x2642,0x2660,0x2663,0x2665,0x2666,0x266a,0x266b, 85 | }; 86 | static const uint8_t cp437_index[] = { 87 | 255,173,155,156,157, 21,166,174,170,248,241,253,230, 20,250,167, 88 | 175,172,171,168,142,143,146,128,144,165,153,154,225,133,160,131, 89 | 132,134,145,135,138,130,136,137,141,161,140,139,164,149,162,147, 90 | 148,246,151,163,150,129,152,159,226,233,228,232,234,224,235,238, 91 | 227,229,231,237, 7, 19,252,158, 27, 24, 26, 25, 29, 18, 23,249, 92 | 251,236,239,247,240,243,242,169, 28,244,245,196,179,218,191,192, 93 | 217,195,180,194,193,197,205,186,213,214,201,184,183,187,212,211, 94 | 200,190,189,188,198,199,204,181,182,185,209,210,203,207,208,202, 95 | 216,215,206,223,220,219,221,222,176,177,178,254, 22, 30, 16, 31, 96 | 17, 9, 8, 10, 1, 2, 15, 12, 11, 6, 5, 3, 4, 13, 14 97 | }; 98 | int begin = 0; 99 | int end = sizeof(cp437_unicode) / sizeof(cp437_unicode[0]); 100 | while (begin < end) { 101 | int mid = (begin + end) / 2; 102 | uint16_t code = cp437_unicode[mid]; 103 | if (code == unicode) { 104 | return cp437_index[mid]; 105 | } 106 | else if (code < unicode) 107 | begin = mid + 1; 108 | else 109 | end = mid; 110 | } 111 | return -1; 112 | } 113 | 114 | static int 115 | search_cp936(int unicode) { 116 | int begin = 0; 117 | int end = sizeof(unimap_cp936) / sizeof(unimap_cp936[0]); 118 | while (begin < end) { 119 | int mid = (begin + end) / 2; 120 | uint16_t code = unimap_cp936[mid]; 121 | if (code == unicode) 122 | return mid; 123 | else if (code < unicode) 124 | begin = mid + 1; 125 | else 126 | end = mid; 127 | } 128 | return -1; 129 | } 130 | 131 | static int 132 | unicode_index(struct context *ctx, int unicode) { 133 | if (unicode <= 127) 134 | return unicode; 135 | int slot = inthash(unicode); 136 | if (ctx->u.unicode[slot] != unicode) { 137 | ctx->u.unicode[slot] = unicode; 138 | ctx->u.index[slot] = 255; 139 | int code = search_cp437(unicode); 140 | if (code >= 0) { 141 | ctx->u.index[slot] = code; 142 | } else { 143 | code = search_cp936(unicode); 144 | if (code >= 0) { 145 | ctx->u.index[slot] = code + 256; 146 | } 147 | } 148 | } 149 | return ctx->u.index[slot]; 150 | } 151 | 152 | static struct context * 153 | getCtx(lua_State *L) { 154 | struct context * ctx = (struct context *)lua_touserdata(L, lua_upvalueindex(1)); 155 | return ctx; 156 | } 157 | 158 | static int 159 | get_int(lua_State *L, int idx, const char * name) { 160 | if (lua_getfield(L, idx, name) != LUA_TNUMBER) { 161 | luaL_error(L, "Can't get %s as number", name); 162 | } 163 | int isnum; 164 | int r = lua_tointegerx(L, -1, &isnum); 165 | if (!isnum) 166 | luaL_error(L, "Can't get %s as integer", name); 167 | lua_pop(L, 1); 168 | return r; 169 | } 170 | 171 | static uint32_t 172 | is_enable(lua_State *L, int idx, const char * name) { 173 | lua_getfield(L, idx, name); 174 | int enable = lua_toboolean(L, -1); 175 | lua_pop(L, 1); 176 | return enable ? 0xffffffff : 0; 177 | } 178 | 179 | static void 180 | init_surface(lua_State *L, struct context *ctx) { 181 | ctx->surface = SDL_CreateRGBSurface(0, ctx->width * PIXELWIDTH, ctx->height * PIXELHEIGHT, 24, 0, 0, 0, 0); 182 | if (ctx->surface == NULL) { 183 | luaL_error(L, "Create surface failed : %s", SDL_GetError()); 184 | } 185 | } 186 | 187 | static void 188 | init_slotbuffer(lua_State *L, struct context *ctx) { 189 | size_t sz = ctx->width * ctx->height * sizeof(struct slot); 190 | struct slot * s = (struct slot *)lua_newuserdatauv(L, sz, 0); 191 | memset(s, 0, sz); 192 | ctx->s = s; 193 | lua_setiuservalue(L, lua_upvalueindex(1), 1); 194 | s->color = 0xffff; 195 | } 196 | 197 | static int 198 | linit(lua_State *L) { 199 | struct context * ctx = getCtx(L); 200 | if (ctx->window != NULL) 201 | return luaL_error(L, "Already init"); 202 | if (SDL_Init(SDL_INIT_VIDEO) < 0) 203 | return luaL_error(L, "Couldn't initialize SDL: %s\n", SDL_GetError()); 204 | 205 | luaL_checktype(L, 1, LUA_TTABLE); 206 | 207 | int width = get_int(L, 1, "width"); 208 | int height = get_int(L, 1, "height"); 209 | 210 | SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); 211 | 212 | uint32_t flags = 0; 213 | 214 | flags |= is_enable(L, 1, "borderless") & SDL_WINDOW_BORDERLESS; 215 | flags |= is_enable(L, 1, "resizeable") & SDL_WINDOW_RESIZABLE; 216 | flags |= is_enable(L, 1, "fullscreen") & SDL_WINDOW_FULLSCREEN; 217 | 218 | double scale = 1; 219 | if (lua_getfield(L, 1, "scale") != LUA_TNIL) { 220 | scale = luaL_checknumber(L, -1); 221 | } 222 | lua_pop(L, 1); 223 | 224 | ctx->w = width * scale * PIXELWIDTH; 225 | ctx->h = height * scale * PIXELHEIGHT; 226 | 227 | const char * title = ""; 228 | if (lua_getfield(L, 1, "title") == LUA_TSTRING) { 229 | title = lua_tostring(L, -1); 230 | lua_pop(L, 1); 231 | } 232 | 233 | SDL_Window *wnd = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, ctx->w, ctx->h, flags); 234 | if (wnd == NULL) { 235 | return luaL_error(L, "Couldn't create window : %s", SDL_GetError()); 236 | } 237 | 238 | flags = is_enable(L, 1, "software") ? SDL_RENDERER_SOFTWARE : SDL_RENDERER_ACCELERATED; 239 | flags |= is_enable(L, 1, "vsync") & SDL_RENDERER_PRESENTVSYNC; 240 | 241 | SDL_Renderer *r = SDL_CreateRenderer(wnd, -1, flags); 242 | if (r == NULL) { 243 | return luaL_error(L, "Couldn't create renderer: %s", SDL_GetError()); 244 | } 245 | 246 | SDL_RenderSetLogicalSize(r, width * PIXELWIDTH, height * PIXELHEIGHT); 247 | 248 | ctx->renderer = r; 249 | ctx->window = wnd; 250 | ctx->tick = SDL_GetTicks64(); 251 | ctx->frame = 0; 252 | ctx->fps = get_int(L, 1, "fps"); 253 | ctx->width = width; 254 | ctx->height = height; 255 | ctx->surface = NULL; 256 | 257 | init_surface(L, ctx); 258 | init_slotbuffer(L, ctx); 259 | 260 | return 0; 261 | } 262 | 263 | static inline void 264 | color16to24(uint16_t c16, uint8_t c[3]) { 265 | c[2] = c16 >> 11; 266 | c[2] = (c[2] << 3) | (c[2] & 7); 267 | c[1] = c16 >> 5; 268 | c[1] = (c[1] << 2) | (c[1] & 3); 269 | c[0] = (c16 << 3) | (c16 & 3); 270 | } 271 | 272 | static inline void 273 | draw_slot(uint8_t *p, struct slot *s, int pitch) { 274 | const uint8_t *g; 275 | int g_pitch; 276 | if (s->code <= 255) { 277 | g = &uni6x12_cp437[s->code * 12]; 278 | g_pitch = 1; 279 | } else { 280 | int code = s->code - 256; 281 | g = &uni12x12_cp936[code * 24]; 282 | if (s->rightpart) 283 | ++g; 284 | g_pitch = 2; 285 | } 286 | uint8_t b[3], c[3]; 287 | color16to24(s->background, b); 288 | color16to24(s->color, c); 289 | int i,j; 290 | for (i=0;i<12;i++) { 291 | uint8_t m = *g; 292 | for (j=0;j<6;j++) { 293 | uint8_t *color = (m & 0x80) ? c : b; 294 | p[j*3+0] = color[0]; 295 | p[j*3+1] = color[1]; 296 | p[j*3+2] = color[2]; 297 | m <<= 1; 298 | } 299 | p+=pitch; 300 | g+=g_pitch; 301 | } 302 | } 303 | 304 | static void 305 | flush_slotbuffer(uint8_t *p, struct slot *s, int w, int h ) { 306 | int i,j; 307 | int pitch = w * PIXELWIDTH * 3; 308 | for (i=0;ix - ctx->x - spr->kx; 322 | int des_y = spr->y - ctx->y - spr->ky; 323 | int w = spr->w; 324 | int h = spr->h; 325 | if (des_x < 0) { 326 | src_x -= des_x; 327 | if (src_x >= w) 328 | return; 329 | des_x = 0; 330 | w -= src_x; 331 | } else if (des_x >= ctx->width) { 332 | return; 333 | } 334 | if (des_x + w > ctx->width) { 335 | w = ctx->width - des_x; 336 | } 337 | if (des_y < 0) { 338 | src_y -= des_y; 339 | if (src_y >= h) 340 | return; 341 | des_y = 0; 342 | h -= src_y; 343 | } else if (des_y >= ctx->height) { 344 | return; 345 | } 346 | if (des_y + h > ctx->height) { 347 | h = ctx->height - des_y; 348 | } 349 | int i,j; 350 | struct slot *src_slot = &spr->s[src_y * spr->w + src_x]; 351 | struct slot *des_slot = &ctx->s[des_y * ctx->width + des_x]; 352 | for (i=0;ilayer[src_slot[j].layer] == 0 && src_slot[j].code) { 355 | if (src_slot[j].layer >= des_slot[j].layer) { 356 | if (spr->background) { 357 | des_slot[j] = src_slot[j]; 358 | } else { 359 | uint16_t bg = des_slot[j].background; 360 | des_slot[j] = src_slot[j]; 361 | des_slot[j].background = bg; 362 | } 363 | } else if (spr->background) { 364 | des_slot[j].background = src_slot[j].background; 365 | } 366 | } 367 | } 368 | src_slot += spr->w; 369 | des_slot += ctx->width; 370 | } 371 | } 372 | 373 | static void 374 | draw_sprites(struct context *ctx) { 375 | struct sprite * spr = ctx->spr; 376 | if (spr == NULL) 377 | return; 378 | do { 379 | draw_sprite(ctx, spr); 380 | spr = spr->next; 381 | } while (spr != ctx->spr); 382 | } 383 | 384 | static void 385 | flip_surface(struct context *ctx) { 386 | SDL_Surface *ws = SDL_GetWindowSurface(ctx->window); 387 | int w = ctx->width * PIXELWIDTH; 388 | int h = ctx->height * PIXELHEIGHT; 389 | 390 | draw_sprites(ctx); 391 | 392 | SDL_LockSurface(ctx->surface); 393 | flush_slotbuffer(ctx->surface->pixels, ctx->s, ctx->width, ctx->height); 394 | SDL_UnlockSurface(ctx->surface); 395 | memset(ctx->s, 0, sizeof(struct slot) * ctx->width * ctx->height); 396 | 397 | if (ws->w == w && ws->h == h) { 398 | SDL_BlitSurface(ctx->surface, NULL, ws, NULL); 399 | } else { 400 | SDL_BlitScaled(ctx->surface, NULL, ws, NULL); 401 | } 402 | SDL_UpdateWindowSurface(ctx->window); 403 | } 404 | 405 | static int 406 | lframe(lua_State *L) { 407 | struct context * ctx = getCtx(L); 408 | if (ctx->surface == NULL) 409 | return luaL_error(L, "Init first"); 410 | ctx->x = luaL_optinteger(L, 1, 0); 411 | ctx->y = luaL_optinteger(L, 2, 0); 412 | flip_surface(ctx); 413 | uint64_t c = SDL_GetTicks64(); 414 | int lastframe = ctx->frame; 415 | int frame = lastframe + 1; 416 | if (frame > ctx->fps) { 417 | lastframe = 0; 418 | frame = 1; 419 | } 420 | int delta = FRAMESEC * frame / ctx->fps - FRAMESEC * lastframe / ctx->fps; 421 | ctx->frame = frame; 422 | ctx->tick += delta; 423 | if (c < ctx->tick) 424 | SDL_Delay(ctx->tick - c); 425 | if (c - ctx->tick > FRAMESEC) { 426 | // reset frame count if the error is too large 427 | ctx->tick = c; 428 | ctx->frame = 0; 429 | } 430 | 431 | return 0; 432 | } 433 | 434 | static void 435 | resize_window(struct context *ctx, int width, int height) { 436 | int ow = ctx->width * PIXELWIDTH; 437 | int oh = ctx->height * PIXELHEIGHT; 438 | if (ow * height == oh * width) { 439 | ctx->w = width; 440 | ctx->h = height; 441 | return; 442 | } 443 | if (width > ctx->w) { 444 | // enlarge width 445 | height = oh * width / ow; 446 | } else if (height > ctx->h) { 447 | // enlarge height 448 | width = ow * height / oh; 449 | } else if (width < ctx->w) { 450 | // shrink width 451 | height = oh * width / ow; 452 | } else { 453 | // shrink height 454 | width = ow * height / oh; 455 | } 456 | 457 | ctx->w = width; 458 | ctx->h = height; 459 | 460 | SDL_SetWindowSize(ctx->window, width, height); 461 | } 462 | 463 | static void 464 | winevent(lua_State *L, SDL_Event *ev) { 465 | struct context * ctx = getCtx(L); 466 | switch (ev->window.event) { 467 | case SDL_WINDOWEVENT_SIZE_CHANGED : 468 | resize_window(ctx, ev->window.data1, ev->window.data2); 469 | break; 470 | } 471 | } 472 | 473 | static int 474 | keyevent(lua_State *L, SDL_Event *ev) { 475 | // if (ev->key.repeat) 476 | // return 0; 477 | lua_pushstring(L, "KEY"); 478 | lua_pushstring(L, SDL_GetKeyName(ev->key.keysym.sym)); 479 | lua_pushboolean(L, ev->key.type == SDL_KEYDOWN); 480 | return 3; 481 | } 482 | 483 | static void 484 | screen_coord(struct context *ctx, int *x, int *y) { 485 | *x /= PIXELWIDTH; 486 | *y /= PIXELHEIGHT; 487 | } 488 | 489 | static int 490 | motionevent(lua_State *L, SDL_Event *ev) { 491 | struct context * ctx = getCtx(L); 492 | int x = ev->motion.x; 493 | int y = ev->motion.y; 494 | screen_coord(ctx, &x, &y); 495 | if (x == ctx->mousex && y == ctx->mousey) 496 | return 0; 497 | ctx->mousex = x; 498 | ctx->mousey = y; 499 | lua_pushstring(L, "MOTION"); 500 | lua_pushinteger(L, x); 501 | lua_pushinteger(L, y); 502 | return 3; 503 | } 504 | 505 | static int 506 | buttonevent(lua_State *L, SDL_Event *ev) { 507 | struct context * ctx = getCtx(L); 508 | int x = ev->motion.x; 509 | int y = ev->motion.y; 510 | screen_coord(ctx, &x, &y); 511 | ctx->mousex = x; 512 | ctx->mousey = y; 513 | lua_pushstring(L, "BUTTON"); 514 | lua_pushinteger(L, x); 515 | lua_pushinteger(L, y); 516 | lua_pushinteger(L, ev->button.button); 517 | lua_pushboolean(L, ev->button.state == SDL_PRESSED); 518 | lua_pushinteger(L, ev->button.clicks); 519 | return 6; 520 | } 521 | 522 | static int 523 | levent(lua_State *L) { 524 | SDL_Event event; 525 | 526 | int r; 527 | 528 | while (SDL_PollEvent(&event)) { 529 | switch (event.type) { 530 | case SDL_QUIT: 531 | lua_pushstring(L, "QUIT"); 532 | return 1; 533 | case SDL_WINDOWEVENT: 534 | winevent(L, &event); 535 | break; 536 | case SDL_KEYDOWN: 537 | case SDL_KEYUP: 538 | if ((r = keyevent(L, &event)) > 0) 539 | return r; 540 | break; 541 | case SDL_TEXTEDITING: 542 | SDL_StopTextInput(); 543 | break; 544 | case SDL_MOUSEMOTION: 545 | if ((r = motionevent(L, &event)) > 0) 546 | return r; 547 | break; 548 | case SDL_MOUSEBUTTONDOWN: 549 | case SDL_MOUSEBUTTONUP: 550 | return buttonevent(L, &event); 551 | default: 552 | break; 553 | } 554 | } 555 | return 0; 556 | } 557 | 558 | static struct sprite * 559 | getSpr(lua_State *L) { 560 | struct sprite *spr = lua_touserdata(L, 1); 561 | if (spr == NULL) 562 | luaL_error(L, "Need sprite"); 563 | return spr; 564 | } 565 | 566 | 567 | static int 568 | lsetpos(lua_State *L) { 569 | struct sprite *spr = getSpr(L); 570 | spr->x = luaL_checkinteger(L, 2); 571 | spr->y = luaL_checkinteger(L, 3); 572 | return 0; 573 | } 574 | 575 | static void 576 | link_sprite(struct context *ctx, struct sprite *spr) { 577 | struct sprite * node = ctx->spr; 578 | if (node == NULL) { 579 | spr->prev = spr->next = spr; 580 | } else { 581 | // insert before node 582 | spr->next = node; 583 | spr->prev = node->prev; 584 | 585 | node->prev = spr; 586 | spr->prev->next = spr; 587 | } 588 | ctx->spr = spr; 589 | } 590 | 591 | static void 592 | unlink_sprite(struct context *ctx, struct sprite *spr) { 593 | if (ctx->spr == spr) { 594 | if (spr->prev == spr->next) { 595 | ctx->spr = NULL; 596 | } else { 597 | ctx->spr = spr->next; 598 | } 599 | } 600 | struct sprite *prev = spr->prev; 601 | struct sprite *next = spr->next; 602 | prev->next = next; 603 | next->prev = prev; 604 | spr->prev = NULL; 605 | spr->next = NULL; 606 | } 607 | 608 | static int 609 | lvisible(lua_State *L) { 610 | struct sprite *spr = getSpr(L); 611 | int visible = lua_toboolean(L, 2); 612 | if (visible) { 613 | if (spr->prev) 614 | return 0; // already visible 615 | struct context *ctx = getCtx(L); 616 | link_sprite(ctx, spr); 617 | } else { 618 | if (spr->prev == NULL) 619 | return 0; // already invisible 620 | struct context *ctx = getCtx(L); 621 | unlink_sprite(ctx, spr); 622 | } 623 | return 0; 624 | } 625 | 626 | static int 627 | lspriteinfo(lua_State *L) { 628 | struct sprite *spr = lua_touserdata(L, 1); 629 | lua_pushfstring(L, "[sprite %dx%d+%d+%d %d %d]", spr->w, spr->h, spr->kx, spr->ky, spr->x, spr->y); 630 | 631 | return 1; 632 | } 633 | 634 | struct sprite_attribs { 635 | int transparency; 636 | uint16_t background; 637 | uint16_t color; 638 | uint8_t layer; 639 | }; 640 | 641 | /* 642 | ** From lua 5.4 lutf8lib.c 643 | ** Decode one UTF-8 sequence, returning NULL if byte sequence is 644 | ** invalid. The array 'limits' stores the minimum value for each 645 | ** sequence length, to check for overlong representations. Its first 646 | ** entry forces an error for non-ascii bytes with no continuation 647 | ** bytes (count == 0). 648 | */ 649 | static const char * 650 | utf8_decode(const char *s, int *val) { 651 | static const int limits[] = 652 | {~(int)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u}; 653 | unsigned int c = (unsigned char)s[0]; 654 | int res = 0; /* final result */ 655 | if (c < 0x80) /* ascii? */ 656 | res = c; 657 | else { 658 | int count = 0; /* to count number of continuation bytes */ 659 | for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */ 660 | unsigned int cc = (unsigned char)s[++count]; /* read next byte */ 661 | if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ 662 | return NULL; /* invalid byte sequence */ 663 | res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ 664 | } 665 | res |= ((int)(c & 0x7F) << (count * 5)); /* add first byte */ 666 | if (count > 5 || res < limits[count]) 667 | return NULL; /* invalid byte sequence */ 668 | s += count; /* skip continuation bytes read */ 669 | } 670 | if (val) *val = res; 671 | return s + 1; /* +1 to include first byte */ 672 | } 673 | 674 | static void 675 | sprite_graph(lua_State *L, int idx, struct context *ctx, struct sprite *spr, struct sprite_attribs *attrib) { 676 | int i,j; 677 | struct slot *s = spr->s; 678 | for (i=0;ih;i++) { 679 | lua_geti(L, idx, i+1); 680 | const char * str = lua_tostring(L, -1); 681 | lua_pop(L, 1); 682 | for (j=0;jw;j++) { 683 | s[j].background = attrib->background; 684 | s[j].color = attrib->color; 685 | s[j].layer = attrib->layer; 686 | int unicode; 687 | if (!(str = utf8_decode(str, &unicode))) 688 | luaL_error(L, "Invalid utf8 text"); 689 | int c = unicode_index(ctx, unicode); 690 | if (c == attrib->transparency) 691 | c = 0; 692 | s[j].code = c; 693 | s[j].rightpart = 0; 694 | if (c > 256) { 695 | s[j+1] = s[j]; 696 | s[j+1].rightpart = 1; 697 | ++j; 698 | } 699 | } 700 | s += spr->w; 701 | } 702 | } 703 | 704 | static inline uint16_t 705 | color24to16(uint32_t c) { 706 | int r = (c >> 16) & 0xff; 707 | int g = (c >> 8) & 0xff; 708 | int b = c & 0xff; 709 | return ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3); 710 | } 711 | 712 | static uint16_t 713 | get_color(lua_State *L, int idx, const char *name, uint16_t def, int *hascolor) { 714 | if (lua_getfield(L, idx, name) == LUA_TNIL) { 715 | if (hascolor) { 716 | *hascolor = 0; 717 | } 718 | lua_pop(L, 1); 719 | return def; 720 | } 721 | if (hascolor) { 722 | *hascolor = 1; 723 | } 724 | int isnum; 725 | uint32_t c = lua_tointegerx(L, -1, &isnum); 726 | if (!isnum) 727 | luaL_error(L, "Color should be uint32"); 728 | lua_pop(L, 1); 729 | return color24to16(c); 730 | } 731 | 732 | static inline size_t 733 | sprite_size(int w, int h) { 734 | return sizeof(struct sprite) + sizeof(struct slot) * (w * h -1); 735 | } 736 | 737 | static int 738 | lclone(lua_State *L) { 739 | struct sprite *spr = getSpr(L); 740 | size_t sz = sprite_size(spr->w,spr->h); 741 | struct sprite *clone = (struct sprite *)lua_newuserdatauv(L, sz, 0); 742 | memcpy(clone, spr, sz); 743 | if (lua_isboolean(L, 2)) { 744 | clone->prev = NULL; 745 | clone->next = NULL; 746 | if (lua_toboolean(L, 2)) { 747 | link_sprite(getCtx(L), clone); 748 | } 749 | } else { 750 | if (clone->prev) { 751 | clone->prev = NULL; 752 | clone->next = NULL; 753 | link_sprite(getCtx(L), clone); 754 | } 755 | } 756 | luaL_getmetatable(L, "RSPRITE"); 757 | lua_setmetatable(L, -2); 758 | return 1; 759 | } 760 | 761 | static void 762 | reset_color(struct sprite *spr, uint16_t c) { 763 | int i,j; 764 | struct slot *s = spr->s; 765 | for (i=0;ih;i++) { 766 | for (j=0;jw;j++) { 767 | s[j].color = c; 768 | } 769 | s += spr->w; 770 | } 771 | } 772 | 773 | #define COLOR_UNINIT -2 774 | #define COLOR_UNDEF -1 775 | 776 | static int 777 | lsetcolor(lua_State *L) { 778 | struct sprite *spr = getSpr(L); 779 | if (lua_type(L, 2) == LUA_TNUMBER) { 780 | int isnum; 781 | uint32_t c = lua_tointegerx(L, -1, &isnum); 782 | if (!isnum) 783 | return luaL_error(L, "Color should be uint32"); 784 | uint16_t c16 = color24to16(c); 785 | reset_color(spr, c16); 786 | return 0; 787 | } 788 | luaL_checktype(L, 2, LUA_TTABLE); 789 | int pal[256]; 790 | int i,j; 791 | for (i=0;i<256;i++) { 792 | pal[i] = COLOR_UNINIT; 793 | } 794 | struct slot *s = spr->s; 795 | for (i=0;ih;i++) { 796 | if (lua_geti(L, 2, i+1) != LUA_TSTRING) { 797 | return luaL_error(L, "Invalid colormap"); 798 | } 799 | const char * str = lua_tostring(L, -1); 800 | lua_pop(L, 1); 801 | for (j=0;jw;j++) { 802 | int index = (uint8_t)str[j]; 803 | if (index > 127 || index == 0) 804 | return luaL_error(L, "Invalid colormap, ascii only"); 805 | if (pal[index] >= 0) { 806 | s[j].color = pal[index]; 807 | } else if (pal[index] == COLOR_UNINIT) { 808 | char key[2] = { index, 0 }; 809 | if (lua_getfield(L, 2, key) == LUA_TNIL) { 810 | pal[index] = COLOR_UNDEF; 811 | } else { 812 | int isnum; 813 | uint32_t c = lua_tointegerx(L, -1, &isnum); 814 | if (!isnum) { 815 | return luaL_error(L, "Pal .%c should be integer", index); 816 | } 817 | pal[index] = color24to16(c); 818 | s[j].color = pal[index]; 819 | } 820 | lua_pop(L, 1); 821 | } 822 | } 823 | s += spr->w; 824 | } 825 | return 0; 826 | } 827 | 828 | static void 829 | reset_layer(struct sprite *spr, uint8_t c) { 830 | int i,j; 831 | struct slot *s = spr->s; 832 | for (i=0;ih;i++) { 833 | for (j=0;jw;j++) { 834 | s[j].layer = c; 835 | } 836 | s += spr->w; 837 | } 838 | } 839 | 840 | static int 841 | lsetlayer(lua_State *L) { 842 | struct sprite *spr = getSpr(L); 843 | if (lua_type(L, 2) == LUA_TNUMBER) { 844 | int isnum; 845 | uint32_t c = lua_tointegerx(L, -1, &isnum); 846 | if (!isnum) 847 | return luaL_error(L, "Layer should be byte"); 848 | reset_layer(spr, c); 849 | return 0; 850 | } 851 | return luaL_error(L, "Invalid layer"); 852 | } 853 | 854 | 855 | static void 856 | clear_sprite_text(struct sprite *spr) { 857 | int n = spr->w * spr->h; 858 | int i; 859 | for (i=0;is[i].code = ' '; 861 | spr->s[i].rightpart = 0; 862 | } 863 | } 864 | 865 | static int 866 | lsettext(lua_State *L) { 867 | struct context *ctx = getCtx(L); 868 | struct sprite * spr = getSpr(L); 869 | const char *text = luaL_checkstring(L, 2); 870 | int x=0; 871 | int y=0; 872 | struct slot *s = spr->s; 873 | int unicode = 0; 874 | clear_sprite_text(spr); 875 | while (y < spr->h && ((text = utf8_decode(text, &unicode)), unicode)) { 876 | if (text == NULL) 877 | return luaL_error(L, "Invalid UTF-8 string %s", lua_tostring(L, 2)); 878 | int c = unicode_index(ctx, unicode); 879 | if (c == '\n') { 880 | x = spr->w; 881 | } else if (c == '\t') { 882 | x = (x / TABSIZE + 1) * TABSIZE; 883 | } else if (c <= 255) { 884 | s[x].code = c; 885 | ++x; 886 | } else { 887 | if (x + 1 >= spr->w) { 888 | if (spr->w < 2) 889 | return luaL_error(L, "Invalid sprite width %d", spr->w); 890 | x = 0; 891 | ++y; 892 | if (y <= spr->h) 893 | break; 894 | s += spr->w; 895 | } 896 | s[x].code = c; 897 | ++x; 898 | s[x].code = c; 899 | s[x].rightpart = 1; 900 | ++x; 901 | } 902 | if (x >= spr->w) { 903 | x = 0; 904 | ++y; 905 | s += spr->w; 906 | } 907 | } 908 | return 0; 909 | } 910 | 911 | static int 912 | get_sprite_width(lua_State *L, struct context *ctx, int idx, int line) { 913 | if (lua_geti(L, idx, line) != LUA_TSTRING) { 914 | luaL_error(L, "Invalid sprite"); 915 | } 916 | const char * s = lua_tostring(L, -1); 917 | int len = 0; 918 | int code = 0; 919 | while ((s = utf8_decode(s, &code)) && code) { 920 | int c = unicode_index(ctx, code); 921 | if (c > 255) 922 | len += 2; 923 | else 924 | ++len; 925 | } 926 | lua_pop(L, 1); 927 | return len; 928 | } 929 | 930 | static void 931 | check_sprite_size(lua_State *L, struct context *ctx, int idx, int *w, int *h) { 932 | int lines = (int)lua_rawlen(L, idx); 933 | if (lines <= 0) 934 | luaL_error(L, "sprite height 0"); 935 | *h = lines; 936 | int width = get_sprite_width(L, ctx, idx, 1); 937 | if (width <= 0) 938 | luaL_error(L, "sprite width 0"); 939 | *w = width; 940 | int i; 941 | for (i=2;i<=lines;i++) { 942 | if (get_sprite_width(L, ctx, idx, i) != width) { 943 | luaL_error(L, "sprite is not a rect"); 944 | } 945 | } 946 | } 947 | 948 | static int 949 | lsprite(lua_State *L) { 950 | struct context *ctx = getCtx(L); 951 | luaL_checktype(L, 1, LUA_TTABLE); 952 | int w,h; 953 | check_sprite_size(L, ctx, 1, &w, &h); 954 | size_t sz = sprite_size(w,h); 955 | struct sprite *spr = (struct sprite *)lua_newuserdatauv(L, sz, 0); 956 | spr->w = w; 957 | spr->h = h; 958 | spr->x = 0; 959 | spr->y = 0; 960 | spr->kx =0; 961 | spr->ky =0; 962 | spr->prev = NULL; 963 | spr->next = NULL; 964 | struct sprite_attribs a; 965 | a.transparency = 0; 966 | if (lua_getfield(L, 1, "transparency") == LUA_TSTRING) { 967 | const char * t = lua_tostring(L, -1); 968 | a.transparency = (unsigned)*t; 969 | if (a.transparency > 127 || a.transparency == 0) { 970 | return luaL_error(L, "transparency is ascii only"); 971 | } 972 | } 973 | lua_pop(L, 1); 974 | a.color = get_color(L, 1, "color", 0xffff, NULL); 975 | a.background = get_color(L, 1, "background", 0, &spr->background); 976 | a.layer = 1; 977 | if (lua_getfield(L, 1, "layer") == LUA_TNUMBER) { 978 | int layer = lua_tointeger(L, -1); 979 | if (layer < 0) 980 | layer = 0; 981 | else if (layer > 255) 982 | layer = 255; 983 | a.layer = layer; 984 | } 985 | lua_pop(L, 1); 986 | if (lua_getfield(L, 1, "kx") == LUA_TNUMBER) { 987 | spr->kx = lua_tointeger(L, -1); 988 | } 989 | lua_pop(L, 1); 990 | if (lua_getfield(L, 1, "ky") == LUA_TNUMBER) { 991 | spr->ky = lua_tointeger(L, -1); 992 | } 993 | lua_pop(L, 1); 994 | 995 | sprite_graph(L, 1, ctx, spr, &a); 996 | if (luaL_newmetatable(L, "RSPRITE")) { 997 | luaL_Reg l[] = { 998 | { "setpos", lsetpos }, 999 | { "setcolor", lsetcolor }, 1000 | { "setlayer", lsetlayer }, 1001 | { "clone", NULL }, 1002 | { "visible", NULL }, 1003 | { "__tostring", lspriteinfo }, 1004 | { "__gc", NULL }, 1005 | { "__index", NULL }, 1006 | { NULL, NULL }, 1007 | }; 1008 | luaL_setfuncs(L, l, 0); 1009 | lua_pushvalue(L, -1); 1010 | lua_setfield(L, -2, "__index"); 1011 | 1012 | luaL_Reg l2[] = { 1013 | { "clone", lclone }, 1014 | { "visible", lvisible }, 1015 | { "text", lsettext }, 1016 | { "__gc", lvisible }, 1017 | { NULL, NULL }, 1018 | }; 1019 | 1020 | lua_pushvalue(L, lua_upvalueindex(1)); 1021 | luaL_setfuncs(L, l2, 1); 1022 | } 1023 | lua_setmetatable(L, -2); 1024 | link_sprite(ctx, spr); 1025 | return 1; 1026 | } 1027 | 1028 | static int 1029 | llayer(lua_State *L) { 1030 | struct context * ctx = getCtx(L); 1031 | luaL_checktype(L, 1, LUA_TTABLE); 1032 | lua_pushnil(L); 1033 | while (lua_next(L, 1) != 0) { 1034 | int isnum; 1035 | int layer = lua_tointegerx(L, -2, &isnum); 1036 | if (isnum && layer >=0 && layer <=255) { 1037 | int hide = lua_toboolean(L, -1); 1038 | ctx->layer[layer] = !hide; 1039 | } 1040 | lua_pop(L, 1); 1041 | } 1042 | return 0; 1043 | } 1044 | 1045 | LUAMOD_API int 1046 | luaopen_rogue_core(lua_State *L) { 1047 | luaL_checkversion(L); 1048 | luaL_Reg l[] = { 1049 | { "init", linit }, 1050 | { "frame", lframe }, 1051 | { "event", levent }, 1052 | { "sprite", lsprite }, 1053 | { "layer", llayer }, 1054 | { NULL, NULL }, 1055 | }; 1056 | luaL_newlibtable(L, l); 1057 | struct context *ctx = (struct context *)lua_newuserdatauv(L, sizeof(struct context), 1); 1058 | memset(ctx, 0, sizeof(*ctx)); 1059 | ctx->mousex = -1; 1060 | ctx->mousey = -1; 1061 | luaL_setfuncs(L,l,1); 1062 | return 1; 1063 | } 1064 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | assert(package.loadlib(assert(package.searchpath("SDL2", package.cpath)), "*")) 2 | 3 | local c = require "rogue.core" 4 | 5 | c.init { 6 | title = "测试", 7 | width = 80, 8 | height = 25, 9 | fps = 25, 10 | resizeable = true, 11 | scale = 1, 12 | software = true, 13 | vsync = true, 14 | } 15 | 16 | local background = c.sprite { 17 | [[..........................................]], 18 | [[..........................................]], 19 | [[.......................... ☺☻♥♦♣♠•◘○◙♂♀♪♫☼]], 20 | [[..........................►◄↕‼¶§▬↨↑↓→←∟↔▲▼]], 21 | [[.......................... !"#$%&'()*+,-./]], 22 | [[..........................0123456789:;<=>?]], 23 | [[..........................@ABCDEFGHIJKLMNO]], 24 | [[..........................PQRSTUVWXYZ[\]^_]], 25 | [[..........................`abcdefghijklmno]], 26 | [[..........................pqrstuvwxyz{|}~⌂]], 27 | [[..........................ÇüéâäàåçêëèïîìÄÅ]], 28 | [[..........................ÉæÆôöòûùÿÖÜ¢£¥₧ƒ]], 29 | [[..........................áíóúñѪº¿⌐¬½¼¡«»]], 30 | [[..........................░▒▓│┤╡╢╖╕╣║╗╝╜╛┐]], 31 | [[..........................└┴┬├─┼╞╟╚╔╩╦╠═╬╧]], 32 | [[..........................╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀]], 33 | [[..........................αßΓπΣσµτΦΘΩδ∞φε∩]], 34 | [[..........................≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ]], 35 | [[................................你好,世界]], 36 | color = 0x404040, 37 | layer = 1, 38 | } 39 | 40 | local s = c.sprite { 41 | ".-----.", 42 | "| ^ ^ |", 43 | "| - |", 44 | ".-----.", 45 | color = 0xff0000, 46 | transparency = '.', 47 | layer = 2, 48 | kx = 3, 49 | ky = 3, 50 | } 51 | 52 | local title = c.sprite { 53 | " ", 54 | " ", 55 | color = 0x80ff, 56 | layer = 3, 57 | kx = 3, 58 | ky = -1, 59 | } 60 | 61 | local s2 = s:clone(true) 62 | s2:setcolor(0xff00) 63 | s2:setcolor { 64 | Y = 0xffff00, 65 | W = 0xffffff, 66 | ".-----.", 67 | "| Y Y |", 68 | "| W |", 69 | ".-----.", 70 | } 71 | 72 | s2:setpos(5,5) 73 | 74 | local mouse_cursor = c.sprite { 75 | " ", 76 | background = 0x808080, 77 | layer = 0, 78 | } 79 | 80 | 81 | local x = 3 82 | local y = 3 83 | 84 | local camera_x = 0 85 | local camera_y = 0 86 | 87 | local EVENT = {} 88 | 89 | function EVENT.QUIT() 90 | return true 91 | end 92 | 93 | function EVENT.KEY(name, press) 94 | if press then 95 | if name == "Left" then 96 | x = x - 1 97 | elseif name == "Right" then 98 | x = x + 1 99 | elseif name == "Up" then 100 | y = y - 1 101 | elseif name == "Down" then 102 | y = y + 1 103 | elseif name == "Q" then 104 | title:visible(false) 105 | elseif name == "Z" then 106 | c.layer { [1] = false } 107 | elseif name == "A" then 108 | camera_x = camera_x - 1 109 | elseif name == "D" then 110 | camera_x = camera_x + 1 111 | elseif name == "W" then 112 | camera_y = camera_y - 1 113 | elseif name == "S" then 114 | camera_y = camera_y + 1 115 | end 116 | else 117 | if name == "Q" then 118 | title:visible(true) 119 | elseif name == "Z" then 120 | c.layer { [1] = true } 121 | end 122 | end 123 | end 124 | 125 | function EVENT.MOTION(x, y) 126 | mouse_cursor:setpos(x,y) 127 | end 128 | 129 | function EVENT.BUTTON(x, y, button, pressed, click) 130 | mouse_cursor:setpos(x,y) 131 | mouse_cursor:visible(not pressed) 132 | end 133 | 134 | local function dispatch(name, ...) 135 | if name then 136 | return not EVENT[name](...) 137 | else 138 | return true 139 | end 140 | end 141 | 142 | while dispatch(c.event()) do 143 | s:setpos(x,y) 144 | title:setpos(x, y) 145 | title:text(string.format("x = %d\ny = %d", x, y)) 146 | c.frame(camera_x, camera_y) 147 | end 148 | --------------------------------------------------------------------------------