libbgi: gfx_pal_sync + палитра ↔ файл (gfx_pal_fsave/fload); все PASS
- gfx_pal_sync(): палитра страницы 1 := палитре 0 (все 256 записей, чанками по 64 через общий буфер _gfx_pal_buf в W2) — обязательный шаг дабл-буфера (грабли examples/space: без него флип на страницу 1 чёрный). examples/space переведён на хелпер. - gfx_pal_fsave(pal, path): 256 записей × 4 Б (B,G,R,0 — родной формат BIOS $A4) = 1024 Б. - gfx_pal_fload(pal, path): принимает и усечённый файл (64 Б = палитра 16 цветов) — грузит сколько есть, остальные слоты не трогает; возвращает число записей. tests/palfile (MAME dev, все PASS): fsave; fload восстанавливает испорченные слоты (n=256); усечённый файл на 2 записи чинит только их (n=2, слот 2 не тронут); sync чинит испорченный слот палитры 1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,12 +39,13 @@ mdview2 27031
|
|||||||
mem_test 4555
|
mem_test 4555
|
||||||
mouse 4382
|
mouse 4382
|
||||||
openenv 6124
|
openenv 6124
|
||||||
|
palfile 5406
|
||||||
ptime 5744
|
ptime 5744
|
||||||
rt_test 4892
|
rt_test 4892
|
||||||
seek 4188
|
seek 4188
|
||||||
simple 955
|
simple 955
|
||||||
solidt 11531
|
solidt 11531
|
||||||
space 10956
|
space 10976
|
||||||
spranim 8752
|
spranim 8752
|
||||||
spriteclip 4119
|
spriteclip 4119
|
||||||
sprites 6791
|
sprites 6791
|
||||||
|
|||||||
|
@@ -104,13 +104,7 @@ int main(void)
|
|||||||
initgraph();
|
initgraph();
|
||||||
gfx_sprite_clip(0); /* цели в пределах */
|
gfx_sprite_clip(0); /* цели в пределах */
|
||||||
|
|
||||||
/* Палитра страницы 1 = палитре страницы 0 — иначе флип на page 1
|
gfx_pal_sync(); /* обязательный шаг дабл-буфера (см. gfx.h) */
|
||||||
* показывает сцену ЧЁРНОЙ (у каждой страницы своя палитра). */
|
|
||||||
{
|
|
||||||
static uint8_t egapal[16 * 4];
|
|
||||||
gfx_pal_get(0, 0, 16, egapal);
|
|
||||||
gfx_pal_load(1, 0, 16, egapal);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Спрайты: астероиды (LOOP + цель), взрывы (скрыты), маяк (PINGPONG). */
|
/* Спрайты: астероиды (LOOP + цель), взрывы (скрыты), маяк (PINGPONG). */
|
||||||
for (i = 0; i < NAST; i++) {
|
for (i = 0; i < NAST; i++) {
|
||||||
|
|||||||
@@ -155,6 +155,12 @@ void _gfx_w0_isr(void);
|
|||||||
#define _ATL_DIR_OFF 0x68u /* каталог: count × 8 Б (макс 19) */
|
#define _ATL_DIR_OFF 0x68u /* каталог: count × 8 Б (макс 19) */
|
||||||
#define _ATL_DATA_OFF 0x100u /* ленты; = резерв ISR-стаба */
|
#define _ATL_DATA_OFF 0x100u /* ленты; = резерв ISR-стаба */
|
||||||
|
|
||||||
|
/* ---- Палитровые хелперы (common/_gfx_pal_buf.c) ------------------- *
|
||||||
|
* Общий буфер чанковых операций (sync/fload/fsave): 64 записи × 4 Б;
|
||||||
|
* в W2 (BIOS $A4 требует буфер в #4000-#BFFF). */
|
||||||
|
#define _GFX_PAL_CHUNK 64u
|
||||||
|
extern uint8_t _gfx_pal_buf[_GFX_PAL_CHUNK * 4];
|
||||||
|
|
||||||
/* ---- Авто-анимация спрайтов (§9г) --------------------------------- *
|
/* ---- Авто-анимация спрайтов (§9г) --------------------------------- *
|
||||||
* Тикер подключается указателем (DCE: программа без sprite_anim/
|
* Тикер подключается указателем (DCE: программа без sprite_anim/
|
||||||
* sprite_moveto не тянет его код): дефолт NULL (_BSS), ставят
|
* sprite_moveto не тянет его код): дефолт NULL (_BSS), ставят
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* _gfx_pal_buf — общий строковый буфер палитровых хелперов
|
||||||
|
* (gfx_pal_sync / gfx_pal_fload / gfx_pal_fsave): 64 записи × 4 байта.
|
||||||
|
* Статик в W2 — BIOS $A4 требует буфер в #4000-#BFFF. Отдельный
|
||||||
|
* data-модуль: линкуется только с самими хелперами (DCE).
|
||||||
|
*/
|
||||||
|
#include "../_bgi.h"
|
||||||
|
|
||||||
|
uint8_t _gfx_pal_buf[_GFX_PAL_CHUNK * 4];
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* gfx_pal_fload — загрузить палитру pal_num (0..3) из файла формата
|
||||||
|
* gfx_pal_fsave (записи по 4 байта: B, G, R, 0). Файл может быть
|
||||||
|
* УСЕЧЁН: грузится столько полных записей, сколько есть (палитра
|
||||||
|
* 16-цветной картинки — файл 64 байта), остальные слоты не трогаются.
|
||||||
|
* Возврат: число загруженных записей (0..256) или -1 + errno.
|
||||||
|
*
|
||||||
|
* NB: заливает только палитру pal_num — для дабл-буфера после загрузки
|
||||||
|
* в 0 звать gfx_pal_sync().
|
||||||
|
*/
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "../_bgi.h"
|
||||||
|
|
||||||
|
int gfx_pal_fload(uint8_t pal_num, const char *path)
|
||||||
|
{
|
||||||
|
int fd, n, total = 0;
|
||||||
|
uint8_t start = 0;
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while (total < 256) {
|
||||||
|
uint8_t entries;
|
||||||
|
|
||||||
|
n = read(fd, _gfx_pal_buf, _GFX_PAL_CHUNK * 4);
|
||||||
|
if (n < 0) { close(fd); return -1; }
|
||||||
|
entries = (uint8_t)(n / 4);
|
||||||
|
if (!entries)
|
||||||
|
break;
|
||||||
|
gfx_pal_load(pal_num, start, entries, _gfx_pal_buf);
|
||||||
|
start += entries;
|
||||||
|
total += entries;
|
||||||
|
if (n < (int)(_GFX_PAL_CHUNK * 4))
|
||||||
|
break; /* конец файла */
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
return total;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* gfx_pal_fsave — сохранить палитру pal_num (0..3) в файл: 256 записей
|
||||||
|
* по 4 байта (B, G, R, 0 — родной формат BIOS $A4), итого 1024 байта.
|
||||||
|
* Пишется чанками по 64 записи через общий буфер. 0 — OK; -1 + errno.
|
||||||
|
*/
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "../_bgi.h"
|
||||||
|
|
||||||
|
int gfx_pal_fsave(uint8_t pal_num, const char *path)
|
||||||
|
{
|
||||||
|
uint8_t k, start = 0;
|
||||||
|
int fd, rc = 0;
|
||||||
|
|
||||||
|
fd = creat(path, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (k = 0; k < 4; k++) {
|
||||||
|
gfx_pal_get(pal_num, start, _GFX_PAL_CHUNK, _gfx_pal_buf);
|
||||||
|
if (write(fd, _gfx_pal_buf, _GFX_PAL_CHUNK * 4)
|
||||||
|
!= _GFX_PAL_CHUNK * 4) {
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start += _GFX_PAL_CHUNK;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* gfx_pal_sync — палитра страницы 1 := палитре страницы 0 (все 256
|
||||||
|
* записей, чанками по 64 через общий буфер). Обязательный шаг
|
||||||
|
* seamless-дабл-буфера: у каждой графической страницы СВОЯ палитра, и
|
||||||
|
* без синхронизации флип на страницу 1 показывает сцену чёрной
|
||||||
|
* (грабли examples/space 2026-07-13). Звать после initgraph и после
|
||||||
|
* любых правок палитры 0 (gfx_pal_set/load/reset).
|
||||||
|
*/
|
||||||
|
#include "../_bgi.h"
|
||||||
|
|
||||||
|
void gfx_pal_sync(void)
|
||||||
|
{
|
||||||
|
uint8_t k, start = 0;
|
||||||
|
|
||||||
|
for (k = 0; k < 4; k++) {
|
||||||
|
gfx_pal_get(0, start, _GFX_PAL_CHUNK, _gfx_pal_buf);
|
||||||
|
gfx_pal_load(1, start, _GFX_PAL_CHUNK, _gfx_pal_buf);
|
||||||
|
start += _GFX_PAL_CHUNK;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -126,4 +126,17 @@ void gfx_pal_get_color(uint8_t pal_num, uint8_t idx,
|
|||||||
uint8_t *r, uint8_t *g, uint8_t *b);
|
uint8_t *r, uint8_t *g, uint8_t *b);
|
||||||
void gfx_pal_reset(void);
|
void gfx_pal_reset(void);
|
||||||
|
|
||||||
|
/* Палитра страницы 1 := палитре страницы 0 (все 256 записей).
|
||||||
|
* ОБЯЗАТЕЛЬНЫЙ шаг дабл-буфера: без него флип на страницу 1 показывает
|
||||||
|
* сцену чёрной (у каждой страницы своя палитра). Звать после initgraph
|
||||||
|
* и после правок палитры 0. */
|
||||||
|
void gfx_pal_sync(void);
|
||||||
|
|
||||||
|
/* Палитра ↔ файл. Формат: записи по 4 байта (B, G, R, 0 — родной
|
||||||
|
* BIOS $A4), полная палитра = 1024 байта. fload принимает и усечённый
|
||||||
|
* файл (напр. 64 Б = 16 цветов) — остальные слоты не трогает; возврат:
|
||||||
|
* число загруженных записей или -1. fsave пишет все 256; 0 / -1. */
|
||||||
|
int gfx_pal_fsave(uint8_t pal_num, const char *path);
|
||||||
|
int gfx_pal_fload(uint8_t pal_num, const char *path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
PROJ_ROOT := $(abspath $(CURDIR)/../..)
|
||||||
|
EXAMPLE := palfile
|
||||||
|
EXTRA_FLAGS ?= --gfx 256 --memory tiny
|
||||||
|
include $(PROJ_ROOT)/app.mk
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* palfile — тест палитровых хелперов: gfx_pal_sync / gfx_pal_fsave /
|
||||||
|
* gfx_pal_fload. Программные проверки (gfx_pal_get_color), MAME —
|
||||||
|
* только хост.
|
||||||
|
*
|
||||||
|
* P1 fsave: сохранить дефолтную палитру 0 → PAL0.PAL (1024 Б).
|
||||||
|
* P2 fload: испортить слоты 1 и 200 → fload(0) вернул 256 и ОБА
|
||||||
|
* слота восстановились (полный файл).
|
||||||
|
* P3 усечённый файл: записать 2 записи (8 Б) → испортить слоты 0,1,2
|
||||||
|
* → fload вернул 2, слоты 0,1 восстановлены, слот 2 НЕ тронут.
|
||||||
|
* P4 sync: испортить слот 5 палитры 1 → gfx_pal_sync() → слот 5
|
||||||
|
* палитры 1 == слоту 5 палитры 0.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <graphics.h>
|
||||||
|
#include <gfx.h>
|
||||||
|
|
||||||
|
static uint8_t eq(uint8_t p, uint8_t i, uint8_t r, uint8_t g, uint8_t b)
|
||||||
|
{
|
||||||
|
uint8_t rr, gg, bb;
|
||||||
|
|
||||||
|
gfx_pal_get_color(p, i, &rr, &gg, &bb);
|
||||||
|
return rr == r && gg == g && bb == b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get3(uint8_t p, uint8_t i, uint8_t *rgb)
|
||||||
|
{
|
||||||
|
gfx_pal_get_color(p, i, rgb, rgb + 1, rgb + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
uint8_t a[3], c[3], ok;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
puts("PALFILE: pal sync/fsave/fload");
|
||||||
|
initgraph();
|
||||||
|
|
||||||
|
/* ---- P1: сохранить дефолт ---------------------------------------- */
|
||||||
|
ok = (gfx_pal_fsave(0, "pal0.pal") == 0);
|
||||||
|
closegraph();
|
||||||
|
printf("P1 fsave: %s\n", ok ? "PASS" : "FAIL");
|
||||||
|
if (!ok) return 1;
|
||||||
|
|
||||||
|
initgraph();
|
||||||
|
/* ---- P2: полный fload восстанавливает испорченное ----------------- */
|
||||||
|
get3(0, 1, a); /* эталоны */
|
||||||
|
get3(0, 200, c);
|
||||||
|
gfx_pal_set(0, 1, 63, 0, 63); /* испортить */
|
||||||
|
gfx_pal_set(0, 200, 1, 2, 3);
|
||||||
|
n = gfx_pal_fload(0, "pal0.pal");
|
||||||
|
ok = (n == 256) && eq(0, 1, a[0], a[1], a[2])
|
||||||
|
&& eq(0, 200, c[0], c[1], c[2]);
|
||||||
|
closegraph();
|
||||||
|
printf("P2 fload: %s (n=%d)\n", ok ? "PASS" : "FAIL", n);
|
||||||
|
|
||||||
|
initgraph();
|
||||||
|
/* ---- P3: усечённый файл ------------------------------------------- */
|
||||||
|
{
|
||||||
|
int fd = creat("pal2.pal", 0);
|
||||||
|
uint8_t two[8];
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
/* первые 2 записи из pal0.pal */
|
||||||
|
for (i = 0; i < 8; i++) two[i] = 0;
|
||||||
|
{
|
||||||
|
int f0 = open("pal0.pal", O_RDONLY);
|
||||||
|
read(f0, two, 8);
|
||||||
|
close(f0);
|
||||||
|
}
|
||||||
|
write(fd, two, 8);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
get3(0, 0, a);
|
||||||
|
get3(0, 1, c);
|
||||||
|
gfx_pal_set(0, 0, 63, 63, 0);
|
||||||
|
gfx_pal_set(0, 1, 0, 63, 63);
|
||||||
|
gfx_pal_set(0, 2, 7, 7, 7); /* слот 2 портим НАВСЕГДА */
|
||||||
|
n = gfx_pal_fload(0, "pal2.pal");
|
||||||
|
ok = (n == 2) && eq(0, 0, a[0], a[1], a[2])
|
||||||
|
&& eq(0, 1, c[0], c[1], c[2])
|
||||||
|
&& eq(0, 2, 7, 7, 7); /* не тронут fload'ом */
|
||||||
|
closegraph();
|
||||||
|
printf("P3 trunc: %s (n=%d)\n", ok ? "PASS" : "FAIL", n);
|
||||||
|
|
||||||
|
initgraph();
|
||||||
|
/* ---- P4: sync ------------------------------------------------------ */
|
||||||
|
get3(0, 5, a);
|
||||||
|
gfx_pal_set(1, 5, 1, 1, 1); /* испортить у страницы 1 */
|
||||||
|
gfx_pal_sync();
|
||||||
|
ok = eq(1, 5, a[0], a[1], a[2]);
|
||||||
|
closegraph();
|
||||||
|
printf("P4 sync: %s\n", ok ? "PASS" : "FAIL");
|
||||||
|
|
||||||
|
puts("done");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user