Top secrets sources NedoPC pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

#include "std.h"

#include "emul.h"
#include "vars.h"
#include "draw.h"
#include "drawnomc.h"
#include "dx.h"
#include "dxr_text.h"
#include "dxr_rsm.h"
#include "dxr_advm.h"
#include "memory.h"
#include "config.h"

#include "util.h"

// 44 146

//                                              R       G       B
    unsigned char dbg_clr_array[16][3] = {  {   0,      0,      0       },      //black
                                            {   16,     16,     64      },      // selected window
                                            {   (59),   16,     16      },      //BPW
                                            {   61,     0,      61      },
                                                               
                                            {   16,     (45),   16      },      //BPR
                                            {   37,     72,     84      },      // panelz       //32,   96,     96      //{     64,     200,    200     },
                                            {   (55),   (55),   16      },      //BPR BPW
                                            {   190,    210,    200     },      // ROM
                                                               
                                            {   33,     33,     33      },
                                            {   38,     38,     255     },      // watches
                                            {   (255)40,     40      },      //BREAK EX
                                            {   255,    64,     255     },      //cursor
                                                               
                                            {   32,     255,    32      },      //
                                            {   96,     255,    255     },      // window names
                                            {   255,    255,    32      },      //
                                            {   255,    255,    255     }       //WHITE
                                        };

        unsigned char dbg_clr_R[16] = { 0x00,0x50,0xC0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
        unsigned char dbg_clr_G[16] = { 0x00,0x00,0x00,0x00,0x40,0x70,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
        unsigned char dbg_clr_B[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };


//=============================================================================
#ifdef CACHE_ALIGNED
CACHE_ALIGNED unsigned char rbuf[sizeof_rbuf];
#else // __declspec(align) not available, force QWORD align with old method
__int64 rbuf__[sizeof_rbuf/sizeof(__int64)];
unsigned char * const rbuf = (unsigned char*)rbuf__;
#endif
//=============================================================================

unsigned char * const rbuf_s = rbuf + rb2_offs;                 // frames to mix with noflic and resampler filters
unsigned char * const save_buf = rbuf_s + rb2_offs*MAX_BUFFERS; // used in monitor

T t;    //alco style :rofl:

videopoint *vcurr; // Óêàçàòåëü íà òåêóùèé ýëåìåíò èç video[]

// Ìàññèâ âèäåîñòðîê âêëþ÷àÿ áîðäþð
// video[i] - íà÷àëî ñòðîêè (èñïîëüçóåòñÿ òîëüêî next_t)
// video[i+1] - êîíåö ñòðîêè  (èñïîëüçóþòñÿ âñå ïàðàìåòðû)
static videopoint video[4*MAX_HEIGHT];

unsigned vmode;                 // what are drawing: 0-not visible, 1-border, 2-screen
static unsigned prev_t;         // òàêò íà êîòîðîì áûë îòðèñîâàí ïîñëåäíèé ïèêñåëü
unsigned *atrtab;

unsigned char colortab[0x100];  // map zx attributes to pc attributes

unsigned colortab_s8[0x100];    // colortab shifted to 8 and 24
unsigned colortab_s24[0x100];

/*
#include "drawnomc.cpp"
#include "draw_384.cpp"
*/


PALETTEENTRY pal0[ 0x100];      // emulator palette

PALETTEENTRY pal_dbg[ 0x100];   // debuger palette [NS]

//=============================================================================
void AtmVideoController::PrepareFrameATM2(int VideoMode)
{
    for (int y=0; y<256; y++)
    {
        if ( VideoMode == 6 )
        {
            // ñìåùåíèÿ â òåêñòîâîì âèäåîðåæèìå
            Scanlines[y].Offset = 64 * (y / 8);
        }
        else
        {
            // ñìåùåíèÿ â ðàñòðîâîì âèäåîðåæèìå
            Scanlines[y].Offset = (y < 56)  ?   0               :
                                                40*(y-56)       ;
        }
        Scanlines[y].VideoMode = VideoMode;
    }
    CurrentRayLine = 0;
    IncCounter_InRaster = 0;
    IncCounter_InBorder = 0;
}
//=============================================================================


//=============================================================================
void AtmVideoController::PrepareFrameATM1(int VideoMode)
{
    for (int y=56; y<256; y++)
    {
        Scanlines[y].Offset = 40 * (y - 56);
        Scanlines[y].VideoMode = VideoMode;
    }
}
//=============================================================================

AtmVideoController AtmVideoCtrl;

//=============================================================================
void video_permanent_tables()                   //ãåíåðàöèÿ òàáëèö äëÿ âèäåî?
{
    // pixel doubling table
    unsigned i; //Alone Coder 0.36.7
    for (/*unsigned*/ i = 0; i < 0x100; i++)
    {
        unsigned res = 0;
        for (unsigned j = 0x80; j; j/=2)
        {
            res <<= 2;
            if (i & j)
            {
                res |= 3;
            }
        }
        t.dbl[i] = res;
    }

    for (i = 0; i < 0x100; i++)
    {
        unsigned r1 = 0, r2 = 0;
        if (i & 0x01)
        {
            r1++;
            r2 += 1;
        }
        if (i & 0x02)
        {
            r1++;
            r2 += 1;
        }
        if (i & 0x04)
        {
            r1++;
            r2 += 0x100;
        }
        if (i & 0x08)
        {
            r1++;
            r2 += 0x100;
        }
        if (i & 0x10)
        {
            r1 += 0x100;
            r2 += 0x10000;
        }
        if (i & 0x20)
        {
            r1 += 0x100;
            r2 += 0x10000;
        }
        if (i & 0x40)
        {
            r1 += 0x100;
            r2 += 0x1000000;
        }
        if (i & 0x80)
        {
            r1 += 0x100;
            r2 += 0x1000000;
        }
        // low byte of settab - number of pixels in low nibble of i
        // high byte of low word of settab - number of pixels in high nibble of i
        t.settab[i] = r1;
        t.settab2[i] = r2*4;    // *4 - convert square 2x2 to 4x4
    }

    //-------------------------------------------------------------------------
    // calc screen addresses
    i = 0;
    for(unsigned p = 0; p < 4; p++)
    {
        for(unsigned y = 0; y < 8; y++)
        {
            for(unsigned o = 0; o < 8; o++, i++)
            {
                t.scrtab[i] = p * 0x800 + y * 0x20 + o * 0x100;
                t.atrtab_hwmc[i] = t.scrtab[i] + 0x2000;
                t.atrtab[i] = 0x1800 + (p * 8 + y) * 32;
            }
        }
    }
    //-------------------------------------------------------------------------

    // alco table
    static unsigned disp_0[] = {        0x0018,
                                        0x2000,
                                        0x2008,
                                        0x2010,
                                        0x2018,
                                        0x0008
                                };
    static unsigned base_s[] = {        0x10000,
                                        0x14000,
                                        0x14800,
                                        0x15000,
                                        0x11800
                                };
    static unsigned base_a[] = {        0x11000,
                                        0x15800,
                                        0x15900,
                                        0x15A00,
                                        0x11300
                                };
                               
    for (unsigned y = 0; y < 304; y++)
        for (unsigned x = 0; x < 6; x++)
        {
            unsigned disp = disp_0[x] + (y & 0x38)*4;
            ::t.alco[y][x].a = memory + base_a[y/64] + disp;
            ::t.alco[y][x].s = memory + base_s[y/64] + disp + (y & 7)*0x100;
        }

    //-------------------------------------------------------------------------
    // Video Drive by SAM style
    #ifdef MOD_VID_VD
    // this code is only for ygrbYGRB palette
    for (unsigned byte = 0; byte < 0x100; byte++)
        for (int bit = 0; bit < 8; bit++)
            t.vdtab[0][0][byte].m64_u8[7-bit] = (byte & (1 << bit)) ? 0x11 : 0;
    for (int pl = 1; pl < 4; pl++)
        for (unsigned byte = 0; byte < 0x100; byte++)
            t.vdtab[0][pl][byte] = _mm_slli_pi32(t.vdtab[0][0][byte], pl);
    for (i = 0; i < sizeof t.vdtab[0]; i++)
        ((unsigned char*)t.vdtab[1])[i] = ((unsigned char*)t.vdtab[0])[i] & 0x0F;
    _mm_empty();
    #endif
    //-------------------------------------------------------------------------

    temp.offset_vscroll_prev = 0;
    temp.offset_vscroll = 0;
    temp.offset_hscroll_prev = 0;
    temp.offset_hscroll = 0;
}
//=============================================================================



//=============================================================================
static unsigned getYUY2(unsigned r, unsigned g, unsigned b)
{
    int y = (int)(0.29*r + 0.59*g + 0.14*b);
    int u = (int)(128.0 - 0.14*r - 0.29*g + 0.43*b);
    int v = (int)(128.0 + 0.36*r - 0.29*g - 0.07*b);
    if (y < 0) y = 0; if (y > 255) y = 255;
    if (u < 0) u = 0; if (u > 255) u = 255;
    if (v < 0) v = 0; if (v > 255) v = 255;
    return WORD4(y,u,y,v);
}
//=============================================================================



//=============================================================================
static void create_palette()
{
    //printf("create_palette()\n");

    if ((temp.rflags & RF_8BPCH) && temp.obpp == 8)
    {
        temp.rflags |= RF_GRAY;
        conf.flashcolor = 0;
    }

    PALETTE_OPTIONS *pl = &pals[conf.pal];
    //                                Ii          Ii          Ii          Ii
    //                                00          01          10          11
    unsigned char brights[4] = { u8(pl->ZZ), u8(pl->ZN), u8(pl->NN), u8(pl->BB) };
    unsigned char brtab[16] =
    {   //   ZZ          NN          ZZ          BB
        u8(pl->ZZ), u8(pl->ZN), u8(pl->ZZ), u8(pl->ZB), // ZZ
        u8(pl->ZN), u8(pl->NN), u8(pl->ZN), u8(pl->NB), // NN
        u8(pl->ZZ), u8(pl->ZN), u8(pl->ZZ), u8(pl->ZB), // ZZ (bright=1,ink=0)
        u8(pl->ZB), u8(pl->NB), u8(pl->ZB), u8(pl->BB)  // BB
    };



//draw.cpp:262:43: warning: iteration 1 invokes undefined behavior [-Waggressive-loop-optimizations]

    int i = 255;                                // ÐÀÁÎ×ÈÉ êîñòûëü
    while (i >= 0)                              // çàïîëíåíèå â îáðàòíîì ïîðÿäêå
    {
//
//  for (unsigned i = 0; i < 0x100; i++)        // îðèãèíàë
//  {                                           // óñëîâèå íå ñðàáàòûâàåò ïðè -O1+ !!!!!
//
//  int i = 0;
//  while (i < 256)                             // óñëîâèå íå ñðàáàòûâàåò ïðè -O1+ !!!!!
//  {

        unsigned r0, g0, b0;
        if (temp.rflags & RF_GRAY)
        { // grayscale palette
            r0 = g0 = b0 = i;
        }
        else if (temp.rflags & RF_PALB)
        { // palette index:
            if (comp.ula_plus_en) // gggrrrbb (ULA+)
            { // Ëèíåéíàÿ èíòåðïîëÿöèÿ ÿðêîñòè
                b0 = ((i & 3) * 255) / 3;               // 2 áèòà
                r0 = (((i >> 2) & 7) * 255) / 7;        // 3 áèòà
                g0 = (((i >> 5) & 7) * 255) / 7;        // 3 áèòà
            }
            else // gg0rr0bb (ATM / profi / bilinear filter)
            { // Íåëèíåéíàÿ êîððåêöèÿ ÿðêîñòè (íà 2 áèòà) ïî òàáëèöå ïàëèòðû èç .ini ôàéëà
                b0 = brights[i & 3];
                r0 = brights[(i >> 3) & 3];
                g0 = brights[(i >> 6) & 3];
            }
        }
        else
        { // palette index: ygrbYGRB (îáû÷íûé zx ðåæèì áåç ïàëèòðû)
          // Íåëèíåéíàÿ êîððåêöèÿ ÿðêîñòè (íà 4 áèòà) ïî òàáëèöå ïàëèòðû èç .ini ôàéëà
            b0 = brtab[((i >> 0) & 1) + ((i >> 2) & 2) + ((i >> 2) & 4) + ((i >> 4) & 8)]; // brtab[ybYB]
            r0 = brtab[((i >> 1) & 1) + ((i >> 2) & 2) + ((i >> 3) & 4) + ((i >> 4) & 8)]; // brtab[yrYR]
            g0 = brtab[((i >> 2) & 1) + ((i >> 2) & 2) + ((i >> 4) & 4) + ((i >> 4) & 8)]; // brtab[ygYG]
        }
        //      printf("i = %d\n",i);
             
        // transform with current settings
        unsigned r = 0xFF & ((r0 * pl->r11 + g0 * pl->r12 + b0 * pl->r13) / 0x100);
        unsigned g = 0xFF & ((r0 * pl->r21 + g0 * pl->r22 + b0 * pl->r23) / 0x100);
        unsigned b = 0xFF & ((r0 * pl->r31 + g0 * pl->r32 + b0 * pl->r33) / 0x100);

//draw.cpp:262:43: warning: iteration 1 invokes undefined behavior [-Waggressive-l
//oop-optimizations]
//  262 |         gdibmp.header.bmiColors[i].rgbRed = pal0[i].peRed = BYTE(r);
//      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
//draw.cpp:226:27: note: within this loop
//  226 |     for(unsigned i = 0; i < 0x100; i++)
//      |                         ~~^~~~~~~
     


        // prepare palette in bitmap header for GDI renderer
        gdibmp.header.bmiColors[i].rgbRed =             pal0[i].peRed =         BYTE(r);
        gdibmp.header.bmiColors[i].rgbGreen =           pal0[i].peGreen =       BYTE(g);
        gdibmp.header.bmiColors[i].rgbBlue =            pal0[i].peBlue =        BYTE(b);
       

        gdi_dbg_bmp.header.bmiColors[i].rgbRed =        pal_dbg[i].peRed =      BYTE( dbg_clr_array[i%16][0] );
        gdi_dbg_bmp.header.bmiColors[i].rgbGreen =      pal_dbg[i].peGreen =    BYTE( dbg_clr_array[i%16][1] );
        gdi_dbg_bmp.header.bmiColors[i].rgbBlue =       pal_dbg[i].peBlue =     BYTE( dbg_clr_array[i%16][2] );

       
        //system ("pause");

        i--;

//            printf("i = %d\n",i);
    }
   
   

 
 
       
    memcpy(syspalette + 10, pal0 + 10, (246 - 9) * sizeof *syspalette);

    if (conf.mem_model == MM_PROFI)
    {
        // profi palette mapping (port out to palette index)
        for(unsigned i = 0; i < 0x100; i++)
        {
            unsigned dst;
            dst = i;                    // Gg0Rr0Bb => Gg0Rr0Bb
            t.profi_pal_map[i] = dst;
        }
    }
}
//=============================================================================

void atm_zc_tables();           //forward

//=============================================================================
// make colortab: zx-attr -> pc-attr

static void make_colortab(char flash_active)
{
// âî âðåìÿ ìèãàíèÿ ôëåøà òîæû âûçûâàåòñî !!
//printf("make_colortab\n");

    if (conf.flashcolor || conf.ula_plus)
        flash_active = 0;

    for (unsigned a = 0; a < 0x100; a++)        // a - zx-attr
    {
        unsigned char ink = a & 7;              //.....III
        unsigned char paper = (a >> 3) & 7;     //>>>..PPP ...
        unsigned char bright = (a >> 6) & 1;    //>>>>>>.B ......
        unsigned char flash = (a >> 7) & 1;     //>>>>>>>F .......

// if((conf.flashcolor && ink) || !conf.flashcolor)
        ink |= bright << 3;                     //....BIII

// if((conf.flashcolor && paper) || !conf.flashcolor)

        paper |= ( (conf.flashcolor || (conf.ula_plus && comp.ula_plus_en))  ?  flash :
                                                                                bright ) << 3;
       
//                                              //....FPPP - flash color / ula plus
//                                              //....BPPP - 6912

        //ink/paper swap
        if (flash_active && flash)
        {
            unsigned char t = ink;
            ink = paper;
            paper = t;
        }

        u8 color = u8((paper << 4) | ink);      // color - pc-attr

        colortab[a] = color;
        colortab_s8[a] = unsigned(color << 8U);
        colortab_s24[a] = unsigned(color << 24U);
    }

   if (conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3 || conf.mem_model == MM_ATM450)
        atm_zc_tables();        // update with new flash bit
}
//=============================================================================


//=============================================================================
// make attrtab: pc-attr + 0x100*pixel -> palette index

static void attr_tables()
{
    unsigned char flashcolor = (temp.rflags & RF_MON)? 0 : conf.flashcolor;
   
    for (unsigned a = 0; a < 0x100; a++)
    {
        unsigned char ink = (a & 0x0F), paper = u8(a >> 4);
        if (flashcolor)
            paper = (paper & 7) + (ink & 8);    // paper_bright from ink
               
        //---------------------------------------------------------------------
        if (temp.rflags & RF_GRAY)
        {
            // grayscale palette
            t.attrtab[a] =       paper * 16;
            t.attrtab[a+0x100] = ink   * 16;
        }
        //---------------------------------------------------------------------
        else if (temp.rflags & RF_COMPPAL)
        {
            // Ïàëèòðà â ôîðìàòå ULA+
            u8 paper_idx;               // fb1ppp
            u8 ink_idx;                 // fb0iii
           
            //-----------------------------------------------------------------
            if (comp.ula_plus_en)
            {
                u8 flash = (a & 0x80) >> 7;
                u8 bright = (a & 8) >> 3;
                paper &= 7;
                ink &= 7;
                u8 pal_no = u8(((flash << 1) | bright) << 4);
                paper_idx = u8(pal_no | 8 | paper);
                ink_idx   = u8(pal_no | 0 | ink);
            }
            //-----------------------------------------------------------------
            else
            {
                //ATM / profi palette
                //direct values from palette registers
                paper = a >> 4;
                ink = a & 0x0F;
                paper_idx = u8(((paper & 8) << 1) | (paper & 7));
                ink_idx = u8(((ink & 8) << 1) | (ink & 7));
            }
            //-----------------------------------------------------------------
            t.attrtab[a] =              comp.comp_pal[paper_idx];  // paper
            t.attrtab[a | 0x100] =      comp.comp_pal[ink_idx];    // ink
        }
        //---------------------------------------------------------------------
        else if (temp.rflags & RF_PALB)
        {
            //for bilinear
            unsigned char b0,b1, r0,r1, g0,g1;
            b0 = (paper >> 0) & 1;
            r0 = (paper >> 1) & 1;
            g0 = (paper >> 2) & 1;
            b1 = (ink   >> 0) & 1;
            r1 = (ink   >> 1) & 1;
            g1 = (ink   >> 2) & 1;

            if (flashcolor && (a & 0x80))
            {
                b1 += b0; r1 += r0; g1 += g0;
                r0 = b0 = g0 = 0;
            }
            else
            {
                b0 *= 2; r0 *= 2; g0 *= 2;
                b1 *= 2; r1 *= 2; g1 *= 2;
            }

            unsigned char br1 = (ink >> 3) & 1;
            if (r1) r1 += br1;
            if (g1) g1 += br1;
            if (b1) b1 += br1;

            unsigned char br0 = (paper >> 3) & 1;
            if (r0) r0 += br0;
            if (g0) g0 += br0;
            if (b0) b0 += br0;

            // palette index: gg0rr0bb
            t.attrtab[a+0x100]  = u8((g1 << 6) + (r1 << 3) + b1);
            t.attrtab[a]        = u8((g0 << 6) + (r0 << 3) + b0);
        }
        //---------------------------------------------------------------------
        else
        {
        // all others
       
            // palette index: ygrbYGRB
            if (flashcolor && (a & 0x80))
            {
                t.attrtab[a] = 0;
                t.attrtab[a+0x100] = u8(ink+(paper<<4));
            }
            else
            {
                t.attrtab[a] =       paper * 0x11; // p[3..0]:p[3..0] (óäâîåíèå)
                t.attrtab[a+0x100] = ink   * 0x11; // i[3..0]:i[3..0] (óäâîåíèå)
            }
        }
    }
}
//=============================================================================


//=============================================================================
static void p4bpp_tables()
{
    for (unsigned pass = 0; pass < 2; pass++)
    {
        for (unsigned bt = 0; bt < 0x100; bt++)
        {
            unsigned lf = ((bt >> 3) & 7) + ((bt >> 4) & 8);
            unsigned rt = (bt & 7) + ((bt >> 3) & 8);
            //-----------------------------------------------------------------
            if (temp.obpp == 8)
            {
                t.p4bpp8[pass][bt] =    (t.sctab8[pass][0x0F+0x10*rt] & 0xFFFF) +
                                        (t.sctab8[pass][0x0F+0x10*lf] & 0xFFFF0000);
            }
            //-----------------------------------------------------------------
            else if (temp.obpp == 16)
            {
                t.p4bpp16[pass][bt * 2 + 0] = t.sctab16[pass][0x03 + 4 * rt];
                t.p4bpp16[pass][bt * 2 + 1] = t.sctab16[pass][0x03 + 4 * lf];
            }
            //-----------------------------------------------------------------
            else /* if (temp.obpp == 32) */
            {
                t.p4bpp32[pass][bt * 2 + 0] = t.sctab32[pass][0x100 + rt];
                t.p4bpp32[pass][bt * 2 + 1] = t.sctab32[pass][0x100 + lf];
            }
            //-----------------------------------------------------------------
        }
    }
}
//=============================================================================


//=============================================================================
void atm_zc_tables()    // atm,profi screens (use normal zx-flash)
{
    for (unsigned pass = 0; pass < 2; pass++)
    {
        for (unsigned at = 0; at < 0x100; at++)
        {
            unsigned pc_attr = colortab[at];
            //-----------------------------------------------------------------
            if (temp.obpp == 8)
            {
                for(unsigned j = 0; j < 4; j++)
                {
                    t.zctab8ad[pass][at * 4 + j] = t.sctab8d[pass][pc_attr * 4 + j];
                }
            }
            //-----------------------------------------------------------------
            else if (temp.obpp == 16)
            {
                t.zctab16ad[pass][at] = t.sctab16d[pass][pc_attr];
                t.zctab16ad[pass][at + 0x100] = t.sctab16d[pass][pc_attr + 0x100];
            }
            //-----------------------------------------------------------------
            else /* if (temp.obpp == 32) */
            {
                t.zctab32ad[pass][at] = t.sctab32[pass][pc_attr];
                t.zctab32ad[pass][at + 0x100] = t.sctab32[pass][pc_attr + 0x100];
            }
            //-----------------------------------------------------------------
        }
    }

    // atm palette mapping (port out to palette index)
    for (unsigned i = 0; i < 0x100; i++)
    {
        unsigned v = i ^ 0xFF, dst;
       
        if (conf.mem_model == MM_ATM450)
        {
            // ATM1: --grbGRB => Gg0Rr0Bb
            dst =       ((v & 0x20) << 1) | // g
                        ((v & 0x10) >> 1) | // r
                        ((v & 0x08) >> 3) | // b
                        ((v & 0x04) << 5) | // G
                        ((v & 0x02) << 3) | // R
                        ((v & 0x01) << 1) ; // B
        }
        else
        {
            // ATM2: grbG--RB => Gg0Rr0Bb
            dst =       ((v & 0x80) >> 1) | // g
                        ((v & 0x40) >> 3) | // r
                        ((v & 0x20) >> 5) | // b
                        ((v & 0x10) << 3) | // G
                        ((v & 0x02) << 3) | // R
                        ((v & 0x01) << 1) ; // B
        }
       
        t.atm_pal_map[i] = dst;
    }
}
//=============================================================================


//=============================================================================
static void hires_sc_tables()  // atm,profi screens (use zx-attributes & flash -> paper_bright)
{
    for (unsigned pass = 0; pass < 2; pass++)
    {
        for (unsigned at = 0; at < 0x100; at++)
        {
            unsigned pc_attr = (at & 0x80) + (at & 0x38)*2 + (at & 0x40)/8 + (at & 7);
            //-----------------------------------------------------------------
            if (temp.obpp == 8)
                for (unsigned j = 0; j < 16; j++)
                    t.zctab8[pass][at*0x10+j] = t.sctab8[pass][pc_attr*0x10+j];
            //-----------------------------------------------------------------
            else if (temp.obpp == 16)
                for (unsigned j = 0; j < 4; j++)
                    t.zctab16[pass][at*4+j] = t.sctab16[pass][pc_attr*4+j];
            //-----------------------------------------------------------------
            else /* if (temp.obpp == 32) */
                for (unsigned j = 0; j < 2; j++)
                    t.zctab32[pass][at+0x100*j] = t.sctab32[pass][pc_attr+0x100*j];
            //-----------------------------------------------------------------
        }
    }
}
//=============================================================================


//=============================================================================
static void calc_noflic_16_32()
{
    unsigned at, pass;
    //-------------------------------------------------------------------------
    if (temp.obpp == 16)
    {
        for (pass = 0; pass < 2; pass++)
        {
            for (at = 0; at < 2*0x100; at++)
                t.sctab16d_nf[pass][at] = (t.sctab16d[pass][at] & temp.shift_mask)/2;
            for (at = 0; at < 4*0x100; at++)
                t.sctab16_nf[pass][at] = (t.sctab16[pass][at] & temp.shift_mask)/2;
            for (at = 0; at < 2*0x100; at++)
                t.p4bpp16_nf[pass][at] = (t.p4bpp16[pass][at] & temp.shift_mask)/2;
        }
    }
    //-------------------------------------------------------------------------
    if (temp.obpp == 32)
    {
        unsigned shift_mask = 0xFEFEFEFE;
        for (pass = 0; pass < 2; pass++)
        {
            for (at = 0; at < 2*0x100; at++)
                t.sctab32_nf[pass][at] = (t.sctab32[pass][at] & shift_mask)/2;
            for (at = 0; at < 2*0x100; at++)
                t.p4bpp32_nf[pass][at] = (t.p4bpp32[pass][at] & shift_mask)/2;
        }
    }
    //-------------------------------------------------------------------------
}
//=============================================================================


//=============================================================================
// pal.index => raw video data, shadowed with current scanline pass
static unsigned raw_data(unsigned index, unsigned pass, unsigned bpp)
{
    if (bpp == 8)
    {
        if (pass)
        {
            if (!conf.scanbright)
                return 0;
               
            // palette too small to realize noflic/atari with shaded scanlines
            if (conf.scanbright < 100 && !conf.noflic && !conf.atariset[0])
            {
                if (temp.rflags & RF_PALB)
                    index = (index & (index << 1) & 0x92) | ((index ^ 0xFF) & (index >> 1) & 0x49);
                else
                    index &= 0x0F;
            }
        }
        return index * 0x01010101;      // 4 òî÷êè (8bit)
    }

   unsigned r = pal0[index].peRed, g = pal0[index].peGreen, b = pal0[index].peBlue;

    if (pass)
    {
        r = r * conf.scanbright / 100;
        g = g * conf.scanbright / 100;
        b = b * conf.scanbright / 100;
    }
    //-------------------------------------------------------------------------
    if (bpp == 32)
        return WORD4(b,g,r,0);                                  // 1 òî÷êà (32bit)
    //-------------------------------------------------------------------------
    // else (bpp == 16)
    if (temp.hi15==0)
        return ((b/8) + ((g/4)<<5) + ((r/8)<<11)) * 0x10001;    // 2 òî÷êè (16bit)
    //-------------------------------------------------------------------------
    if (temp.hi15==1)
        return ((b/8) + ((g/8)<<5) + ((r/8)<<10)) * 0x10001;    // 2 òî÷êè (16bit)
    //-------------------------------------------------------------------------
    if (temp.hi15==2)
        return getYUY2(r,g,b);                                  // yuyv (32bit)
    //-------------------------------------------------------------------------
    return 0;
}
//=============================================================================


//=============================================================================
static unsigned atari_to_raw(unsigned at, unsigned pass)
{
    unsigned c1 = at/0x10, c2 = at & 0x0F;
    unsigned raw0 = raw_data(   t.attrtab[c1+0x100],
                                pass,
                                temp.obpp
                             );
    unsigned raw1 = raw_data(   t.attrtab[c2+0x100],
                                pass,
                                temp.obpp
                             );
    if (raw0 == raw1)
        return raw1;

    if (temp.obpp == 8)
        return (temp.rflags & RF_PALB)    ?     (0x49494949 & ((raw0&raw1)^((raw0^raw1)>>1))) |
                                                (0x92929292 & ((raw0&raw1)|((raw0|raw1)&((raw0&raw1)<<1))))
                                          :
                                                (0x0F0F0F0F & raw0) | (0xF0F0F0F0 & raw1);

    return (raw0 & temp.shift_mask)/2 + (raw1 & temp.shift_mask)/2;
}
//=============================================================================


//=============================================================================
void pixel_tables()
{
    attr_tables();
    for (unsigned pass = 0; pass < 2; pass++)
    {
        for (unsigned at = 0; at < 0x100; at++)
        {
            // Òî÷êà âûêëþ÷åíà (èíäåêñ ïàëèòðû ýìóëÿòîðà, ïàëèòðà 8[idx]->32[xrgb])
            unsigned px0 = t.attrtab[at];
            // Òî÷êà âêëþ÷åíà (èíäåêñ ïàëèòðû ýìóëÿòîðà, ïàëèòðà 8[idx]->32[xrgb])
            unsigned px1 = t.attrtab[at + 0x100];

            // 4 òî÷êè (îäèíàêîâûõ, ó÷åòâåðåíèå) äëÿ 8bpp
            // 2 òî÷êè (îäèíàêîâûõ, óäâîåíèå) äëÿ 16bpp
            // 1 òî÷êà äëÿ 32bpp
           
            // Òî÷êà âûêëþ÷åíà (äàííûå äëÿ pc âèäåîïàìÿòè)
            unsigned p0 = raw_data(     px0,
                                        pass,
                                        temp.obpp
                                   );
            // Òî÷êà âêëþ÷åíà (äàííûå äëÿ pc âèäåîïàìÿòè)          
            unsigned p1 = raw_data(     px1,
                                        pass,
                                        temp.obpp
                                   );

            //-----------------------------------------------------------------
            // sctab32 required for frame resampler in 16-bit mode, so temp.obpp=16 here
            // Âõîäíûå äàííûå 1 áèò
            //
            // Òî÷êà âûêëþ÷åíà (äàííûå äëÿ pc âèäåîïàìÿòè xrgb)
            t.sctab32[pass][at] = raw_data(     px0,
                                                pass,
                                                32
                                           );
            // Òî÷êà âêëþ÷åíà (äàííûå äëÿ pc âèäåîïàìÿòè xrgb)
            t.sctab32[pass][at + 0x100] = raw_data(     px1,
                                                        pass,
                                                        32
                                                   );
            //-----------------------------------------------------------------
            // 8 bit
            unsigned j;
            // j - Âõîäíûå äàííûå (çíà÷åíèå ÷/á ïèêñåëåé) 4áèòà (16 êîìáèíàöèé)
            for (j = 0; j < 0x10; j++)
            {
                unsigned mask = (j >> 3) * 0xFF + (j & 0x04)*(0xFF00 / 4) +
                                (j & 0x02)*(0xFF0000 / 2) + (j & 1) * 0xFF000000;
                // Äàííûå äëÿ pc âèäåîïàìÿòè 4 òî÷êè
                t.sctab8[pass][j + at * 0x10] = (mask & p1) + (~mask & p0);
            }
            //-----------------------------------------------------------------
            // j - Âõîäíûå äàííûå (çíà÷åíèå ÷/á ïèêñåëåé) 2áèòà (4 êîìáèíàöèè)
            for (j = 0; j < 4; j++)
            {
                unsigned mask = (j >> 1) * 0xFFFF + (j & 1) * 0xFFFF0000;
                // Äàííûå äëÿ pc âèäåîïàìÿòè 2 òî÷êè ñ óäâîåíèåì
                t.sctab8d[pass][j + at * 4] = (mask & p1) + (~mask & p0);
            }
            //-----------------------------------------------------------------
            // Âõîäíûå äàííûå (çíà÷åíèå ÷/á ïèêñåëåé) 1áèò (2 êîìáèíàöèè)
               
                // Äàííûå äëÿ pc âèäåîïàìÿòè 1 òî÷êà ñ ó÷åòâåðåíèåì
                t.sctab8q[at] = p0; t.sctab8q[at + 0x100] = p1;
            //-----------------------------------------------------------------
            // 16 bit
            // j - Âõîäíûå äàííûå (çíà÷åíèå ÷/á ïèêñåëåé) 2áèòà (4 êîìáèíàöèè)
            for (j = 0; j < 4; j++)
            {
                unsigned mask = (j >> 1) * 0xFFFF + (j & 1) * 0xFFFF0000;
                // Äàííûå äëÿ pc âèäåîïàìÿòè 2 òî÷êè
                t.sctab16[pass][j + at * 4] = (mask & p1) + (~mask & p0);
            }
            //-----------------------------------------------------------------
            // Âõîäíûå äàííûå (çíà÷åíèå ÷/á ïèêñåëåé) 1áèò (2 êîìáèíàöèè)
               
                // Äàííûå äëÿ pc âèäåîïàìÿòè 1 òî÷êà ñ óäâîåíèåì
                t.sctab16d[pass][at] = p0; t.sctab16d[pass][at + 0x100] = p1;
            //-----------------------------------------------------------------
            unsigned atarimode;
            if (!(temp.rflags & RF_MON) && (atarimode = temp.ataricolors[at]))
            {
                unsigned rawdata[4], i;
                //-------------------------------------------------------------
                for (i = 0; i < 4; i++)
                {
                    rawdata[i] = atari_to_raw(  (atarimode >> (8 * i)) & 0xFF,
                                                pass
                                              );
                }
                //-------------------------------------------------------------
                for (i = 0; i < 16; i++)
                {
                    t.sctab8[pass][at * 0x10 + i] = rawdata[i / 4] + 16 * rawdata[i & 3];
                }
                //-------------------------------------------------------------
                for (i = 0; i < 4; i++)
                {
                    t.sctab8d[pass][at * 4 + i] = rawdata[i];
                }
                //-------------------------------------------------------------
                for (i = 0; i < 4; i++)
                {
                    t.sctab16[pass][at * 4 + i] = rawdata[i];
                }
                //-------------------------------------------------------------
            }
        }
    }
    //-------------------------------------------------------------------------

    p4bpp_tables();     // used for ATM2+ mode0 and Pentagon-4bpp

    //-------------------------------------------------------------------------
    if (temp.obpp > 8 && conf.noflic)
    {
        calc_noflic_16_32();
    }
    //-------------------------------------------------------------------------
    if (    (   ( temp.rflags & (RF_DRIVER | RF_2X | RF_USEFONT) ) == (RF_DRIVER | RF_2X)
             )
            && // render="double"
            (   (conf.mem_model == MM_ATM450)   ||
                (conf.mem_model == MM_ATM710)   ||
                (conf.mem_model == MM_ATM3)     ||
                (conf.mem_model == MM_PROFI)
             )
      )
    {
        hires_sc_tables();
    }
    //-------------------------------------------------------------------------
   
   
   
    //-----------------------------------------------------------------------------
    // DDp ïàëèòðà !!!!!!!!
   
    if (conf.ATM_DDp_4K_Palette != 0) // [NS]
    {
        //added by Alone Coder 04.12.2021 (no ULAplus!!! no default palette!!! ATM3 only!!!):
        if (    (conf.mem_model == MM_ATM3)     &&              //NEDOREPO
                ((comp.pBF & 0x20) != 0)
          )        
        {
            PALETTE_OPTIONS *pl = &pals[conf.pal];
           
            //colorindex = comp.border_attr;
            for (u8 colorindex = 0; colorindex < 16; colorindex++) //çóáîäðîáèòåëüíûé àëîíîêîä
            {
                unsigned r0, g0, b0;
                u16 atm3color = comp.atm3_pal[colorindex];
                r0 = (((atm3color>>1)<<3)&8) + (((atm3color>>6)<<2)&4) + (((atm3color>>9)<<1)&2) + ((atm3color>>14)&1);
                g0 = (((atm3color>>4)<<3)&8) + (((atm3color>>7)<<2)&4) +(((atm3color>>12)<<1)&2) + ((atm3color>>15)&1);
                b0 = (((atm3color>>0)<<3)&8) + (((atm3color>>5)<<2)&4) + (((atm3color>>8)<<1)&2) + ((atm3color>>13)&1);
                r0 = (r0^15) * 17;      //0..255
                g0 = (g0^15) * 17;      //0..255
                b0 = (b0^15) * 17;      //0..255
                unsigned r = 0xFF & ((r0 * pl->r11 + g0 * pl->r12 + b0 * pl->r13) / 0x100); //pl->r11 etc. = 0..0x100
                unsigned g = 0xFF & ((r0 * pl->r21 + g0 * pl->r22 + b0 * pl->r23) / 0x100);
                unsigned b = 0xFF & ((r0 * pl->r31 + g0 * pl->r32 + b0 * pl->r33) / 0x100);
               
                // prepare palette in bitmap header for GDI renderer
                /*             
                gdibmp.header.bmiColors[colorindex].rgbRed = pal0[colorindex].peRed = BYTE(r);
                gdibmp.header.bmiColors[colorindex].rgbGreen = pal0[colorindex].peGreen = BYTE(g);
                gdibmp.header.bmiColors[colorindex].rgbBlue = pal0[colorindex].peBlue = BYTE(b);
                setpal(0);
                */

                u32 rgb = (r<<16) + (g<<8) + b;
                //pixels in EGA are shown in order "ink","paper" (%PIpppiii) with this code (src[] is ZX Spectrum memory):
                //        d[x+0]  = d[x+1]  = tab[0+2*src[ega0_ofs + src_offset]]; //"ink" pixel
                //        d[x+2]  = d[x+3]  = tab[1+2*src[ega0_ofs + src_offset]]; //"paper" pixel
                //unsigned *tab = t.p4bpp32[0] (even lines) or [1] (odd lines);
               
                u8 inkindex = (colorindex&7) + ((colorindex&8)<<3);
               
                for (u8 paper = 0; paper < 16; paper++)
                {
                    u8 paperindex = ((paper&7)<<3) + ((paper&8)<<4);
                    t.p4bpp32[0][0+2*(inkindex+paperindex)] = rgb;      //"ink" pixel (even lines)
                    t.p4bpp32[1][0+2*(inkindex+paperindex)] = rgb;      //"ink" pixel (odd lines)
                }
               
                u8 paperindex = ((colorindex&7)<<3) + ((colorindex&8)<<4);
               
                for (u8 ink = 0; ink < 16; ink++)
                {
                   u8 inkindex = (ink&7) + ((ink&8)<<3);
                   t.p4bpp32[0][1+2*(inkindex+paperindex)] = rgb; //"paper" pixel (even lines)
                   t.p4bpp32[1][1+2*(inkindex+paperindex)] = rgb; //"paper" pixel (odd lines)
                }
            }
        }
    } // ATM_DDp_4K_Palette
       
//-----------------------------------------------------------------------------
   
} // pixel_tables()

//=============================================================================




//=============================================================================
void video_color_tables()
{
    temp.shift_mask = 0xFEFEFEFE;       // 32bit, 16bit YUY2
    if (temp.obpp == 16 && temp.hi15==0) temp.shift_mask = 0xF7DEF7DE;
    if (temp.obpp == 16 && temp.hi15==1) temp.shift_mask = 0x7BDE7BDE;

    create_palette();
    pixel_tables();
    make_colortab(0);

    if (temp.rflags & (RF_USEC32 | RF_USE32AS16))
    {
        for (unsigned at = 0; at < 0x100; at++)
        {
            for (unsigned vl = 0; vl <= 0x10; vl++)
            {
                unsigned br = (at & 0x40) ?     0xFF :
                                                0xBF ;
                unsigned c1, c2, res;
                c1 = (at & 1) >> 0;
                c2 = (at & 0x08) >> 3;
                unsigned b = (c1*vl + c2*(0x10-vl))*br/0x10;
               
                c1 = (at & 2) >> 1;
                c2 = (at & 0x10) >> 4;
                unsigned r = (c1*vl + c2*(0x10-vl))*br/0x10;
               
                c1 = (at & 4) >> 2;
                c2 = (at & 0x20) >> 5;
                unsigned g = (c1*vl + c2*(0x10-vl))*br/0x10;
               
                if (temp.rflags & RF_USE32AS16)
                {
                    if (temp.hi15 == 0) res = (b/8) + ((g/4)<<5) + ((r/8)<<11);
                    if (temp.hi15 == 1) res = (b/8) + ((g/8)<<5) + ((r/8)<<10);
                    if (temp.hi15 == 2)
                        res = getYUY2(r,g,b);
                    else
                        res *= 0x10001; // for hi15=0,1
                }
                else
                {
                    res =  WORD4(b,g,r,0);
                }
               
                t.c32tab[at][vl] = res;
            }
        }
    }
   
    setpal(0);
}
//=============================================================================


//=============================================================================
void video_timing_tables()
{
// ïðè èíèöèàëèçàöèè è ñìåíå âèäåîäðàéâåðà
// ïðè ñìåíå íàñòðîåê

        //printf("video_timing_tables()\n");

    if (conf.frame < 2000)      //!!!!!!!!!!!
    {
        conf.frame = 2000;
        cpu.SetTpi(conf.frame);
    }
    if (conf.t_line < 128) conf.t_line = 128;
   
    conf.nopaper &= 1;
    atrtab = (comp.pEFF7 & EFF7_HWMC) ? t.atrtab_hwmc   :
                                        t.atrtab        ;

//   conf.bordersize=2;
//   temp.scx = 384, temp.scy = 300;


    // Ïåðåâîä âåëè÷èíû â ïèêñåëÿõ â ÷èñëî çíàêîìåñò ñ ó÷åòîì àòðèáóòîâ
    // (êàæäîå çíàêîìåñòî çàíèìàåò 2 áàéòà, áàéò äàííûõ è áàéò àòðèáóòîâ)

#define p2cc(p) ((p)/4)

    // Øèðèíà ýêðàíà â çíàêîìåñòàõ * 2 (ò.ê. èñïîëüçóþòñÿ ïèêñåëè è àòðèáóòû íà 1 çíàêîìåñòî)
    const unsigned width = p2cc(temp.scx);
    //temp.vidbufsize = temp.scx*temp.scy/4;

    // make video table
    unsigned mid_lines = 192;           // ×èñëî ñòðîê â öåíòðàëüíîé ÷àñòè ýêðàíà (áåç áîðäþðà)
    const unsigned buf_mid = 256;       // ×èñëî ïèêñåëåé â öåíòðàëüíîé ÷àñòè ýêðàíà (áåç áîðäþðà)

    //-------------------------------------------------------------------------
    // Ðàñ÷åò ðàçìåð áîðäþðà â ïèêñåëÿõ (1 ïèêñåëü = 2 òàêòà)
    temp.b_bottom = temp.b_top = conf.b_top_small;
    temp.b_left = conf.b_left_small;                            // border small
    //-------------------------------------------------------------------------
    if (conf.bordersize == 0)                                   // border none
    {
        temp.b_top = temp.b_left = 0;
    }
    //-------------------------------------------------------------------------
    if (conf.bordersize == 2)                                   // border wide
    {
        temp.b_top = conf.b_top_full;
        temp.b_left = conf.b_left_full;
    }
    //-------------------------------------------------------------------------
    if (conf.bordersize == 3)           // border full  // òê ðàçìåðû ïî X íóæíû êðàòíûå 8
    {                                   // [NS]         // òî íåëüçÿ îòîáðàçèòü ïðàâèëüíûé ðàçìåð
                                        //              // äîáàâëÿÿ ñëåâà îòúåäàåòñî ÷àñòü èçîáðàæåíèÿ ñïðàâà
                                        //              // ïîýòîìó èçîáðàæåíèå çàäàåòñî ñ çàïàñîì ñî âñåõ ñòîðîí
                                        //              // è âèäíî ìóñîð
                                        //              // ìîæåò âáóäóõùåì íåâàëèäíàÿ ÷àñòü áóäåò çàòèðàòñî ïîâåðõ
                                        //              // òàê æå 16ñ ðåæèìû ðèñóþò ìèìî !!!!!!111
//      temp.b_top = (conf.paper / conf.t_line) + 2;
//      temp.b_left = (((conf.paper % conf.t_line) & 0x07 ) == 0)   ?   (conf.paper % conf.t_line)              :
//                                                                      (((conf.paper % conf.t_line) | 0x07)+1) ;
//   conf.paper = GetPrivateProfileInt(ula, "Paper", 17989, ininame);
// 17989 / 224 = 80,308035714285714285714285714286 y
// 17989 % 224 = 69,000000000000000000000000000064 ??? x

        temp.b_top = 84;
        temp.b_left = 128;
    }
    //-------------------------------------------------------------------------
   
        //printf("temp.b_top %d\n",temp.b_top);
        //printf("temp.b_left %d\n",temp.b_left);
       



   // temp.scx - ÷èñëî òî÷åê â ìóëüòèêîëîðå ïî ãîðèçîíòàëè
   // temp.scy - ÷èñëî ñòðîê â ìóëüòèêîëîðå
   // 256x192 - border none
   // 320x240 - border small
   // 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)))

    // Ðàñ÷åò ðàçìåðà ïðàâîé ÷àñòè áîðäþðà â ïèêñåëÿõ (1 ïèêñåëü = 1/2 òàêòà)
    temp.b_right = temp.scx - buf_mid - temp.b_left;
    // Ðàñ÷åò ðàçìåðà íèæíåé ÷àñòè áîðäþðà â ïèêñåëÿõ (1 ïèêñåëü = 1/2 òàêòà)
    temp.b_bottom = temp.scy - mid_lines - temp.b_top;

    //-------------------------------------------------------------------------
    // Ðåæèì nopaper (ðàñòð â ñåðåäèíå ýêðàíà îòñóòñòâóåò)
    if (conf.nopaper)
    {
        temp.b_bottom += mid_lines;
        mid_lines = 0;
    }
    //-------------------------------------------------------------------------
   
   
   
    //-------------------------------------------------------------------------
    int inx = 0;

    unsigned i;
   
#define ts(t) (((int)(t) < 0) ? 0 : t)

// Ïåðåâîä ïèêñåëåé â òàêòû
#define p2t(p) ((p)/2)

    // conf.paper - ×èñëî òàêòîâ îò íà÷àëà ðàñòðà äî öåíòðàëüíîé ÷àñòè spectrum ýêðàíà
    // (âêëþ÷àåò íåâèäèìóþ ÷àñòü + ïîëíîñòüþ âåðõíèé áîðäþð + íà÷àëî ñòðîêè øèðèíîé hblank + ëåâûé áîðäþð)
    // Äëÿ pentagon 128: (16+64)*(32+36+128+28)+32+36 = 17988 òàêòîâ
    // 16 ñòðîê íàä âåðõíèì áîðäþðîì
    // 64 ñòðîêè - âåðõíèé áîðäþð
    // êàæäàÿ ñòðîêà 224 òàêòà:
    // 32 òàêòà hblank
    // 36 òàêòîâ - ëåâûé áîðäþð
    // 128 òàêòîâ - öåíòð ýêðàíà
    // 28 òàêòîâ - ïðàâûé áîðäþð
   
    // ×èñëî òàêòîâ äî íà÷àëà âåðõíåãî áîðäþðà (âêëþ÷àÿ hblank + ëåâûé áîðäþð â ïåðâîé ñòðîêå paper)
    unsigned t = conf.paper - temp.b_top*conf.t_line;
    // ×èñëî òàêòîâ â hblank
    const unsigned hblank = conf.t_line - p2t(temp.scx);
    // Èñêëþ÷åíèå ëåâîãî áîðäþðà (next_t - òàêò íà÷àëà ïåðâîé ñòðîêè âåðõíåãî áîðäþðà)
    video[inx++].next_t = ts(t - p2t(temp.b_left));

//   printf("btop: temp.b_top=%u, conf.b_top_full=%u\n", temp.b_top, conf.b_top_full);

    //-------------------------------------------------------------------------
    // âåðõíèé áîðäþð
    for (i = 0; i < temp.b_top; i++)
    {
   
        // Êîíåö ïðàâîãî áîðäþðà (òàêò êîíöà òåêóùåé ñòðîêè)
        video[inx].next_t = ts(t + p2t(buf_mid+temp.b_right));
        // Óêàçàòåëü íà íà÷àëî òåêóùåé ñòðîêè â áóôåðå îòðèñîâêè
        video[inx].screen_ptr = rbuf+width*i;
        // hblank (ïåðåõîä ê íîâîé ñòðîêå)
        video[inx].nextvmode = 0;      
       
// printf("%3u: b=%u, e=%u, o=%u\n", i, video[inx-1].next_t, video[inx].next_t, width*i);

        // Ïåðåõîä ê ñëåäóþùåé ñòðîêå (t - òàêò íà÷àëà paper ñëåäóþùåé ñòðîêè hblank + ëåâûé áîðäþð)
        inx++; t += conf.t_line;
        // Èñêëþ÷åíèå ëåâîãî áîðäþðà (òàêò íà÷àëà ëåâîãî áîðäþðà íà ñëåäóþùåé ñòðîêå)
        video[inx++].next_t = ts(t - p2t(temp.b_left));
    }
    //-------------------------------------------------------------------------
   
//   printf("paper:\n");

    //-------------------------------------------------------------------------
    // hblank + ëåâûé áîðäþð + ýêðàí + ïðàâûé áîðäþð
    for (i = 0; i < mid_lines; i++)
    {  
        // Êîíåö ëåâîãî áîðäþðà (òàêò íà÷àëà paper íà òåêóùåé ñòðîêå)
        video[inx].next_t = ts(t);
        // Óêàçàòåëü íà íà÷àëî ié ñòðîêè ëåâîãî áîðäþðà â áóôåðå îòðèñîâêè
        video[inx].screen_ptr = rbuf+width*(i+temp.b_top);
        // Äàëåå ïðîðèñîâûâàåòñÿ paper
        video[inx].nextvmode = 2;
// printf("%3u: b=%u ", i, video[inx-1].next_t);
        inx++;
        //---------------------------------------------------------------------
        // Êîíåö paper (òàêò íà÷àëà ïðàâîãî áîðäþðà íà òåêóùåé ñòðîêå)
        video[inx].next_t = ts(t + p2t(buf_mid));
        // Óêàçàòåëü íà íà÷àëî ié ñòðîêè paper â áóôåðå îòðèñîâêè
        video[inx].screen_ptr = rbuf+width*(i+temp.b_top)+p2cc(temp.b_left);
        // Ñìåùåíèå îò íà÷àëà zx ýêðàíà (ïèêñåëè)
        video[inx].scr_offs = ::t.scrtab[i];
        // Ñìåùåíèå îò íà÷àëà çîíû àòðèáóòîâ zx ýêðàíà
        video[inx].atr_offs = atrtab[i];
        inx++;
        //---------------------------------------------------------------------
        // Êîíåö ïðàâîãî áîðäþðà (òàêò êîíöà òåêóùåé ñòðîêè)
        video[inx].next_t = ts(t + p2t(buf_mid+temp.b_right));
        // Óêàçàòåëü íà íà÷àëî ié ñòðîêè ïðàâîãî áîðäþðà â áóôåðå îòðèñîâêè
        video[inx].screen_ptr = rbuf+width*(i+temp.b_top)+p2cc(buf_mid+temp.b_left);
        // hblank (ïåðåõîä ê íîâîé ñòðîêå)
        video[inx].nextvmode = 0;      

// printf("e=%u\n", video[inx].next_t);

        // Ïåðåõîä ê ñëåäóþùåé ñòðîêå (t - òàêò íà÷àëà paper ñëåäóþùåé ñòðîêè hblank + ëåâûé áîðäþð)
        inx++;          t += conf.t_line;
        // Èñêëþ÷åíèå ëåâîãî áîðäþðà (òàêò íà÷àëà ñëåäóþùåé ñòðîêè)
        video[inx++].next_t = ts(t - p2t(temp.b_left));
    }
    //-------------------------------------------------------------------------
   
//   printf("bbot:\n");

    //-------------------------------------------------------------------------
    // íèæíèé áîðäþð
    for (i = 0; i < temp.b_bottom; i++)
    {
        // Êîíåö ïðàâîãî áîðäþðà (òàêò êîíöà òåêóùåé ñòðîêè)
        video[inx].next_t = ts(t + p2t(buf_mid+temp.b_right));
        // Óêàçàòåëü íà íà÷àëî ié ñòðîêè íèæíåãî áîðäþðà â áóôåðå îòðèñîâêè
        video[inx].screen_ptr = rbuf+width*(i+temp.b_top+mid_lines);
        // hblank (ïåðåõîä ê íîâîé ñòðîêå)
        video[inx].nextvmode = 0;
       
// printf("%3u: b=%u, e=%u\n", i, video[inx-1].next_t, video[inx].next_t);

        // Ïåðåõîä ê ñëåäóþùåé ñòðîêå (t - òàêò íà÷àëà paper ñëåäóþùåé ñòðîêè hblank + ëåâûé áîðäþð)
        inx++;          t += conf.t_line;
        // Èñêëþ÷åíèå ëåâîãî áîðäþðà (òàêò íà÷àëà ñëåäóþùåé ñòðîêè)
        video[inx++].next_t = ts(t - p2t(temp.b_left));
   }
   //-------------------------------------------------------------------------
   
    video[inx-1].next_t = 0x7FFFFFFF;   // Ïðèçíàê ïîñëåäíåé ñòðîêè
//   exit(0);

    temp.evenM1_C0 = conf.even_M1    ?  0xC0 :
                                        0x00;
    temp.border_add = conf.border_4T ?  6 :
                                        0;
    temp.border_and = conf.border_4T ?  0xFFFFFFFC :
                                        0xFFFFFFFF;

    //-------------------------------------------------------------------------
    for (i = 0; i < NUM_LEDS; i++)
    {
        unsigned z = *(&conf.led.ay + i);
   
        int x = (signed short)(z & 0xFFFF);
        int y = (signed short)(((z >> 16) & 0x7FFF) + ((z >> 15) & 0x8000));
        //printf("leds convert??? %X %X %X\n",z,x,y);
        if (x < 0) x += width * 8;
        if (y < 0) y += temp.scy;
        *(&temp.led.ay + i) = (z & 0x80000000)    ?     rbuf + ( (x >> 2) & 0xFE ) + unsigned(y) * width :
                                                        nullptr;
      //printf("leds convert??? %X\n",*(&temp.led.ay+i));
    }
    //-------------------------------------------------------------------------
      //printf("\n");
     
    if (temp.rflags & RF_USEFONT)
        create_font_tables();

    needclr = 2;
}
//=============================================================================



//=============================================================================
//void set_video()
void set_video( bool preserve_size)
{
// bool preserve_size = FALSE by default
//   printf("%s\n", __FUNCTION__);
//    set_vidmode();
    set_vidmode( preserve_size);        // preserve size tezt
    video_color_tables();
}
//=============================================================================



//=============================================================================
// void apply_video()
void apply_video( bool preserve_size)                                   // [NS]
{
// bool preserve_size = FALSE by default !!!!

//   printf("%s\n", __FUNCTION__);
    load_ula_preset();

    //-------------------------------------------------------------------------
    if (        (conf.mem_model == MM_ATM710)   ||
                (conf.mem_model == MM_ATM3)     ||
                (conf.mem_model == MM_ATM450)   ||
                (conf.mem_model == MM_PROFI)
      )
    {
        // Äëÿ ìîäåëåé ñ ýêðàíîì 640x200 ïîääåðæèâàåòñÿ òîëüêî redner = double (640x480)
        conf.render = 1;        //"double" - RENDER renders[] â dx.cpp
        printf("Force <double> video filter\n");
        //      âðîäå íå ïðèâîäèò ê ïàäåíèÿì
        //      ÍÎ íè÷åãî íå îòîáðàæàåòñî ïðè ýòîì â ðàñøèðåíîì ðåæèìå

        // [NS] çàïóñê ÀÒÌ âèäåî ðåæèìîâ â ðåæèìå áåç áîðäþðà
        // ìîæåò âîîáùå âûçâàòü ïàäåíèå äðàéâåðà âèäþõè íàõ!
        //      ïî õîðîøåìó íàäî âêëþ÷àòü òîëüêî êîãäà ðàáîòàåò ýòîò âèäåî ðåæèì !!!
        if (!conf.bordersize)
        {
            conf.bordersize = 1;
            printf("Force <Small> border\n");
        }
    }
    //-------------------------------------------------------------------------
   
    temp.rflags = renders[ conf.render].flags;
   
    //-------------------------------------------------------------------------
    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)
                               )
      )
    {
        temp.rflags |= ( RF_COMPPAL | RF_PALB );
       
        // disable palette noflic, only if it is really used
        if (  (temp.obpp == 8)  &&  ( (temp.rflags & (RF_DRIVER | RF_USEFONT | RF_8BPCH) ) == RF_DRIVER)  )
            conf.noflic = 0;
    }
    //-------------------------------------------------------------------------
    if (conf.ula_plus/* && comp.ula_plus_en*/)
    {
        temp.rflags |= RF_COMPPAL | RF_PALB;
    }
    //-------------------------------------------------------------------------
    if (renders[conf.render].func == render_rsm)
        conf.flip = 1;  // todo: revert back after returning from frame resampler //Alone Coder
  //-------------------------------------------------------------------------
    if (renders[ conf.render].func == render_advmame)
    {
        if (conf.videoscale == 2)       temp.rflags |= RF_2X;
        if (conf.videoscale == 3)       temp.rflags |= RF_3X;
        if (conf.videoscale == 4)       temp.rflags |= RF_4X;
    } //Alone Coder
    //-------------------------------------------------------------------------
   
    set_video( preserve_size);
   
    calc_rsm_tables();
   
    video_timing_tables();
}
//=============================================================================



