PDA

Просмотр полной версии : Сишный исходник просмотрщика спектрумовской графики для Спринтера



Shaos
22.05.2021, 08:13
Передаю в общественное достояние графическую программу просмотра спектрумовской графики в форматах SCR (6912 и 6144 байта), ATR (768 байт) и IMG (Gigascreen 13824 байта), написанную мной в марте-апреле прямо на Спринтере Sp2000 для компиляции в SOLiD-C - вот батник для сборки:


set PROG=zxview
set PREFIX=C:\SOLID\EXAMPLES
REM SolidC EXE files must be in PATH
cls 2
del %PROG%.exe
cc1 -m %PREFIX%\%PROG%
cc2 %PREFIX%\%PROG%
as %PREFIX%\%PROG%
REM LD filename length is limited to 12 characters!
%PREFIX%\ld /R6DF0 /P6E00 %PROG%,clib/l/gXMAIN /x
REM %PREFIX%\ld %PROG%,clib/l/gXMAIN /x
REM del %PROG%.tmc
REM del %PROG%.rel
REM del %PROG%.asm


Исходник программы:


/* ZXVIEW.C - Alexander "Shaos" Shabarshin <[email protected]>

25-MAR-2021 - initial version for Solid-C that shows SCR and IMG
26-MAR-2021 - v1.0 optimized and linked from 0x7000 to avoid screen snowing
27-MAR-2021 - v1.1 implemented gamma correction as per sRGB (gamma=2.2)
23-APR-2021 - v1.2 implemented incomplete palette filling and B/W SCR
25-APR-2021 - v1.3 fixed incomplete palette and also ATR support
09-MAY-2021 - v1.4 rolled back pallette function update

This code is PUBLIC DOMAIN - use it on your own RISK! */

#include <malloc.h>
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <mem.h>

#define SCRSIZE 6912
#define ATRSIZE 768
#define BWSCRSZ 6144

union REGS inregs,outregs;
int oldmode,oldpage;
char *scr;
FILE *f;

#define WINDOW3 0xE2 /* Port for memory page 0xC000...0xFFFF */
#define PORT_Y 0x89 /* Port to set Y for videomemory */

/*

Color number Binary value BRIGHT 0 (RGB) BRIGHT 1 (RGB) Color name
---------------------------------------------------------------------------
0 000 #000000 #000000 black
1 001 #0000CD #0000FF blue
2 010 #CD0000 #FF0000 red
3 011 #CD00CD #FF00FF magenta
4 100 #00CD00 #00FF00 green
5 101 #00CDCD #00FFFF cyan
6 110 #CDCD00 #FFFF00 yellow
7 111 #CDCDCD #FFFFFF white
*/

setpal()
{
/* sRGB scale (gamma=2.2): 0% ---- 20% 40% 60% 80% 100% */
static char scale[] = { 0x00, 0x0E, 0x7C, 0xAA, 0xCB, 0xE7, 0xFF };
static char *po = (char*)(0xC000+992); /* address to apply palette */
static int i,c1,c2;
for(i=0;i<256;i++)
{
outp(PORT_Y,(char)i);
/* palette_index = (first_color<<4)|second_color */
c1 = (i&0x80)?3:2;
c2 = (i&0x08)?3:2;
po[2] = scale[((i&0x10)?c1:0)+((i&0x01)?c2:0)];
po[0] = scale[((i&0x20)?c1:0)+((i&0x02)?c2:0)];
po[1] = scale[((i&0x40)?c1:0)+((i&0x04)?c2:0)];
}
}

int getsize()
{
static f_point *fp;
fseek(f,0,0,SEEK_END);
fp = ftell(f);
fseek(f,0,0,SEEK_SET);
return fp->low;
}

int fread1(buf,sz,f)
char* buf;
int sz;
FILE *f;
{
static int i,o,r;
r = 0;
for(i=0;i<sz;i++)
{
o = fgetc(f);
if(o < 0) break;
buf[i] = o;
r++;
}
return r;
}

