mirror of
https://github.com/NeoFlock/neonucleus.git
synced 2025-09-24 09:03:32 +02:00
962 lines
26 KiB
C
962 lines
26 KiB
C
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "neonucleus.h"
|
|
#include "testLuaArch.h"
|
|
#include <raylib.h>
|
|
|
|
#ifdef NN_BAREMETAL
|
|
|
|
#ifdef NN_POSIX
|
|
|
|
#include <time.h>
|
|
|
|
static double nni_realTime() {
|
|
struct timespec time;
|
|
if(clock_gettime(CLOCK_MONOTONIC, &time) < 0) return 0; // oh no
|
|
return time.tv_sec + ((double)time.tv_nsec) / 1e9;
|
|
}
|
|
|
|
#else
|
|
|
|
#include <windows.h>
|
|
|
|
static double nni_realTime() {
|
|
LARGE_INTEGER frequency = {0};
|
|
if(!QueryPerformanceFrequency(&frequency)) return 0;
|
|
|
|
LARGE_INTEGER now = {0};
|
|
if(!QueryPerformanceCounter(&now)) return 0;
|
|
|
|
return (double)now.QuadPart / frequency.QuadPart;
|
|
}
|
|
|
|
#endif
|
|
|
|
static double nni_realTimeClock(void *_) {
|
|
return nni_realTime();
|
|
}
|
|
|
|
nn_Clock nn_libcRealTime() {
|
|
return (nn_Clock) {
|
|
.userdata = NULL,
|
|
.proc = nni_realTimeClock,
|
|
};
|
|
}
|
|
|
|
static void *nn_libcAllocProc(void *_, void *ptr, nn_size_t oldSize, nn_size_t newSize, void *__) {
|
|
if(newSize == 0) {
|
|
//printf("Freed %lu bytes from %p\n", oldSize, ptr);
|
|
free(ptr);
|
|
return NULL;
|
|
} else {
|
|
void *rptr = realloc(ptr, newSize);
|
|
//printf("Allocated %lu bytes for %p\n", newSize - oldSize, rptr);
|
|
return rptr;
|
|
}
|
|
}
|
|
|
|
nn_Alloc nn_libcAllocator() {
|
|
return (nn_Alloc) {
|
|
.userdata = NULL,
|
|
.proc = nn_libcAllocProc,
|
|
};
|
|
}
|
|
|
|
static nn_size_t nni_rand(void *userdata) {
|
|
return rand();
|
|
}
|
|
|
|
nn_Rng nn_libcRng() {
|
|
srand(time(NULL));
|
|
return (nn_Rng) {
|
|
.userdata = NULL,
|
|
.maximum = RAND_MAX,
|
|
.proc = nni_rand,
|
|
};
|
|
}
|
|
|
|
nn_Context nn_libcContext() {
|
|
return (nn_Context) {
|
|
.allocator = nn_libcAllocator(),
|
|
.clock = nn_libcRealTime(),
|
|
.lockManager = nn_noMutex(),
|
|
.rng = nn_libcRng(),
|
|
};
|
|
}
|
|
|
|
#endif
|
|
|
|
Color ne_processColor(unsigned int color) {
|
|
color <<= 8;
|
|
color |= 0xFF;
|
|
return GetColor(color);
|
|
}
|
|
|
|
nn_eepromControl ne_eeprom_getControl(nn_component *component, void *_) {
|
|
return (nn_eepromControl) {
|
|
.readHeatPerByte = 0.0015,
|
|
.writeHeatPerByte = 0.03,
|
|
.readEnergyCostPerByte = 0.001,
|
|
.writeEnergyCostPerByte = 0.05,
|
|
.bytesReadPerTick = 32768,
|
|
.bytesWrittenPerTick = 4096,
|
|
};
|
|
}
|
|
|
|
size_t ne_eeprom_getSize(nn_component *component, void *_) {
|
|
return 4096;
|
|
}
|
|
|
|
size_t ne_eeprom_getDataSize(nn_component *component, void *_) {
|
|
return 1024;
|
|
}
|
|
|
|
void ne_eeprom_getLabel(nn_component *component, void *_, char *buf, size_t *buflen) {
|
|
*buflen = 0;
|
|
}
|
|
|
|
size_t ne_eeprom_setLabel(nn_component *component, void *_, const char *buf, size_t buflen) {
|
|
return 0;
|
|
}
|
|
|
|
const char *ne_location(nn_address address) {
|
|
static char buffer[256];
|
|
snprintf(buffer, 256, "data/%s", address);
|
|
return buffer;
|
|
}
|
|
|
|
size_t ne_eeprom_get(nn_component *component, void *_, char *buf) {
|
|
FILE *f = fopen(ne_location(nn_getComponentAddress(component)), "rb");
|
|
if (f == NULL) {
|
|
printf("couldn't read eeprom");
|
|
exit(1);
|
|
}
|
|
fseek(f, 0, SEEK_END);
|
|
size_t len = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
fread(buf, sizeof(char), len, f);
|
|
fclose(f);
|
|
return len;
|
|
}
|
|
|
|
void ne_eeprom_set(nn_component *component, void *_, const char *buf, size_t len) {
|
|
FILE *f = fopen(ne_location(nn_getComponentAddress(component)), "wb");
|
|
if (f == NULL) {
|
|
printf("couldn't write eeprom");
|
|
exit(1);
|
|
}
|
|
fwrite(buf, sizeof(char), len, f);
|
|
fclose(f);
|
|
}
|
|
|
|
int ne_eeprom_getData(nn_component *component, void *_, char *buf) {
|
|
return 0;
|
|
}
|
|
|
|
void ne_eeprom_setData(nn_component *component, void *_, const char *buf, size_t len) {}
|
|
|
|
nn_bool_t ne_eeprom_isReadonly(nn_component *component, void *userdata) {
|
|
return false;
|
|
}
|
|
|
|
void ne_eeprom_makeReadonly(nn_component *component, void *userdata) {}
|
|
|
|
#define NE_FS_MAX 128
|
|
|
|
typedef struct ne_fs {
|
|
FILE *files[NE_FS_MAX];
|
|
size_t fileLen;
|
|
} ne_fs;
|
|
|
|
nn_filesystemControl ne_fs_getControl(nn_component *component, ne_fs *_) {
|
|
return (nn_filesystemControl) {
|
|
.readBytesPerTick = 65536,
|
|
.writeBytesPerTick = 32768,
|
|
.removeFilesPerTick = 16,
|
|
.createFilesPerTick = 16,
|
|
|
|
.readHeatPerByte = 0.0000015,
|
|
.writeHeatPerByte = 0.000015,
|
|
.removeHeat = 0.035,
|
|
.createHeat = 0.045,
|
|
|
|
.readEnergyPerByte = 0.0015,
|
|
.writeEnergyPerByte = 0.0035,
|
|
.removeEnergy = 0.135,
|
|
.createEnergy = 0.325,
|
|
};
|
|
}
|
|
|
|
size_t ne_fs_spaceUsed(nn_component *component, void *_) {
|
|
return 0; // ultra accurate
|
|
}
|
|
|
|
size_t ne_fs_spaceTotal(nn_component *component, void *_) {
|
|
return 1*1024*1024;
|
|
}
|
|
|
|
const char *ne_fs_diskPath(nn_component *component, const char *path) {
|
|
static char buf[256];
|
|
const char *root = ne_location(nn_getComponentAddress(component));
|
|
if(path[0] == '/') {
|
|
snprintf(buf, 256, "%s%s", root, path);
|
|
} else {
|
|
snprintf(buf, 256, "%s/%s", root, path);
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
size_t ne_fs_open(nn_component *component, ne_fs *fs, const char *path, const char *mode) {
|
|
if(fs->fileLen == NE_FS_MAX) {
|
|
nn_setCError(nn_getComputerOfComponent(component), "too many files");
|
|
return 0;
|
|
}
|
|
|
|
const char *trueMode = "rb";
|
|
if(strcmp(mode, "w") == 0) {
|
|
trueMode = "wb";
|
|
}
|
|
if(strcmp(mode, "a") == 0) {
|
|
trueMode = "ab";
|
|
}
|
|
|
|
const char *p = ne_fs_diskPath(component, path);
|
|
if(p[0] == '/') p++;
|
|
FILE *f = fopen(p, trueMode);
|
|
|
|
if(f == NULL) {
|
|
nn_setCError(nn_getComputerOfComponent(component), strerror(errno));
|
|
return 0;
|
|
}
|
|
|
|
for(size_t i = 0; i < fs->fileLen; i++) {
|
|
if(fs->files[i] == NULL) {
|
|
fs->files[i] = f;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
size_t i = fs->fileLen++;
|
|
fs->files[i] = f;
|
|
return i;
|
|
}
|
|
|
|
bool ne_fs_close(nn_component *component, ne_fs *fs, int fd) {
|
|
// we pray
|
|
fclose(fs->files[fd]);
|
|
fs->files[fd] = NULL;
|
|
return true;
|
|
}
|
|
|
|
bool ne_fs_write(nn_component *component, ne_fs *fs, int fd, const char *buf, size_t len) {
|
|
FILE *f = fs->files[fd];
|
|
return fwrite(buf, sizeof(char), len, f) > 0;
|
|
}
|
|
|
|
size_t ne_fs_read(nn_component *component, ne_fs *fs, int fd, char *buf, size_t required) {
|
|
FILE *f = fs->files[fd];
|
|
if(feof(f)) return 0;
|
|
return fread(buf, sizeof(char), required, f);
|
|
}
|
|
|
|
size_t ne_fs_seek(nn_component *component, ne_fs *fs, int fd, const char *whence, int off, int *moved) {
|
|
FILE *f = fs->files[fd];
|
|
*moved = 0;
|
|
int w = SEEK_SET;
|
|
if(strcmp(whence, "cur") == 0) {
|
|
w = SEEK_CUR;
|
|
}
|
|
if(strcmp(whence, "end") == 0) {
|
|
w = SEEK_END;
|
|
}
|
|
fseek(f, w, off);
|
|
return ftell(f);
|
|
}
|
|
|
|
char **ne_fs_list(nn_Alloc *alloc, nn_component *component, ne_fs *fs, const char *path, size_t *len) {
|
|
const char *p = ne_fs_diskPath(component, path);
|
|
if(p[0] == '/') p++;
|
|
|
|
FilePathList files = LoadDirectoryFiles(p);
|
|
*len = files.count;
|
|
|
|
char **buf = nn_alloc(alloc, sizeof(char *) * files.count);
|
|
for(size_t i = 0; i < files.count; i++) {
|
|
buf[i] = nn_strdup(alloc, GetFileName(files.paths[i]));
|
|
}
|
|
|
|
UnloadDirectoryFiles(files);
|
|
|
|
return buf;
|
|
}
|
|
|
|
size_t ne_fs_size(nn_component *component, ne_fs *fs, const char *path) {
|
|
const char *p = ne_fs_diskPath(component, path);
|
|
if(p[0] == '/') p++;
|
|
|
|
if(DirectoryExists(p)) return 0;
|
|
|
|
return GetFileLength(p);
|
|
}
|
|
|
|
size_t ne_fs_lastModified(nn_component *component, ne_fs *fs, const char *path) {
|
|
const char *p = ne_fs_diskPath(component, path);
|
|
if(p[0] == '/') p++;
|
|
|
|
return GetFileModTime(p);
|
|
}
|
|
|
|
bool ne_fs_isDirectory(nn_component *component, ne_fs *fs, const char *path) {
|
|
const char *p = ne_fs_diskPath(component, path);
|
|
if(p[0] == '/') p++;
|
|
|
|
return DirectoryExists(p);
|
|
}
|
|
|
|
bool ne_fs_makeDirectory(nn_component *component, ne_fs *fs, const char *path) {
|
|
const char *p = ne_fs_diskPath(component, path);
|
|
if(p[0] == '/') p++;
|
|
|
|
return MakeDirectory(p) == 0;
|
|
}
|
|
|
|
bool ne_fs_exists(nn_component *component, ne_fs *fs, const char *path) {
|
|
const char *p = ne_fs_diskPath(component, path);
|
|
if(p[0] == '/') p++;
|
|
|
|
return FileExists(p) || DirectoryExists(p);
|
|
}
|
|
|
|
typedef struct ne_drive {
|
|
FILE *file;
|
|
} ne_drive;
|
|
|
|
void ne_drive_close(nn_component *component, ne_drive *drive) {
|
|
fclose(drive->file);
|
|
}
|
|
nn_driveControl ne_drive_getControl(nn_component *component, ne_drive *_) {
|
|
return (nn_driveControl){};
|
|
}
|
|
size_t ne_drive_getPlatterCount(nn_component *component, ne_drive *_) {
|
|
return 1;
|
|
}
|
|
size_t ne_drive_getSectorSize(nn_component *component, ne_drive *_) {
|
|
return 512;
|
|
}
|
|
size_t ne_drive_getCapacity(nn_component *component, ne_drive *drive) {
|
|
fseek(drive->file, 0, SEEK_END);
|
|
return ftell(drive->file);
|
|
}
|
|
void ne_drive_readSector(nn_component *component, ne_drive *drive, int shifted_sector, char *buf) {
|
|
int sector = shifted_sector - 1;
|
|
size_t sectorSize = ne_drive_getSectorSize(component, drive);
|
|
|
|
size_t offset = sector * sectorSize;
|
|
fseek(drive->file, offset, SEEK_SET);
|
|
fread(buf, sizeof(char), sectorSize, drive->file);
|
|
}
|
|
void ne_drive_writeSector(nn_component *component, ne_drive *drive, int shifted_sector, const char *buf) {
|
|
int sector = shifted_sector - 1;
|
|
size_t sectorSize = ne_drive_getSectorSize(component, drive);
|
|
|
|
size_t offset = sector * sectorSize;
|
|
fseek(drive->file, offset, SEEK_SET);
|
|
fwrite(buf, sizeof(char), sectorSize, drive->file);
|
|
|
|
// this is probably not needed but i believe someone isn't running the deinit
|
|
fflush(drive->file);
|
|
}
|
|
|
|
|
|
int keycode_to_oc(int keycode) {
|
|
switch (keycode) {
|
|
case KEY_NULL:
|
|
return 0;
|
|
case KEY_APOSTROPHE:
|
|
return 0x28;
|
|
case KEY_COMMA:
|
|
return 0x33;
|
|
case KEY_MINUS:
|
|
return 0x0C;
|
|
case KEY_PERIOD:
|
|
return 0x34;
|
|
case KEY_SLASH:
|
|
return 0x35;
|
|
case KEY_ZERO:
|
|
return 0x0B;
|
|
case KEY_ONE:
|
|
return 0x02;
|
|
case KEY_TWO:
|
|
return 0x03;
|
|
case KEY_THREE:
|
|
return 0x04;
|
|
case KEY_FOUR:
|
|
return 0x05;
|
|
case KEY_FIVE:
|
|
return 0x06;
|
|
case KEY_SIX:
|
|
return 0x07;
|
|
case KEY_SEVEN:
|
|
return 0x08;
|
|
case KEY_EIGHT:
|
|
return 0x09;
|
|
case KEY_NINE:
|
|
return 0x0A;
|
|
case KEY_SEMICOLON:
|
|
return 0x27;
|
|
case KEY_EQUAL:
|
|
return 0x0D;
|
|
case KEY_A:
|
|
return 0x1E;
|
|
case KEY_B:
|
|
return 0x30;
|
|
case KEY_C:
|
|
return 0x2E;
|
|
case KEY_D:
|
|
return 0x20;
|
|
case KEY_E:
|
|
return 0x12;
|
|
case KEY_F:
|
|
return 0x21;
|
|
case KEY_G:
|
|
return 0x22;
|
|
case KEY_H:
|
|
return 0x23;
|
|
case KEY_I:
|
|
return 0x17;
|
|
case KEY_J:
|
|
return 0x24;
|
|
case KEY_K:
|
|
return 0x25;
|
|
case KEY_L:
|
|
return 0x26;
|
|
case KEY_M:
|
|
return 0x32;
|
|
case KEY_N:
|
|
return 0x31;
|
|
case KEY_O:
|
|
return 0x18;
|
|
case KEY_P:
|
|
return 0x19;
|
|
case KEY_Q:
|
|
return 0x10;
|
|
case KEY_R:
|
|
return 0x13;
|
|
case KEY_S:
|
|
return 0x1F;
|
|
case KEY_T:
|
|
return 0x14;
|
|
case KEY_U:
|
|
return 0x16;
|
|
case KEY_V:
|
|
return 0x2F;
|
|
case KEY_W:
|
|
return 0x11;
|
|
case KEY_X:
|
|
return 0x2D;
|
|
case KEY_Y:
|
|
return 0x15;
|
|
case KEY_Z:
|
|
return 0x2C;
|
|
case KEY_LEFT_BRACKET:
|
|
return 0x1A;
|
|
case KEY_BACKSLASH:
|
|
return 0x2B;
|
|
case KEY_RIGHT_BRACKET:
|
|
return 0x1B;
|
|
case KEY_GRAVE:
|
|
return 0x29;
|
|
case KEY_SPACE:
|
|
return 0x39;
|
|
case KEY_ESCAPE:
|
|
return 0;
|
|
case KEY_ENTER:
|
|
return 0x1C;
|
|
case KEY_TAB:
|
|
return 0x0F;
|
|
case KEY_BACKSPACE:
|
|
return 0x0E;
|
|
case KEY_INSERT:
|
|
return 0xD2;
|
|
case KEY_DELETE:
|
|
return 0xD3;
|
|
case KEY_RIGHT:
|
|
return 0xCD;
|
|
case KEY_LEFT:
|
|
return 0xCB;
|
|
case KEY_DOWN:
|
|
return 0xD0;
|
|
case KEY_UP:
|
|
return 0xC8;
|
|
case KEY_PAGE_UP:
|
|
return 0xC9;
|
|
case KEY_PAGE_DOWN:
|
|
return 0xD1;
|
|
case KEY_HOME:
|
|
return 0xC7;
|
|
case KEY_END:
|
|
return 0xCF;
|
|
case KEY_CAPS_LOCK:
|
|
return 0x3A;
|
|
case KEY_SCROLL_LOCK:
|
|
return 0x46;
|
|
case KEY_NUM_LOCK:
|
|
return 0x45;
|
|
case KEY_PRINT_SCREEN:
|
|
return 0;
|
|
case KEY_PAUSE:
|
|
return 0xC5;
|
|
case KEY_F1:
|
|
return 0x3B;
|
|
case KEY_F2:
|
|
return 0x3C;
|
|
case KEY_F3:
|
|
return 0x3D;
|
|
case KEY_F4:
|
|
return 0x3E;
|
|
case KEY_F5:
|
|
return 0x3F;
|
|
case KEY_F6:
|
|
return 0x40;
|
|
case KEY_F7:
|
|
return 0x41;
|
|
case KEY_F8:
|
|
return 0x42;
|
|
case KEY_F9:
|
|
return 0x43;
|
|
case KEY_F10:
|
|
return 0x44;
|
|
case KEY_F11:
|
|
return 0x57;
|
|
case KEY_F12:
|
|
return 0x58;
|
|
case KEY_LEFT_SHIFT:
|
|
return 0x2A;
|
|
case KEY_LEFT_CONTROL:
|
|
return 0x1D;
|
|
case KEY_LEFT_ALT:
|
|
return 0x38;
|
|
case KEY_LEFT_SUPER:
|
|
return 0;
|
|
case KEY_RIGHT_SHIFT:
|
|
return 0x36;
|
|
case KEY_RIGHT_CONTROL:
|
|
return 0x9D;
|
|
case KEY_RIGHT_ALT:
|
|
return 0xB8;
|
|
case KEY_RIGHT_SUPER:
|
|
return 0;
|
|
case KEY_KB_MENU:
|
|
return 0;
|
|
case KEY_KP_0:
|
|
return 0x52;
|
|
case KEY_KP_1:
|
|
return 0x4F;
|
|
case KEY_KP_2:
|
|
return 0x50;
|
|
case KEY_KP_3:
|
|
return 0x51;
|
|
case KEY_KP_4:
|
|
return 0x4B;
|
|
case KEY_KP_5:
|
|
return 0x4C;
|
|
case KEY_KP_6:
|
|
return 0x4D;
|
|
case KEY_KP_7:
|
|
return 0x47;
|
|
case KEY_KP_8:
|
|
return 0x48;
|
|
case KEY_KP_9:
|
|
return 0x49;
|
|
case KEY_KP_DECIMAL:
|
|
return 0x54;
|
|
case KEY_KP_DIVIDE:
|
|
return 0xB5;
|
|
case KEY_KP_MULTIPLY:
|
|
return 0x37;
|
|
case KEY_KP_SUBTRACT:
|
|
return 0x4A;
|
|
case KEY_KP_ADD:
|
|
return 0x4E;
|
|
case KEY_KP_ENTER:
|
|
return 0x9C;
|
|
case KEY_KP_EQUAL:
|
|
return 0x8D;
|
|
case KEY_BACK:
|
|
return 0;
|
|
case KEY_MENU:
|
|
return 0;
|
|
case KEY_VOLUME_DOWN:
|
|
return 0;
|
|
case KEY_VOLUME_UP:
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
typedef struct ne_premappedPixel {
|
|
int codepoint;
|
|
int mappedDepth;
|
|
int mappedFgFor;
|
|
int mappedFgRes;
|
|
int mappedBgFor;
|
|
int mappedBgRes;
|
|
} ne_premappedPixel;
|
|
|
|
ne_premappedPixel ne_getPremap(ne_premappedPixel *pixels, nn_screen *screen, int x, int y) {
|
|
int maxW, maxH;
|
|
nn_maxResolution(screen, &maxW, &maxH);
|
|
int depth = nn_getDepth(screen);
|
|
|
|
int i = y * maxW + x;
|
|
ne_premappedPixel premapped = pixels[i];
|
|
|
|
nn_scrchr_t pixel = nn_getPixel(screen, x, y);
|
|
int fg = pixel.fg;
|
|
int bg = pixel.bg;
|
|
|
|
if(premapped.mappedDepth != depth) {
|
|
premapped.mappedDepth = depth;
|
|
premapped.mappedFgFor = -1;
|
|
premapped.mappedBgFor = -1;
|
|
}
|
|
|
|
bool miss = false;
|
|
if(premapped.mappedFgFor != fg) {
|
|
premapped.mappedFgFor = fg;
|
|
premapped.mappedFgRes = nn_mapDepth(fg, depth);
|
|
miss = true;
|
|
}
|
|
if(premapped.mappedBgFor != bg) {
|
|
premapped.mappedBgFor = bg;
|
|
premapped.mappedBgRes = nn_mapDepth(bg, depth);
|
|
miss = true;
|
|
}
|
|
premapped.codepoint = pixel.codepoint;
|
|
|
|
pixels[i] = premapped;
|
|
return premapped;
|
|
}
|
|
|
|
ne_premappedPixel *ne_allocPremap(int width, int height) {
|
|
int len = width * height;
|
|
ne_premappedPixel *pixels = malloc(sizeof(ne_premappedPixel) * len);
|
|
for(int i = 0; i < len; i++) pixels[i] = (ne_premappedPixel) {
|
|
.mappedDepth = -1,
|
|
.mappedFgFor = -1,
|
|
.mappedBgFor = -1,
|
|
};
|
|
return pixels;
|
|
}
|
|
|
|
typedef struct ne_pressedKey {
|
|
int charcode;
|
|
int keycode;
|
|
bool repeat;
|
|
} ne_pressedKey;
|
|
|
|
int main() {
|
|
printf("Setting up universe\n");
|
|
nn_Context ctx = nn_libcContext();
|
|
nn_Alloc alloc = ctx.allocator;
|
|
nn_universe *universe = nn_newUniverse(ctx);
|
|
if(universe == NULL) {
|
|
printf("Failed to create universe\n");
|
|
return 1;
|
|
}
|
|
nn_loadCoreComponentTables(universe);
|
|
|
|
nn_architecture *arch = testLuaArch_getArchitecture("src/sandbox.lua");
|
|
assert(arch != NULL && "Loading architecture failed");
|
|
|
|
// 1MB of RAM, 16 components max
|
|
nn_computer *computer = nn_newComputer(universe, "testMachine", arch, NULL, 1*1024*1024, 16);
|
|
nn_setEnergyInfo(computer, 5000, 5000);
|
|
nn_setCallBudget(computer, 18000);
|
|
nn_addSupportedArchitecture(computer, arch);
|
|
|
|
nn_eeprom genericEEPROM = {
|
|
.userdata = NULL,
|
|
.refc = 1,
|
|
.deinit = NULL,
|
|
.control = ne_eeprom_getControl,
|
|
.getSize = ne_eeprom_getSize,
|
|
.getDataSize = ne_eeprom_getDataSize,
|
|
.getLabel = ne_eeprom_getLabel,
|
|
.setLabel = ne_eeprom_setLabel,
|
|
.get = ne_eeprom_get,
|
|
.set = ne_eeprom_set,
|
|
.getData = ne_eeprom_getData,
|
|
.setData = ne_eeprom_setData,
|
|
.isReadonly = ne_eeprom_isReadonly,
|
|
.makeReadonly = ne_eeprom_makeReadonly,
|
|
};
|
|
|
|
nn_addEeprom(computer, "luaBios.lua", 0, &genericEEPROM);
|
|
|
|
ne_fs fs = {
|
|
.files = {NULL},
|
|
.fileLen = 0,
|
|
};
|
|
|
|
nn_filesystem genericFS = {
|
|
.refc = 0,
|
|
.userdata = &fs,
|
|
.deinit = NULL,
|
|
.control = (void *)ne_fs_getControl,
|
|
.getLabel = ne_eeprom_getLabel,
|
|
.setLabel = ne_eeprom_setLabel,
|
|
.spaceUsed = ne_fs_spaceUsed,
|
|
.spaceTotal = ne_fs_spaceTotal,
|
|
.isReadOnly = ne_eeprom_isReadonly,
|
|
.size = (void *)ne_fs_size,
|
|
.remove = NULL,
|
|
.lastModified = (void *)ne_fs_lastModified,
|
|
.rename = NULL,
|
|
.exists = (void *)ne_fs_exists,
|
|
.isDirectory = (void *)ne_fs_isDirectory,
|
|
.makeDirectory = (void *)ne_fs_makeDirectory,
|
|
.list = (void *)ne_fs_list,
|
|
.open = (void *)ne_fs_open,
|
|
.close = (void *)ne_fs_close,
|
|
.write = (void *)ne_fs_write,
|
|
.read = (void *)ne_fs_read,
|
|
.seek = (void *)ne_fs_seek,
|
|
};
|
|
nn_addFileSystem(computer, "OpenOS", 1, &genericFS);
|
|
|
|
ne_drive drive = {
|
|
.file = fopen("data/drive.img", "r+")
|
|
};
|
|
assert(drive.file != NULL);
|
|
|
|
nn_drive genericDrive = {
|
|
.refc = 0,
|
|
.userdata = &drive,
|
|
.deinit = (void *)ne_drive_close,
|
|
.control = (void *)ne_drive_getControl,
|
|
.getLabel = ne_eeprom_getLabel,
|
|
.setLabel = ne_eeprom_setLabel,
|
|
.getPlatterCount = (void *)ne_drive_getPlatterCount,
|
|
.getSectorSize = (void *)ne_drive_getSectorSize,
|
|
.getCapacity = (void *)ne_drive_getCapacity,
|
|
.readSector = (void *)ne_drive_readSector,
|
|
.writeSector = (void *)ne_drive_writeSector,
|
|
};
|
|
|
|
nn_addDrive(computer, "drive.img", 4, &genericDrive);
|
|
|
|
int maxWidth = 80, maxHeight = 32;
|
|
|
|
nn_screen *s = nn_newScreen(&ctx, maxWidth, maxHeight, 24, 16, 256);
|
|
nn_setDepth(s, 4); // looks cool
|
|
nn_addKeyboard(s, "shitty keyboard");
|
|
nn_mountKeyboard(computer, "shitty keyboard", 2);
|
|
nn_addScreen(computer, "Main Screen", 2, s);
|
|
|
|
ne_premappedPixel *premap = ne_allocPremap(maxWidth, maxHeight);
|
|
|
|
nn_gpuControl gpuCtrl = {
|
|
.totalVRAM = 16*1024,
|
|
.screenCopyPerTick = 8,
|
|
.screenFillPerTick = 16,
|
|
.screenSetsPerTick = 32,
|
|
.screenColorChangesPerTick = 64,
|
|
|
|
.heatPerPixelChange = 0.0005,
|
|
.heatPerPixelReset = 0.0001,
|
|
.heatPerVRAMChange = 0.000015,
|
|
|
|
.energyPerPixelChange = 0.05,
|
|
.energyPerPixelReset = 0.01,
|
|
.energyPerVRAMChange = 0.0015,
|
|
};
|
|
|
|
nn_addGPU(computer, "RTX 6090", 3, &gpuCtrl);
|
|
|
|
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
|
InitWindow(800, 600, "emulator");
|
|
|
|
Font unscii = LoadFont("unscii-16-full.ttf");
|
|
|
|
static ne_pressedKey release_check_list[256];
|
|
memset(release_check_list, 0, sizeof(ne_pressedKey)*256);
|
|
uint8_t release_check_ptr;
|
|
|
|
SetExitKey(KEY_NULL);
|
|
|
|
double idleTime = 0;
|
|
int tps = 20; // mc TPS
|
|
double interval = 1.0/tps;
|
|
|
|
while(true) {
|
|
if(WindowShouldClose()) break;
|
|
nn_setEnergyInfo(computer, 5000, 5000);
|
|
|
|
double dt = GetFrameTime();
|
|
|
|
double heat = nn_getTemperature(computer);
|
|
double roomHeat = nn_getRoomTemperature(computer);
|
|
|
|
double tx = 0.1;
|
|
|
|
// remove some heat per second
|
|
nn_removeHeat(computer, dt * (rand() % 3) * tx * (heat - roomHeat));
|
|
if(nn_isOverheating(computer)) {
|
|
goto render;
|
|
}
|
|
|
|
while (true) { // TODO: find out if we can check if the keycode and unicode are for the same key event or not
|
|
int keycode = GetKeyPressed();
|
|
int unicode = GetCharPressed();
|
|
|
|
if (keycode == 0 && unicode == 0) {
|
|
break;
|
|
}
|
|
|
|
if (keycode != 0) {
|
|
release_check_list[release_check_ptr].keycode = keycode;
|
|
release_check_list[release_check_ptr].charcode = unicode;
|
|
release_check_list[release_check_ptr].repeat = false;
|
|
release_check_ptr++;
|
|
}
|
|
|
|
nn_value values[5];
|
|
|
|
values[0] = nn_values_cstring("key_down");
|
|
values[1] = nn_values_cstring("shitty keyboard");
|
|
values[2] = nn_values_integer(unicode);
|
|
values[3] = nn_values_integer(keycode_to_oc(keycode));
|
|
values[4] = nn_values_cstring("USER");
|
|
|
|
const char* error = nn_pushSignal(computer, values, 5);
|
|
|
|
if (error != NULL) {
|
|
// well fuck
|
|
printf("error happened when eventing the keyboarding: %s\n", error);;;;;;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 256; i++) {
|
|
ne_pressedKey *key = release_check_list + i;
|
|
if (key->keycode != 0) {
|
|
key->repeat = IsKeyPressedRepeat(key->keycode);
|
|
if (IsKeyReleased(key->keycode)) {
|
|
// omg
|
|
nn_value values[5];
|
|
values[0] = nn_values_cstring("key_up");
|
|
values[1] = nn_values_cstring("shitty keyboard");
|
|
values[2] = nn_values_integer(key->charcode);
|
|
values[3] = nn_values_integer(keycode_to_oc(key->keycode));
|
|
values[4] = nn_values_cstring("USER");
|
|
|
|
const char* error = nn_pushSignal(computer, values, 5);
|
|
|
|
if (error != NULL) {
|
|
// well fuck
|
|
printf("error happened when eventing the keyboarding: %s\n", error);;;;;;
|
|
}
|
|
key->keycode = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
idleTime += dt;
|
|
|
|
if(idleTime >= interval) {
|
|
idleTime -= interval;
|
|
|
|
for (int i = 0; i < 256; i++) {
|
|
ne_pressedKey *key = release_check_list + i;
|
|
if (key->keycode != 0) {
|
|
if (key->repeat) {
|
|
// omg
|
|
nn_value values[5];
|
|
values[0] = nn_values_cstring("key_down");
|
|
values[1] = nn_values_cstring("shitty keyboard");
|
|
values[2] = nn_values_integer(key->charcode);
|
|
values[3] = nn_values_integer(keycode_to_oc(key->keycode));
|
|
values[4] = nn_values_cstring("USER");
|
|
|
|
const char* error = nn_pushSignal(computer, values, 5);
|
|
|
|
if (error != NULL) {
|
|
// well fuck
|
|
printf("error happened when eventing the keyboarding: %s\n", error);;;;;;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int state = nn_tickComputer(computer);
|
|
if(state == NN_STATE_SWITCH) {
|
|
nn_architecture *nextArch = nn_getNextArchitecture(computer);
|
|
printf("Next architecture: %s\n", nextArch->archName);
|
|
break;
|
|
} else if(state == NN_STATE_CLOSING || state == NN_STATE_REPEAT) {
|
|
break;
|
|
} else if(state == NN_STATE_BLACKOUT) {
|
|
printf("blackout\n");
|
|
break;
|
|
}
|
|
const char *e = nn_getError(computer);
|
|
if(e != NULL) {
|
|
printf("Error: %s\n", e);
|
|
break;
|
|
}
|
|
}
|
|
|
|
render:
|
|
BeginDrawing();
|
|
|
|
ClearBackground(BLACK);
|
|
|
|
int scrW = 1, scrH = 1;
|
|
nn_getResolution(s, &scrW, &scrH);
|
|
int pixelHeight = GetScreenHeight() / scrH;
|
|
float spacing = (float)pixelHeight/10;
|
|
int pixelWidth = MeasureTextEx(unscii, "A", pixelHeight, spacing).x;
|
|
|
|
int depth = nn_getDepth(s);
|
|
|
|
int offX = (GetScreenWidth() - scrW * pixelWidth) / 2;
|
|
int offY = (GetScreenHeight() - scrH * pixelHeight) / 2;
|
|
|
|
for(size_t x = 0; x < scrW; x++) {
|
|
for(size_t y = 0; y < scrH; y++) {
|
|
ne_premappedPixel p = ne_getPremap(premap, s, x, y);
|
|
|
|
// fuck palettes
|
|
Color fgColor = ne_processColor(p.mappedFgRes);
|
|
Color bgColor = ne_processColor(p.mappedBgRes);
|
|
DrawRectangle(x * pixelWidth + offX, y * pixelHeight + offY, pixelWidth, pixelHeight, bgColor);
|
|
DrawTextCodepoint(unscii, p.codepoint, (Vector2) {x * pixelWidth + offX, y * pixelHeight + offY}, pixelHeight - 5, fgColor);
|
|
}
|
|
}
|
|
|
|
Color heatColor = GREEN;
|
|
if(heat > 60) heatColor = YELLOW;
|
|
if(heat > 80) heatColor = RED;
|
|
|
|
size_t memUsage = nn_getComputerMemoryUsed(computer);
|
|
size_t memTotal = nn_getComputerMemoryTotal(computer);
|
|
|
|
DrawText(TextFormat("Heat: %.02lf Memory Used: %.2lf%%", heat, (double)memUsage / memTotal * 100), 10, GetScreenHeight() - 30, 20, heatColor);
|
|
DrawFPS(10, 10);
|
|
|
|
EndDrawing();
|
|
}
|
|
|
|
// destroy
|
|
nn_deleteComputer(computer);
|
|
nn_unsafeDeleteUniverse(universe);
|
|
CloseWindow();
|
|
free(premap);
|
|
return 0;
|
|
}
|