1 /*
2 * Copyright (C) 2002-2010 The DOSBox Team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 /* $Id: render.cpp,v 1.60 2009-04-26 19:14:50 harekiet Exp $ */
20
21 #include <sys/types.h>
22 #include <assert.h>
23 #include <math.h>
24
25 #include "dosbox.h"
26 #include "video.h"
27 #include "render.h"
28 #include "setup.h"
29 #include "control.h"
30 #include "mapper.h"
31 #include "cross.h"
32 #include "hardware.h"
33 #include "support.h"
34
35 #include "render_scalers.h"
36
37 Render_t render;
38 ScalerLineHandler_t RENDER_DrawLine;
39
40 static void RENDER_CallBack( GFX_CallBackFunctions_t function );
41
Check_Palette(void)42 static void Check_Palette(void) {
43 /* Clean up any previous changed palette data */
44 if (render.pal.changed) {
45 memset(render.pal.modified, 0, sizeof(render.pal.modified));
46 render.pal.changed = false;
47 }
48 if (render.pal.first>render.pal.last)
49 return;
50 Bitu i;
51 switch (render.scale.outMode) {
52 case scalerMode8:
53 GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]);
54 break;
55 case scalerMode15:
56 case scalerMode16:
57 for (i=render.pal.first;i<=render.pal.last;i++) {
58 Bit8u r=render.pal.rgb[i].red;
59 Bit8u g=render.pal.rgb[i].green;
60 Bit8u b=render.pal.rgb[i].blue;
61 Bit16u newPal = GFX_GetRGB(r,g,b);
62 if (newPal != render.pal.lut.b16[i]) {
63 render.pal.changed = true;
64 render.pal.modified[i] = 1;
65 render.pal.lut.b16[i] = newPal;
66 }
67 }
68 break;
69 case scalerMode32:
70 default:
71 for (i=render.pal.first;i<=render.pal.last;i++) {
72 Bit8u r=render.pal.rgb[i].red;
73 Bit8u g=render.pal.rgb[i].green;
74 Bit8u b=render.pal.rgb[i].blue;
75 Bit32u newPal = GFX_GetRGB(r,g,b);
76 if (newPal != render.pal.lut.b32[i]) {
77 render.pal.changed = true;
78 render.pal.modified[i] = 1;
79 render.pal.lut.b32[i] = newPal;
80 }
81 }
82 break;
83 }
84 /* Setup pal index to startup values */
85 render.pal.first=256;
86 render.pal.last=0;
87 }
88
RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue)89 void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue) {
90 render.pal.rgb[entry].red=red;
91 render.pal.rgb[entry].green=green;
92 render.pal.rgb[entry].blue=blue;
93 if (render.pal.first>entry) render.pal.first=entry;
94 if (render.pal.last<entry) render.pal.last=entry;
95 }
96
RENDER_EmptyLineHandler(const void * src)97 static void RENDER_EmptyLineHandler(const void * src) {
98 }
99
RENDER_StartLineHandler(const void * s)100 static void RENDER_StartLineHandler(const void * s) {
101 if (s) {
102 const Bitu *src = (Bitu*)s;
103 Bitu *cache = (Bitu*)(render.scale.cacheRead);
104 for (Bits x=render.src.start;x>0;) {
105 if (GCC_UNLIKELY(src[0] != cache[0])) {
106 if (!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )) {
107 RENDER_DrawLine = RENDER_EmptyLineHandler;
108 return;
109 }
110 render.scale.outWrite += render.scale.outPitch * Scaler_ChangedLines[0];
111 RENDER_DrawLine = render.scale.lineHandler;
112 RENDER_DrawLine( s );
113 return;
114 }
115 x--; src++; cache++;
116 }
117 }
118 render.scale.cacheRead += render.scale.cachePitch;
119 Scaler_ChangedLines[0] += Scaler_Aspect[ render.scale.inLine ];
120 render.scale.inLine++;
121 render.scale.outLine++;
122 }
123
RENDER_FinishLineHandler(const void * s)124 static void RENDER_FinishLineHandler(const void * s) {
125 if (s) {
126 const Bitu *src = (Bitu*)s;
127 Bitu *cache = (Bitu*)(render.scale.cacheRead);
128 for (Bits x=render.src.start;x>0;) {
129 cache[0] = src[0];
130 x--; src++; cache++;
131 }
132 }
133 render.scale.cacheRead += render.scale.cachePitch;
134 }
135
136
RENDER_ClearCacheHandler(const void * src)137 static void RENDER_ClearCacheHandler(const void * src) {
138 Bitu x, width;
139 Bit32u *srcLine, *cacheLine;
140 srcLine = (Bit32u *)src;
141 cacheLine = (Bit32u *)render.scale.cacheRead;
142 width = render.scale.cachePitch / 4;
143 for (x=0;x<width;x++)
144 cacheLine[x] = ~srcLine[x];
145 render.scale.lineHandler( src );
146 }
147
RENDER_StartUpdate(void)148 bool RENDER_StartUpdate(void) {
149 if (GCC_UNLIKELY(render.updating))
150 return false;
151 if (GCC_UNLIKELY(!render.active))
152 return false;
153 if (GCC_UNLIKELY(render.frameskip.count<render.frameskip.max)) {
154 render.frameskip.count++;
155 return false;
156 }
157 render.frameskip.count=0;
158 if (render.scale.inMode == scalerMode8) {
159 Check_Palette();
160 }
161 render.scale.inLine = 0;
162 render.scale.outLine = 0;
163 render.scale.cacheRead = (Bit8u*)&scalerSourceCache;
164 render.scale.outWrite = 0;
165 render.scale.outPitch = 0;
166 Scaler_ChangedLines[0] = 0;
167 Scaler_ChangedLineIndex = 0;
168 /* Clearing the cache will first process the line to make sure it's never the same */
169 if (GCC_UNLIKELY( render.scale.clearCache) ) {
170 // LOG_MSG("Clearing cache");
171 //Will always have to update the screen with this one anyway, so let's update already
172 if (GCC_UNLIKELY(!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )))
173 return false;
174 render.fullFrame = true;
175 render.scale.clearCache = false;
176 RENDER_DrawLine = RENDER_ClearCacheHandler;
177 } else {
178 if (render.pal.changed) {
179 /* Assume pal changes always do a full screen update anyway */
180 if (GCC_UNLIKELY(!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )))
181 return false;
182 RENDER_DrawLine = render.scale.linePalHandler;
183 render.fullFrame = true;
184 } else {
185 RENDER_DrawLine = RENDER_StartLineHandler;
186 if (GCC_UNLIKELY(CaptureState & (CAPTURE_IMAGE|CAPTURE_VIDEO)))
187 render.fullFrame = true;
188 else
189 render.fullFrame = false;
190 }
191 }
192 render.updating = true;
193 return true;
194 }
195
RENDER_Halt(void)196 static void RENDER_Halt( void ) {
197 RENDER_DrawLine = RENDER_EmptyLineHandler;
198 GFX_EndUpdate( 0 );
199 render.updating=false;
200 render.active=false;
201 }
202
203 extern Bitu PIC_Ticks;
RENDER_EndUpdate(bool abort)204 void RENDER_EndUpdate( bool abort ) {
205 if (GCC_UNLIKELY(!render.updating))
206 return;
207 RENDER_DrawLine = RENDER_EmptyLineHandler;
208 if (GCC_UNLIKELY(CaptureState & (CAPTURE_IMAGE|CAPTURE_VIDEO))) {
209 Bitu pitch, flags;
210 flags = 0;
211 if (render.src.dblw != render.src.dblh) {
212 if (render.src.dblw) flags|=CAPTURE_FLAG_DBLW;
213 if (render.src.dblh) flags|=CAPTURE_FLAG_DBLH;
214 }
215 float fps = render.src.fps;
216 pitch = render.scale.cachePitch;
217 if (render.frameskip.max)
218 fps /= 1+render.frameskip.max;
219 CAPTURE_AddImage( render.src.width, render.src.height, render.src.bpp, pitch,
220 flags, fps, (Bit8u *)&scalerSourceCache, (Bit8u*)&render.pal.rgb );
221 }
222 if ( render.scale.outWrite ) {
223 GFX_EndUpdate( abort? NULL : Scaler_ChangedLines );
224 render.frameskip.hadSkip[render.frameskip.index] = 0;
225 } else {
226 #if 0
227 Bitu total = 0, i;
228 render.frameskip.hadSkip[render.frameskip.index] = 1;
229 for (i = 0;i<RENDER_SKIP_CACHE;i++)
230 total += render.frameskip.hadSkip[i];
231 LOG_MSG( "Skipped frame %d %d", PIC_Ticks, (total * 100) / RENDER_SKIP_CACHE );
232 #endif
233 }
234 render.frameskip.index = (render.frameskip.index + 1) & (RENDER_SKIP_CACHE - 1);
235 render.updating=false;
236 }
237
MakeAspectTable(Bitu skip,Bitu height,double scaley,Bitu miny)238 static Bitu MakeAspectTable(Bitu skip,Bitu height,double scaley,Bitu miny) {
239 Bitu i;
240 double lines=0;
241 Bitu linesadded=0;
242 for (i=0;i<skip;i++)
243 Scaler_Aspect[i] = 0;
244
245 height += skip;
246 for (i=skip;i<height;i++) {
247 lines += scaley;
248 if (lines >= miny) {
249 Bitu templines = (Bitu)lines;
250 lines -= templines;
251 linesadded += templines;
252 Scaler_Aspect[i] = templines;
253 } else {
254 Scaler_Aspect[i] = 0;
255 }
256 }
257 return linesadded;
258 }
259
260
RENDER_Reset(void)261 static void RENDER_Reset( void ) {
262 Bitu width=render.src.width;
263 Bitu height=render.src.height;
264 bool dblw=render.src.dblw;
265 bool dblh=render.src.dblh;
266
267 double gfx_scalew;
268 double gfx_scaleh;
269
270 Bitu gfx_flags, xscale, yscale;
271 ScalerSimpleBlock_t *simpleBlock = &ScaleNormal1x;
272 ScalerComplexBlock_t *complexBlock = 0;
273 if (render.aspect) {
274 if (render.src.ratio>1.0) {
275 gfx_scalew = 1;
276 gfx_scaleh = render.src.ratio;
277 } else {
278 gfx_scalew = (1/render.src.ratio);
279 gfx_scaleh = 1;
280 }
281 } else {
282 gfx_scalew = 1;
283 gfx_scaleh = 1;
284 }
285 if ((dblh && dblw) || (render.scale.forced && !dblh && !dblw)) {
286 /* Initialize always working defaults */
287 if (render.scale.size == 2)
288 simpleBlock = &ScaleNormal2x;
289 else if (render.scale.size == 3)
290 simpleBlock = &ScaleNormal3x;
291 else
292 simpleBlock = &ScaleNormal1x;
293 /* Maybe override them */
294 #if RENDER_USE_ADVANCED_SCALERS>0
295 switch (render.scale.op) {
296 #if RENDER_USE_ADVANCED_SCALERS>2
297 case scalerOpAdvInterp:
298 if (render.scale.size == 2)
299 complexBlock = &ScaleAdvInterp2x;
300 else if (render.scale.size == 3)
301 complexBlock = &ScaleAdvInterp3x;
302 break;
303 case scalerOpAdvMame:
304 if (render.scale.size == 2)
305 complexBlock = &ScaleAdvMame2x;
306 else if (render.scale.size == 3)
307 complexBlock = &ScaleAdvMame3x;
308 break;
309 case scalerOpHQ:
310 if (render.scale.size == 2)
311 complexBlock = &ScaleHQ2x;
312 else if (render.scale.size == 3)
313 complexBlock = &ScaleHQ3x;
314 break;
315 case scalerOpSuperSaI:
316 if (render.scale.size == 2)
317 complexBlock = &ScaleSuper2xSaI;
318 break;
319 case scalerOpSuperEagle:
320 if (render.scale.size == 2)
321 complexBlock = &ScaleSuperEagle;
322 break;
323 case scalerOpSaI:
324 if (render.scale.size == 2)
325 complexBlock = &Scale2xSaI;
326 break;
327 #endif
328 case scalerOpTV:
329 if (render.scale.size == 2)
330 simpleBlock = &ScaleTV2x;
331 else if (render.scale.size == 3)
332 simpleBlock = &ScaleTV3x;
333 break;
334 case scalerOpRGB:
335 if (render.scale.size == 2)
336 simpleBlock = &ScaleRGB2x;
337 else if (render.scale.size == 3)
338 simpleBlock = &ScaleRGB3x;
339 break;
340 case scalerOpScan:
341 if (render.scale.size == 2)
342 simpleBlock = &ScaleScan2x;
343 else if (render.scale.size == 3)
344 simpleBlock = &ScaleScan3x;
345 break;
346 default:
347 break;
348 }
349 #endif
350 } else if (dblw) {
351 simpleBlock = &ScaleNormalDw;
352 } else if (dblh) {
353 simpleBlock = &ScaleNormalDh;
354 } else {
355 forcenormal:
356 complexBlock = 0;
357 simpleBlock = &ScaleNormal1x;
358 }
359 if (complexBlock) {
360 #if RENDER_USE_ADVANCED_SCALERS>1
361 if ((width >= SCALER_COMPLEXWIDTH - 16) || height >= SCALER_COMPLEXHEIGHT - 16) {
362 LOG_MSG("Scaler can't handle this resolution, going back to normal");
363 goto forcenormal;
364 }
365 #else
366 goto forcenormal;
367 #endif
368 gfx_flags = complexBlock->gfxFlags;
369 xscale = complexBlock->xscale;
370 yscale = complexBlock->yscale;
371 // LOG_MSG("Scaler:%s",complexBlock->name);
372 } else {
373 gfx_flags = simpleBlock->gfxFlags;
374 xscale = simpleBlock->xscale;
375 yscale = simpleBlock->yscale;
376 // LOG_MSG("Scaler:%s",simpleBlock->name);
377 }
378 switch (render.src.bpp) {
379 case 8:
380 render.src.start = ( render.src.width * 1) / sizeof(Bitu);
381 if (gfx_flags & GFX_CAN_8)
382 gfx_flags |= GFX_LOVE_8;
383 else
384 gfx_flags |= GFX_LOVE_32;
385 break;
386 case 15:
387 render.src.start = ( render.src.width * 2) / sizeof(Bitu);
388 gfx_flags |= GFX_LOVE_15;
389 gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
390 break;
391 case 16:
392 render.src.start = ( render.src.width * 2) / sizeof(Bitu);
393 gfx_flags |= GFX_LOVE_16;
394 gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
395 break;
396 case 32:
397 render.src.start = ( render.src.width * 4) / sizeof(Bitu);
398 gfx_flags |= GFX_LOVE_32;
399 gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
400 break;
401 }
402 gfx_flags=GFX_GetBestMode(gfx_flags);
403 if (!gfx_flags) {
404 if (!complexBlock && simpleBlock == &ScaleNormal1x)
405 E_Exit("Failed to create a rendering output");
406 else
407 goto forcenormal;
408 }
409 width *= xscale;
410 Bitu skip = complexBlock ? 1 : 0;
411 if (gfx_flags & GFX_SCALING) {
412 height = MakeAspectTable(skip, render.src.height, yscale, yscale );
413 } else {
414 if ((gfx_flags & GFX_CAN_RANDOM) && gfx_scaleh > 1) {
415 gfx_scaleh *= yscale;
416 height = MakeAspectTable( skip, render.src.height, gfx_scaleh, yscale );
417 } else {
418 gfx_flags &= ~GFX_CAN_RANDOM; //Hardware surface when possible
419 height = MakeAspectTable( skip, render.src.height, yscale, yscale);
420 }
421 }
422 /* Setup the scaler variables */
423 gfx_flags=GFX_SetSize(width,height,gfx_flags,gfx_scalew,gfx_scaleh,&RENDER_CallBack);
424 if (gfx_flags & GFX_CAN_8)
425 render.scale.outMode = scalerMode8;
426 else if (gfx_flags & GFX_CAN_15)
427 render.scale.outMode = scalerMode15;
428 else if (gfx_flags & GFX_CAN_16)
429 render.scale.outMode = scalerMode16;
430 else if (gfx_flags & GFX_CAN_32)
431 render.scale.outMode = scalerMode32;
432 else
433 E_Exit("Failed to create a rendering output");
434 ScalerLineBlock_t *lineBlock;
435 if (gfx_flags & GFX_HARDWARE) {
436 #if RENDER_USE_ADVANCED_SCALERS>1
437 if (complexBlock) {
438 lineBlock = &ScalerCache;
439 render.scale.complexHandler = complexBlock->Linear[ render.scale.outMode ];
440 } else
441 #endif
442 {
443 render.scale.complexHandler = 0;
444 lineBlock = &simpleBlock->Linear;
445 }
446 } else {
447 #if RENDER_USE_ADVANCED_SCALERS>1
448 if (complexBlock) {
449 lineBlock = &ScalerCache;
450 render.scale.complexHandler = complexBlock->Random[ render.scale.outMode ];
451 } else
452 #endif
453 {
454 render.scale.complexHandler = 0;
455 lineBlock = &simpleBlock->Random;
456 }
457 }
458 switch (render.src.bpp) {
459 case 8:
460 render.scale.lineHandler = (*lineBlock)[0][render.scale.outMode];
461 render.scale.linePalHandler = (*lineBlock)[4][render.scale.outMode];
462 render.scale.inMode = scalerMode8;
463 render.scale.cachePitch = render.src.width * 1;
464 break;
465 case 15:
466 render.scale.lineHandler = (*lineBlock)[1][render.scale.outMode];
467 render.scale.linePalHandler = 0;
468 render.scale.inMode = scalerMode15;
469 render.scale.cachePitch = render.src.width * 2;
470 break;
471 case 16:
472 render.scale.lineHandler = (*lineBlock)[2][render.scale.outMode];
473 render.scale.linePalHandler = 0;
474 render.scale.inMode = scalerMode16;
475 render.scale.cachePitch = render.src.width * 2;
476 break;
477 case 32:
478 render.scale.lineHandler = (*lineBlock)[3][render.scale.outMode];
479 render.scale.linePalHandler = 0;
480 render.scale.inMode = scalerMode32;
481 render.scale.cachePitch = render.src.width * 4;
482 break;
483 default:
484 E_Exit("RENDER:Wrong source bpp %d", render.src.bpp );
485 }
486 render.scale.blocks = render.src.width / SCALER_BLOCKSIZE;
487 render.scale.lastBlock = render.src.width % SCALER_BLOCKSIZE;
488 render.scale.inHeight = render.src.height;
489 /* Reset the palette change detection to it's initial value */
490 render.pal.first= 0;
491 render.pal.last = 255;
492 render.pal.changed = false;
493 memset(render.pal.modified, 0, sizeof(render.pal.modified));
494 //Finish this frame using a copy only handler
495 RENDER_DrawLine = RENDER_FinishLineHandler;
496 render.scale.outWrite = 0;
497 /* Signal the next frame to first reinit the cache */
498 render.scale.clearCache = true;
499 render.active=true;
500 }
501
RENDER_CallBack(GFX_CallBackFunctions_t function)502 static void RENDER_CallBack( GFX_CallBackFunctions_t function ) {
503 if (function == GFX_CallBackStop) {
504 RENDER_Halt( );
505 return;
506 } else if (function == GFX_CallBackRedraw) {
507 render.scale.clearCache = true;
508 return;
509 } else if ( function == GFX_CallBackReset) {
510 GFX_EndUpdate( 0 );
511 RENDER_Reset();
512 } else {
513 E_Exit("Unhandled GFX_CallBackReset %d", function );
514 }
515 }
516
RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double ratio,bool dblw,bool dblh)517 void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double ratio,bool dblw,bool dblh) {
518 RENDER_Halt( );
519 if (!width || !height || width > SCALER_MAXWIDTH || height > SCALER_MAXHEIGHT) {
520 return;
521 }
522 if ( ratio > 1 ) {
523 double target = height * ratio + 0.025;
524 ratio = target / height;
525 } else {
526 //This would alter the width of the screen, we don't care about rounding errors here
527 }
528 render.src.width=width;
529 render.src.height=height;
530 render.src.bpp=bpp;
531 render.src.dblw=dblw;
532 render.src.dblh=dblh;
533 render.src.fps=fps;
534 render.src.ratio=ratio;
535 RENDER_Reset( );
536 }
537
538 extern void GFX_SetTitle(Bit32s cycles, Bits frameskip,bool paused);
IncreaseFrameSkip(bool pressed)539 static void IncreaseFrameSkip(bool pressed) {
540 if (!pressed)
541 return;
542 if (render.frameskip.max<10) render.frameskip.max++;
543 LOG_MSG("Frame Skip at %d",render.frameskip.max);
544 GFX_SetTitle(-1,render.frameskip.max,false);
545 }
546
DecreaseFrameSkip(bool pressed)547 static void DecreaseFrameSkip(bool pressed) {
548 if (!pressed)
549 return;
550 if (render.frameskip.max>0) render.frameskip.max--;
551 LOG_MSG("Frame Skip at %d",render.frameskip.max);
552 GFX_SetTitle(-1,render.frameskip.max,false);
553 }
554 /* Disabled as I don't want to waste a keybind for that. Might be used in the future (Qbix)
555 static void ChangeScaler(bool pressed) {
556 if (!pressed)
557 return;
558 render.scale.op = (scalerOperation)((int)render.scale.op+1);
559 if((render.scale.op) >= scalerLast || render.scale.size == 1) {
560 render.scale.op = (scalerOperation)0;
561 if(++render.scale.size > 3)
562 render.scale.size = 1;
563 }
564 RENDER_CallBack( GFX_CallBackReset );
565 } */
566
RENDER_Init(Section * sec)567 void RENDER_Init(Section * sec) {
568 Section_prop * section=static_cast<Section_prop *>(sec);
569
570 //For restarting the renderer.
571 static bool running = false;
572 bool aspect = render.aspect;
573 Bitu scalersize = render.scale.size;
574 bool scalerforced = render.scale.forced;
575 scalerOperation_t scaleOp = render.scale.op;
576
577 render.pal.first=256;
578 render.pal.last=0;
579 render.aspect=section->Get_bool("aspect");
580 render.frameskip.max=section->Get_int("frameskip");
581 render.frameskip.count=0;
582 std::string cline;
583 std::string scaler;
584 //Check for commandline paramters and parse them through the configclass so they get checked against allowed values
585 if (control->cmdline->FindString("-scaler",cline,false)) {
586 section->HandleInputline(std::string("scaler=") + cline);
587 } else if (control->cmdline->FindString("-forcescaler",cline,false)) {
588 section->HandleInputline(std::string("scaler=") + cline + " forced");
589 }
590
591 Prop_multival* prop = section->Get_multival("scaler");
592 scaler = prop->GetSection()->Get_string("type");
593 std::string f = prop->GetSection()->Get_string("force");
594 render.scale.forced = false;
595 if(f == "forced") render.scale.forced = true;
596
597 if (scaler == "none") { render.scale.op = scalerOpNormal;render.scale.size = 1; }
598 else if (scaler == "normal2x") { render.scale.op = scalerOpNormal;render.scale.size = 2; }
599 else if (scaler == "normal3x") { render.scale.op = scalerOpNormal;render.scale.size = 3; }
600 #if RENDER_USE_ADVANCED_SCALERS>2
601 else if (scaler == "advmame2x") { render.scale.op = scalerOpAdvMame;render.scale.size = 2; }
602 else if (scaler == "advmame3x") { render.scale.op = scalerOpAdvMame;render.scale.size = 3; }
603 else if (scaler == "advinterp2x") { render.scale.op = scalerOpAdvInterp;render.scale.size = 2; }
604 else if (scaler == "advinterp3x") { render.scale.op = scalerOpAdvInterp;render.scale.size = 3; }
605 else if (scaler == "hq2x") { render.scale.op = scalerOpHQ;render.scale.size = 2; }
606 else if (scaler == "hq3x") { render.scale.op = scalerOpHQ;render.scale.size = 3; }
607 else if (scaler == "2xsai") { render.scale.op = scalerOpSaI;render.scale.size = 2; }
608 else if (scaler == "super2xsai") { render.scale.op = scalerOpSuperSaI;render.scale.size = 2; }
609 else if (scaler == "supereagle") { render.scale.op = scalerOpSuperEagle;render.scale.size = 2; }
610 #endif
611 #if RENDER_USE_ADVANCED_SCALERS>0
612 else if (scaler == "tv2x") { render.scale.op = scalerOpTV;render.scale.size = 2; }
613 else if (scaler == "tv3x") { render.scale.op = scalerOpTV;render.scale.size = 3; }
614 else if (scaler == "rgb2x"){ render.scale.op = scalerOpRGB;render.scale.size = 2; }
615 else if (scaler == "rgb3x"){ render.scale.op = scalerOpRGB;render.scale.size = 3; }
616 else if (scaler == "scan2x"){ render.scale.op = scalerOpScan;render.scale.size = 2; }
617 else if (scaler == "scan3x"){ render.scale.op = scalerOpScan;render.scale.size = 3; }
618 #endif
619
620 //If something changed that needs a ReInit
621 // Only ReInit when there is a src.bpp (fixes crashes on startup and directly changing the scaler without a screen specified yet)
622 if(running && render.src.bpp && ((render.aspect != aspect) || (render.scale.op != scaleOp) ||
623 (render.scale.size != scalersize) || (render.scale.forced != scalerforced) ||
624 render.scale.forced))
625 RENDER_CallBack( GFX_CallBackReset );
626
627 if(!running) render.updating=true;
628 running = true;
629
630 MAPPER_AddHandler(DecreaseFrameSkip,MK_f7,MMOD1,"decfskip","Dec Fskip");
631 MAPPER_AddHandler(IncreaseFrameSkip,MK_f8,MMOD1,"incfskip","Inc Fskip");
632 GFX_SetTitle(-1,render.frameskip.max,false);
633 }
634
635