Browse Source

[curses] make real

kvm
asie 10 months ago
parent
commit
487539cc55
5 changed files with 559 additions and 197 deletions
  1. 88
    69
      src/frontend_curses.c
  2. 322
    0
      src/frontend_curses_tables.c
  3. 144
    0
      src/frontend_posix.c
  4. 2
    126
      src/frontend_sdl.c
  5. 3
    2
      zeta_curses.sh

+ 88
- 69
src/frontend_curses.c View File

@@ -17,33 +17,51 @@
* along with Zeta. If not, see <http://www.gnu.org/licenses/>.
*/

#define _DEFAULT_SOURCE
#define _POSIX_C_SOURCE 2
#include <unistd.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ncurses.h>
#include <locale.h>

#include "zzt.h"
#include "posix_vfs.h"

#include <ncurses.h>

static int video_blink;

long zeta_time_ms() {
clock_t c = clock();
return c / (CLOCKS_PER_SEC/1000);
struct timespec spec;

clock_gettime(CLOCK_REALTIME, &spec);
return ((long) spec.tv_sec * 1000) + (long) (spec.tv_nsec / 1000000);
}

void cpu_ext_log(const char* s) {
fprintf(stderr, "%s\n", s);
// fprintf(stderr, "%s\n", s);
}

void speaker_on(double freq) {}
void speaker_off() {}

static int map_char_to_key[512];
static WINDOW* window;

#include "frontend_curses_tables.c"

int zeta_has_feature(int feature) {
return 1;
}

void zeta_update_charset(int width, int height, u8* data) {
}

void zeta_update_palette(u32* data) {
}

