Skip to content

Commit caf36eb

Browse files
authored
Merge pull request #10 from yuchanns/feat/support-linux
feat: support Linux
2 parents aa87867 + 4ca2c46 commit caf36eb

File tree

15 files changed

+267
-10
lines changed

15 files changed

+267
-10
lines changed

.github/workflows/nightly.yml

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ jobs:
6969
strategy:
7070
fail-fast: false
7171
matrix:
72-
os: [windows-latest, macos-latest]
72+
os: [windows-latest, macos-latest, ubuntu-latest]
7373
steps:
7474
- uses: actions/checkout@v5
7575
with:
@@ -102,11 +102,20 @@ jobs:
102102
- uses: yuchanns/actions-luamake@v1.0.0
103103
with:
104104
luamake-version: "5bedfce66f075a9f68b1475747738b81b3b41c25"
105+
- name: Install Dependencies (Linux)
106+
if: runner.os == 'Linux'
107+
run: |
108+
sudo apt-get update
109+
sudo apt-get install -y build-essential \
110+
libgl1-mesa-dev libglu1-mesa-dev libx11-dev \
111+
libxrandr-dev libxi-dev libxxf86vm-dev libxcursor-dev \
112+
libasound2-dev libfontconfig1-dev
105113
- name: Build (Windows)
106114
if: runner.os == 'Windows'
107115
shell: powershell
108116
id: build-windows
109117
run: |
118+
luamake clean
110119
luamake precompile
111120
luamake soluna
112121
$SOLUNA_BINARY = "soluna.exe"
@@ -122,8 +131,15 @@ jobs:
122131
run: |
123132
luamake precompile
124133
luamake soluna
134+
if [[ "$RUNNER_OS" == "Linux" ]]; then
135+
RENAME_BINARY="soluna-linux-amd64"
136+
elif [[ "$RUNNER_OS" == "macOS" ]]; then
137+
RENAME_BINARY="soluna-macos-arm64"
138+
else
139+
echo "Unsupported OS: $RUNNER_OS"
140+
exit 1
141+
fi
125142
SOLUNA_BINARY="soluna"
126-
RENAME_BINARY="soluna-macos-arm64"
127143
SOLUNA_PATH=$(find bin -name $SOLUNA_BINARY | head -n 1)
128144
cp "$SOLUNA_PATH" "bin/$RENAME_BINARY"
129145
echo "SOLUNA_PATH=bin/$RENAME_BINARY" >> $GITHUB_OUTPUT

clibs/sokol/make.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ end
2222

2323
for path in fs.pairs("src") do
2424
local lang = lm.os == "windows" and "hlsl4" or
25-
lm.os == "macos" and "metal_macos" or "unknown"
25+
lm.os == "macos" and "metal_macos" or
26+
lm.os == "linux" and "glsl430" or "unknown"
2627
if path:extension() == ".glsl" then
2728
local base = path:stem():string()
2829
compile_shader(path:string(), base .. ".glsl.h", lang)

clibs/soluna/make.lua

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,20 @@ lm:source_set "soluna_src" {
2727
"-x objective-c",
2828
},
2929
},
30+
linux = {
31+
links = {
32+
"pthread",
33+
"dl",
34+
"GL",
35+
"X11",
36+
"Xrandr",
37+
"Xi",
38+
"Xxf86vm",
39+
"Xcursor",
40+
"GLU",
41+
"asound",
42+
},
43+
},
3044
msvc = {
3145
ldflags = {
3246
"-SUBSYSTEM:WINDOWS",

make.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ lm:conf({
6262
lm.os ~= "windows" and "fontconfig",
6363
},
6464
},
65+
defines = {
66+
-- "SOKOL_DEBUG",
67+
}
6568
})
6669

6770
lm:import "clibs/lua/make.lua"

src/entry.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
#define SOKOL_METAL
1010

11+
#elif defined(__linux__)
12+
13+
#define SOKOL_GLCORE
14+
1115
#else
1216

1317
#error Unsupport platform
@@ -40,6 +44,10 @@
4044

4145
#define PLATFORM "macos"
4246

