2023-10-25 07:50:14 +00:00
|
|
|
/*
|
|
|
|
* mii_nuklear.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include "mii.h"
|
|
|
|
#include "mii_bank.h"
|
|
|
|
#include "mii_sw.h"
|
|
|
|
|
|
|
|
#define NK_INCLUDE_FIXED_TYPES
|
|
|
|
#define NK_INCLUDE_STANDARD_IO
|
|
|
|
#define NK_INCLUDE_STANDARD_VARARGS
|
|
|
|
#define NK_INCLUDE_DEFAULT_ALLOCATOR
|
|
|
|
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
|
|
|
|
#define NK_INCLUDE_FONT_BAKING
|
|
|
|
#define NK_INCLUDE_DEFAULT_FONT
|
|
|
|
#define NK_BUTTON_TRIGGER_ON_RELEASE
|
|
|
|
#include "nuklear.h"
|
|
|
|
#include "nuklear_xlib_gl3.h"
|
|
|
|
//#include "stb_image_write.h"
|
|
|
|
#include <GL/gl.h>
|
|
|
|
#include <GL/glx.h>
|
|
|
|
|
|
|
|
#define _NK_RGBA(_r,_g,_b,_a) {.r=_r,.g=_g,.b=_b,.a=_a}
|
|
|
|
static const struct nk_color style[NK_COLOR_COUNT] = {
|
|
|
|
[NK_COLOR_TEXT] = _NK_RGBA(0, 0, 0, 255),
|
|
|
|
[NK_COLOR_WINDOW] = _NK_RGBA(175, 175, 175, 255),
|
|
|
|
[NK_COLOR_HEADER] = _NK_RGBA(175, 175, 175, 255),
|
|
|
|
[NK_COLOR_BORDER] = _NK_RGBA(0, 0, 0, 255),
|
|
|
|
[NK_COLOR_BUTTON] = _NK_RGBA(185, 185, 185, 255),
|
|
|
|
[NK_COLOR_BUTTON_HOVER] = _NK_RGBA(170, 170, 170, 255),
|
|
|
|
[NK_COLOR_BUTTON_ACTIVE] = _NK_RGBA(160, 160, 160, 255),
|
|
|
|
[NK_COLOR_TOGGLE] = _NK_RGBA(150, 150, 150, 255),
|
|
|
|
[NK_COLOR_TOGGLE_HOVER] = _NK_RGBA(120, 120, 120, 255),
|
|
|
|
[NK_COLOR_TOGGLE_CURSOR] = _NK_RGBA(175, 175, 175, 255),
|
|
|
|
[NK_COLOR_SELECT] = _NK_RGBA(190, 190, 190, 255),
|
|
|
|
[NK_COLOR_SELECT_ACTIVE] = _NK_RGBA(175, 175, 175, 255),
|
|
|
|
[NK_COLOR_SLIDER] = _NK_RGBA(190, 190, 190, 255),
|
|
|
|
[NK_COLOR_SLIDER_CURSOR] = _NK_RGBA(80, 80, 80, 255),
|
|
|
|
[NK_COLOR_SLIDER_CURSOR_HOVER] = _NK_RGBA(70, 70, 70, 255),
|
|
|
|
[NK_COLOR_SLIDER_CURSOR_ACTIVE] = _NK_RGBA(60, 60, 60, 255),
|
|
|
|
[NK_COLOR_PROPERTY] = _NK_RGBA(175, 175, 175, 255),
|
|
|
|
[NK_COLOR_EDIT] = _NK_RGBA(150, 150, 150, 255),
|
|
|
|
[NK_COLOR_EDIT_CURSOR] = _NK_RGBA(0, 0, 0, 255),
|
|
|
|
[NK_COLOR_COMBO] = _NK_RGBA(175, 175, 175, 255),
|
|
|
|
[NK_COLOR_CHART] = _NK_RGBA(160, 160, 160, 255),
|
|
|
|
[NK_COLOR_CHART_COLOR] = _NK_RGBA(45, 45, 45, 255),
|
|
|
|
[NK_COLOR_CHART_COLOR_HIGHLIGHT] = _NK_RGBA( 255, 0, 0, 255),
|
|
|
|
[NK_COLOR_SCROLLBAR] = _NK_RGBA(180, 180, 180, 255),
|
|
|
|
[NK_COLOR_SCROLLBAR_CURSOR] = _NK_RGBA(140, 140, 140, 255),
|
|
|
|
[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = _NK_RGBA(150, 150, 150, 255),
|
|
|
|
[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = _NK_RGBA(160, 160, 160, 255),
|
|
|
|
[NK_COLOR_TAB_HEADER] = _NK_RGBA(180, 180, 180, 255),
|
|
|
|
};
|
|
|
|
|
|
|
|
static GLuint screen_texture;
|
|
|
|
static struct nk_image screen_nk;
|
|
|
|
|
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
typedef uint64_t mii_time_t;
|
|
|
|
enum {
|
|
|
|
MII_TIME_RES = 1,
|
|
|
|
MII_TIME_SECOND = 1000000,
|
|
|
|
MII_TIME_MS = (MII_TIME_SECOND/1000),
|
|
|
|
};
|
|
|
|
mii_time_t
|
|
|
|
mii_get_time()
|
|
|
|
{
|
|
|
|
struct timespec tim;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC_RAW, &tim);
|
|
|
|
uint64_t time = ((uint64_t)tim.tv_sec) * (1000000 / MII_TIME_RES) +
|
|
|
|
tim.tv_nsec / (1000 * MII_TIME_RES);
|
|
|
|
return time;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include <pthread.h>
|
|
|
|
#include "fifo_declare.h"
|
|
|
|
|
|
|
|
static pthread_t mii_thread;
|
|
|
|
static bool mii_thread_running = false;
|
|
|
|
//static mii_trace_t mii_trace = {};
|
|
|
|
float default_fps = 60;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
SIGNAL_RESET,
|
|
|
|
SIGNAL_STOP,
|
|
|
|
SIGNAL_STEP,
|
|
|
|
SIGNAL_RUN,
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint8_t cmd;
|
|
|
|
uint8_t data;
|
|
|
|
} signal_t;
|
|
|
|
|
|
|
|
DECLARE_FIFO(signal_t, signal_fifo, 16);
|
|
|
|
DEFINE_FIFO(signal_t, signal_fifo);
|
|
|
|
|
|
|
|
signal_fifo_t signal_fifo;
|
|
|
|
|
|
|
|
static void *mii_thread_func(void *arg)
|
|
|
|
{
|
|
|
|
mii_t *mii = (mii_t *) arg;
|
|
|
|
mii_thread_running = true;
|
|
|
|
__uint128_t last_cycles = mii->cycles;
|
|
|
|
uint32_t running = 1;
|
|
|
|
unsigned long target_fps_us = 1000000 / default_fps;
|
|
|
|
long sleep_time = target_fps_us;
|
|
|
|
|
|
|
|
//mii_time_t base = mii_get_time(NULL);
|
|
|
|
uint32_t last_frame = mii->video.frame_count;
|
|
|
|
mii_time_t last_frame_stamp = mii_get_time();
|
|
|
|
while (mii_thread_running) {
|
|
|
|
signal_t sig;
|
|
|
|
while (!signal_fifo_isempty(&signal_fifo)) {
|
|
|
|
sig = signal_fifo_read(&signal_fifo);
|
|
|
|
switch (sig.cmd) {
|
|
|
|
case SIGNAL_RESET:
|
|
|
|
mii_reset(mii, sig.data);
|
|
|
|
break;
|
|
|
|
case SIGNAL_STOP:
|
|
|
|
mii_dump_run_trace(mii);
|
|
|
|
mii_dump_trace_state(mii);
|
|
|
|
mii->state = MII_STOPPED;
|
|
|
|
break;
|
|
|
|
case SIGNAL_STEP:
|
|
|
|
mii->state = MII_STEP;
|
|
|
|
running = 1;
|
|
|
|
break;
|
|
|
|
case SIGNAL_RUN:
|
|
|
|
mii->state = MII_RUNNING;
|
|
|
|
last_frame_stamp = mii_get_time();
|
|
|
|
running = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mii->state != MII_STOPPED)
|
|
|
|
mii_run(mii);
|
|
|
|
|
|
|
|
switch (mii->state) {
|
|
|
|
case MII_STOPPED:
|
|
|
|
usleep(1000);
|
|
|
|
break;
|
|
|
|
case MII_STEP:
|
|
|
|
if (running) {
|
|
|
|
running--;
|
|
|
|
mii_dump_trace_state(mii);
|
|
|
|
usleep(1000);
|
|
|
|
running = 1;
|
|
|
|
if (mii->trace.step_inst)
|
|
|
|
mii->trace.step_inst--;
|
|
|
|
if (mii->trace.step_inst == 0)
|
|
|
|
mii->state = MII_STOPPED;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MII_RUNNING:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mii->video.frame_count != last_frame) {
|
|
|
|
sleep_time = target_fps_us;
|
|
|
|
mii_time_t now = mii_get_time();
|
|
|
|
if (mii->state == MII_RUNNING) {
|
|
|
|
mii_time_t delta = now - last_frame_stamp;
|
|
|
|
// printf("frame time %d/%d sleep time %d\n",
|
|
|
|
// (int)delta, (int)target_fps_us,
|
|
|
|
// (int)target_fps_us - delta);
|
|
|
|
sleep_time = target_fps_us - delta;
|
|
|
|
if (sleep_time < 0)
|
|
|
|
sleep_time = 0;
|
|
|
|
last_frame = mii->video.frame_count;
|
|
|
|
while (last_frame_stamp <= now)
|
|
|
|
last_frame_stamp += target_fps_us;
|
|
|
|
|
|
|
|
// calculate the MHz
|
|
|
|
__uint128_t cycles = mii->cycles;
|
|
|
|
__uint128_t delta_cycles = cycles - last_cycles;
|
|
|
|
last_cycles = cycles;
|
|
|
|
mii->speed_current = delta_cycles / (float)target_fps_us;
|
|
|
|
}
|
|
|
|
usleep(sleep_time);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern struct nk_font *nk_main_font;
|
|
|
|
struct nk_font *nk_mono_font = NULL;
|
|
|
|
|
|
|
|
extern const unsigned char mii_proggy_data[];
|
|
|
|
extern const unsigned int mii_proggy_size;
|
|
|
|
extern const unsigned char mii_droid_data[];
|
|
|
|
extern const unsigned int mii_droid_size;
|
|
|
|
|
|
|
|
void
|
|
|
|
mii_nuklear_init(
|
|
|
|
mii_t *mii,
|
|
|
|
struct nk_context *ctx)
|
|
|
|
{
|
|
|
|
nk_style_from_table(ctx, style);
|
|
|
|
|
|
|
|
{
|
|
|
|
struct nk_font_atlas *atlas;
|
|
|
|
nk_x11_font_stash_begin(&atlas);
|
|
|
|
struct nk_font_config cfg = nk_font_config(0);
|
|
|
|
#if 0
|
|
|
|
nk_rune ranges[] = {
|
|
|
|
0x0020, 0x007E, /* Ascii */
|
|
|
|
0x00A1, 0x00FF, /* Symbols + Umlaute */
|
|
|
|
0
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
cfg.range = nk_font_default_glyph_ranges();
|
|
|
|
cfg.oversample_h = cfg.oversample_v = 1;
|
|
|
|
cfg.pixel_snap = true;
|
|
|
|
struct nk_font *nkf = nk_font_atlas_add_from_memory(atlas,
|
|
|
|
(void*)mii_proggy_data, mii_proggy_size, 20, &cfg);
|
|
|
|
nk_x11_font_stash_end();
|
|
|
|
nk_mono_font = nkf;
|
|
|
|
}
|
|
|
|
|
|
|
|
glGenTextures(1, &screen_texture);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, screen_texture);
|
|
|
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, 4,
|
|
|
|
MII_VRAM_WIDTH,
|
|
|
|
MII_VRAM_HEIGHT, 0, GL_RGBA,
|
|
|
|
GL_UNSIGNED_BYTE,
|
|
|
|
mii->video.pixels);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
// printf("%s texture created %d\n", __func__, screen_texture);
|
|
|
|
// display opengl error
|
|
|
|
GLenum err = glGetError();
|
|
|
|
if (err != GL_NO_ERROR) {
|
|
|
|
printf("Error creating texture: %d\n", err);
|
|
|
|
}
|
|
|
|
screen_nk = nk_subimage_id(
|
|
|
|
screen_texture, MII_VRAM_WIDTH, MII_VRAM_HEIGHT,
|
|
|
|
nk_rect(0, 0, MII_VIDEO_WIDTH, MII_VIDEO_HEIGHT));
|
|
|
|
|
|
|
|
/* start the thread */
|
|
|
|
pthread_create(&mii_thread, NULL, mii_thread_func, mii);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
extern int disk2_debug;
|
|
|
|
int show_zero_page = 0;
|
|
|
|
|
|
|
|
static void
|
|
|
|
mii_nuklear_handle_input(
|
|
|
|
mii_t *mii,
|
|
|
|
struct nk_context *ctx)
|
|
|
|
{
|
|
|
|
struct nk_input *in = &ctx->input;
|
|
|
|
if (in->keyboard.text_len) {
|
|
|
|
// printf("INPUT %d %s\n", in->keyboard.text_len, in->keyboard.text);
|
|
|
|
if (in->keyboard.text_len < 4) {
|
|
|
|
mii_keypress(mii, in->keyboard.text[0]);
|
|
|
|
} else if (in->keyboard.text_len > 1) {
|
|
|
|
uint32_t *raw = ((uint32_t *) in->keyboard.text);
|
|
|
|
for (int ki = 0; ki < in->keyboard.text_len / 4; ki ++) {
|
|
|
|
uint32_t key = (raw[ki] >> 16) & 0xffff;
|
|
|
|
uint8_t down = raw[ki] & 0xff;
|
|
|
|
printf("KEY %04x %s\n", key, down ? "down" : "up");
|
|
|
|
if (down) {
|
|
|
|
if (key == 0xffc9) { // F12
|
|
|
|
if (nk_input_is_key_down(in, NK_KEY_CTRL)) {
|
|
|
|
signal_t sig = {
|
|
|
|
.cmd = SIGNAL_RESET,
|
|
|
|
.data = nk_input_is_key_down(in, NK_KEY_SHIFT)
|
|
|
|
};
|
|
|
|
signal_fifo_write(&signal_fifo, sig);
|
|
|
|
printf("RESET\n");
|
|
|
|
}
|
|
|
|
} else if (key == 0xffc8) { // F11
|
|
|
|
if (nk_input_is_key_down(in, NK_KEY_CTRL)) {
|
|
|
|
signal_t sig = {
|
|
|
|
.cmd = SIGNAL_STOP,
|
|
|
|
};
|
|
|
|
signal_fifo_write(&signal_fifo, sig);
|
|
|
|
printf("STOP\n");
|
|
|
|
}
|
|
|
|
} else if (key == 0xffc7) { // F10
|
|
|
|
if (nk_input_is_key_down(in, NK_KEY_CTRL)) {
|
|
|
|
signal_t sig = {
|
|
|
|
.cmd = SIGNAL_STEP,
|
|
|
|
};
|
|
|
|
signal_fifo_write(&signal_fifo, sig);
|
|
|
|
printf("STEP\n");
|
|
|
|
}
|
|
|
|
} else if (key == 0xffc6) { // F9
|
|
|
|
if (nk_input_is_key_down(in, NK_KEY_CTRL)) {
|
|
|
|
signal_t sig = {
|
|
|
|
.cmd = SIGNAL_RUN,
|
|
|
|
};
|
|
|
|
signal_fifo_write(&signal_fifo, sig);
|
|
|
|
printf("RUN\n");
|
|
|
|
}
|
|
|
|
} else if (key == 0xffc2) { // F5
|
|
|
|
mii->speed = 1.0;
|
|
|
|
printf("Speed Normal (1MHz)\n");
|
|
|
|
} else if (key == 0xffc3) { // F6
|
|
|
|
mii->speed = 4;
|
|
|
|
printf("Speed Fast (4MHz)\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (key == 0xffeb || key == 0xffec) { // super left/right
|
|
|
|
key -= 0xffeb;
|
|
|
|
mii_bank_t *bank = &mii->bank[MII_BANK_MAIN];
|
|
|
|
uint8_t old = mii_bank_peek(bank, 0xc061 + key);
|
|
|
|
mii_bank_poke(bank, 0xc061 + key, down ? 0x80 : 0);
|
|
|
|
if (!!down != !!old) {
|
|
|
|
printf("Apple %s %s\n", key ? "Open" : "Close",
|
|
|
|
down ? "down" : "up");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
in->keyboard.text_len = 0;
|
|
|
|
} else {
|
|
|
|
signal_t sig = {.cmd = -1 };
|
|
|
|
if (nk_input_is_key_pressed(in, NK_KEY_ENTER))
|
|
|
|
sig.data = 0x0d;
|
|
|
|
else if (nk_input_is_key_pressed(in, NK_KEY_BACKSPACE))
|
|
|
|
sig.data = 0x08;
|
|
|
|
else if (nk_input_is_key_pressed(in, NK_KEY_DEL))
|
|
|
|
sig.data = 0x7f;
|
|
|
|
else if (nk_input_is_key_pressed(in, NK_KEY_UP))
|
|
|
|
sig.data = 'K' - 'A' + 1;
|
|
|
|
else if (nk_input_is_key_pressed(in, NK_KEY_DOWN))
|
|
|
|
sig.data = 'J' - 'A' + 1;
|
|
|
|
else if (nk_input_is_key_pressed(in, NK_KEY_LEFT))
|
|
|
|
sig.data = 'H' - 'A' + 1;
|
|
|
|
else if (nk_input_is_key_pressed(in, NK_KEY_RIGHT))
|
|
|
|
sig.data = 'U' - 'A' + 1;
|
|
|
|
else if (nk_input_is_key_pressed(in, NK_KEY_ESCAPE))
|
|
|
|
sig.data = 0x1b;
|
|
|
|
if (sig.data) {
|
|
|
|
// signal_fifo_write(&signal_fifo, sig);
|
|
|
|
// printf("Key %d\n", sig.data);
|
|
|
|
mii_keypress(mii, sig.data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mii_nuklear(
|
|
|
|
mii_t *mii,
|
|
|
|
struct nk_context *ctx)
|
|
|
|
{
|
|
|
|
if (mii->video.frame_count != mii->video.frame_drawn) {
|
|
|
|
mii->video.frame_drawn = mii->video.frame_count;
|
|
|
|
// update texture with new pixels; we only need 192 lines, the others
|
|
|
|
// are padding for the power of 2 texture
|
|
|
|
glBindTexture(GL_TEXTURE_2D, screen_texture);
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
|
|
|
MII_VRAM_WIDTH,
|
|
|
|
MII_VIDEO_HEIGHT, GL_RGBA,
|
|
|
|
GL_UNSIGNED_BYTE,
|
|
|
|
mii->video.pixels);
|
|
|
|
}
|
|
|
|
mii_nuklear_handle_input(mii, ctx);
|
|
|
|
int height = 720 - 8;
|
|
|
|
int width = MII_VIDEO_WIDTH * (height / (float)MII_VIDEO_HEIGHT);
|
|
|
|
int xpos = 1280 / 2 - width / 2;
|
|
|
|
{
|
|
|
|
struct nk_style *s = &ctx->style;
|
|
|
|
nk_style_push_color(ctx, &s->window.background,
|
|
|
|
nk_rgba(0,0,0, 255));
|
|
|
|
nk_style_push_style_item(ctx, &s->window.fixed_background,
|
|
|
|
nk_style_item_color(nk_rgba(0,0,0, 255)));
|
|
|
|
if (nk_begin(ctx, "Apple //e Enhanced",
|
|
|
|
nk_rect(xpos, 0, width + 10, height + 20),
|
|
|
|
NK_WINDOW_NO_SCROLLBAR)) {
|
|
|
|
nk_layout_row_static(ctx, height, width, 1);
|
|
|
|
static int was_in = -1;
|
|
|
|
if (nk_widget_is_hovered(ctx) && mii->mouse.enabled) {
|
|
|
|
if (was_in != 1) {
|
|
|
|
was_in = 1;
|
|
|
|
ctx->input.mouse.grab = 1;
|
|
|
|
// printf("IN\n");
|
|
|
|
}
|
|
|
|
struct nk_rect bounds = nk_widget_bounds(ctx);
|
|
|
|
// normalize mouse coordinates
|
|
|
|
double x = ctx->input.mouse.pos.x - bounds.x;
|
|
|
|
double y = ctx->input.mouse.pos.y - bounds.y;
|
|
|
|
// get mouse button state
|
|
|
|
int button = ctx->input.mouse.buttons[NK_BUTTON_LEFT].down;
|
|
|
|
// clamp coordinates inside bounds
|
|
|
|
double vw = bounds.w;
|
|
|
|
double vh = bounds.h;
|
|
|
|
double mw = mii->mouse.max_x - mii->mouse.min_x;
|
|
|
|
double mh = mii->mouse.max_y - mii->mouse.min_y;
|
|
|
|
mii->mouse.x = mii->mouse.min_x + (x * mw / vw) + 0.5;
|
|
|
|
mii->mouse.y = mii->mouse.min_y + (y * mh / vh) + 0.5;
|
|
|
|
mii->mouse.button = button;
|
|
|
|
// printf("Mouse is %d %d\n", (int)mii->mouse.x, (int)mii->mouse.y);
|
|
|
|
} else {
|
|
|
|
if (was_in == 1) {
|
|
|
|
was_in = 0;
|
|
|
|
ctx->input.mouse.ungrab = 1;
|
|
|
|
// printf("OUT\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nk_image(ctx, screen_nk);
|
|
|
|
nk_end(ctx);
|
|
|
|
nk_style_pop_color(ctx);
|
|
|
|
nk_style_pop_style_item(ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct nk_rect bounds = { .x = 0, .y = 0, .w = xpos, .h = height };
|
|
|
|
// nk_window_get_bounds(ctx);
|
|
|
|
bool in = nk_input_is_mouse_hovering_rect(&ctx->input, bounds);
|
|
|
|
static bool menu_open = false;
|
|
|
|
|
|
|
|
if (in || menu_open) {
|
|
|
|
struct nk_style *s = &ctx->style;
|
|
|
|
nk_style_push_color(ctx, &s->window.background,
|
|
|
|
nk_rgba(175, 175, 175, 255));
|
|
|
|
nk_style_push_style_item(ctx, &s->window.fixed_background,
|
|
|
|
nk_style_item_color(nk_rgba(175, 175, 175, 255)));
|
|
|
|
|
|
|
|
if (nk_begin(ctx, "Left Bar",
|
|
|
|
nk_rect(0, 0, xpos, height + 20),
|
|
|
|
NK_WINDOW_NO_SCROLLBAR)) {
|
|
|
|
#if 0
|
|
|
|
nk_menubar_begin(ctx);
|
|
|
|
nk_layout_row_begin(ctx, NK_STATIC, 25, 2);
|
|
|
|
nk_layout_row_push(ctx, 60);
|
|
|
|
bool menu = false;
|
|
|
|
if (nk_menu_begin_label(ctx, "MII", NK_TEXT_LEFT,
|
|
|
|
nk_vec2(140, 200))) {
|
|
|
|
static size_t prog = 40;
|
|
|
|
static float slider = 0.5;
|
|
|
|
static int check = nk_true;
|
|
|
|
nk_layout_row_dynamic(ctx, 25, 1);
|
|
|
|
if (nk_menu_item_label(ctx, "Hide", NK_TEXT_LEFT))
|
|
|
|
;//show_menu = nk_false;
|
|
|
|
if (nk_menu_item_label(ctx, "About", NK_TEXT_LEFT))
|
|
|
|
;//show_app_about = nk_true;
|
|
|
|
nk_progress(ctx, &prog, 100, NK_MODIFIABLE);
|
|
|
|
nk_slider_float(ctx, 0.01, &slider, 1.0, 0.05);
|
|
|
|
nk_checkbox_label(ctx, "Mute", &check);
|
|
|
|
nk_menu_end(ctx);
|
|
|
|
menu = true;
|
|
|
|
}
|
|
|
|
menu_open = menu;
|
|
|
|
nk_menubar_end(ctx);
|
|
|
|
nk_layout_space_end(ctx);
|
|
|
|
#endif
|
|
|
|
int rw = xpos - 8;
|
|
|
|
// nk_layout_row_dynamic(ctx, 4, 1);
|
|
|
|
// nk_spacing(ctx, 1);
|
|
|
|
|
|
|
|
nk_layout_row_static(ctx, 30, rw, 1);
|
|
|
|
if (nk_button_label(ctx, "C-RESET"))
|
|
|
|
mii_reset(mii, false);
|
|
|
|
if (nk_button_label(ctx, "C-OA-RESET"))
|
|
|
|
mii_reset(mii, true);
|
|
|
|
// nk_layout_row_dynamic(ctx, 0, 1);
|
|
|
|
nk_layout_row_begin(ctx, NK_STATIC, 30, 2);
|
|
|
|
nk_layout_row_push(ctx, 20);
|
|
|
|
nk_label(ctx, "V:", NK_TEXT_LEFT);
|
|
|
|
nk_layout_row_push(ctx, rw - 20 - 4);
|
|
|
|
const char *video_modes[] = {
|
|
|
|
"Color",
|
|
|
|
"Green",
|
|
|
|
"Amber",
|
|
|
|
};
|
|
|
|
mii->video.color_mode = nk_combo(ctx,
|
|
|
|
video_modes, NK_LEN(video_modes),
|
|
|
|
mii->video.color_mode, 25, nk_vec2(80,200));
|
|
|
|
nk_layout_space_end(ctx);
|
|
|
|
|
|
|
|
nk_layout_row_begin(ctx, NK_STATIC, 30, 1);
|
|
|
|
nk_layout_row_push(ctx, rw);
|
|
|
|
const char *speed[] = {
|
|
|
|
"1 MHz",
|
|
|
|
"Slow",
|
|
|
|
"Fast",
|
|
|
|
};
|
|
|
|
nk_label(ctx, "Speed:", NK_TEXT_LEFT);
|
|
|
|
nk_layout_row_push(ctx, 100);
|
2023-10-25 17:58:32 +00:00
|
|
|
int spi = mii->speed > .95 && mii->speed < 1.05 ? 0 :
|
|
|
|
mii->speed < 0.9 ? 1 : 2;
|
2023-10-25 07:50:14 +00:00
|
|
|
spi = nk_combo(ctx,
|
|
|
|
speed, NK_LEN(speed),
|
|
|
|
spi, 25, nk_vec2(80,200));
|
2023-10-25 17:58:32 +00:00
|
|
|
mii->speed = spi == 0 ? 1.0 : spi == 1 ? 0.2 : 4.0;
|
2023-10-25 07:50:14 +00:00
|
|
|
nk_layout_space_end(ctx);
|
|
|
|
}
|
|
|
|
nk_end(ctx);
|
|
|
|
nk_style_pop_color(ctx);
|
|
|
|
nk_style_pop_style_item(ctx);
|
|
|
|
}
|
|
|
|
if ( 0 && nk_begin(ctx, "Controls",
|
|
|
|
nk_rect(width, 0, 350, 10 + 192 * 3),
|
|
|
|
NK_WINDOW_NO_SCROLLBAR)) {
|
|
|
|
nk_layout_row_static(ctx, 30, 110, 2);
|
|
|
|
if (nk_button_label(ctx, "C-RESET"))
|
|
|
|
mii_reset(mii, false);
|
|
|
|
if (nk_button_label(ctx, "C-OA-RESET"))
|
|
|
|
mii_reset(mii, true);
|
|
|
|
#if 0
|
|
|
|
if (nk_button_label(ctx, "Screenshot")) {
|
|
|
|
stbi_write_png("screen.png",
|
|
|
|
MII_VIDEO_WIDTH, MII_VIDEO_HEIGHT, 4, mii->video.pixels,
|
|
|
|
MII_VRAM_WIDTH * 4);
|
|
|
|
printf("Screenshot taken\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
nk_layout_row_dynamic(ctx, 30, 4);
|
|
|
|
nk_label(ctx, "Speed:", NK_TEXT_CENTERED);
|
|
|
|
if (nk_option_label(ctx, "Slow", mii->speed < 0.9)) mii->speed = 0.2;
|
|
|
|
if (nk_option_label(ctx, "1 MHz", mii->speed > .95 && mii->speed < 1.05)) mii->speed = 1.0;
|
|
|
|
if (nk_option_label(ctx, "Fast", mii->speed > 1.1 && mii->speed < 4.1)) mii->speed = 4.0;
|
|
|
|
|
|
|
|
nk_layout_row_dynamic(ctx, 30, 4);
|
|
|
|
nk_label(ctx, "Video:", NK_TEXT_CENTERED);
|
|
|
|
if (nk_option_label(ctx, "Color", mii->video.color_mode == MII_VIDEO_COLOR))
|
|
|
|
mii->video.color_mode = MII_VIDEO_COLOR;
|
|
|
|
if (nk_option_label(ctx, "Green", mii->video.color_mode == MII_VIDEO_GREEN))
|
|
|
|
mii->video.color_mode = MII_VIDEO_GREEN;
|
|
|
|
if (nk_option_label(ctx, "Amber", mii->video.color_mode == MII_VIDEO_AMBER))
|
|
|
|
mii->video.color_mode = MII_VIDEO_AMBER;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
nk_layout_row_dynamic(ctx, 20, 1);
|
|
|
|
nk_style_set_font(ctx, &nk_mono_font->handle);
|
|
|
|
struct nk_color save = ctx->style.window.background;
|
|
|
|
|
|
|
|
ctx->style.window.background = (struct nk_color)_NK_RGBA(0, 0, 0, 255);
|
|
|
|
struct nk_color fore = (struct nk_color)_NK_RGBA(0, 255, 0, 255);
|
|
|
|
char label[64];
|
|
|
|
mii_dasm_t _dasm = {};
|
|
|
|
mii_dasm_t *dasm = &_dasm;
|
|
|
|
mii_dasm_init(dasm, mii, 0);
|
|
|
|
dasm->mii = mii;
|
|
|
|
// display the last few cycles up to the PC
|
|
|
|
for (int di = 0; di < 3; di++) {
|
|
|
|
int pci = (mii_trace.idx + MII_PC_LOG_SIZE - 3 + di) % MII_PC_LOG_SIZE;
|
|
|
|
dasm->pc = mii_trace.log[pci];
|
|
|
|
mii_dasm_step(dasm, label, sizeof(label));
|
|
|
|
if (di == 2)
|
|
|
|
label[0] = '*';
|
|
|
|
nk_label_colored(ctx, label, NK_TEXT_LEFT, fore);
|
|
|
|
}
|
|
|
|
// and the (potentially) next instruction here
|
|
|
|
mii_dasm_step(dasm, label, sizeof(label));
|
|
|
|
nk_label_colored(ctx, label, NK_TEXT_LEFT, fore);
|
|
|
|
|
|
|
|
sprintf(label, "A:%02X X:%02X Y:%02X S:%02X",
|
|
|
|
mii->cpu.A, mii->cpu.X, mii->cpu.Y, mii->cpu.S);
|
|
|
|
nk_label_colored(ctx, label, NK_TEXT_CENTERED, fore);
|
|
|
|
char n[] = {'C','Z','I','D','B','V','N'};
|
|
|
|
label[0] = 0;
|
|
|
|
sprintf(label, "%04x ", mii->cpu.PC);
|
|
|
|
for (int i = 0; i < 7; i++)
|
|
|
|
sprintf(label + strlen(label), "%c%d ", n[i],
|
|
|
|
mii->cpu.P.P[i]);
|
|
|
|
nk_label_colored(ctx, label, NK_TEXT_CENTERED, fore);
|
|
|
|
|
|
|
|
ctx->style.window.background = save;
|
|
|
|
nk_style_set_font(ctx, &nk_main_font->handle);
|
|
|
|
#endif
|
|
|
|
nk_layout_row_static(ctx, 30, 30, 3);
|
|
|
|
|
|
|
|
if (nk_button_symbol(ctx, NK_SYMBOL_RECT_SOLID)) {
|
|
|
|
signal_fifo_write(&signal_fifo, (signal_t){.cmd = SIGNAL_STOP});
|
|
|
|
}
|
|
|
|
if (nk_button_symbol(ctx, NK_SYMBOL_PLUS)) {
|
|
|
|
signal_fifo_write(&signal_fifo, (signal_t){.cmd = SIGNAL_STEP});
|
|
|
|
}
|
|
|
|
if (nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_RIGHT)) {
|
|
|
|
signal_fifo_write(&signal_fifo, (signal_t){.cmd = SIGNAL_RUN});
|
|
|
|
}
|
|
|
|
nk_layout_row_dynamic(ctx, 20, 3);
|
|
|
|
{
|
|
|
|
char label[32];
|
|
|
|
sprintf(label, "CPU: %.1fMHz", mii->speed_current);
|
|
|
|
nk_label(ctx, label, NK_TEXT_CENTERED);
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
nk_layout_row_dynamic(ctx, 20, 2);
|
|
|
|
nk_checkbox_label(ctx, "Disk II Debug", &disk2_debug);
|
|
|
|
nk_checkbox_label(ctx, "Slowmo", &mii_SLOW);
|
|
|
|
// nk_checkbox_label(ctx, "Zero Page", &show_zero_page);
|
|
|
|
#endif
|
|
|
|
nk_end(ctx);
|
|
|
|
}
|
|
|
|
if (show_zero_page) {
|
|
|
|
if (nk_begin(ctx, "Zero Page",
|
|
|
|
nk_rect(0, 10 + 192 * 3, 600, 10 + 16 * 20),
|
|
|
|
0 )) {
|
|
|
|
nk_layout_row_dynamic(ctx, 20, 1);
|
|
|
|
nk_style_set_font(ctx, &nk_mono_font->handle);
|
|
|
|
struct nk_color fore = (struct nk_color)_NK_RGBA(0, 255, 0, 255);
|
|
|
|
uint8_t *zp = mii->bank[0].mem;
|
|
|
|
char label[128];
|
|
|
|
for (int ri = 0; ri < (256 / 16); ri++) {
|
|
|
|
sprintf(label, "%02x: ", ri * 16);
|
|
|
|
for (int ci = 0; ci < 16; ci++) {
|
|
|
|
sprintf(label + strlen(label), "%02X ",
|
|
|
|
zp[ri * 16 + ci]);
|
|
|
|
}
|
|
|
|
nk_label_colored(ctx, label, NK_TEXT_LEFT, fore);
|
|
|
|
}
|
|
|
|
nk_style_set_font(ctx, &nk_main_font->handle);
|
|
|
|
nk_end(ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|