Subversion Repositories pentevo

Rev

Rev 796 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "std.h"
  2.  
  3. #include "resource.h"
  4. #include "emul.h"
  5. #include "vars.h"
  6. #include "snapshot.h"
  7. #include "tape.h"
  8. #include "memory.h"
  9. #include "opendlg.h"
  10. #include "draw.h"
  11. #include "config.h"
  12. #include "z80.h"
  13. #include "sshot_png.h"
  14. #include "funcs.h"
  15.  
  16. #include "util.h"
  17.  
  18. int readSP();
  19. int readSNA48();
  20. int readSNA128();
  21. int readZ80();
  22. int writeSNA(FILE*);
  23.  
  24. int load_arc(char *fname);
  25.  
  26. SNAP what_is(char *filename)
  27. {
  28.    FILE *ff = fopen(filename, "rb");
  29.    if (!ff) return snNOFILE;
  30.    snapsize = unsigned(fread(snbuf, 1, sizeof snbuf, ff));
  31.    fclose(ff);
  32.    if (snapsize == sizeof snbuf) return snTOOLARGE;
  33.    SNAP type = snUNKNOWN;
  34.    char *ptr = strrchr(filename, '.');
  35.    unsigned ext = ptr? (*(unsigned*)(ptr+1) | 0x20202020U) : 0;
  36.    if (snapsize < 32) return type;
  37.  
  38.    if (snapsize == 131103 || snapsize == 147487) type = snSNA_128;
  39.    if (snapsize == 49179) type = snSNA_48;
  40.    if (ext == WORD4('t','a','p',' ')) type = snTAP;
  41.    if (ext == WORD4('z','8','0',' ')) type = snZ80;
  42.    if(ext == WORD4('p', 'a', 'l', ' ') && (snapsize == sizeof(comp.comp_pal)))
  43.    {
  44.        type = snPAL;
  45.        return type;
  46.    }
  47.    if (conf.trdos_present)
  48.    {
  49.       if (!snbuf[13] && snbuf[14] && (int)snapsize == snbuf[14]*256+17) type = snHOB;
  50.       if (snapsize >= 8192 && !(snapsize & 0xFF) && ext == WORD4('t','r','d',' ')) type = snTRD;
  51.  
  52.       if (snapsize >= 8192 && ext == WORD4('i','s','d',' '))
  53.           type = snISD;
  54.  
  55.       if (snapsize >= 8192 && ext == WORD4('p','r','o',' '))
  56.           type = snPRO;
  57.  
  58.       if (!memcmp(snbuf, "SINCLAIR", 8))
  59.       {
  60.           unsigned nfiles = snbuf[8];
  61.           unsigned nsec = 0;
  62.           for(unsigned i = 0; i < nfiles; i++)
  63.           {
  64.               nsec += snbuf[9+14*i+13];
  65.           }
  66.          
  67.           if(snapsize >= 9 + nfiles * 14 + nsec * 0x100)
  68.               type = snSCL;
  69.       }
  70.       if (!memcmp(snbuf, "FDI", 3) && *(unsigned short*)(snbuf+4) <= MAX_CYLS && *(unsigned short*)(snbuf+6) <= 2) type = snFDI;
  71.       if (((*(short*)snbuf|0x2020) == WORD2('t','d')) && snbuf[4] >= 10 && snbuf[4] <= 21 && snbuf[9] <= 2) type = snTD0;
  72.       if (*(unsigned*)snbuf == WORD4('U','D','I','!') && *(unsigned*)(snbuf+4)==snapsize-4 && snbuf[9] < MAX_CYLS && snbuf[10]<2 && !snbuf[8]) type = snUDI;
  73.    }
  74.    if (snapsize > 10 && !memcmp(snbuf, "ZXTape!\x1A", 8))
  75.    {
  76.        type = snTZX;
  77.    }
  78.    if (snapsize > 0x22 && !memcmp(snbuf, "Compressed Square Wave\x1A", 23)) type = snCSW;
  79.    if (*(unsigned short*)snbuf == WORD2('S','P') && *(unsigned short*)(snbuf+2)+0x26 == (int)snapsize) type = snSP;
  80.    return type;
  81. }
  82.  
  83. static int readPAL();
  84.  
  85. int loadsnap(char *filename)
  86. {
  87.    if (load_arc(filename))
  88.        return 1;
  89.    SNAP type = what_is(filename);
  90.  
  91.    if (type >= snHOB)
  92.    {
  93.  
  94.       if (trd_toload == -1U)
  95.       {
  96.          unsigned last = -1U;
  97.          for (unsigned i = 0; i < 4; i++) if (trd_loaded[i]) last = i;
  98.          trd_toload = (last == -1U)? 0 : ((type == snHOB)? last : (last+1) & 3);
  99.       }
  100.  
  101.       for (unsigned k = 0; k < 4; k++)
  102.       {
  103.          if (k != trd_toload && !stricmp(comp.wd.fdd[k].name, filename))
  104.          {
  105.             static char err[] = "This disk image is already loaded to drive X:\n"
  106.                                 "Do you still want to load it to drive Y:?";
  107.             err[43] = char(k+'A');
  108.             err[84] = char(trd_toload+'A');
  109.             if (MessageBox(GetForegroundWindow(), err, "Warning", MB_YESNO | MB_ICONWARNING) == IDNO) return 1;
  110.          }
  111.       }
  112.  
  113.       FDD *drive = comp.wd.fdd + trd_toload;
  114.       if (!drive->test())
  115.           return 0;
  116.       comp.wd.Eject(trd_toload);
  117.       int ok = drive->read(type);
  118.       if (ok)
  119.       {
  120.          if (*conf.appendboot)
  121.              drive->addboot();
  122.          strcpy(drive->name, filename);
  123.          if (GetFileAttributes(filename) & FILE_ATTRIBUTE_READONLY)
  124.             conf.trdos_wp[trd_toload] = 1;
  125.          drive->snaptype = (type == snHOB || type == snSCL)? snTRD : type;
  126.          trd_loaded[trd_toload] = 1;
  127. //---------Alone Coder
  128.          char *name = filename;
  129.          for (char *x = name; *x; x++)
  130.              if (*x == '\\') name = x+1;
  131.          strcpy(temp.LastSnapName, name);
  132.          char *p = strrchr(temp.LastSnapName, '.');
  133.          if(p)
  134.          {
  135.              *p = 0;
  136.          }
  137.          char wintitle[0x200];
  138.          strcpy(wintitle,name);
  139.          strcat(wintitle," - UnrealSpeccy");
  140.          SetWindowText(wnd, wintitle);
  141. //~---------Alone Coder
  142.       }
  143.       return ok;
  144.    }
  145.  
  146.    if (type == snSP) return readSP();
  147.    if (type == snSNA_48) return readSNA48();
  148.    if (type == snSNA_128) return readSNA128();
  149.    if (type == snZ80) return readZ80();
  150.    if (type == snTAP) return readTAP();
  151.    if (type == snTZX) return readTZX();
  152.    if (type == snCSW) return readCSW();
  153.    if(type == snPAL)
  154.    {
  155.        return readPAL();
  156.    }
  157.  
  158.    return 0;
  159. }
  160.  
  161. int readSNA128()
  162. {
  163.    if(conf.mem_model == MM_PENTAGON && conf.Sna128Lock)
  164.    {
  165.        conf.ramsize = 128;
  166.        temp.ram_mask = u8((conf.ramsize-1) >> 4);
  167.    }
  168.  
  169.    hdrSNA128 *hdr = (hdrSNA128*)snbuf;
  170.    reset(hdr->trdos? RM_DOS : RM_SOS);
  171.    cpu.alt.af = hdr->altaf;
  172.    cpu.alt.bc = hdr->altbc;
  173.    cpu.alt.de = hdr->altde;
  174.    cpu.alt.hl = hdr->althl;
  175.    cpu.af = hdr->af;
  176.    cpu.bc = hdr->bc;
  177.    cpu.de = hdr->de;
  178.    cpu.hl = hdr->hl;
  179.    cpu.ix = hdr->ix;
  180.    cpu.iy = hdr->iy;
  181.    cpu.sp = hdr->sp;
  182.    cpu.pc = hdr->pc;
  183.    cpu.i = hdr->i;
  184.    cpu.r_low = hdr->r;
  185.    cpu.r_hi = hdr->r & 0x80;
  186.    cpu.im = hdr->im;
  187.    cpu.iff1 = cpu.iff2 = (hdr->iff >> 2) & 1;
  188.    comp.p7FFD = hdr->p7FFD;
  189.    comp.pFE = hdr->pFE;
  190.    comp.border_attr = comp.pFE & 7;
  191.    memcpy(memory+PAGE*5, hdr->page5, PAGE);
  192.    memcpy(memory+PAGE*2, hdr->page2, PAGE);
  193.    memcpy(memory+PAGE*(hdr->p7FFD & 7), hdr->active_page, PAGE);
  194.    unsigned char *newpage = snbuf+0xC01F;
  195.    unsigned char mapped = u8(0x24U | (1 << (hdr->p7FFD & 7)));
  196.    for (unsigned char i = 0; i < 8; i++)
  197.    {
  198.       if (!(mapped & (1 << i)))
  199.       {
  200.          memcpy(memory + PAGE*i, newpage, PAGE);
  201.          newpage += PAGE;
  202.       }
  203.    }
  204.    set_banks();
  205.    return 1;
  206. }
  207.  
  208. int readSNA48()
  209. {
  210.    //conf.mem_model = MM_PENTAGON; conf.ramsize = 128;  // molodcov_alex
  211.    reset(RM_SOS);
  212.    hdrSNA128 *hdr = (hdrSNA128*)snbuf;
  213.    cpu.alt.af = hdr->altaf; cpu.alt.bc = hdr->altbc;
  214.    cpu.alt.de = hdr->altde; cpu.alt.hl = hdr->althl;
  215.    cpu.af = hdr->af; cpu.bc = hdr->bc; cpu.de = hdr->de; cpu.hl = hdr->hl;
  216.    cpu.ix = hdr->ix; cpu.iy = hdr->iy; cpu.sp = hdr->sp;
  217.    cpu.i = hdr->i; cpu.r_low = hdr->r; cpu.r_hi = hdr->r & 0x80; cpu.im = hdr->im;
  218.    cpu.iff1 = cpu.iff2 = (hdr->iff >> 2) & 1; comp.p7FFD = 0x30;
  219.    comp.pEFF7 |= EFF7_LOCKMEM; //Alone Coder
  220.    comp.pFE = hdr->pFE; comp.border_attr = comp.pFE & 7;
  221.    memcpy(memory+PAGE*5, hdr->page5, PAGE);
  222.    memcpy(memory+PAGE*2, hdr->page2, PAGE);
  223.    memcpy(memory+PAGE*0, hdr->active_page, PAGE);
  224.    cpu.pc = cpu.DirectRm(cpu.sp)+0x100*cpu.DirectRm(cpu.sp+1); cpu.sp += 2;
  225.    set_banks(); return 1;
  226. }
  227.  
  228. int readSP()
  229. {
  230.    //conf.mem_model = MM_PENTAGON; conf.ramsize = 128;  // molodcov_alex
  231.    reset(RM_SOS);
  232.    hdrSP *hdr = (hdrSP*)snbuf;
  233.    cpu.alt.af = hdr->altaf; cpu.alt.bc = hdr->altbc;
  234.    cpu.alt.de = hdr->altde; cpu.alt.hl = hdr->althl;
  235.    cpu.af = hdr->af; cpu.bc = hdr->bc; cpu.de = hdr->de; cpu.hl = hdr->hl;
  236.    cpu.ix = hdr->ix; cpu.iy = hdr->iy; cpu.sp = hdr->sp; cpu.pc = hdr->pc;
  237.    cpu.i = hdr->i; cpu.r_low = hdr->r; cpu.r_hi = hdr->r & 0x80;
  238.    cpu.iff1 = (hdr->flags & 1);
  239.    cpu.im = 1 + ((hdr->flags >> 1) & 1);
  240.    cpu.iff2 = (hdr->flags >> 2) & 1;
  241.    comp.p7FFD = 0x30;
  242.    comp.pEFF7 |= EFF7_LOCKMEM; //Alone Coder
  243.    comp.pFE = hdr->pFE; comp.border_attr = comp.pFE & 7;
  244.    for (unsigned i = 0; i < hdr->len; i++)
  245.       cpu.DirectWm(hdr->start + i, snbuf[i + 0x26]);
  246.    set_banks(); return 1;
  247. }
  248.  
  249. int writeSNA(FILE *ff)
  250. {
  251. /*   if (conf.ramsize != 128) {
  252.       MessageBox(GetForegroundWindow(), "SNA format can hold only\r\n128kb memory models", "Save", MB_ICONERROR);
  253.       return 0;
  254.    }*/ //Alone Coder
  255.    hdrSNA128 *hdr = (hdrSNA128*)snbuf;
  256.    hdr->trdos = (comp.flags & CF_TRDOS)? 1 : 0;
  257.    hdr->altaf = u16(cpu.alt.af); hdr->altbc = u16(cpu.alt.bc);
  258.    hdr->altde = u16(cpu.alt.de); hdr->althl = u16(cpu.alt.hl);
  259.    hdr->af = u16(cpu.af); hdr->bc = u16(cpu.bc); hdr->de = u16(cpu.de); hdr->hl = u16(cpu.hl);
  260.    hdr->ix = u16(cpu.ix); hdr->iy = u16(cpu.iy); hdr->sp = u16(cpu.sp); hdr->pc = u16(cpu.pc);
  261.    hdr->i = cpu.i; hdr->r = (cpu.r_low & 0x7F)+cpu.r_hi; hdr->im = cpu.im;
  262.    hdr->iff = cpu.iff2 ? 4 : 0;
  263.    hdr->p7FFD = comp.p7FFD;
  264.    hdr->pFE = comp.pFE; comp.border_attr = comp.pFE & 7;
  265.    unsigned savesize = sizeof(hdrSNA128);
  266.    unsigned char mapped = u8(0x24U | (1 << (comp.p7FFD & 7)));
  267.    if (comp.p7FFD == 0x30)
  268.    { // save 48k
  269.       mapped = 0xFF;
  270.       savesize = 0xC01B;
  271.       hdr->sp -= 2;
  272.       cpu.DirectWm(hdr->sp, cpu.pcl);
  273.       cpu.DirectWm(hdr->sp+1, cpu.pch);
  274.    }
  275.    memcpy(hdr->page5, memory+PAGE*5, PAGE);
  276.    memcpy(hdr->page2, memory+PAGE*2, PAGE);
  277.    memcpy(hdr->active_page, memory+PAGE*(comp.p7FFD & 7), PAGE);
  278.    if (fwrite(hdr, 1, savesize, ff) != savesize) return 0;
  279.    for (unsigned char i = 0; i < 8; i++)
  280.       if (!(mapped & (1 << i))) {
  281.          if (fwrite(memory + PAGE*i, 1, PAGE, ff) != PAGE) return 0;
  282.       }
  283.    return 1;
  284. }
  285.  
  286. static void unpack_page(unsigned char *dst, unsigned dstlen, unsigned char *src, unsigned srclen)
  287. {
  288.    memset(dst, 0, dstlen);
  289.    while (srclen > 0 && dstlen > 0)
  290.    {
  291.       if (srclen >= 4 && src[0] == 0xED && src[1] == 0xED)
  292.       {
  293.          size_t len = src[2];
  294.          memset(dst, src[3], len);
  295.          dstlen -= len;
  296.          srclen -= 4;
  297.          src += 4;
  298.          dst += len;
  299.       }
  300.       else
  301.       {
  302.           *dst++ = *src++;
  303.           dstlen--;
  304.           srclen--;
  305.       }
  306.    }
  307. }
  308.  
  309. int readZ80()
  310. {
  311.    //conf.mem_model = MM_PENTAGON; conf.ramsize = 128;  // molodcov_alex
  312.    hdrZ80 *hdr = (hdrZ80*)snbuf;
  313.    unsigned char *ptr = snbuf + 30;
  314.    unsigned char model48k = (hdr->model < 3);
  315.    reset((model48k|(hdr->p7FFD & 0x10)) ? RM_SOS : RM_128);
  316.    if (hdr->flags == 0xFF)
  317.        hdr->flags = 1;
  318.    if (hdr->pc == 0)
  319.    { // 2.01
  320.       ptr += 2 + hdr->len;
  321.       hdr->pc = hdr->newpc;
  322.       memset(RAM_BASE_M, 0, PAGE*8); // clear 128k - first 8 pages
  323.  
  324.       unsigned char * const p48[] =
  325.       {
  326.              base_sos_rom, nullptr, nullptr, nullptr,
  327.              RAM_BASE_M+2*PAGE, RAM_BASE_M+0*PAGE, nullptr, nullptr,
  328.              RAM_BASE_M+5*PAGE, nullptr, nullptr, nullptr
  329.       };
  330.       unsigned char * const p128[] =
  331.       {
  332.              base_sos_rom, base_dos_rom, base_128_rom, RAM_BASE_M+0*PAGE,
  333.              RAM_BASE_M+1*PAGE, RAM_BASE_M+2*PAGE, RAM_BASE_M+3*PAGE, RAM_BASE_M+4*PAGE,
  334.              RAM_BASE_M+5*PAGE, RAM_BASE_M+6*PAGE, RAM_BASE_M+7*PAGE, nullptr
  335.       };
  336.  
  337.       while (ptr < snbuf+snapsize)
  338.       {
  339.          unsigned len = *(unsigned short*)ptr;
  340.          if (ptr[2] > 11)
  341.              return 0;
  342.          unsigned char *dstpage = model48k ? p48[ptr[2]] : p128[ptr[2]];
  343.          if (!dstpage)
  344.              return 0;
  345.          ptr += 3;
  346.          if (len == 0xFFFF)
  347.          {
  348.              len = PAGE;
  349.              memcpy(dstpage, ptr, len);
  350.          }
  351.          else
  352.              unpack_page(dstpage, PAGE, ptr, len);
  353.          ptr += len;
  354.       }
  355.    }
  356.    else
  357.    {
  358.       unsigned len = snapsize - 30;
  359.       unsigned char *mem48 = ptr;
  360.       if (hdr->flags & 0x20)
  361.          unpack_page(mem48 = snbuf + 4*PAGE, 3*PAGE, ptr, len);
  362.       memcpy(memory + PAGE*5, mem48, PAGE);
  363.       memcpy(memory + PAGE*2, mem48 + PAGE, PAGE);
  364.       memcpy(memory + PAGE*0, mem48 + 2*PAGE, PAGE);
  365.       model48k = 1;
  366.    }
  367.    cpu.a = hdr->a; cpu.f = hdr->f;
  368.    cpu.bc = hdr->bc; cpu.de = hdr->de; cpu.hl = hdr->hl;
  369.    cpu.alt.bc = hdr->bc1; cpu.alt.de = hdr->de1; cpu.alt.hl = hdr->hl1;
  370.    cpu.alt.a = hdr->a1; cpu.alt.f = hdr->f1;
  371.    cpu.pc = hdr->pc; cpu.sp = hdr->sp; cpu.ix = hdr->ix; cpu.iy = hdr->iy;
  372.    cpu.i = hdr->i; cpu.r_low = hdr->r & 0x7F;
  373.    cpu.r_hi = u8((hdr->flags & 1U) << 7U);
  374.    comp.pFE = (hdr->flags >> 1) & 7;
  375.    comp.border_attr = comp.pFE;
  376.    cpu.iff1 = hdr->iff1; cpu.iff2 = hdr->iff2; cpu.im = (hdr->im & 3);
  377.    comp.p7FFD = (model48k) ? 0x30 : hdr->p7FFD;
  378.  
  379.    if(hdr->len == 55) // version 3.0 (with 1ffd)
  380.        comp.p1FFD = hdr->p1FFD;
  381.  
  382.    if (model48k)
  383.        comp.pEFF7 |= EFF7_LOCKMEM; //Alone Coder
  384.  
  385.    set_banks();
  386.  
  387.    return 1;
  388. }
  389.  
  390. static int readPAL()
  391. {
  392.     memcpy(comp.comp_pal, snbuf, snapsize);
  393.     temp.comp_pal_changed = 1;
  394.     if(conf.ula_plus)
  395.     {
  396.         comp.ula_plus_en = true; // ┼ёыш яЁшёєЄёЄтєхЄ ULA+, Єю ёЁрчє ш ръЄштшЁєхь хх (ўЄюс√ шчьхэхэш  ярышЄЁ√ с√ыш тшфэ√)
  397.     }
  398.     return 1;
  399. }
  400.  
  401. static int writePAL(FILE *ff)
  402. {
  403.     if(fwrite(comp.comp_pal, 1, sizeof(comp.comp_pal), ff) != sizeof(comp.comp_pal))
  404.     {
  405.         return 0;
  406.     }
  407.     return 1;
  408. }
  409.  
  410. #define arctmp ((char*)rbuf)
  411. static char *arc_fname;
  412. static INT_PTR CALLBACK ArcDlg(HWND dlg, UINT msg, WPARAM wp, LPARAM lp)
  413. {
  414.    (void)lp;
  415.  
  416.    if (msg == WM_INITDIALOG) {
  417.       for (char *dst = arctmp; *dst; dst += strlen(dst)+1)
  418.          SendDlgItemMessage(dlg, IDC_ARCLIST, LB_ADDSTRING, 0, (LPARAM)dst);
  419.       SendDlgItemMessage(dlg, IDC_ARCLIST, LB_SETCURSEL, 0, 0);
  420.       return 1;
  421.    }
  422.    if ((msg == WM_COMMAND && wp == IDCANCEL) ||
  423.        (msg == WM_SYSCOMMAND && (wp & 0xFFF0) == SC_CLOSE)) EndDialog(dlg, 0);
  424.    if (msg == WM_COMMAND && (LOWORD(wp) == IDOK || (HIWORD(wp)==LBN_DBLCLK && LOWORD(wp) == IDC_ARCLIST)))
  425.    {
  426.       int n = int(SendDlgItemMessage(dlg, IDC_ARCLIST, LB_GETCURSEL, 0, 0));
  427.       char *dst = arctmp;
  428.       for (int q = 0; q < n; q++) dst += strlen(dst)+1;
  429.       arc_fname = dst;
  430.       EndDialog(dlg, 0);
  431.    }
  432.    return 0;
  433. }
  434.  
  435. static bool filename_ok(char *fname)
  436. {
  437.    for (char *wc = skiparc; *wc; wc += strlen(wc)+1)
  438.       if (wcmatch(fname, wc)) return 0;
  439.    return 1;
  440. }
  441.  
  442. int load_arc(char *fname)
  443. {
  444.    char *ext = strrchr(fname, '.'); if (!ext) return 0;
  445.    ext++;
  446.    char *cmdtmp;
  447.    char done = 0;
  448.    for (char *x = arcbuffer; *x; x = cmdtmp + strlen(cmdtmp)+1) {
  449.       cmdtmp = x + strlen(x)+1;
  450.       if (stricmp(ext, x)) continue;
  451.  
  452.       char dir[0x200]; GetCurrentDirectory(sizeof dir, dir);
  453.       char tmp[0x200]; GetTempPath(sizeof tmp, tmp);
  454.       char d1[0x20]; sprintf(d1, "us%08lX", GetTickCount());
  455.       SetCurrentDirectory(tmp);
  456.       CreateDirectory(d1, nullptr);
  457.       SetCurrentDirectory(d1);
  458.  
  459.       color();
  460.       char cmdln[0x200]; sprintf(cmdln, cmdtmp, fname);
  461.       STARTUPINFO si = { sizeof si };
  462.       si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE;
  463.       PROCESS_INFORMATION pi;
  464.       unsigned flags = CREATE_NEW_CONSOLE;
  465.       HANDLE hc = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
  466.       if(hc != INVALID_HANDLE_VALUE)
  467.       {
  468.           CloseHandle(hc);
  469.           flags = 0;
  470.       }
  471.       if (CreateProcess(nullptr, cmdln, nullptr, nullptr, 0, flags, nullptr, nullptr, &si, &pi)) {
  472.          WaitForSingleObject(pi.hProcess, INFINITE);
  473.          DWORD code; GetExitCodeProcess(pi.hProcess, &code);
  474.          CloseHandle(pi.hThread);
  475.          CloseHandle(pi.hProcess);
  476.          if (!code || MessageBox(GetForegroundWindow(), "Broken archive", nullptr, MB_ICONERROR | MB_OKCANCEL) == IDOK) {
  477.             WIN32_FIND_DATA fd; HANDLE h;
  478.             char *dst = arctmp; unsigned nfiles = 0;
  479.             if ((h = FindFirstFile("*.*", &fd)) != INVALID_HANDLE_VALUE) {
  480.                do {
  481.                   if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && filename_ok(fd.cFileName)) {
  482.                      strcpy(dst, fd.cFileName); dst += strlen(dst)+1;
  483.                      nfiles++;
  484.                   }
  485.                } while (FindNextFile(h, &fd));
  486.                FindClose(h);
  487.             }
  488.             *dst = 0; arc_fname = nullptr;
  489.             if (nfiles == 1) arc_fname = arctmp;
  490.             if (nfiles > 1)
  491.                 DialogBox(hIn, MAKEINTRESOURCE(IDD_ARC), GetForegroundWindow(), ArcDlg);
  492.             if (!nfiles) MessageBox(GetForegroundWindow(), "Empty archive!", nullptr, MB_ICONERROR | MB_OK);
  493.             char buf[0x200]; strcpy(buf, tmp); strcat(buf, "\\");
  494.             strcat(buf, d1);
  495.             strcat(buf, "\\");
  496.             if(arc_fname)
  497.             {
  498.                 strcat(buf, arc_fname);
  499.                 arc_fname = buf;
  500.             }
  501.             if (arc_fname && !(done = (char)loadsnap(arc_fname))) MessageBox(GetForegroundWindow(), "loading error", arc_fname, MB_ICONERROR);
  502.             if (!done) done = -1;
  503.          }
  504.          // delete junk
  505.          SetCurrentDirectory(tmp);
  506.          SetCurrentDirectory(d1);
  507.          WIN32_FIND_DATA fd; HANDLE h;
  508.          if ((h = FindFirstFile("*.*", &fd)) != INVALID_HANDLE_VALUE) {
  509.             do { DeleteFile(fd.cFileName); } while (FindNextFile(h, &fd));
  510.             FindClose(h);
  511.          }
  512.       }
  513.       SetCurrentDirectory(tmp);
  514.       RemoveDirectory(d1);
  515.       SetCurrentDirectory(dir);
  516.       eat(); if (done) return done > 0 ? 1 : 0;
  517.    }
  518.    eat(); return 0;
  519. }
  520.  
  521. void opensnap(unsigned index)
  522. {
  523.    char mask[0x200]; *mask = 0;
  524.    for(char *x = arcbuffer; *x; )
  525.    {
  526.        strcat(mask, ";*.");
  527.        strcat(mask, x);
  528.        x += strlen(x) + 1;
  529.        x += strlen(x) + 1;
  530.    }
  531.  
  532.    char fline[0x400];
  533.    const char *src = "all (sna,z80,sp,tap,tzx,csw,trd,scl,fdi,td0,udi,isd,pro,hobeta,pal)\0"
  534.                "*.sna;*.z80;*.sp;*.tap;*.tzx;*.csw;*.trd;*.scl;*.td0;*.udi;*.fdi;*.isd;*.pro;*.$?;*.!?;*.pal<\0"
  535.                "Disk B (trd,scl,fdi,td0,udi,isd,pro,hobeta)\0*.trd;*.scl;*.fdi;*.udi;*.td0;*.isd;*.pro;*.$?<\0"
  536.                "Disk C (trd,scl,fdi,td0,udi,isd,pro,hobeta)\0*.trd;*.scl;*.fdi;*.udi;*.td0;*.isd;*.pro;*.$?<\0"
  537.                "Disk D (trd,scl,fdi,td0,udi,isd,pro,hobeta)\0*.trd;*.scl;*.fdi;*.udi;*.td0;*.isd;*.pro;*.$?<\0\0>";
  538.    if (!conf.trdos_present)
  539.       src = "ZX files (sna,z80,tap,tzx,csw,pal)\0*.sna;*.z80;*.tap;*.tzx;*.csw;*.pal<\0\0>";
  540.    for(char *dst = fline; *src != '>'; src++)
  541.    {
  542.        if(*src == '<')
  543.        {
  544.            strcpy(dst, mask);
  545.            dst += strlen(dst);
  546.        }
  547.        else
  548.        {
  549.            *dst++ = *src;
  550.        }
  551.    }
  552.  
  553.    OPENFILENAME ofn = { };
  554.    char fname[0x200]; *fname = 0;
  555.    char dir[0x200]; GetCurrentDirectory(sizeof dir, dir);
  556.  
  557.    ofn.lStructSize = (WinVerMajor < 5) ? OPENFILENAME_SIZE_VERSION_400 : sizeof(OPENFILENAME);
  558.    ofn.hwndOwner = GetForegroundWindow();
  559.    ofn.lpstrFilter = fline;
  560.    ofn.lpstrFile = fname; ofn.nMaxFile = sizeof fname;
  561.    ofn.lpstrTitle = "Load Snapshot / Disk / Tape";
  562.    ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  563.    ofn.nFilterIndex = DWORD(index);
  564.    ofn.lpstrInitialDir = dir;
  565. //   __debugbreak();
  566.    if (GetSnapshotFileName(&ofn, 0))
  567.    {
  568.       trd_toload = ofn.nFilterIndex-1;
  569.       if (!loadsnap(fname))
  570.           MessageBox(GetForegroundWindow(), fname, "loading error", MB_ICONERROR);
  571.    }
  572.    eat();
  573. }
  574.  
  575. static const int mx_typs = (1+4*6);
  576. static unsigned char snaps[mx_typs];
  577. static unsigned exts[mx_typs];
  578. static unsigned drvs[mx_typs];
  579. static unsigned snp;
  580. static void addref(LPSTR &ptr, unsigned char sntype, const char *ref, unsigned drv, unsigned ext)
  581. {
  582.    strcpy(ptr, ref); ptr += strlen(ptr)+1;
  583.    strcpy(ptr, ref+strlen(ref)+1); ptr += strlen(ptr)+1;
  584.    drvs[snp] = drv; exts[snp] = ext; snaps[snp++] = sntype;
  585. }
  586.  
  587. void savesnap(int diskindex)
  588. {
  589. again:
  590.    OPENFILENAME ofn = { };
  591.    char fname[0x200]; *fname = 0;
  592.    if (diskindex >= 0) {
  593.       strcpy(fname, comp.wd.fdd[diskindex].name);
  594.       size_t ln = strlen(fname);
  595.       if (ln > 4 && (*(unsigned*)(fname+ln-4) | WORD4(0,0x20,0x20,0x20)) == WORD4('.','s','c','l'))
  596.          *(unsigned*)(fname+ln-4) = WORD4('.','t','r','d');
  597.    }
  598.  
  599.    snp = 1; char types[600], *ptr = types;
  600.  
  601.    if (diskindex < 0)
  602.    {
  603.       exts[snp] = WORD4('s','n','a',0); snaps[snp] = snSNA_128; // default
  604.       addref(ptr, snSNA_128, "ZX-Spectrum 128K snapshot (SNA)\0*.sna", -1U, WORD4('s','n','a',0));
  605.  
  606.       exts[snp] = WORD4('p', 'a', 'l', 0); snaps[snp] = snPAL;
  607.       addref(ptr, snPAL, "Palette (ULA+)\0*.pal", -1U, WORD4('p', 'a', 'l', 0));
  608.    }
  609.  
  610.    ofn.lStructSize = (WinVerMajor < 5) ? OPENFILENAME_SIZE_VERSION_400 : sizeof(OPENFILENAME);
  611.    ofn.nFilterIndex = 1;
  612.  
  613.    if (conf.trdos_present)
  614.    {
  615.       static char mask[] = "Disk A (TRD)\0*.trd";
  616.       static const char ex[][3] = { {'T','R','D'}, {'F','D','I'},{'T','D','0'},{'U','D','I'},{'I','S','D'},{'P','R','O'}};
  617.       static const unsigned ex2[] = { snTRD, snFDI, snTD0, snUDI, snISD, snPRO };
  618.  
  619.       for (unsigned n = 0; n < 4; n++)
  620.       {
  621.          if (!comp.wd.fdd[n].rawdata)
  622.              continue;
  623.          if (diskindex >= 0 && unsigned(diskindex) != n)
  624.              continue;
  625.          mask[5] = char('A'+n);
  626.  
  627.          for (size_t i = 0; i < sizeof ex/sizeof(ex[0]); i++)
  628.          {
  629.             if (unsigned(diskindex) == n && ex2[i] == comp.wd.fdd[n].snaptype)
  630.                 ofn.nFilterIndex = snp;
  631.             memcpy(mask+8, ex[i], 3);
  632.             memcpy(mask+15, ex[i], 3);
  633.             addref(ptr, u8(ex2[i]), mask, n, (*(const unsigned*)ex[i] & 0xFFFFFF) | 0x202020);
  634.          }
  635.       }
  636.    }
  637.    ofn.lpstrFilter = types; *ptr = 0;
  638.    ofn.lpstrFile = fname; ofn.nMaxFile = sizeof fname;
  639.    ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  640.    ofn.hwndOwner = GetForegroundWindow();
  641.    char *path = strrchr(fname, '\\');
  642.    if (path)
  643.    { // check if directory exists (for files opened from archive)
  644.       char x = *path; *path = 0;
  645.       unsigned atr = GetFileAttributes(fname); *path = x;
  646.       if (atr == -1U || !(atr & FILE_ATTRIBUTE_DIRECTORY)) *fname = 0;
  647.    } else path = fname;
  648.    path = strrchr(path, '.'); if (path) *path = 0; // delete extension
  649.  
  650.    if (GetSnapshotFileName(&ofn, 1))
  651.    {
  652.       char *fn = strrchr(ofn.lpstrFile, '\\');
  653.       fn = fn? fn+1 : ofn.lpstrFile;
  654.       char *extpos = strrchr(fn, '.');
  655.       if (!extpos || stricmp(extpos+1, (char*)&exts[ofn.nFilterIndex]))
  656.       {
  657.          char *dst = fn + strlen(fn); *dst++ = '.';
  658.          *(unsigned*)dst = exts[ofn.nFilterIndex];
  659.       }
  660.       if (GetFileAttributes(ofn.lpstrFile) != INVALID_FILE_ATTRIBUTES &&
  661.             IDNO == MessageBox(GetForegroundWindow(), "File exists. Overwrite ?", "Save", MB_ICONQUESTION | MB_YESNO))
  662.          goto again;
  663.  
  664.       FILE *ff = fopen(ofn.lpstrFile, "wb");
  665.       if (ff)
  666.       {
  667.          int res = 0;
  668.          FDD *saveto = comp.wd.fdd + drvs[ofn.nFilterIndex];
  669.          switch (snaps[ofn.nFilterIndex])
  670.          {
  671.             case snSNA_128: res = writeSNA(ff); break;
  672.             case snPAL: res = writePAL(ff); break;
  673.             case snTRD: res = saveto->write_trd(ff); break;
  674.             case snUDI: res = saveto->write_udi(ff); break;
  675.             case snFDI: res = saveto->write_fdi(ff); break;
  676.             case snTD0: res = saveto->write_td0(ff); break;
  677.             case snISD: res = saveto->write_isd(ff); break;
  678.             case snPRO: res = saveto->write_pro(ff); break;
  679.          }
  680.          fclose(ff);
  681.          if (!res)
  682.              MessageBox(GetForegroundWindow(), "write error", "Save", MB_ICONERROR);
  683.          else if (drvs[ofn.nFilterIndex]!=-1U)
  684.          {
  685.              comp.wd.fdd[drvs[ofn.nFilterIndex]].optype=0;
  686.              strcpy(comp.wd.fdd[drvs[ofn.nFilterIndex]].name, ofn.lpstrFile);
  687.  
  688.              //---------Alone Coder
  689.              char *name = ofn.lpstrFile;
  690.              for (char *x = name; *x; x++)
  691.              {
  692.                  if (*x == '\\')
  693.                      name = x+1;
  694.              }
  695.              char wintitle[0x200];
  696.              strcpy(wintitle,name);
  697.              strcat(wintitle," - UnrealSpeccy");
  698.              SetWindowText(wnd, wintitle);
  699.              //~---------Alone Coder
  700.          }
  701.       }
  702.       else
  703.           MessageBox(GetForegroundWindow(), "Can't open file for writing", "Save", MB_ICONERROR);
  704.    }
  705.    eat();
  706. }
  707.  
  708. void ConvPal8ToBgr24(u8 *dst, u8 *scrbuf, int dx)
  709. {
  710.     u8 *ds = dst;
  711.     for(unsigned i = 0; i < temp.oy; i++) // convert to BGR24 format
  712.     {
  713.        unsigned char *src = scrbuf + int(i)*dx;
  714.        for (unsigned y = 0; y < temp.ox; y++)
  715.        {
  716.           ds[0] = pal0[src[y]].peBlue;
  717.           ds[1] = pal0[src[y]].peGreen;
  718.           ds[2] = pal0[src[y]].peRed;
  719.           ds += 3;
  720.        }
  721.        ds = (PBYTE)(ULONG_PTR(ds + 3) & ~ULONG_PTR(3)); // ърцфр  ёЄЁюър т√Ёртэхэр эр 4
  722.     }
  723. }
  724.  
  725. void ConvRgb15ToBgr24(u8 *dst, u8 *scrbuf, int dx)
  726. {
  727.     u8 *ds = dst;
  728.     for(unsigned i = 0; i < temp.oy; i++) // convert to BGR24 format
  729.     {
  730.        unsigned char *src = scrbuf + int(i)*dx;
  731.        for (unsigned y = 0; y < temp.ox; y++)
  732.        {
  733.           unsigned xx;
  734.           xx = *(unsigned*)(src + y*2);
  735.  
  736.           ds[0] = u8((xx & 0x1F)<<3);
  737.           ds[1] = u8((xx & 0x03E0)>>2);
  738.           ds[2] = u8((xx & 0x7C00)>>7);
  739.           ds += 3;
  740.        }
  741.        ds = (PBYTE)(ULONG_PTR(ds + 3) & ~ULONG_PTR(3)); // ърцфр  ёЄЁюър т√Ёртэхэр эр 4
  742.     }
  743. }
  744.  
  745. void ConvRgb16ToBgr24(u8 *dst, u8 *scrbuf, int dx)
  746. {
  747.     u8 *ds = dst;
  748.     for(unsigned i = 0; i < temp.oy; i++) // convert to BGR24 format
  749.     {
  750.        unsigned char *src = scrbuf + int(i)*dx;
  751.        for (unsigned y = 0; y < temp.ox; y++)
  752.        {
  753.           unsigned xx;
  754.           xx = *(unsigned*)(src + y*2);
  755.  
  756.           ds[0] = u8((xx&0x1F)<<3);
  757.           ds[1] = u8((xx&0x07E0)>>3);
  758.           ds[2] = u8((xx&0xF800)>>8);
  759.           ds += 3;
  760.        }
  761.        ds = (PBYTE)(ULONG_PTR(ds + 3) & ~ULONG_PTR(3)); // ърцфр  ёЄЁюър т√Ёртэхэр эр 4
  762.     }
  763. }
  764.  
  765. void ConvYuy2ToBgr24(u8 *dst, u8 *scrbuf, int dx)
  766. {
  767.     u8 *ds = dst;
  768.     for(unsigned i = 0; i < temp.oy; i++) // convert to BGR24 format
  769.     {
  770.         unsigned char *src = scrbuf + int(i)*dx;
  771.         for (unsigned y = 0; y < temp.ox; y++)
  772.         {
  773.             unsigned xx;
  774.             xx = *(unsigned*)(src + y*2);
  775.  
  776.             int u = src[y/2*4+1], v = src[y/2*4+3], Y = src[y*2];
  777.             int r = (int)(.4732927654e-2*u-255.3076403+1.989858012*v+.9803921569*Y);
  778.             int g = (int)(-.9756592292*v+186.0716700-.4780256930*u+.9803921569*Y);
  779.             int b = (int)(.9803921569*Y+2.004732928*u-255.3076403-.1014198783e-1*v); // mapple rulez!
  780.             if (r < 0) r = 0; if (r > 255) r = 255;
  781.             if (g < 0) g = 0; if (g > 255) g = 255;
  782.             if (b < 0) b = 0; if (b > 255) b = 255;
  783.  
  784.             ds[0] = u8(b);
  785.             ds[1] = u8(g);
  786.             ds[2] = u8(r);
  787.             ds += 3;
  788.         }
  789.         ds = (PBYTE)(ULONG_PTR(ds + 3) & ~ULONG_PTR(3)); // ърцфр  ёЄЁюър т√Ёртэхэр эр 4
  790.     }
  791. }
  792.  
  793. void ConvBgr32ToBgr24(u8 *dst, u8 *scrbuf, int dx)
  794. {
  795.     u8 *ds = dst;
  796.     for(unsigned i = 0; i < temp.oy; i++) // convert to BGR24 format
  797.     {
  798.        unsigned char *src = scrbuf + int(i)*dx;
  799.        for (unsigned x = 0; x < temp.ox; x++)
  800.        {
  801.           ds[0] = src[0];
  802.           ds[1] = src[1];
  803.           ds[2] = src[2];
  804.           src += 4;
  805.           ds += 3;
  806.        }
  807.        ds = (PBYTE)(ULONG_PTR(ds + 3) & ~ULONG_PTR(3)); // ърцфр  ёЄЁюър т√Ёртэхэр эр 4
  808.     }
  809. }
  810.  
  811.  
  812. TColorConverter ConvBgr24 = nullptr;
  813.  
  814. static void SaveBmp(FILE *File, u8 *ds)
  815. {
  816.      static u8 bmpheader32[]=
  817.      {
  818.             // BITMAPFILEHEADER
  819.             0x42,0x4d,           // Type
  820.             0x36,0x10,0x0e,0x00, // Size
  821.             0x00,0x00,           // Reserved1
  822.             0x00,0x00,           // Reserved2
  823.             0x36,0x00,0x00,0x00, // OffBits
  824.             // BITMAPINFOHEADER
  825.             0x28,0x00,0x00,0x00, // Size
  826.             0x80,0x02,0x00,0x00, // Width
  827.             0xe0,0x01,0x00,0x00, // Height
  828.             0x01,0x00,           // Planes
  829.             0x18,0x00,           // BitCount
  830.             0x00,0x00,0x00,0x00, // Compression
  831.             0x00,0x10,0x0e,0x00, // SizeImage
  832.             0x00,0x00,0x00,0x00, // XPixelsPerMeter
  833.             0x00,0x00,0x00,0x00, // YPixelsPerMeter
  834.             0x00,0x00,0x00,0x00, // ClrUsed
  835.             0x00,0x00,0x00,0x00  // ClrImportant
  836.      };
  837.  
  838.     *(unsigned*)(bmpheader32 + 2) = temp.ox * temp.oy * 3 + sizeof(bmpheader32); // filesize
  839.     *(unsigned*)(bmpheader32 + 0x12) = temp.ox;
  840.     *(unsigned*)(bmpheader32 + 0x16) = temp.oy;
  841.     fwrite(bmpheader32, 1, sizeof(bmpheader32), File);
  842.  
  843.     for(int y = int(temp.oy - 1); y >= 0 ; y--)
  844.     {
  845.         fwrite(ds + ((unsigned(y) * temp.ox * 3 + 3) & ~3U), 1, temp.ox * 3, File);
  846.     }
  847. }
  848.  
  849. static void SavePng(FILE *File, u8 *ds)
  850. {
  851.     static png_color bkgColor = {127, 127, 127};
  852.  
  853.     if(!temp.PngSupport)
  854.         return;
  855.  
  856.     PngSaveImage(File, ds, int(temp.ox), int(temp.oy), bkgColor);
  857. }
  858.  
  859. #define MAKE_RGBQUAD(r,g,b) (ULONG) (u32(b) | (u32(g)<<8) | (u32(r)<<16))
  860.  
  861. static void SaveBmp16c(FILE *File, const u8 *ds)
  862. {
  863.      static u8 bmpheader32[]=
  864.      {
  865.             // BITMAPFILEHEADER
  866.             0x42,0x4d,           // Type
  867.             0x36,0x10,0x0e,0x00, // Size = 320*200/2 + sizeof(bmpheader32)
  868.             0x00,0x00,           // Reserved1
  869.             0x00,0x00,           // Reserved2
  870.             0x76,0x00,0x00,0x00, // OffBits
  871.             // BITMAPINFOHEADER
  872.             0x28,0x00,0x00,0x00, // Size
  873.             0x40,0x01,0x00,0x00, // Width = 320
  874.             0xc8,0x00,0x00,0x00, // Height = 200
  875.             0x01,0x00,           // Planes
  876.             0x04,0x00,           // BitCount = 4
  877.             0x00,0x00,0x00,0x00, // Compression = BI_RGB
  878.             0x00,0x10,0x0e,0x00, // SizeImage
  879.             0x00,0x00,0x00,0x00, // XPixelsPerMeter
  880.             0x00,0x00,0x00,0x00, // YPixelsPerMeter
  881.             0x00,0x00,0x00,0x00, // ClrUsed
  882.             0x00,0x00,0x00,0x00, // ClrImportant
  883.             // PALETTE
  884.             0,0,0,0,             //  0 bgra
  885.             0,0,0,0,             //  1 bgra
  886.             0,0,0,0,             //  2 bgra
  887.             0,0,0,0,             //  3 bgra
  888.             0,0,0,0,             //  4 bgra
  889.             0,0,0,0,             //  5 bgra
  890.             0,0,0,0,             //  6 bgra
  891.             0,0,0,0,             //  7 bgra
  892.             0,0,0,0,             //  8 bgra
  893.             0,0,0,0,             //  9 bgra
  894.             0,0,0,0,             // 10 bgra
  895.             0,0,0,0,             // 11 bgra
  896.             0,0,0,0,             // 12 bgra
  897.             0,0,0,0,             // 13 bgra
  898.             0,0,0,0,             // 14 bgra
  899.             0,0,0,0              // 15 bgra
  900.      };
  901.  
  902.     *(unsigned*)(bmpheader32 + 2) = 320 * 200 / 2 + sizeof(bmpheader32); // filesize
  903.     for(unsigned i = 0; i < 16; i++)
  904.     {
  905.         // ╘юЁьрЄ фрээ√ї ярышЄЁ√ Gg0Rr0Bb
  906.         // ╨рёъырфър ярышЄЁ√ ¤ьєы ЄюЁр - ULA+
  907.         unsigned PalIdx = ((i & 8) << 1) | (i & 7);
  908.         u8 r = u8(u32((comp.comp_pal[PalIdx] >> 3) & 3) * 255 / 3);
  909.         u8 g = u8(u32((comp.comp_pal[PalIdx] >> 6) & 3) * 255 / 3);
  910.         u8 b = u8(u32(comp.comp_pal[PalIdx] & 3) * 255 / 3);
  911.  
  912.         *(PULONG)(bmpheader32 + 54 + 4*i) = MAKE_RGBQUAD(r,g,b);
  913.     }
  914.     fwrite(bmpheader32, 1, sizeof(bmpheader32), File);
  915.     fwrite(ds, 1, 320 * 200 / 2, File);
  916. }
  917.  
  918. static void ConvPal16cAtm1(u8 *Buf)
  919. {
  920.     static const int ega0_ofs = -4*PAGE;
  921.     static const int ega1_ofs = 0;
  922.     static const int ega2_ofs = -4*PAGE+0x2000;
  923.     static const int ega3_ofs = 0x2000;
  924.  
  925.    for (int y = 200 - 1; y >= 0; y--)
  926.    {
  927.       const u8 *src = temp.base + y*40;
  928.  
  929.       for(unsigned x = 0; x < 320; x += 8)
  930.       {
  931.           u8 v0 = src[ega0_ofs];
  932.           u8 v1 = src[ega1_ofs];
  933.           u8 v2 = src[ega2_ofs];
  934.           u8 v3 = src[ega3_ofs];
  935.           Buf[0] = u8(((((v0 >> 3) & 8) | (v0 & 0x7)) << 4) |
  936.                    (((v0 & 0x80) | ((v0 << 1) & 0x70)) >> 4));
  937.           Buf[1] = u8(((((v1 >> 3) & 8) | (v1 & 0x7)) << 4) |
  938.                    (((v1 & 0x80) | ((v1 << 1) & 0x70)) >> 4));
  939.           Buf[2] = u8(((((v2 >> 3) & 8) | (v2 & 0x7)) << 4) |
  940.                    (((v2 & 0x80) | ((v2 << 1) & 0x70)) >> 4));
  941.           Buf[3] = u8(((((v3 >> 3) & 8) | (v3 & 0x7)) << 4) |
  942.                    (((v3 & 0x80) | ((v3 << 1) & 0x70)) >> 4));
  943.          
  944.           src++;
  945.           Buf += 4;
  946.       }
  947.    }
  948.  
  949. }
  950.  
  951. #define ConvPal16cAtm2 ConvPal16cAtm1
  952.  
  953. typedef void (*TSaver)(FILE *File, u8 *ds);
  954.  
  955. void main_scrshot()
  956. {
  957.    char fname[FILENAME_MAX];
  958.    static unsigned sshot = 0;
  959.    static const char *Format[] = { "scr", "bmp", "png" };
  960.    static const TSaver Saver[] = { SaveBmp, SavePng };
  961.  
  962.    const char *Ext = Format[conf.scrshot];
  963.  
  964.    if (conf.scrshot == 0 &&
  965.        (
  966.         ((conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3) && ((comp.pFF77 & 7) == 0)) ||
  967.         ((conf.mem_model == MM_ATM450) && (((comp.aFE >> 5) & 3) == 0))
  968.        )
  969.       )
  970.    {
  971.        Ext = Format[1];
  972.    }
  973.  
  974.    snprintf(fname, _countof(fname), "%s\\%s_%06u.%s", conf.scrshot_dir,
  975.        temp.LastSnapName[0] ? temp.LastSnapName : "sshot", sshot, Ext);
  976.    fname[FILENAME_MAX-1] = 0;
  977.  
  978.    FILE *fileShot = fopen(fname, "wb");
  979.    if (!fileShot)
  980.       return;
  981.  
  982.    if (conf.scrshot == 0)
  983.    {
  984.       switch(conf.mem_model)
  985.       {
  986.       case MM_ATM710:
  987.       case MM_ATM3:
  988.           {
  989.               switch(comp.pFF77 & 7)
  990.               {
  991.               case 0: // EGA 320x200 16c
  992.                   {
  993.                       u8 *Buf = (u8 *)malloc(320*200/2);
  994.                       ConvPal16cAtm2(Buf);
  995.                       SaveBmp16c(fileShot, Buf);
  996.                       free(Buf);
  997.                   }
  998.               break;
  999.               case 3:
  1000.                   goto standard_zx_mode;
  1001.               }
  1002.           }
  1003.       break;
  1004.  
  1005.       case MM_ATM450:
  1006.           switch((comp.aFE >> 5) & 3)
  1007.           {
  1008.           case 0: // EGA 320x200 16c
  1009.               {
  1010.                   u8 *Buf = (u8 *)malloc(320*200/2);
  1011.                   ConvPal16cAtm1(Buf);
  1012.                   SaveBmp16c(fileShot, Buf);
  1013.                   free(Buf);
  1014.               }
  1015.           break;
  1016.  
  1017.           case 3:
  1018.               goto standard_zx_mode;
  1019.           }
  1020.       break;
  1021.  
  1022.       default:
  1023. standard_zx_mode:;
  1024.           fwrite(temp.base, 1, 6912, fileShot);
  1025.       }
  1026.    }
  1027.    else
  1028.    {
  1029.       unsigned dx = temp.ox * temp.obpp / 8;
  1030.       unsigned char *scrbuf_unaligned = (unsigned char*)malloc(dx * temp.oy + CACHE_LINE);
  1031.       unsigned char *scrbuf = (unsigned char*)align_by(scrbuf_unaligned, CACHE_LINE);
  1032.       memset(scrbuf, 0, dx * temp.oy);
  1033.       renders[conf.render].func(scrbuf, dx); // render to memory buffer (PAL8, YUY2, RGB15, RGB16, RGB32)
  1034.  
  1035.       u8 *ds = (u8 *)malloc(((temp.ox * 3 + 3) & ~3U) * temp.oy);
  1036.       ConvBgr24(ds, scrbuf, int(dx));
  1037.  
  1038.       Saver[conf.scrshot - 1](fileShot, ds);
  1039.  
  1040.       free(ds);
  1041.       free(scrbuf_unaligned);
  1042.    }
  1043.    fclose(fileShot);
  1044.    sprintf(statusline, "saving %s", strrchr(fname, '\\') + 1);
  1045.    statcnt = 30;
  1046.    sshot++;
  1047. }
  1048. /*
  1049. static void VideoFrameSaver()
  1050. {
  1051.    char fname[FILENAME_MAX];
  1052.    static unsigned FrameNum = 0;
  1053.    static const char *Format[] = { "scr", "bmp", "png" };
  1054.    static const TSaver Saver[] = { SaveBmp, SavePng };
  1055.  
  1056.    sprintf(fname, "video%06u.%s", FrameNum, Format[conf.scrshot]);
  1057.    addpath(fname);
  1058.  
  1059.    FILE *fileShot = fopen(fname, "wb");
  1060.    if (!fileShot)
  1061.       return;
  1062.  
  1063.    if (conf.scrshot == 0)
  1064.    {
  1065.       fwrite(temp.base, 1, 6912, fileShot);
  1066.    }
  1067.    else
  1068.    {
  1069.        unsigned dx = temp.ox * temp.obpp / 8;
  1070.        unsigned char *scrbuf_unaligned = (unsigned char*)malloc(dx * temp.oy + CACHE_LINE);
  1071.        unsigned char *scrbuf = (unsigned char*)align_by(scrbuf_unaligned, CACHE_LINE);
  1072.        memset(scrbuf, 0, dx * temp.oy);
  1073.        renders[conf.render].func(scrbuf, dx); // render to memory buffer (PAL8, YUY2, RGB15, RGB16, RGB32)
  1074.  
  1075.        u8 *ds = (u8 *)malloc(((temp.ox * 3 + 3) & ~3) * temp.oy);
  1076.        ConvBgr24(ds, scrbuf, dx);
  1077.  
  1078.        Saver[conf.scrshot - 1](fileShot, ds);
  1079.  
  1080.        free(ds);
  1081.        free(scrbuf_unaligned);
  1082.    }
  1083.    fclose(fileShot);
  1084.    FrameNum++;
  1085. }
  1086.  
  1087. static void VideoNullSaver()
  1088. {
  1089.  
  1090. }
  1091.  
  1092. TVideoSaver VideoSaver = VideoNullSaver;
  1093.  
  1094. void main_savevideo()
  1095. {
  1096.    static bool StartSave = false;
  1097.  
  1098.    if(!StartSave)
  1099.    {
  1100.        sprintf(statusline, "start saving video");
  1101.        StartSave = true;
  1102.        VideoSaver = VideoFrameSaver;
  1103.    }
  1104.    else
  1105.    {
  1106.        sprintf(statusline, "stop saving video");
  1107.        StartSave = false;
  1108.        VideoSaver = VideoNullSaver;
  1109.    }
  1110.  
  1111.    statcnt = 30;
  1112. }
  1113. */
  1114.  
  1115.