1
0
Fork 0

Rendering rewrite for aspect correction and vga vertical stretching

Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@1411
This commit is contained in:
Sjoerd van der Berg 2003-11-08 09:53:11 +00:00
parent 7b36937c81
commit a1e279829b
6 changed files with 302 additions and 785 deletions

View file

@ -23,23 +23,13 @@ enum RENDER_Operation {
OP_Shot,
OP_Normal2x,
OP_AdvMame2x,
OP_Blit,
};
enum {
DoubleNone= 0x00,
DoubleWidth= 0x01,
DoubleHeight= 0x02,
DoubleBoth= 0x03
};
typedef void (* RENDER_Part_Handler)(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy);
typedef void (* RENDER_Draw_Handler)(RENDER_Part_Handler part_handler);
void RENDER_DoUpdate(void);
void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,float ratio,Bitu flags,RENDER_Draw_Handler draw_handler);
void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,double ratio,Bitu scalew,Bitu scaleh,RENDER_Draw_Handler draw_handler);
void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue);

View file

@ -1,6 +1,7 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libgui.a
libgui_a_SOURCES = sdlmain.cpp render.cpp render_normal.h render_scale2x.h \
libgui_a_SOURCES = sdlmain.cpp \
render.cpp render_normal.h render_scale2x.h render_templates.h \
midi.cpp midi_win32.h midi_oss.h midi_coreaudio.h midi_alsa.h

View file