//=============================================================================
//__inline unsigned char *raypointer()  // ýòî ðàçîâàÿ ôóíêöèÿ [NS]
unsigned char *raypointer()             // åé ñîâåðøåííî íå íóæíî áûòü inline
{                                       // è ïðè ýòîì åå íàäî âûçûâàòü èç äðóãèõ ôàéëîâ
    //-------------------------------------------------------------------------
    if (prev_t > conf.frame)
    {
        return rbuf + rb2_offs;
    }
    //-------------------------------------------------------------------------
    if (!vmode)
    {
        return vcurr[1].screen_ptr;
    }
    //-------------------------------------------------------------------------
    unsigned offs = (prev_t - vcurr[-1].next_t) / 4;
//  prev_t è vcurr[-1].next_t áîëüøå íå îáíîâëÿþòñî ïîñëå êîíöà ôðåéìà â äåáàãåðå!!!

//  printf("offs %d             prev_t %d       vcurr[-1].next_t %d\n",offs,prev_t,vcurr[-1].next_t);  
    return vcurr->screen_ptr + (offs+1) * 2;
    //-------------------------------------------------------------------------

}
//=============================================================================



//=============================================================================
// ìåðçñêàÿ ñòèðàëêà "ïîñëå ëó÷à"
// äëÿ ïîêàçà â äåáàãåðå

