Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
716 lvd 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