XORLib - игровая либа для старой школы ;)

Использование и разработка софта (преимущественно на ПЦ)

Moderator: Shaos

User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Частота дискретизации вот в этой картинке составляет 14.31818 МГц (тут для простоты опущено поле справа и синхросигнал - видны только "color burst" в начале каждой строки и 640 мнохромных пикселов, в которых NTSC-телек улавливает цветные пикселы с эффективным горизонтальным разрешением 160 пикселов в строке).

Code: Select all

Затравка (9 иголок "color burst") идёт с частотой 3.57954 МГц:
11001100110011001100110011001100110000000000...
Сигнал с частотой 7.15909 МГц должен в идеале показываться серым:
1010101010101010101010...
Белая строка пикселов это последовательность единиц:
11111111111111...
А чёрная строка пикселов это последовательность нулей:
00000000000000...
Для более точной работы наверное надо сделать частоту дискретизации в 2 раза больше - 28.63636 МГц (чтобы точно не упустить никаких мелочей).
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Shaos wrote: Image

Вот пока начал с яркости:
You do not have the required permissions to view the files attached to this post.
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

И ещё одна старая картинка с 6й страницы этого топика:

Image

Image

Image

Пропускаем монохром (самый первый выше) через цифровой фильтр IIR:
cgatrick_xbm025_gray.jpg
Теперь осталось добавить цвет :mrgreen:
You do not have the required permissions to view the files attached to this post.
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Вроде подогнал :)
You do not have the required permissions to view the files attached to this post.
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

А вот все 15 цветов полученные программно (напомню, что не 16 потому, что два серых одинаковые):
cgatrick_colors.jpg
Это очень похоже на композитные цвета в DOSBox сдвинутые на 60 градусов (возможно DOSBox считает по такому же алгоритму, что и я):

----->Image

А вот как было на почившем сониковском телеке:



Получается сейчас уже можно городить порт XORLib на Linux с настоящими композитными цветами :roll:

P.S. Вот только режим 400 строк так просто не сымитировать, хотя наверное можно попробовать...
You do not have the required permissions to view the files attached to this post.
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

А теперь посмотрим как может выглядеть экран ZX-спектрума на программно сымитированной композитной картинке :)
zx1.jpg
На большом телеке напомню было так:

You do not have the required permissions to view the files attached to this post.
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Ну т.е. в-принципе похоже получается:
zx2.jpg

You do not have the required permissions to view the files attached to this post.
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

zx6.jpg

You do not have the required permissions to view the files attached to this post.
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Ну а теперь самое главное - берём программу генерации косых линий:

 colodiag.c

Code: Select all

/* colodiag.c - A.A.Shabarshin (October 2022) */

/* THIS PUBLIC DOMAIN SOURCE CODE IS PROVIDED AS IS */

#include "xorlib.h"

