Subversion Repositories pentevo

Rev

Rev 1108 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

  1. #include "std.h"
  2.  
  3. #include "emul.h"
  4. #include "vars.h"
  5. #include "draw.h"
  6. #include "drawnomc.h"
  7. #include "dx.h"
  8. #include "dxr_text.h"
  9. #include "dxr_rsm.h"
  10. #include "dxr_advm.h"
  11. #include "memory.h"
  12. #include "config.h"
  13.  
  14. #include "util.h"
  15.  
  16. #ifdef CACHE_ALIGNED
  17. CACHE_ALIGNED unsigned char rbuf[sizeof_rbuf];
  18. #else // __declspec(align) not available, force QWORD align with old method
  19. __int64 rbuf__[sizeof_rbuf/sizeof(__int64)];
  20. unsigned char * const rbuf = (unsigned char*)rbuf__;
  21. #endif
  22.  
  23. unsigned char * const rbuf_s = rbuf + rb2_offs; // frames to mix with noflic and resampler filters
  24. unsigned char * const save_buf = rbuf_s + rb2_offs*MAX_BUFFERS; // used in monitor
  25.  
  26. T t;
  27.  
  28. videopoint *vcurr; // Указатель на текущий элемент из video[]
  29. // Массив видеострок включая бордюр
  30. // video[i] - начало строки (используется только next_t)
  31. // video[i+1] - конец строки  (используются все параметры)
  32. static videopoint video[4*MAX_HEIGHT];
  33. unsigned vmode;  // what are drawing: 0-not visible, 1-border, 2-screen
  34. static unsigned prev_t; // такт на котором был отрисован последний пиксель
  35. unsigned *atrtab;
  36.  
  37. unsigned char colortab[0x100];// map zx attributes to pc attributes
  38. // colortab shifted to 8 and 24
  39. unsigned colortab_s8[0x100];
  40. unsigned colortab_s24[0x100];
  41.  
  42. /*
  43. #include "drawnomc.cpp"
  44. #include "draw_384.cpp"
  45. */
  46.  
  47. PALETTEENTRY pal0[0x100]; // emulator palette
  48.  
  49. void AtmVideoController::PrepareFrameATM2(int VideoMode)
  50. {
  51.     for (int y=0; y<256; y++)
  52.     {
  53.         if ( VideoMode == 6 )
  54.         {
  55.             // смещения в текстовом видеорежиме
  56.             Scanlines[y].Offset = 64*(y/8);
  57.         } else {
  58.             // смещения в растровом видеорежиме
  59.             Scanlines[y].Offset = (y<56) ? 0 : 40*(y-56);
  60.         }
  61.         Scanlines[y].VideoMode = VideoMode;
  62.     }
  63.     CurrentRayLine = 0;
  64.     IncCounter_InRaster = 0;
  65.     IncCounter_InBorder = 0;
  66. }
  67.  
  68. void AtmVideoController::PrepareFrameATM1(int VideoMode)
  69. {
  70.     for (int y=56; y<256; y++)
  71.     {
  72.         Scanlines[y].Offset = 40*(y-56);
  73.         Scanlines[y].VideoMode = VideoMode;
  74.     }
  75. }
  76.  
  77.  
  78. AtmVideoController AtmVideoCtrl;
  79.  
  80. void video_permanent_tables()
  81. {
  82.    // pixel doubling table
  83.    unsigned i; //Alone Coder 0.36.7
  84.    for (/*unsigned*/ i = 0; i < 0x100; i++) {
  85.       unsigned res = 0;
  86.       for (unsigned j = 0x80; j; j/=2) {
  87.          res <<= 2;
  88.          if(i & j)
  89.          {
  90.              res |= 3;
  91.          }
  92.       }
  93.       t.dbl[i] = res;
  94.    }
  95.  
  96.    for (i = 0; i < 0x100; i++) {
  97.       unsigned r1 = 0, r2 = 0;
  98.       if(i & 0x01)
  99.       {
  100.           r1++; r2 += 1;
  101.       }
  102.       if(i & 0x02)
  103.       {
  104.           r1++; r2 += 1;
  105.       }
  106.       if(i & 0x04)
  107.       {
  108.           r1++; r2 += 0x100;
  109.       }
  110.       if(i & 0x08)
  111.       {
  112.           r1++; r2 += 0x100;
  113.       }
  114.       if(i & 0x10)
  115.       {
  116.           r1 += 0x100; r2 += 0x10000;
  117.       }
  118.       if(i & 0x20)
  119.       {
  120.           r1 += 0x100; r2 += 0x10000;
  121.       }
  122.       if(i & 0x40)
  123.       {
  124.           r1 += 0x100; r2 += 0x1000000;
  125.       }
  126.       if(i & 0x80)
  127.       {
  128.           r1 += 0x100; r2 += 0x1000000;
  129.       }
  130.       // low byte of settab - number of pixels in low nibble of i
  131.       // high byte of low word of settab - number of pixels in high nibble of i
  132.       t.settab[i] = r1;
  133.       t.settab2[i] = r2*4; // *4 - convert square 2x2 to 4x4
  134.    }
  135.  
  136.    i = 0; // calc screen addresses
  137.    for(unsigned p = 0; p < 4; p++)
  138.    {
  139.        for(unsigned y = 0; y < 8; y++)
  140.        {
  141.            for(unsigned o = 0; o < 8; o++, i++)
  142.            {
  143.                t.scrtab[i] = p * 0x800 + y * 0x20 + o * 0x100;
  144.                t.atrtab_hwmc[i] = t.scrtab[i] + 0x2000;
  145.                t.atrtab[i] = 0x1800 + (p * 8 + y) * 32;
  146.            }
  147.        }
  148.    }
  149.  
  150.    // alco table
  151.    static unsigned disp_0[] = { 0x0018, 0x2000, 0x2008, 0x2010, 0x2018, 0x0008 };
  152.    static unsigned base_s[] = { 0x10000, 0x14000, 0x14800, 0x15000, 0x11800 };
  153.    static unsigned base_a[] = { 0x11000, 0x15800, 0x15900, 0x15A00, 0x11300 };
  154.    for (unsigned y = 0; y < 304; y++)
  155.       for (unsigned x = 0; x < 6; x++) {
  156.          unsigned disp = disp_0[x] + (y & 0x38)*4;
  157.          ::t.alco[y][x].a = memory + base_a[y/64] + disp;
  158.          ::t.alco[y][x].s = memory + base_s[y/64] + disp + (y & 7)*0x100;
  159.       }
  160.  
  161.    #ifdef MOD_VID_VD
  162.    // this code is only for ygrbYGRB palette
  163.    for (unsigned byte = 0; byte < 0x100; byte++)
  164.       for (int bit = 0; bit < 8; bit++)
  165.          t.vdtab[0][0][byte].m64_u8[7-bit] = (byte & (1 << bit))? 0x11 : 0;
  166.    for (int pl = 1; pl < 4; pl++)
  167.       for (unsigned byte = 0; byte < 0x100; byte++)
  168.          t.vdtab[0][pl][byte] = _mm_slli_pi32(t.vdtab[0][0][byte], pl);
  169.    for (i = 0; i < sizeof t.vdtab[0]; i++)
  170.       ((unsigned char*)t.vdtab[1])[i] = ((unsigned char*)t.vdtab[0])[i] & 0x0F;
  171.    _mm_empty();
  172.    #endif
  173.  
  174.    temp.offset_vscroll_prev = 0;
  175.    temp.offset_vscroll = 0;
  176.    temp.offset_hscroll_prev = 0;
  177.    temp.offset_hscroll = 0;
  178. }
  179.  
  180. static unsigned getYUY2(unsigned r, unsigned g, unsigned b)
  181. {
  182.    int y = (int)(0.29*r + 0.59*g + 0.14*b);
  183.    int u = (int)(128.0 - 0.14*r - 0.29*g + 0.43*b);
  184.    int v = (int)(128.0 + 0.36*r - 0.29*g - 0.07*b);
  185.    if (y < 0) y = 0; if (y > 255) y = 255;
  186.    if (u < 0) u = 0; if (u > 255) u = 255;
  187.    if (v < 0) v = 0; if (v > 255) v = 255;
  188.    return WORD4(y,u,y,v);
  189. }
  190.  
  191. static void create_palette()
  192. {
  193.     if((temp.rflags & RF_8BPCH) && temp.obpp == 8)
  194.     {
  195.         temp.rflags |= RF_GRAY;
  196.         conf.flashcolor = 0;
  197.     }
  198.  
  199.     PALETTE_OPTIONS *pl = &pals[conf.pal];
  200.     //                                Ii          Ii          Ii          Ii
  201.     //                                00          01          10          11
  202.     unsigned char brights[4] = { u8(pl->ZZ), u8(pl->ZN), u8(pl->NN), u8(pl->BB) };
  203.     unsigned char brtab[16] =
  204.     {   //   ZZ          NN          ZZ          BB
  205.         u8(pl->ZZ), u8(pl->ZN), u8(pl->ZZ), u8(pl->ZB), // ZZ
  206.         u8(pl->ZN), u8(pl->NN), u8(pl->ZN), u8(pl->NB), // NN
  207.         u8(pl->ZZ), u8(pl->ZN), u8(pl->ZZ), u8(pl->ZB), // ZZ (bright=1,ink=0)
  208.         u8(pl->ZB), u8(pl->NB), u8(pl->ZB), u8(pl->BB)  // BB
  209.     };
  210.  
  211.     for(unsigned i = 0; i < 0x100u; i++)
  212.     {
  213.         unsigned r0, g0, b0;
  214.         if(temp.rflags & RF_GRAY)
  215.         { // grayscale palette
  216.             r0 = g0 = b0 = i;
  217.         }
  218.         else if(temp.rflags & RF_PALB)
  219.         { // palette index:
  220.             if(comp.ula_plus_en) // gggrrrbb (ULA+)
  221.             { // Линейная интерполяция яркости
  222.                 b0 = ((i & 3) * 255) / 3; // 2 бита
  223.                 r0 = (((i >> 2) & 7) * 255) / 7; // 3 бита
  224.                 g0 = (((i >> 5) & 7) * 255) / 7; // 3 бита
  225.             }
  226.             else // gg0rr0bb (ATM / profi / bilinear filter)
  227.             { // Нелинейная коррекция яркости (на 2 бита) по таблице палитры из .ini файла
  228.                 b0 = brights[i & 3];
  229.                 r0 = brights[(i >> 3) & 3];
  230.                 g0 = brights[(i >> 6) & 3];
  231.             }
  232.         }
  233.         else
  234.         { // palette index: ygrbYGRB (обычный zx режим без палитры)
  235.           // Нелинейная коррекция яркости (на 4 бита) по таблице палитры из .ini файла
  236.             b0 = brtab[((i >> 0) & 1) + ((i >> 2) & 2) + ((i >> 2) & 4) + ((i >> 4) & 8)]; // brtab[ybYB]
  237.             r0 = brtab[((i >> 1) & 1) + ((i >> 2) & 2) + ((i >> 3) & 4) + ((i >> 4) & 8)]; // brtab[yrYR]
  238.             g0 = brtab[((i >> 2) & 1) + ((i >> 2) & 2) + ((i >> 4) & 4) + ((i >> 4) & 8)]; // brtab[ygYG]
  239.         }
  240.  
  241.         // transform with current settings
  242.         unsigned r = 0xFF & ((r0 * pl->r11 + g0 * pl->r12 + b0 * pl->r13) / 0x100);
  243.         unsigned g = 0xFF & ((r0 * pl->r21 + g0 * pl->r22 + b0 * pl->r23) / 0x100);
  244.         unsigned b = 0xFF & ((r0 * pl->r31 + g0 * pl->r32 + b0 * pl->r33) / 0x100);
  245.  
  246.         // prepare palette in bitmap header for GDI renderer
  247.         gdibmp.header.bmiColors[i].rgbRed = pal0[i].peRed = BYTE(r);
  248.         gdibmp.header.bmiColors[i].rgbGreen = pal0[i].peGreen = BYTE(g);
  249.         gdibmp.header.bmiColors[i].rgbBlue = pal0[i].peBlue = BYTE(b);
  250.     }
  251.     memcpy(syspalette + 10, pal0 + 10, (246 - 9) * sizeof *syspalette);
  252.  
  253.     if(conf.mem_model == MM_PROFI)
  254.     {
  255.         // profi palette mapping (port out to palette index)
  256.         for(unsigned i = 0; i < 0x100; i++)
  257.         {
  258.             unsigned dst;
  259.             dst = i; // Gg0Rr0Bb => Gg0Rr0Bb
  260.             t.profi_pal_map[i] = dst;
  261.         }
  262.     }
  263. }
  264.  
  265. void atm_zc_tables();//forward
  266.  
  267. // make colortab: zx-attr -> pc-attr
  268. static void make_colortab(char flash_active)
  269. {
  270.    if (conf.flashcolor || conf.ula_plus)
  271.        flash_active = 0;
  272.  
  273.    for (unsigned a = 0; a < 0x100; a++) // a - zx-attr
  274.    {
  275.       unsigned char ink = a & 7;
  276.       unsigned char paper = (a >> 3) & 7;
  277.       unsigned char bright = (a >> 6) & 1;
  278.       unsigned char flash = (a >> 7) & 1;
  279.  
  280. //      if((conf.flashcolor && ink) || !conf.flashcolor)
  281.       ink |= bright << 3;
  282.  
  283. //      if((conf.flashcolor && paper) || !conf.flashcolor)
  284.           paper |= ((conf.flashcolor || (conf.ula_plus && comp.ula_plus_en)) ? flash : bright) << 3;
  285.  
  286.       if (flash_active && flash)
  287.       {
  288.           unsigned char t = ink;
  289.           ink = paper;
  290.           paper = t;
  291.       }
  292.  
  293.       u8 color = u8((paper << 4) | ink); // color - pc-attr
  294.  
  295.       colortab[a] = color;
  296.       colortab_s8[a] = unsigned(color << 8U);
  297.       colortab_s24[a] = unsigned(color << 24U);
  298.    }
  299.  
  300.    if (conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3 || conf.mem_model == MM_ATM450)
  301.        atm_zc_tables(); // update with new flash bit
  302. }
  303.  
  304. // make attrtab: pc-attr + 0x100*pixel -> palette index
  305. static void attr_tables()
  306. {
  307.    unsigned char flashcolor = (temp.rflags & RF_MON)? 0 : conf.flashcolor;
  308.    for (unsigned a = 0; a < 0x100; a++)
  309.    {
  310.       unsigned char ink = (a & 0x0F), paper = u8(a >> 4);
  311.       if (flashcolor)
  312.           paper = (paper & 7) + (ink & 8); // paper_bright from ink
  313.  
  314.       if (temp.rflags & RF_GRAY)
  315.       { // grayscale palette
  316.          t.attrtab[a] = paper*16;
  317.          t.attrtab[a+0x100] = ink*16;
  318.       }
  319.       else if (temp.rflags & RF_COMPPAL)
  320.       {
  321.           // Палитра в формате ULA+
  322.           u8 paper_idx; // fb1ppp
  323.           u8 ink_idx;   // fb0iii
  324.           if(comp.ula_plus_en)
  325.           {
  326.               u8 flash = (a & 0x80) >> 7;
  327.               u8 bright = (a & 8) >> 3;
  328.               paper &= 7;
  329.               ink &= 7;
  330.               u8 pal_no = u8(((flash << 1) | bright) << 4);
  331.               paper_idx = u8(pal_no | 8 | paper);
  332.               ink_idx   = u8(pal_no | 0 | ink);
  333.           }
  334.           else
  335.           { //------ for ATM / profi palette - direct values from palette registers
  336.               paper = a >> 4;
  337.               ink = a & 0x0F;
  338.               paper_idx = u8(((paper & 8) << 1) | (paper & 7));
  339.               ink_idx = u8(((ink & 8) << 1) | (ink & 7));
  340.           }
  341.           t.attrtab[a] = comp.comp_pal[paper_idx]; // paper
  342.           t.attrtab[a | 0x100] = comp.comp_pal[ink_idx]; // ink
  343.       }
  344.       else if (temp.rflags & RF_PALB)
  345.       { //----------------------------- for bilinear
  346.          unsigned char b0,b1, r0,r1, g0,g1;
  347.          b0 = (paper >> 0) & 1; r0 = (paper >> 1) & 1; g0 = (paper >> 2) & 1;
  348.          b1 = (ink >> 0) & 1; r1 = (ink >> 1) & 1; g1 = (ink >> 2) & 1;
  349.  
  350.          if (flashcolor && (a & 0x80))
  351.          {
  352.              b1 += b0; r1 += r0; g1 += g0;
  353.              r0 = b0 = g0 = 0;
  354.          }
  355.          else
  356.          {
  357.              b0 *= 2; r0 *= 2; g0 *= 2;
  358.              b1 *= 2; r1 *= 2; g1 *= 2;
  359.          }
  360.  
  361.          unsigned char br1 = (ink >> 3) & 1;
  362.          if (r1) r1 += br1;
  363.          if (g1) g1 += br1;
  364.          if (b1) b1 += br1;
  365.  
  366.          unsigned char br0 = (paper >> 3) & 1;
  367.          if (r0) r0 += br0;
  368.          if (g0) g0 += br0;
  369.          if (b0) b0 += br0;
  370.  
  371.          // palette index: gg0rr0bb
  372.          t.attrtab[a+0x100]  = u8((g1 << 6) + (r1 << 3) + b1);
  373.          t.attrtab[a]        = u8((g0 << 6) + (r0 << 3) + b0);
  374.       }
  375.       else //------------------------------------ all others
  376.       {
  377.          // palette index: ygrbYGRB
  378.          if (flashcolor && (a & 0x80))
  379.          {
  380.              t.attrtab[a] = 0;
  381.              t.attrtab[a+0x100] = u8(ink+(paper<<4));
  382.          }
  383.          else
  384.          {
  385.              t.attrtab[a] = paper * 0x11; // p[3..0]:p[3..0] (удвоение)
  386.              t.attrtab[a+0x100] = ink * 0x11; // i[3..0]:i[3..0] (удвоение)
  387.          }
  388.       }
  389.    }
  390. }
  391.  
  392. static void p4bpp_tables()
  393. {
  394.    for (unsigned pass = 0; pass < 2; pass++) {
  395.       for (unsigned bt = 0; bt < 0x100; bt++) {
  396.          unsigned lf = ((bt >> 3) & 7) + ((bt >> 4) & 8);
  397.          unsigned rt = (bt & 7) + ((bt >> 3) & 8);
  398.          if (temp.obpp == 8) {
  399.             t.p4bpp8[pass][bt] = (t.sctab8[pass][0x0F+0x10*rt] & 0xFFFF) +
  400.                                    (t.sctab8[pass][0x0F+0x10*lf] & 0xFFFF0000);
  401.          } else if (temp.obpp == 16) {
  402.              t.p4bpp16[pass][bt * 2 + 0] = t.sctab16[pass][0x03 + 4 * rt];
  403.              t.p4bpp16[pass][bt * 2 + 1] = t.sctab16[pass][0x03 + 4 * lf];
  404.          } else /* if (temp.obpp == 32) */ {
  405.              t.p4bpp32[pass][bt * 2 + 0] = t.sctab32[pass][0x100 + rt];
  406.              t.p4bpp32[pass][bt * 2 + 1] = t.sctab32[pass][0x100 + lf];
  407.          }
  408.       }
  409.    }
  410. }
  411.  
  412. void atm_zc_tables() // atm,profi screens (use normal zx-flash)
  413. {
  414.    for (unsigned pass = 0; pass < 2; pass++) {
  415.       for (unsigned at = 0; at < 0x100; at++) {
  416.          unsigned pc_attr = colortab[at];
  417.          if(temp.obpp == 8)
  418.          {
  419.              for(unsigned j = 0; j < 4; j++)
  420.              {
  421.                  t.zctab8ad[pass][at * 4 + j] = t.sctab8d[pass][pc_attr * 4 + j];
  422.              }
  423.          }
  424.          else if(temp.obpp == 16)
  425.          {
  426.              t.zctab16ad[pass][at] = t.sctab16d[pass][pc_attr];
  427.              t.zctab16ad[pass][at + 0x100] = t.sctab16d[pass][pc_attr + 0x100];
  428.          }
  429.          else /* if (temp.obpp == 32) */
  430.          {
  431.              t.zctab32ad[pass][at] = t.sctab32[pass][pc_attr];
  432.              t.zctab32ad[pass][at + 0x100] = t.sctab32[pass][pc_attr + 0x100];
  433.          }
  434.       }
  435.    }
  436.  
  437.    // atm palette mapping (port out to palette index)
  438.    for (unsigned i = 0; i < 0x100; i++) {
  439.       unsigned v = i ^ 0xFF, dst;
  440.       if (conf.mem_model == MM_ATM450)
  441.          dst = // ATM1: --grbGRB => Gg0Rr0Bb
  442.                ((v & 0x20) << 1) | // g
  443.                ((v & 0x10) >> 1) | // r
  444.                ((v & 0x08) >> 3) | // b
  445.                ((v & 0x04) << 5) | // G
  446.                ((v & 0x02) << 3) | // R
  447.                ((v & 0x01) << 1);  // B
  448.       else
  449.          dst = // ATM2: grbG--RB => Gg0Rr0Bb
  450.                ((v & 0x80) >> 1) | // g
  451.                ((v & 0x40) >> 3) | // r
  452.                ((v & 0x20) >> 5) | // b
  453.                ((v & 0x10) << 3) | // G
  454.                ((v & 0x02) << 3) | // R
  455.                ((v & 0x01) << 1);  // B
  456.       t.atm_pal_map[i] = dst;
  457.    }
  458. }
  459.  
  460. static void hires_sc_tables()  // atm,profi screens (use zx-attributes & flash -> paper_bright)
  461. {
  462.    for (unsigned pass = 0; pass < 2; pass++) {
  463.       for (unsigned at = 0; at < 0x100; at++) {
  464.          unsigned pc_attr = (at & 0x80) + (at & 0x38)*2 + (at & 0x40)/8 + (at & 7);
  465.          if (temp.obpp == 8)
  466.             for (unsigned j = 0; j < 16; j++)
  467.                t.zctab8[pass][at*0x10+j] = t.sctab8[pass][pc_attr*0x10+j];
  468.          else if (temp.obpp == 16)
  469.             for (unsigned j = 0; j < 4; j++)
  470.                t.zctab16[pass][at*4+j] = t.sctab16[pass][pc_attr*4+j];
  471.          else /* if (temp.obpp == 32) */
  472.             for (unsigned j = 0; j < 2; j++)
  473.                t.zctab32[pass][at+0x100*j] = t.sctab32[pass][pc_attr+0x100*j];
  474.       }
  475.    }
  476. }
  477.  
  478. static void calc_noflic_16_32()
  479. {
  480.    unsigned at, pass;
  481.    if (temp.obpp == 16) {
  482.       for (pass = 0; pass < 2; pass++) {
  483.          for (at = 0; at < 2*0x100; at++)
  484.             t.sctab16d_nf[pass][at] = (t.sctab16d[pass][at] & temp.shift_mask)/2;
  485.          for (at = 0; at < 4*0x100; at++)
  486.             t.sctab16_nf[pass][at] = (t.sctab16[pass][at] & temp.shift_mask)/2;
  487.          for (at = 0; at < 2*0x100; at++)
  488.             t.p4bpp16_nf[pass][at] = (t.p4bpp16[pass][at] & temp.shift_mask)/2;
  489.       }
  490.    }
  491.    if (temp.obpp == 32) {
  492.       unsigned shift_mask = 0xFEFEFEFE;
  493.       for (pass = 0; pass < 2; pass++) {
  494.          for (at = 0; at < 2*0x100; at++)
  495.             t.sctab32_nf[pass][at] = (t.sctab32[pass][at] & shift_mask)/2;
  496.          for (at = 0; at < 2*0x100; at++)
  497.             t.p4bpp32_nf[pass][at] = (t.p4bpp32[pass][at] & shift_mask)/2;
  498.       }
  499.    }
  500. }
  501.  
  502. // pal.index => raw video data, shadowed with current scanline pass
  503. static unsigned raw_data(unsigned index, unsigned pass, unsigned bpp)
  504. {
  505.    if (bpp == 8)
  506.    {
  507.       if (pass)
  508.       {
  509.          if (!conf.scanbright)
  510.              return 0;
  511.          // palette too small to realize noflic/atari with shaded scanlines
  512.          if (conf.scanbright < 100 && !conf.noflic && !conf.atariset[0])
  513.          {
  514.             if (temp.rflags & RF_PALB)
  515.                 index = (index & (index << 1) & 0x92) | ((index ^ 0xFF) & (index >> 1) & 0x49);
  516.             else
  517.                 index &= 0x0F;
  518.          }
  519.       }
  520.       return index * 0x01010101; // 4 точки (8bit)
  521.    }
  522.  
  523.    unsigned r = pal0[index].peRed, g = pal0[index].peGreen, b = pal0[index].peBlue;
  524.    if (pass)
  525.    {
  526.        r = r * conf.scanbright / 100;
  527.        g = g * conf.scanbright / 100;
  528.        b = b * conf.scanbright / 100;
  529.    }
  530.  
  531.    if (bpp == 32)
  532.        return WORD4(b,g,r,0); // 1 точка (32bit)
  533.  
  534.    // else (bpp == 16)
  535.    if (temp.hi15==0)
  536.        return ((b/8) + ((g/4)<<5) + ((r/8)<<11)) * 0x10001; // 2 точки (16bit)
  537.    if (temp.hi15==1)
  538.        return ((b/8) + ((g/8)<<5) + ((r/8)<<10)) * 0x10001; // 2 точки (16bit)
  539.    if (temp.hi15==2)
  540.        return getYUY2(r,g,b); // yuyv (32bit)
  541.    return 0;
  542. }
  543.  
  544. static unsigned atari_to_raw(unsigned at, unsigned pass)
  545. {
  546.    unsigned c1 = at/0x10, c2 = at & 0x0F;
  547.    unsigned raw0 = raw_data(t.attrtab[c1+0x100], pass, temp.obpp);
  548.    unsigned raw1 = raw_data(t.attrtab[c2+0x100], pass, temp.obpp);
  549.    if (raw0 == raw1) return raw1;
  550.  
  551.    if (temp.obpp == 8)
  552.       return (temp.rflags & RF_PALB)? (0x49494949 & ((raw0&raw1)^((raw0^raw1)>>1))) |
  553.                                       (0x92929292 & ((raw0&raw1)|((raw0|raw1)&((raw0&raw1)<<1))))
  554.                                     : (0x0F0F0F0F & raw0) | (0xF0F0F0F0 & raw1);
  555.  
  556.    return (raw0 & temp.shift_mask)/2 + (raw1 & temp.shift_mask)/2;
  557. }
  558.  
  559. void pixel_tables()
  560. {
  561.     attr_tables();
  562.     for(unsigned pass = 0; pass < 2; pass++)
  563.     {
  564.         for(unsigned at = 0; at < 0x100; at++)
  565.         {
  566.             unsigned px0 = t.attrtab[at]; // Точка выключена (индекс палитры эмулятора, палитра 8[idx]->32[xrgb])
  567.             unsigned px1 = t.attrtab[at + 0x100]; // Точка включена (индекс палитры эмулятора, палитра 8[idx]->32[xrgb])
  568.  
  569.             // 4 точки (одинаковых, учетверение) для 8bpp
  570.             // 2 точки (одинаковых, удвоение) для 16bpp
  571.             // 1 точка для 32bpp
  572.             unsigned p0 = raw_data(px0, pass, temp.obpp); // Точка выключена (данные для pc видеопамяти)
  573.             unsigned p1 = raw_data(px1, pass, temp.obpp); // Точка включена (данные для pc видеопамяти)
  574.  
  575.             // sctab32 required for frame resampler in 16-bit mode, so temp.obpp=16 here
  576.             // Входные данные 1 бит
  577.             t.sctab32[pass][at] = raw_data(px0, pass, 32); // Точка выключена (данные для pc видеопамяти xrgb)
  578.             t.sctab32[pass][at + 0x100] = raw_data(px1, pass, 32); // Точка включена (данные для pc видеопамяти xrgb)
  579.  
  580.             // 8 bit
  581.             unsigned j;
  582.             for(j = 0; j < 0x10; j++) // j - Входные данные (значение ч/б пикселей) 4бита (16 комбинаций)
  583.             {
  584.                 unsigned mask = (j >> 3) * 0xFF + (j & 0x04)*(0xFF00 / 4) +
  585.                     (j & 0x02)*(0xFF0000 / 2) + (j & 1) * 0xFF000000;
  586.                 t.sctab8[pass][j + at * 0x10] = (mask & p1) + (~mask & p0); // Данные для pc видеопамяти 4 точки
  587.             }
  588.             for(j = 0; j < 4; j++) // j - Входные данные (значение ч/б пикселей) 2бита (4 комбинации)
  589.             {
  590.                 unsigned mask = (j >> 1) * 0xFFFF + (j & 1) * 0xFFFF0000;
  591.                 t.sctab8d[pass][j + at * 4] = (mask & p1) + (~mask & p0); // Данные для pc видеопамяти 2 точки с удвоением
  592.             }
  593.             // Входные данные (значение ч/б пикселей) 1бит (2 комбинации)
  594.             t.sctab8q[at] = p0; t.sctab8q[at + 0x100] = p1; // Данные для pc видеопамяти 1 точка с учетверением
  595.  
  596.             // 16 bit
  597.             for(j = 0; j < 4; j++) // j - Входные данные (значение ч/б пикселей) 2бита (4 комбинации)
  598.             {
  599.                 unsigned mask = (j >> 1) * 0xFFFF + (j & 1) * 0xFFFF0000;
  600.                 t.sctab16[pass][j + at * 4] = (mask & p1) + (~mask & p0); // Данные для pc видеопамяти 2 точки
  601.             }
  602.             // Входные данные (значение ч/б пикселей) 1бит (2 комбинации)
  603.             t.sctab16d[pass][at] = p0; t.sctab16d[pass][at + 0x100] = p1; // Данные для pc видеопамяти 1 точка с удвоением
  604.  
  605.             unsigned atarimode;
  606.             if(!(temp.rflags & RF_MON) && (atarimode = temp.ataricolors[at]))
  607.             {
  608.                 unsigned rawdata[4], i;
  609.                 for(i = 0; i < 4; i++)
  610.                 {
  611.                     rawdata[i] = atari_to_raw((atarimode >> (8 * i)) & 0xFF, pass);
  612.                 }
  613.                 for(i = 0; i < 16; i++)
  614.                 {
  615.                     t.sctab8[pass][at * 0x10 + i] = rawdata[i / 4] + 16 * rawdata[i & 3];
  616.                 }
  617.                 for(i = 0; i < 4; i++)
  618.                 {
  619.                     t.sctab8d[pass][at * 4 + i] = rawdata[i];
  620.                 }
  621.                 for(i = 0; i < 4; i++)
  622.                 {
  623.                     t.sctab16[pass][at * 4 + i] = rawdata[i];
  624.                 }
  625.             }
  626.         }
  627.     }
  628.  
  629.     p4bpp_tables(); // used for ATM2+ mode0 and Pentagon-4bpp
  630.  
  631.     if(temp.obpp > 8 && conf.noflic)
  632.     {
  633.         calc_noflic_16_32();
  634.     }
  635.  
  636.     if((temp.rflags & (RF_DRIVER | RF_2X | RF_USEFONT)) == (RF_DRIVER | RF_2X) && // render="double"
  637.         (conf.mem_model == MM_ATM450 || conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3 || conf.mem_model == MM_PROFI))
  638.     {
  639.         hires_sc_tables();
  640.     }
  641.    
  642. if ((conf.mem_model == MM_ATM3) && ((comp.pBF&0x20) != 0) && (temp.obpp == 32)) { //added by Alone Coder 04.12.2021 (no ULAplus!!! no default palette!!! ATM3 only!!!):
  643.    PALETTE_OPTIONS *pl = &pals[conf.pal];
  644.    //colorindex = comp.border_attr;
  645.  for (u8 colorindex = 0; colorindex < 16; colorindex++) {
  646.    unsigned r0, g0, b0;
  647.    u16 atm3color = comp.atm3_pal[colorindex];
  648.    r0 = (((atm3color>>1)<<3)&8) + (((atm3color>>6)<<2)&4) + (((atm3color>>9)<<1)&2) + ((atm3color>>14)&1);
  649.    g0 = (((atm3color>>4)<<3)&8) + (((atm3color>>7)<<2)&4) +(((atm3color>>12)<<1)&2) + ((atm3color>>15)&1);
  650.    b0 = (((atm3color>>0)<<3)&8) + (((atm3color>>5)<<2)&4) + (((atm3color>>8)<<1)&2) + ((atm3color>>13)&1);
  651.    r0 = (r0^15) * 17; //0..255
  652.    g0 = (g0^15) * 17; //0..255
  653.    b0 = (b0^15) * 17; //0..255
  654.    unsigned r = 0xFF & ((r0 * pl->r11 + g0 * pl->r12 + b0 * pl->r13) / 0x100); //pl->r11 etc. = 0..0x100
  655.    unsigned g = 0xFF & ((r0 * pl->r21 + g0 * pl->r22 + b0 * pl->r23) / 0x100);
  656.    unsigned b = 0xFF & ((r0 * pl->r31 + g0 * pl->r32 + b0 * pl->r33) / 0x100);
  657.         // prepare palette in bitmap header for GDI renderer
  658. /*   gdibmp.header.bmiColors[colorindex].rgbRed = pal0[colorindex].peRed = BYTE(r);
  659.    gdibmp.header.bmiColors[colorindex].rgbGreen = pal0[colorindex].peGreen = BYTE(g);
  660.    gdibmp.header.bmiColors[colorindex].rgbBlue = pal0[colorindex].peBlue = BYTE(b);
  661.    setpal(0);*/
  662.    u32 rgb = (r<<16) + (g<<8) + b;
  663. //pixels in EGA are shown in order "ink","paper" (%PIpppiii) with this code (src[] is ZX Spectrum memory):
  664. //        d[x+0]  = d[x+1]  = tab[0+2*src[ega0_ofs + src_offset]]; //"ink" pixel
  665. //        d[x+2]  = d[x+3]  = tab[1+2*src[ega0_ofs + src_offset]]; //"paper" pixel
  666.    //unsigned *tab = t.p4bpp32[0] (even lines) or [1] (odd lines);
  667.    u8 inkindex = (colorindex&7) + ((colorindex&8)<<3);
  668.    for (u8 paper = 0; paper < 16; paper++) {
  669.         u8 paperindex = ((paper&7)<<3) + ((paper&8)<<4);
  670.         t.p4bpp32[0][0+2*(inkindex+paperindex)] = rgb; //"ink" pixel (even lines)
  671.         t.p4bpp32[1][0+2*(inkindex+paperindex)] = rgb; //"ink" pixel (odd lines)
  672.    }
  673.    u8 paperindex = ((colorindex&7)<<3) + ((colorindex&8)<<4);
  674.    for (u8 ink = 0; ink < 16; ink++) {
  675.         u8 inkindex = (ink&7) + ((ink&8)<<3);
  676.         t.p4bpp32[0][1+2*(inkindex+paperindex)] = rgb; //"paper" pixel (even lines)
  677.         t.p4bpp32[1][1+2*(inkindex+paperindex)] = rgb; //"paper" pixel (odd lines)
  678.    }
  679.  }
  680. }
  681. }
  682.  
  683. void video_color_tables()
  684. {
  685.    temp.shift_mask = 0xFEFEFEFE; // 32bit, 16bit YUY2
  686.    if (temp.obpp == 16 && temp.hi15==0) temp.shift_mask = 0xF7DEF7DE;
  687.    if (temp.obpp == 16 && temp.hi15==1) temp.shift_mask = 0x7BDE7BDE;
  688.  
  689.    create_palette();
  690.    pixel_tables();
  691.    make_colortab(0);
  692.  
  693.    if (temp.rflags & (RF_USEC32 | RF_USE32AS16)) {
  694.       for (unsigned at = 0; at < 0x100; at++) {
  695.          for (unsigned vl = 0; vl <= 0x10; vl++) {
  696.             unsigned br = (at & 0x40) ? 0xFF : 0xBF;
  697.             unsigned c1, c2, res;
  698.             c1 = (at & 1) >> 0; c2 = (at & 0x08) >> 3;
  699.             unsigned b = (c1*vl + c2*(0x10-vl))*br/0x10;
  700.             c1 = (at & 2) >> 1; c2 = (at & 0x10) >> 4;
  701.             unsigned r = (c1*vl + c2*(0x10-vl))*br/0x10;
  702.             c1 = (at & 4) >> 2; c2 = (at & 0x20) >> 5;
  703.             unsigned g = (c1*vl + c2*(0x10-vl))*br/0x10;
  704.             if (temp.rflags & RF_USE32AS16) {
  705.                if (temp.hi15==0) res = (b/8) + ((g/4)<<5) + ((r/8)<<11);
  706.                if (temp.hi15==1) res = (b/8) + ((g/8)<<5) + ((r/8)<<10);
  707.                if (temp.hi15==2) res = getYUY2(r,g,b);
  708.                else res *= 0x10001; // for hi15=0,1
  709.             } else res =  WORD4(b,g,r,0);
  710.             t.c32tab[at][vl] = res;
  711.          }
  712.       }
  713.    }
  714.    setpal(0);
  715. }
  716.  
  717. void video_timing_tables()
  718. {
  719.    if (conf.frame < 2000)
  720.    {
  721.        conf.frame = 2000;
  722.        cpu.SetTpi(conf.frame);
  723.    }
  724.    if (conf.t_line < 128) conf.t_line = 128;
  725.    conf.nopaper &= 1;
  726.    atrtab = (comp.pEFF7 & EFF7_HWMC) ? t.atrtab_hwmc : t.atrtab;
  727.  
  728. //   conf.bordersize=2;
  729. //   temp.scx = 384, temp.scy = 300;
  730.    #define p2cc(p) ((p)/4) // Перевод величины в пикселях в число знакомест с учетом атрибутов (каждое знакоместо занимает 2 байта, байт данных и байт атрибутов)
  731.    const unsigned width = p2cc(temp.scx); // Ширина экрана в знакоместах * 2 (т.к. используются пиксели и атрибуты на 1 знакоместо)
  732.    //temp.vidbufsize = temp.scx*temp.scy/4;
  733.  
  734.    // make video table
  735.    unsigned mid_lines = 192; // Число строк в центральной части экрана (без бордюра)
  736.    const unsigned buf_mid = 256; // Число пикселей в центральной части экрана (без бордюра)
  737.  
  738.    // Расчет размер бордюра в пикселях (1 пиксель = 2 такта)
  739.    temp.b_bottom = temp.b_top = conf.b_top_small; temp.b_left = conf.b_left_small; // border small
  740.    if (conf.bordersize==0) temp.b_top = temp.b_left = 0; // border none
  741.    if (conf.bordersize==2) { temp.b_top = conf.b_top_full; temp.b_left = conf.b_left_full; } // border full
  742.  
  743.    // temp.scx - число точек в мультиколоре по горизонтали
  744.    // temp.scy - число строк в мультиколоре
  745.    // 256x192 - border none
  746.    // 320x240 - border small
  747.    // 384x300 - border full, pentagon: ((36+128+28)*2=384)x(304=64+192+48), scorpion: ((24+128+32)*2=368)x(296=64+192+40)))
  748.    temp.b_right = temp.scx - buf_mid - temp.b_left; // Расчет размера правой части бордюра в пикселях (1 пиксель = 1/2 такта)
  749.    temp.b_bottom = temp.scy - mid_lines - temp.b_top; // Расчет размера нижней части бордюра в пикселях (1 пиксель = 1/2 такта)
  750.  
  751.    if(conf.nopaper) // Режим nopaper (растр в середине экрана отсутствует)
  752.    {
  753.        temp.b_bottom += mid_lines;
  754.        mid_lines = 0;
  755.    }
  756.    int inx = 0;
  757.  
  758.    unsigned i;
  759.    #define ts(t) (((int)(t) < 0) ? 0 : t)
  760.    #define p2t(p) ((p)/2) // Перевод пикселей в такты
  761.    // conf.paper - Число тактов от начала растра до центральной части spectrum экрана
  762.    // (включает невидимую часть + полностью верхний бордюр + начало строки шириной hblank + левый бордюр)
  763.    // Для pentagon 128: (16+64)*(32+36+128+28)+32+36 = 17988 тактов
  764.    // 16 строк над верхним бордюром
  765.    // 64 строки - верхний бордюр
  766.    // каждая строка 224 такта:
  767.    // 32 такта hblank
  768.    // 36 тактов - левый бордюр
  769.    // 128 тактов - центр экрана
  770.    // 28 тактов - правый бордюр
  771.    unsigned t = conf.paper - temp.b_top*conf.t_line; // Число тактов до начала верхнего бордюра (включая hblank + левый бордюр в первой строке paper)
  772.    const unsigned hblank = conf.t_line - p2t(temp.scx); // Число тактов в hblank
  773.    video[inx++].next_t = ts(t - p2t(temp.b_left)); // Исключение левого бордюра (next_t - такт начала первой строки верхнего бордюра)
  774. //   printf("btop: temp.b_top=%u, conf.b_top_full=%u\n", temp.b_top, conf.b_top_full);
  775.    for (i = 0; i < temp.b_top; i++)
  776.    { // верхний бордюр
  777.       video[inx].next_t = ts(t + p2t(buf_mid+temp.b_right)); // Конец правого бордюра (такт конца текущей строки)
  778.       video[inx].screen_ptr = rbuf+width*i; // Указатель на на чало текущей строки в буфере отрисовки
  779.       video[inx].nextvmode = 0; // hblank (переход к новой строке)
  780. //      printf("%3u: b=%u, e=%u, o=%u\n", i, video[inx-1].next_t, video[inx].next_t, width*i);
  781.  
  782.        // Переход к следующей строке (t - такт начала paper следующей строки hblank + левый бордюр)
  783.       inx++; t += conf.t_line;
  784.       video[inx++].next_t = ts(t - p2t(temp.b_left)); // Исключение левого бордюра (такт начала левого бордюра на следующей строке)
  785.    }
  786. //   printf("paper:\n");
  787.    for (i = 0; i < mid_lines; i++)
  788.    { // hblank + левый бордюр + экран + правый бордюр
  789.       video[inx].next_t = ts(t); // Конец левого бордюра (такт начала paper на текущей строке)
  790.       video[inx].screen_ptr = rbuf+width*(i+temp.b_top); // Указатель на начало iй строки левого бордюра в буфере отрисовки
  791.       video[inx].nextvmode = 2; // Далее прорисовывается paper
  792. //      printf("%3u: b=%u ", i, video[inx-1].next_t);
  793.  
  794.       inx++;
  795.       video[inx].next_t = ts(t + p2t(buf_mid)); // Конец paper (такт начала правого бордюра на текущей строке)
  796.       video[inx].screen_ptr = rbuf+width*(i+temp.b_top)+p2cc(temp.b_left);// Указатель на начало iй строки paper в буфере отрисовки
  797.       video[inx].scr_offs = ::t.scrtab[i]; // Смещение от начала zx экрана (пиксели)
  798.       video[inx].atr_offs = atrtab[i]; // Смещение от начала зоны атрибутов zx экрана
  799.  
  800.       inx++;
  801.       video[inx].next_t = ts(t + p2t(buf_mid+temp.b_right));  // Конец правого бордюра (такт конца текущей строки)
  802.       video[inx].screen_ptr = rbuf+width*(i+temp.b_top)+p2cc(buf_mid+temp.b_left); // Указатель на начало iй строки правого бордюра в буфере отрисовки
  803.       video[inx].nextvmode = 0; // hblank (переход к новой строке)
  804.  
  805. //      printf("e=%u\n", video[inx].next_t);
  806.        // Переход к следующей строке (t - такт начала paper следующей строки hblank + левый бордюр)
  807.       inx++; t += conf.t_line;
  808.       video[inx++].next_t = ts(t - p2t(temp.b_left)); // Исключение левого бордюра (такт начала следующей строки)
  809.    }
  810. //   printf("bbot:\n");
  811.    for (i = 0; i < temp.b_bottom; i++)
  812.    { // нижний бордюр
  813.       video[inx].next_t = ts(t + p2t(buf_mid+temp.b_right)); // Конец правого бордюра (такт конца текущей строки)
  814.       video[inx].screen_ptr = rbuf+width*(i+temp.b_top+mid_lines); // Указатель на на чало iй строки нижнего бордюра в буфере отрисовки
  815.       video[inx].nextvmode = 0; // hblank (переход к новой строке)
  816. //      printf("%3u: b=%u, e=%u\n", i, video[inx-1].next_t, video[inx].next_t);
  817.  
  818.        // Переход к следующей строке (t - такт начала paper следующей строки hblank + левый бордюр)
  819.       inx++; t += conf.t_line;
  820.       video[inx++].next_t = ts(t - p2t(temp.b_left)); // Исключение левого бордюра (такт начала следующей строки)
  821.    }
  822.    video[inx-1].next_t = 0x7FFFFFFF; // Признак последней строки
  823. //   exit(0);
  824.  
  825.    temp.evenM1_C0 = conf.even_M1 ? 0xC0 : 0x00;
  826.    temp.border_add = conf.border_4T ? 6 : 0;
  827.    temp.border_and = conf.border_4T ? 0xFFFFFFFC : 0xFFFFFFFF;
  828.  
  829.    for (i = 0; i < NUM_LEDS; i++)
  830.    {
  831.       unsigned z = *(&conf.led.ay + i);
  832.       int x = (signed short)(z & 0xFFFF);
  833.       int y = (signed short)(((z >> 16) & 0x7FFF) + ((z >> 15) & 0x8000));
  834.       if (x < 0) x += width*8;
  835.       if (y < 0) y += temp.scy;
  836.       *(&temp.led.ay+i) = (z & 0x80000000) ? rbuf + ((x>>2)&0xFE) + unsigned(y)*width : nullptr;
  837.    }
  838.  
  839.    if (temp.rflags & RF_USEFONT)
  840.        create_font_tables();
  841.  
  842.    needclr = 2;
  843. }
  844.  
  845. void set_video()
  846. {
  847. //   printf("%s\n", __FUNCTION__);
  848.    set_vidmode();
  849.    video_color_tables();
  850. }
  851.  
  852. void apply_video()
  853. {
  854. //   printf("%s\n", __FUNCTION__);
  855.    load_ula_preset();
  856.  
  857.    if(conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3 || conf.mem_model == MM_ATM450 || conf.mem_model == MM_PROFI)
  858.    {
  859.        conf.render = 1; // Для моделей с экраном 640x200 поддерживается только redner = double (640x480)
  860.    }
  861.  
  862.    temp.rflags = renders[conf.render].flags;
  863.    if (conf.use_comp_pal && (conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3 || conf.mem_model == MM_ATM450 || conf.mem_model == MM_PROFI))
  864.    {
  865.       temp.rflags |= RF_COMPPAL | RF_PALB;
  866.       // disable palette noflic, only if it is really used
  867.       if (temp.obpp == 8 && (temp.rflags & (RF_DRIVER | RF_USEFONT | RF_8BPCH)) == RF_DRIVER)
  868.       conf.noflic = 0;
  869.    }
  870.  
  871.    if(conf.ula_plus/* && comp.ula_plus_en*/)
  872.    {
  873.        temp.rflags |= RF_COMPPAL | RF_PALB;
  874.    }
  875.  
  876.    if (renders[conf.render].func == render_rsm)
  877.        conf.flip = 1; // todo: revert back after returning from frame resampler //Alone Coder
  878.  
  879.    if (renders[conf.render].func == render_advmame)
  880.    {
  881.       if (conf.videoscale == 2)
  882.           temp.rflags |= RF_2X;
  883.       if (conf.videoscale == 3)
  884.           temp.rflags |= RF_3X;
  885.       if (conf.videoscale == 4)
  886.           temp.rflags |= RF_4X;
  887.    } //Alone Coder
  888.  
  889.    set_video();
  890.    calc_rsm_tables();
  891.    video_timing_tables();
  892. }
  893.  
  894. __inline unsigned char *raypointer()
  895. {
  896.    if (prev_t > conf.frame)
  897.        return rbuf + rb2_offs;
  898.    if (!vmode)
  899.        return vcurr[1].screen_ptr;
  900.    unsigned offs = (prev_t - vcurr[-1].next_t) / 4;
  901.    return vcurr->screen_ptr + (offs+1) * 2;
  902. }
  903.  
  904. __inline void clear_until_ray()
  905. {
  906.    unsigned char *dst = raypointer();
  907.    while(dst < rbuf + rb2_offs)
  908.    {
  909.        *dst++ = 0;
  910.        *dst++ = 0x55;
  911.    }
  912. }
  913.  
  914. void paint_scr(char alt) // alt=0/1 - main/alt screen, alt=2 - ray-painted
  915. {
  916.     if(alt == 2)
  917.     {
  918.         update_screen();
  919.         clear_until_ray();
  920.     }
  921.     else
  922.     {
  923.         if(alt)
  924.         {
  925.             comp.p7FFD ^= 8;
  926.             set_banks();
  927.         }
  928.         draw_screen();
  929.         if(alt)
  930.         {
  931.             comp.p7FFD ^= 8;
  932.             set_banks();
  933.         }
  934.     }
  935. }
  936.  
  937. // Вызывается при записи в видеопамять/(порты FE/7FFD) нового значения
  938. // Производит отрисовку бордюра/экрана в промежуточный буфер с использованием pc атрибутов
  939. void update_screen()
  940. {
  941.    unsigned last_t = (cpu.t + temp.border_add) & temp.border_and;
  942.    unsigned t = prev_t; // Выполняется отрисовка от последнего отрисованного такта prev_t до текущего округленного такта last_t
  943. //   printf("upd_scr: t=%u, lt=%u, vm=%u\n", t, last_t, vmode);
  944.    if (t >= last_t) // Невидимая часть строки (hblank либо невидимые строки верхнего бордюра)
  945.        return;
  946.  
  947.    unsigned char b = comp.border_attr;
  948.    b |= (b<<4); // Атрибуты бордюра дублируются в формате pc атрибутов ink=paper
  949.  
  950.    if(vmode == 1)
  951.    {
  952.        goto mode1; // border
  953.    }
  954.  
  955.    if(vmode == 2) // screen
  956.    {
  957.        goto mode2;
  958.    }
  959.  
  960. mode0: // not visible
  961.    {
  962.       vmode = 1;
  963.       t = vcurr->next_t; // Такт начала строки
  964.       vcurr++; // Переход к концу строки
  965.       if (t >= last_t)
  966.       {
  967. done:
  968.           prev_t = t; // Последний отрисованный такт
  969.           return;
  970.       }
  971.    }
  972. mode1: // border
  973.    {
  974.       unsigned offs = (t - vcurr[-1].next_t); // Смещение в тактах от начала строки (1 такт = 2 пикселя)
  975.       unsigned char *ptr = vcurr->screen_ptr + offs/2; // Указатель на адрес точки в промежуточном буфере (структура буфера 8pix:attr)
  976. //      u8 *pp =ptr;
  977.       ptr = (unsigned char*)(ULONG_PTR(ptr) & ~ULONG_PTR(1)); // Выравание до четного адреса
  978.       if(offs & 3)
  979.       { // Смена цвета бордюра произошла не по границе знакоместа (два цвета бордюра внутри одного знакоместа, эмулируются через ink/paper)
  980.           u8 old_b = (ptr[1] & 0x0F);
  981.           if(old_b ^ (b & 0xF)) // Цвет бордюра изменился по сравнению с предыдущим
  982.           {
  983.               u8 mask = u8((unsigned)0xFF00 >> ((offs & 3) * 2)); // Маска пикселей (для 1 - используется цвет ink, для 0 - paper)
  984.               *ptr = mask;
  985.               ptr++;
  986.               t += 4 - (offs & 3);
  987.               *ptr = old_b | (b & 0xF0); // Атрибуты (ink - старый цвет бордюра, paper - текущий цвет бордюра)
  988.               ptr++;
  989.           }
  990.       }
  991.       unsigned end = min(vcurr->next_t, last_t);
  992. //      printf("upd_scr_m1: o=%uT, p=%u, t=%uT, end=%uT\n", offs, pp - rbuf, t, end);
  993.       for (; t < end; t+=4) // Обработка пикселей по знакоместам (по 8 точек)
  994.       {
  995.          *ptr++ = 0; // Пиксели не используются
  996.          *ptr++ = b; // Атрибуты
  997.       }
  998.       t = end;
  999.       if (t == vcurr->next_t)
  1000.       { // Строка закончилась,  переход к следующей точке
  1001.           vmode = vcurr->nextvmode;
  1002.           vcurr++;
  1003.       }
  1004.       if (t == last_t) // Отрисовка закончена, выход
  1005.           goto done;
  1006.  
  1007.       if (!vmode) // Начало следующей строки
  1008.           goto mode0;
  1009.    }
  1010. mode2: // screen
  1011.    {
  1012.       unsigned offs = (t - vcurr[-1].next_t)/4; // Смещение в знакоместах от начала строки (1 знакоместо = 4 такта = 8 пикселей)
  1013.       unsigned char *scr = temp.base + vcurr->scr_offs + offs; // spectrum пиксели
  1014.       unsigned char *atr = temp.base + vcurr->atr_offs + offs; // spectrum атрибуты
  1015.       unsigned char *ptr = vcurr->screen_ptr + offs*2; // Структура буфера 8pix:attr
  1016.       unsigned end = min(last_t, vcurr->next_t);
  1017.       for (int i = 0; t < end; t += 4, i++)
  1018.       {
  1019.          ptr[2*i] = scr[i]; // Копирование spectrum пикселей
  1020.          ptr[2*i+1] = colortab[atr[i]]; // Конвертирование spectrum атрибутов в pc атрибуты
  1021.       }
  1022.       t = end;
  1023.       if (t == vcurr->next_t)
  1024.       { // Центральная часть экрана закончилась, отрисовка правого бордюра
  1025.           vmode = 1; // border
  1026.           vcurr++;
  1027.       }
  1028.       if (t == last_t) // Отрисовка закончена, выход
  1029.           goto done;
  1030.       goto mode1; // Отрисовка правого бордюра
  1031.    }
  1032. }
  1033.  
  1034. void init_frame()
  1035. {
  1036.    // recreate colors with flash attribute
  1037.    unsigned char frame = (unsigned char)comp.frame_counter;
  1038.    if (!(frame & 15) /* && !conf.flashcolor */ )
  1039.        make_colortab(frame & 16);
  1040.  
  1041.    prev_t = -1U; // block MCR
  1042.    temp.base_2 = nullptr; // block paper trace
  1043.  
  1044.    if (temp.vidblock)
  1045.        return;
  1046.  
  1047. /* [vv] Отключен, т.к. этот бит используется для DDp scroll
  1048.    // AlCo384 - no border/paper rendering
  1049.    if (comp.pEFF7 & EFF7_384)
  1050.        return;
  1051. */
  1052.    // GIGASCREEN - no paper rendering
  1053. //   if (comp.pEFF7 & EFF7_GIGASCREEN) goto allow_border; //Alone Coder
  1054.  
  1055.    // disable multicolors, border still works
  1056.    if ((temp.rflags & RF_BORDER) || // chunk/etc filter
  1057.        (conf.mem_model == MM_PROFI && (comp.pDFFD & 0x80)) ||   // profi hires screen
  1058.        ((conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3)&& (comp.pFF77 & 7) != 3) ||  // ATM-2 hires screen
  1059.        (conf.mem_model == MM_ATM450 && (comp.aFE & 0x60) != 0x60)) // ATM-1 hires screen
  1060.    {
  1061.        if ((conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3))
  1062.        {
  1063.            // ATM2, один из расширенных видеорежимов
  1064.            AtmVideoCtrl.PrepareFrameATM2(comp.pFF77 & 7);
  1065.        }
  1066.  
  1067.        if (conf.mem_model == MM_ATM450)
  1068.        {
  1069.            // ATM1, один из расширенных видеорежимов
  1070.            AtmVideoCtrl.PrepareFrameATM1( (comp.aFE >> 5) & 3 );
  1071.  
  1072.        }
  1073.        
  1074.       // if border update disabled, dont show anything on zx-screen
  1075.       if (!conf.updateb)
  1076.           return;
  1077.    }
  1078.  
  1079.    // paper + border
  1080.    temp.base_2 = temp.base;
  1081. //allow_border:
  1082.    prev_t = vmode = 0;
  1083.    vcurr = video;
  1084. }
  1085.  
  1086. void flush_frame()
  1087. {
  1088.    if (temp.vidblock)
  1089.        return;
  1090.    if (prev_t != -1U)
  1091.    { // MCR on
  1092.       if (prev_t)
  1093.       {  // paint until end of frame
  1094.          // paint until screen bottom, even if n_lines*t_line < cpu.t (=t_frame)
  1095.          unsigned t = cpu.t;
  1096.          cpu.t = 0x7FFF0000;
  1097.          update_screen();
  1098.          cpu.t = t;
  1099. //         if (comp.pEFF7 & EFF7_GIGASCREEN) draw_gigascreen_no_border(); //Alone Coder
  1100.       }
  1101.       else
  1102.       { // MCR on, but no screen updates in last frame - use fast painter
  1103.          if (temp.base_2 /*|| (comp.pEFF7 & EFF7_GIGASCREEN)*/ /*Alone Coder*/)
  1104.              draw_screen();
  1105.          else
  1106.              draw_border();
  1107.       }
  1108.       return;
  1109.    }
  1110.    if (comp.pEFF7 & EFF7_384)
  1111.        draw_alco();
  1112. }
  1113.  
  1114. // spectrum colors -> palette indexes (RF_PALB - gggrrrbb format)
  1115. static const u8 comp_pal[16] =
  1116. {
  1117.     // normal bright  g   r   b   g  r  b
  1118.     0x00, // black   000|000|00  00|00|00
  1119.     0x02, // blue    000|000|10  00|00|10
  1120.     0x10, // red     000|100|00  00|10|00
  1121.     0x12, // magenta 000|100|10  00|10|10
  1122.     0x80, // green   100|000|00  10|00|00
  1123.     0x82, // cyan    100|000|10  10|00|10
  1124.     0x90, // yellow  100|100|00  10|10|00
  1125.     0x92, // white   100|100|10  10|10|10
  1126.  
  1127.     // high bright    g   r   b   g  r  b
  1128.     0x00, // black   000|000|00  00|00|00
  1129.     0x03, // blue    000|000|11  00|00|11
  1130.     0x1C, // red     000|111|00  00|11|00
  1131.     0x1F, // magenta 000|111|11  00|11|11
  1132.     0xE0, // green   111|000|00  11|00|00
  1133.     0xE3, // cyan    111|000|11  11|00|11
  1134.     0xFC, // yellow  111|111|00  11|11|00
  1135.     0xFF  // white   111|111|11  11|11|11
  1136. };
  1137.  
  1138. void load_spec_colors()
  1139. {
  1140.     for(unsigned flash = 0; flash < 2; flash++)
  1141.     {
  1142.         for(unsigned bright = 0; bright < 2; bright++)
  1143.         {
  1144.             unsigned PalNo = ((flash << 1) | bright) << 4;
  1145.             memcpy(comp.comp_pal + (PalNo | (0 << 3)), comp_pal + (bright << 3), sizeof(comp_pal) / 2); // ink
  1146.             memcpy(comp.comp_pal + (PalNo | (1 << 3)), comp_pal + (bright << 3), sizeof(comp_pal) / 2); // paper
  1147.         }
  1148.     }
  1149.     temp.comp_pal_changed = 1;
  1150. }
  1151.