__inline void clear_until_ray()
{    
    unsigned char *dst = raypointer();
   
    //printf ("ray_addr %x\n",dst);
    while (dst < rbuf + rb2_offs)
    {
        //*dst++ = 0;   //px
        //*dst++ = 0x55;        //attr

        // åäèíñòâåííîå ÷òî ìîæíî ñäåëàòü ñ ýòèì ãàôíîì         // [NS]
        // invert                              
        //*dst = ~(*dst);       //px
        dst++;
        *dst = ~(*dst);         //attr
        dst++;
    }
}
//=============================================================================




//=============================================================================
void paint_scr( char alt)       // alt=0/1 - main/alt screen,
{                               // alt=2 - ray-painted

// âûçûâàåòñÿ ïðè îòðèñîâêè îêíà â äåáàãåðå
// printf("paint_scr ");

    //-------------------------------------------------------------------------
    if (alt == 2)
    {
        update_screen();
        clear_until_ray();
    }
    //-------------------------------------------------------------------------
    else
    {
        //---------------------------------------------------------------------
        if (alt)
        {
            comp.p7FFD ^= 8;    // ëîëøòî îíî ÷òî äåðãàåò áàíêè äëÿ îòðèñîâêè?
            set_banks();
        }
        //---------------------------------------------------------------------
        draw_screen();
        //---------------------------------------------------------------------
        if (alt)
        {
            comp.p7FFD ^= 8;
            set_banks();
        }
        //---------------------------------------------------------------------
    }
}
//=============================================================================