int main()
{

 int i,y;
 unsigned char *p;

 xoinit(XOMODE_160x200_COL15); /* gray colors 5 and 10 are identical */

/*
 0 - Default composite mode colors
 1 - Similar to CGA composite mode colors
 2 - Similar to Tandy composite mode colors
 3 - Similar to PCjr composite mode colors
*/
 xopalette(0);

 for(y=0;y<200;y++)
 {
   p = xodirectline(y);
   if(y<2||y>=198)
   {   /* white frame */
       for(i=0;i<80;i++) p[i] = 0xFF;
       continue;
   }
   p[0] = 0xF0;
   p[79] = 0x0F;

   if(y>=2 && y<14) for(i=1;i<79;i++) p[i]=0x00;
   if(y>=15 && y<26) for(i=1;i<79;i++) p[i]=0x11;
   if(y>=27 && y<38) for(i=1;i<79;i++) p[i]=0x22;
   if(y>=39 && y<50) for(i=1;i<79;i++) p[i]=0x33;
   if(y>=51 && y<62) for(i=1;i<79;i++) p[i]=0x44;
   if(y>=63 && y<74) for(i=1;i<79;i++) p[i]=0x55;
   if(y>=75 && y<86) for(i=1;i<79;i++) p[i]=0x66;
   if(y>=87 && y<98) for(i=1;i<79;i++) p[i]=0x77;
   if(y>=99 && y<110) for(i=1;i<79;i++) p[i]=0x88;
   if(y>=111 && y<122) for(i=1;i<79;i++) p[i]=0x99;
   if(y>=123 && y<134) for(i=1;i<79;i++) p[i]=0xAA;
   if(y>=135 && y<146) for(i=1;i<79;i++) p[i]=0xBB;
   if(y>=147 && y<158) for(i=1;i<79;i++) p[i]=0xCC;
   if(y>=159 && y<170) for(i=1;i<79;i++) p[i]=0xDD;
   if(y>=171 && y<182) for(i=1;i<79;i++) p[i]=0xEE;
   if(y>=183 && y<194) for(i=1;i<79;i++) p[i]=0xFF;

   for(i=y+5;i<y+35;i++) xopixel(i,y,i&1);   
   
   for(i=y+70;i<y+170;i++) xopixel(i,y,0);
   for(i=y+170;i<y+270;i++) xopixel(i,y,i&1);
   for(i=y+270;i<y+370;i++) xopixel(i,y,1);
   
   for(i=y+405;i<y+435;i++) xopixel(i,y,(i&1)?0:1);
 }

 return 0;
}

Как оно было на телеке:

Image

И как выглядит будучи программно сгенерённым на компьютере:
You do not have the required permissions to view the files attached to this post.
User avatar
Lavr
Supreme God
Posts: 16765
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Плата центрального недопроцессора nedoCPU-32

Post by Lavr »

Shaos wrote:Вобщем я вот чего думаю - вместо того чтобы экспериментировать на реальном железе, наблюдая в реальности во что может превратиться та или иная последовательность пикселов... надо написать софт для ПЦ, который будет имитировать "обманувшийся" телек NTSC...
Обычно здесь меня упрекают в чрезмерном пристрастии к эмуляции... :roll:
А тут и ты сам вдруг к этой стезе склонился! :o
А как же "трюЪ железное" видео? :lol:
iLavr
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Ну железяка у меня уже есть :lol:

В данном случае точная имитация композитного экрана нужна исключительно для ускорения процесса разработки :roll:
User avatar
Lavr
Supreme God
Posts: 16765
Joined: 21 Oct 2009 08:08
Location: Россия

Re: Плата центрального недопроцессора nedoCPU-32

Post by Lavr »

Shaos wrote:В данном случае точная имитация композитного экрана нужна исключительно для ускорения процесса разработки :roll:
А, собственно эмуляция, и различные расчеты именно с этой целью и нужны. :wink:
iLavr
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: XORLib - игровая либа для старой школы ;)

Post by Shaos »

Автор картинки откуда я взял вот этот кусочек:
Image
запрещает её использование где либо: https://www.deviantart.com/howling/art/BoxedTown-2-9534561

Поэтому я экспериментирую с этой картинкой только в пределах этого форума - приаттачиваю архив с XBM файлом, используемой для сборки конвертера - XBM соответствует вот этой монохромной картинке:

Image

А исходный текст самого конвертера можно найти под спойлером:

 composite.c

Code: Select all

/* Created by Alexander "Shaos" Shabarshin in January 2023
   and immediately turned into PULIC DOMAIN

   http://xorlib.com

   Build: gcc composite.c -o composite -lpng -lm
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <png.h> /* libpng */

/*
#define COLORBARS
*/

#include "cgatrick_xbm025.xbm"
#define IMGARRAY cgatrick_xbm025_bits

#define OFFSET 96
#define DX 736
#define DY 200

#define FILTERS 3

/*
./mkfilter -Bu -Lp -o 3 -a 0.0469 0.0000000000e+00 -l
*/

#define NZEROS 3
#define NPOLES 3
#define GAIN   4.1115485147e+02

double xv[FILTERS][NZEROS+1], yv[FILTERS][NPOLES+1];

