diff --git a/src/main.c b/src/main.c index bb23c92..ae328c2 100644 --- a/src/main.c +++ b/src/main.c @@ -46,10 +46,22 @@ static nn_Exit sandbox_handler(nn_ComponentRequest *req) { return NN_OK; } -Color ne_processColor(unsigned int color) { +static unsigned char ne_processColorPart(unsigned char channel, double brightness) { + double n = (double)channel / 255; + n *= brightness; + if(n < 0) n = 0; + if(n > 1) n = 1; + return n * 255; +} + +Color ne_processColor(unsigned int color, double brightness) { color <<= 8; color |= 0xFF; - return GetColor(color); + Color c = GetColor(color); + c.r = ne_processColorPart(c.r, brightness); + c.g = ne_processColorPart(c.g, brightness); + c.b = ne_processColorPart(c.b, brightness); + return c; } int keycode_to_oc(int keycode) { @@ -447,15 +459,6 @@ int main(int argc, char **argv) { ncl_ScreenState *scrstate = nn_getComponentState(screen); ncl_mountKeyboard(scrstate, "mainKB"); - { - // 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); - } - } nn_Computer *c = nn_createComputer(u, NULL, "computer0", ramTotal, 256, 256); nn_Component *wrappedC = nn_wrapComputer(c); @@ -512,6 +515,7 @@ int main(int argc, char **argv) { int offX = (GetScreenWidth() - cwidth * scrw) / 2; int offY = (GetScreenHeight() - cheight * scrh) / 2; + double scrbright = ncl_getScreenBrightness(scrbuf); for(int y = 1; y <= scrh; y++) { for(int x = 1; x <= scrw; x++) { ncl_Pixel p = ncl_getScreenPixel(scrbuf, x, y); @@ -520,9 +524,9 @@ int main(int argc, char **argv) { offY + (y - 1) * cheight, }; ncl_needGlyph(gc, p.codepoint); - DrawRectangle(pos.x, pos.y, cwidth, cheight, ne_processColor(p.bgColor)); + DrawRectangle(pos.x, pos.y, cwidth, cheight, ne_processColor(p.bgColor, scrbright)); if(p.codepoint != 0) { - ncl_drawGlyph(gc, p.codepoint, pos, cheight, ne_processColor(p.fgColor)); + ncl_drawGlyph(gc, p.codepoint, pos, cheight, ne_processColor(p.fgColor, scrbright)); } } } @@ -530,7 +534,7 @@ int main(int argc, char **argv) { ncl_unlockScreen(scrbuf); ncl_flushGlyphs(gc); } -skipDrawScreen: +skipDrawScreen:; int statY = 10; if(sand.buf != NULL) { diff --git a/src/ncomplib.c b/src/ncomplib.c index 7c6e530..741fbd1 100644 --- a/src/ncomplib.c +++ b/src/ncomplib.c @@ -2232,6 +2232,18 @@ static nn_Exit ncl_screenHandler(nn_ScreenRequest *req) { nn_unlock(ctx, st->lock); return NN_OK; } + if(req->action == NN_SCREEN_GETBRIGHT) { + nn_lock(ctx, st->lock); + req->brightness = st->brightness; + nn_unlock(ctx, st->lock); + return NN_OK; + } + if(req->action == NN_SCREEN_SETBRIGHT) { + nn_lock(ctx, st->lock); + st->brightness = req->brightness; + nn_unlock(ctx, st->lock); + return NN_OK; + } if(C) nn_setError(C, "ncl-screen: bad action"); return NN_EBADCALL; diff --git a/src/neonucleus.c b/src/neonucleus.c index ee59ab4..5374b88 100644 --- a/src/neonucleus.c +++ b/src/neonucleus.c @@ -2695,6 +2695,8 @@ const nn_ScreenConfig nn_defaultScreens[4] = { .editableColors = 0, .features = NN_SCRF_NONE, .energyPerPixel = 0.05, + .minBrightness = 0.5, + .maxBrightness = 1, }, NN_INIT(nn_ScreenConfig) { .maxWidth = 80, @@ -2705,6 +2707,8 @@ const nn_ScreenConfig nn_defaultScreens[4] = { .editableColors = 0, .features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED, .energyPerPixel = 0.05, + .minBrightness = 0.25, + .maxBrightness = 1.2, }, NN_INIT(nn_ScreenConfig) { .maxWidth = 160, @@ -2715,6 +2719,8 @@ const nn_ScreenConfig nn_defaultScreens[4] = { .editableColors = 16, .features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED | NN_SCRF_PRECISE | NN_SCRF_EDITABLECOLORS, .energyPerPixel = 0.05, + .minBrightness = 0.1, + .maxBrightness = 1.5, }, NN_INIT(nn_ScreenConfig) { .maxWidth = 240, @@ -2725,6 +2731,8 @@ const nn_ScreenConfig nn_defaultScreens[4] = { .editableColors = 256, .features = NN_SCRF_NONE | NN_SCRF_EDITABLECOLORS, .energyPerPixel = 0.05, + .minBrightness = 0.1, + .maxBrightness = 2, }, }; @@ -4760,6 +4768,11 @@ typedef enum nn_ScreenNum { NN_SCRNUM_ISPRECISE, NN_SCRNUM_SETTOUCHINVERTED, NN_SCRNUM_ISTOUCHINVERTED, + NN_SCRNUM_MINBRIGHTNESS, + NN_SCRNUM_MAXBRIGHTNESS, + NN_SCRNUM_SETBRIGHTNESS, + NN_SCRNUM_GETBRIGHTNESS, + NN_SCRNUM_COUNT, } nn_ScreenNum; @@ -4891,6 +4904,31 @@ static nn_Exit nn_screenHandler(nn_ComponentRequest *req) { req->returnCount = 1; return nn_pushbool(C, s.flag); } + if(m == NN_SCRNUM_MINBRIGHTNESS) { + req->returnCount = 1; + return nn_pushinteger(C, cls->scrconf.minBrightness * 100); + } + if(m == NN_SCRNUM_MAXBRIGHTNESS) { + req->returnCount = 1; + return nn_pushinteger(C, cls->scrconf.maxBrightness * 100); + } + if(m == NN_SCRNUM_GETBRIGHTNESS) { + s.action = NN_SCREEN_GETBRIGHT; + e = cls->handler(&s); + if(e) return e; + req->returnCount = 1; + return nn_pushnumber(C, s.brightness * 100); + } + if(m == NN_SCRNUM_SETBRIGHTNESS) { + if(nn_checknumber(C, 0, "bad argument #1 (number expected)")) return NN_EBADCALL; + s.action = NN_SCREEN_SETBRIGHT; + s.brightness = nn_tonumber(C, 0) / 100; + if(s.brightness < cls->scrconf.minBrightness) s.brightness = cls->scrconf.minBrightness; + if(s.brightness > cls->scrconf.maxBrightness) s.brightness = cls->scrconf.maxBrightness; + e = cls->handler(&s); + if(e) return e; + return nn_pushnumber(C, s.brightness * 100); + } nn_setError(C, "screen: not implemented"); return NN_EBADCALL; @@ -4943,6 +4981,10 @@ nn_Component *nn_createScreen( "isTouchModeInverted", "function(): boolean - Returns whether inverse touch mode is enabled", NN_DIRECT}, + [NN_SCRNUM_MINBRIGHTNESS] = {"minBrightness", "function(): number - Returns the minimum brightness", NN_DIRECT}, + [NN_SCRNUM_MAXBRIGHTNESS] = {"maxBrightness", "function(): number - Returns the maximum brightness", NN_DIRECT}, + [NN_SCRNUM_GETBRIGHTNESS] = {"getBrightness", "function(): number - Returns the current brightness", NN_DIRECT}, + [NN_SCRNUM_SETBRIGHTNESS] = {"setBrightness", "function(brightness: number): number - Sets the brightness, returns the new one", NN_DIRECT}, }; nn_Exit e = nn_setComponentMethodsArray( diff --git a/src/neonucleus.h b/src/neonucleus.h index 26a410e..f970c86 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -420,6 +420,20 @@ void nn_forceCrashComputer(nn_Computer *computer, const char *s); // returns whether an architecture state is present bool nn_isComputerOn(nn_Computer *computer); +typedef enum nn_ComputerEvent { + // when powered on + NN_COMPUTER_POWERON, + // when powered off + NN_COMPUTER_POWEROFF, + // when force-crashed + NN_COMPUTER_FORCECRASH, + // when crashed + NN_COMPUTER_CRASH, +} nn_ComputerEvent; + +typedef void nn_ComputerListener(nn_Computer *computer, nn_ComputerEvent event); +void nn_setComputerListener(nn_Computer *computer, nn_ComputerListener *listener); + typedef struct nn_Beep { double frequency; double duration; @@ -1356,6 +1370,12 @@ typedef struct nn_ScreenConfig { // Scaled to mathc luminance of each pixel. // This is meant to be per Minecraft tick, so 20 times per second. double energyPerPixel; + // minimum brightness. Default brightness is always 100% + // The value here is meant to be scaled such that 1 means 100% brightness + double minBrightness; + // maximum brightness. Note that brightness rendering is emulator-specific + // The value here is meant to be scaled such that 1 means 100% brightness + double maxBrightness; } nn_ScreenConfig; // OC has 3 tiers, NN adds a 4th one as well. @@ -1526,6 +1546,10 @@ typedef enum nn_ScreenAction { NN_SCREEN_ISPRECISE, NN_SCREEN_SETTOUCHINVERTED, NN_SCREEN_ISTOUCHINVERTED, + // sets the brightness (from 0 to 1) + NN_SCREEN_SETBRIGHT, + // get the brightness (from 0 to 1) + NN_SCREEN_GETBRIGHT, } nn_ScreenAction; typedef struct nn_ScreenRequest { @@ -1550,6 +1574,7 @@ typedef struct nn_ScreenRequest { // setPrecise / isPrecise / // setTouchModeInverted / isTouchModeInverted bool flag; + double brightness; }; } nn_ScreenRequest;