//=============================================================================
// Âûçûâàåòñÿ ïðè çàïèñè â âèäåîïàìÿòü/(ïîðòû FE/7FFD) íîâîãî çíà÷åíèÿ
// Ïðîèçâîäèò îòðèñîâêó áîðäþðà/ýêðàíà â ïðîìåæóòî÷íûé áóôåð ñ èñïîëüçîâàíèåì pc àòðèáóòîâ

// êòîæ äîäóìàëñî òàêîå äåëîòü...

void update_screen()
{
//printf("update_screen() ");

    unsigned last_t = (cpu.t + temp.border_add) & temp.border_and;
    unsigned t = prev_t;

// Âûïîëíÿåòñÿ îòðèñîâêà îò ïîñëåäíåãî îòðèñîâàííîãî òàêòà prev_t äî òåêóùåãî îêðóãëåííîãî òàêòà last_t
//   printf("upd_scr: t=%u, lt=%u, vm=%u\n", t, last_t, vmode);
   
    // Íåâèäèìàÿ ÷àñòü ñòðîêè (hblank ëèáî íåâèäèìûå ñòðîêè âåðõíåãî áîðäþðà)
    if (t >= last_t)
        return; // [NS] áåç ýòîãî óíðèàë ìîæîò êðàøèòñî ñ çàïèñüþ â íåòóäà

    unsigned char b = comp.border_attr;
    b |= (b<<4); // Àòðèáóòû áîðäþðà äóáëèðóþòñÿ â ôîðìàòå pc àòðèáóòîâ ink=paper

    if (vmode == 1)
    {
        goto mode1; // border
    }

    if(vmode == 2) // screen
    {
        goto mode2;
    }

//-----------------------------------------------------------------------------
mode0: // not visible
    {
        vmode = 1;
        t = vcurr->next_t;      // Òàêò íà÷àëà ñòðîêè
        vcurr++;                // Ïåðåõîä ê êîíöó ñòðîêè
     
        if (t >= last_t)
        {
done:
            prev_t = t;         // Ïîñëåäíèé îòðèñîâàííûé òàêò
            return;
        }
    }
//-----------------------------------------------------------------------------
mode1: // border
    {
        // Ñìåùåíèå â òàêòàõ îò íà÷àëà ñòðîêè (1 òàêò = 2 ïèêñåëÿ)
        unsigned offs = (t - vcurr[-1].next_t);
        // Óêàçàòåëü íà àäðåñ òî÷êè â ïðîìåæóòî÷íîì áóôåðå (ñòðóêòóðà áóôåðà 8pix:attr)
        unsigned char *ptr = vcurr->screen_ptr + offs/2;
//      u8 *pp =ptr;
        ptr = (unsigned char*)(ULONG_PTR(ptr) & ~ULONG_PTR(1)); // Âûðàâàíèå äî ÷åòíîãî àäðåñà
       
        //---------------------------------------------------------------------
        if (offs & 3)
        {
            // Ñìåíà öâåòà áîðäþðà ïðîèçîøëà íå ïî ãðàíèöå çíàêîìåñòà
            // (äâà öâåòà áîðäþðà âíóòðè îäíîãî çíàêîìåñòà, ýìóëèðóþòñÿ ÷åðåç ink/paper)
            //
            u8 old_b = (ptr[1] & 0x0F);
            if (old_b ^ (b & 0xF))
            {
                // Öâåò áîðäþðà èçìåíèëñÿ ïî ñðàâíåíèþ ñ ïðåäûäóùèì
                //
                // Ìàñêà ïèêñåëåé (äëÿ 1 - èñïîëüçóåòñÿ öâåò ink, äëÿ 0 - paper)
                u8 mask = u8((unsigned)0xFF00 >> ((offs & 3) * 2));
                *ptr = mask;
                ptr++;
                t += 4 - (offs & 3);
                // Àòðèáóòû (ink - ñòàðûé öâåò áîðäþðà, paper - òåêóùèé öâåò áîðäþðà)
                *ptr = old_b | (b & 0xF0);
                ptr++;
            }
        }
        //---------------------------------------------------------------------
        unsigned end = min(vcurr->next_t, last_t);
       
// printf("upd_scr_m1: o=%uT, p=%u, t=%uT, end=%uT\n", offs, pp - rbuf, t, end);

        //---------------------------------------------------------------------
        // Îáðàáîòêà ïèêñåëåé ïî çíàêîìåñòàì (ïî 8 òî÷åê)
        for (; t < end; t+=4)
        {
            *ptr++ = 0; // Ïèêñåëè íå èñïîëüçóþòñÿ
            *ptr++ = b; // Àòðèáóòû
        }
        //---------------------------------------------------------------------
        t = end;
        //---------------------------------------------------------------------
        // Ñòðîêà çàêîí÷èëàñü,  ïåðåõîä ê ñëåäóþùåé òî÷êå
        if (t == vcurr->next_t)
        {
            vmode = vcurr->nextvmode;
            vcurr++;
        }
        //---------------------------------------------------------------------
        // Îòðèñîâêà çàêîí÷åíà, âûõîä
        if (t == last_t)
            goto done;
        //---------------------------------------------------------------------
        // Íà÷àëî ñëåäóþùåé ñòðîêè
        if (!vmode)
            goto mode0;
        //---------------------------------------------------------------------
    }
//-----------------------------------------------------------------------------
mode2: // screen
    {
        // Ñìåùåíèå â çíàêîìåñòàõ îò íà÷àëà ñòðîêè (1 çíàêîìåñòî = 4 òàêòà = 8 ïèêñåëåé)
        unsigned offs = (t - vcurr[-1].next_t)/4;
        // spectrum ïèêñåëè
        unsigned char *scr = temp.base + vcurr->scr_offs + offs;       
        // spectrum àòðèáóòû
        unsigned char *atr = temp.base + vcurr->atr_offs + offs;
        // Ñòðóêòóðà áóôåðà 8pix:attr
        unsigned char *ptr = vcurr->screen_ptr + offs*2;
       
        unsigned end = min(last_t, vcurr->next_t);
       
        //---------------------------------------------------------------------
        for (int i = 0; t < end; t += 4, i++)
        {
            // Êîïèðîâàíèå spectrum ïèêñåëåé
            ptr[2*i] = scr[i];
            // Êîíâåðòèðîâàíèå spectrum àòðèáóòîâ â pc àòðèáóòû
            ptr[2*i+1] = colortab[atr[i]];
        }
        //---------------------------------------------------------------------
        t = end;
        //---------------------------------------------------------------------
        // Öåíòðàëüíàÿ ÷àñòü ýêðàíà çàêîí÷èëàñü, îòðèñîâêà ïðàâîãî áîðäþðà
        if (t == vcurr->next_t)
        {
            vmode = 1; // border
            vcurr++;
        }
        //---------------------------------------------------------------------
        // Îòðèñîâêà çàêîí÷åíà, âûõîä
        if (t == last_t)
            goto done;
        //---------------------------------------------------------------------
        goto mode1; // Îòðèñîâêà ïðàâîãî áîðäþðà
    }
}
//=============================================================================



