Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest]
os: [windows-latest, macos-latest, ubuntu-latest]
steps:
- uses: actions/checkout@v5
with:
Expand Down Expand Up @@ -102,11 +102,20 @@ jobs:
- uses: yuchanns/actions-luamake@v1.0.0
with:
luamake-version: "5bedfce66f075a9f68b1475747738b81b3b41c25"
- name: Install Dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y build-essential \
libgl1-mesa-dev libglu1-mesa-dev libx11-dev \
libxrandr-dev libxi-dev libxxf86vm-dev libxcursor-dev \
libasound2-dev libfontconfig1-dev
- name: Build (Windows)
if: runner.os == 'Windows'
shell: powershell
id: build-windows
run: |
luamake clean
luamake precompile
luamake soluna
$SOLUNA_BINARY = "soluna.exe"
Expand All @@ -122,8 +131,15 @@ jobs:
run: |
luamake precompile
luamake soluna
if [[ "$RUNNER_OS" == "Linux" ]]; then
RENAME_BINARY="soluna-linux-amd64"
elif [[ "$RUNNER_OS" == "macOS" ]]; then
RENAME_BINARY="soluna-macos-arm64"
else
echo "Unsupported OS: $RUNNER_OS"
exit 1
fi
SOLUNA_BINARY="soluna"
RENAME_BINARY="soluna-macos-arm64"
SOLUNA_PATH=$(find bin -name $SOLUNA_BINARY | head -n 1)
cp "$SOLUNA_PATH" "bin/$RENAME_BINARY"
echo "SOLUNA_PATH=bin/$RENAME_BINARY" >> $GITHUB_OUTPUT
Expand Down
3 changes: 2 additions & 1 deletion clibs/sokol/make.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ end

for path in fs.pairs("src") do
local lang = lm.os == "windows" and "hlsl4" or
lm.os == "macos" and "metal_macos" or "unknown"
lm.os == "macos" and "metal_macos" or
lm.os == "linux" and "glsl430" or "unknown"
if path:extension() == ".glsl" then
local base = path:stem():string()
compile_shader(path:string(), base .. ".glsl.h", lang)
Expand Down
14 changes: 14 additions & 0 deletions clibs/soluna/make.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ lm:source_set "soluna_src" {
"-x objective-c",
},
},
linux = {
links = {
"pthread",
"dl",
"GL",
"X11",
"Xrandr",
"Xi",
"Xxf86vm",
"Xcursor",
"GLU",
"asound",
},
},
msvc = {
ldflags = {
"-SUBSYSTEM:WINDOWS",
Expand Down
3 changes: 3 additions & 0 deletions make.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ lm:conf({
lm.os ~= "windows" and "fontconfig",
},
},
defines = {
-- "SOKOL_DEBUG",
}
})

lm:import "clibs/lua/make.lua"
Expand Down
26 changes: 26 additions & 0 deletions src/entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

#define SOKOL_METAL

#elif defined(__linux__)

#define SOKOL_GLCORE

#else

#error Unsupport platform
Expand Down Expand Up @@ -40,6 +44,10 @@

#define PLATFORM "macos"

#elif defined(__linux__)

#define PLATFORM "linux"

#else

#define PLATFORM "unknown"
Expand Down Expand Up @@ -168,10 +176,28 @@ lmqueue(lua_State *L) {
return 1;
}

static int
lcontext_acquire(lua_State *L) {
#if defined(__linux__)
_sapp_glx_make_current();
#endif
return 0;
}

static int
lcontext_release(lua_State *L) {
#if defined(__linux__)
_sapp.glx.MakeCurrent(_sapp.x11.display, None, NULL);
#endif
return 0;
}

int
luaopen_soluna_app(lua_State *L) {
luaL_checkversion(L);
luaL_Reg l[] = {
{ "context_acquire", lcontext_acquire },
{ "context_release", lcontext_release },
{ "mqueue", lmqueue },
{ "unpackmessage", lmessage_unpack },
{ "sendmessage", lmessage_send },
Expand Down
88 changes: 88 additions & 0 deletions src/font_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,94 @@ lttfdata(lua_State *L) {
return 1;
}

#elif defined(__linux__)

#include <fontconfig/fontconfig.h>
#include <stdio.h>
#include <stdlib.h>

static void *
free_data(void *ud, void *ptr, size_t oszie, size_t nsize) {
free(ptr);
return NULL;
}

static int
lttfdata(lua_State *L) {
const char *familyName = luaL_checkstring(L, 1);

if (!FcInit()) {
return luaL_error(L, "Failed to initialize fontconfig");
}

FcPattern *pattern = FcNameParse((const FcChar8*)familyName);
if (!pattern) {
FcFini();
return luaL_error(L, "Failed to parse font name: %s", familyName);
}

FcConfigSubstitute(NULL, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);

FcResult result;
FcPattern *match = FcFontMatch(NULL, pattern, &result);
FcPatternDestroy(pattern);

if (!match || result != FcResultMatch) {
if (match) FcPatternDestroy(match);
FcFini();
return luaL_error(L, "Font not found: %s", familyName);
}

FcChar8 *filename;
if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) {
FcPatternDestroy(match);
FcFini();
return luaL_error(L, "Failed to get font file path for: %s", familyName);
}

FILE *file = fopen((const char*)filename, "rb");
if (!file) {
FcPatternDestroy(match);
FcFini();
return luaL_error(L, "Failed to open font file: %s", filename);
}

fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);

if (fileSize <= 0) {
fclose(file);
FcPatternDestroy(match);
FcFini();
return luaL_error(L, "Invalid font file size: %s", filename);
}

char *buf = malloc(fileSize + 1);
if (!buf) {
fclose(file);
FcPatternDestroy(match);
FcFini();
return luaL_error(L, "Out of memory : sysfont");
}

size_t bytesRead = fread(buf, 1, fileSize, file);
fclose(file);
FcPatternDestroy(match);
FcFini();

if (bytesRead != fileSize) {
free(buf);
return luaL_error(L, "Failed to read font file: %s", filename);
}

buf[fileSize] = 0;

lua_pushexternalstring(L, buf, fileSize, free_data, NULL);
return 1;
}

