Передаю в общественное достояние графическую программу просмотра спектрумовской графики в форматах 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 <me@shaos.net> 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
Сохранение текущего графического режима с видеостраницей:
Установка графического режима 320x256 256 цветов:Код:inregs.h.c = 0x51; intdos(&inregs,&outregs); oldmode = (outregs.x.bc & 0xFF00) | outregs.h.a; printf("Old mode %04X\n",oldmode);
Сохранение страницы памяти в последнем окне и установка туда графической страницы #50:Код:inregs.h.c = 0x50; inregs.h.b = 0; inregs.h.a = 0x81; intdos(&inregs,&outregs);
Хитрая 256-цветная палитра создаётся процедурно и записывается в видеопамять по смещению 992 (палитра №0) в функции setpal():Код:oldpage = inp(WINDOW3); outp(WINDOW3,0x50);
Хитрость заключается в том, что взяв 2 спектрумовских 4-битных цвета c1 и c2 можно легко получить их смешение (причём с учётом гаммы sRGB) как цвет в этой 256-цветной палитре по индексу (c1<<4)|c2Код: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)]; } }
Далее засылаем координату 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 (верхняя картинка):
![]()
![]()
IMG-файлы взяты по следующим ссылкам:
https://zxart.ee/rus/avtory/t/tutty/...-arthur-fleck/
https://zxart.ee/rus/avtory/t/tmk/save-the-animals/
https://zxart.ee/rus/avtory/r/riskej...anding-single/
- - - Добавлено - - -
P.S. Если кто-то придерживается мнения, что гигаскрин обязан мерцать, а у смотрящего из глаз должна сочиться кровь, лучше сюда ничего не писать
P.P.S. Отдаю исходник в PUBLIC DOMAIN соответственно публика может делать с ним что захочет, а я в бижайшем будущем хочу добавить просмотр мультиколорных картинок и SXG (поэтому желательно релизить под другим названием и версионностью, если кто-то что-то поменяет в нём)






Ответить с цитированием
Размещение рекламы на форуме способствует его дальнейшему развитию 