//=============================================================================
void init_frame()
{
    // recreate colors with flash attribute
    unsigned char frame = (unsigned char)comp.frame_counter;

    if (!(frame & 15) /* && !conf.flashcolor */ )
        make_colortab(frame & 16);

    prev_t = -1U;               // block MCR
    temp.base_2 = nullptr;      // block paper trace

    if (temp.vidblock)
        return;


/* [vv] Îòêëþ÷åí, ò.ê. ýòîò áèò èñïîëüçóåòñÿ äëÿ DDp scroll
    //-------------------------------------------------------------------------
    // AlCo384 - no border/paper rendering
    if (comp.pEFF7 & EFF7_384)
        return;
    //-------------------------------------------------------------------------
*/


    //-------------------------------------------------------------------------
    // GIGASCREEN - no paper rendering
//  if (comp.pEFF7 & EFF7_GIGASCREEN) goto allow_border; //Alone Coder
    //-------------------------------------------------------------------------

    //-------------------------------------------------------------------------
    // disable multicolors, border still works
    if (     (temp.rflags & RF_BORDER)                                  ||      // chunk/etc filter
         (   (conf.mem_model == MM_PROFI) && (comp.pDFFD & 0x80)   )    ||      // profi hires screen
         ( ( (conf.mem_model == MM_ATM710) || (conf.mem_model == MM_ATM3) )  &&  (comp.pFF77 & 7) != 3 ) ||  // ATM-2 hires screen
         (   (conf.mem_model == MM_ATM450) && ((comp.aFE & 0x60) != 0x60) )     // ATM-1 hires screen
       )
    {
        //---------------------------------------------------------------------
        // ATM2, îäèí èç ðàñøèðåííûõ âèäåîðåæèìîâ
        if (    (conf.mem_model == MM_ATM710)   ||
                (conf.mem_model == MM_ATM3)
          )
        {
            AtmVideoCtrl.PrepareFrameATM2(comp.pFF77 & 7);
        }
        //---------------------------------------------------------------------
        // ATM1, îäèí èç ðàñøèðåííûõ âèäåîðåæèìîâ
        if (conf.mem_model == MM_ATM450)
        {
            AtmVideoCtrl.PrepareFrameATM1( (comp.aFE >> 5) & 3 );
        }
        //---------------------------------------------------------------------
        // if border update disabled, dont show anything on zx-screen
        if (!conf.updateb)
            return;
        //---------------------------------------------------------------------
    }
    //-------------------------------------------------------------------------
    // paper + border
    temp.base_2 = temp.base;
//allow_border:                 //îñòàòîê îò GIGASCREEN
    prev_t = vmode = 0;
    vcurr = video;
}
//=============================================================================



