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

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

Moderator: Shaos

User avatar
Shaos
Admin
Posts: 23989
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 МГц (чтобы точно не упустить никаких мелочей).
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
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.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
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.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
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.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
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.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
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.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
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.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
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.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
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.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Lavr
Supreme God
Posts: 16676
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: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

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

Post by Shaos »

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

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

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

Post by Lavr »

Shaos wrote:В данном случае точная имитация композитного экрана нужна исключительно для ускорения процесса разработки :roll:
А, собственно эмуляция, и различные расчеты именно с этой целью и нужны. :wink:
iLavr
User avatar
Shaos
Admin
Posts: 23989
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.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
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.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
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.
Я тут за главного - если что шлите мыло на me собака shaos точка net