static void platform_kbd_tick() {
int c = getch();
if (c == ERR) return;
@@ -51,59 +69,33 @@ static void platform_kbd_tick() {
if (c == 0 || map_char_to_key[c] != 0) {
int k = map_char_to_key[c];
zzt_key(c, k);
zzt_keyup(k);
}
}

static void init_map_char_to_key() {
map_char_to_key[258] = 0x50; // down
map_char_to_key[260] = 0x4B; // left
map_char_to_key[259] = 0x48; // up
map_char_to_key[261] = 0x4D; // right
map_char_to_key[13] = 0x1C; // enter
map_char_to_key[0] = 0;
map_char_to_key[0x1C] = 1; // esc
for (int i = 1; i <= 9; i++) map_char_to_key[i + 48] = i + 1;
char* chrs = "!@#$%^&*()";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = i + 1;
map_char_to_key[48] = 11; // numbers
map_char_to_key[45] = 12; // -
map_char_to_key[95] = 12; // _
map_char_to_key[61] = 13; // =
map_char_to_key[43] = 12; // +
map_char_to_key[8] = 14; // backspace
map_char_to_key[9] = 15; // tab
chrs = "qwertyuiop[]";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 15 + i;
chrs = "QWERTYUIOP{}";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 15 + i;
map_char_to_key[13] = 28; // enter
// 29?
chrs = "asdfghjkl;'";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 29 + i;
chrs = "ASDFGHJKL:\"";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 29 + i;
map_char_to_key[96] = 41; // `
map_char_to_key[126] = 41; // ~
// 42?
map_char_to_key[92] = 43;
map_char_to_key[124] = 43; // |
chrs = "zxcvbnm,./";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 43 + i;
chrs = "ZXCVBNM<>?";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 43 + i;
// 54?
map_char_to_key[42] = 55; // *
// 56?
map_char_to_key[32] = 57; // space
#include "frontend_posix.c"

static int nc_color_map[] = {
COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE
};

static void init_ncurses_colors() {
for (int i = 0; i < 64; i++) {
init_pair(i+1, nc_color_map[i&7], nc_color_map[i>>3]);
}
}

int main(int argc, char** argv) {
init_posix_vfs("vfs/");
init_posix_vfs("");
init_map_char_to_key();
zzt_init();
int handle = vfs_open(argv[1]);
zzt_load_binary(handle, argc > 2 ? argv[2] : "");
vfs_close(handle);

if (posix_zzt_init(argc, argv) < 0) {
fprintf(stderr, "Could not load ZZT!\n");
return 1;
}

setlocale(LC_ALL, "");

window = initscr();
cbreak();
@@ -115,31 +107,58 @@ int main(int argc, char** argv) {
idlok(window, 1);
keypad(window, 1);

clock_t last = clock();
clock_t curr = last;

while (zzt_execute(1600000)) {
// refresh screen
u8* ram = zzt_get_ram();
for (int y = 0; y < 25; y++) {
for (int x = 0; x < 80; x++) {
u8 chr = ram[TEXT_ADDR(x,y)];
if (chr == 2) chr = '@';
else if (chr == 0) chr = 32;
else if (chr < 32 || chr >= 128)
chr = '0' + (chr % 10);
mvwaddch(window, y, x, chr);
start_color();
init_ncurses_colors();
/* clock_t last = clock();
clock_t curr = last; */

long timer_ms = zeta_time_ms();
long render_ms = timer_ms;

int rcode = 0;

while ((rcode = zzt_execute(64000)) > 0) {
long curr_ms = zeta_time_ms();

if ((curr_ms - render_ms) >= 10) {
// refresh screen
u8* ram = zzt_get_ram();
for (int y = 0; y < 25; y++) {
for (int x = 0; x < 80; x++) {
u8 chr = ram[TEXT_ADDR(x,y)];
u8 col = ram[TEXT_ADDR(x,y)+1];

int attr = COLOR_PAIR(1+((col & 7) | ((col & 0x70) >> 1) ));
if ((col & 0x08) != 0) attr |= A_BOLD;
wattrset(window, attr);
mvwaddstr(window, y, x, map_char_to_unicode[chr]);
}
}
render_ms = curr_ms;
}

wrefresh(window);
zzt_mark_frame();

curr = clock();
/* curr = clock();
float secs = (float) (curr - last) / CLOCKS_PER_SEC;
fprintf(stderr, "%.2f opc/sec\n", 1600000.0f / secs);
platform_kbd_tick();
last = curr;
last = curr; */

if (rcode == 3) {
long sleep_time = 55 - (curr_ms - timer_ms);
if (sleep_time > 1) {
usleep(sleep_time * 1000);
}
}

zzt_mark_timer();
if ((curr_ms - timer_ms) >= 55) {
zzt_mark_timer();
timer_ms = curr_ms;
}

platform_kbd_tick();
}

endwin();
}

+ 322
- 0
src/frontend_curses_tables.c View File

@@ -0,0 +1,322 @@
/**
* Copyright (c) 2018, 2019 Adrian Siekierka
*
* This file is part of Zeta.
*
* Zeta is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Zeta is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Zeta. If not, see <http://www.gnu.org/licenses/>.
*/

static u8 map_char_to_key[512];

static void init_map_char_to_key() {
map_char_to_key[258] = 0x50; // down
map_char_to_key[260] = 0x4B; // left
map_char_to_key[259] = 0x48; // up
map_char_to_key[261] = 0x4D; // right
map_char_to_key[13] = 0x1C; // enter
map_char_to_key[0] = 0;
map_char_to_key[0x1C] = 1; // esc
for (int i = 1; i <= 9; i++) map_char_to_key[i + 48] = i + 1;
char* chrs = "!@#$%^&*()";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = i + 1;
map_char_to_key[48] = 11; // numbers
map_char_to_key[45] = 12; // -
map_char_to_key[95] = 12; // _
map_char_to_key[61] = 13; // =
map_char_to_key[43] = 12; // +
map_char_to_key[8] = 14; // backspace
map_char_to_key[9] = 15; // tab
chrs = "qwertyuiop[]";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 15 + i;
chrs = "QWERTYUIOP{}";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 15 + i;
map_char_to_key[13] = 28; // enter
// 29?
chrs = "asdfghjkl;'";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 29 + i;
chrs = "ASDFGHJKL:\"";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 29 + i;
map_char_to_key[96] = 41; // `
map_char_to_key[126] = 41; // ~
// 42?
map_char_to_key[92] = 43;
map_char_to_key[124] = 43; // |
chrs = "zxcvbnm,./";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 43 + i;
chrs = "ZXCVBNM<>?";
for (int i = 0; i < strlen(chrs); i++) map_char_to_key[(int)chrs[i]] = 43 + i;
// 54?
map_char_to_key[42] = 55; // *
// 56?
map_char_to_key[32] = 57; // space
}

static const char* map_char_to_unicode[] = {
"\x20",
"\u263A",
"\u263B",
"\u2665",
"\u2666",
"\u2663",
"\u2660",
"\u2022",
"\u25D8",
"\u25EF",
"\u25D9",
"\u2642",
"\u2640",
"\u266A",
"\u266C",
"\u263C",
"\u25BA",
"\u25C4",
"\u2195",
"\u203C",
"\u00B6",
"\u00A7",
"\u25AC",
"\u21A8",
"\u2191",
"\u2193",
"\u2192",
"\u2190",
"\u2319",
"\u2194",
"\u25B2",
"\u25BC",
"\x20",
"\x21",
"\x22",
"\x23",
"\x24",
"\x25",
"\x26",
"\x27",
"\x28",
"\x29",
"\x2A",
"\x2B",
"\x2C",
"\x2D",
"\x2E",
"\x2F",
"\x30",
"\x31",
"\x32",
"\x33",
"\x34",
"\x35",
"\x36",
"\x37",
"\x38",
"\x39",
"\x3A",
"\x3B",
"\x3C",
"\x3D",
"\x3E",
"\x3F",
"\x40",
"\x41",
"\x42",
"\x43",
"\x44",
"\x45",
"\x46",
"\x47",
"\x48",
"\x49",
"\x4A",
"\x4B",
"\x4C",
"\x4D",
"\x4E",
"\x4F",
"\x50",
"\x51",
"\x52",
"\x53",
"\x54",
"\x55",
"\x56",
"\x57",
"\x58",
"\x59",
"\x5A",
"\x5B",
"\x5C",
"\x5D",
"\x5E",
"\x5F",
"\x60",
"\x61",
"\x62",
"\x63",
"\x64",
"\x65",
"\x66",
"\x67",
"\x68",
"\x69",
"\x6A",
"\x6B",
"\x6C",
"\x6D",
"\x6E",
"\x6F",
"\x70",
"\x71",
"\x72",
"\x73",
"\x74",
"\x75",
"\x76",
"\x77",
"\x78",
"\x79",
"\x7A",
"\x7B",
"\x7C",
"\x7D",
"\x7E",
"\x7F",
"\u00C7",
"\u00FC",
"\u00E9",
"\u00E2",
"\u00E4",
"\u00E0",
"\u00E5",
"\u00E7",
"\u00EA",
"\u00EB",
"\u00E8",
"\u00EF",
"\u00EE",
"\u00EC",
"\u00C4",
"\u00C5",
"\u00C9",
"\u00E6",
"\u00C6",
"\u00F4",
"\u00F6",
"\u00F2",
"\u00FB",
"\u00F9",
"\u00FF",
"\u00D6",
"\u00DC",
"\u00A2",
"\u00A3",
"\u00A5",
"\u20A7",
"\u0192",
"\u00E1",
"\u00ED",
"\u00F3",
"\u00FA",
"\u00F1",
"\u00D1",
"\u00AA",
"\u00BA",
"\u00BF",
"\u2310",
"\u00AC",
"\u00BD",
"\u00BC",
"\u00A1",
"\u00AB",
"\u00BB",
"\u2591",
"\u2592",
"\u2593",
"\u2502",
"\u2524",
"\u2561",
"\u2562",
"\u2556",
"\u2555",
"\u2563",
"\u2551",
"\u2557",
"\u255D",
"\u255C",
"\u255B",
"\u2510",
"\u2514",
"\u2534",
"\u252C",
"\u251C",
"\u2500",
"\u253C",
"\u255E",
"\u255F",
"\u255A",
"\u2554",
"\u2569",
"\u2566",
"\u2560",
"\u2550",
"\u256C",
"\u2567",
"\u2568",
"\u2564",
"\u2565",
"\u2559",
"\u2558",
"\u2552",
"\u2553",
"\u256B",
"\u256A",
"\u2518",
"\u250C",
"\u2588",
"\u2584",
"\u258C",
"\u2590",
"\u2580",
"\u03B1",
"\u00DF",
"\u0393",
"\u03C0",
"\u03A3",
"\u03C3",
"\u00B5",
"\u03C4",
"\u03A6",
"\u0398",
"\u03A9",
"\u03B4",
"\u221E",
"\u03C6",
"\u03B5",
"\u2229",
"\u2261",
"\u00B1",
"\u2265",
"\u2264",
"\u2320",
"\u2321",
"\u00F7",
"\u2248",
"\u00B0",
"\u2219",
"\u00B7",
"\u221A",
"\u207F",
"\u00B2",
"\u25A0",
"\x20"
};

+ 144
- 0
src/frontend_posix.c View File

@@ -0,0 +1,144 @@
/**
* Copyright (c) 2018, 2019 Adrian Siekierka
*
* This file is part of Zeta.
*
* Zeta is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Zeta is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Zeta. If not, see <http://www.gnu.org/licenses/>.
*/

static int posix_vfs_exists(const char *filename) {
int h = vfs_open(filename, 0);
if (h >= 0) { vfs_close(h); return 1; }
else { return 0; }
}

static void posix_zzt_help(int argc, char **argv) {
fprintf(stderr, "Usage: %s [-e command] [-bt] [world file]\n", argv > 0 ? argv[0] : "zeta");
fprintf(stderr, "\n");
fprintf(stderr, " -b disable blinking, enable bright backgrounds\n");
fprintf(stderr, " -e [] execute command - repeat to run multiple commands\n");
fprintf(stderr, " by default, runs either ZZT.EXE or SUPERZ.EXE\n");
fprintf(stderr, " -t enable world testing mode (skip K, C, ENTER)\n");
fprintf(stderr, "\n");
fprintf(stderr, "See <https://zeta.asie.pl/> for more information.\n");
}

static int posix_zzt_init(int argc, char **argv) {
char arg_name[257];
char *execs[16];
int exec_count = 0;
int c;
int skip_kc = 0;

#ifndef NO_GETOPT
while ((c = getopt(argc, argv, "be:ht")) >= 0) {
switch(c) {
case 'b':
video_blink = 0;
break;
case 'e':
if (exec_count > 16) {
fprintf(stderr, "Too many -e commands!\n");
return -1;
}
execs[exec_count++] = optarg;
break;
case 'h':
posix_zzt_help(argc, argv);
exit(0);
return -1;
case 't':
skip_kc = 1;
break;
case '?':
fprintf(stderr, "Could not parse options! Try %s -h for help.\n", argv > 0 ? argv[0] : "running with");
exit(0);
return -1;
}
}
#endif

zzt_init();

#ifdef NO_GETOPT
if (argc > 1 && posix_vfs_exists(argv[1])) {
strncpy(arg_name, argv[1], 256);
#else
if (argc > optind && posix_vfs_exists(argv[optind])) {
strncpy(arg_name, argv[optind], 256);
#endif
} else if (argc > 0) {
char *sl_ptr = strrchr(argv[0], '/');
if (sl_ptr == NULL)
sl_ptr = strrchr(argv[0], '\\');
if (sl_ptr == NULL)
sl_ptr = argv[0] - 1;

strncpy(arg_name, sl_ptr + 1, 256);
char *dot_ptr = strrchr(arg_name, '.');
if (dot_ptr == NULL) dot_ptr = arg_name + strlen(arg_name);
strncpy(dot_ptr, ".zzt", 256 - (dot_ptr - arg_name));

if (!posix_vfs_exists(arg_name)) {
arg_name[0] = 0;
}
}

if (exec_count > 0) {
int exeh = 0;
for (int i = 0; i < exec_count; i++) {
char *space_ptr = strchr(execs[i], ' ');
if (space_ptr != NULL) {
space_ptr[0] = '\0';
exeh = vfs_open(execs[i], 0);
if (exeh < 0) {
fprintf(stderr, "Could not load %s!\n", execs[i]);
space_ptr[0] = ' ';
return -1;
}
space_ptr[0] = ' ';
fprintf(stderr, "'%s'\n", space_ptr + 1);
zzt_load_binary(exeh, space_ptr + 1);
vfs_close(exeh);
} else {
exeh = vfs_open(execs[i], 0);
if (exeh < 0) {
fprintf(stderr, "Could not load %s!\n", execs[i]);
return -1;
}
zzt_load_binary(exeh, (i == exec_count - 1) ? arg_name : NULL);
vfs_close(exeh);
}

// last binary is engine
if (i == exec_count - 1) break;
while (zzt_execute(10000) != STATE_END) { }
}
} else {
int exeh = vfs_open("zzt.exe", 0);
if (exeh < 0)
exeh = vfs_open("superz.exe", 0);
if (exeh < 0)
return -1;
zzt_load_binary(exeh, arg_name);
vfs_close(exeh);
}

if (skip_kc) {
zzt_key('k', 0x25);
zzt_key('c', 0x2E);
zzt_key('\r', 0x1C);
}
return 0;
}

+ 2
- 126
src/frontend_sdl.c View File

@@ -485,131 +485,7 @@ void zeta_update_palette(u32* data) {
SDL_UnlockMutex(render_data_update_mutex);
}

static int sdl_vfs_exists(const char *filename) {
int h = vfs_open(filename, 0);
if (h >= 0) { vfs_close(h); return 1; }
else { return 0; }
}

static void sdl_zzt_help(int argc, char **argv) {
fprintf(stderr, "Usage: %s [-e command] [-bt] [world file]\n", argv > 0 ? argv[0] : "zeta");
fprintf(stderr, "\n");
fprintf(stderr, " -b disable blinking, enable bright backgrounds\n");
fprintf(stderr, " -e [] execute command - repeat to run multiple commands\n");
fprintf(stderr, " by default, runs either ZZT.EXE or SUPERZ.EXE\n");
fprintf(stderr, " -t enable world testing mode (skip K, C, ENTER)\n");
fprintf(stderr, "\n");
fprintf(stderr, "See <https://zeta.asie.pl/> for more information.\n");
}

static int sdl_zzt_init(int argc, char **argv) {
char arg_name[257];
char *execs[16];
int exec_count = 0;
int c;
int skip_kc = 0;

#ifndef NO_GETOPT
while ((c = getopt(argc, argv, "be:ht")) >= 0) {
switch(c) {
case 'b':
video_blink = 0;
break;
case 'e':
if (exec_count > 16) {
fprintf(stderr, "Too many -e commands!\n");
return -1;
}
execs[exec_count++] = optarg;
break;
case 'h':
sdl_zzt_help(argc, argv);
exit(0);
return -1;
case 't':
skip_kc = 1;
break;
case '?':
fprintf(stderr, "Could not parse options! Try %s -h for help.\n", argv > 0 ? argv[0] : "running with");
exit(0);
return -1;
}
}
#endif

zzt_init();

#ifdef NO_GETOPT
if (argc > 1 && sdl_vfs_exists(argv[1])) {
strncpy(arg_name, argv[1], 256);
#else
if (argc > optind && sdl_vfs_exists(argv[optind])) {
strncpy(arg_name, argv[optind], 256);
#endif
} else if (argc > 0) {
char *sl_ptr = strrchr(argv[0], '/');
if (sl_ptr == NULL)
sl_ptr = strrchr(argv[0], '\\');
if (sl_ptr == NULL)
sl_ptr = argv[0] - 1;

strncpy(arg_name, sl_ptr + 1, 256);
char *dot_ptr = strrchr(arg_name, '.');
if (dot_ptr == NULL) dot_ptr = arg_name + strlen(arg_name);
strncpy(dot_ptr, ".zzt", 256 - (dot_ptr - arg_name));

if (!sdl_vfs_exists(arg_name)) {
arg_name[0] = 0;
}
}

if (exec_count > 0) {
int exeh = 0;
for (int i = 0; i < exec_count; i++) {
char *space_ptr = strchr(execs[i], ' ');
if (space_ptr != NULL) {
space_ptr[0] = '\0';
exeh = vfs_open(execs[i], 0);
if (exeh < 0) {
fprintf(stderr, "Could not load %s!\n", execs[i]);
space_ptr[0] = ' ';
return -1;
}
space_ptr[0] = ' ';
fprintf(stderr, "'%s'\n", space_ptr + 1);
zzt_load_binary(exeh, space_ptr + 1);
vfs_close(exeh);
} else {
exeh = vfs_open(execs[i], 0);
if (exeh < 0) {
fprintf(stderr, "Could not load %s!\n", execs[i]);
return -1;
}
zzt_load_binary(exeh, (i == exec_count - 1) ? arg_name : NULL);
vfs_close(exeh);
}

// last binary is engine
if (i == exec_count - 1) break;
while (zzt_execute(10000) != STATE_END) { }
}
} else {
int exeh = vfs_open("zzt.exe", 0);
if (exeh < 0)
exeh = vfs_open("superz.exe", 0);
if (exeh < 0)
return -1;
zzt_load_binary(exeh, arg_name);
vfs_close(exeh);
}

if (skip_kc) {
zzt_key('k', 0x25);
zzt_key('c', 0x2E);
zzt_key('\r', 0x1C);
}
return 0;
}
#include "frontend_posix.c"

int main(int argc, char **argv) {
int scancodes_lifted[sdl_to_pc_scancode_max + 1];
@@ -636,7 +512,7 @@ int main(int argc, char **argv) {
zzt_thread_cond = SDL_CreateCond();
audio_mutex = SDL_CreateMutex();

if (sdl_zzt_init(argc, argv) < 0) {
if (posix_zzt_init(argc, argv) < 0) {
fprintf(stderr, "Could not load ZZT!\n");
SDL_Quit();
return 1;

+ 3
- 2
zeta_curses.sh View File

@@ -1,3 +1,4 @@
#!/bin/sh
gcc -o build/zeta86 -g -O2 -std=c11 -Wall -lncurses \
src/frontend_curses.c src/posix_vfs.c src/zzt.c src/cpu.c
xxd -i res/8x14.bin > res/8x14.c
gcc -o build/zeta86 -g -O2 -std=c11 -Wall -lncursesw \
src/frontend_curses.c src/posix_vfs.c src/zzt.c src/cpu.c res/8x14.c

Loading…
Cancel
Save