main(argc,argv)
int argc;
char** argv;
{
int sz;
static char c1,c2,*po;
static int i,j,k,l,l1,l2;
static int atr1,atr2,pla1,pla2;

printf("ZXVIEW v1.4 - viewer for SCR, ATR and IMG (Gigascreen) graphics\n");
printf("This code is PUBLIC DOMAIN - use it on your own RISK!\n");
printf("Created by Shaos in March-April 2021 for SOLiD-C examples\n");
printf("http://sprinter.nedopc.org\n");
if(argc<2)
{
printf("\nUsage: zxview path-to-file\n\n");
exit(-1);
}

scr = (char*)malloc(SCRSIZE*2);
if(scr==NULL) exit(-2);
printf("Screen buffer 0x%X...0x%X\n",scr,scr+SCRSIZE*2-1);
l = (int)(&inregs);
printf("Data start: 0x%X\n",l);

f = fopen(argv[1],"rb");
if(f==NULL) exit(-3);
sz = getsize();
j = -1;
i = fread1(scr,sz,f);
if(sz==ATRSIZE)
{
memcpy(&scr[BWSCRSZ],scr,ATRSIZE);
memcpy(&scr[BWSCRSZ+SCRSIZE],scr,ATRSIZE);
for(l=0;l<12;l++)
{
l1 = l<<9;
l2 = l1 + 256;
memset(&scr[l1],0x55,256);
memset(&scr[l2],0xAA,256);
memset(&scr[l1+SCRSIZE],0x55,256);
memset(&scr[l2+SCRSIZE],0xAA,256);
}
}
else if(sz<=SCRSIZE)
{
fseek(f,0,0,SEEK_SET);
j = fread1(&scr[SCRSIZE],sz,f);
}
fclose(f);
printf("File %s (%d) - read %d %d\n",argv[1],sz,i,j);

if(i==BWSCRSZ) /* B/W SCR */
{
for(j=BWSCRSZ;j<SCRSIZE;j++)
{
scr[j] = 0x07;
scr[j+SCRSIZE] = 0x07;
}
}

inregs.h.c = 0x51;
intdos(&inregs,&outregs);
oldmode = (outregs.x.bc & 0xFF00) | outregs.h.a;
printf("Old mode %04X\n",oldmode);

inregs.h.c = 0x50;
inregs.h.b = 0;
inregs.h.a = 0x81;
intdos(&inregs,&outregs);

oldpage = inp(WINDOW3);
outp(WINDOW3,0x50);

setpal();

for(j=0;j<192;j++)
{
// if(kbhit()) break;
po = (char*)0xC020; /* it's not a constant - it's incremented below! */
outp(PORT_Y,(char)(j+32));
l1 = SCRSIZE-768+((j&0xF8)<<2);
l2 = ((j&0xC0)<<5)+((j&0x07)<<8)+((j&0x38)<<2);
for(i=0;i<32;i++)
{
l = l1 + i;
atr1 = scr[l];
atr2 = scr[l+SCRSIZE];
l = l2 + i;
pla1 = scr[l];
pla2 = scr[l+SCRSIZE];
l = 0x80;
for(k=0;k<8;k++)
{
if(pla1 & l)
c1 = atr1&7;
else
c1 = (atr1>>3)&7;
if(pla2 & l)
c2 = atr2&7;
else
c2 = (atr2>>3)&7;
if(atr1 & 0x40) c1 += 8;
if(atr2 & 0x40) c2 += 8;
if(c1 >= c2)
*po++ = (c1<<4)|c2;
else
*po++ = (c2<<4)|c1;
l >>= 1;
}
}
}

getch();

free(scr);

outp(WINDOW3,oldpage);

inregs.x.bc = oldmode;
inregs.h.a = oldmode & 255;
inregs.h.c = 0x50;
intdos(&inregs,&outregs);

}


- - - Добавлено - - -

Кое какие пояснения по коду - в данный момент fread на солиде глючит, поэтому я написал свою заглушку int fread1(buf,sz,f) работающую через fgetc

Сохранение текущего графического режима с видеостраницей:


inregs.h.c = 0x51;
intdos(&inregs,&outregs);
oldmode = (outregs.x.bc & 0xFF00) | outregs.h.a;
printf("Old mode %04X\n",oldmode);


Установка графического режима 320x256 256 цветов:


inregs.h.c = 0x50;
inregs.h.b = 0;
inregs.h.a = 0x81;
intdos(&inregs,&outregs);


Сохранение страницы памяти в последнем окне и установка туда графической страницы #50:


oldpage = inp(WINDOW3);
outp(WINDOW3,0x50);


Хитрая 256-цветная палитра создаётся процедурно и записывается в видеопамять по смещению 992 (палитра №0) в функции setpal():



