File: common\loadfdos.c
1 /*
2 loadfdos.c - subroutine of loadfile.c (read_overlay) which sets
3 up video (mode, screen size).
4 This module is linked as an overlay, should only be called from loadfile.c
5
6 This code was split to a separate module to isolate the DOS only aspects
7 of loading an image. get_video_mode should return with:
8 return code 0 for ok, -1 for error or cancelled by user
9 video parameters setup for the mainline, in the dos case this means
10 setting initmode to video mode, based on this fractint.c will set up
11 for and call setvideomode
12 set viewwindow on if file going to be loaded into a view smaller than
13 physical screen, in this case also set viewreduction, viewxdots,
14 viewydots, and finalaspectratio
15 set skipxdots and skipydots, to 0 if all pixels are to be loaded,
16 to 1 for every 2nd pixel, 2 for every 3rd, etc
17
18 In WinFract, at least initially, get_video_mode can do just the
19 following:
20 set overall image x & y dimensions (sxdots and sydots) to filexdots
21 and fileydots (note that filecolors is the number of colors in the
22 gif, not sure if that is of any use...)
23 if current window smaller than new sxdots and sydots, use scroll bars,
24 if larger perhaps reduce the window size? whatever
25 set viewwindow to 0 (no need? it always is for now in windows vsn?)
26 set finalaspectratio to .75 (ditto?)
27 set skipxdots and skipydots to 0
28 return 0
29
30 */
31
32 #include <string.h>
33 /* see Fractint.c for a description of the "include" hierarchy */
34 #include "port.h"
35 #include "prototyp.h"
36 #include "helpdefs.h"
37
38 /* routines in this module */
39
40 #ifndef XFRACT
41 static int vidcompare(VOIDCONSTPTR ,VOIDCONSTPTR );
42 static void format_item(int,char *);
43 static int check_modekey(int,int);
44 static void format_vid_inf(int i,char *err,char *buf);
45 #endif
46 static double vid_aspect(int tryxdots,int tryydots);
47
48 struct vidinf {
49 int entnum; /* videoentry subscript */
50 unsigned flags; /* flags for sort's compare, defined below */
51 };
52 /* defines for flags; done this way instead of bit union to ensure ordering;
53 these bits represent the sort sequence for video mode list */
54 #define VI_EXACT 0x8000 /* unless the one and only exact match */
55 #define VI_NOKEY 512 /* if no function key assigned */
56 #define VI_DISK1 256 /* disk video and size not exact */
57 #define VI_SSMALL 128 /* screen smaller than file's screen */
58 #define VI_SBIG 64 /* screen bigger than file's screen */
59 #define VI_VSMALL 32 /* screen smaller than file's view */
60 #define VI_VBIG 16 /* screen bigger than file's view */
61 #define VI_CSMALL 8 /* mode has too few colors */
62 #define VI_CBIG 4 /* mode has excess colors */
63 #define VI_DISK2 2 /* disk video */
64 #define VI_ASPECT 1 /* aspect ratio bad */
65
66 #ifndef XFRACT
67 static int vidcompare(VOIDCONSTPTR p1,VOIDCONSTPTR p2)
68 {
69 struct vidinf CONST *ptr1,*ptr2;
70 ptr1 = (struct vidinf CONST *)p1;
71 ptr2 = (struct vidinf CONST *)p2;
72 if (ptr1->flags < ptr2->flags) return(-1);
73 if (ptr1->flags > ptr2->flags) return(1);
74 if (vidtbl[ptr1->entnum].keynum < vidtbl[ptr2->entnum].keynum) return(-1);
75 if (vidtbl[ptr1->entnum].keynum > vidtbl[ptr2->entnum].keynum) return(1);
76 if (ptr1->entnum < ptr2->entnum) return(-1);
77 return(1);
78 }
79
80 static void format_vid_inf(int i,char *err,char *buf)
81 {
82 char kname[5];
83 far_memcpy((char far *)&videoentry,(char far *)&vidtbl[i],
84 sizeof(videoentry));
85 vidmode_keyname(videoentry.keynum,kname);
86 sprintf(buf,"%-5s %-25s %-4s %5d %5d %3d %-25s", /* 78 chars */
87 kname, videoentry.name, err,
88 videoentry.xdots, videoentry.ydots,
89 videoentry.colors, videoentry.comment);
90 videoentry.xdots = 0; /* so tab_display knows to display nothing */
91 }
92 #endif
93
94 static double vid_aspect(int tryxdots,int tryydots)
95 { /* calc resulting aspect ratio for specified dots in current mode */
96 return (double)tryydots / (double)tryxdots
97 * (double)videoentry.xdots / (double)videoentry.ydots
98 * screenaspect;
99 }
100
101 #ifndef XFRACT
102 static struct vidinf *vidptr;
103 #endif
104
105 int get_video_mode(struct fractal_info *info,struct ext_blk_3 *blk_3_info)
106 {
107 static FCODE o_hdg2[]={"key...name......................err...xdot..ydot.clr.comment.................."};
108 static FCODE o_warning[]={"\nWARNING: non-standard aspect ratio; loading will change your <v>iew settings"};
109 static FCODE o_select_msg[]={"\
110 Select a video mode. Use the cursor keypad to move the pointer.\n\
111 Press ENTER for selected mode, or use a video mode function key.\n\
112 Press F1 for help, "};
113 char far *hdg2, far *warning, far *select_msg, far *ptr;
114 struct vidinf vid[MAXVIDEOMODES];
115 int i,j;
116 int gotrealmode;
117 double ftemp,ftemp2;
118 unsigned tmpflags;
119
120 int tmpxdots,tmpydots;
121 float tmpreduce;
122 #ifndef XFRACT
123 char *nameptr;
124 int *attributes;
125 int oldhelpmode;
126 #endif
127 VIDEOINFO *vident;
128
129 /* save overlayed strings to extraseg memory */
130 ptr = (char far *)MK_FP(extraseg,ENDVID); /* ENDVID is to avoid videotable */
131 hdg2 = ptr;
132 ptr += sizeof(o_hdg2);
133 warning = ptr;
134 ptr += sizeof(o_warning);
135 select_msg = ptr;
136 far_strcpy(hdg2,o_hdg2);
137 far_strcpy(warning,o_warning);
138 far_strcpy(select_msg,o_select_msg);
139
140 initmode = -1;
141 load_fractint_cfg(0); /* get fractint.cfg into *vidtbl (== extraseg) */
142
143 /* try to change any VESA entries to fit the loaded image size */
144 if (virtual && video_vram && initmode == -1) {
145 unsigned long vram = (unsigned long)video_vram << 16,
146 need = (unsigned long)info->xdots * info->ydots;
147 if (need <= vram) {
148 char over[25]; /* overwrite comments with original resolutions */
149 int bppx; /* bytesperpixel multiplier */
150 for (i = 0; i < vidtbllen; ++i) {
151 vident = &vidtbl[i];
152 if (vident->dotmode%100 == 28 && vident->colors >= 256
153 && (info->xdots > vident->xdots || info->ydots > vident->ydots)
154 && vram >= (unsigned long)
155 (info->xdots < vident->xdots ? vident->xdots : info->xdots)
156 * (info->ydots < vident->ydots ? vident->ydots : info->ydots)
157 * ((bppx = vident->dotmode/1000) < 2 ? ++bppx : bppx)) {
158
159 sprintf(over,"<-VIRTUAL! at %4u x %4u",vident->xdots,vident->ydots);
160 far_strcpy((char far *)vident->comment,(char far *)over);
161
162 if (info->xdots > vident->xdots)
163 vident->xdots = info->xdots;
164 if (info->ydots > vident->ydots)
165 vident->ydots = info->ydots;
166 } /* change entry to force VESA virtual scanline setup */
167 }
168 }
169 }
170
171 /* try to find exact match for vid mode */
172 for (i = 0; i < vidtbllen; ++i) {
173 vident = &vidtbl[i];
174 if (info->xdots == vident->xdots && info->ydots == vident->ydots
175 && filecolors == vident->colors
176 && info->videomodeax == vident->videomodeax
177 && info->videomodebx == vident->videomodebx
178 && info->videomodecx == vident->videomodecx
179 && info->videomodedx == vident->videomodedx
180 && info->dotmode%100 == vident->dotmode%100) {
181 initmode = i;
182 break;
183 }
184 }
185
186 /* exit in makepar mode if no exact match of video mode in file */
187 if(*s_makepar == '\0' && initmode == -1)
188 return(0);
189
190 if (initmode == -1) /* try to find very good match for vid mode */
191 for (i = 0; i < vidtbllen; ++i) {
192 vident = &vidtbl[i];
193 if (info->xdots == vident->xdots && info->ydots == vident->ydots
194 && filecolors == vident->colors) {
195 initmode = i;
196 break;
197 }
198 }
199
200 /* setup table entry for each vid mode, flagged for how well it matches */
201 for (i = 0; i < vidtbllen; ++i) {
202 far_memcpy((char far *)&videoentry,(char far *)&vidtbl[i],
203 sizeof(videoentry));
204 tmpflags = VI_EXACT;
205 if (videoentry.keynum == 0)
206 tmpflags |= VI_NOKEY;
207 if (info->xdots > videoentry.xdots || info->ydots > videoentry.ydots)
208 tmpflags |= VI_SSMALL;
209 else if (info->xdots < videoentry.xdots || info->ydots < videoentry.ydots)
210 tmpflags |= VI_SBIG;
211 if (filexdots > videoentry.xdots || fileydots > videoentry.ydots)
212 tmpflags |= VI_VSMALL;
213 else if (filexdots < videoentry.xdots || fileydots < videoentry.ydots)
214 tmpflags |= VI_VBIG;
215 if (filecolors > videoentry.colors)
216 tmpflags |= VI_CSMALL;
217 if (filecolors < videoentry.colors)
218 tmpflags |= VI_CBIG;
219 if (i == initmode)
220 tmpflags -= VI_EXACT;
221 if (videoentry.dotmode%100 == 11) {
222 tmpflags |= VI_DISK2;
223 if ((tmpflags & (VI_SBIG+VI_SSMALL+VI_VBIG+VI_VSMALL)) != 0)
224 tmpflags |= VI_DISK1;
225 }
226 if (fileaspectratio != 0 && videoentry.dotmode%100 != 11
227 && (tmpflags & VI_VSMALL) == 0) {
228 ftemp = vid_aspect(filexdots,fileydots);
229 if ( ftemp < fileaspectratio * 0.98
230 || ftemp > fileaspectratio * 1.02)
231 tmpflags |= VI_ASPECT;
232 }
233 vid[i].entnum = i;
234 vid[i].flags = tmpflags;
235 }
236
237 if (fastrestore && !askvideo)
238 initmode = adapter;
239
240 #ifndef XFRACT
241 gotrealmode = 0;
242 if ((initmode < 0 || (askvideo && !initbatch)) && *s_makepar != '\0') {
243 /* no exact match or (askvideo=yes and batch=no), and not
244 in makepar mode, talk to user */
245
246 qsort(vid,vidtbllen,sizeof(vid[0]),vidcompare); /* sort modes */
247
248 attributes = (int *)&dstack[1000];
249 for (i = 0; i < vidtbllen; ++i)
250 attributes[i] = 1;
251 vidptr = &vid[0]; /* for format_item */
252
253 /* format heading */
254 if (info->info_id[0] == 'G')
255 strcpy(temp1," Non-fractal GIF");
256 else {
257 nameptr = curfractalspecific->name;
258 if (*nameptr == '*') ++nameptr;
259 if (display3d) nameptr = "3D Transform";
260 if ((!strcmp(nameptr,"formula")) ||
261 (!strcmp(nameptr,"lsystem")) ||
262 (!strncmp(nameptr,"ifs",3))) /* for ifs and ifs3d */
263 sprintf(temp1,"Type: %s -> %s",nameptr,blk_3_info->form_name);
264 else
265 sprintf(temp1,"Type: %s",nameptr);
266 }
267 sprintf((char *)dstack,"File: %-44s %d x %d x %d\n%-52s",
268 readname,filexdots,fileydots,filecolors,temp1);
269 if (info->info_id[0] != 'G') {
270 if (save_system)
271 strcat((char *)dstack,"WinFract ");
272 sprintf(temp1,"v%d.%01d",save_release/100,(save_release%100)/10);
273 if (save_release%100) {
274 i = strlen(temp1);
275 temp1[i] = (char)((save_release%10) + '0');
276 temp1[i+1] = 0;
277 }
278 if (save_system == 0 && save_release <= 1410)
279 strcat(temp1," or earlier");
280 strcat((char *)dstack,temp1);
281 }
282 strcat((char *)dstack,"\n");
283 if (info->info_id[0] != 'G' && save_system == 0)
284 if (initmode < 0)
285 strcat((char *)dstack,"Saved in unknown video mode.");
286 else {
287 format_vid_inf(initmode,"",temp1);
288 strcat((char *)dstack,temp1);
289 }
290 if (fileaspectratio != 0 && fileaspectratio != screenaspect)
291 far_strcat((char *)dstack,warning);
292 strcat((char *)dstack,"\n");
293 /* set up instructions */
294 far_strcpy(temp1,select_msg);
295 if (info->info_id[0] != 'G')
296 strcat(temp1,"TAB for fractal information, ");
297 strcat(temp1,"ESCAPE to back out.");
298
299 oldhelpmode = helpmode;
300 helpmode = HELPLOADFILE;
301 i = fullscreen_choice(0,(char *)dstack,hdg2,temp1,vidtbllen,NULL,attributes,
302 1,13,78,0,format_item,NULL,NULL,check_modekey);
303 helpmode = oldhelpmode;
304 if (i == -1)
305 return(-1);
306 if (i < 0) { /* returned -100 - videotable entry number */
307 initmode = -100 - i;
308 gotrealmode = 1;
309 }
310 else
311 initmode = vid[i].entnum;
312 }
317 #endif
318
319 if (gotrealmode == 0) { /* translate from temp table to permanent */
320 if ((j = vidtbl[i=initmode].keynum) != 0) {
321 for (initmode = 0; initmode < MAXVIDEOTABLE-1; ++initmode)
322 if (videotable[initmode].keynum == j) break;
323 if (initmode >= MAXVIDEOTABLE-1) j = 0;
324 }
325 if (j == 0) /* mode has no key, add to reserved slot at end */
326 far_memcpy((char far *)&videotable[initmode=MAXVIDEOTABLE-1],
327 (char far *)&vidtbl[i],sizeof(*vidtbl));
328 }
329
330 /* ok, we're going to return with a video mode */
331
332 far_memcpy((char far *)&videoentry,(char far *)&videotable[initmode],
333 sizeof(videoentry));
334
335
336 if (viewwindow &&
337 filexdots == videoentry.xdots && fileydots == videoentry.ydots) {
338 /* pull image into a view window */
339 if (calc_status != 4) /* if not complete */
340 calc_status = 0; /* can't resume anyway */
341 if (viewxdots) {
342 viewreduction = videoentry.xdots / viewxdots;
343 viewxdots = viewydots = 0; /* easier to use auto reduction */
344 }
345 viewreduction = (float)((int)(viewreduction + 0.5)); /* need integer value */
346 skipxdots = skipydots = (short)(viewreduction - 1);
347 return(0);
348 }
349
350 skipxdots = skipydots = 0; /* set for no reduction */
351 if (videoentry.xdots < filexdots || videoentry.ydots < fileydots) {
352 /* set up to load only every nth pixel to make image fit */
353 if (calc_status != 4) /* if not complete */
354 calc_status = 0; /* can't resume anyway */
355 skipxdots = skipydots = 1;
356 while (skipxdots * videoentry.xdots < filexdots) ++skipxdots;
357 while (skipydots * videoentry.ydots < fileydots) ++skipydots;
358 i = j = 0;
359 for(;;) {
360 tmpxdots = (filexdots + skipxdots - 1) / skipxdots;
361 tmpydots = (fileydots + skipydots - 1) / skipydots;
362 if (fileaspectratio == 0 || videoentry.dotmode%100 == 11)
363 break;
364 /* reduce further if that improves aspect */
365 if ((ftemp = vid_aspect(tmpxdots,tmpydots)) > fileaspectratio) {
366 if (j) break; /* already reduced x, don't reduce y */
367 ftemp2 = vid_aspect(tmpxdots,(fileydots+skipydots)/(skipydots+1));
368 if (ftemp2 < fileaspectratio
369 && ftemp/fileaspectratio *0.9 <= fileaspectratio/ftemp2)
370 break; /* further y reduction is worse */
371 ++skipydots;
372 ++i;
373 }
374 else {
375 if (i) break; /* already reduced y, don't reduce x */
376 ftemp2 = vid_aspect((filexdots+skipxdots)/(skipxdots+1),tmpydots);
377 if (ftemp2 > fileaspectratio
378 && fileaspectratio/ftemp *0.9 <= ftemp2/fileaspectratio)
379 break; /* further x reduction is worse */
380 ++skipxdots;
381 ++j;
382 }
383 }
384 filexdots = tmpxdots;
385 fileydots = tmpydots;
386 --skipxdots;
387 --skipydots;
388 }
389
390 if ((finalaspectratio = fileaspectratio) == 0) /* assume display correct */
391 finalaspectratio = (float)vid_aspect(filexdots,fileydots);
392 if (finalaspectratio >= screenaspect-0.02
393 && finalaspectratio <= screenaspect+0.02)
394 finalaspectratio = screenaspect;
395 i = (int)(finalaspectratio * 1000.0 + 0.5);
396 finalaspectratio = (float)(i/1000.0); /* chop precision to 3 decimals */
397
398 /* setup view window stuff */
399 viewwindow = viewxdots = viewydots = 0;
400 if (filexdots != videoentry.xdots || fileydots != videoentry.ydots) {
401 /* image not exactly same size as screen */
402 viewwindow = 1;
403 ftemp = finalaspectratio
404 * (double)videoentry.ydots / (double)videoentry.xdots
405 / screenaspect;
406 if (finalaspectratio <= screenaspect) {
407 i = (int)((double)videoentry.xdots / (double)filexdots * 20.0 + 0.5);
408 tmpreduce = (float)(i/20.0); /* chop precision to nearest .05 */
409 i = (int)((double)videoentry.xdots / tmpreduce + 0.5);
410 j = (int)((double)i * ftemp + 0.5);
411 }
412 else {
413 i = (int)((double)videoentry.ydots / (double)fileydots * 20.0 + 0.5);
414 tmpreduce = (float)(i/20.0); /* chop precision to nearest .05 */
415 j = (int)((double)videoentry.ydots / tmpreduce + 0.5);
416 i = (int)((double)j / ftemp + 0.5);
417 }
418 if (i != filexdots || j != fileydots) { /* too bad, must be explicit */
419 viewxdots = filexdots;
420 viewydots = fileydots;
421 }
422 else
423 viewreduction = tmpreduce; /* ok, this works */
424 }
425 if (*s_makepar && !fastrestore && !initbatch &&
426 (fabs(finalaspectratio - screenaspect) > .00001 || viewxdots != 0)) {
427 static FCODE msg[] = {"\
428 Warning: <V>iew parameters are being set to non-standard values.\n\
429 Remember to reset them when finished with this image!"};
430 stopmsg(4,msg);
431 }
432 return(0);
433 }
434
435 #ifndef XFRACT
436 static void format_item(int choice,char *buf)
437 {
438 char errbuf[10];
439 unsigned tmpflags;
440 errbuf[0] = 0;
441 tmpflags = vidptr[choice].flags;
442 if (tmpflags & (VI_VSMALL+VI_CSMALL+VI_ASPECT)) strcat(errbuf,"*");
443 if (tmpflags & VI_VSMALL) strcat(errbuf,"R");
444 if (tmpflags & VI_CSMALL) strcat(errbuf,"C");
445 if (tmpflags & VI_ASPECT) strcat(errbuf,"A");
446 if (tmpflags & VI_VBIG) strcat(errbuf,"v");
447 if (tmpflags & VI_CBIG) strcat(errbuf,"c");
448 format_vid_inf(vidptr[choice].entnum,errbuf,buf);
449 }
450
451 static int check_modekey(int curkey,int choice)
452 {
453 int i;
454 i=choice; /* avoid warning */
455 return (((i = check_vidmode_key(0,curkey)) >= 0) ? -100-i : 0);
456 }
457 #endif
458