New about box. Also some fixes for some WOZ1 files

AppleGalaxian failed to load because of a sparse track map.

Signed-off-by: Michel Pollet <buserror@gmail.com>
This commit is contained in:
Michel Pollet 2024-02-14 20:23:11 +00:00
parent 5650323d05
commit d399b12a9d
No known key found for this signature in database
10 changed files with 316 additions and 27 deletions

View File

@ -61,6 +61,8 @@ $(LIB)/ui_tests.so : $(OBJ)/mii_mui_1mb.o
$(LIB)/ui_tests.so : $(OBJ)/mii_mui_2dsk.o
$(LIB)/ui_tests.so : $(OBJ)/mii_mui_about.o
$(OBJ)/mii_mui_about.o : CPPFLAGS+=-DMII_ICON64_DEFINE
# use a .temp file, otherwise the playground tries to reload before the file
# is fully written, and it fails.
# the ${filter} are there to make the sure object files are linked before the .a

BIN
libmui/fonts/Geneva.ttf Normal file

Binary file not shown.

View File

@ -242,15 +242,20 @@ mui_timer_reset(
if (id >= MUI_TIMER_COUNT)
return 0;
if (!(ui->timer.map & (1 << id)) ||
ui->timer.timers[id].cb != cb)
ui->timer.timers[id].cb != cb) {
printf("%s: timer %d not active\n", __func__, id);
return 0;
}
mui_time_t res = 0;
uint64_t now = mui_get_time();
if (ui->timer.timers[id].when > now)
res = ui->timer.timers[id].when - now;
ui->timer.timers[id].when = now + delay;
if (delay == 0)
if (delay == 0) {
ui->timer.map &= ~(1 << id);
printf("%s: timer %d removed\n", __func__, id);
}
return res;
}

View File