static double filterstep(double v, int i)
{
        xv[i][0] = xv[i][1]; xv[i][1] = xv[i][2]; xv[i][2] = xv[i][3];
        xv[i][3] = v / GAIN;
        yv[i][0] = yv[i][1]; yv[i][1] = yv[i][2]; yv[i][2] = yv[i][3];
        yv[i][3] =   (xv[i][0] + xv[i][3]) + 3 * (xv[i][1] + xv[i][2])
                     + (  5.5347203431e-01 * yv[i][0]) + ( -1.9855726416e+00 * yv[i][1])
                     + (  2.4126432180e+00 * yv[i][2]);
        return yv[i][3];
}

void filtersclean(void)
{
  int i,j;
  for(i=0;i<FILTERS;i++)
  {
     for(j=0;j<=NZEROS;j++)
     {
       xv[i][j] = 0.0;
       yv[i][j] = 0.0;
     }
  }
}

int savepng(char* filename, int width, int height, unsigned char* data)
{
   /* Assume that it's RGB888 image */
   int bitdepth = 8;
   int colortype = PNG_COLOR_TYPE_RGB;
   int transform = PNG_TRANSFORM_IDENTITY;
   int i = 0;
   int r = 0;
   FILE* fp = NULL;
   png_structp png_ptr = NULL;
   png_infop info_ptr = NULL;
   static png_bytep row_pointers[1024];
   if(NULL == data) { r = -1; goto endlabel; }
   if(!filename || !filename[0]) { r = -2; goto endlabel; }
   if(NULL == (fp = fopen(filename, "wb"))) { r = -4; goto endlabel; }
   if(NULL == (png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) { r = -5; goto endlabel; }
   if(NULL == (info_ptr = png_create_info_struct(png_ptr))) { r = -6; goto endlabel; }
   png_set_IHDR(png_ptr, info_ptr, width, height, bitdepth,
                colortype,          /* PNG_COLOR_TYPE_{GRAY, PALETTE, RGB, RGB_ALPHA, GRAY_ALPHA, RGBA, GA} */
                PNG_INTERLACE_NONE, /* PNG_INTERLACE_{NONE, ADAM7 } */
                PNG_COMPRESSION_TYPE_BASE,
                PNG_FILTER_TYPE_BASE);
   for(i = 0; i < height; ++i) row_pointers[i] = data + i*width*3;
   png_init_io(png_ptr, fp);
   png_set_rows(png_ptr, info_ptr, row_pointers);
   png_write_png(png_ptr, info_ptr, transform, NULL);
 endlabel:
   if(NULL != fp)
   {
     fclose(fp);
     fp = NULL;
   }
   if(NULL != png_ptr)
   {
     if(NULL == info_ptr) r = -7;
     png_destroy_write_struct(&png_ptr, &info_ptr);
   }
   return r;
}

double shiftedcos[8],shiftedsin[8];

unsigned char* img;

#define PHASEOFFSET 200

int main(int argc, char** argv)
{
  int x,y,i,j,m,r,g,b,phase=0;
  double d,dy,du,dv;
  unsigned char c,by;
  img = (unsigned char*)malloc(1288*1008*3);
  if(img==NULL) return -1;
  if(argc>1) phase=atoi(argv[1]);
  for(i=0;i<8;i++)
  {
    d = M_PI*(phase+PHASEOFFSET)/180.0;
    shiftedcos[i] = cos(M_PI/4.0*i+d);
    shiftedsin[i] = sin(M_PI/4.0*i+d);
  }
#define CLAMP(x) if(x<0) x=0; if(x>255) x=255
#define GETRGB(r,g,b,y,u,v) r=y+1.13983*v;g=y-0.39465*u-0.58060*v;b=y+2.03211*u
  for(y=0;y<1008;y++)
  {
    if(y<4 || y>=1004)
    {
       memset(&img[y*1288*3],0,1288*3);
       continue;
    }
    filtersclean();
    i = (y-4)/5*DX/8+OFFSET/8;
    for(x=0;x<1280;x+=16)
    {
       by = IMGARRAY[i++];
       m = 1;
       for(j=0;j<8;j++)
       {
#ifndef COLORBARS
          if(by&m)
               d = 0.0;
          else d = 1.0;
#else
          switch(j)
          {
             case 0: case 4: d=((x/80)&8)?1.0:0.0; break;
             case 1: case 5: d=((x/80)&4)?1.0:0.0; break;
             case 2: case 6: d=((x/80)&2)?1.0:0.0; break;
             case 3: case 7: d=((x/80)&1)?1.0:0.0; break;
          }
#endif
          dy = 255*filterstep(d,0);
          dv = 255*filterstep(d*shiftedcos[(x+j+j)&7],1);
          du = 255*filterstep(d*shiftedsin[(x+j+j)&7],2);
          GETRGB(r,g,b,dy,du,dv);
          CLAMP(r);CLAMP(g);CLAMP(b);
          img[(y*1288+x+j*2)*3] = r;
          img[(y*1288+x+j*2)*3+1] = g;
          img[(y*1288+x+j*2)*3+2] = b;
          dy = 255*filterstep(d,0);
          dv = 255*filterstep(d*shiftedcos[(x+j+j+1)&7],1);
          du = 255*filterstep(d*shiftedsin[(x+j+j+1)&7],2);
          GETRGB(r,g,b,dy,du,dv);
          CLAMP(r);CLAMP(g);CLAMP(b);
          img[(y*1288+x+j*2+1)*3] = r;
          img[(y*1288+x+j*2+1)*3+1] = g;
          img[(y*1288+x+j*2+1)*3+2] = b;
          m <<= 1;
       }
    }
    for(j=0;j<8;j++)
    {
       dy = 255*filterstep(0,0);
       dv = 255*filterstep(0,1);
       du = 255*filterstep(0,2);
       GETRGB(r,g,b,dy,du,dv);
       CLAMP(r);CLAMP(g);CLAMP(b);
       img[(y*1288+1280+j)*3] = r;
       img[(y*1288+1280+j)*3+1] = g;
       img[(y*1288+1280+j)*3+2] = b;
    }
  }
  savepng("composite.png",1288,1008,img);
  free(img);
  return 0;
}

Для фильтрации я использую вот такой фильтр низкой частоты, сгенерированный программой mkfilter (точнее 3 таких фильтра):

Code: Select all

#define FILTERS 3

/*
./mkfilter -Bu -Lp -o 3 -a 0.0469 0.0000000000e+00 -l
*/

#define NZEROS 3
#define NPOLES 3
#define GAIN   4.1115485147e+02

double xv[FILTERS][NZEROS+1], yv[FILTERS][NPOLES+1];

static double filterstep(double v, int i)
{
        xv[i][0] = xv[i][1]; xv[i][1] = xv[i][2]; xv[i][2] = xv[i][3];
        xv[i][3] = v / GAIN;
        yv[i][0] = yv[i][1]; yv[i][1] = yv[i][2]; yv[i][2] = yv[i][3];
        yv[i][3] =   (xv[i][0] + xv[i][3]) + 3 * (xv[i][1] + xv[i][2])
                     + (  5.5347203431e-01 * yv[i][0]) + ( -1.9855726416e+00 * yv[i][1])
                     + (  2.4126432180e+00 * yv[i][2]);
        return yv[i][3];
}
Частота среза у этого фильтра составляет 0.0469 от частоты дискретизации, т.е. если вспомнить, что она у нас 28.63636 МГц, то частота среза будет 1.343045284 МГц (пока лучшие результаты именно с таким получаются - при большем значении в цветах появлятся черезпослосица, а при меньшем значении всё размыливается). Входной сигнал пропускается через первый фильтр (фильтр с индексом 0) для получения яркостной составляющей Y. Два других фильтра используются для фильтрации произведения входного сигнала на косинус и синус 3.5795 МГц сдвинутых на 200 градусов (причём из комадной строки можно ввести дополнительный сдвиг в градусах, если нужно) - в результате фильтры отделяют постоянную составляющую (разницу частот) от высокочастотной (суммы частот) выдавая цветоразностные составляющие V и U. Далее по формуле преобразования YUV в RGB для телевиденья стандартного разрешения (r=y+1.13983*v;g=y-0.39465*u-0.58060*v;b=y+2.03211*u) получаем цветовые составляющие R, G и B, искусственно ограничиенные снизу нулём, а сверху 255, которые заносятся в буфер экрана 1288x1008, сохранямый в 24-битном PNG формате в файле composite.png. Чтобы соотношение сторон было близко к 4:3 каждая строчка из входных 200 обрабатывается 5 раз (давая 1000 строк на выходе - возможно надо будет поддержать 16:9 тоже) и кроме того в картинке имеется 4 чёрных строки сверху и 4 чёрных строки снизу (для создания эффекта эдакой чёрной рамки) - всего 1008 строк. Горизонтальное разрешение 1288 обусловлено тем, что филтры дают задержку и первые 4-6 пикселов в каждой строке плавно выводят из черноты в картинку поэтому после обработанных 1280 пикселов (ширина видимого экрана NTSC при частоте дискретизации 28.63636 МГц) я прогоняю фильтры ещё 8 итераций, чтобы остатки изображения "пробежали" свою задержку и "проявились" до конца. Вот полноценный не ужатый вывод этой программы как есть:
composite.png
You do not have the required permissions to view the files attached to this post.
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: XORLib - игровая либа для старой школы ;)