#else

static int
Expand Down
64 changes: 64 additions & 0 deletions src/gamepad.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,70 @@ gamepad_getstate(int index, struct gamepad_state *state) {
return 0;
}

#elif defined(__linux__)

#include <fcntl.h>
#include <unistd.h>
#include <linux/joystick.h>
#include <sys/ioctl.h>

static int
gamepad_getstate(int index, struct gamepad_state *state) {
char device_path[32];
snprintf(device_path, sizeof(device_path), "/dev/input/js%d", index);

int fd = open(device_path, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
return 1;
}

static struct {
uint16_t buttons;
uint8_t lt, rt;
int16_t ls_x, ls_y, rs_x, rs_y;
uint32_t packet;
} cache = {0};

struct js_event event;

while (read(fd, &event, sizeof(event)) == sizeof(event)) {
cache.packet++;

if (event.type & JS_EVENT_BUTTON) {
if (event.number < 16) {
if (event.value) {
cache.buttons |= (1 << event.number);
} else {
cache.buttons &= ~(1 << event.number);
}
}
} else if (event.type & JS_EVENT_AXIS) {
int16_t value = event.value;
switch (event.number) {
case 0: cache.ls_x = value; break;
case 1: cache.ls_y = -value; break;
case 2: cache.lt = (value + 32768) >> 8; break;
case 3: cache.rs_x = value; break;
case 4: cache.rs_y = -value; break;
case 5: cache.rt = (value + 32768) >> 8; break;
}
}
}

close(fd);

state->packet = cache.packet;
state->buttons = cache.buttons;
state->lt = cache.lt;
state->rt = cache.rt;
state->ls_x = cache.ls_x;
state->ls_y = cache.ls_y;
state->rs_x = cache.rs_x;
state->rs_y = cache.rs_y;

return 0;
}

#else

// todo : linux and mac support
Expand Down
15 changes: 14 additions & 1 deletion src/lualib/fontmgr.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,20 @@ local ids = {
UNICODE_2_0_BMP = 3,
UNICODE_2_0_FULL = 4,
},
lang = { default = 0 },
lang = {
default = 0,
ENGLISH = 0,
CHINESE = 1,
FRENCH = 2,
GERMAN = 3,
JAPANESE = 4,
KOREAN = 5,
SPANISH = 6,
ITALIAN = 7,
DUTCH = 8,
SWEDISH = 9,
RUSSIAN = 10,
},
},
MICROSOFT = {
id = 3,
Expand Down
2 changes: 2 additions & 0 deletions src/lualib/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,10 @@ local function start(config)
if v then
dispatch_appmsg(v)
end
soluna_app.context_release()
send_message("frame", count)
frame_barrier:wait()
soluna_app.context_acquire()
end,
event = function(ev)
send_message(unpackevent(ev))
Expand Down
2 changes: 1 addition & 1 deletion src/lualib/soluna.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function soluna.gamedir(name)
dir = dir .. "\\" .. name
lfs.mkdir(dir)
return dir .. "\\"
elseif soluna.platform == "macos" then
elseif soluna.platform == "macos" or soluna.platform == "linux" then
local lfs = require "soluna.lfs"
local dir = lfs.personaldir() .. "/.local/share"
lfs.mkdir(dir)
Expand Down
6 changes: 6 additions & 0 deletions src/material_default.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ lmaterial_default_draw(lua_State *L) {
static void
init_pipeline(struct material_default *p) {
sg_shader shd = sg_make_shader(texquad_shader_desc(sg_query_backend()));
if (sg_query_shader_state(shd) != SG_RESOURCESTATE_VALID) {
fprintf(stderr, "failed to create shader for default material\n");
}

p->pip = sg_make_pipeline(&(sg_pipeline_desc) {
.layout = {
Expand All @@ -117,6 +120,9 @@ init_pipeline(struct material_default *p) {
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
.label = "default-pipeline"
});
if (sg_query_pipeline_state(p->pip) != SG_RESOURCESTATE_VALID) {
fprintf(stderr, "failed to create pipeline for default material\n");
}
}

static int
Expand Down
6 changes: 6 additions & 0 deletions src/material_mask.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ lmaterial_mask_draw(lua_State *L) {
static void
init_pipeline(struct material_mask *p) {
sg_shader shd = sg_make_shader(maskquad_shader_desc(sg_query_backend()));
if (sg_query_shader_state(shd) != SG_RESOURCESTATE_VALID) {
fprintf(stderr, "Failed to create shader for mask material!\n");
}

p->pip = sg_make_pipeline(&(sg_pipeline_desc) {
.layout = {
Expand All @@ -132,6 +135,9 @@ init_pipeline(struct material_mask *p) {
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
.label = "mask-pipeline"
});
if (sg_query_pipeline_state(p->pip) != SG_RESOURCESTATE_VALID) {
fprintf(stderr, "Failed to create pipeline for mask material!\n");
}
}

static int
Expand Down
Loading
Loading