//=============================================================================
void flush_frame()
{
    //-------------------------------------------------------------------------
    if (temp.vidblock)
        return;
    //-------------------------------------------------------------------------  
    if (prev_t != -1U)
    {
        // MCR on
        if (prev_t)
        {  
            // paint until end of frame
            // paint until screen bottom, even if n_lines*t_line < cpu.t (=t_frame)
            unsigned t = cpu.t;
            cpu.t = 0x7FFF0000;
            update_screen();
            cpu.t = t;
//          if (comp.pEFF7 & EFF7_GIGASCREEN) draw_gigascreen_no_border(); //Alone Coder
        }
        // MCR on, but no screen updates in last frame - use fast painter
        else
        {
            if (temp.base_2 /*|| (comp.pEFF7 & EFF7_GIGASCREEN)*/ /*Alone Coder*/)
                draw_screen();
            else
                draw_border();
        }
        return;
    }
    //-------------------------------------------------------------------------
    if (comp.pEFF7 & EFF7_384)
        draw_alco();
    //-------------------------------------------------------------------------
}
//=============================================================================



//=============================================================================
// spectrum colors -> palette indexes (RF_PALB - gggrrrbb format)
static const u8 comp_pal[16] =
{
    // normal bright  g   r   b   g  r  b
    0x00, // black   000|000|00  00|00|00
    0x02, // blue    000|000|10  00|00|10
    0x10, // red     000|100|00  00|10|00
    0x12, // magenta 000|100|10  00|10|10
    0x80, // green   100|000|00  10|00|00
    0x82, // cyan    100|000|10  10|00|10
    0x90, // yellow  100|100|00  10|10|00
    0x92, // white   100|100|10  10|10|10

    // high bright    g   r   b   g  r  b
    0x00, // black   000|000|00  00|00|00
    0x03, // blue    000|000|11  00|00|11
    0x1C, // red     000|111|00  00|11|00
    0x1F, // magenta 000|111|11  00|11|11
    0xE0, // green   111|000|00  11|00|00
    0xE3, // cyan    111|000|11  11|00|11
    0xFC, // yellow  111|111|00  11|11|00
    0xFF  // white   111|111|11  11|11|11
};
//=============================================================================




//=============================================================================
void load_spec_colors()
{
    for (unsigned flash = 0; flash < 2; flash++)
    {
        for (unsigned bright = 0; bright < 2; bright++)
        {
            unsigned PalNo = ((flash << 1) | bright) << 4;
            // ink ------------------------------------------------------------
            memcpy(     comp.comp_pal + (PalNo | (0 << 3)),
                        comp_pal + (bright << 3),
                        sizeof(comp_pal) / 2
                   );
            // paper ----------------------------------------------------------
            memcpy(     comp.comp_pal + (PalNo | (1 << 3)),
                        comp_pal + (bright << 3),
                        sizeof(comp_pal) / 2
                   );
            //-----------------------------------------------------------------
        }
    }
    temp.comp_pal_changed = 1;
}
//=============================================================================