Post by Shaos »

Включив макрос COLORBARS можно заставить программу composite.c, приведённую выше, генерировать цветные полоски с цветами от 0 до 15:
composite-0.jpg
Из комадной строки можно подвигать фазу - например сдвиг 90 градусов:
composite-1.jpg
Сдвиг 180 градусов:
composite-2.jpg
Сдвиг 270 градусов:
composite-3.jpg
Как можно видеть эти цвета соответствуют палитрам Xorya с номерами 0, 1, 2 и 3:
composite-all4.jpg
Image

которые в свою очередь похожи на композитные палитры CGA (1), Tandy (2) и PCjr (3)...
You do not have the required permissions to view the files attached to this post.
User avatar
Shaos
Admin
Posts: 24236
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: XORLib - игровая либа для старой школы ;)

Post by Shaos »

Вспомнил, что забыл залить исходник на гитлаб :oops:

https://gitlab.com/shaos/xorlib/-/blob/master/tools/compositesim.c

(по сравнению с исходником выше добавилось комментов и изменилось название файла, чтобы не конфликтовать с composite из ImageMagick, который есть в любом линух-дистрибутиве)

P.S. Ну и ещё до кучи:
https://gitlab.com/shaos/xorlib/-/blob/master/examples/xbmdraw.c (вывод 200-строчных или 400-строчных XBM-файлов)
https://gitlab.com/shaos/xorlib/-/blob/master/examples/colodiag.c (апдейт диагонального теста двумя тонкими серыми линиями слева и справа)

P.P.S. Вот по диагональному тесту расписал где по краям получается эффективное разрешение 640 точек по ширине (только между чёрной и белой заливкой - отмечено зелёными стрелками), где 320 точек (отмечено жёлтыми стрелками и окружностями), а где остаётся 160 (цветное разрешение во всех остальных местах):
diags-edges.jpg
P.P.P.S. Дальнейшие эксперименты показали, что если гладкость есть при переходе из цвета в черноту (или белоту), то и обратный переход тоже будет "гладкий". Также переключение палитр никак не влияет на места гладкости - т.е. если нужно обеспечить гладкость перехода для какого-то другого цвета, надо просто подобрать нужную палитру, где переход с этого цвета станет "гладким" (хотя есть цвета, которые не будут гладко переходить в чёрное или белое в любой палитре). Теперь ещё надо поэкспериментировать с переходами из цвета в цвет...
You do not have the required permissions to view the files attached to this post.