Subversion Repositories pentevo

Rev

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