47+
#elif defined(__linux__)
48+
49+
#define PLATFORM "linux"
50+
4351
#else
4452

4553
#define PLATFORM "unknown"
@@ -168,10 +176,28 @@ lmqueue(lua_State *L) {
168176
return 1;
169177
}
170178

179+
static int
180+
lcontext_acquire(lua_State *L) {
181+
#if defined(__linux__)
182+
_sapp_glx_make_current();
183+
#endif
184+
return 0;
185+
}
186+
187+
static int
188+
lcontext_release(lua_State *L) {
189+
#if defined(__linux__)
190+
_sapp.glx.MakeCurrent(_sapp.x11.display, None, NULL);
191+
#endif
192+
return 0;
193+
}
194+
171195
int
172196
luaopen_soluna_app(lua_State *L) {
173197
luaL_checkversion(L);
174198
luaL_Reg l[] = {
199+
{ "context_acquire", lcontext_acquire },
200+
{ "context_release", lcontext_release },
175201
{ "mqueue", lmqueue },
176202
{ "unpackmessage", lmessage_unpack },
177203
{ "sendmessage", lmessage_send },

src/font_system.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,94 @@ lttfdata(lua_State *L) {
178178
return 1;
179179
}
180180

181+
#elif defined(__linux__)
182+
183+
#include <fontconfig/fontconfig.h>
184+
#include <stdio.h>
185+
#include <stdlib.h>
186+
187+
static void *
188+
free_data(void *ud, void *ptr, size_t oszie, size_t nsize) {
189+
free(ptr);
190+
return NULL;
191+
}
192+
193+
static int
194+
lttfdata(lua_State *L) {
195+
const char *familyName = luaL_checkstring(L, 1);
196+
197+
if (!FcInit()) {
198+
return luaL_error(L, "Failed to initialize fontconfig");
199+
}
200+
201+
FcPattern *pattern = FcNameParse((const FcChar8*)familyName);
202+
if (!pattern) {
203+
FcFini();
204+
return luaL_error(L, "Failed to parse font name: %s", familyName);
205+
}
206+
207+
FcConfigSubstitute(NULL, pattern, FcMatchPattern);
208+
FcDefaultSubstitute(pattern);
209+
210+
FcResult result;
211+
FcPattern *match = FcFontMatch(NULL, pattern, &result);
212+
FcPatternDestroy(pattern);
213+
214+
if (!match || result != FcResultMatch) {
215+
if (match) FcPatternDestroy(match);
216+
FcFini();
217+
return luaL_error(L, "Font not found: %s", familyName);
218+
}
219+
220+
FcChar8 *filename;
221+
if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) {
222+
FcPatternDestroy(match);
223+
FcFini();
224+
return luaL_error(L, "Failed to get font file path for: %s", familyName);
225+
}
226+
227+
FILE *file = fopen((const char*)filename, "rb");
228+
if (!file) {
229+
FcPatternDestroy(match);
230+
FcFini();
231+
return luaL_error(L, "Failed to open font file: %s", filename);
232+
}
233+
234+
fseek(file, 0, SEEK_END);
235+
long fileSize = ftell(file);
236+
fseek(file, 0, SEEK_SET);
237+
238+
if (fileSize <= 0) {
239+
fclose(file);
240+
FcPatternDestroy(match);
241+
FcFini();
242+
return luaL_error(L, "Invalid font file size: %s", filename);
243+
}
244+
245+
char *buf = malloc(fileSize + 1);
246+
if (!buf) {
247+
fclose(file);
248+
FcPatternDestroy(match);
249+
FcFini();
250+
return luaL_error(L, "Out of memory : sysfont");
251+
}
252+
253+
size_t bytesRead = fread(buf, 1, fileSize, file);
254+
fclose(file);
255+
FcPatternDestroy(match);
256+
FcFini();
257+
258+
if (bytesRead != fileSize) {
259+
free(buf);
260+
return luaL_error(L, "Failed to read font file: %s", filename);
261+
}
262+
263+
buf[fileSize] = 0;
264+
265+
lua_pushexternalstring(L, buf, fileSize, free_data, NULL);
266+
return 1;
267+
}
268+
181269
#else
182270

183271
static int

src/gamepad.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,70 @@ gamepad_getstate(int index, struct gamepad_state *state) {
182182
return 0;
183183
}
184184

185+
#elif defined(__linux__)
186+
187+
#include <fcntl.h>
188+
#include <unistd.h>
189+
#include <linux/joystick.h>
190+
#include <sys/ioctl.h>
191+
192+
static int
193+
gamepad_getstate(int index, struct gamepad_state *state) {
194+
char device_path[32];
195+
snprintf(device_path, sizeof(device_path), "/dev/input/js%d", index);
196+
197+
int fd = open(device_path, O_RDONLY | O_NONBLOCK);
198+
if (fd < 0) {
199+
return 1;
200+
}
201+
202+
static struct {
203+
uint16_t buttons;
204+
uint8_t lt, rt;
205+
int16_t ls_x, ls_y, rs_x, rs_y;
206+
uint32_t packet;
207+
} cache = {0};
208+
209+
struct js_event event;
210+
211+
while (read(fd, &event, sizeof(event)) == sizeof(event)) {
212+
cache.packet++;
213+
214+
if (event.type & JS_EVENT_BUTTON) {
215+
if (event.number < 16) {
216+
if (event.value) {
217+
cache.buttons |= (1 << event.number);
218+
} else {
219+
cache.buttons &= ~(1 << event.number);
220+
}
221+
}
222+
} else if (event.type & JS_EVENT_AXIS) {
223+
int16_t value = event.value;
224+
switch (event.number) {
225+
case 0: cache.ls_x = value; break;
226+
case 1: cache.ls_y = -value; break;
227+
case 2: cache.lt = (value + 32768) >> 8; break;
228+
case 3: cache.rs_x = value; break;
229+
case 4: cache.rs_y = -value; break;
230+
case 5: cache.rt = (value + 32768) >> 8; break;
231+
}
232+
}
233+
}
234+
235+
close(fd);
236+
237+
state->packet = cache.packet;
238+
state->buttons = cache.buttons;
239+
state->lt = cache.lt;
240+
state->rt = cache.rt;
241+
state->ls_x = cache.ls_x;
242+
state->ls_y = cache.ls_y;
243+
state->rs_x = cache.rs_x;
244+
state->rs_y = cache.rs_y;
245+
246+
return 0;
247+
}
248+
185249
#else
186250

187251
// todo : linux and mac support

src/lualib/fontmgr.lua

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,20 @@ local ids = {
3939
UNICODE_2_0_BMP = 3,
4040
UNICODE_2_0_FULL = 4,
4141
},
42-
lang = { default = 0 },
42+
lang = {
43+
default = 0,
44+
ENGLISH = 0,
45+
CHINESE = 1,
46+
FRENCH = 2,
47+
GERMAN = 3,
48+
JAPANESE = 4,
49+
KOREAN = 5,
50+
SPANISH = 6,
51+
ITALIAN = 7,
52+
DUTCH = 8,
53+
SWEDISH = 9,
54+
RUSSIAN = 10,
55+
},
4356
},
4457
MICROSOFT = {
4558
id = 3,

src/lualib/main.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,10 @@ local function start(config)
124124
if v then
125125
dispatch_appmsg(v)
126126
end
127+
soluna_app.context_release()
127128
send_message("frame", count)
128129
frame_barrier:wait()
130+
soluna_app.context_acquire()
129131
end,
130132
event = function(ev)
131133
send_message(unpackevent(ev))

src/lualib/soluna.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function soluna.gamedir(name)
4949
dir = dir .. "\\" .. name
5050
lfs.mkdir(dir)
5151
return dir .. "\\"
52-
elseif soluna.platform == "macos" then
52+
elseif soluna.platform == "macos" or soluna.platform == "linux" then
5353
local lfs = require "soluna.lfs"
5454
local dir = lfs.personaldir() .. "/.local/share"
5555
lfs.mkdir(dir)

0 commit comments

Comments
 (0)