mirror of
https://github.com/NeoFlock/neonucleus.git
synced 2026-02-15 04:03:49 +01:00
progress on unicode lib
This commit is contained in:
parent
66b73ec006
commit
a2ddcfa030
@ -40,5 +40,5 @@ shell.setWorkingDirectory(os.getenv("HOME"))
|
||||
|
||||
local home_shrc = shell.resolve(".shrc")
|
||||
if fs.exists(home_shrc) then
|
||||
loadfile(shell.resolve("source", "lua"))(home_shrc)
|
||||
assert(loadfile(shell.resolve("source", "lua")))(home_shrc)
|
||||
end
|
||||
|
||||
@ -14,10 +14,12 @@ do
|
||||
end
|
||||
|
||||
while true do
|
||||
debug.print("try shell")
|
||||
local result, reason = xpcall(require("shell").getShell(), function(msg)
|
||||
return tostring(msg).."\n"..debug.traceback()
|
||||
end)
|
||||
if not result then
|
||||
debug.print(reason)
|
||||
io.stderr:write((reason ~= nil and tostring(reason) or "unknown error") .. "\n")
|
||||
io.write("Press any key to continue.\n")
|
||||
os.sleep(0.5)
|
||||
|
||||
@ -409,6 +409,81 @@ static int luaArch_component_fields(lua_State *L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_unicode_char(lua_State *L) {
|
||||
size_t argc = lua_gettop(L);
|
||||
size_t len = 0;
|
||||
for(int i = 1; i <= argc; i++) {
|
||||
nn_codepoint codepoint = lua_tointeger(L, i);
|
||||
size_t size = nn_unicode_codepointSize(codepoint);
|
||||
if(size == 0) luaL_error(L, "codepoint #%d out of range", i);
|
||||
len += size;
|
||||
}
|
||||
char *buf = malloc(len);
|
||||
len = 0;
|
||||
for(int i = 1; i <= argc; i++) {
|
||||
nn_codepoint codepoint = lua_tointeger(L, i);
|
||||
size_t size = nn_unicode_codepointToChar(buf + len, codepoint);
|
||||
len += size;
|
||||
}
|
||||
lua_pushlstring(L, buf, len);
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_unicode_len(lua_State *L) {
|
||||
size_t len;
|
||||
const char *s = lua_tolstring(L, 1, &len);
|
||||
len = nn_unicode_lenPermissive(s, len);
|
||||
lua_pushinteger(L, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_unicode_sub(lua_State *L) {
|
||||
size_t slen;
|
||||
const char *s = lua_tolstring(L, 1, &slen);
|
||||
if(lua_gettop(L) < 2) lua_pushinteger(L, 1);
|
||||
if(lua_gettop(L) < 3) lua_pushinteger(L, -1);
|
||||
|
||||
size_t len = nn_unicode_lenPermissive(s, slen);
|
||||
|
||||
int start = lua_tointeger(L, 2);
|
||||
int end = lua_tointeger(L, 3);
|
||||
|
||||
if(end == 0) {
|
||||
lua_pushstring(L, "");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(start > 0) start--;
|
||||
if(start < 0) start = len + start;
|
||||
if(end > 0) end--;
|
||||
if(end < 0) end = len + end;
|
||||
|
||||
if(start < 0) start = 0;
|
||||
if(start >= len) start = len-1;
|
||||
if(end < 0) end = 0;
|
||||
if(end >= len) end = len-1;
|
||||
|
||||
nn_codepoint *cp = malloc(sizeof(*cp) * len);
|
||||
nn_unicode_codepointsPermissive(s, slen, cp);
|
||||
|
||||
size_t substrlen = nn_unicode_countBytes(cp + start, end - start + 1);
|
||||
char *buf = malloc(substrlen);
|
||||
nn_unicode_writeBytes(buf, cp + start, end - start + 1);
|
||||
lua_pushlstring(L, buf, substrlen);
|
||||
free(buf);
|
||||
free(cp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaArch_unicode_wlen(lua_State *L) {
|
||||
size_t slen;
|
||||
const char *s = lua_tolstring(L, 1, &slen);
|
||||
size_t len = nn_unicode_wlenPermissive(s, slen);
|
||||
lua_pushinteger(L, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void luaArch_loadEnv(lua_State *L) {
|
||||
lua_createtable(L, 0, 10);
|
||||
int computer = lua_gettop(L);
|
||||
@ -464,6 +539,17 @@ static void luaArch_loadEnv(lua_State *L) {
|
||||
lua_pushcfunction(L, luaArch_component_fields);
|
||||
lua_setfield(L, component, "fields");
|
||||
lua_setglobal(L, "component");
|
||||
lua_createtable(L, 0, 10);
|
||||
int unicode = lua_gettop(L);
|
||||
lua_pushcfunction(L, luaArch_unicode_char);
|
||||
lua_setfield(L, component, "char");
|
||||
lua_pushcfunction(L, luaArch_unicode_len);
|
||||
lua_setfield(L, component, "len");
|
||||
lua_pushcfunction(L, luaArch_unicode_sub);
|
||||
lua_setfield(L, component, "sub");
|
||||
lua_pushcfunction(L, luaArch_unicode_wlen);
|
||||
lua_setfield(L, component, "wlen");
|
||||
lua_setglobal(L, "unicode");
|
||||
}
|
||||
|
||||
static nn_Exit luaArch_handler(nn_ArchitectureRequest *req) {
|
||||
|
||||
@ -163,9 +163,6 @@ function checkArg(arg, val, ...)
|
||||
error("bad argument #" .. arg .. " (" .. table.concat(t, ", ") .. ") expected", 2)
|
||||
end
|
||||
|
||||
-- HORRENDOUS approximation
|
||||
unicode = string
|
||||
|
||||
if os.getenv("NN_REPL") == "1" then
|
||||
while true do
|
||||
io.write("lua> ")
|
||||
|
||||
324
rewrite/main.c
324
rewrite/main.c
@ -9,6 +9,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <raylib.h>
|
||||
|
||||
nn_Architecture getLuaArch();
|
||||
|
||||
@ -292,6 +293,7 @@ typedef struct ne_ScreenBuffer {
|
||||
int maxHeight;
|
||||
int width;
|
||||
int height;
|
||||
char depth;
|
||||
char maxDepth;
|
||||
ne_Pixel *pixels;
|
||||
int maxPalette;
|
||||
@ -301,13 +303,39 @@ typedef struct ne_ScreenBuffer {
|
||||
const char *keyboard;
|
||||
} ne_ScreenBuffer;
|
||||
|
||||
bool ne_ocCompatibleColors = true;
|
||||
|
||||
void ne_remapScreen(ne_ScreenBuffer *buf) {
|
||||
int depth = buf->maxDepth;
|
||||
|
||||
for(int i = 0; i < buf->maxPalette; i++) {
|
||||
buf->mappedPalette[i] = nn_mapDepth(buf->virtualPalette[i], depth, ne_ocCompatibleColors);
|
||||
}
|
||||
|
||||
for(int y = 0; y < buf->height; y++) {
|
||||
for(int x = 0; x < buf->width; x++) {
|
||||
ne_Pixel *pixel = &buf->pixels[y * buf->maxWidth + x];
|
||||
int virtfg = pixel->fg, virtbg = pixel->bg;
|
||||
if(pixel->isFgPalette) virtfg = buf->mappedPalette[virtfg];
|
||||
else virtfg = nn_mapDepth(virtfg, depth, ne_ocCompatibleColors);
|
||||
if(pixel->isBgPalette) virtbg = buf->mappedPalette[virtfg];
|
||||
else virtbg = nn_mapDepth(virtbg, depth, ne_ocCompatibleColors);
|
||||
|
||||
pixel->truefg = virtfg;
|
||||
pixel->truebg = virtbg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ne_ScreenBuffer *ne_newScreenBuf(nn_ScreenConfig conf, const char *keyboard) {
|
||||
ne_ScreenBuffer *buf = malloc(sizeof(*buf));
|
||||
buf->maxWidth = conf.maxWidth;
|
||||
buf->maxHeight = conf.maxHeight;
|
||||
buf->width = buf->maxWidth;
|
||||
buf->height = buf->maxHeight;
|
||||
buf->maxDepth = conf.maxDepth;
|
||||
buf->depth = buf->maxDepth;
|
||||
buf->maxPalette = conf.paletteColors;
|
||||
buf->editableColors = conf.editableColors;
|
||||
buf->pixels = malloc(sizeof(ne_Pixel) * conf.maxWidth * conf.maxHeight);
|
||||
buf->virtualPalette = malloc(sizeof(int) * conf.paletteColors);
|
||||
memset(buf->virtualPalette, 0, sizeof(int) * buf->maxPalette);
|
||||
@ -315,26 +343,73 @@ ne_ScreenBuffer *ne_newScreenBuf(nn_ScreenConfig conf, const char *keyboard) {
|
||||
buf->keyboard = keyboard;
|
||||
|
||||
int *palette = NULL;
|
||||
// TODO: uncomment once the palettes are implemented
|
||||
if(buf->maxPalette == 16) {
|
||||
//palette = nn_mcpalette4;
|
||||
if(buf->maxDepth == 4) {
|
||||
palette = nn_mcpalette4;
|
||||
}
|
||||
if(buf->maxPalette == 256) {
|
||||
//palette = nn_ocpalette8;
|
||||
if(buf->maxDepth == 8) {
|
||||
palette = nn_ocpalette8;
|
||||
}
|
||||
if(palette) memcpy(buf->virtualPalette, palette, sizeof(int) * buf->maxPalette);
|
||||
memcpy(buf->mappedPalette, buf->virtualPalette, sizeof(int) * buf->maxPalette);
|
||||
|
||||
for(int y = 0; y < buf->height; y++) {
|
||||
for(int x = 0; x < buf->width; x++) {
|
||||
buf->pixels[y * buf->width + x] = (ne_Pixel) {
|
||||
.fg = 0xFFFFFF,
|
||||
.bg = 0x000000,
|
||||
.isFgPalette = false,
|
||||
.isBgPalette = false,
|
||||
.codepoint = ' ',
|
||||
.truefg = 0xFFFFFF,
|
||||
.truebg = 0x000000,
|
||||
};
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void ne_dropScreenBuf(ne_ScreenBuffer *buf) {
|
||||
free(buf->pixels);
|
||||
free(buf->mappedPalette);
|
||||
free(buf->virtualPalette);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
ne_Pixel defaultPixel = {
|
||||
.codepoint = ' ',
|
||||
.fg = 0xFFFFFF,
|
||||
.bg = 0x000000,
|
||||
.isFgPalette = false,
|
||||
.isBgPalette = false,
|
||||
.truefg = 0xFFFFFF,
|
||||
.truebg = 0x000000,
|
||||
};
|
||||
|
||||
bool ne_inScreenBuf(ne_ScreenBuffer *buf, int x, int y) {
|
||||
return x > 0 && y > 0 && x <= buf->width && y <= buf->height;
|
||||
}
|
||||
|
||||
ne_Pixel ne_getPixel(ne_ScreenBuffer *buf, int x, int y) {
|
||||
if(!ne_inScreenBuf(buf, x, y)) return defaultPixel;
|
||||
x--;
|
||||
y--;
|
||||
return buf->pixels[y * buf->maxWidth + x];
|
||||
}
|
||||
|
||||
void ne_setPixel(ne_ScreenBuffer *buf, int x, int y, ne_Pixel pixel) {
|
||||
if(!ne_inScreenBuf(buf, x, y)) return;
|
||||
x--;
|
||||
y--;
|
||||
buf->pixels[y * buf->maxWidth + x] = pixel;
|
||||
}
|
||||
|
||||
nn_Exit ne_screen_handler(nn_ScreenRequest *req) {
|
||||
ne_ScreenBuffer *buf = req->instance;
|
||||
switch(req->action) {
|
||||
case NN_SCR_DROP:
|
||||
free(buf->pixels);
|
||||
free(buf->mappedPalette);
|
||||
free(buf->virtualPalette);
|
||||
free(buf);
|
||||
// this'd require the GPU is dropped first...
|
||||
// its best we just dont bother and free later
|
||||
//ne_dropScreenBuf(buf);
|
||||
return NN_OK;
|
||||
case NN_SCR_GETASPECTRATIO:
|
||||
req->w = 1;
|
||||
@ -377,9 +452,181 @@ nn_Exit ne_screen_handler(nn_ScreenRequest *req) {
|
||||
return NN_OK;
|
||||
}
|
||||
|
||||
#define NE_MAX_VRAMBUF 16
|
||||
|
||||
typedef struct ne_GPUState {
|
||||
ne_ScreenBuffer *screenBuf;
|
||||
int currentFg;
|
||||
int currentBg;
|
||||
bool isFgPalette;
|
||||
bool isBgPalette;
|
||||
int freeMemory;
|
||||
int activeBuffer;
|
||||
int scrAddrLen;
|
||||
char scrAddr[NN_MAX_ADDRESS];
|
||||
ne_ScreenBuffer *vramBufs[NE_MAX_VRAMBUF];
|
||||
} ne_GPUState;
|
||||
|
||||
ne_GPUState *ne_newGPU(nn_GPU gpu) {
|
||||
ne_GPUState *state = malloc(sizeof(*state));
|
||||
state->screenBuf = NULL;
|
||||
state->currentFg = 0xFFFFFF;
|
||||
state->currentBg = 0x000000;
|
||||
state->isFgPalette = false;
|
||||
state->isBgPalette = false;
|
||||
state->activeBuffer = 0;
|
||||
state->freeMemory = gpu.totalVRAM;
|
||||
for(int i = 0; i < NE_MAX_VRAMBUF; i++) {
|
||||
state->vramBufs[i] = NULL;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
ne_ScreenBuffer *ne_gpu_currentBuffer(ne_GPUState *state) {
|
||||
if(state->activeBuffer == 0) return state->screenBuf;
|
||||
return state->vramBufs[state->activeBuffer - 1];
|
||||
}
|
||||
|
||||
nn_Exit ne_gpu_handler(nn_GPURequest *req) {
|
||||
nn_Computer *C = req->computer;
|
||||
ne_GPUState *state = req->instance;
|
||||
|
||||
int maxWidth = req->gpuConf->maxWidth;
|
||||
int maxHeight = req->gpuConf->maxHeight;
|
||||
int maxDepth = req->gpuConf->maxDepth;
|
||||
|
||||
ne_ScreenBuffer *activeBuf = ne_gpu_currentBuffer(state);
|
||||
|
||||
if(state->screenBuf != NULL) {
|
||||
ne_ScreenBuffer *buf = state->screenBuf;
|
||||
if(maxWidth > buf->maxWidth) maxWidth = buf->maxWidth;
|
||||
if(maxHeight > buf->maxHeight) maxHeight = buf->maxHeight;
|
||||
if(maxDepth > buf->maxDepth) maxDepth = buf->maxDepth;
|
||||
}
|
||||
|
||||
int x, y, dx, dy, w, h, fg, bg;
|
||||
ne_Pixel p;
|
||||
|
||||
switch(req->action) {
|
||||
case NN_GPU_DROP:
|
||||
for(int i = 0; i < NE_MAX_VRAMBUF; i++) {
|
||||
ne_ScreenBuffer *buf = state->vramBufs[i];
|
||||
if(buf != NULL) ne_dropScreenBuf(buf);
|
||||
}
|
||||
free(state);
|
||||
return NN_OK;
|
||||
case NN_GPU_BIND:
|
||||
state->screenBuf = nn_getComponentUserdata(C, req->text);
|
||||
memcpy(state->scrAddr, req->text, req->width);
|
||||
state->scrAddrLen = req->width;
|
||||
return NN_OK;
|
||||
case NN_GPU_UNBIND:
|
||||
state->screenBuf = NULL;
|
||||
return NN_OK;
|
||||
case NN_GPU_GETSCREEN:
|
||||
if(state->screenBuf == NULL) {
|
||||
req->text = NULL;
|
||||
return NN_OK;
|
||||
}
|
||||
memcpy(req->text, state->scrAddr, state->scrAddrLen);
|
||||
req->width = state->scrAddrLen;
|
||||
return NN_OK;
|
||||
case NN_GPU_GETRESOLUTION:
|
||||
if(state->screenBuf == NULL) {
|
||||
nn_setError(C, "no screen");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
req->width = state->screenBuf->width;
|
||||
req->height = state->screenBuf->height;
|
||||
return NN_OK;
|
||||
case NN_GPU_GET:
|
||||
if(activeBuf == NULL) {
|
||||
nn_setError(C, "no screen");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
p = ne_getPixel(activeBuf, req->x, req->y);
|
||||
fg = p.fg;
|
||||
bg = p.bg;
|
||||
if(p.isFgPalette) fg = activeBuf->virtualPalette[fg];
|
||||
if(p.isBgPalette) bg = activeBuf->virtualPalette[bg];
|
||||
|
||||
req->codepoint = p.codepoint;
|
||||
req->width = fg;
|
||||
req->height = bg;
|
||||
req->dest = p.isFgPalette ? p.fg : -1;
|
||||
req->src = p.isBgPalette ? p.bg : -1;
|
||||
return NN_OK;
|
||||
case NN_GPU_SET:
|
||||
case NN_GPU_SETVERTICAL:
|
||||
if(activeBuf == NULL) {
|
||||
nn_setError(C, "no screen");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
dx = 1;
|
||||
dy = 0;
|
||||
if(req->action == NN_GPU_SETVERTICAL) dx = 0, dy = 1;
|
||||
|
||||
x = req->x;
|
||||
y = req->y;
|
||||
for(int i = 0; i < req->width; i++) {
|
||||
if(!ne_inScreenBuf(activeBuf, x, y)) break;
|
||||
ne_Pixel p = {
|
||||
.fg = state->currentFg,
|
||||
.bg = state->currentBg,
|
||||
.isFgPalette = state->isFgPalette,
|
||||
.isBgPalette = state->isBgPalette,
|
||||
.codepoint = req->text[i],
|
||||
};
|
||||
ne_setPixel(activeBuf, x, y, p);
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
ne_remapScreen(activeBuf);
|
||||
return NN_OK;
|
||||
case NN_GPU_FILL:
|
||||
if(activeBuf == NULL) {
|
||||
nn_setError(C, "no screen");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
x = req->x;
|
||||
y = req->y;
|
||||
w = req->width;
|
||||
h = req->height;
|
||||
if(x < 1) x = 1;
|
||||
if(y < 1) y = 1;
|
||||
if(w >= activeBuf->width) w = activeBuf->width - 1;
|
||||
if(h >= activeBuf->height) h = activeBuf->height - 1;
|
||||
|
||||
p = (ne_Pixel) {
|
||||
.fg = state->currentFg,
|
||||
.bg = state->currentBg,
|
||||
.isFgPalette = state->isFgPalette,
|
||||
.isBgPalette = state->isBgPalette,
|
||||
.codepoint = req->codepoint,
|
||||
};
|
||||
for(int oy = 0; oy < h; oy++) {
|
||||
for(int ox = 0; ox < w; ox++) {
|
||||
ne_setPixel(activeBuf, x + ox, y + oy, p);
|
||||
}
|
||||
}
|
||||
return NN_OK;
|
||||
}
|
||||
return NN_OK;
|
||||
}
|
||||
|
||||
Color ne_processColor(unsigned int color) {
|
||||
color <<= 8;
|
||||
color |= 0xFF;
|
||||
return GetColor(color);
|
||||
}
|
||||
|
||||
int main() {
|
||||
nn_Context ctx;
|
||||
nn_initContext(&ctx);
|
||||
nn_initPalettes();
|
||||
|
||||
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
||||
InitWindow(800, 600, "NeoNucleus Test Emulator");
|
||||
|
||||
// create the universe
|
||||
nn_Universe *u = nn_createUniverse(&ctx);
|
||||
@ -409,7 +656,9 @@ int main() {
|
||||
for(size_t i = 1; i < 5; i++) {
|
||||
fstype[i] = nn_createFilesystem(u, &nn_defaultFilesystems[i-1], ne_fsState_handler, NULL);
|
||||
}
|
||||
nn_ComponentType *scrtype = nn_createScreen(u, NULL, ne_screen_handler);
|
||||
nn_ComponentType *scrtype = nn_createScreen(u, ne_screen_handler, NULL);
|
||||
nn_ComponentType *keytype = nn_createKeyboard(u);
|
||||
nn_ComponentType *gputype = nn_createGPU(u, &nn_defaultGPUs[3], ne_gpu_handler, NULL);
|
||||
|
||||
nn_Computer *c = nn_createComputer(u, NULL, "computer0", 8 * NN_MiB, 256, 256);
|
||||
|
||||
@ -422,10 +671,55 @@ int main() {
|
||||
ne_FsState *mainFS = ne_newFS("OpenOS", false);
|
||||
nn_addComponent(c, fstype[1], "mainFS", 2, mainFS);
|
||||
|
||||
ne_ScreenBuffer *scrbuf = ne_newScreenBuf(nn_defaultScreens[3], NULL);
|
||||
nn_addComponent(c, keytype, "mainKB", 4, NULL);
|
||||
ne_ScreenBuffer *scrbuf = ne_newScreenBuf(nn_defaultScreens[1], "mainKB");
|
||||
nn_addComponent(c, scrtype, "mainScreen", -1, scrbuf);
|
||||
|
||||
ne_GPUState *gpu = ne_newGPU(nn_defaultGPUs[3]);
|
||||
nn_addComponent(c, gputype, "mainGPU", 3, gpu);
|
||||
|
||||
SetExitKey(KEY_NULL);
|
||||
|
||||
Font font = LoadFont("unscii-16-full.ttf");
|
||||
double tickDelay = 0.05;
|
||||
double tickClock = 0;
|
||||
|
||||
while(true) {
|
||||
if(WindowShouldClose()) break;
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(BLACK);
|
||||
|
||||
int scrW = scrbuf->width;
|
||||
int scrH = scrbuf->height;
|
||||
|
||||
int pixelHeight = GetScreenHeight() / scrH;
|
||||
float spacing = (float)pixelHeight/10;
|
||||
int pixelWidth = MeasureTextEx(font, "A", pixelHeight, spacing).x;
|
||||
|
||||
int depth = scrbuf->depth;
|
||||
|
||||
int offX = (GetScreenWidth() - scrW * pixelWidth) / 2;
|
||||
int offY = (GetScreenHeight() - scrH * pixelHeight) / 2;
|
||||
|
||||
for(int y = 0; y < scrH; y++) {
|
||||
for(int x = 0; x < scrW; x++) {
|
||||
ne_Pixel p = ne_getPixel(scrbuf, x+1, y+1);
|
||||
|
||||
Color fgColor = ne_processColor(p.truefg);
|
||||
Color bgColor = ne_processColor(p.truebg);
|
||||
|
||||
DrawRectangle(x * pixelWidth + offX, y * pixelHeight + offY, pixelWidth, pixelHeight, bgColor);
|
||||
DrawTextCodepoint(font, p.codepoint, (Vector2) {x * pixelWidth + offX, y * pixelHeight + offY}, pixelHeight - 5, fgColor);
|
||||
}
|
||||
}
|
||||
EndDrawing();
|
||||
|
||||
tickClock -= GetFrameTime();
|
||||
|
||||
if(tickClock <= 0) {
|
||||
tickClock = tickDelay;
|
||||
|
||||
nn_Exit e = nn_tick(c);
|
||||
if(e != NN_OK) {
|
||||
nn_setErrorFromExit(c, e);
|
||||
@ -453,14 +747,20 @@ int main() {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:;
|
||||
nn_destroyComputer(c);
|
||||
nn_destroyComponentType(ctype);
|
||||
nn_destroyComponentType(etype);
|
||||
nn_destroyComponentType(scrtype);
|
||||
nn_destroyComponentType(keytype);
|
||||
nn_destroyComponentType(gputype);
|
||||
for(size_t i = 0; i < 5; i++) nn_destroyComponentType(fstype[i]);
|
||||
ne_dropScreenBuf(scrbuf);
|
||||
// rip the universe
|
||||
nn_destroyUniverse(u);
|
||||
UnloadFont(font);
|
||||
CloseWindow();
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -95,35 +95,33 @@ extern "C" {
|
||||
|
||||
typedef unsigned int nn_codepoint;
|
||||
|
||||
// validates that a NULL-terminated string is valid UTF-8
|
||||
bool nn_unicode_validate(const char *s);
|
||||
bool nn_unicode_validate(const char *s, size_t len);
|
||||
// validates only the *first* codepoint in the NULL-terminated string.
|
||||
// This returns the length in bytes of the codepoint, with 0 meaning
|
||||
// invalid.
|
||||
size_t nn_unicode_validateFirstChar(const char *s);
|
||||
size_t nn_unicode_validateFirstChar(const char *s, size_t len);
|
||||
|
||||
// returns the amount of unicode codepoints in the UTF-8 string.
|
||||
// Undefined behavior for invalid UTF-8, make sure to validate it if needed.
|
||||
size_t nn_unicode_len(const char *s);
|
||||
size_t nn_unicode_len(const char *s, size_t len);
|
||||
// returns the amount of unicode codepoints in the UTF-8 string.
|
||||
// If s is invalid UTF-8, all invalid bytes are considered a 1-byte codepoint.
|
||||
size_t nn_unicode_lenPermissive(const char *s);
|
||||
size_t nn_unicode_lenPermissive(const char *s, size_t len);
|
||||
|
||||
// Writes the codepoints of s into codepoints.
|
||||
// Undefined behavior for invalid UTF-8, make sure to validate it if needed.
|
||||
// The codepoints buffer must be big enough to store the string, use nn_unicode_len()
|
||||
// to get the required buffer length.
|
||||
void nn_unicode_codepoints(const char *s, nn_codepoint *codepoints);
|
||||
void nn_unicode_codepoints(const char *s, size_t len, nn_codepoint *codepoints);
|
||||
// Writes the codepoints of s into codepoints.
|
||||
// If s is invalid UTF-8, all invalid bytes are considered a 1-byte codepoint.
|
||||
// The codepoints buffer must be big enough to store the string, use nn_unicode_lenPermissive()
|
||||
// to get the required buffer length.
|
||||
void nn_unicode_codepointsPermissive(const char *s, nn_codepoint *codepoints);
|
||||
void nn_unicode_codepointsPermissive(const char *s, size_t len, nn_codepoint *codepoints);
|
||||
|
||||
// Returns the codepoint at a given byte offset in the string.
|
||||
// If it is out of bounds, the behavior is undefined.
|
||||
// If s is invalid UTF-8 at that offset, the behavior is undefined.
|
||||
nn_codepoint nn_unicode_codepointAt(const char *s, size_t byteOffset);
|
||||
// Returns the first codepoint from a UTF-8 string.
|
||||
// If s is invalid UTF-8, the behavior is undefined.
|
||||
nn_codepoint nn_unicode_firstCodepoint(const char *s);
|
||||
// Returns the size, in bytes, required by UTF-8 for a codepoint.
|
||||
size_t nn_unicode_codepointSize(nn_codepoint codepoint);
|
||||
// Writes the UTF-8 bytes for a given codepoint into buffer.
|
||||
@ -134,7 +132,18 @@ size_t nn_unicode_codepointToChar(char buffer[NN_MAXIMUM_UNICODE_BUFFER], nn_cod
|
||||
size_t nn_unicode_charWidth(nn_codepoint codepoint);
|
||||
// The width, on a screen, for an entire string.
|
||||
// The behavior is undefined for
|
||||
size_t nn_unicode_wlen(const char *s);
|
||||
size_t nn_unicode_wlen(const char *s, size_t len);
|
||||
size_t nn_unicode_wlenPermissive(const char *s, size_t len);
|
||||
|
||||
// Returns the amount of bytes needed to store the UTF-8 encoded text.
|
||||
// The behavior on invalid codepoints is undefined.
|
||||
size_t nn_unicode_countBytes(nn_codepoint *codepoints, size_t len);
|
||||
// Writes the UTF-8 encoded text.
|
||||
// DOES NOT WRITE A NULL TERMINATOR.
|
||||
// s must be big enough to store the string, use nn_unicode_bytelen()
|
||||
// to allocate the correct amount of space.
|
||||
// The behavior on invalid codepoints is undefined.
|
||||
void nn_unicode_writeBytes(char *s, nn_codepoint *codepoints, size_t len);
|
||||
|
||||
// Returns the uppercase version of the codepoint
|
||||
nn_codepoint nn_unicode_upper(nn_codepoint codepoint);
|
||||
@ -178,7 +187,7 @@ typedef struct nn_LockRequest {
|
||||
// This is used for synchronization. OpenComputers achieves synchronization
|
||||
// between the worker threads by sending them as requests to a central thread (indirect methods).
|
||||
// In NeoNucleus, the function pointer is invoked on the calling thead. This technically makes all methods direct,
|
||||
// however we consider methods to be indirect if they require synchronization of mutable state.
|
||||
// however methods which are meant to be slow may become indirect, as indirect methods consume the entire call budget.
|
||||
// Do note that locks are only used in "full" component implementations, such as the volatile storage devices.
|
||||
// The interfaces do not do any automatic synchronization via locks, all synchronization is assumed
|
||||
// to be handled in the implementer of the interface, because only you know how to best synchronize
|
||||
@ -306,6 +315,9 @@ void nn_destroyComputer(nn_Computer *computer);
|
||||
// get the userdata pointer
|
||||
void *nn_getComputerUserdata(nn_Computer *computer);
|
||||
const char *nn_getComputerAddress(nn_Computer *computer);
|
||||
nn_Universe *nn_getComputerUniverse(nn_Computer *computer);
|
||||
nn_Context *nn_getUniverseContext(nn_Universe *universe);
|
||||
nn_Context *nn_getComputerContext(nn_Computer *computer);
|
||||
|
||||
// address is copied.
|
||||
// It can be NULL if you wish to have no tmp address.
|
||||
@ -411,7 +423,9 @@ void nn_removeDeviceInfo(nn_Computer *computer, const char *address);
|
||||
const nn_DeviceInfo *nn_getDeviceInfo(nn_Computer *computer, size_t *len);
|
||||
|
||||
typedef enum nn_MethodFlags {
|
||||
// calling will consume the entire call budget
|
||||
NN_INDIRECT = 0,
|
||||
// calling will only consume 1 call from the call budget
|
||||
NN_DIRECT = (1<<0),
|
||||
// this indicates this method wraps a *field*
|
||||
// getter means calling it with no arguments will return the current value,
|
||||
@ -552,6 +566,8 @@ nn_Exit nn_pushnull(nn_Computer *computer);
|
||||
nn_Exit nn_pushbool(nn_Computer *computer, bool truthy);
|
||||
// pushes a number on the call stack
|
||||
nn_Exit nn_pushnumber(nn_Computer *computer, double num);
|
||||
// casts [num] to a double and pushes it on the call stack
|
||||
nn_Exit nn_pushinteger(nn_Computer *computer, intptr_t num);
|
||||
// pushes a NULL-terminated string on the call stack. The string is copied, so you can free it afterwards without worry.
|
||||
nn_Exit nn_pushstring(nn_Computer *computer, const char *str);
|
||||
// pushes a string on the call stack. The string is copied, so you can free it afterwards without worry. The copy will have a NULL terminator inserted
|
||||
@ -601,6 +617,9 @@ bool nn_isboolean(nn_Computer *computer, size_t idx);
|
||||
// Returns whether the value at [idx] is a number.
|
||||
// [idx] starts at 0.
|
||||
bool nn_isnumber(nn_Computer *computer, size_t idx);
|
||||
// Returns whether the value at [idx] is a number AND
|
||||
// the number can safely be cast to an intptr_t.
|
||||
bool nn_isinteger(nn_Computer *computer, size_t idx);
|
||||
// Returns whether the value at [idx] is a string.
|
||||
// [idx] starts at 0.
|
||||
bool nn_isstring(nn_Computer *computer, size_t idx);
|
||||
@ -614,12 +633,60 @@ bool nn_istable(nn_Computer *computer, size_t idx);
|
||||
// For out of bounds indexes, "none" is returned.
|
||||
const char *nn_typenameof(nn_Computer *computer, size_t idx);
|
||||
|
||||
// Argument helpers
|
||||
|
||||
// Returns true if the argument at that index is not null.
|
||||
bool nn_checknull(nn_Computer *computer, size_t idx, const char *errMsg);
|
||||
// Returns true if the argument at that index is not a boolean.
|
||||
bool nn_checkboolean(nn_Computer *computer, size_t idx, const char *errMsg);
|
||||
// Returns true if the argument at that index is not a number.
|
||||
bool nn_checknumber(nn_Computer *computer, size_t idx, const char *errMsg);
|
||||
// Returns true if the argument at that index is not an integer.
|
||||
bool nn_checkinteger(nn_Computer *computer, size_t idx, const char *errMsg);
|
||||
// Returns true if the argument at that index is not a string.
|
||||
bool nn_checkstring(nn_Computer *computer, size_t idx, const char *errMsg);
|
||||
// Returns true if the argument at that index is not userdata.
|
||||
bool nn_checkuserdata(nn_Computer *computer, size_t idx, const char *errMsg);
|
||||
// Returns true if the argument at that index is a table.
|
||||
bool nn_checktable(nn_Computer *computer, size_t idx, const char *errMsg);
|
||||
|
||||
// Checks if idx is equal to the stack size.
|
||||
// If it is, it will push a null.
|
||||
nn_Exit nn_defaultnull(nn_Computer *computer, size_t idx);
|
||||
// Checks if idx is equal to the stack size.
|
||||
// If it is, it will push a boolean [value].
|
||||
nn_Exit nn_defaultboolean(nn_Computer *computer, size_t idx, bool value);
|
||||
// Checks if idx is equal to the stack size.
|
||||
// If it is, it will push a number [num].
|
||||
nn_Exit nn_defaultnumber(nn_Computer *computer, size_t idx, double num);
|
||||
// Checks if idx is equal to the stack size.
|
||||
// If it is, it will push an integer [num].
|
||||
nn_Exit nn_defaultinteger(nn_Computer *computer, size_t idx, intptr_t num);
|
||||
// Checks if idx is equal to the stack size.
|
||||
// If it is, it will push a string [str].
|
||||
nn_Exit nn_defaultstring(nn_Computer *computer, size_t idx, const char *str);
|
||||
// Checks if idx is equal to the stack size.
|
||||
// If it is, it will push a string [str].
|
||||
nn_Exit nn_defaultlstring(nn_Computer *computer, size_t idx, const char *str, size_t len);
|
||||
// Checks if idx is equal to the stack size.
|
||||
// If it is, it will push the userdata [userdataIdx].
|
||||
nn_Exit nn_defaultuserdata(nn_Computer *computer, size_t idx, size_t userdataIdx);
|
||||
// Checks if idx is equal to the stack size.
|
||||
// If it is, it will push an empty table.
|
||||
nn_Exit nn_defaulttable(nn_Computer *computer, size_t idx);
|
||||
|
||||
// NOTE: behavior of the nn_to*() functions and nn_dumptable() when the values have the wrong types or at out of bounds indexes is undefined.
|
||||
|
||||
// Returns the boolean value at [idx].
|
||||
bool nn_toboolean(nn_Computer *computer, size_t idx);
|
||||
// Returns the number value at [idx].
|
||||
double nn_tonumber(nn_Computer *computer, size_t idx);
|
||||
// Returns the number value at [idx] cast to an intptr_t.
|
||||
// NOTE: for numbers where nn_isinteger() returns false,
|
||||
// the cast is undefined.
|
||||
// This includes values such as infinity and NaN, where
|
||||
// the behavior is platform, ABI and compiler-specific.
|
||||
intptr_t nn_tointeger(nn_Computer *computer, size_t idx);
|
||||
// Returns the string value at [idx].
|
||||
const char *nn_tostring(nn_Computer *computer, size_t idx);
|
||||
// Returns the string value and its length at [idx].
|
||||
@ -953,6 +1020,8 @@ typedef enum nn_ScreenFeatures {
|
||||
NN_SCRF_PRECISE = 1<<1,
|
||||
// Whether touch inverted is supported.
|
||||
NN_SCRF_TOUCHINVERTED = 1<<2,
|
||||
// it indicates that the palette can be edited.
|
||||
NN_SCRF_EDITABLECOLORS = 1<<3,
|
||||
} nn_ScreenFeatures;
|
||||
|
||||
// A struct for the reference screen configurations
|
||||
@ -963,7 +1032,6 @@ typedef struct nn_ScreenConfig {
|
||||
int maxWidth;
|
||||
int maxHeight;
|
||||
nn_ScreenFeatures features;
|
||||
int editableColors;
|
||||
int paletteColors;
|
||||
char maxDepth;
|
||||
} nn_ScreenConfig;
|
||||
@ -973,7 +1041,9 @@ extern nn_ScreenConfig nn_defaultScreens[4];
|
||||
|
||||
typedef nn_Exit nn_ScreenHandler(nn_ScreenRequest *req);
|
||||
|
||||
nn_ComponentType *nn_createScreen(nn_Universe *universe, void *userdata, nn_ScreenHandler *handler);
|
||||
nn_ComponentType *nn_createScreen(nn_Universe *universe, nn_ScreenHandler *handler, void *userdata);
|
||||
// a useless component which does nothing
|
||||
nn_ComponentType *nn_createKeyboard(nn_Universe *universe);
|
||||
|
||||
// Remember:
|
||||
// - Colors are in 0xRRGGBB format.
|
||||
@ -987,9 +1057,11 @@ typedef enum nn_GPUAction {
|
||||
// Conventional GPU functions
|
||||
|
||||
// requests to bind to a screen connected to the computer.
|
||||
// The address, as well as its length, are stored in text, with the length in width.
|
||||
// The address is stored in text, with the length in width.
|
||||
// The interface does check that the computer does have the screen, but do look out
|
||||
// for time-of-check/time-of-use issues which may occur in multi-threaded environments.
|
||||
// If x is set to 1, the reset flag is enabled. This means the GPU should "reset" the state
|
||||
// of the screen.
|
||||
NN_GPU_BIND,
|
||||
// requests to unbind the GPU from its screen.
|
||||
// If there is no screen, it just does nothing.
|
||||
@ -1007,6 +1079,7 @@ typedef enum nn_GPUAction {
|
||||
// Sets the current background.
|
||||
// x should store either the color in 0xRRGGBB format or the palette index.
|
||||
// y should be 1 if x is a palette index and 0 if it is a color.
|
||||
// The values x and y should be updated to reflect the old state.
|
||||
NN_GPU_SETBACKGROUND,
|
||||
// Gets the current foreground.
|
||||
// x should store either the color in 0xRRGGBB format or the palette index.
|
||||
@ -1015,6 +1088,7 @@ typedef enum nn_GPUAction {
|
||||
// Sets the current foreground.
|
||||
// x should store either the color in 0xRRGGBB format or the palette index.
|
||||
// y should be 1 if x is a palette index and 0 if it is a color.
|
||||
// The values x and y should be updated to reflect the old state.
|
||||
NN_GPU_SETFOREGROUND,
|
||||
// Gets the palette color.
|
||||
// x is the index.
|
||||
@ -1054,6 +1128,12 @@ typedef enum nn_GPUAction {
|
||||
// The new viewport dimensions are stored in width and height.
|
||||
NN_GPU_SETVIEWPORT,
|
||||
// Gets a character.
|
||||
// The position requested is given in x and y.
|
||||
// The codepoint of the character should be set in [codepoint].
|
||||
// The foreground and background color should be set in [width] and [height].
|
||||
// The palette indexes of the foreground and background should be set
|
||||
// in [dest] and [src] respectively. If the pixel color was not from
|
||||
// the palette, the imaginary -1 palette index can be used.
|
||||
NN_GPU_GET,
|
||||
// Sets a horizontal line of text at a given x, y.
|
||||
// The position is stored in x, y, and is the position of the first character.
|
||||
@ -1120,6 +1200,7 @@ typedef struct nn_GPURequest {
|
||||
void *userdata;
|
||||
void *instance;
|
||||
nn_Computer *computer;
|
||||
struct nn_GPU *gpuConf;
|
||||
nn_GPUAction action;
|
||||
int x;
|
||||
int y;
|
||||
@ -1161,9 +1242,13 @@ typedef struct nn_GPU {
|
||||
double energyPerClear;
|
||||
} nn_GPU;
|
||||
|
||||
typedef nn_Exit nn_GPUHandler(nn_GPURequest *req);
|
||||
|
||||
// 1 GPU tier for every screen.
|
||||
extern nn_GPU nn_defaultGPUs[4];
|
||||
|
||||
nn_ComponentType *nn_createGPU(nn_Universe *universe, const nn_GPU *gpu, nn_GPUHandler *handler, void *userdata);
|
||||
|
||||
// Colors and palettes.
|
||||
// Do note that the
|
||||
|
||||
@ -1182,6 +1267,9 @@ extern int nn_mcpalette4[16];
|
||||
// The OC 8-bit palette.
|
||||
extern int nn_ocpalette8[256];
|
||||
|
||||
// initializes the contents of the palettes.
|
||||
void nn_initPalettes();
|
||||
|
||||
// Expensive.
|
||||
// Maps a color to the closest match in a palette.
|
||||
int nn_mapColor(int color, int *palette, size_t len);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user