@ -326,10 +326,16 @@ typedef struct mui_drawable_t {
struct cg_ctx_t * cg;
union pixman_image * pixman; // (try) not to use these directly
unsigned int pixman_clip_dirty: 1,
cg_clip_dirty : 1;
cg_clip_dirty : 1,
dispose_pixels : 1;
// (default) position in destination when drawing
c2_pt_t origin;
mui_clip_stack_t clip;
} mui_drawable_t;
// Use IMPLEMENT_C_ARRAY(mui_drawable_array); if you need this
DECLARE_C_ARRAY(mui_drawable_t *, mui_drawable_array, 4);
/*
* Drawable related
*/
@ -425,6 +431,13 @@ mui_font_t *
mui_font_find(
struct mui_t * ui,
const char * name);
mui_font_t *
mui_font_from_mem(
struct mui_t * ui,
const char *name,
unsigned int size,
const void *font_data,
unsigned int font_size );
void
mui_font_text_draw(
mui_font_t * font,
@ -473,6 +486,15 @@ mui_font_measure(
unsigned int text_len,
mui_glyph_line_array_t *lines,
uint16_t flags);
// to be used exclusively with mui_font_measure
void
mui_font_measure_draw(
mui_font_t *font,
mui_drawable_t *dr,
c2_rect_t bbox,
mui_glyph_line_array_t *lines,
mui_color_t color,
uint16_t flags);
// clear all the lines, and glyph lists. Use it after mui_font_measure
void
mui_font_measure_clear(

View File

@ -36,6 +36,8 @@ mui_drawable_clear(
for (int i = 0; i < (int)dr->clip.count; i++)
pixman_region32_fini(&dr->clip.e[i]);
mui_clip_stack_clear(&dr->clip);
if (dr->pix.pixels && dr->dispose_pixels)
free(dr->pix.pixels);
dr->_pix_hash = NULL;
}

View File

@ -24,6 +24,7 @@
INCBIN(main_font, "fonts/Charcoal_mui.ttf");
INCBIN(icon_font, "fonts/typicon.ttf");
INCBIN(dingbat_font, "fonts/Dingbat.ttf");
INCBIN(geneva_font, "fonts/Geneva.ttf");
#include "mui.h"

View File

@ -172,11 +172,10 @@ _init(
m_cpu_menu);
// mii_mui_configure_slots(g->ui, &g_machine_conf);
// mii_mui_load_binary(g->ui, &g_loadbin_conf);
mii_mui_load_binary(g->ui, &g_loadbin_conf);
// mii_mui_load_1mbrom(g->ui, &g_machine_conf.slot[0].conf.rom1mb);
// mii_mui_load_2dsk(g->ui,
// &g_machine_conf.slot[0].conf.disk2, MII_2DSK_DISKII);
mii_mui_about(g->ui);
// mii_mui_load_2dsk(g->ui, &g_machine_conf.slot[0].conf.disk2, MII_2DSK_DISKII);
// mii_mui_about(g->ui);
#if 0
mui_alert(ui, C2_PT(0,0),
"Testing one Two",
@ -234,4 +233,4 @@ mui_plug_t mui_plug = {
.dispose = _dispose,
.draw = _draw,
.event = _event,
};
};

View File

@ -205,6 +205,24 @@ mii_floppy_write_track_woz(
return 0;
}
static uint64_t
mii_floppy_woz_load_tmap(
mii_floppy_t *f,
mii_woz_tmap_t *tmap )
{
uint64_t used_tracks = 0;
int tmap_size = le32toh(tmap->chunk.size_le);
for (int ti = 0; ti < (int)sizeof(f->track_id) && ti < tmap_size; ti++) {
if (tmap->track_id[ti] == 0xff) {
f->track_id[ti] = MII_FLOPPY_RANDOM_TRACK_ID;
continue;
}
f->track_id[ti] = tmap->track_id[ti];
used_tracks |= 1L << f->track_id[ti];
}
return used_tracks;
}
static int
mii_floppy_load_woz(
mii_floppy_t *f,
@ -221,12 +239,15 @@ mii_floppy_load_woz(
}
version += !strncmp((char*)header, "WOZ2", 4);
mii_woz_tmap_t *tmap = NULL;
uint64_t used_tracks = 0;
if (version == 1) {
mii_woz1_info_t *info = (mii_woz1_info_t *)(header + 1);
tmap = (mii_woz_tmap_t *)((uint8_t *)info +
le32toh(info->chunk.size_le) + sizeof(mii_woz_chunk_t));
mii_woz1_trks_t *trks = (mii_woz1_trks_t *)((uint8_t *)tmap +
le32toh(tmap->chunk.size_le) + sizeof(mii_woz_chunk_t));
used_tracks = mii_floppy_woz_load_tmap(f, tmap);
#if 1
printf("WOZ: version %d, type %d\n",
info->version, info->disk_type );
@ -237,8 +258,13 @@ mii_floppy_load_woz(
printf("WOZ: Track chunk %4.4s size %d\n",
(char*)&trks->chunk.id_le, le32toh(trks->chunk.size_le));
#endif
for (int i = 0; i < 35; i++) {
int max_track = le32toh(trks->chunk.size_le) / sizeof(trks->track[0]);
for (int i = 0; i < 35 && i < max_track; i++) {
uint8_t *track = trks->track[i].bits;
if (!(used_tracks & (1L << i))) {
// printf("WOZ: Track %d not used\n", i);
continue;
}
memcpy(f->tracks[i].data, track, le16toh(trks->track[i].byte_count_le));
f->tracks[i].bit_count = le32toh(trks->track[i].bit_count_le);
}
@ -248,6 +274,7 @@ mii_floppy_load_woz(
le32toh(info->chunk.size_le) + sizeof(mii_woz_chunk_t));
mii_woz2_trks_t *trks = (mii_woz2_trks_t *)((uint8_t *)tmap +
le32toh(tmap->chunk.size_le) + sizeof(mii_woz_chunk_t));
used_tracks = mii_floppy_woz_load_tmap(f, tmap);
#if 1
printf("WOZ: version %d, type %d, sides %d, largest track %d, optimal bit timing: %d\n",
info->version, info->disk_type, info->sides,
@ -263,6 +290,10 @@ mii_floppy_load_woz(
/* TODO: this doesn't work yet... */
// f->bit_timing = info->optimal_bit_timing;
for (int i = 0; i < 35; i++) {
if (!(used_tracks & (1L << i))) {
// printf("WOZ: Track %d not used\n", i);
continue;
}
uint8_t *track = file->map +
(le16toh(trks->track[i].start_block_le) << 9);
uint32_t byte_count = (le32toh(trks->track[i].bit_count_le) + 7) >> 3;
@ -270,15 +301,6 @@ mii_floppy_load_woz(
f->tracks[i].bit_count = le32toh(trks->track[i].bit_count_le);
}
}
// copy the track map from the file to the floppy
for (int ti = 0; ti < (int)sizeof(f->track_id); ti++) {
f->track_id[ti] = tmap->track_id[ti] == 0xff ?
MII_FLOPPY_RANDOM_TRACK_ID : tmap->track_id[ti];
if (f->tracks[f->track_id[ti]].bit_count == 0) {
printf("%s Invalid qtrack %d (points to track %d) has zero bits!\n",
__func__, ti, f->track_id[ti]);
}
}
return version;
}

View File

@ -14,20 +14,129 @@
#include "mui.h"
#include "mii-icon-64.h"
extern const unsigned char mui_geneva_font_data[];
extern const unsigned int mui_geneva_font_size;
enum {
MII_ABOUT_WINDOW_ID = FCC('a','b','o','t'),
MII_ABOUT_OK = FCC('O','K','!',' '),
};
struct mui_drawable_control_t;
typedef struct mii_mui_about_t {
mui_window_t win;
struct mui_drawable_control_t * text;
uint8_t timer_id;
bool terminate;
} mii_mui_about_t;
//DECLARE_C_ARRAY(mui_drawable_t *, mui_drawable_array, 4);
typedef struct mui_drawable_control_t {
mui_control_t control;
uint16_t flags;
mui_drawable_t * mask;
mui_drawable_array_t drawables;
} mui_drawable_control_t;
IMPLEMENT_C_ARRAY(mui_drawable_array);
static void
mui_drawable_draw(
mui_window_t * win,
mui_control_t * c,
mui_drawable_t *dr )
{
c2_rect_t f = c->frame;
c2_rect_offset(&f, win->content.l, win->content.t);
mui_drawable_clip_push(dr, &f);
mui_drawable_control_t *dc = (mui_drawable_control_t *)c;
for (int i = 0; i < (int)dc->drawables.count; i++) {
mui_drawable_t *d = dc->drawables.e[i];
if (!d->pix.pixels)
continue;
c2_rect_t src = C2_RECT_WH(0, 0,
d->pix.size.x,
d->pix.size.y);
c2_rect_offset(&src, d->origin.x, d->origin.y);
pixman_image_composite32(PIXMAN_OP_OVER,
mui_drawable_get_pixman(d),
mui_drawable_get_pixman(dc->mask),
mui_drawable_get_pixman(dr),
src.l, src.t, 0, 0,
f.l, f.t,
c2_rect_width(&src), c2_rect_height(&src));
}
mui_drawable_clip_pop(dr);
}
static bool
mui_cdef_drawable(
struct mui_control_t * c,
uint8_t what,
void * param)
{
// mui_textbox_control_t *tb = (mui_textbox_control_t *)c;
switch (what) {
case MUI_CDEF_DRAW: {
mui_drawable_t * dr = param;
switch (c->type) {
case 0:
mui_drawable_draw(c->win, c, dr);
break;
}
} break;
case MUI_CDEF_DISPOSE: {
switch (c->type) {
case 0: {
mui_drawable_control_t *dc = (mui_drawable_control_t *)c;
for (int i = 0; i < (int)dc->drawables.count; i++) {
mui_drawable_t *d = dc->drawables.e[i];
mui_drawable_dispose(d);
free(d);
}
mui_drawable_dispose(dc->mask);
if (dc->mask)
free(dc->mask);
mui_drawable_array_free(&dc->drawables);
} break;
}
} break;
}
return false;
}
static mui_time_t
mui_about_timer_cb(
struct mui_t * mui,
mui_time_t now,
void * param)
{
mii_mui_about_t * m = (mii_mui_about_t*)param;
if (m->terminate) {
mui_window_dispose(&m->win);
return 0;
}
mui_drawable_control_t *dc = m->text;
mui_drawable_t * dr = dc->drawables.e[0];
dr->origin.y++;
int height = dr->pix.size.y + c2_rect_height(&dc->control.frame);
if (dr->origin.y > dr->pix.size.y)
dr->origin.y -= height;
// printf("Y: %d/%d\n", dr->origin.y, height);
mui_control_inval(&dc->control);
return MUI_TIME_SECOND / 30;
}
static int
_mii_about_action_cb(
_mii_about_button_cb(
mui_control_t * c,
void * cb_param, // mii_mui_about_t
uint32_t what,
@ -42,8 +151,7 @@ _mii_about_action_cb(
printf("%s control %4.4s\n", __func__, (char*)&uid);
switch (uid) {
case MII_ABOUT_OK: {
// save the config
mui_window_dispose(&m->win);
m->terminate = true;
} break;
}
break;
@ -51,6 +159,32 @@ _mii_about_action_cb(
return 0;
}
#ifndef MII_VERSION
#define MII_VERSION "0.0.0"
#endif
static const char * about =
"\n"
"The MII " MUI_GLYPH_IIE " Emulator\n"
"Version " MII_VERSION "\n"
"Built " __DATE__ " " __TIME__ "\n"
"© Michel Pollet 2023-2024\n\n"
"Thanks to:\n"
;
static const char * thanksto =
"Steve Wozniak\n"
"Bill Atkinson\n"
"Andy Hertzfeld\n"
"Randy Wigginton\n"
"Jef Raskin\n"
"Susan Kare\n"
"Thierry Magniez\n"
"Charles \"regnips\" Springer\n"
"Jeroen \"Sprite_tm\" Domburg\n"
"Claude \"Claude\" Schwarz\n"
"... and many others"
;
struct mui_window_t *
mii_mui_about(
struct mui_t *mui )
@ -64,7 +198,7 @@ mii_mui_about(
return w;
}
c2_pt_t where = {};
c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 560, 240);
c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 500, 240);
if (where.x == 0 && where.y == 0)
c2_rect_offset(&wpos,
(ui->screen_size.x / 2) - (c2_rect_width(&wpos) / 2),
@ -73,18 +207,119 @@ mii_mui_about(
"About the MII " MUI_GLYPH_IIE " Emulator",
sizeof(mii_mui_about_t));
mui_window_set_id(w, MII_ABOUT_WINDOW_ID);
mii_mui_about_t * m = (mii_mui_about_t*)w;
mui_control_t * c = NULL;
mui_control_t * c = NULL, *ok = NULL;
c2_rect_t cf;
cf = C2_RECT_WH(0, 0, base_size * 4, base_size * 1.4);
c2_rect_left_of(&cf, c2_rect_width(&w->content), margin);
c2_rect_top_of(&cf, c2_rect_height(&w->content), margin);
c = mui_button_new(w,
ok = c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_DEFAULT,
"OK", MII_ABOUT_OK);
c->key_equ = MUI_KEY_EQU(0, 13);
mui_control_set_action(c, _mii_about_button_cb, w);
cf = C2_RECT_WH(margin, margin, mii_icon64[0], mii_icon64[1]);
/*
Icon
*/
c = mui_control_new(
w, 0, mui_cdef_drawable,
cf, NULL, 0, sizeof(mui_drawable_control_t));
mui_drawable_control_t *dc = (mui_drawable_control_t*)c;
mui_drawable_t *dr = calloc(1, sizeof(mui_drawable_t));
/* the Xorg icon is in fact using unsigned int (64 bits!) per pixels
* for some bizare reason. Here we convert it back to 32bpp */
dr->pix.bpp = 32;
dr->pix.size.x = mii_icon64[0];
dr->pix.size.y = mii_icon64[1];
dr->pix.row_bytes = dr->pix.size.x * 4;
dr->pix.pixels = calloc(1, dr->pix.row_bytes * dr->pix.size.y);
dr->dispose_pixels = true;
/*
* if the clear color is 0, it means we are using OpenGL as a renderer
* this is not ideal as it means we need to reverse our internal format
* (ARGB) to the one used by OpenGL (ABGR)
*/
for (int y = 0; y < dr->pix.size.y; y++) {
for (int x = 0; x < dr->pix.size.x; x++) {
uint32_t *p = (uint32_t*)dr->pix.pixels;
p += y * dr->pix.size.x + x;
uint32_t pix = mii_icon64[2 + y * dr->pix.size.x + x];
if (ui->color.clear.a == 0) {
// ARGB -> ABGR
*p = ((pix & 0xff00ff00) |
((pix & 0x00ff0000) >> 16) |
((pix & 0x000000ff) << 16));
} else
*p = pix;
}
}
mui_drawable_array_add(&dc->drawables, dr);
/*
* Text in two parts
*/
cf = C2_RECT_WH(cf.r + margin, 10,
c2_rect_width(&w->frame) - cf.r - margin*2,
ok->frame.t - margin);
c2_rect_t tbox = cf;
c2_rect_offset(&tbox, -tbox.l, -tbox.t);
tbox.b = 1000;
mui_font_t *font = mui_font_find(ui, "main");
mui_font_t *geneva = mui_font_find(ui, "geneva");
if (!geneva) {
geneva = mui_font_from_mem(ui, "geneva", 24,
mui_geneva_font_data, mui_geneva_font_size);
}
mui_glyph_line_array_t lines_about = {};
mui_font_measure(font, tbox, about, 0, &lines_about, MUI_TEXT_ALIGN_CENTER);
c2_rect_t about_frame = tbox;
about_frame.b = 0;
for (int li = 0; li < (int)lines_about.count; li++) {
mui_glyph_array_t * line = &lines_about.e[li];
// printf("line %d x %d y %d w %d\n", li, line->x, line->y, line->w);
about_frame.b = line->y;
}
mui_glyph_line_array_t lines_thanks = {};
mui_font_measure(geneva, tbox, thanksto, 0, &lines_thanks, MUI_TEXT_ALIGN_CENTER);
c2_rect_t frame_thanks = tbox;
frame_thanks.b = 0;
for (int li = 0; li < (int)lines_thanks.count; li++) {
mui_glyph_array_t * line = &lines_thanks.e[li];
// printf("line %d x %d y %d w %d\n", li, line->x, line->y, line->w);
frame_thanks.b = line->y;
}
c2_rect_offset(&frame_thanks, 0, about_frame.b + 0);
c = mui_control_new(
w, 0, mui_cdef_drawable,
cf, NULL, 0, sizeof(mui_drawable_control_t));
tbox.b = frame_thanks.b + 2;
m->text = dc = (mui_drawable_control_t*)c;
dr = calloc(1, sizeof(mui_drawable_t));
dr->pix.bpp = 32;
dr->pix.size.x = c2_rect_width(&tbox);
dr->pix.size.y = c2_rect_height(&tbox);
dr->pix.row_bytes = dr->pix.size.x * 4;
dr->pix.pixels = calloc(1, dr->pix.row_bytes * dr->pix.size.y);
dr->dispose_pixels = true;
mui_color_t text_color = MUI_COLOR(0x000000ff);
mui_font_measure_draw(font, dr, tbox, &lines_about,
text_color, MUI_TEXT_ALIGN_CENTER);
mui_font_measure_draw(geneva, dr, frame_thanks, &lines_thanks,
text_color, MUI_TEXT_ALIGN_CENTER);
mui_drawable_array_add(&dc->drawables, dr);
m->timer_id = mui_timer_register(ui,
mui_about_timer_cb, m, MUI_TIME_SECOND);
return w;
}

View File

@ -209,7 +209,8 @@ mii_menubar_action(
// (char*)&item->uid, item->title);
switch (item->uid) {
case FCC('a','b','o','t'): {
_mii_show_about(ui);
// _mii_show_about(ui);
mii_mui_about(&ui->mui);
} break;
case FCC('q','u','i','t'): {
// printf("%s Quit?\n", __func__);
@ -395,4 +396,4 @@ mii_mui_menus_init(
mui_menubar_add_simple(mbar, "CPU",
FCC('c','p','u','m'),
m_cpu_menu);
}
}