diff --git a/src/luaarch.c b/src/luaarch.c index faf2b81..0649a02 100644 --- a/src/luaarch.c +++ b/src/luaarch.c @@ -281,6 +281,10 @@ static int luaArch_component_list(lua_State *L) { luaArch *arch = luaArch_from(L); lua_createtable(L, 64, 0); size_t len = nn_countComponents(arch->computer); + if(len == 0) { + lua_createtable(L, 0, 0); + return 1; + } const char *comps[len]; nn_getComponents(arch->computer, comps); for(size_t i = 0; i < len; i++) { @@ -377,6 +381,10 @@ static int luaArch_component_methods(lua_State *L) { return 2; } size_t methodLen = nn_countComponentMethods(c); + if(methodLen == 0) { + lua_createtable(L, 0, 0); + return 1; + } const char *methods[methodLen]; nn_getComponentMethods(c, methods, &methodLen); lua_createtable(L, 0, methodLen); @@ -402,6 +410,10 @@ static int luaArch_component_fields(lua_State *L) { return 2; } size_t methodLen = nn_countComponentMethods(c); + if(methodLen == 0) { + lua_createtable(L, 0, 0); + return 1; + } const char *methods[methodLen]; nn_getComponentMethods(c, methods, &methodLen); lua_createtable(L, 0, methodLen); diff --git a/src/main.c b/src/main.c index 94ba957..c60ea7b 100644 --- a/src/main.c +++ b/src/main.c @@ -412,6 +412,19 @@ int main(int argc, char **argv) { double nextSecond = 0; double wattage = 0; + nn_Component *screen = ncl_createScreen(u, NULL, &nn_defaultScreens[3]); + //nn_Component *gpu = ncl_createGPU(u, NULL, &nn_defaultGPUs[3]); + + { + // draw test + const char *s = "hello there"; + for(size_t i = 0; s[i]; i++) { + unsigned char c = s[i]; + ncl_ScreenState *scrstate = nn_getComponentState(screen); + ncl_setScreenPixel(scrstate, i+1, 1, c, 0xFFFFFF, 0x000000, false, false); + } + } + restart:; nn_Computer *c = nn_createComputer(u, NULL, "computer0", ramTotal, 256, 256); @@ -426,6 +439,7 @@ restart:; nn_setArchitecture(c, &arch); nn_addSupportedArchitecture(c, &arch); + nn_mountComponent(c, screen, -1); nn_mountComponent(c, ocelotCard, -1); nn_mountComponent(c, eepromCard, 0); nn_mountComponent(c, managedfs, 1); @@ -436,6 +450,31 @@ restart:; BeginDrawing(); ClearBackground(BLACK); + // drawing the screen + { + int offX = 0; + int offY = 0; + int cheight = 20; + int cwidth = MeasureText("A", cheight); + + ncl_ScreenState *scrbuf = nn_getComponentState(screen); + ncl_lockScreen(scrbuf); + size_t scrw, scrh; + ncl_getScreenResolution(scrbuf, &scrw, &scrh); + for(int y = 1; y <= scrh; y++) { + for(int x = 1; x <= scrw; x++) { + ncl_Pixel p = ncl_getScreenPixel(scrbuf, x, y); + Vector2 pos = { + offX + (x - 1) * cwidth, + offY + (y - 1) * cheight, + }; + DrawRectangle(pos.x, pos.y, cwidth, cheight, ne_processColor(p.bgColor)); + DrawTextCodepoint(font, p.codepoint, pos, cheight, ne_processColor(p.fgColor)); + } + } + ncl_unlockScreen(scrbuf); + } + int statY = 10; if(sand.buf != NULL) { DrawText(TextFormat("mem used: %.2f%%", (double)sand.used / sand.cap * 100), 10, statY, 20, YELLOW); @@ -536,6 +575,8 @@ cleanup:; nn_destroyComputer(c); nn_dropComponent(ocelotCard); nn_dropComponent(eepromCard); + nn_dropComponent(managedfs); + nn_dropComponent(screen); // rip the universe nn_destroyUniverse(u); UnloadFont(font); diff --git a/src/ncomplib.c b/src/ncomplib.c index 934c587..2216de5 100644 --- a/src/ncomplib.c +++ b/src/ncomplib.c @@ -274,7 +274,21 @@ bool ncl_remove(ncl_VFS vfs, const char *path) { return vfs.handler(&req); } -bool ncl_removeRecursive(ncl_VFS vfs, const char *path); +bool ncl_removeRecursive(ncl_VFS vfs, const char *path) { + ncl_Stat s; + if(!ncl_stat(vfs, path, &s)) return false; + if(s.isDirectory) { + void *dir = ncl_opendir(vfs, path); + char name[NN_MAX_PATH]; + while(ncl_readdir(vfs, dir, name)) { + char subpath[NN_MAX_PATH]; + snprintf(subpath, sizeof(subpath), "%s%c%s", path, vfs.pathsep, name); + ncl_removeRecursive(vfs, subpath); + } + ncl_closedir(vfs, dir); + } + return ncl_remove(vfs, path); +} bool ncl_mkdir(ncl_VFS vfs, const char *path) { ncl_VFSRequest req; @@ -298,6 +312,7 @@ typedef struct ncl_ScreenPixel { typedef struct ncl_ScreenState { nn_Context *ctx; + nn_Lock *lock; nn_ScreenConfig conf; int width; int height; @@ -308,6 +323,8 @@ typedef struct ncl_ScreenState { int *resolvedPalette; ncl_ScreenPixel *pixels; ncl_ScreenFlags flags; + size_t keyboardCount; + char *keyboards[NCL_MAX_KEYBOARD]; } ncl_ScreenState; typedef struct nn_VRAMBuf { @@ -378,7 +395,6 @@ typedef struct ncl_DriveState { size_t usage; size_t lastSector; char *path; - FILE *file; char label[NN_MAX_LABEL]; size_t labellen; } ncl_DriveState; @@ -637,6 +653,23 @@ static nn_Exit ncl_fsHandler(nn_FSRequest *req) { nn_unlock(ctx, state->lock); return NN_OK; } + if(req->action == NN_FS_STAT) { + nn_lock(ctx, state->lock); + char path[NN_MAX_PATH]; + ncl_fixPath(state, req->stat.path, path); + ncl_Stat s; + if(!ncl_stat(state->vfs, path, &s)) { + nn_unlock(ctx, state->lock); + nn_setError(C, "no such file or directory"); + return NN_EBADCALL; + } + req->stat.isDirectory = s.isDirectory; + req->stat.size = s.size; + req->stat.lastModified = s.lastModified; + nn_unlock(ctx, state->lock); + return NN_OK; + } + // TODO: mkdir, rename if(C) nn_setError(C, "not implemented yet"); return NN_EBADCALL; @@ -677,12 +710,16 @@ nn_Component *ncl_createFilesystem(nn_Universe *universe, const char *address, c nn_free(ctx, state, sizeof(*state)); return NULL; } + // TODO: handle OOM case + nn_setComponentTypeID(c, NCL_FS); return c; } nn_Component *ncl_createDrive(nn_Universe *universe, const char *address, const char *path, const nn_Drive *drive, bool isReadonly); nn_Component *ncl_createEEPROM(nn_Universe *universe, const char *address, const char *codepath, const char *datapath, bool isReadonly); +ncl_VFS ncl_setVFS(nn_Component *component, ncl_VFS vfs); + static ncl_ScreenPixel ncl_getRealScreenPixel(const ncl_ScreenState *state, int x, int y) { if(x < 1 || y < 1 || x >= state->width || y >= state->height) { return (ncl_ScreenPixel) { @@ -740,9 +777,99 @@ static void ncl_recomputeScreen(const ncl_ScreenState *state) { } } -nn_Component *ncl_createScreen(nn_Universe *universe, const char *address, const nn_ScreenConfig *config); +static nn_Exit ncl_screenHandler(nn_ScreenRequest *req) { + nn_Context *ctx = req->ctx; + nn_Computer *C = req->computer; + ncl_ScreenState *state = req->state; + const nn_ScreenConfig *conf = req->screen; + + if(req->action == NN_SCREEN_DROP) { + for(size_t i = 0; i < state->keyboardCount; i++) { + nn_strfree(ctx, state->keyboards[i]); + } + nn_destroyLock(ctx, state->lock); + nn_free(ctx, state->pixels, sizeof(ncl_ScreenPixel) * state->conf.maxWidth * state->conf.maxHeight); + nn_free(ctx, state->palette, sizeof(int) * state->conf.paletteColors); + nn_free(ctx, state->resolvedPalette, sizeof(int) * state->conf.paletteColors); + nn_free(ctx, state, sizeof(*state)); + return NN_OK; + } + + if(C) nn_setError(C, "ncl-screen: not implemented yet"); + return NN_EBADCALL; +} + +nn_Component *ncl_createScreen(nn_Universe *universe, const char *address, const nn_ScreenConfig *config) { + nn_Context *ctx = nn_getUniverseContext(universe); + ncl_ScreenState *screen = NULL; + ncl_ScreenPixel *pixels = NULL; + int *palette = NULL; + int *resolvedPalette = NULL; + nn_Component *c = NULL; + nn_Lock *lock = NULL; + + screen = nn_alloc(ctx, sizeof(ncl_ScreenState)); + if(screen == NULL) goto fail; + + lock = nn_createLock(ctx); + if(lock == NULL) goto fail; + + pixels = nn_alloc(ctx, sizeof(ncl_ScreenPixel) * config->maxWidth * config->maxHeight); + if(pixels == NULL) goto fail; + + palette = nn_alloc(ctx, sizeof(int) * config->paletteColors); + if(palette == NULL) goto fail; + memcpy(palette, config->defaultPalette, sizeof(int) * config->paletteColors); + + resolvedPalette = nn_alloc(ctx, sizeof(int) * config->paletteColors); + if(resolvedPalette == NULL) goto fail; + + screen->conf = *config; + screen->ctx = ctx; + screen->lock = lock; + screen->width = config->maxWidth; + screen->height = config->maxHeight; + screen->palette = palette; + screen->resolvedPalette = resolvedPalette; + screen->pixels = pixels; + screen->flags = 0; + screen->depth = config->maxDepth; + screen->viewportWidth = screen->width; + screen->viewportHeight = screen->height; + screen->keyboardCount = 0; + + ncl_resetScreen(screen); + + c = nn_createScreen(universe, address, config, screen, ncl_screenHandler); + if(c == NULL) goto fail; + + if(nn_setComponentTypeID(c, NCL_SCREEN)) goto fail; + + return c; + +fail:; + if(c != NULL) { + nn_dropComponent(c); + return NULL; + } + if(lock != NULL) nn_destroyLock(ctx, lock); + nn_free(ctx, screen, sizeof(*screen)); + nn_free(ctx, palette, sizeof(int) * config->paletteColors); + nn_free(ctx, resolvedPalette, sizeof(int) * config->paletteColors); + nn_free(ctx, pixels, sizeof(ncl_ScreenPixel) * config->maxWidth * config->maxHeight); + return NULL; +} + nn_Component *ncl_createGPU(nn_Universe *universe, const char *address, const nn_GPU *gpu); +void ncl_lockScreen(ncl_ScreenState *state) { + nn_lock(state->ctx, state->lock); +} + +void ncl_unlockScreen(ncl_ScreenState *state) { + nn_unlock(state->ctx, state->lock); +} + void ncl_resetScreen(ncl_ScreenState *state) { state->width = state->conf.maxWidth; state->height = state->conf.maxHeight; @@ -784,6 +911,18 @@ ncl_Pixel ncl_getScreenPixel(const ncl_ScreenState *state, int x, int y) { }; } +void ncl_setScreenPixel(ncl_ScreenState *state, int x, int y, nn_codepoint codepoint, int fg, int bg, bool isFgPalette, bool isBgPalette) { + ncl_ScreenPixel p = { + .codepoint = codepoint, + .storedFg = fg, + .storedBg = bg, + .realFg = isFgPalette ? -1 : fg, + .realBg = isBgPalette ? -1 : bg, + }; + ncl_setRealScreenPixel(state, x, y, p); + ncl_recomputeScreen(state); +} + ncl_ScreenFlags ncl_getScreenFlags(const ncl_ScreenState *state) { return state->flags; } @@ -792,6 +931,19 @@ void ncl_setScreenFlags(ncl_ScreenState *state, ncl_ScreenFlags flags) { state->flags = flags; } +char ncl_getScreenDepth(ncl_ScreenState *state) { + return state->depth; +} + +void ncl_setScreenDepth(ncl_ScreenState *state, char depth) { + state->depth = depth; +} + +nn_Exit ncl_mountKeyboard(ncl_ScreenState *state, const char *keyboardAddress); +void ncl_unmountKeyboard(ncl_ScreenState *state, const char *keyboardAddress); +bool ncl_hasKeyboard(ncl_ScreenState *state, const char *keyboardAddress); +const char *ncl_getKeyboard(ncl_ScreenState *state, size_t idx); + // general stuff void ncl_statComponent(nn_Component *component, ncl_ComponentStat *stat) { @@ -843,6 +995,19 @@ void ncl_statComponent(nn_Component *component, ncl_ComponentStat *stat) { nn_unlock(ee->ctx, ee->lock); return; } + if(strcmp(ty, NCL_SCREEN) == 0) { + ncl_ScreenState *screen = state; + nn_lock(screen->ctx, screen->lock); + stat->screen.conf = &screen->conf; + stat->screen.depth = screen->depth; + stat->screen.flags = screen->flags; + stat->screen.keyboardCount = screen->keyboardCount; + stat->screen.viewportWidth = screen->viewportWidth; + stat->screen.viewportHeight = screen->viewportHeight; + stat->screen.state = screen; + nn_unlock(screen->ctx, screen->lock); + return; + } } // For EEPROMs, filesystems, drives diff --git a/src/ncomplib.h b/src/ncomplib.h index f54d21b..9b2181e 100644 --- a/src/ncomplib.h +++ b/src/ncomplib.h @@ -10,6 +10,7 @@ #define NCL_SCREEN "ncl-screen" #define NCL_MAX_VRAMBUF 128 +#define NCL_MAX_KEYBOARD 64 // very low-level actions // some environment have VFSes so @@ -32,7 +33,7 @@ typedef struct ncl_Stat { size_t diskSize; // The UNIX timestamp of the last modified date // of the entry. - size_t lastModified; + intptr_t lastModified; } ncl_Stat; typedef enum ncl_VFSAction { @@ -235,6 +236,8 @@ typedef struct ncl_ComponentStat { ncl_ScreenFlags flags; int viewportWidth; int viewportHeight; + char depth; + size_t keyboardCount; } screen; }; } ncl_ComponentStat; @@ -244,11 +247,20 @@ void ncl_statComponent(nn_Component *component, ncl_ComponentStat *stat); // Returns whether it was successful or not. bool ncl_makeReadonly(nn_Component *component); +void ncl_lockScreen(ncl_ScreenState *state); +void ncl_unlockScreen(ncl_ScreenState *state); void ncl_resetScreen(ncl_ScreenState *state); void ncl_getScreenResolution(const ncl_ScreenState *state, size_t *width, size_t *height); void ncl_getScreenViewport(const ncl_ScreenState *state, size_t *width, size_t *height); ncl_Pixel ncl_getScreenPixel(const ncl_ScreenState *state, int x, int y); +void ncl_setScreenPixel(ncl_ScreenState *state, int x, int y, nn_codepoint codepoint, int fg, int bg, bool isFgPalette, bool isBgPalette); ncl_ScreenFlags ncl_getScreenFlags(const ncl_ScreenState *state); void ncl_setScreenFlags(ncl_ScreenState *state, ncl_ScreenFlags flags); +char ncl_getScreenDepth(ncl_ScreenState *state); +void ncl_setScreenDepth(ncl_ScreenState *state, char depth); +nn_Exit ncl_mountKeyboard(ncl_ScreenState *state, const char *keyboardAddress); +void ncl_unmountKeyboard(ncl_ScreenState *state, const char *keyboardAddress); +bool ncl_hasKeyboard(ncl_ScreenState *state, const char *keyboardAddress); +const char *ncl_getKeyboard(ncl_ScreenState *state, size_t idx); #endif diff --git a/src/neonucleus.c b/src/neonucleus.c index e171fc0..c6af2ff 100644 --- a/src/neonucleus.c +++ b/src/neonucleus.c @@ -1469,6 +1469,7 @@ void nn_dropComponentN(nn_Component *c, size_t n) { nn_strfree(ctx, c->type); nn_strfree(ctx, c->internalID); nn_hashDeinit(&c->methodsMap); + nn_free(ctx, c, sizeof(*c)); } void nn_setComponentHandler(nn_Component *c, nn_ComponentHandler *handler) { @@ -3315,6 +3316,7 @@ static nn_Exit nn_veepromHandler(nn_EEPROMRequest *request) { if(request->action == NN_EEPROM_DROP) { nn_free(ctx, state->code, eeprom->size); nn_free(ctx, state->data, eeprom->dataSize); + nn_free(ctx, state, sizeof(*state)); return NN_OK; } if(request->action == NN_EEPROM_GET) { @@ -3384,6 +3386,12 @@ nn_Component *nn_createVEEPROM(nn_Universe *universe, const char *address, const state->datalen = veeprom->datalen; nn_memcpy(state->label, veeprom->label, veeprom->labellen); state->labellen = veeprom->labellen; + if(veeprom->arch == NULL) { + state->archlen = 0; + } else { + state->archlen = nn_strlen(veeprom->arch); + } + nn_memcpy(state->arch, veeprom->arch, state->archlen); nn_Component *c = nn_createEEPROM(universe, address, eeprom, state, nn_veepromHandler); if(c == NULL) goto fail; @@ -3767,3 +3775,53 @@ nn_Component *nn_createFilesystem(nn_Universe *universe, const char *address, co nn_setComponentHandler(c, nn_fsHandler); return c; } + +nn_Component *nn_createVFilesystem(nn_Universe *universe, const char *address, const nn_VFilesystem *vfs, const nn_Filesystem *fs); + +typedef struct nn_ScreenState { + nn_Context *ctx; + nn_ScreenConfig scrconf; + nn_ScreenHandler *handler; +} nn_ScreenState; + +static nn_Exit nn_screenHandler(nn_ComponentRequest *req) { + if(req->action == NN_COMP_CHECKMETHOD) return NN_OK; + if(req->action == NN_COMP_SIGNAL) return NN_OK; + nn_Context *ctx = req->ctx; + nn_ScreenState *state = req->classState; + nn_Computer *C = req->computer; + nn_ScreenRequest sreq; + sreq.ctx = ctx; + sreq.state = req->state; + sreq.computer = C; + sreq.screen = &state->scrconf; + + if(req->action == NN_COMP_DROP) { + sreq.action = NN_SCREEN_DROP; + state->handler(&sreq); + nn_free(ctx, state, sizeof(*state)); + return NN_OK; + } + + nn_setError(C, "screen: not yet implemented"); + return NN_EBADCALL; +} + +nn_Component *nn_createScreen(nn_Universe *universe, const char *address, const nn_ScreenConfig *scrconf, void *state, nn_ScreenHandler *handler) { + nn_Component *c = nn_createComponent(universe, address, "screen"); + if(c == NULL) return NULL; + // TODO: methods + nn_Context *ctx = &universe->ctx; + nn_ScreenState *scrstate = nn_alloc(ctx, sizeof(*scrstate)); + if(scrstate == NULL) { + nn_dropComponent(c); + return NULL; + } + scrstate->ctx = ctx; + scrstate->scrconf = *scrconf; + scrstate->handler = handler; + nn_setComponentState(c, state); + nn_setComponentClassState(c, scrstate); + nn_setComponentHandler(c, nn_screenHandler); + return c; +} diff --git a/src/neonucleus.h b/src/neonucleus.h index 56b8044..db9d965 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -1003,7 +1003,7 @@ typedef struct nn_FSRequest { bool isDirectory; // in seconds. Result will be multiplied by 1000. // This is because OpenOS code is garbage. - size_t lastModified; + intptr_t lastModified; // size. 0 for directories. size_t size; } stat; @@ -1175,6 +1175,22 @@ typedef struct nn_ScreenConfig { // OC has 3 tiers, NN adds a 4th one as well. extern const nn_ScreenConfig nn_defaultScreens[4]; +typedef enum nn_ScreenAction { + NN_SCREEN_DROP, +} nn_ScreenAction; + +typedef struct nn_ScreenRequest { + nn_Context *ctx; + nn_Computer *computer; + void *state; + const nn_ScreenConfig *screen; + nn_ScreenAction action; +} nn_ScreenRequest; + +typedef nn_Exit (nn_ScreenHandler)(nn_ScreenRequest *req); + +nn_Component *nn_createScreen(nn_Universe *universe, const char *address, const nn_ScreenConfig *scrconf, void *state, nn_ScreenHandler *handler); + // GPU class typedef struct nn_GPU {