setpal()
{
/* sRGB scale (gamma=2.2): 0% ---- 20% 40% 60% 80% 100% */
static char scale[] = { 0x00, 0x0E, 0x7C, 0xAA, 0xCB, 0xE7, 0xFF };
static char *po = (char*)(0xC000+992); /* address to apply palette */
static int i,c1,c2;
for(i=0;i<256;i++)
{
outp(PORT_Y,(char)i);
/* palette_index = (first_color<<4)|second_color */
c1 = (i&0x80)?3:2;
c2 = (i&0x08)?3:2;
po[2] = scale[((i&0x10)?c1:0)+((i&0x01)?c2:0)];
po[0] = scale[((i&0x20)?c1:0)+((i&0x02)?c2:0)];
po[1] = scale[((i&0x40)?c1:0)+((i&0x04)?c2:0)];
}
}


Хитрость заключается в том, что взяв 2 спектрумовских 4-битных цвета c1 и c2 можно легко получить их смешение (причём с учётом гаммы sRGB) как цвет в этой 256-цветной палитре по индексу (c1<<4)|c2

Далее засылаем координату Y в порт #89 outp(PORT_Y,y) и пишем нужный цвет по смещению 0xC000+x (используя координату X для отступа от начала последнего окна памяти) - всё просто :)

- - - Добавлено - - -

Ну и в конце код возврата старой страницы памяти в последнее окно и возвращение старого графического режима со старой видеостраницей:


outp(WINDOW3,oldpage);

inregs.x.bc = oldmode;
inregs.h.a = oldmode & 255;
inregs.h.c = 0x50;
intdos(&inregs,&outregs);


- - - Добавлено - - -

Для сравнения вот как просмотрщик показывает гигаскриновскую картинку в эмуляторе (нижняя картинка) рядом с картинкой из ZXArt.ee (верхняя картинка):

https://zx-pk.ru/attachment.php?attachmentid=75446 https://zx-pk.ru/attachment.php?attachmentid=75447 https://zx-pk.ru/attachment.php?attachmentid=75448

IMG-файлы взяты по следующим ссылкам:
https://zxart.ee/rus/avtory/t/tutty/farewell-mister-arthur-fleck/
https://zxart.ee/rus/avtory/t/tmk/save-the-animals/
https://zxart.ee/rus/avtory/r/riskej/shepherds-outstanding-single/

- - - Добавлено - - -

P.S. Если кто-то придерживается мнения, что гигаскрин обязан мерцать, а у смотрящего из глаз должна сочиться кровь, лучше сюда ничего не писать :)

P.P.S. Отдаю исходник в PUBLIC DOMAIN соответственно публика может делать с ним что захочет, а я в бижайшем будущем хочу добавить просмотр мультиколорных картинок и SXG (поэтому желательно релизить под другим названием и версионностью, если кто-то что-то поменяет в нём)

Shaos
31.07.2021, 07:33
Вот универсальный батник SC.BAT для сборки простых сишных программ, состоящих из одного C-файла - он собирает EXE со стартовой точкой 4300h (это ок для текстовых программ, но для графических надо область переменных сдвигать за 8000h чтобы на экране небыло мусора - выше показано как это можно делать):


set PROG=%1
set PREFIX=C:\SOLID\EXAMPLES
REM SolidC EXE files must be in PATH on disk C!
cls 2
del %PROG%.exe
cc1 -m %PREFIX%\%PROG%
cc2 %PREFIX%\%PROG%
as %PREFIX%\%PROG%
REM LD filename length is limited to 12 characters!
%PREFIX%\ld %PROG%,clib/l/gXMAIN /x
del %PROG%.tmc
del %PROG%.rel
del %PROG%.asm

Это батник SC.BAT, а также файлы LD.EXE и CLIB.IRL должны лежать в каталоге с исходником (т.к. LD пока не умеет работать с путями), а все остальные EXE-шники должны быть доступны через PATH, который задаётся в SYSTEM.BAT - ниже пример моего стартового BAT-файла:


@echo off
set PATH=%BOOTDSK%\;%BOOTDSK%\FN\;%BOOTDSK%\BIN\;%BOOT DSK%\ZX\;%BOOTDSK%\SOLID\
ver
@echo on
fn


Пример простого исходника HELLO.C (он уже упоминался в соседнем топике (https://zx-pk.ru/threads/33340-rabota-s-obychnoj-sprinterovskoj-grafikoj-(i-hello-world).html)):


#include <stdio.h>

main()
{
printf("\nHello world !\n");
fprintf(stdout,"Привет мир !\n");
}


Который собирается путём запуска команды SC.BAT HELLO

P.S. Для совсем простого случая в батнике можно захардкодить имя файла set PROG=HELLO, чтобы можно было просто по Enter в FN его пускать (или мышью)