@ -16,10 +16,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* $Id: render.cpp,v 1.19 2003-10-15 08:20:50 harekiet Exp $ */
/* $Id: render.cpp,v 1.20 2003-11-08 09:53:11 harekiet Exp $ */
#include <sys/types.h>
#include <dirent.h>
#include <assert.h>
#include <math.h>
#include "dosbox.h"
#include "video.h"
@ -29,7 +31,8 @@
#include "cross.h"
#include "support.h"
#define MAX_RES 2048
#define RENDER_MAXWIDTH 1280
#define RENDER_MAXHEIGHT 1024
struct PalData {
struct {
@ -43,6 +46,7 @@ struct PalData {
union {
Bit32u bpp32[256];
Bit16u bpp16[256];
Bit32u yuv[256];
} lookup;
};
@ -53,28 +57,36 @@ static struct {
Bitu height;
Bitu bpp;
Bitu pitch;
Bitu flags;
float ratio;
Bitu scalew;
Bitu scaleh;
double ratio;
RENDER_Draw_Handler draw_handler;
} src;
struct {
Bitu width;
Bitu height;
Bitu pitch;
Bitu bpp; /* The type of BPP the operation requires for input */
GFX_MODES gfx_mode;
RENDER_Operation type;
RENDER_Operation want_type;
RENDER_Part_Handler part_handler;
void * dest;
void * buffer;
void * pixels;
Bit8u * dest;
Bit8u * buffer;
Bit8u * pixels;
} op;
struct {
Bitu count;
Bitu max;
} frameskip;
Bitu flags;
PalData pal;
struct {
Bit8u hlines[RENDER_MAXHEIGHT];
Bit16u hindex[RENDER_MAXHEIGHT];
} normal;
struct {
Bit16u hindex[RENDER_MAXHEIGHT];
Bitu line_starts[RENDER_MAXHEIGHT][3];
} advmame2x;
#if (C_SSHOT)
struct {
RENDER_Operation type;
@ -84,12 +96,14 @@ static struct {
#endif
bool screenshot;
bool active;
bool aspect;
} render;
/* Forward declerations */
static void RENDER_ResetPal(void);
/* Include the different rendering routines */
#include "render_templates.h"
#include "render_normal.h"
#include "render_scale2x.h"
@ -201,28 +215,41 @@ static void EnableScreenShot(void) {
/* This could go kinda bad with multiple threads */
static void Check_Palette(void) {
if (render.pal.first>render.pal.last) return;
switch (render.op.bpp) {
case 8:
Bitu i;
switch (render.op.gfx_mode) {
case GFX_8BPP:
GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]);
break;
case 16:
for (;render.pal.first<=render.pal.last;render.pal.first++) {
render.pal.lookup.bpp16[render.pal.first]=GFX_GetRGB(
render.pal.rgb[render.pal.first].red,
render.pal.rgb[render.pal.first].green,
render.pal.rgb[render.pal.first].blue);
case GFX_15BPP:
case GFX_16BPP:
for (i=render.pal.first;i<=render.pal.last;i++) {
Bit8u r=render.pal.rgb[i].red;
Bit8u g=render.pal.rgb[i].green;
Bit8u b=render.pal.rgb[i].blue;
render.pal.lookup.bpp16[i]=GFX_GetRGB(r,g,b);
}
break;
case 32:
for (;render.pal.first<=render.pal.last;render.pal.first++) {
render.pal.lookup.bpp32[render.pal.first]=
GFX_GetRGB(
render.pal.rgb[render.pal.first].red,
render.pal.rgb[render.pal.first].green,
render.pal.rgb[render.pal.first].blue);
case GFX_24BPP:
case GFX_32BPP:
for (i=render.pal.first;i<=render.pal.last;i++) {
Bit8u r=render.pal.rgb[i].red;
Bit8u g=render.pal.rgb[i].green;
Bit8u b=render.pal.rgb[i].blue;
render.pal.lookup.bpp32[i]=GFX_GetRGB(r,g,b);
}
break;
};
case GFX_YUV:
for (i=render.pal.first;i<=render.pal.last;i++) {
Bit8u r=render.pal.rgb[i].red;
Bit8u g=render.pal.rgb[i].green;
Bit8u b=render.pal.rgb[i].blue;
Bit8u y = ( 9797*(r) + 19237*(g) + 3734*(b) ) >> 15;
Bit8u u = (18492*((b)-(y)) >> 15) + 128;
Bit8u v = (23372*((r)-(y)) >> 15) + 128;
render.pal.lookup.yuv[i]=(u << 0) | (y << 8) | (v << 16) | (y << 24);
}
break;
}
/* Setup pal index to startup values */
render.pal.first=256;
render.pal.last=0;
@ -251,19 +278,14 @@ void RENDER_DoUpdate(void) {
GFX_DoUpdate();
}
static void RENDER_DrawScreen(void * data) {
static void RENDER_DrawScreen(Bit8u * data,Bitu pitch) {
render.op.pitch=pitch;
switch (render.op.type) {
#if (C_SSHOT)
doagain:
#endif
case OP_None:
render.op.dest=render.op.pixels=data;
render.src.draw_handler(render.op.part_handler);
break;
case OP_Blit:
render.op.dest=render.op.pixels=data;
render.src.draw_handler(render.op.part_handler);
break;
case OP_Normal2x:
case OP_AdvMame2x:
render.op.dest=render.op.pixels=data;
render.src.draw_handler(render.op.part_handler);
@ -272,8 +294,8 @@ doagain:
case OP_Shot:
render.shot.pitch=render.op.pitch;
render.op.pitch=render.src.width;
render.op.pixels=malloc(render.src.width*render.src.height);
render.src.draw_handler(Normal_DN_8);
render.op.pixels=(Bit8u*)malloc(render.src.width*render.src.height);
// render.src.draw_handler(Normal_DN_8);
TakeScreenShot((Bit8u *)render.op.pixels);
free(render.op.pixels);
render.op.pitch=render.shot.pitch;
@ -283,30 +305,134 @@ doagain:
}
}
static void RENDER_Resize(Bitu * width,Bitu * height) {
/* Calculate the new size the window should be */
if (!*width && !*height) {
/* Special command to reset any resizing for fullscreen */
*width=render.src.width;
*height=render.src.height;
} else {
if ((*width/render.src.ratio)<*height) *height=(Bitu)(*width/render.src.ratio);
else *width=(Bitu)(*height*render.src.ratio);
}
static void SetAdvMameTable(Bitu index,Bits src0,Bits src1,Bits src2) {
if (src0<0) src0=0;
if ((Bitu)src0>=render.src.height) src0=render.src.height-1;
if ((Bitu)src1>=render.src.height) src1=render.src.height-1;
if ((Bitu)src2>=render.src.height) src2=render.src.height-1;
render.advmame2x.line_starts[index][0]=src0*render.src.pitch;
render.advmame2x.line_starts[index][1]=src1*render.src.pitch;
render.advmame2x.line_starts[index][2]=src2*render.src.pitch;
}
static void Render_Blit_CallBack(Bitu width,Bitu height,Bitu bpp,Bitu pitch,Bitu flags) {
void RENDER_ReInit(void) {
Bitu width=render.src.width;
Bitu height=render.src.height;
Bitu bpp=render.src.bpp;
Bitu scalew=render.src.scalew;
Bitu scaleh=render.src.scaleh;
double gfx_scalew=1.0;
double gfx_scaleh=1.0;
if (render.src.ratio>1.0) gfx_scaleh*=render.src.ratio;
else gfx_scalew*=(1/render.src.ratio);
GFX_MODES gfx_mode;Bitu gfx_flags;
gfx_mode=GFX_GetBestMode(render.src.bpp,gfx_flags);
Bitu index;
switch (gfx_mode) {
case GFX_8BPP: index=0;break;
case GFX_15BPP: index=1;break;
case GFX_16BPP: index=1;break;
case GFX_24BPP: index=2;break;
case GFX_32BPP: index=3;break;
case GFX_YUV: index=3;break;
}
/* Initial scaler testing */
switch (render.op.want_type) {
case OP_Normal2x:
case OP_None:
render.op.type=render.op.want_type;
normalop:
if (gfx_flags & GFX_HASSCALING) {
gfx_scalew*=scalew;
gfx_scaleh*=scaleh;
render.op.part_handler=Normal_SINGLE_8[index];
for (Bitu i=0;i<render.src.height;i++) {
render.normal.hindex[i]=i;
render.normal.hlines[i]=0;
}
} else {
gfx_scaleh*=scaleh;
if (scalew==2) {
if (scaleh>1 && (render.op.type==OP_None)) {
render.op.part_handler=Normal_SINGLE_8[index];
scalew>>=1;gfx_scaleh/=2;
} else {
render.op.part_handler=Normal_DOUBLE_8[index];
}
} else render.op.part_handler=Normal_SINGLE_8[index];
width*=scalew;
double lines=0.0;
gfx_scaleh=(gfx_scaleh*render.src.height-(double)render.src.height)/(double)render.src.height;
height=0;
for (Bitu i=0;i<render.src.height;i++) {
render.normal.hindex[i]=height++;
Bitu temp_lines=(Bitu)(lines);
lines=lines+gfx_scaleh-temp_lines;
render.normal.hlines[i]=temp_lines;
height+=temp_lines;
}
}
break;
case OP_AdvMame2x:
if (scalew!=2){
render.op.type=OP_Normal2x;
goto normalop;
}
if (gfx_flags & GFX_HASSCALING) {
height=scaleh*height;
} else {
height=(Bitu)(gfx_scaleh*scaleh*height);
}
width<<=1;
{
Bits i;
double src_add=(double)height/(double)render.src.height;
double src_index=0;
double src_lines=0;
Bitu height=0;
for (i=0;i<=(Bits)render.src.height;i++) {
render.advmame2x.hindex[i]=(Bitu)src_index;
Bitu lines=(Bitu)src_lines;
src_lines-=lines;
src_index+=src_add;
src_lines+=src_add;
switch (lines) {
case 0:
break;
case 1:
SetAdvMameTable(height++,i,i,i);
break;
case 2:
SetAdvMameTable(height++,i-1,i,i+1);
SetAdvMameTable(height++,i+1,i,i-1);
break;
default:
SetAdvMameTable(height++,i-1,i,i+1);
for (lines-=2;lines>0;lines--) SetAdvMameTable(height++,i,i,i);
SetAdvMameTable(height++,i+1,i,i-1);
break;
}
}
render.op.part_handler=AdvMame2x_8_Table[index];
}
break;
}
render.op.gfx_mode=gfx_mode;
render.op.width=width;
render.op.height=height;
render.op.bpp=bpp;
render.op.pitch=pitch;
render.op.type=OP_Blit;
render.op.part_handler=GFX_Render_Blit;
GFX_SetSize(width,height,gfx_mode,gfx_scalew,gfx_scaleh,&RENDER_ReInit,RENDER_DrawScreen);
RENDER_ResetPal();
GFX_Start();
}
void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,float ratio,Bitu flags,RENDER_Draw_Handler draw_handler) {
void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,double ratio,Bitu scalew,Bitu scaleh,RENDER_Draw_Handler draw_handler) {
if ((!width) || (!height) || (!pitch)) {
render.active=false;return;
}
@ -315,67 +441,12 @@ void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,float ratio,Bitu
render.src.height=height;
render.src.bpp=bpp;
render.src.pitch=pitch;
render.src.ratio=ratio;
render.src.flags=flags;
render.src.ratio=render.aspect ? ratio : 1.0;
render.src.scalew=scalew;
render.src.scaleh=scaleh;
render.src.draw_handler=draw_handler;
RENDER_ReInit();
GFX_ModeCallBack mode_callback=0;
switch (render.op.want_type) {
case OP_None:
normalop:
switch (render.src.flags) {
case DoubleNone:
flags=0;
break;
case DoubleWidth:
width*=2;
flags=GFX_SHADOW;
break;
case DoubleHeight:
height*=2;
flags=0;
break;
case DoubleBoth:
render.src.flags=0;
flags=0;
break;
}
mode_callback=Render_Normal_CallBack;
break;
case OP_Normal2x:
switch (render.src.flags) {
case DoubleBoth:
width*=2;height*=2;
flags=GFX_SHADOW;
mode_callback=Render_Normal_CallBack;
break;
default:
goto normalop;
}
break;
case OP_AdvMame2x:
switch (render.src.flags) {
case DoubleBoth:
mode_callback=Render_Scale2x_CallBack;
width*=2;height*=2;
#if defined (SCALE2X_MMX)
flags=GFX_SHADOW;
#else
flags=GFX_SHADOW;
#endif
break;
default:
goto normalop;
}
break;
default:
goto normalop;
}
GFX_SetSize(width,height,bpp,flags,mode_callback,RENDER_DrawScreen);
GFX_Start();
}
extern void GFX_SetTitle(Bits cycles, Bits frameskip);
@ -396,6 +467,7 @@ void RENDER_Init(Section * sec) {
render.pal.first=256;
render.pal.last=0;
render.aspect=section->Get_bool("aspect");
render.frameskip.max=section->Get_int("frameskip");
render.frameskip.count=0;
#if (C_SSHOT)

View file

@ -16,166 +16,49 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#define LOOPSIZE 4
static Bit8u normal_cache[RENDER_MAXWIDTH*2];
#define SIZE_8 1
#define SIZE_16 2
#define SIZE_32 4
#define MAKE_8(FROM) Bit8u val=*(Bit8u *)(FROM);
#define MAKE_16(FROM) Bit16u val=render.pal.lookup.bpp16[*(Bit8u *)(FROM)];
#define MAKE_32(FROM) Bit32u val=render.pal.lookup.bpp32[*(Bit8u *)(FROM)];
#define SAVE_8(WHERE) *(Bit8u *)(WHERE)=val;
#define SAVE_16(WHERE) *(Bit16u *)(WHERE)=val;
#define SAVE_32(WHERE) *(Bit32u *)(WHERE)=val;
#define LINES_DN 1
#define LINES_DW 1
#define LINES_DH 2
#define LINES_DB 2
#define PIXELS_DN 1
#define PIXELS_DW 2
#define PIXELS_DH 1
#define PIXELS_DB 2
#define NORMAL_DN(BPP,FROM,DEST) \
MAKE_ ## BPP(FROM); \
SAVE_ ## BPP(DEST); \
#define NORMAL_DW(BPP,FROM,DEST) \
MAKE_ ## BPP (FROM); \
SAVE_ ## BPP (DEST); \
SAVE_ ## BPP (DEST + SIZE_ ## BPP); \
#define NORMAL_DH(BPP,FROM,DEST) \
MAKE_ ## BPP (FROM); \
SAVE_ ## BPP (DEST); \
SAVE_ ## BPP ((DEST) + render.op.pitch); \
#define NORMAL_DB(BPP,FROM,DEST) \
MAKE_ ## BPP (FROM); \
SAVE_ ## BPP (DEST); \
SAVE_ ## BPP ((DEST)+SIZE_ ## BPP ); \
SAVE_ ## BPP ((DEST)+render.op.pitch ); \
SAVE_ ## BPP ((DEST)+render.op.pitch+SIZE_ ## BPP ); \
#define NORMAL_LOOP(COUNT,FUNC,BPP) \
if (COUNT>0) {NORMAL_ ## FUNC (BPP,(src+0),(dest+0 * PIXELS_ ## FUNC * SIZE_ ## BPP )) }\
if (COUNT>1) {NORMAL_ ## FUNC (BPP,(src+1),(dest+1 * PIXELS_ ## FUNC * SIZE_ ## BPP )) }\
if (COUNT>2) {NORMAL_ ## FUNC (BPP,(src+2),(dest+2 * PIXELS_ ## FUNC * SIZE_ ## BPP )) }\
if (COUNT>3) {NORMAL_ ## FUNC (BPP,(src+3),(dest+3 * PIXELS_ ## FUNC * SIZE_ ## BPP )) }\
if (COUNT>4) {NORMAL_ ## FUNC (BPP,(src+4),(dest+4 * PIXELS_ ## FUNC * SIZE_ ## BPP )) }\
if (COUNT>5) {NORMAL_ ## FUNC (BPP,(src+5),(dest+5 * PIXELS_ ## FUNC * SIZE_ ## BPP )) }\
if (COUNT>6) {NORMAL_ ## FUNC (BPP,(src+6),(dest+6 * PIXELS_ ## FUNC * SIZE_ ## BPP )) }\
if (COUNT>7) {NORMAL_ ## FUNC (BPP,(src+7),(dest+7 * PIXELS_ ## FUNC * SIZE_ ## BPP )) }\
#define MAKENORMAL(FUNC,BPP) \
static void Normal_ ## FUNC ## _ ##BPP(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { \
Bit8u * dest=(Bit8u *)render.op.pixels+y*LINES_ ## FUNC*render.op.pitch+x*PIXELS_ ## FUNC * SIZE_ ## BPP; \
Bitu next_src=render.src.pitch-dx; \
Bitu next_dest=(LINES_ ## FUNC*render.op.pitch) - (dx*PIXELS_ ## FUNC * SIZE_ ## BPP); \
dx/=LOOPSIZE; \
for (;dy>0;dy--) { \
for (Bitu tempx=dx;tempx>0;tempx--) { \
NORMAL_LOOP(LOOPSIZE,FUNC,BPP); \
src+=LOOPSIZE;dest+=LOOPSIZE*PIXELS_ ## FUNC * SIZE_ ## BPP; \
} \
src+=next_src;dest+=next_dest; \
} \
}
MAKENORMAL(DW,8);
MAKENORMAL(DB,8);
MAKENORMAL(DN,16);
MAKENORMAL(DW,16);
MAKENORMAL(DH,16);
MAKENORMAL(DB,16);
MAKENORMAL(DN,32);
MAKENORMAL(DW,32);
MAKENORMAL(DH,32);
MAKENORMAL(DB,32);
/* Special versions for the 8-bit ones that can do direct line copying */
static void Normal_DN_8(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) {
Bit8u * dest=(Bit8u *)render.op.pixels+y*render.op.pitch+x;
Bitu next_src=render.src.pitch-dx;
Bitu next_dest=render.op.pitch-dx;
Bitu rem=dx&3;dx>>=2;
for (;dy>0;dy--) {
Bitu tempx;
for (tempx=dx;tempx>0;tempx--) {
Bit32u temp=*(Bit32u *)src;src+=4;
*(Bit32u *)dest=temp;
dest+=4;
template <Bitu sbpp,Bitu dbpp,bool xdouble>
static void Normal(Bit8u * src,Bitu x,Bitu y,Bitu _dx,Bitu _dy) {
Bit8u * dst=render.op.pixels+(render.normal.hindex[y]*render.op.pitch);
Bitu line_size=LineSize<dbpp>(_dx) * (xdouble ? 2 : 1);
src+=x;
Bit8u * line;
for (;_dy;_dy--) {
if (sbpp == dbpp && !xdouble) {
line=src;
BituMove(dst,line,line_size);
} else {
Bit8u * line_dst=&normal_cache[0];
Bit8u * real_dst=dst;
line=line_dst;
Bit8u * temp_src=src;
for (Bitu tempx=_dx;tempx;tempx--) {
Bitu val=ConvBPP<sbpp,dbpp>(LoadSrc<sbpp>(temp_src));
AddDst<dbpp>(line_dst,val);
AddDst<dbpp>(real_dst,val);
if (xdouble) {
AddDst<dbpp>(line_dst,val);
AddDst<dbpp>(real_dst,val);
}
}
}
for (tempx=rem;tempx>0;tempx--) {
*dest++=*src++;
dst+=render.op.pitch;
for (Bitu lines=render.normal.hlines[y++];lines;lines--) {
BituMove(dst,line,line_size);
dst+=render.op.pitch;
}
src+=next_src;dest+=next_dest;
src+=render.src.pitch;
}
}
static void Normal_DH_8(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) {
Bit8u * dest=(Bit8u *)render.op.pixels+2*y*render.op.pitch+x;
Bitu next_src=render.src.pitch-dx;
Bitu next_dest=(2*render.op.pitch)-dx;
Bitu rem=dx&3;dx>>=2;
for (;dy>0;dy--) {
Bitu tempx;
for (tempx=dx;tempx>0;tempx--) {
Bit32u temp=*(Bit32u *)src;src+=4;
*(Bit32u *)dest=temp;
*(Bit32u *)(dest+render.op.pitch)=temp;
dest+=4;
}
for (tempx=rem;tempx>0;tempx--) {
*dest=*src;
*(dest+render.op.pitch)=*src;
dest++;
}
src+=next_src;dest+=next_dest;
}
}
static RENDER_Part_Handler Render_Normal_8_Table[4]= {
Normal_DN_8,Normal_DW_8,Normal_DH_8,Normal_DB_8,
RENDER_Part_Handler Normal_SINGLE_8[4]={
Normal<8,8 ,false>,Normal<8,16,false>,
Normal<8,24,false>,Normal<8,32,false>,
};
static RENDER_Part_Handler Render_Normal_16_Table[4]= {
Normal_DN_16,Normal_DW_16,Normal_DH_16,Normal_DB_16,
};
static RENDER_Part_Handler Render_Normal_32_Table[4]= {
Normal_DN_32,Normal_DW_32,Normal_DH_32,Normal_DB_32,
};
static void Render_Normal_CallBack(Bitu width,Bitu height,Bitu bpp,Bitu pitch,Bitu flags) {
if (!(flags & MODE_SET)) return;
render.op.width=width;
render.op.height=height;
render.op.bpp=bpp;
render.op.pitch=pitch;
render.op.type=OP_None;
switch (bpp) {
case 8:
render.op.part_handler=Render_Normal_8_Table[render.src.flags];
break;
case 16:
render.op.part_handler=Render_Normal_16_Table[render.src.flags];
break;
case 32:
render.op.part_handler=Render_Normal_32_Table[render.src.flags];
break;
default:
E_Exit("RENDER:Unsupported display depth of %d",bpp);
break;
}
RENDER_ResetPal();
}
RENDER_Part_Handler Normal_DOUBLE_8[4]={
Normal<8,8 ,true>,Normal<8,16,true>,
Normal<8,24,true>,Normal<8,32,true>,
};

View file

@ -29,531 +29,49 @@
*/
/*
* This file contains a C and MMX implentation of the Scale2x effect.
*
* You can found an high level description of the effect at :
*
* This algorithm was based on the scale2x/advmame2x effect.
* http://scale2x.sourceforge.net/scale2x.html
*
* Alternatively at the previous license terms, you are allowed to use this
* code in your program with these conditions:
* - the program is not used in commercial activities.
* - the whole source code of the program is released with the binary.
* - derivative works of the program are allowed.
*/
/*
* Made some changes to only support the 8-bit version.
* Also added mulitple destination bpp targets.
*/
#ifndef __SCALE2X_H
#define __SCALE2X_H
#include <assert.h>
/***************************************************************************/
/* basic types */
typedef Bit8u scale2x_uint8;
typedef Bit16u scale2x_uint16;
typedef Bit32u scale2x_uint32;
static void scale2x_line_8(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
{
assert(count >= 2);
/* first pixel */
dst0[0] = src1[0];
dst1[0] = src1[0];
if (src1[1] == src0[0] && src2[0] != src0[0])
dst0[1] = src0[0];
else
dst0[1] = src1[0];
if (src1[1] == src2[0] && src0[0] != src2[0])
dst1[1] = src2[0];
else
dst1[1] = src1[0];
++src0;
++src1;
++src2;
dst0 += 2;
dst1 += 2;
template <Bitu sbpp,Bitu dbpp>
static void AdvMame2x_line(Bit8u * dst, const Bit8u * src0, const Bit8u * src1, const Bit8u * src2, Bitu count) {
AddDst<dbpp>(dst,ConvBPP<sbpp,dbpp>(src1[0]));
AddDst<dbpp>(dst,ConvBPP<sbpp,dbpp>((src1[1] == src0[0] && src2[0] != src0[0]) ? src0[0] : src1[0]));
src0++;src1++;src2++;count-=2;
/* central pixels */
count -= 2;
while (count) {
if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0])
dst0[0] = src0[0];
else
dst0[0] = src1[0];
if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0])
dst0[1] = src0[0];
else
dst0[1] = src1[0];
if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0])
dst1[0] = src2[0];
else
dst1[0] = src1[0];
if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0])
dst1[1] = src2[0];
else
dst1[1] = src1[0];
++src0;
++src1;
++src2;
dst0 += 2;
dst1 += 2;
--count;
AddDst<dbpp>(dst,ConvBPP<sbpp,dbpp>((src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) ? src0[0] : src1[0]));
AddDst<dbpp>(dst,ConvBPP<sbpp,dbpp>((src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) ? src0[0] : src1[0]));
src0++;src1++;src2++;count--;
}
/* last pixel */
if (src1[-1] == src0[0] && src2[0] != src0[0])
dst0[0] = src0[0];
else
dst0[0] = src1[0];
if (src1[-1] == src2[0] && src0[0] != src2[0])
dst1[0] = src2[0];
else
dst1[0] = src1[0];
dst0[1] = src1[0];
dst1[1] = src1[0];
AddDst<dbpp>(dst,ConvBPP<sbpp,dbpp>((src1[-1] == src0[0] && src2[0] != src0[0]) ? src0[0] : src1[0]));
AddDst<dbpp>(dst,ConvBPP<sbpp,dbpp>(src1[0]));
}
static void scale2x_line_16(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
{
assert(count >= 2);
/* first pixel */
dst0[0] = render.pal.lookup.bpp16[src1[0]];
dst1[0] = render.pal.lookup.bpp16[src1[0]];
if (src1[1] == src0[0] && src2[0] != src0[0])
dst0[1] = render.pal.lookup.bpp16[src0[0]];
else
dst0[1] = render.pal.lookup.bpp16[src1[0]];
if (src1[1] == src2[0] && src0[0] != src2[0])
dst1[1] = render.pal.lookup.bpp16[src2[0]];
else
dst1[1] = render.pal.lookup.bpp16[src1[0]];
++src0;
++src1;
++src2;
dst0 += 2;
dst1 += 2;
/* central pixels */
count -= 2;
while (count) {
if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0])
dst0[0] = render.pal.lookup.bpp16[src0[0]];
else
dst0[0] = render.pal.lookup.bpp16[src1[0]];
if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0])
dst0[1] = render.pal.lookup.bpp16[src0[0]];
else
dst0[1] = render.pal.lookup.bpp16[src1[0]];
if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0])
dst1[0] = render.pal.lookup.bpp16[src2[0]];
else
dst1[0] = render.pal.lookup.bpp16[src1[0]];
if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0])
dst1[1] = render.pal.lookup.bpp16[src2[0]];
else
dst1[1] = render.pal.lookup.bpp16[src1[0]];
++src0;
++src1;
++src2;
dst0 += 2;
dst1 += 2;
--count;
template <Bitu sbpp,Bitu dbpp>
static void AdvMame2x(Bit8u * src,Bitu x,Bitu y,Bitu _dx,Bitu _dy) {
_dy=render.advmame2x.hindex[y+_dy];
y=render.advmame2x.hindex[y];
Bit8u * dest=render.op.pixels+render.op.pitch*y;
src-=render.advmame2x.line_starts[y][0];
src+=x;
for (;y<_dy;y++) {
Bit8u * src0=src+render.advmame2x.line_starts[y][0];
Bit8u * src1=src+render.advmame2x.line_starts[y][1];
Bit8u * src2=src+render.advmame2x.line_starts[y][2];
AdvMame2x_line<sbpp,dbpp>(dest,src0,src1,src2,_dx);
dest+=render.op.pitch;
}
/* last pixel */
if (src1[-1] == src0[0] && src2[0] != src0[0])
dst0[0] = render.pal.lookup.bpp16[src0[0]];
else
dst0[0] = render.pal.lookup.bpp16[src1[0]];
if (src1[-1] == src2[0] && src0[0] != src2[0])
dst1[0] = render.pal.lookup.bpp16[src2[0]];
else
dst1[0] = render.pal.lookup.bpp16[src1[0]];
dst0[1] = render.pal.lookup.bpp16[src1[0]];
dst1[1] = render.pal.lookup.bpp16[src1[0]];
}
static void scale2x_line_32(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
{
assert(count >= 2);
/* first pixel */
dst0[0] = render.pal.lookup.bpp32[src1[0]];
dst1[0] = render.pal.lookup.bpp32[src1[0]];
if (src1[1] == src0[0] && src2[0] != src0[0])
dst0[1] = render.pal.lookup.bpp32[src0[0]];
else
dst0[1] = render.pal.lookup.bpp32[src1[0]];
if (src1[1] == src2[0] && src0[0] != src2[0])
dst1[1] = render.pal.lookup.bpp32[src2[0]];
else
dst1[1] = render.pal.lookup.bpp32[src1[0]];
++src0;
++src1;
++src2;
dst0 += 2;
dst1 += 2;
RENDER_Part_Handler AdvMame2x_8_Table[4]={
AdvMame2x<8,8>,AdvMame2x<8,16>,AdvMame2x<8,24>,AdvMame2x<8,32>
};
/* central pixels */
count -= 2;
while (count) {
if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0])
dst0[0] = render.pal.lookup.bpp32[src0[0]];
else
dst0[0] = render.pal.lookup.bpp32[src1[0]];
if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0])
dst0[1] = render.pal.lookup.bpp32[src0[0]];
else
dst0[1] = render.pal.lookup.bpp32[src1[0]];
if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0])
dst1[0] = render.pal.lookup.bpp32[src2[0]];
else
dst1[0] = render.pal.lookup.bpp32[src1[0]];
if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0])
dst1[1] = render.pal.lookup.bpp32[src2[0]];
else
dst1[1] = render.pal.lookup.bpp32[src1[0]];
++src0;
++src1;
++src2;
dst0 += 2;
dst1 += 2;
--count;
}
/* last pixel */
if (src1[-1] == src0[0] && src2[0] != src0[0])
dst0[0] = render.pal.lookup.bpp32[src0[0]];
else
dst0[0] = render.pal.lookup.bpp32[src1[0]];
if (src1[-1] == src2[0] && src0[0] != src2[0])
dst1[0] = render.pal.lookup.bpp32[src2[0]];
else
dst1[0] = render.pal.lookup.bpp32[src1[0]];
dst0[1] = render.pal.lookup.bpp32[src1[0]];
dst1[1] = render.pal.lookup.bpp32[src1[0]];
}
static void Scale2x_8(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) {
if (dy<3) return;
Bit8u * dest=(Bit8u *)render.op.pixels+2*y*render.op.pitch;
/* First line */
scale2x_line_8(dest,dest+render.op.pitch,src,src,src+render.src.pitch,dx);
dest+=render.op.pitch*2;
src+=render.src.pitch;
dy-=2;
/* Middle part */
for (;dy>0;dy--) {
scale2x_line_8((Bit8u *)dest,(Bit8u *)(dest+render.op.pitch),src-render.src.pitch,src,src+render.src.pitch,dx);
dest+=render.op.pitch*2;
src+=render.src.pitch;
}
/* Last Line */
scale2x_line_8((Bit8u *)dest,(Bit8u *)(dest+render.op.pitch),src-render.src.pitch,src,src,dx);
}
static void Scale2x_16(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) {
if (dy<3) return;
Bit8u * dest=(Bit8u *)render.op.pixels+2*y*render.op.pitch;
/* First line */
scale2x_line_16((Bit16u *)dest,(Bit16u *)(dest+render.op.pitch),src,src,src+render.src.pitch,dx);
dest+=render.op.pitch*2;
src+=render.src.pitch;
dy-=2;
/* Middle part */
for (;dy>0;dy--) {
scale2x_line_16((Bit16u *)dest,(Bit16u *)(dest+render.op.pitch),src-render.src.pitch,src,src+render.src.pitch,dx);
dest+=render.op.pitch*2;
src+=render.src.pitch;
}
/* Last Line */
scale2x_line_16((Bit16u *)dest,(Bit16u *)(dest+render.op.pitch),src-render.src.pitch,src,src,dx);
}
static void Scale2x_32(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) {
if (dy<3) return;
Bit8u * dest=(Bit8u *)render.op.pixels+2*y*render.op.pitch;
/* First line */
scale2x_line_32((Bit32u *)dest,(Bit32u *)(dest+render.op.pitch),src,src,src+render.src.pitch,dx);
dest+=render.op.pitch*2;
src+=render.src.pitch;
dy-=2;
/* Middle part */
for (;dy>0;dy--) {
scale2x_line_32((Bit32u *)dest,(Bit32u *)(dest+render.op.pitch),src-render.src.pitch,src,src+render.src.pitch,dx);
dest+=render.op.pitch*2;
src+=render.src.pitch;
}
/* Last Line */
scale2x_line_32((Bit32u *)dest,(Bit32u *)(dest+render.op.pitch),src-render.src.pitch,src,src,dx);
}
#if defined(__GNUC__) && defined(__i386__)
#define SCALE2X_MMX 1
static __inline__ void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
{
assert(count >= 16);
assert(count % 8 == 0);
/* always do the first and last run */
count -= 2*8;
__asm__ __volatile__(
/* first run */
/* set the current, current_pre, current_next registers */
"movq 0(%1),%%mm0\n"
"movq 0(%1),%%mm7\n"
"movq 8(%1),%%mm1\n"
"psllq $56,%%mm0\n"
"psllq $56,%%mm1\n"
"psrlq $56,%%mm0\n"
"movq %%mm7,%%mm2\n"
"movq %%mm7,%%mm3\n"
"psllq $8,%%mm2\n"
"psrlq $8,%%mm3\n"
"por %%mm2,%%mm0\n"
"por %%mm3,%%mm1\n"
/* current_upper */
"movq (%0),%%mm6\n"
/* compute the upper-left pixel for dst on %%mm2 */
/* compute the upper-right pixel for dst on %%mm4 */
"movq %%mm0,%%mm2\n"
"movq %%mm1,%%mm4\n"
"movq %%mm0,%%mm3\n"
"movq %%mm1,%%mm5\n"
"pcmpeqb %%mm6,%%mm2\n"
"pcmpeqb %%mm6,%%mm4\n"
"pcmpeqb (%2),%%mm3\n"
"pcmpeqb (%2),%%mm5\n"
"pandn %%mm2,%%mm3\n"
"pandn %%mm4,%%mm5\n"
"movq %%mm0,%%mm2\n"
"movq %%mm1,%%mm4\n"
"pcmpeqb %%mm1,%%mm2\n"
"pcmpeqb %%mm0,%%mm4\n"
"pandn %%mm3,%%mm2\n"
"pandn %%mm5,%%mm4\n"
"movq %%mm2,%%mm3\n"
"movq %%mm4,%%mm5\n"
"pand %%mm6,%%mm2\n"
"pand %%mm6,%%mm4\n"
"pandn %%mm7,%%mm3\n"
"pandn %%mm7,%%mm5\n"
"por %%mm3,%%mm2\n"
"por %%mm5,%%mm4\n"
/* set *dst */
"movq %%mm2,%%mm3\n"
"punpcklbw %%mm4,%%mm2\n"
"punpckhbw %%mm4,%%mm3\n"
"movq %%mm2,(%3)\n"
"movq %%mm3,8(%3)\n"
/* next */
"addl $8,%0\n"
"addl $8,%1\n"
"addl $8,%2\n"
"addl $16,%3\n"
/* central runs */
"shrl $3,%4\n"
"jz 1f\n"
"0:\n"
/* set the current, current_pre, current_next registers */
"movq -8(%1),%%mm0\n"
"movq (%1),%%mm7\n"
"movq 8(%1),%%mm1\n"
"psrlq $56,%%mm0\n"
"psllq $56,%%mm1\n"
"movq %%mm7,%%mm2\n"
"movq %%mm7,%%mm3\n"
"psllq $8,%%mm2\n"
"psrlq $8,%%mm3\n"
"por %%mm2,%%mm0\n"
"por %%mm3,%%mm1\n"
/* current_upper */
"movq (%0),%%mm6\n"
/* compute the upper-left pixel for dst on %%mm2 */
/* compute the upper-right pixel for dst on %%mm4 */
"movq %%mm0,%%mm2\n"
"movq %%mm1,%%mm4\n"
"movq %%mm0,%%mm3\n"
"movq %%mm1,%%mm5\n"
"pcmpeqb %%mm6,%%mm2\n"
"pcmpeqb %%mm6,%%mm4\n"
"pcmpeqb (%2),%%mm3\n"
"pcmpeqb (%2),%%mm5\n"
"pandn %%mm2,%%mm3\n"
"pandn %%mm4,%%mm5\n"
"movq %%mm0,%%mm2\n"
"movq %%mm1,%%mm4\n"
"pcmpeqb %%mm1,%%mm2\n"
"pcmpeqb %%mm0,%%mm4\n"
"pandn %%mm3,%%mm2\n"
"pandn %%mm5,%%mm4\n"
"movq %%mm2,%%mm3\n"
"movq %%mm4,%%mm5\n"
"pand %%mm6,%%mm2\n"
"pand %%mm6,%%mm4\n"
"pandn %%mm7,%%mm3\n"
"pandn %%mm7,%%mm5\n"
"por %%mm3,%%mm2\n"
"por %%mm5,%%mm4\n"
/* set *dst */
"movq %%mm2,%%mm3\n"
"punpcklbw %%mm4,%%mm2\n"
"punpckhbw %%mm4,%%mm3\n"
"movq %%mm2,(%3)\n"
"movq %%mm3,8(%3)\n"
/* next */
"addl $8,%0\n"
"addl $8,%1\n"
"addl $8,%2\n"
"addl $16,%3\n"
"decl %4\n"
"jnz 0b\n"
"1:\n"
/* final run */
/* set the current, current_pre, current_next registers */
"movq (%1),%%mm1\n"
"movq (%1),%%mm7\n"
"movq -8(%1),%%mm0\n"
"psrlq $56,%%mm1\n"
"psrlq $56,%%mm0\n"
"psllq $56,%%mm1\n"
"movq %%mm7,%%mm2\n"
"movq %%mm7,%%mm3\n"
"psllq $8,%%mm2\n"
"psrlq $8,%%mm3\n"
"por %%mm2,%%mm0\n"
"por %%mm3,%%mm1\n"
/* current_upper */
"movq (%0),%%mm6\n"
/* compute the upper-left pixel for dst on %%mm2 */
/* compute the upper-right pixel for dst on %%mm4 */
"movq %%mm0,%%mm2\n"
"movq %%mm1,%%mm4\n"
"movq %%mm0,%%mm3\n"
"movq %%mm1,%%mm5\n"
"pcmpeqb %%mm6,%%mm2\n"
"pcmpeqb %%mm6,%%mm4\n"
"pcmpeqb (%2),%%mm3\n"
"pcmpeqb (%2),%%mm5\n"
"pandn %%mm2,%%mm3\n"
"pandn %%mm4,%%mm5\n"
"movq %%mm0,%%mm2\n"
"movq %%mm1,%%mm4\n"
"pcmpeqb %%mm1,%%mm2\n"
"pcmpeqb %%mm0,%%mm4\n"
"pandn %%mm3,%%mm2\n"
"pandn %%mm5,%%mm4\n"
"movq %%mm2,%%mm3\n"
"movq %%mm4,%%mm5\n"
"pand %%mm6,%%mm2\n"
"pand %%mm6,%%mm4\n"
"pandn %%mm7,%%mm3\n"
"pandn %%mm7,%%mm5\n"
"por %%mm3,%%mm2\n"
"por %%mm5,%%mm4\n"
/* set *dst */
"movq %%mm2,%%mm3\n"
"punpcklbw %%mm4,%%mm2\n"
"punpckhbw %%mm4,%%mm3\n"
"movq %%mm2,(%3)\n"
"movq %%mm3,8(%3)\n"
"emms"
: "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
:
: "cc"
);
}
static void scale2x_line_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
{
assert(count >= 16);
assert(count % 8 == 0);
scale2x_8_mmx_single(dst0, src0, src1, src2, count);
scale2x_8_mmx_single(dst1, src2, src1, src0, count);
}
static void Scale2x_8_mmx(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) {
if (dy<3) return;
Bit8u * dest=(Bit8u *)render.op.pixels+2*y*render.op.pitch;
/* First line */
scale2x_line_8_mmx(dest,dest+render.op.pitch,src,src,src+render.src.pitch,dx);
dest+=render.op.pitch*2;
src+=render.src.pitch;
dy-=2;
/* Middle part */
for (;dy>0;dy--) {
scale2x_line_8_mmx((Bit8u *)dest,(Bit8u *)(dest+render.op.pitch),src-render.src.pitch,src,src+render.src.pitch,dx);
dest+=render.op.pitch*2;
src+=render.src.pitch;
}
/* Last Line */
scale2x_line_8_mmx((Bit8u *)dest,(Bit8u *)(dest+render.op.pitch),src-render.src.pitch,src,src,dx);
}
#endif
static void Render_Scale2x_CallBack(Bitu width,Bitu height,Bitu bpp,Bitu pitch,Bitu flags) {
if (!(flags & MODE_SET)) return;
render.op.width=width;
render.op.height=height;
render.op.bpp=bpp;
render.op.pitch=pitch;
render.op.type=OP_AdvMame2x;
switch (bpp) {
case 8:
#if defined(SCALE2X_MMX)
render.op.part_handler=Scale2x_8_mmx;
#else
render.op.part_handler=Scale2x_8;
#endif
break;
case 16:
render.op.part_handler=Scale2x_16;;
break;
case 32:
render.op.part_handler=Scale2x_32;
break;
default:
E_Exit("RENDER:Unsupported display depth of %d",bpp);
break;
}
RENDER_ResetPal();
}
#endif

View file

@ -0,0 +1,53 @@
template <Bitu dbpp>
static INLINE void AddDst(Bit8u * & dst,Bitu val) {
switch (dbpp) {
case 8: *(Bit8u*)dst=val;dst+=1;break;
case 16:*(Bit16u*)dst=val;dst+=2;break;
case 24:*(Bit32u*)dst=val;dst+=3;break;
case 32:*(Bit32u*)dst=val;dst+=4;break;
}
}
template <Bitu bpp>
static INLINE Bitu LineSize(Bitu pixels) {
switch (bpp) {
case 8:return pixels;
case 16:return pixels*2;
case 24:return pixels*3;
case 32:return pixels*4;
}
return 0;
}
static INLINE void BituMove(Bit8u * dst,Bit8u * src,Bitu pixels) {
pixels/=sizeof(Bitu);
while (pixels--) {
*(Bitu*)dst=*(Bitu*)src;
src+=sizeof(Bitu);
dst+=sizeof(Bitu);
}
}
template <Bitu sbpp>
static INLINE Bitu LoadSrc(Bit8u * & src) {
Bitu val;
switch (sbpp) {
case 8:val=*(Bit8u *) src;src+=1;break;
case 16:val=*(Bit16u *) src;src+=2;break;
case 24:val=(*(Bit32u *)src)&0xffffff;src+=3;break;
case 32:val=*(Bit32u *)src;src+=4;break;
}
return val;
}
template <Bitu sbpp,Bitu dbpp>
static INLINE Bitu ConvBPP(Bitu val) {
if (sbpp==8) switch (dbpp) {
case 8:return val;
case 16:return render.pal.lookup.bpp16[val];
case 24:return render.pal.lookup.bpp32[val];
case 32:return render.pal.lookup.bpp32[val];
}
return 0;
}