Subversion Repositories pentevo

Rev

Rev 716 | Blame | Last modification | View Log | Download | RSS feed

  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. videopoint video[4*MAX_HEIGHT];
  33. unsigned vmode;  // what are drawing: 0-not visible, 1-border, 2-screen
  34. 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 (int j = 0x80; j; j/=2) {
  87.          res <<= 2; if (i & j) res |= 3;
  88.       }
  89.       t.dbl[i] = res;
  90.    }
  91.  
  92.    for (i = 0; i < 0x100; i++) {
  93.       unsigned r1 = 0, r2 = 0;
  94.       if (i & 0x01) r1++,        r2 += 1;
  95.       if (i & 0x02) r1++,        r2 += 1;
  96.       if (i & 0x04) r1++,        r2 += 0x100;
  97.       if (i & 0x08) r1++,        r2 += 0x100;
  98.       if (i & 0x10) r1 += 0x100, r2 += 0x10000;
  99.       if (i & 0x20) r1 += 0x100, r2 += 0x10000;
  100.       if (i & 0x40) r1 += 0x100, r2 += 0x1000000;
  101.       if (i & 0x80) r1 += 0x100, r2 += 0x1000000;
  102.       // low byte of settab - number of pixels in low nibble of i
  103.       // high byte of low word of settab - number of pixels in high nibble of i
  104.       t.settab[i] = r1;
  105.       t.settab2[i] = r2*4; // *4 - convert square 2x2 to 4x4
  106.    }
  107.  
  108.    i = 0; // calc screen addresses
  109.    for (int p = 0; p < 4; p++)
  110.       for (int y = 0; y < 8; y++)
  111.          for (int o = 0; o < 8; o++, i++)
  112.             t.scrtab[i] = p*0x800 + y*0x20 + o*0x100,
  113.             t.atrtab_hwmc[i] = t.scrtab[i] + 0x2000,
  114.             t.atrtab[i] = 0x1800 + (p*8+y)*32;
  115.  
  116.    // alco table
  117.    static unsigned disp_0[] = { 0x0018, 0x2000, 0x2008, 0x2010, 0x2018, 0x0008 };
  118.    static unsigned base_s[] = { 0x10000, 0x14000, 0x14800, 0x15000, 0x11800 };
  119.    static unsigned base_a[] = { 0x11000, 0x15800, 0x15900, 0x15A00, 0x11300 };
  120.    for (unsigned y = 0; y < 304; y++)
  121.       for (unsigned x = 0; x < 6; x++) {
  122.          unsigned disp = disp_0[x] + (y & 0x38)*4;
  123.          ::t.alco[y][x].a = memory + base_a[y/64] + disp;
  124.          ::t.alco[y][x].s = memory + base_s[y/64] + disp + (y & 7)*0x100;
  125.       }
  126.  
  127.    #ifdef MOD_VID_VD
  128.    // this code is only for ygrbYGRB palette
  129.    for (unsigned byte = 0; byte < 0x100; byte++)
  130.       for (int bit = 0; bit < 8; bit++)
  131.          t.vdtab[0][0][byte].m64_u8[7-bit] = (byte & (1 << bit))? 0x11 : 0;
  132.    for (int pl = 1; pl < 4; pl++)
  133.       for (unsigned byte = 0; byte < 0x100; byte++)
  134.          t.vdtab[0][pl][byte] = _mm_slli_pi32(t.vdtab[0][0][byte], pl);
  135.    for (i = 0; i < sizeof t.vdtab[0]; i++)
  136.       ((unsigned char*)t.vdtab[1])[i] = ((unsigned char*)t.vdtab[0])[i] & 0x0F;
  137.    _mm_empty();
  138.    #endif
  139.  
  140.    temp.offset_vscroll_prev = 0;
  141.    temp.offset_vscroll = 0;
  142.    temp.offset_hscroll_prev = 0;
  143.    temp.offset_hscroll = 0;
  144. }
  145.  
  146. unsigned getYUY2(unsigned r, unsigned g, unsigned b)
  147. {
  148.    int y = (int)(0.29*r + 0.59*g + 0.14*b);
  149.    int u = (int)(128.0 - 0.14*r - 0.29*g + 0.43*b);
  150.    int v = (int)(128.0 + 0.36*r - 0.29*g - 0.07*b);
  151.    if (y < 0) y = 0; if (y > 255) y = 255;
  152.    if (u < 0) u = 0; if (u > 255) u = 255;
  153.    if (v < 0) v = 0; if (v > 255) v = 255;
  154.    return WORD4(y,u,y,v);
  155. }
  156.  
  157. void create_palette()
  158. {
  159.    if ((temp.rflags & RF_8BPCH) && temp.obpp == 8) temp.rflags |= RF_GRAY, conf.flashcolor = 0;
  160.  
  161.    PALETTE_OPTIONS *pl = &pals[conf.pal];
  162.    unsigned char brights[4] = { u8(pl->ZZ), u8(pl->ZN), u8(pl->NN), u8(pl->BB) };
  163.    unsigned char brtab[16] =
  164.       {  //  ZZ          NN          ZZ          BB
  165.         u8(pl->ZZ), u8(pl->ZN), u8(pl->ZZ), u8(pl->ZB),    // ZZ
  166.         u8(pl->ZN), u8(pl->NN), u8(pl->ZN), u8(pl->NB),    // NN
  167.         u8(pl->ZZ), u8(pl->ZN), u8(pl->ZZ), u8(pl->ZB),    // ZZ (bright=1,ink=0)
  168.         u8(pl->ZB), u8(pl->NB), u8(pl->ZB), u8(pl->BB)     // BB
  169.       };
  170.  
  171.    for (unsigned i = 0; i < 0x100; i++) {
  172.       unsigned r0, g0, b0;
  173.       if (temp.rflags & RF_GRAY) { // grayscale palette
  174.          r0 = g0 = b0 = i;
  175.       } else if (temp.rflags & RF_PALB) { // palette index: gg0rr0bb
  176.          b0 = brights[i & 3];
  177.          r0 = brights[(i >> 3) & 3];
  178.          g0 = brights[(i >> 6) & 3];
  179.       } else { // palette index: ygrbYGRB
  180.          b0 = brtab[((i>>0)&1)+((i>>2)&2)+((i>>2)&4)+((i>>4)&8)]; // brtab[ybYB]
  181.          r0 = brtab[((i>>1)&1)+((i>>2)&2)+((i>>3)&4)+((i>>4)&8)]; // brtab[yrYR]
  182.          g0 = brtab[((i>>2)&1)+((i>>2)&2)+((i>>4)&4)+((i>>4)&8)]; // brtab[ygYG]
  183.       }
  184.  
  185.       // transform with current settings
  186.       unsigned r = 0xFF & ((r0 * pl->r11 + g0 * pl->r12 + b0 * pl->r13) / 0x100);
  187.       unsigned g = 0xFF & ((r0 * pl->r21 + g0 * pl->r22 + b0 * pl->r23) / 0x100);
  188.       unsigned b = 0xFF & ((r0 * pl->r31 + g0 * pl->r32 + b0 * pl->r33) / 0x100);
  189.  
  190.       // prepare palette in bitmap header for GDI renderer
  191.       gdibmp.header.bmiColors[i].rgbRed   = pal0[i].peRed   = r;
  192.       gdibmp.header.bmiColors[i].rgbGreen = pal0[i].peGreen = g;
  193.       gdibmp.header.bmiColors[i].rgbBlue  = pal0[i].peBlue  = b;
  194.    }
  195.    memcpy(syspalette + 10, pal0 + 10, (246-9) * sizeof *syspalette);
  196. }
  197.  
  198. void atm_zc_tables();//forward
  199.  
  200. // make colortab: zx-attr -> pc-attr
  201. void make_colortab(char flash_active)
  202. {
  203.    if (conf.flashcolor)
  204.        flash_active = 0;
  205.  
  206.    for (unsigned a = 0; a < 0x100; a++)
  207.    {
  208.       unsigned char ink = a & 7;
  209.       unsigned char paper = (a >> 3) & 7;
  210.       unsigned char bright = (a >> 6) & 1;
  211.       unsigned char flash = (a >> 7) & 1;
  212.  
  213.       if((conf.flashcolor && ink) || !conf.flashcolor)
  214.           ink |= bright << 3;
  215.  
  216.       if((conf.flashcolor && paper) || !conf.flashcolor)
  217.           paper |= (conf.flashcolor ? flash : bright) << 3;
  218.  
  219.       if (flash_active && flash)
  220.       {
  221.           unsigned char t = ink;
  222.           ink = paper;
  223.           paper = t;
  224.       }
  225.  
  226.       u8 color = (paper << 4) | ink;
  227.  
  228.       colortab[a] = color;
  229.       colortab_s8[a] = color << 8;
  230.       colortab_s24[a] = color << 24;
  231.    }
  232.  
  233.    if (conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3 || conf.mem_model == MM_ATM450)
  234.        atm_zc_tables(); // update with new flash bit
  235. }
  236.  
  237. // make attrtab: pc-attr + 0x100*pixel -> palette index
  238. void attr_tables()
  239. {
  240.    unsigned char flashcolor = (temp.rflags & RF_MON)? 0 : conf.flashcolor;
  241.    for (unsigned a = 0; a < 0x100; a++)
  242.    {
  243.       unsigned char ink = (a & 0x0F), paper = (a >> 4);
  244.       if (flashcolor)
  245.           paper = (paper & 7) + (ink & 8); // paper_bright from ink
  246.  
  247.       if (temp.rflags & RF_GRAY)
  248.       { // grayscale palette
  249.          t.attrtab[a] = paper*16;
  250.          t.attrtab[a+0x100] = ink*16;
  251.       }
  252.       else if (temp.rflags & RF_COMPPAL)
  253.       { //------ for ATM palette - direct values from palette registers
  254.          t.attrtab[a] = comp.comp_pal[a >> 4];
  255.          t.attrtab[a+0x100] = comp.comp_pal[a & 0x0F];
  256.       }
  257.       else if (temp.rflags & RF_PALB)
  258.       { //----------------------------- for bilinear
  259.          unsigned char b0,b1, r0,r1, g0,g1;
  260.          b0 = (paper >> 0) & 1, r0 = (paper >> 1) & 1, g0 = (paper >> 2) & 1;
  261.          b1 = (ink >> 0) & 1, r1 = (ink >> 1) & 1, g1 = (ink >> 2) & 1;
  262.  
  263.          if (flashcolor && (a & 0x80))
  264.          {
  265.             b1 += b0, r1 += r0, g1 += g0;
  266.             r0 = b0 = g0 = 0;
  267.          }
  268.          else
  269.          {
  270.             b0 *= 2, r0 *= 2, g0 *=2,
  271.             b1 *= 2, r1 *= 2, g1 *=2;
  272.          }
  273.  
  274.          unsigned char br1 = (ink >> 3) & 1;
  275.          if (r1) r1 += br1;
  276.          if (g1) g1 += br1;
  277.          if (b1) b1 += br1;
  278.  
  279.          unsigned char br0 = (paper >> 3) & 1;
  280.          if (r0) r0 += br0;
  281.          if (g0) g0 += br0;
  282.          if (b0) b0 += br0;
  283.  
  284.          // palette index: gg0rr0bb
  285.          t.attrtab[a+0x100]  = (g1 << 6) + (r1 << 3) + b1;
  286.          t.attrtab[a]        = (g0 << 6) + (r0 << 3) + b0;
  287.       }
  288.       else //------------------------------------ all others
  289.       {
  290.          // palette index: ygrbYGRB
  291.          if (flashcolor && (a & 0x80))
  292.          {
  293.              t.attrtab[a] = 0;
  294.              t.attrtab[a+0x100] = ink+(paper<<4);
  295.          }
  296.          else
  297.          {
  298.              t.attrtab[a] = paper * 0x11;
  299.              t.attrtab[a+0x100] = ink * 0x11;
  300.          }
  301.       }
  302.    }
  303. }
  304.  
  305. void p4bpp_tables()
  306. {
  307.    for (unsigned pass = 0; pass < 2; pass++) {
  308.       for (unsigned bt = 0; bt < 0x100; bt++) {
  309.          unsigned lf = ((bt >> 3) & 7) + ((bt >> 4) & 8);
  310.          unsigned rt = (bt & 7) + ((bt >> 3) & 8);
  311.          if (temp.obpp == 8) {
  312.             t.p4bpp8[pass][bt] = (t.sctab8[pass][0x0F+0x10*rt] & 0xFFFF) +
  313.                                    (t.sctab8[pass][0x0F+0x10*lf] & 0xFFFF0000);
  314.          } else if (temp.obpp == 16) {
  315.             t.p4bpp16[pass][bt*2+0] = t.sctab16[pass][0x03+4*rt],
  316.             t.p4bpp16[pass][bt*2+1] = t.sctab16[pass][0x03+4*lf];
  317.          } else /* if (temp.obpp == 32) */ {
  318.             t.p4bpp32[pass][bt*2+0] = t.sctab32[pass][0x100+rt],
  319.             t.p4bpp32[pass][bt*2+1] = t.sctab32[pass][0x100+lf];
  320.          }
  321.       }
  322.    }
  323. }
  324.  
  325. void atm_zc_tables() // atm,profi screens (use normal zx-flash)
  326. {
  327.    for (unsigned pass = 0; pass < 2; pass++) {
  328.       for (unsigned at = 0; at < 0x100; at++) {
  329.          unsigned pc_attr = colortab[at];
  330.          if (temp.obpp == 8)
  331.             for (unsigned j = 0; j < 4; j++)
  332.                t.zctab8ad[pass][at*4+j] = t.sctab8d[pass][pc_attr*4+j];
  333.          else if (temp.obpp == 16)
  334.             t.zctab16ad[pass][at] = t.sctab16d[pass][pc_attr],
  335.             t.zctab16ad[pass][at+0x100] = t.sctab16d[pass][pc_attr+0x100];
  336.          else /* if (temp.obpp == 32) */
  337.             t.zctab32ad[pass][at] = t.sctab32[pass][pc_attr],
  338.             t.zctab32ad[pass][at+0x100] = t.sctab32[pass][pc_attr+0x100];
  339.       }
  340.    }
  341.  
  342.    // atm palette mapping (port out to palette index)
  343.    for (unsigned i = 0; i < 0x100; i++) {
  344.       unsigned v = i ^ 0xFF, dst;
  345.       if (conf.mem_model == MM_ATM450)
  346.          dst = // ATM1: --grbGRB => Gg0Rr0Bb
  347.                ((v & 0x20) << 1) | // g
  348.                ((v & 0x10) >> 1) | // r
  349.                ((v & 0x08) >> 3) | // b
  350.                ((v & 0x04) << 5) | // G
  351.                ((v & 0x02) << 3) | // R
  352.                ((v & 0x01) << 1);  // B
  353.       else
  354.          dst = // ATM2: grbG--RB => Gg0Rr0Bb
  355.                ((v & 0x80) >> 1) | // g
  356.                ((v & 0x40) >> 3) | // r
  357.                ((v & 0x20) >> 5) | // b
  358.                ((v & 0x10) << 3) | // G
  359.                ((v & 0x02) << 3) | // R
  360.                ((v & 0x01) << 1);  // B
  361.       t.atm_pal_map[i] = dst;
  362.    }
  363. }
  364.  
  365. void hires_sc_tables()  // atm,profi screens (use zx-attributes & flash -> paper_bright)
  366. {
  367.    for (unsigned pass = 0; pass < 2; pass++) {
  368.       for (unsigned at = 0; at < 0x100; at++) {
  369.          unsigned pc_attr = (at & 0x80) + (at & 0x38)*2 + (at & 0x40)/8 + (at & 7);
  370.          if (temp.obpp == 8)
  371.             for (unsigned j = 0; j < 16; j++)
  372.                t.zctab8[pass][at*0x10+j] = t.sctab8[pass][pc_attr*0x10+j];
  373.          else if (temp.obpp == 16)
  374.             for (unsigned j = 0; j < 4; j++)
  375.                t.zctab16[pass][at*4+j] = t.sctab16[pass][pc_attr*4+j];
  376.          else /* if (temp.obpp == 32) */
  377.             for (unsigned j = 0; j < 2; j++)
  378.                t.zctab32[pass][at+0x100*j] = t.sctab32[pass][pc_attr+0x100*j];
  379.       }
  380.    }
  381. }
  382.  
  383. void calc_noflic_16_32()
  384. {
  385.    unsigned at, pass;
  386.    if (temp.obpp == 16) {
  387.       for (pass = 0; pass < 2; pass++) {
  388.          for (at = 0; at < 2*0x100; at++)
  389.             t.sctab16d_nf[pass][at] = (t.sctab16d[pass][at] & temp.shift_mask)/2;
  390.          for (at = 0; at < 4*0x100; at++)
  391.             t.sctab16_nf[pass][at] = (t.sctab16[pass][at] & temp.shift_mask)/2;
  392.          for (at = 0; at < 2*0x100; at++)
  393.             t.p4bpp16_nf[pass][at] = (t.p4bpp16[pass][at] & temp.shift_mask)/2;
  394.       }
  395.    }
  396.    if (temp.obpp == 32) {
  397.       unsigned shift_mask = 0xFEFEFEFE;
  398.       for (pass = 0; pass < 2; pass++) {
  399.          for (at = 0; at < 2*0x100; at++)
  400.             t.sctab32_nf[pass][at] = (t.sctab32[pass][at] & shift_mask)/2;
  401.          for (at = 0; at < 2*0x100; at++)
  402.             t.p4bpp32_nf[pass][at] = (t.p4bpp32[pass][at] & shift_mask)/2;
  403.       }
  404.    }
  405. }
  406.  
  407. // pal.index => raw video data, shadowed with current scanline pass
  408. unsigned raw_data(unsigned index, unsigned pass, unsigned bpp)
  409. {
  410.    if (bpp == 8)
  411.    {
  412.  
  413.       if (pass)
  414.       {
  415.          if (!conf.scanbright)
  416.              return 0;
  417.          // palette too small to realize noflic/atari with shaded scanlines
  418.          if (conf.scanbright < 100 && !conf.noflic && !conf.atariset[0])
  419.          {
  420.             if (temp.rflags & RF_PALB)
  421.                 index = (index & (index << 1) & 0x92) | ((index ^ 0xFF) & (index >> 1) & 0x49);
  422.             else
  423.                 index &= 0x0F;
  424.          }
  425.       }
  426.       return index * 0x01010101;
  427.    }
  428.  
  429.    unsigned r = pal0[index].peRed, g = pal0[index].peGreen, b = pal0[index].peBlue;
  430.    if (pass)
  431.    {
  432.        r = r * conf.scanbright / 100;
  433.        g = g * conf.scanbright / 100;
  434.        b = b * conf.scanbright / 100;
  435.    }
  436.  
  437.    if (bpp == 32)
  438.        return WORD4(b,g,r,0);
  439.  
  440.    // else (bpp == 16)
  441.    if (temp.hi15==0)
  442.        return ((b/8) + ((g/4)<<5) + ((r/8)<<11)) * 0x10001;
  443.    if (temp.hi15==1)
  444.        return ((b/8) + ((g/8)<<5) + ((r/8)<<10)) * 0x10001;
  445.    if (temp.hi15==2)
  446.        return getYUY2(r,g,b);
  447.    return 0;
  448. }
  449.  
  450. unsigned atari_to_raw(unsigned at, unsigned pass)
  451. {
  452.    unsigned c1 = at/0x10, c2 = at & 0x0F;
  453.    unsigned raw0 = raw_data(t.attrtab[c1+0x100], pass, temp.obpp);
  454.    unsigned raw1 = raw_data(t.attrtab[c2+0x100], pass, temp.obpp);
  455.    if (raw0 == raw1) return raw1;
  456.  
  457.    if (temp.obpp == 8)
  458.       return (temp.rflags & RF_PALB)? (0x49494949 & ((raw0&raw1)^((raw0^raw1)>>1))) |
  459.                                       (0x92929292 & ((raw0&raw1)|((raw0|raw1)&((raw0&raw1)<<1))))
  460.                                     : (0x0F0F0F0F & raw0) | (0xF0F0F0F0 & raw1);
  461.  
  462.    return (raw0 & temp.shift_mask)/2 + (raw1 & temp.shift_mask)/2;
  463. }
  464.  
  465. void pixel_tables()
  466. {
  467.    attr_tables();
  468.    for (unsigned pass = 0; pass < 2; pass++)
  469.    {
  470.       for (unsigned at = 0; at < 0x100; at++)
  471.       {
  472.          unsigned px0 = t.attrtab[at];
  473.          unsigned px1 = t.attrtab[at+0x100];
  474.          unsigned p0 = raw_data(px0, pass, temp.obpp);
  475.          unsigned p1 = raw_data(px1, pass, temp.obpp);
  476.  
  477.          // sctab32 required for frame resampler in 16-bit mode, so temp.obpp=16 here
  478.          t.sctab32[pass][at] = raw_data(px0, pass, 32);
  479.          t.sctab32[pass][at+0x100] = raw_data(px1, pass, 32);
  480.  
  481.          // 8 bit
  482.          unsigned j;
  483.          for (j = 0; j < 0x10; j++)
  484.          {
  485.             unsigned mask = (j >> 3)*0xFF + (j & 0x04)*(0xFF00/4) +
  486.                             (j & 0x02)*(0xFF0000/2) + (j & 1)*0xFF000000;
  487.             t.sctab8[pass][j + at*0x10] = (mask & p1) + (~mask & p0);
  488.          }
  489.          for (j = 0; j < 4; j++)
  490.          {
  491.             unsigned mask = (j >> 1)*0xFFFF + (j & 1)*0xFFFF0000;
  492.             t.sctab8d[pass][j+at*4] = (mask & p1) + (~mask & p0);
  493.          }
  494.          t.sctab8q[at] = p0, t.sctab8q[at+0x100] = p1;
  495.  
  496.          // 16 bit
  497.          for (j = 0; j < 4; j++)
  498.          {
  499.             unsigned mask = (j >> 1)*0xFFFF + (j & 1)*0xFFFF0000;
  500.             t.sctab16[pass][j+at*4] = (mask & p1) + (~mask & p0);
  501.          }
  502.          t.sctab16d[pass][at] = p0, t.sctab16d[pass][at+0x100] = p1;
  503.  
  504.          unsigned atarimode;
  505.          if (!(temp.rflags & RF_MON) && (atarimode = temp.ataricolors[at]))
  506.          {
  507.             unsigned rawdata[4], i;
  508.             for (i = 0; i < 4; i++) rawdata[i] = atari_to_raw((atarimode >> (8*i)) & 0xFF, pass);
  509.             for (i = 0; i < 16; i++) t.sctab8[pass][at*0x10+i] = rawdata[i/4] + 16*rawdata[i & 3];
  510.             for (i = 0; i < 4; i++) t.sctab8d[pass][at*4+i] = rawdata[i];
  511.             for (i = 0; i < 4; i++) t.sctab16[pass][at*4+i] = rawdata[i];
  512.  
  513.          }
  514.       }
  515.    }
  516.  
  517.    p4bpp_tables(); // used for ATM2+ mode0 and Pentagon-4bpp
  518.  
  519.    if (temp.obpp > 8 && conf.noflic) calc_noflic_16_32();
  520.  
  521.    if ((temp.rflags & (RF_DRIVER|RF_2X|RF_USEFONT))==(RF_DRIVER|RF_2X) && // render="double"
  522.        (conf.mem_model == MM_ATM450 || conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3 || conf.mem_model == MM_PROFI))
  523.       hires_sc_tables();
  524. }
  525.  
  526. void video_color_tables()
  527. {
  528.    temp.shift_mask = 0xFEFEFEFE; // 32bit, 16bit YUY2
  529.    if (temp.obpp == 16 && temp.hi15==0) temp.shift_mask = 0xF7DEF7DE;
  530.    if (temp.obpp == 16 && temp.hi15==1) temp.shift_mask = 0x7BDE7BDE;
  531.  
  532.    create_palette();
  533.    pixel_tables();
  534.    make_colortab(0);
  535.  
  536.    if (temp.rflags & (RF_USEC32 | RF_USE32AS16)) {
  537.       for (unsigned at = 0; at < 0x100; at++) {
  538.          for (unsigned vl = 0; vl <= 0x10; vl++) {
  539.             unsigned br = (at & 0x40) ? 0xFF : 0xBF;
  540.             unsigned c1, c2, res;
  541.             c1 = (at & 1) >> 0, c2 = (at & 0x08) >> 3;
  542.             unsigned b = (c1*vl + c2*(0x10-vl))*br/0x10;
  543.             c1 = (at & 2) >> 1, c2 = (at & 0x10) >> 4;
  544.             unsigned r = (c1*vl + c2*(0x10-vl))*br/0x10;
  545.             c1 = (at & 4) >> 2, c2 = (at & 0x20) >> 5;
  546.             unsigned g = (c1*vl + c2*(0x10-vl))*br/0x10;
  547.             if (temp.rflags & RF_USE32AS16) {
  548.                if (temp.hi15==0) res = (b/8) + ((g/4)<<5) + ((r/8)<<11);
  549.                if (temp.hi15==1) res = (b/8) + ((g/8)<<5) + ((r/8)<<10);
  550.                if (temp.hi15==2) res = getYUY2(r,g,b);
  551.                else res *= 0x10001; // for hi15=0,1
  552.             } else res =  WORD4(b,g,r,0);
  553.             t.c32tab[at][vl] = res;
  554.          }
  555.       }
  556.    }
  557.    setpal(0);
  558. }
  559.  
  560. void video_timing_tables()
  561. {
  562.    if (conf.frame < 2000)
  563.    {
  564.        conf.frame = 2000;
  565.        cpu.SetTpi(conf.frame);
  566.    }
  567.    if (conf.t_line < 128) conf.t_line = 128;
  568.    conf.nopaper &= 1;
  569.    atrtab = (comp.pEFF7 & EFF7_HWMC) ? t.atrtab_hwmc : t.atrtab;
  570.  
  571. //   conf.bordersize=2;
  572. //   temp.scx = 384, temp.scy = 300;
  573.    #define p2cc(p) ((p)/4) // ╧хЁхтюф тхышўшэ√ т яшъёхы ї т ўшёыю чэръюьхёЄ ё єўхЄюь рЄЁшсєЄют (ърцфюх чэръюьхёЄю чрэшьрхЄ 2 срщЄр, срщЄ фрээ√ї ш срщЄ рЄЁшсєЄют)
  574.    const unsigned width = p2cc(temp.scx); // ╪шЁшэр ¤ъЁрэр т чэръюьхёЄрї * 2 (Є.ъ. шёяюы№чє■Єё  яшъёхыш ш рЄЁшсєЄ√ эр 1 чэръюьхёЄю)
  575.    //temp.vidbufsize = temp.scx*temp.scy/4;
  576.  
  577.    // make video table
  578.    unsigned mid_lines = 192; // ╫шёыю ёЄЁюъ т ЎхэЄЁры№эющ ўрёЄш ¤ъЁрэр (схч сюЁф■Ёр)
  579.    const unsigned buf_mid = 256; // ╫шёыю яшъёхыхщ т ЎхэЄЁры№эющ ўрёЄш ¤ъЁрэр (схч сюЁф■Ёр)
  580.  
  581.    // ╨рёўхЄ ЁрчьхЁ сюЁф■Ёр т яшъёхы ї (1 яшъёхы№ = 2 ЄръЄр)
  582.    temp.b_bottom = temp.b_top = conf.b_top_small, temp.b_left = conf.b_left_small; // border small
  583.    if (conf.bordersize==0) temp.b_top = temp.b_left = 0; // border none
  584.    if (conf.bordersize==2) { temp.b_top = conf.b_top_full; temp.b_left = conf.b_left_full; } // border full
  585.  
  586.    // temp.scx - ўшёыю Єюўхъ т ьєы№ЄшъюыюЁх яю уюЁшчюэЄрыш
  587.    // temp.scy - ўшёыю ёЄЁюъ т ьєы№ЄшъюыюЁх
  588.    // 256x192 - border none
  589.    // 320x240 - border small
  590.    // 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)))
  591.    temp.b_right = temp.scx - buf_mid - temp.b_left; // ╨рёўхЄ ЁрчьхЁр яЁртющ ўрёЄш сюЁф■Ёр т яшъёхы ї (1 яшъёхы№ = 1/2 ЄръЄр)
  592.    temp.b_bottom = temp.scy - mid_lines - temp.b_top; // ╨рёўхЄ ЁрчьхЁр эшцэхщ ўрёЄш сюЁф■Ёр т яшъёхы ї (1 яшъёхы№ = 1/2 ЄръЄр)
  593.  
  594.    if (conf.nopaper) temp.b_bottom += mid_lines, mid_lines=0; // ╨хцшь nopaper (ЁрёЄЁ т ёхЁхфшэх ¤ъЁрэр юЄёєЄёЄтєхЄ)
  595.    int inx = 0;
  596.  
  597.    unsigned i;
  598.    #define ts(t) (((int)(t) < 0) ? 0 : t)
  599.    #define p2t(p) ((p)/2) // ╧хЁхтюф яшъёхыхщ т ЄръЄ√
  600.    // conf.paper - ╫шёыю ЄръЄют юЄ эрўрыр ЁрёЄЁр фю ЎхэЄЁры№эющ ўрёЄш spectrum ¤ъЁрэр
  601.    // (тъы■ўрхЄ эхтшфшьє■ ўрёЄ№ + яюыэюёЄ№■ тхЁїэшщ сюЁф■Ё + эрўрыю ёЄЁюъш °шЁшэющ hblank + ыхт√щ сюЁф■Ё)
  602.    // ─ы  pentagon 128: (16+64)*(32+36+128+28)+32+36 = 17988 ЄръЄют
  603.    // 16 ёЄЁюъ эрф тхЁїэшь сюЁф■Ёюь
  604.    // 64 ёЄЁюъш - тхЁїэшщ сюЁф■Ё
  605.    // ърцфр  ёЄЁюър 224 ЄръЄр:
  606.    // 32 ЄръЄр hblank
  607.    // 36 ЄръЄют - ыхт√щ сюЁф■Ё
  608.    // 128 ЄръЄют - ЎхэЄЁ ¤ъЁрэр
  609.    // 28 ЄръЄют - яЁрт√щ сюЁф■Ё
  610.    unsigned t = conf.paper - temp.b_top*conf.t_line; // ╫шёыю ЄръЄют фю эрўрыр тхЁїэхую сюЁф■Ёр (тъы■ўр  hblank + ыхт√щ сюЁф■Ё т яхЁтющ ёЄЁюъх paper)
  611.    const unsigned hblank = conf.t_line - p2t(temp.scx); // ╫шёыю ЄръЄют т hblank
  612.    video[inx++].next_t = ts(t - p2t(temp.b_left)); // ╚ёъы■ўхэшх ыхтюую сюЁф■Ёр (next_t - ЄръЄ эрўрыр яхЁтющ ёЄЁюъш тхЁїэхую сюЁф■Ёр)
  613. //   printf("btop: temp.b_top=%u, conf.b_top_full=%u\n", temp.b_top, conf.b_top_full);
  614.    for (i = 0; i < temp.b_top; i++)
  615.    { // тхЁїэшщ сюЁф■Ё
  616.       video[inx].next_t = ts(t + p2t(buf_mid+temp.b_right)); // ╩юэхЎ яЁртюую сюЁф■Ёр (ЄръЄ ъюэЎр Єхъє∙хщ ёЄЁюъш)
  617.       video[inx].screen_ptr = rbuf+width*i; // ╙ърчрЄхы№ эр эр ўрыю Єхъє∙хщ ёЄЁюъш т сєЇхЁх юЄЁшёютъш
  618.       video[inx].nextvmode = 0; // hblank (яхЁхїюф ъ эютющ ёЄЁюъх)
  619. //      printf("%3u: b=%u, e=%u, o=%u\n", i, video[inx-1].next_t, video[inx].next_t, width*i);
  620.  
  621.        // ╧хЁхїюф ъ ёыхфє■∙хщ ёЄЁюъх (t - ЄръЄ эрўрыр paper ёыхфє■∙хщ ёЄЁюъш hblank + ыхт√щ сюЁф■Ё)
  622.       inx++; t += conf.t_line;
  623.       video[inx++].next_t = ts(t - p2t(temp.b_left)); // ╚ёъы■ўхэшх ыхтюую сюЁф■Ёр (ЄръЄ эрўрыр ыхтюую сюЁф■Ёр эр ёыхфє■∙хщ ёЄЁюъх)
  624.    }
  625. //   printf("paper:\n");
  626.    for (i = 0; i < mid_lines; i++)
  627.    { // hblank + ыхт√щ сюЁф■Ё + ¤ъЁрэ + яЁрт√щ сюЁф■Ё
  628.       video[inx].next_t = ts(t); // ╩юэхЎ ыхтюую сюЁф■Ёр (ЄръЄ эрўрыр paper эр Єхъє∙хщ ёЄЁюъх)
  629.       video[inx].screen_ptr = rbuf+width*(i+temp.b_top); // ╙ърчрЄхы№ эр эрўрыю iщ ёЄЁюъш ыхтюую сюЁф■Ёр т сєЇхЁх юЄЁшёютъш
  630.       video[inx].nextvmode = 2; // ─рыхх яЁюЁшёют√трхЄё  paper
  631. //      printf("%3u: b=%u ", i, video[inx-1].next_t);
  632.  
  633.       inx++;
  634.       video[inx].next_t = ts(t + p2t(buf_mid)); // ╩юэхЎ paper (ЄръЄ эрўрыр яЁртюую сюЁф■Ёр эр Єхъє∙хщ ёЄЁюъх)
  635.       video[inx].screen_ptr = rbuf+width*(i+temp.b_top)+p2cc(temp.b_left);// ╙ърчрЄхы№ эр эрўрыю iщ ёЄЁюъш paper т сєЇхЁх юЄЁшёютъш
  636.       video[inx].scr_offs = ::t.scrtab[i]; // ╤ьх∙хэшх юЄ эрўрыр zx ¤ъЁрэр (яшъёхыш)
  637.       video[inx].atr_offs = atrtab[i]; // ╤ьх∙хэшх юЄ эрўрыр чюэ√ рЄЁшсєЄют zx ¤ъЁрэр
  638.  
  639.       inx++;
  640.       video[inx].next_t = ts(t + p2t(buf_mid+temp.b_right));  // ╩юэхЎ яЁртюую сюЁф■Ёр (ЄръЄ ъюэЎр Єхъє∙хщ ёЄЁюъш)
  641.       video[inx].screen_ptr = rbuf+width*(i+temp.b_top)+p2cc(buf_mid+temp.b_left); // ╙ърчрЄхы№ эр эрўрыю iщ ёЄЁюъш яЁртюую сюЁф■Ёр т сєЇхЁх юЄЁшёютъш
  642.       video[inx].nextvmode = 0; // hblank (яхЁхїюф ъ эютющ ёЄЁюъх)
  643.  
  644. //      printf("e=%u\n", video[inx].next_t);
  645.        // ╧хЁхїюф ъ ёыхфє■∙хщ ёЄЁюъх (t - ЄръЄ эрўрыр paper ёыхфє■∙хщ ёЄЁюъш hblank + ыхт√щ сюЁф■Ё)
  646.       inx++; t += conf.t_line;
  647.       video[inx++].next_t = ts(t - p2t(temp.b_left)); // ╚ёъы■ўхэшх ыхтюую сюЁф■Ёр (ЄръЄ эрўрыр ёыхфє■∙хщ ёЄЁюъш)
  648.    }
  649. //   printf("bbot:\n");
  650.    for (i = 0; i < temp.b_bottom; i++)
  651.    { // эшцэшщ сюЁф■Ё
  652.       video[inx].next_t = ts(t + p2t(buf_mid+temp.b_right)); // ╩юэхЎ яЁртюую сюЁф■Ёр (ЄръЄ ъюэЎр Єхъє∙хщ ёЄЁюъш)
  653.       video[inx].screen_ptr = rbuf+width*(i+temp.b_top+mid_lines); // ╙ърчрЄхы№ эр эр ўрыю iщ ёЄЁюъш эшцэхую сюЁф■Ёр т сєЇхЁх юЄЁшёютъш
  654.       video[inx].nextvmode = 0; // hblank (яхЁхїюф ъ эютющ ёЄЁюъх)
  655. //      printf("%3u: b=%u, e=%u\n", i, video[inx-1].next_t, video[inx].next_t);
  656.  
  657.        // ╧хЁхїюф ъ ёыхфє■∙хщ ёЄЁюъх (t - ЄръЄ эрўрыр paper ёыхфє■∙хщ ёЄЁюъш hblank + ыхт√щ сюЁф■Ё)
  658.       inx++; t += conf.t_line;
  659.       video[inx++].next_t = ts(t - p2t(temp.b_left)); // ╚ёъы■ўхэшх ыхтюую сюЁф■Ёр (ЄръЄ эрўрыр ёыхфє■∙хщ ёЄЁюъш)
  660.    }
  661.    video[inx-1].next_t = 0x7FFFFFFF; // ╧Ёшчэръ яюёыхфэхщ ёЄЁюъш
  662. //   exit(0);
  663.  
  664.    temp.evenM1_C0 = conf.even_M1 ? 0xC0 : 0x00;
  665.    temp.border_add = conf.border_4T ? 6 : 0;
  666.    temp.border_and = conf.border_4T ? 0xFFFFFFFC : 0xFFFFFFFF;
  667.  
  668.    for (i = 0; i < NUM_LEDS; i++)
  669.    {
  670.       unsigned z = *(&conf.led.ay + i);
  671.       int x = (signed short)(z & 0xFFFF);
  672.       int y = (signed short)(((z >> 16) & 0x7FFF) + ((z >> 15) & 0x8000));
  673.       if (x < 0) x += width*8;
  674.       if (y < 0) y += temp.scy;
  675.       *(&temp.led.ay+i) = (z & 0x80000000) ? rbuf + ((x>>2)&0xFE) + y*width : 0;
  676.    }
  677.  
  678.    if (temp.rflags & RF_USEFONT)
  679.        create_font_tables();
  680.  
  681.    needclr = 2;
  682. }
  683.  
  684. void set_video()
  685. {
  686. //   printf("%s\n", __FUNCTION__);
  687.    set_vidmode();
  688.    video_color_tables();
  689. }
  690.  
  691. void apply_video()
  692. {
  693. //   printf("%s\n", __FUNCTION__);
  694.    load_ula_preset();
  695.  
  696.    if(conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3 || conf.mem_model == MM_ATM450 || conf.mem_model == MM_PROFI)
  697.    {
  698.        conf.render = 1; // ─ы  ьюфхыхщ ё ¤ъЁрэюь 640x200 яюффхЁцштрхЄё  Єюы№ъю redner = double (640x480)
  699.    }
  700.  
  701.    temp.rflags = renders[conf.render].flags;
  702.    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))
  703.    {
  704.       temp.rflags |= RF_COMPPAL | RF_PALB;
  705.       // disable palette noflic, only if it is really used
  706.       if (temp.obpp == 8 && (temp.rflags & (RF_DRIVER | RF_USEFONT | RF_8BPCH)) == RF_DRIVER)
  707.       conf.noflic = 0;
  708.    }
  709.  
  710.    if (renders[conf.render].func == render_rsm)
  711.        conf.flip = 1; // todo: revert back after returning from frame resampler //Alone Coder
  712.  
  713.    if (renders[conf.render].func == render_advmame)
  714.    {
  715.       if (conf.videoscale == 2)
  716.           temp.rflags |= RF_2X;
  717.       if (conf.videoscale == 3)
  718.           temp.rflags |= RF_3X;
  719.       if (conf.videoscale == 4)
  720.           temp.rflags |= RF_4X;
  721.    } //Alone Coder
  722.  
  723.    set_video();
  724.    calc_rsm_tables();
  725.    video_timing_tables();
  726. }
  727.  
  728. __inline unsigned char *raypointer()
  729. {
  730.    if (prev_t > conf.frame)
  731.        return rbuf + rb2_offs;
  732.    if (!vmode)
  733.        return vcurr[1].screen_ptr;
  734.    unsigned offs = (prev_t - vcurr[-1].next_t) / 4;
  735.    return vcurr->screen_ptr + (offs+1) * 2;
  736. }
  737.  
  738. __inline void clear_until_ray()
  739. {
  740.    unsigned char *dst = raypointer();
  741.    while (dst < rbuf + rb2_offs) *dst++ = 0, *dst++ = 0x55;
  742. }
  743.  
  744. void paint_scr(char alt) // alt=0/1 - main/alt screen, alt=2 - ray-painted
  745. {
  746.    if (alt == 2) {
  747.       update_screen();
  748.       clear_until_ray();
  749.    } else {
  750.       if (alt) comp.p7FFD ^= 8, set_banks();
  751.       draw_screen();
  752.       if (alt) comp.p7FFD ^= 8, set_banks();
  753.    }
  754. }
  755.  
  756. // ┬√ч√трхЄё  яЁш чряшёш т тшфхюярь Є№/(яюЁЄ√ FE/7FFD) эютюую чэрўхэш 
  757. // ╧ЁюшчтюфшЄ юЄЁшёютъє сюЁф■Ёр/¤ъЁрэр т яЁюьхцєЄюўэ√щ сєЇхЁ ё шёяюы№чютрэшхь pc рЄЁшсєЄют
  758. void update_screen()
  759. {
  760.    unsigned last_t = (cpu.t + temp.border_add) & temp.border_and;
  761.    unsigned t = prev_t;
  762. //   printf("upd_scr: t=%u, lt=%u, vm=%u\n", t, last_t, vmode);
  763.    if (t >= last_t) // ═хтшфшьр  ўрёЄ№ ёЄЁюъш (hblank ышсю эхтшфшь√х ёЄЁюъш тхЁїэхую сюЁф■Ёр)
  764.        return;
  765.  
  766.    unsigned char b = comp.border_attr;
  767.    b |= (b<<4); // └ЄЁшсєЄ√ сюЁф■Ёр фєсышЁє■Єё  т ЇюЁьрЄх pc рЄЁшсєЄют ink=paper
  768.  
  769.    if (vmode == 1)
  770.        goto mode1;
  771.  
  772.    if (vmode == 2)
  773.        goto mode2;
  774.  
  775. mode0: // not visible
  776.    {
  777.       vmode = 1;
  778.       t = vcurr->next_t; // ╥ръЄ эрўрыр ёЄЁюъш
  779.       vcurr++; // ╧хЁхїюф ъ ъюэЎє ёЄЁюъш
  780.       if (t >= last_t)
  781.       {
  782. done:
  783.           prev_t = t;
  784.           return;
  785.       }
  786.    }
  787. mode1: // border
  788.    {
  789.       unsigned offs = (t - vcurr[-1].next_t); // ╤ьх∙хэшх т ЄръЄрї юЄ эрўрыр ёЄЁюъш (1 ЄръЄ = 2 яшъёхы )
  790.       unsigned char *ptr = vcurr->screen_ptr + offs/2; // ╙ърчрЄхы№ эр рфЁхё Єюўъш т яЁюьхцєЄюўэюь сєЇхЁх
  791. //      u8 *pp =ptr;
  792.       ptr = (unsigned char*)(ULONG_PTR(ptr) & ~ULONG_PTR(1)); // ┬√Ёртрэшх фю ўхЄэюую рфЁхёр
  793.       if(offs & 3)
  794.       { // ┼ёЄ№ яшъёхыш эх яюярфр■∙шх эр уЁрэшЎє чэръюьхёЄр
  795.          *ptr++ = ((unsigned)0xFF00 >> ((offs & 3)*2)); // ╠рёър яшъёхыхщ
  796.          t += 4 -(offs & 3);
  797.          *ptr = (*ptr & 0x0F) + (b & 0xF0); // └ЄЁшсєЄ√
  798.          ptr++;
  799.       }
  800.       unsigned end = min(vcurr->next_t, last_t);
  801. //      printf("upd_scr_m1: o=%uT, p=%u, t=%uT, end=%uT\n", offs, pp - rbuf, t, end);
  802.       for (; t < end; t+=4) // ╬сЁрсюЄър яшъёхыхщ яю чэръюьхёЄрь (яю 8 Єюўхъ)
  803.       {
  804.          *ptr++ = 0; // ╧шъёхыш эх шёяюы№чє■Єё 
  805.          *ptr++ = b; // └ЄЁшсєЄ√
  806.       }
  807.       t = end;
  808.       if (t == vcurr->next_t)
  809.       { // ╤ЄЁюър чръюэўшырё№,  яхЁхїюф ъ ёыхфє■∙хщ Єюўъх
  810.           vmode = vcurr->nextvmode;
  811.           vcurr++;
  812.       }
  813.       if (t == last_t) // ╬ЄЁшёютър чръюэўхэр, т√їюф
  814.           goto done;
  815.  
  816.       if (!vmode) // ═рўрыю ёыхфє■∙хщ ёЄЁюъш
  817.           goto mode0;
  818.    }
  819. mode2: // screen
  820.    {
  821.       unsigned offs = (t - vcurr[-1].next_t)/4; // ╤ьх∙хэшх т чэръюьхёЄрї юЄ эрўрыр ёЄЁюъш (1 чэръюьхёЄю = 4 ЄръЄр = 8 яшъёхыхщ)
  822.       unsigned char *scr = temp.base + vcurr->scr_offs + offs; // spectrum яшъёхыш
  823.       unsigned char *atr = temp.base + vcurr->atr_offs + offs; // spectrum рЄЁшсєЄ√
  824.       unsigned char *ptr = vcurr->screen_ptr + offs*2; // ╤ЄЁєъЄєЁр сєЇхЁр 8pix:attr
  825.       unsigned end = min(last_t, vcurr->next_t);
  826.       for (int i = 0; t < end; t += 4, i++)
  827.       {
  828.          ptr[2*i] = scr[i]; // ╩юяшЁютрэшх spectrum яшъёхыхщ
  829.          ptr[2*i+1] = colortab[atr[i]]; // ╩юэтхЁЄшЁютрэшх spectrum рЄЁшсєЄют т pc рЄЁшсєЄ√
  830.       }
  831.       t = end;
  832.       if (t == vcurr->next_t)
  833.       { // ╓хэЄЁры№эр  ўрёЄ№ ¤ъЁрэр чръюэўшырё№, юЄЁшёютър яЁртюую сюЁф■Ёр
  834.           vmode = 1; // border
  835.           vcurr++;
  836.       }
  837.       if (t == last_t) // ╬ЄЁшёютър чръюэўхэр, т√їюф
  838.           goto done;
  839.       goto mode1; // ╬ЄЁшёютър яЁртюую сюЁф■Ёр
  840.    }
  841. }
  842.  
  843. void init_frame()
  844. {
  845.    // recreate colors with flash attribute
  846.    unsigned char frame = (unsigned char)comp.frame_counter;
  847.    if (!(frame & 15) /* && !conf.flashcolor */ )
  848.        make_colortab(frame & 16);
  849.  
  850.    prev_t = -1; // block MCR
  851.    temp.base_2 = 0; // block paper trace
  852.  
  853.    if (temp.vidblock)
  854.        return;
  855.  
  856. /* [vv] ╬Єъы■ўхэ, Є.ъ. ¤ЄюЄ сшЄ шёяюы№чєхЄё  фы  DDp scroll
  857.    // AlCo384 - no border/paper rendering
  858.    if (comp.pEFF7 & EFF7_384)
  859.        return;
  860. */
  861.    // GIGASCREEN - no paper rendering
  862. //   if (comp.pEFF7 & EFF7_GIGASCREEN) goto allow_border; //Alone Coder
  863.  
  864.    // disable multicolors, border still works
  865.    if ((temp.rflags & RF_BORDER) || // chunk/etc filter
  866.        (conf.mem_model == MM_PROFI && (comp.pDFFD & 0x80)) ||   // profi hires screen
  867.        ((conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3)&& (comp.pFF77 & 7) != 3) ||  // ATM-2 hires screen
  868.        (conf.mem_model == MM_ATM450 && (comp.aFE & 0x60) != 0x60)) // ATM-1 hires screen
  869.    {
  870.        if ((conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3))
  871.        {
  872.            // ATM2, юфшэ шч Ёрё°шЁхээ√ї тшфхюЁхцшьют
  873.            AtmVideoCtrl.PrepareFrameATM2(comp.pFF77 & 7);
  874.        }
  875.  
  876.        if (conf.mem_model == MM_ATM450)
  877.        {
  878.            // ATM1, юфшэ шч Ёрё°шЁхээ√ї тшфхюЁхцшьют
  879.            AtmVideoCtrl.PrepareFrameATM1( (comp.aFE >> 5) & 3 );
  880.  
  881.        }
  882.        
  883.       // if border update disabled, dont show anything on zx-screen
  884.       if (!conf.updateb)
  885.           return;
  886.    }
  887.  
  888.    // paper + border
  889.    temp.base_2 = temp.base;
  890. //allow_border:
  891.    prev_t = vmode = 0;
  892.    vcurr = video;
  893. }
  894.  
  895. void flush_frame()
  896. {
  897.    if (temp.vidblock)
  898.        return;
  899.    if (prev_t != -1)
  900.    { // MCR on
  901.       if (prev_t)
  902.       {  // paint until end of frame
  903.          // paint until screen bottom, even if n_lines*t_line < cpu.t (=t_frame)
  904.          unsigned t = cpu.t;
  905.          cpu.t = 0x7FFF0000;
  906.          update_screen();
  907.          cpu.t = t;
  908. //         if (comp.pEFF7 & EFF7_GIGASCREEN) draw_gigascreen_no_border(); //Alone Coder
  909.       }
  910.       else
  911.       { // MCR on, but no screen updates in last frame - use fast painter
  912.          if (temp.base_2 /*|| (comp.pEFF7 & EFF7_GIGASCREEN)*/ /*Alone Coder*/)
  913.              draw_screen();
  914.          else
  915.              draw_border();
  916.       }
  917.       return;
  918.    }
  919.    if (comp.pEFF7 & EFF7_384)
  920.        draw_alco();
  921. }
  922.  
  923. void load_spec_colors()
  924. {
  925.    // spectrum colors -> palette indexes (RF_PALB - gg0rr0bb format)
  926.    static unsigned char comp_pal[16] =
  927.       { 0x00, 0x02, 0x10, 0x12, 0x80, 0x82, 0x90, 0x92,
  928.         0x00, 0x03, 0x18, 0x1B, 0xC0, 0xC3, 0xD8, 0xDB };
  929.    memcpy(comp.comp_pal, comp_pal, sizeof comp.comp_pal);
  930.    temp.comp_pal_changed = 1;
  931. }
  932.