This commit is contained in:
twinaphex
2014-03-30 22:15:17 +02:00
commit 7e6caac57d
370 changed files with 90364 additions and 0 deletions

86
src/drivers/common/args.c Normal file
View File

@@ -0,0 +1,86 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/****************************************************************/
/* FCE Ultra */
/* */
/* This file contains code for parsing command-line */
/* options. */
/* */
/****************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../fceu-types.h"
#include "args.h"
void ParseEA(int x, int argc, char *argv[], ARGPSTRUCT *argsps) {
int y = 0;
do {
if (!argsps[y].name) {
ParseEA(x, argc, argv, (ARGPSTRUCT*)argsps[y].var);
y++;
continue;
}
if (!strcmp(argv[x], argsps[y].name)) { // A match.
if (argsps[y].subs) {
if ((x + 1) >= argc)
break;
if (argsps[y].substype & 0x2000) {
((void (*)(char *))argsps[y].subs)(argv[x + 1]);
} else if (argsps[y].substype & 0x8000) {
*(int*)argsps[y].subs &= ~(argsps[y].substype & (~0x8000));
*(int*)argsps[y].subs |= atoi(argv[x + 1]) ? (argsps[y].substype & (~0x8000)) : 0;
} else
switch (argsps[y].substype & (~0x4000)) {
case 0: // Integer
*(int*)argsps[y].subs = atoi(argv[x + 1]);
break;
case 2: // Double float
*(double*)argsps[y].subs = atof(argv[x + 1]);
break;
case 1: // String
if (argsps[y].substype & 0x4000) {
if (*(char**)argsps[y].subs)
free(*(char**)argsps[y].subs);
if (!(*(char**)argsps[y].subs = (char*)malloc(strlen(argv[x + 1]) + 1)))
break;
}
strcpy(*(char**)argsps[y].subs, argv[x + 1]);
break;
}
}
if (argsps[y].var)
*argsps[y].var = 1;
}
y++;
} while (argsps[y].var || argsps[y].subs);
}
void ParseArguments(int argc, char *argv[], ARGPSTRUCT *argsps) {
int x;
for (x = 0; x < argc; x++)
ParseEA(x, argc, argv, argsps);
}

12
src/drivers/common/args.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef _DRIVERS_ARGH
typedef struct {
char *name;
int *var;
void *subs;
int substype;
} ARGPSTRUCT;
void ParseArguments(int argc, char *argv[], ARGPSTRUCT * argsps);
#define _DRIVERS_ARGH
#endif

467
src/drivers/common/cheat.c Normal file
View File

@@ -0,0 +1,467 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <ctype.h>
#include "../../driver.h"
static void GetString(char *s, int max) {
int x;
fgets(s, max, stdin);
for (x = 0; x < max; x++)
if (s[x] == '\n') {
s[x] = 0;
break;
}
}
/* Get unsigned 16-bit integer from stdin in hex. */
static uint32 GetH16(unsigned int def) {
char buf[32];
fgets(buf, 32, stdin);
if (buf[0] == '\n')
return(def);
if (buf[0] == '$')
sscanf(buf + 1, "%04x", &def);
else
sscanf(buf, "%04x", &def);
return def;
}
/* Get unsigned 8-bit integer from stdin in decimal. */
static uint8 Get8(unsigned int def) {
char buf[32];
fgets(buf, 32, stdin);
if (buf[0] == '\n')
return(def);
sscanf(buf, "%u", &def);
return def;
}
static int GetI(int def) {
char buf[32];
fgets(buf, 32, stdin);
if (buf[0] == '\n')
return(def);
sscanf(buf, "%d", &def);
return def;
}
static int GetYN(int def) {
char buf[32];
printf("(Y/N)[%s]: ", def ? "Y" : "N");
fgets(buf, 32, stdin);
if (buf[0] == 'y' || buf[0] == 'Y')
return(1);
if (buf[0] == 'n' || buf[0] == 'N')
return(0);
return(def);
}
/*
** Begin list code.
**
*/
static int listcount;
static int listids[16];
static int listsel;
static int mordoe;
void BeginListShow(void) {
listcount = 0;
listsel = -1;
mordoe = 0;
}
/* Hmm =0 for in list choices, hmm=1 for end of list choices. */
/* Return equals 0 to continue, -1 to stop, otherwise a number. */
int ListChoice(int hmm) {
char buf[32];
if (!hmm) {
int num = 0;
tryagain:
printf(" <'Enter' to continue, (S)top, or enter a number.> ");
fgets(buf, 32, stdin);
if (buf[0] == 's' || buf[0] == 'S') return(-1);
if (buf[0] == '\n') return(0);
if (!sscanf(buf, "%d", &num))
return(0);
if (num < 1) goto tryagain;
return(num);
} else {
int num = 0;
tryagain2:
printf(" <'Enter' to make no selection or enter a number.> ");
fgets(buf, 32, stdin);
if (buf[0] == '\n') return(0);
if (!sscanf(buf, "%d", &num))
return(0);
if (num < 1) goto tryagain2;
return(num);
}
}
int EndListShow(void) {
if (mordoe) {
int r = ListChoice(1);
if (r > 0 && r <= listcount)
listsel = listids[r - 1];
}
return(listsel);
}
/* Returns 0 to stop listing, 1 to continue. */
int AddToList(char *text, uint32 id) {
if (listcount == 16) {
int t = ListChoice(0);
mordoe = 0;
if (t == -1) return(0); // Stop listing.
else if (t > 0 && t < 17) {
listsel = listids[t - 1];
return(0);
}
listcount = 0;
}
mordoe = 1;
listids[listcount] = id;
printf("%2d) %s\n", listcount + 1, text);
listcount++;
return(1);
}
/*
**
** End list code.
**/
typedef struct MENU {
char *text;
void *action;
int type; // 0 for menu, 1 for function.
} MENU;
static void SetOC(void) {
FCEUI_CheatSearchSetCurrentAsOriginal();
}
static void UnhideEx(void) {
FCEUI_CheatSearchShowExcluded();
}
static void ToggleCheat(int num) {
printf("Cheat %d %sabled.\n", 1 + num,
FCEUI_ToggleCheat(num) ? "en" : "dis");
}
static void ModifyCheat(int num) {
char *name;
char buf[256];
uint32 A;
uint8 V;
int compare;
int type;
int s;
int t;
FCEUI_GetCheat(num, &name, &A, &V, &compare, &s, &type);
printf("Name [%s]: ", name);
GetString(buf, 256);
/* This obviously doesn't allow for cheats with no names. Bah. Who wants
nameless cheats anyway...
*/
if (buf[0])
name = buf; // Change name when FCEUI_SetCheat() is called.
else
name = 0; // Don't change name when FCEUI_SetCheat() is called.
printf("Address [$%04x]: ", (unsigned int)A);
A = GetH16(A);
printf("Value [%03d]: ", (unsigned int)V);
V = Get8(V);
printf("Compare [%3d]: ", compare);
compare = GetI(compare);
printf("Type(0=Old Style, 1=Read Substitute) [%1d]: ", type);
type = GetI(type) ? 1 : 0;
printf("Enable [%s]: ", s ? "Y" : "N");
t = getchar();
if (t == 'Y' || t == 'y') s = 1;
else if (t == 'N' || t == 'n') s = 0;
FCEUI_SetCheat(num, name, A, V, compare, s, type);
}
static void AddCheatGGPAR(int which) {
uint16 A;
uint8 V;
int C;
int type;
char name[256], code[256];
printf("Name: ");
GetString(name, 256);
printf("Code: ");
GetString(code, 256);
printf("Add cheat \"%s\" for code \"%s\"?", name, code);
if (GetYN(0)) {
if (which) {
if (!FCEUI_DecodePAR(code, &A, &V, &C, &type)) {
puts("Invalid Game Genie code.");
return;
}
} else {
if (!FCEUI_DecodeGG(code, &A, &V, &C)) {
puts("Invalid Game Genie code.");
return;
}
type = 1;
}
if (FCEUI_AddCheat(name, A, V, C, type))
puts("Cheat added.");
else
puts("Error adding cheat.");
}
}
static void AddCheatGG(void) {
AddCheatGGPAR(0);
}
static void AddCheatPAR(void) {
AddCheatGGPAR(1);
}
static void AddCheatParam(uint32 A, uint8 V) {
char name[256];
printf("Name: ");
GetString(name, 256);
printf("Address [$%04x]: ", (unsigned int)A);
A = GetH16(A);
printf("Value [%03d]: ", (unsigned int)V);
V = Get8(V);
printf("Add cheat \"%s\" for address $%04x with value %03d?", name, (unsigned int)A, (unsigned int)V);
if (GetYN(0)) {
if (FCEUI_AddCheat(name, A, V, -1, 0))
puts("Cheat added.");
else
puts("Error adding cheat.");
}
}
static void AddCheat(void) {
AddCheatParam(0, 0);
}
static int lid;
static int clistcallb(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data) {
char tmp[512];
int ret;
if (compare >= 0)
sprintf(tmp, "%s $%04x:%03d:%03d - %s", s ? "*" : " ", (unsigned int)a, (unsigned int)v, compare, name);
else
sprintf(tmp, "%s $%04x:%03d - %s", s ? "*" : " ", (unsigned int)a, (unsigned int)v, name);
if (type == 1)
tmp[2] = 'S';
ret = AddToList(tmp, lid);
lid++;
return(ret);
}
static void ListCheats(void) {
int which;
lid = 0;
BeginListShow();
FCEUI_ListCheats(clistcallb, 0);
which = EndListShow();
if (which >= 0) {
char tmp[32];
printf(" <(T)oggle status, (M)odify, or (D)elete this cheat.> ");
fgets(tmp, 32, stdin);
switch (tolower(tmp[0])) {
case 't': ToggleCheat(which);
break;
case 'd': if (!FCEUI_DelCheat(which))
puts("Error deleting cheat!");
else
puts("Cheat has been deleted.");
break;
case 'm': ModifyCheat(which);
break;
}
}
}
static void ResetSearch(void) {
FCEUI_CheatSearchBegin();
puts("Done.");
}
static int srescallb(uint32 a, uint8 last, uint8 current, void *data) {
char tmp[13];
sprintf(tmp, "$%04x:%03d:%03d", (unsigned int)a, (unsigned int)last, (unsigned int)current);
return(AddToList(tmp, a));
}
static void ShowRes(void) {
int n = FCEUI_CheatSearchGetCount();
printf(" %d results:\n", n);
if (n) {
int which;
BeginListShow();
FCEUI_CheatSearchGet(srescallb, 0);
which = EndListShow();
if (which >= 0)
AddCheatParam(which, 0);
}
}
static int ShowShortList(char *moe[], int n, int def) {
int x, c;
unsigned int baa;
char tmp[16];
red:
for (x = 0; x < n; x++)
printf("%d) %s\n", x + 1, moe[x]);
puts("D) Display List");
clo:
printf("\nSelection [%d]> ", def + 1);
fgets(tmp, 256, stdin);
if (tmp[0] == '\n')
return def;
c = tolower(tmp[0]);
baa = c - '1';
if (baa < n)
return baa;
else if (c == 'd')
goto red;
else {
puts("Invalid selection.");
goto clo;
}
}
static void DoSearch(void) {
static int v1 = 0, v2 = 0;
static int method = 0;
char *m[6] = { "O==V1 && C==V2", "O==V1 && |O-C|==V2", "|O-C|==V2", "O!=C", "Value decreased", "Value increased" };
printf("\nSearch Filter:\n");
method = ShowShortList(m, 6, method);
if (method <= 1) {
printf("V1 [%03d]: ", v1);
v1 = Get8(v1);
}
if (method <= 2) {
printf("V2 [%03d]: ", v2);
v2 = Get8(v2);
}
FCEUI_CheatSearchEnd(method, v1, v2);
puts("Search completed.\n");
}
static MENU NewCheatsMenu[] = {
{ "Add Cheat", (void*)AddCheat, 1 },
{ "Reset Search", (void*)ResetSearch, 1 },
{ "Do Search", (void*)DoSearch, 1 },
{ "Set Original to Current", (void*)SetOC, 1 },
{ "Unhide Excluded", (void*)UnhideEx, 1 },
{ "Show Results", (void*)ShowRes, 1 },
{ "Add Game Genie Cheat", (void*)AddCheatGG, 1 },
{ "Add PAR Cheat", (void*)AddCheatPAR, 1 },
{ 0 }
};
static MENU MainMenu[] = {
{ "List Cheats", (void*)ListCheats, 1 },
{ "New Cheats...", (void*)NewCheatsMenu, 0 },
{ 0 }
};
static void DoMenu(MENU *men) {
int x = 0;
redisplay:
x = 0;
puts("");
while (men[x].text) {
printf("%d) %s\n", x + 1, men[x].text);
x++;
}
puts("D) Display Menu\nX) Return to Previous\n");
{
char buf[32];
int c;
recommand:
printf("Command> ");
fgets(buf, 32, stdin);
c = tolower(buf[0]);
if (c == '\n')
goto recommand;
else if (c == 'd')
goto redisplay;
else if (c == 'x') {
return;
} else if (sscanf(buf, "%d", &c)) {
if (c > x) goto invalid;
if (men[c - 1].type) {
void (*func)(void) = (void (*)())men[c - 1].action;
func();
} else
DoMenu((MENU*)men[c - 1].action); /* Mmm...recursivey goodness. */
goto redisplay;
} else {
invalid:
puts("Invalid command.\n");
goto recommand;
}
}
}
void DoConsoleCheatConfig(void) {
MENU *curmenu = MainMenu;
DoMenu(curmenu);
}

View File

@@ -0,0 +1,21 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
void DoConsoleCheatConfig(void);

134
src/drivers/common/config.c Normal file
View File

@@ -0,0 +1,134 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/****************************************************************/
/* FCE Ultra */
/* */
/* This file contains routines for reading/writing the */
/* configuration file. */
/* */
/****************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../fceu-types.h"
#include "config.h"
static int FReadString(FILE *fp, char *str, int n) {
int x = 0, z;
for (;; ) {
z = fgetc(fp);
str[x] = z;
x++;
if (z <= 0) break;
if (x >= n) return 0;
}
if (z < 0) return 0;
return 1;
}
static void GetValueR(FILE *fp, char *str, void *v, int c) {
char buf[256];
int s;
while (FReadString(fp, buf, 256)) {
fread(&s, 1, 4, fp);
if (!strcmp(str, buf)) {
if (!c) { // String, allocate some memory.
if (!(*(char**)v = (char*)malloc(s)))
goto gogl;
fread(*(char**)v, 1, s, fp);
continue;
} else if (s > c || s < c) {
gogl:
fseek(fp, s, SEEK_CUR);
continue;
}
fread((uint8*)v, 1, c, fp);
} else
fseek(fp, s, SEEK_CUR);
}
fseek(fp, 4, SEEK_SET);
}
static void SetValueR(FILE *fp, char *str, void *v, int c) {
fwrite(str, 1, strlen(str) + 1, fp);
fwrite((uint8*)&c, 1, 4, fp);
fwrite((uint8*)v, 1, c, fp);
}
static void SaveParse(CFGSTRUCT *cfgst, FILE *fp) {
int x = 0;
while (cfgst[x].ptr) {
if (!cfgst[x].name) { // Link to new config structure
SaveParse((CFGSTRUCT*)cfgst[x].ptr, fp); // Recursion is sexy. I could
// save a little stack space if I made
// the file pointer a non-local
// variable...
x++;
continue;
}
if (cfgst[x].len) // Plain data
SetValueR(fp, cfgst[x].name, cfgst[x].ptr, cfgst[x].len);
else // String
if (*(char**)cfgst[x].ptr) // Only save it if there IS a string.
SetValueR(fp, cfgst[x].name, *(char**)cfgst[x].ptr,
strlen(*(char**)cfgst[x].ptr) + 1);
x++;
}
}
void SaveFCEUConfig(char *filename, CFGSTRUCT *cfgst) {
FILE *fp;
fp = fopen(filename, "wb");
if (fp == NULL) return;
SaveParse(cfgst, fp);
fclose(fp);
}
static void LoadParse(CFGSTRUCT *cfgst, FILE *fp) {
int x = 0;
while (cfgst[x].ptr) {
if (!cfgst[x].name) { // Link to new config structure
LoadParse((CFGSTRUCT*)cfgst[x].ptr, fp);
x++;
continue;
}
GetValueR(fp, cfgst[x].name, cfgst[x].ptr, cfgst[x].len);
x++;
}
}
void LoadFCEUConfig(char *filename, CFGSTRUCT *cfgst) {
FILE *fp;
fp = fopen(filename, "rb");
if (fp == NULL) return;
LoadParse(cfgst, fp);
fclose(fp);
}

View File

@@ -0,0 +1,40 @@
#ifndef _DRIVERS_CONFIGH
typedef struct {
char *name;
void *ptr;
int len;
} CFGSTRUCT;
void SaveFCEUConfig(char *filename, CFGSTRUCT *cfgst);
void LoadFCEUConfig(char *filename, CFGSTRUCT *cfgst);
/* Macros for building CFGSTRUCT structures. */
/* CFGSTRUCT structures must always end with ENDCFGSTRUCT */
#define ENDCFGSTRUCT { 0, 0, 0 }
/* When this macro is used, the config loading/saving code will parse
the new config structure until the end of it is detected, then it
will continue parsing the original config structure.
*/
#define ADDCFGSTRUCT(x) { 0, &x, 0 }
/* Oops. The NAC* macros shouldn't have the # in front of the w, but
fixing this would break configuration files of previous versions and it
isn't really hurting much.
*/
/* Single piece of data(integer). */
#define AC(x) { # x, &x, sizeof(x) }
#define NAC(w, x) { # w, &x, sizeof(x) }
/* Array. */
#define ACA(x) { # x, x, sizeof(x) }
#define NACA(w, x) { # w, x, sizeof(x) }
/* String(pointer) with automatic memory allocation. */
#define ACS(x) { # x, &x, 0 }
#define NACS(w, x) { # w, &x, 0 }
#define _DRIVERS_CONFIGH
#endif

2434
src/drivers/common/hq2x.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
void hq2x_32(unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int BpL);
int hq2x_InitLUTs(void);
void hq2x_Kill(void);

3318
src/drivers/common/hq3x.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
void hq3x_32(unsigned char * pIn, unsigned char * pOut, int Xres, int Yres, int BpL);
int hq3x_InitLUTs(void);
void hq3x_Kill(void);

View File

@@ -0,0 +1,911 @@
/*
* This file is part of the Scale2x project.
*
* Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This file contains a C and MMX implementation of the Scale2x effect.
*
* You can find an high level description of the effect at :
*
* http://scale2x.sourceforge.net/
*
* 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.
*/
#include "scale2x.h"
#include <assert.h>
/***************************************************************************/
/* Scale2x C implementation */
static inline void scale2x_8_def_single(scale2x_uint8* __restrict__ dst, const scale2x_uint8* __restrict__ src0, const scale2x_uint8* __restrict__ src1, const scale2x_uint8* __restrict__ src2, unsigned count) {
assert(count >= 2);
/* first pixel */
dst[0] = src1[0];
if (src1[1] == src0[0] && src2[0] != src0[0])
dst[1] = src0[0];
else
dst[1] = src1[0];
++src0;
++src1;
++src2;
dst += 2;
/* central pixels */
count -= 2;
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
} else {
dst[0] = src1[0];
dst[1] = src1[0];
}
++src0;
++src1;
++src2;
dst += 2;
--count;
}
/* last pixel */
if (src1[-1] == src0[0] && src2[0] != src0[0])
dst[0] = src0[0];
else
dst[0] = src1[0];
dst[1] = src1[0];
}
static inline void scale2x_16_def_single(scale2x_uint16* __restrict__ dst, const scale2x_uint16* __restrict__ src0, const scale2x_uint16* __restrict__ src1, const scale2x_uint16* __restrict__ src2, unsigned count) {
assert(count >= 2);
/* first pixel */
dst[0] = src1[0];
if (src1[1] == src0[0] && src2[0] != src0[0])
dst[1] = src0[0];
else
dst[1] = src1[0];
++src0;
++src1;
++src2;
dst += 2;
/* central pixels */
count -= 2;
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
} else {
dst[0] = src1[0];
dst[1] = src1[0];
}
++src0;
++src1;
++src2;
dst += 2;
--count;
}
/* last pixel */
if (src1[-1] == src0[0] && src2[0] != src0[0])
dst[0] = src0[0];
else
dst[0] = src1[0];
dst[1] = src1[0];
}
static inline void scale2x_32_def_single(scale2x_uint32* __restrict__ dst, const scale2x_uint32* __restrict__ src0, const scale2x_uint32* __restrict__ src1, const scale2x_uint32* __restrict__ src2, unsigned count) {
assert(count >= 2);
/* first pixel */
dst[0] = src1[0];
if (src1[1] == src0[0] && src2[0] != src0[0])
dst[1] = src0[0];
else
dst[1] = src1[0];
++src0;
++src1;
++src2;
dst += 2;
/* central pixels */
count -= 2;
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
} else {
dst[0] = src1[0];
dst[1] = src1[0];
}
++src0;
++src1;
++src2;
dst += 2;
--count;
}
/* last pixel */
if (src1[-1] == src0[0] && src2[0] != src0[0])
dst[0] = src0[0];
else
dst[0] = src1[0];
dst[1] = src1[0];
}
/**
* Scale by a factor of 2 a row of pixels of 8 bits.
* The function is implemented in C.
* The pixels over the left and right borders are assumed of the same color of
* the pixels on the border.
* \param src0 Pointer at the first pixel of the previous row.
* \param src1 Pointer at the first pixel of the current row.
* \param src2 Pointer at the first pixel of the next row.
* \param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
* \param dst0 First destination row, double length in pixels.
* \param dst1 Second destination row, double length in pixels.
*/
void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) {
assert(count >= 2);
scale2x_8_def_single(dst0, src0, src1, src2, count);
scale2x_8_def_single(dst1, src2, src1, src0, count);
}
/**
* Scale by a factor of 2 a row of pixels of 16 bits.
* This function operates like scale2x_8_def() but for 16 bits pixels.
* \param src0 Pointer at the first pixel of the previous row.
* \param src1 Pointer at the first pixel of the current row.
* \param src2 Pointer at the first pixel of the next row.
* \param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
* \param dst0 First destination row, double length in pixels.
* \param dst1 Second destination row, double length in pixels.
*/
void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) {
assert(count >= 2);
scale2x_16_def_single(dst0, src0, src1, src2, count);
scale2x_16_def_single(dst1, src2, src1, src0, count);
}
/**
* Scale by a factor of 2 a row of pixels of 32 bits.
* This function operates like scale2x_8_def() but for 32 bits pixels.
* \param src0 Pointer at the first pixel of the previous row.
* \param src1 Pointer at the first pixel of the current row.
* \param src2 Pointer at the first pixel of the next row.
* \param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
* \param dst0 First destination row, double length in pixels.
* \param dst1 Second destination row, double length in pixels.
*/
void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) {
assert(count >= 2);
scale2x_32_def_single(dst0, src0, src1, src2, count);
scale2x_32_def_single(dst1, src2, src1, src0, count);
}
/***************************************************************************/
/* Scale2x MMX implementation */
#if defined(__GNUC__) && defined(__i386__)
/*
* Apply the Scale2x effect at a single row.
* This function must be called only by the other scale2x functions.
*
* Considering the pixel map :
*
* ABC (src0)
* DEF (src1)
* GHI (src2)
*
* this functions compute 2 new pixels in substitution of the source pixel E
* like this map :
*
* ab (dst)
*
* with these variables :
*
* &current -> E
* &current_left -> D
* &current_right -> F
* &current_upper -> B
* &current_lower -> H
*
* %0 -> current_upper
* %1 -> current
* %2 -> current_lower
* %3 -> dst
* %4 -> counter
*
* %mm0 -> *current_left
* %mm1 -> *current_next
* %mm2 -> tmp0
* %mm3 -> tmp1
* %mm4 -> tmp2
* %mm5 -> tmp3
* %mm6 -> *current_upper
* %mm7 -> *current
*/
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"
: "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
:
: "cc"
);
}
static inline void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) {
assert(count >= 8);
assert(count % 4 == 0);
/* always do the first and last run */
count -= 2 * 4;
__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 $48, %%mm0\n"
"psllq $48, %%mm1\n"
"psrlq $48, %%mm0\n"
"movq %%mm7, %%mm2\n"
"movq %%mm7, %%mm3\n"
"psllq $16, %%mm2\n"
"psrlq $16, %%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"
"pcmpeqw %%mm6, %%mm2\n"
"pcmpeqw %%mm6, %%mm4\n"
"pcmpeqw (%2), %%mm3\n"
"pcmpeqw (%2), %%mm5\n"
"pandn %%mm2, %%mm3\n"
"pandn %%mm4, %%mm5\n"
"movq %%mm0, %%mm2\n"
"movq %%mm1, %%mm4\n"
"pcmpeqw %%mm1, %%mm2\n"
"pcmpeqw %%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"
"punpcklwd %%mm4, %%mm2\n"
"punpckhwd %%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 $2, %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 $48, %%mm0\n"
"psllq $48, %%mm1\n"
"movq %%mm7, %%mm2\n"
"movq %%mm7, %%mm3\n"
"psllq $16, %%mm2\n"
"psrlq $16, %%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"
"pcmpeqw %%mm6, %%mm2\n"
"pcmpeqw %%mm6, %%mm4\n"
"pcmpeqw (%2), %%mm3\n"
"pcmpeqw (%2), %%mm5\n"
"pandn %%mm2, %%mm3\n"
"pandn %%mm4, %%mm5\n"
"movq %%mm0, %%mm2\n"
"movq %%mm1, %%mm4\n"
"pcmpeqw %%mm1, %%mm2\n"
"pcmpeqw %%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"
"punpcklwd %%mm4, %%mm2\n"
"punpckhwd %%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 $48, %%mm1\n"
"psrlq $48, %%mm0\n"
"psllq $48, %%mm1\n"
"movq %%mm7, %%mm2\n"
"movq %%mm7, %%mm3\n"
"psllq $16, %%mm2\n"
"psrlq $16, %%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"
"pcmpeqw %%mm6, %%mm2\n"
"pcmpeqw %%mm6, %%mm4\n"
"pcmpeqw (%2), %%mm3\n"
"pcmpeqw (%2), %%mm5\n"
"pandn %%mm2, %%mm3\n"
"pandn %%mm4, %%mm5\n"
"movq %%mm0, %%mm2\n"
"movq %%mm1, %%mm4\n"
"pcmpeqw %%mm1, %%mm2\n"
"pcmpeqw %%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"
"punpcklwd %%mm4, %%mm2\n"
"punpckhwd %%mm4, %%mm3\n"
"movq %%mm2, (%3)\n"
"movq %%mm3, 8(%3)\n"
: "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
:
: "cc"
);
}
static inline void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) {
assert(count >= 4);
assert(count % 2 == 0);
/* always do the first and last run */
count -= 2 * 2;
__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 $32, %%mm0\n"
"psllq $32, %%mm1\n"
"psrlq $32, %%mm0\n"
"movq %%mm7, %%mm2\n"
"movq %%mm7, %%mm3\n"
"psllq $32, %%mm2\n"
"psrlq $32, %%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"
"pcmpeqd %%mm6, %%mm2\n"
"pcmpeqd %%mm6, %%mm4\n"
"pcmpeqd (%2), %%mm3\n"
"pcmpeqd (%2), %%mm5\n"
"pandn %%mm2, %%mm3\n"
"pandn %%mm4, %%mm5\n"
"movq %%mm0, %%mm2\n"
"movq %%mm1, %%mm4\n"
"pcmpeqd %%mm1, %%mm2\n"
"pcmpeqd %%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"
"punpckldq %%mm4, %%mm2\n"
"punpckhdq %%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 $1, %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 $32, %%mm0\n"
"psllq $32, %%mm1\n"
"movq %%mm7, %%mm2\n"
"movq %%mm7, %%mm3\n"
"psllq $32, %%mm2\n"
"psrlq $32, %%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"
"pcmpeqd %%mm6, %%mm2\n"
"pcmpeqd %%mm6, %%mm4\n"
"pcmpeqd (%2), %%mm3\n"
"pcmpeqd (%2), %%mm5\n"
"pandn %%mm2, %%mm3\n"
"pandn %%mm4, %%mm5\n"
"movq %%mm0, %%mm2\n"
"movq %%mm1, %%mm4\n"
"pcmpeqd %%mm1, %%mm2\n"
"pcmpeqd %%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"
"punpckldq %%mm4, %%mm2\n"
"punpckhdq %%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 $32, %%mm1\n"
"psrlq $32, %%mm0\n"
"psllq $32, %%mm1\n"
"movq %%mm7, %%mm2\n"
"movq %%mm7, %%mm3\n"
"psllq $32, %%mm2\n"
"psrlq $32, %%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"
"pcmpeqd %%mm6, %%mm2\n"
"pcmpeqd %%mm6, %%mm4\n"
"pcmpeqd (%2), %%mm3\n"
"pcmpeqd (%2), %%mm5\n"
"pandn %%mm2, %%mm3\n"
"pandn %%mm4, %%mm5\n"
"movq %%mm0, %%mm2\n"
"movq %%mm1, %%mm4\n"
"pcmpeqd %%mm1, %%mm2\n"
"pcmpeqd %%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"
"punpckldq %%mm4, %%mm2\n"
"punpckhdq %%mm4, %%mm3\n"
"movq %%mm2, (%3)\n"
"movq %%mm3, 8(%3)\n"
: "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
:
: "cc"
);
}
/**
* Scale by a factor of 2 a row of pixels of 8 bits.
* This is a very fast MMX implementation.
* The implementation uses a combination of cmp/and/not operations to
* completly remove the need of conditional jumps. This trick give the
* major speed improvement.
* Also, using the 8 bytes MMX registers more than one pixel are computed
* at the same time.
* Before calling this function you must ensure that the currenct CPU supports
* the MMX instruction set. After calling it you must be sure to call the EMMS
* instruction before any floating-point operation.
* The pixels over the left and right borders are assumed of the same color of
* the pixels on the border.
* \param src0 Pointer at the first pixel of the previous row.
* \param src1 Pointer at the first pixel of the current row.
* \param src2 Pointer at the first pixel of the next row.
* \param count Length in pixels of the src0, src1 and src2 rows. It must
* be at least 16 and a multiple of 8.
* \param dst0 First destination row, double length in pixels.
* \param dst1 Second destination row, double length in pixels.
*/
void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count) {
if (count % 8 != 0 || count < 16) {
scale2x_8_def(dst0, dst1, src0, src1, src2, count);
} else {
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);
}
}
/**
* Scale by a factor of 2 a row of pixels of 16 bits.
* This function operates like scale2x_8_mmx() but for 16 bits pixels.
* \param src0 Pointer at the first pixel of the previous row.
* \param src1 Pointer at the first pixel of the current row.
* \param src2 Pointer at the first pixel of the next row.
* \param count Length in pixels of the src0, src1 and src2 rows. It must
* be at least 8 and a multiple of 4.
* \param dst0 First destination row, double length in pixels.
* \param dst1 Second destination row, double length in pixels.
*/
void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count) {
if (count % 4 != 0 || count < 8) {
scale2x_16_def(dst0, dst1, src0, src1, src2, count);
} else {
assert(count >= 8);
assert(count % 4 == 0);
scale2x_16_mmx_single(dst0, src0, src1, src2, count);
scale2x_16_mmx_single(dst1, src2, src1, src0, count);
}
}
/**
* Scale by a factor of 2 a row of pixels of 32 bits.
* This function operates like scale2x_8_mmx() but for 32 bits pixels.
* \param src0 Pointer at the first pixel of the previous row.
* \param src1 Pointer at the first pixel of the current row.
* \param src2 Pointer at the first pixel of the next row.
* \param count Length in pixels of the src0, src1 and src2 rows. It must
* be at least 4 and a multiple of 2.
* \param dst0 First destination row, double length in pixels.
* \param dst1 Second destination row, double length in pixels.
*/
void scale2x_32_mmx(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count) {
if (count % 2 != 0 || count < 4) {
scale2x_32_def(dst0, dst1, src0, src1, src2, count);
} else {
assert(count >= 4);
assert(count % 2 == 0);
scale2x_32_mmx_single(dst0, src0, src1, src2, count);
scale2x_32_mmx_single(dst1, src2, src1, src0, count);
}
}
#endif

View File

@@ -0,0 +1,51 @@
/*
* This file is part of the Scale2x project.
*
* Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __SCALE2X_H
#define __SCALE2X_H
typedef unsigned char scale2x_uint8;
typedef unsigned short scale2x_uint16;
typedef unsigned scale2x_uint32;
void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
#if defined(__GNUC__) && defined(__i386__)
void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
void scale2x_32_mmx(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
/**
* End the use of the MMX instructions.
* This function must be called before using any floating-point operations.
*/
static inline void scale2x_mmx_emms(void) {
__asm__ __volatile__ (
"emms"
);
}
#endif
#endif

View File

@@ -0,0 +1,373 @@
/*
* This file is part of the Scale2x project.
*
* Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This file contains a C and MMX implementation of the Scale2x effect.
*
* You can find an high level description of the effect at :
*
* http://scale2x.sourceforge.net/
*
* 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.
*/
#include "scale3x.h"
#include <assert.h>
/***************************************************************************/
/* Scale3x C implementation */
static inline void scale3x_8_def_border(scale3x_uint8* __restrict__ dst, const scale3x_uint8* __restrict__ src0, const scale3x_uint8* __restrict__ src1, const scale3x_uint8* __restrict__ src2, unsigned count) {
assert(count >= 2);
/* first pixel */
dst[0] = src1[0];
dst[1] = src1[0];
if (src1[1] == src0[0] && src2[0] != src0[0])
dst[2] = src0[0];
else
dst[2] = src1[0];
++src0;
++src1;
++src2;
dst += 3;
/* central pixels */
count -= 2;
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
} else {
dst[0] = src1[0];
dst[1] = src1[0];
dst[2] = src1[0];
}
++src0;
++src1;
++src2;
dst += 3;
--count;
}
/* last pixel */
if (src1[-1] == src0[0] && src2[0] != src0[0])
dst[0] = src0[0];
else
dst[0] = src1[0];
dst[1] = src1[0];
dst[2] = src1[0];
}
static inline void scale3x_8_def_center(scale3x_uint8* __restrict__ dst, const scale3x_uint8* __restrict__ src0, const scale3x_uint8* __restrict__ src1, const scale3x_uint8* __restrict__ src2, unsigned count) {
assert(count >= 2);
/* first pixel */
dst[0] = src1[0];
dst[1] = src1[0];
if (src0[0] != src2[0]) {
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
} else {
dst[2] = src1[0];
}
++src0;
++src1;
++src2;
dst += 3;
/* central pixels */
count -= 2;
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
dst[1] = src1[0];
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
} else {
dst[0] = src1[0];
dst[1] = src1[0];
dst[2] = src1[0];
}
++src0;
++src1;
++src2;
dst += 3;
--count;
}
/* last pixel */
if (src0[0] != src2[0]) {
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
} else {
dst[0] = src1[0];
}
dst[1] = src1[0];
dst[2] = src1[0];
}
static inline void scale3x_16_def_border(scale3x_uint16* __restrict__ dst, const scale3x_uint16* __restrict__ src0, const scale3x_uint16* __restrict__ src1, const scale3x_uint16* __restrict__ src2, unsigned count) {
assert(count >= 2);
/* first pixel */
dst[0] = src1[0];
dst[1] = src1[0];
if (src1[1] == src0[0] && src2[0] != src0[0])
dst[2] = src0[0];
else
dst[2] = src1[0];
++src0;
++src1;
++src2;
dst += 3;
/* central pixels */
count -= 2;
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
} else {
dst[0] = src1[0];
dst[1] = src1[0];
dst[2] = src1[0];
}
++src0;
++src1;
++src2;
dst += 3;
--count;
}
/* last pixel */
if (src1[-1] == src0[0] && src2[0] != src0[0])
dst[0] = src0[0];
else
dst[0] = src1[0];
dst[1] = src1[0];
dst[2] = src1[0];
}
static inline void scale3x_16_def_center(scale3x_uint16* __restrict__ dst, const scale3x_uint16* __restrict__ src0, const scale3x_uint16* __restrict__ src1, const scale3x_uint16* __restrict__ src2, unsigned count) {
assert(count >= 2);
/* first pixel */
dst[0] = src1[0];
dst[1] = src1[0];
if (src0[0] != src2[0]) {
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
} else {
dst[2] = src1[0];
}
++src0;
++src1;
++src2;
dst += 3;
/* central pixels */
count -= 2;
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
dst[1] = src1[0];
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
} else {
dst[0] = src1[0];
dst[1] = src1[0];
dst[2] = src1[0];
}
++src0;
++src1;
++src2;
dst += 3;
--count;
}
/* last pixel */
if (src0[0] != src2[0]) {
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
} else {
dst[0] = src1[0];
}
dst[1] = src1[0];
dst[2] = src1[0];
}
static inline void scale3x_32_def_border(scale3x_uint32* __restrict__ dst, const scale3x_uint32* __restrict__ src0, const scale3x_uint32* __restrict__ src1, const scale3x_uint32* __restrict__ src2, unsigned count) {
assert(count >= 2);
/* first pixel */
dst[0] = src1[0];
dst[1] = src1[0];
if (src1[1] == src0[0] && src2[0] != src0[0])
dst[2] = src0[0];
else
dst[2] = src1[0];
++src0;
++src1;
++src2;
dst += 3;
/* central pixels */
count -= 2;
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
} else {
dst[0] = src1[0];
dst[1] = src1[0];
dst[2] = src1[0];
}
++src0;
++src1;
++src2;
dst += 3;
--count;
}
/* last pixel */
if (src1[-1] == src0[0] && src2[0] != src0[0])
dst[0] = src0[0];
else
dst[0] = src1[0];
dst[1] = src1[0];
dst[2] = src1[0];
}
static inline void scale3x_32_def_center(scale3x_uint32* __restrict__ dst, const scale3x_uint32* __restrict__ src0, const scale3x_uint32* __restrict__ src1, const scale3x_uint32* __restrict__ src2, unsigned count) {
assert(count >= 2);
/* first pixel */
dst[0] = src1[0];
dst[1] = src1[0];
if (src0[0] != src2[0]) {
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
} else {
dst[2] = src1[0];
}
++src0;
++src1;
++src2;
dst += 3;
/* central pixels */
count -= 2;
while (count) {
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
dst[1] = src1[0];
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
} else {
dst[0] = src1[0];
dst[1] = src1[0];
dst[2] = src1[0];
}
++src0;
++src1;
++src2;
dst += 3;
--count;
}
/* last pixel */
if (src0[0] != src2[0]) {
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
} else {
dst[0] = src1[0];
}
dst[1] = src1[0];
dst[2] = src1[0];
}
/**
* Scale by a factor of 3 a row of pixels of 8 bits.
* The function is implemented in C.
* The pixels over the left and right borders are assumed of the same color of
* the pixels on the border.
* \param src0 Pointer at the first pixel of the previous row.
* \param src1 Pointer at the first pixel of the current row.
* \param src2 Pointer at the first pixel of the next row.
* \param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
* \param dst0 First destination row, triple length in pixels.
* \param dst1 Second destination row, triple length in pixels.
* \param dst2 Third destination row, triple length in pixels.
*/
void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count) {
assert(count >= 2);
scale3x_8_def_border(dst0, src0, src1, src2, count);
scale3x_8_def_center(dst1, src0, src1, src2, count);
scale3x_8_def_border(dst2, src2, src1, src0, count);
}
/**
* Scale by a factor of 3 a row of pixels of 16 bits.
* This function operates like scale3x_8_def() but for 16 bits pixels.
* \param src0 Pointer at the first pixel of the previous row.
* \param src1 Pointer at the first pixel of the current row.
* \param src2 Pointer at the first pixel of the next row.
* \param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
* \param dst0 First destination row, triple length in pixels.
* \param dst1 Second destination row, triple length in pixels.
* \param dst2 Third destination row, triple length in pixels.
*/
void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count) {
assert(count >= 2);
scale3x_16_def_border(dst0, src0, src1, src2, count);
scale3x_16_def_center(dst1, src0, src1, src2, count);
scale3x_16_def_border(dst2, src2, src1, src0, count);
}
/**
* Scale by a factor of 3 a row of pixels of 32 bits.
* This function operates like scale3x_8_def() but for 32 bits pixels.
* \param src0 Pointer at the first pixel of the previous row.
* \param src1 Pointer at the first pixel of the current row.
* \param src2 Pointer at the first pixel of the next row.
* \param count Length in pixels of the src0, src1 and src2 rows.
* It must be at least 2.
* \param dst0 First destination row, triple length in pixels.
* \param dst1 Second destination row, triple length in pixels.
* \param dst2 Third destination row, triple length in pixels.
*/
void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count) {
assert(count >= 2);
scale3x_32_def_border(dst0, src0, src1, src2, count);
scale3x_32_def_center(dst1, src0, src1, src2, count);
scale3x_32_def_border(dst2, src2, src1, src0, count);
}

View File

@@ -0,0 +1,33 @@
/*
* This file is part of the Scale2x project.
*
* Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __SCALE3X_H
#define __SCALE3X_H
typedef unsigned char scale3x_uint8;
typedef unsigned short scale3x_uint16;
typedef unsigned scale3x_uint32;
void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count);
void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count);
void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count);
#endif

View File

@@ -0,0 +1,376 @@
/*
* This file is part of the Scale2x project.
*
* Copyright (C) 2003 Andrea Mazzoleni
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This file contains an example implementation of the Scale effect
* applyed to a generic bitmap.
*
* You can find an high level description of the effect at :
*
* http://scale2x.sourceforge.net/
*
* 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.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "scale2x.h"
#include "scale3x.h"
#if HAVE_ALLOCA_H
#include <alloca.h>
#endif
#include <assert.h>
#include <stdlib.h>
/**
* Apply the Scale2x effect on a group of rows. Used internally.
*/
static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) {
switch (pixel) {
#if defined(__GNUC__) && defined(__i386__)
case 1: scale2x_8_mmx(dst0, dst1, src0, src1, src2, pixel_per_row); break;
case 2: scale2x_16_mmx(dst0, dst1, src0, src1, src2, pixel_per_row); break;
case 4: scale2x_32_mmx(dst0, dst1, src0, src1, src2, pixel_per_row); break;
#else
case 1: scale2x_8_def(dst0, dst1, src0, src1, src2, pixel_per_row); break;
case 2: scale2x_16_def(dst0, dst1, src0, src1, src2, pixel_per_row); break;
case 4: scale2x_32_def(dst0, dst1, src0, src1, src2, pixel_per_row); break;
#endif
}
}
/**
* Apply the Scale3x effect on a group of rows. Used internally.
*/
static inline void stage_scale3x(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) {
switch (pixel) {
case 1: scale3x_8_def(dst0, dst1, dst2, src0, src1, src2, pixel_per_row); break;
case 2: scale3x_16_def(dst0, dst1, dst2, src0, src1, src2, pixel_per_row); break;
case 4: scale3x_32_def(dst0, dst1, dst2, src0, src1, src2, pixel_per_row); break;
}
}
/**
* Apply the Scale4x effect on a group of rows. Used internally.
*/
static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, const void* src3, unsigned pixel, unsigned pixel_per_row) {
stage_scale2x(dst0, dst1, src0, src1, src2, pixel, 2 * pixel_per_row);
stage_scale2x(dst2, dst3, src1, src2, src3, pixel, 2 * pixel_per_row);
}
#define SCDST(i) (dst + (i) * dst_slice)
#define SCSRC(i) (src + (i) * src_slice)
#define SCMID(i) (mid[(i)])
/**
* Apply the Scale2x effect on a bitmap.
* The destination bitmap is filled with the scaled version of the source bitmap.
* The source bitmap isn't modified.
* The destination bitmap must be manually allocated before calling the function,
* note that the resulting size is exactly 2x2 times the size of the source bitmap.
* \param void_dst Pointer at the first pixel of the destination bitmap.
* \param dst_slice Size in bytes of a destination bitmap row.
* \param void_src Pointer at the first pixel of the source bitmap.
* \param src_slice Size in bytes of a source bitmap row.
* \param pixel Bytes per pixel of the source and destination bitmap.
* \param width Horizontal size in pixels of the source bitmap.
* \param height Vertical size in pixels of the source bitmap.
*/
static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
unsigned char* dst = (unsigned char*)void_dst;
const unsigned char* src = (unsigned char*)void_src;
unsigned count;
assert(height >= 2);
count = height;
stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
dst = SCDST(2);
count -= 2;
while (count) {
stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
dst = SCDST(2);
src = SCSRC(1);
--count;
}
stage_scale2x(SCDST(0), SCDST(1), SCSRC(1 - 1), SCSRC(2 - 1), SCSRC(2 - 1), pixel, width);
#if defined(__GNUC__) && defined(__i386__)
scale2x_mmx_emms();
#endif
}
/**
* Apply the Scale32x effect on a bitmap.
* The destination bitmap is filled with the scaled version of the source bitmap.
* The source bitmap isn't modified.
* The destination bitmap must be manually allocated before calling the function,
* note that the resulting size is exactly 3x3 times the size of the source bitmap.
* \param void_dst Pointer at the first pixel of the destination bitmap.
* \param dst_slice Size in bytes of a destination bitmap row.
* \param void_src Pointer at the first pixel of the source bitmap.
* \param src_slice Size in bytes of a source bitmap row.
* \param pixel Bytes per pixel of the source and destination bitmap.
* \param width Horizontal size in pixels of the source bitmap.
* \param height Vertical size in pixels of the source bitmap.
*/
static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
unsigned char* dst = (unsigned char*)void_dst;
const unsigned char* src = (unsigned char*)void_src;
unsigned count;
assert(height >= 2);
count = height;
stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
dst = SCDST(3);
count -= 2;
while (count) {
stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
dst = SCDST(3);
src = SCSRC(1);
--count;
}
stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(1 - 1), SCSRC(2 - 1), SCSRC(2 - 1), pixel, width);
}
/**
* Apply the Scale4x effect on a bitmap.
* The destination bitmap is filled with the scaled version of the source bitmap.
* The source bitmap isn't modified.
* The destination bitmap must be manually allocated before calling the function,
* note that the resulting size is exactly 4x4 times the size of the source bitmap.
* \note This function requires also a small buffer bitmap used internally to store
* intermediate results. This bitmap must have at least an horizontal size in bytes of 2*width*pixel,
* and a vertical size of 6 rows. The memory of this buffer must not be allocated
* in video memory because it's also read and not only written. Generally
* a heap (malloc) or a stack (alloca) buffer is the best choices.
* \param void_dst Pointer at the first pixel of the destination bitmap.
* \param dst_slice Size in bytes of a destination bitmap row.
* \param void_mid Pointer at the first pixel of the buffer bitmap.
* \param mid_slice Size in bytes of a buffer bitmap row.
* \param void_src Pointer at the first pixel of the source bitmap.
* \param src_slice Size in bytes of a source bitmap row.
* \param pixel Bytes per pixel of the source and destination bitmap.
* \param width Horizontal size in pixels of the source bitmap.
* \param height Vertical size in pixels of the source bitmap.
*/
static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsigned mid_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
unsigned char* dst = (unsigned char*)void_dst;
const unsigned char* src = (unsigned char*)void_src;
unsigned count;
unsigned char* mid[6];
assert(height >= 4);
count = height;
/* set the 6 buffer pointers */
mid[0] = (unsigned char*)void_mid;
mid[1] = mid[0] + mid_slice;
mid[2] = mid[1] + mid_slice;
mid[3] = mid[2] + mid_slice;
mid[4] = mid[3] + mid_slice;
mid[5] = mid[4] + mid_slice;
stage_scale2x(SCMID(-2 + 6), SCMID(-1 + 6), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
stage_scale2x(SCMID(0), SCMID(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
stage_scale2x(SCMID(2), SCMID(3), SCSRC(1), SCSRC(2), SCSRC(3), pixel, width);
stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(-2 + 6), SCMID(-2 + 6), SCMID(-1 + 6), SCMID(0), pixel, width);
dst = SCDST(4);
stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(-1 + 6), SCMID(0), SCMID(1), SCMID(2), pixel, width);
dst = SCDST(4);
count -= 4;
while (count) {
unsigned char* tmp;
stage_scale2x(SCMID(4), SCMID(5), SCSRC(2), SCSRC(3), SCSRC(4), pixel, width);
stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(1), SCMID(2), SCMID(3), SCMID(4), pixel, width);
dst = SCDST(4);
src = SCSRC(1);
tmp = SCMID(0); /* shift by 2 position */
SCMID(0) = SCMID(2);
SCMID(2) = SCMID(4);
SCMID(4) = tmp;
tmp = SCMID(1);
SCMID(1) = SCMID(3);
SCMID(3) = SCMID(5);
SCMID(5) = tmp;
--count;
}
stage_scale2x(SCMID(4), SCMID(5), SCSRC(2), SCSRC(3), SCSRC(3), pixel, width);
stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(1), SCMID(2), SCMID(3), SCMID(4), pixel, width);
dst = SCDST(4);
stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(3), SCMID(4), SCMID(5), SCMID(5), pixel, width);
#if defined(__GNUC__) && defined(__i386__)
scale2x_mmx_emms();
#endif
}
/**
* Apply the Scale4x effect on a bitmap.
* The destination bitmap is filled with the scaled version of the source bitmap.
* The source bitmap isn't modified.
* The destination bitmap must be manually allocated before calling the function,
* note that the resulting size is exactly 4x4 times the size of the source bitmap.
* \note This function operates like ::scale4x_buf() but the intermediate buffer is
* automatically allocated in the stack.
* \param void_dst Pointer at the first pixel of the destination bitmap.
* \param dst_slice Size in bytes of a destination bitmap row.
* \param void_src Pointer at the first pixel of the source bitmap.
* \param src_slice Size in bytes of a source bitmap row.
* \param pixel Bytes per pixel of the source and destination bitmap.
* \param width Horizontal size in pixels of the source bitmap.
* \param height Vertical size in pixels of the source bitmap.
*/
static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
unsigned mid_slice;
void* mid;
mid_slice = 2 * pixel * width; /* required space for 1 row buffer */
mid_slice = (mid_slice + 0x7) & ~0x7; /* align to 8 bytes */
#if HAVE_ALLOCA
mid = alloca(6 * mid_slice); /* allocate space for 6 row buffers */
assert(mid != 0); /* alloca should never fails */
#else
mid = malloc(6 * mid_slice); /* allocate space for 6 row buffers */
if (!mid)
return;
#endif
scale4x_buf(void_dst, dst_slice, mid, mid_slice, void_src, src_slice, pixel, width, height);
#if !HAVE_ALLOCA
free(mid);
#endif
}
/**
* Check if the scale implementation is applicable at the given arguments.
* \param scale Scale factor. 2, 3 or 4.
* \param pixel Bytes per pixel of the source and destination bitmap.
* \param width Horizontal size in pixels of the source bitmap.
* \param height Vertical size in pixels of the source bitmap.
* \return
* - -1 on precondition violated.
* - 0 on success.
*/
int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned height) {
if (scale != 2 && scale != 3 && scale != 4)
return -1;
if (pixel != 1 && pixel != 2 && pixel != 4)
return -1;
switch (scale) {
case 2:
case 3:
if (height < 2)
return -1;
break;
case 4:
if (height < 4)
return -1;
break;
}
#if defined(__GNUC__) && defined(__i386__)
switch (scale) {
case 2:
case 4:
if (width < (16 / pixel))
return -1;
if (width % (8 / pixel) != 0)
return -1;
break;
case 3:
if (width < 2)
return -1;
break;
}
#else
if (width < 2)
return -1;
#endif
return 0;
}
/**
* Apply the Scale effect on a bitmap.
* This function is simply a common interface for ::scale2x(), ::scale3x() and ::scale4x().
* \param scale Scale factor. 2, 3 or 4.
* \param void_dst Pointer at the first pixel of the destination bitmap.
* \param dst_slice Size in bytes of a destination bitmap row.
* \param void_src Pointer at the first pixel of the source bitmap.
* \param src_slice Size in bytes of a source bitmap row.
* \param pixel Bytes per pixel of the source and destination bitmap.
* \param width Horizontal size in pixels of the source bitmap.
* \param height Vertical size in pixels of the source bitmap.
*/
void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
switch (scale) {
case 2:
scale2x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
break;
case 3:
scale3x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
break;
case 4:
scale4x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
break;
}
}

View File

@@ -0,0 +1,43 @@
/*
* This file is part of the Scale2x project.
*
* Copyright (C) 2003 Andrea Mazzoleni
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This file contains an example implementation of the Scale effect
* applyed to a generic bitmap.
*
* You can find an high level description of the effect at :
*
* http://scale2x.sourceforge.net/
*
* 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.
*/
#ifndef __SCALEBIT_H
#define __SCALEBIT_H
int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned height);
void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height);
#endif

View File

@@ -0,0 +1,726 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include "scalebit.h"
#include "hq2x.h"
#include "hq3x.h"
#include "../../fceu-types.h"
static uint32 CBM[3];
static uint32 *palettetranslate = 0;
static uint16 *specbuf = NULL; // 8bpp -> 16bpp, pre hq2x/hq3x
static uint32 *specbuf32bpp = NULL; // Buffer to hold output
// of hq2x/hq3x when converting
// to 16bpp and 24bpp
static int backBpp, backshiftr[3], backshiftl[3];
//static uint32 backmask[3];
static uint8 *specbuf8bpp = NULL; // For 2xscale, 3xscale.
static int silt;
static int Bpp; // BYTES per pixel
static int highefx;
#define BLUR_RED 20
#define BLUR_GREEN 20
#define BLUR_BLUE 10
#define FVB_SCANLINES 1
/* The blur effect is only available for bpp>=16. It could be easily modified
to look like what happens on the real NES and TV, but lack of decent
synchronization to the vertical retrace period makes it look rather
blah.
*/
#define FVB_BLUR 2
static void CalculateShift(uint32 *CBM, int *cshiftr, int *cshiftl) {
int a, x, z, y;
cshiftl[0] = cshiftl[1] = cshiftl[2] = -1;
for (a = 0; a < 3; a++) {
for (x = 0, y = -1, z = 0; x < 32; x++) {
if (CBM[a] & (1 << x)) {
if (cshiftl[a] == -1) cshiftl[a] = x;
z++;
}
}
cshiftr[a] = (8 - z);
}
}
int InitBlitToHigh(int b, uint32 rmask, uint32 gmask, uint32 bmask, int efx, int specfilt) {
if (specfilt == 2 || specfilt == 4) { // scale2x and scale3x
int multi;
if (specfilt == 2) multi = 2 * 2;
else multi = 3 * 3;
specbuf8bpp = malloc(256 * 240 * multi);
} else if (specfilt == 1 || specfilt == 3) { // hq2x and hq3x
if (b == 1)
return(0);
if (b == 2 || b == 3) { // 8->16->(hq2x)->32-> 24 or 16. YARGH.
uint32 tmpCBM[3];
backBpp = b;
tmpCBM[0] = rmask;
tmpCBM[1] = gmask;
tmpCBM[2] = bmask;
CalculateShift(tmpCBM, backshiftr, backshiftl);
if (b == 2) {
// ark
backshiftr[0] += 16;
backshiftr[1] += 8;
backshiftr[2] += 0;
// Begin iffy code(requires 16bpp and 32bpp to have same RGB order)
//backmask[0] = (rmask>>backshiftl[0]) << (backshiftr[0]);
//backmask[1] = (gmask>>backshiftl[1]) << (backshiftr[1]);
//backmask[2] = (bmask>>backshiftl[2]) << (backshiftr[2]);
//int x;
//for(x=0;x<3;x++)
// backshiftr[x] -= backshiftl[x];
// End iffy code
}
if (specfilt == 1) specbuf32bpp = malloc(256 * 240 * 4 * sizeof(uint32));
else if (specfilt == 3) specbuf32bpp = malloc(256 * 240 * 9 * sizeof(uint32));
}
efx = 0;
b = 2;
rmask = 0x1F << 11;
gmask = 0x3F << 5;
bmask = 0x1F;
if (specfilt == 3)
hq3x_InitLUTs();
else
hq2x_InitLUTs();
specbuf = malloc(256 * 240 * sizeof(uint16));
}
silt = specfilt;
Bpp = b;
highefx = efx;
if (Bpp <= 1 || Bpp > 4)
return(0);
if (efx & FVB_BLUR) {
if (Bpp == 2)
palettetranslate = (uint32*)malloc(65536 * 4);
else if (Bpp >= 3)
palettetranslate = (uint32*)malloc(65536 * 4);
} else {
if (Bpp == 2)
palettetranslate = (uint32*)malloc(65536 * 4);
else if (Bpp >= 3)
palettetranslate = (uint32*)malloc(256 * 4);
}
if (!palettetranslate)
return(0);
CBM[0] = rmask;
CBM[1] = gmask;
CBM[2] = bmask;
return(1);
}
void KillBlitToHigh(void) {
if (palettetranslate) {
free(palettetranslate);
palettetranslate = NULL;
}
if (specbuf8bpp) {
free(specbuf8bpp);
specbuf8bpp = NULL;
}
if (specbuf32bpp) {
free(specbuf32bpp);
specbuf32bpp = NULL;
}
if (specbuf) {
if (silt == 3)
hq3x_Kill();
else
hq2x_Kill();
specbuf = NULL;
}
}
void SetPaletteBlitToHigh(uint8 *src) {
int cshiftr[3];
int cshiftl[3];
int x, y;
CalculateShift(CBM, cshiftr, cshiftl);
switch (Bpp) {
case 2:
if (highefx & FVB_BLUR) {
for (x = 0; x < 256; x++) {
uint32 r, g, b;
for (y = 0; y < 256; y++) {
r = src[x << 2] * (100 - BLUR_RED);
g = src[(x << 2) + 1] * (100 - BLUR_GREEN);
b = src[(x << 2) + 2] * (100 - BLUR_BLUE);
r += src[y << 2] * BLUR_RED;
g += src[(y << 2) + 1] * BLUR_GREEN;
b += src[(y << 2) + 2] * BLUR_BLUE;
r /= 100;
g /= 100;
b /= 100;
if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
palettetranslate[x | (y << 8)] = ((r >> cshiftr[0]) << cshiftl[0]) |
((g >> cshiftr[1]) << cshiftl[1]) |
((b >> cshiftr[2]) << cshiftl[2]);
}
}
} else
for (x = 0; x < 65536; x++) {
uint16 lower, upper;
lower = (src[((x & 255) << 2)] >> cshiftr[0]) << cshiftl[0];
lower |= (src[((x & 255) << 2) + 1] >> cshiftr[1]) << cshiftl[1];
lower |= (src[((x & 255) << 2) + 2] >> cshiftr[2]) << cshiftl[2];
upper = (src[((x >> 8) << 2)] >> cshiftr[0]) << cshiftl[0];
upper |= (src[((x >> 8) << 2) + 1] >> cshiftr[1]) << cshiftl[1];
upper |= (src[((x >> 8) << 2) + 2] >> cshiftr[2]) << cshiftl[2];
palettetranslate[x] = lower | (upper << 16);
}
break;
case 3:
case 4:
for (x = 0; x < 256; x++) {
uint32 r, g, b;
if (!(highefx & FVB_BLUR)) {
r = src[x << 2];
g = src[(x << 2) + 1];
b = src[(x << 2) + 2];
palettetranslate[x] = (r << cshiftl[0]) | (g << cshiftl[1]) | (b << cshiftl[2]);
} else
for (y = 0; y < 256; y++) {
r = src[x << 2] * (100 - BLUR_RED);
g = src[(x << 2) + 1] * (100 - BLUR_GREEN);
b = src[(x << 2) + 2] * (100 - BLUR_BLUE);
r += src[y << 2] * BLUR_RED;
g += src[(y << 2) + 1] * BLUR_GREEN;
b += src[(y << 2) + 2] * BLUR_BLUE;
r /= 100;
g /= 100;
b /= 100;
if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
palettetranslate[x | (y << 8)] = (r << cshiftl[0]) | (g << cshiftl[1]) | (b << cshiftl[2]);
}
}
break;
}
}
static void Blit32to24(uint32 *src, uint8 *dest, int xr, int yr, int dpitch) {
int x, y;
for (y = yr; y; y--) {
for (x = xr; x; x--) {
uint32 tmp = *src;
*dest = tmp;
dest++;
*dest = tmp >> 8;
dest++;
*dest = tmp >> 16;
dest++;
src++;
}
dest += dpitch / 3 - xr;
}
}
static void Blit32to16(uint32 *src, uint16 *dest, int xr, int yr, int dpitch,
int shiftr[3], int shiftl[3]) {
int x, y;
//printf("%d\n",shiftl[1]);
for (y = yr; y; y--) {
for (x = xr; x; x--) {
uint32 tmp = *src;
uint16 dtmp;
// Begin iffy code
//dtmp = (tmp & backmask[2]) >> shiftr[2];
//dtmp |= (tmp & backmask[1]) >> shiftr[1];
//dtmp |= (tmp & backmask[0]) >> shiftr[0];
// End iffy code
// Begin non-iffy code
dtmp = ((tmp & 0x0000FF) >> shiftr[2]) << shiftl[2];
dtmp |= ((tmp & 0x00FF00) >> shiftr[1]) << shiftl[1];
dtmp |= ((tmp & 0xFF0000) >> shiftr[0]) << shiftl[0];
// End non-iffy code
//dtmp = ((tmp&0x0000FF) >> 3);
//dtmp |= ((tmp&0x00FC00) >>5);
//dtmp |= ((tmp&0xF80000) >>8);
*dest = dtmp;
src++;
dest++;
}
dest += dpitch / 2 - xr;
}
}
void Blit8To8(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale, int yscale, int efx, int special) {
int x, y;
int pinc;
if (special == 2) {
if (xscale != 2 || yscale != 2) return;
scale(2, dest, pitch, src, 256, 1, xr, yr);
return;
}
if (special == 4) {
if (xscale != 3 || yscale != 3) return;
scale(3, dest, pitch, src, 256, 1, xr, yr);
return;
}
pinc = pitch - (xr * xscale);
if (xscale != 1 || yscale != 1) {
if (efx & FVB_SCANLINES) {
for (y = yr; y; y--, src += 256 - xr) {
int doo = yscale - (yscale >> 1);
do {
for (x = xr; x; x--, src++) {
int too = xscale;
do {
*(uint8*)dest = *(uint8*)src;
dest++;
} while (--too);
}
src -= xr;
dest += pinc;
} while (--doo);
//src-=xr*(yscale-(yscale>>1));
dest += pitch * (yscale >> 1);
src += xr;
}
} else {
for (y = yr; y; y--, src += 256 - xr) {
int doo = yscale;
do {
for (x = xr; x; x--, src++) {
int too = xscale;
do {
*(uint8*)dest = *(uint8*)src;
dest++;
} while (--too);
}
src -= xr;
dest += pinc;
} while (--doo);
src += xr;
}
}
} else {
for (y = yr; y; y--, dest += pinc, src += 256 - xr)
for (x = xr; x; x -= 4, dest += 4, src += 4)
*(uint32*)dest = *(uint32*)src;
}
}
/* Todo: Make sure 24bpp code works right with big-endian cpus */
void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch,
int xscale, int yscale) {
int x, y;
int pinc;
uint8 *destbackup = NULL; /* For hq2x */
int pitchbackup = 0;
//static int google=0;
//google^=1;
if (specbuf8bpp) { // 2xscale/3xscale
int mult;
int base;
if (silt == 2) mult = 2;
else mult = 3;
Blit8To8(src, specbuf8bpp, xr, yr, 256 * mult, xscale, yscale, 0, silt);
xr *= mult;
yr *= mult;
xscale = yscale = 1;
src = specbuf8bpp;
base = 256 * mult;
switch (Bpp) {
case 4:
pinc = pitch - (xr << 2);
for (y = yr; y; y--, src += base - xr) {
for (x = xr; x; x--) {
*(uint32*)dest = palettetranslate[(uint32) * src];
dest += 4;
src++;
}
dest += pinc;
}
break;
case 3:
pinc = pitch - (xr + xr + xr);
for (y = yr; y; y--, src += base - xr) {
for (x = xr; x; x--) {
uint32 tmp = palettetranslate[(uint32) * src];
*(uint8*)dest = tmp;
*((uint8*)dest + 1) = tmp >> 8;
*((uint8*)dest + 2) = tmp >> 16;
dest += 3;
src++;
src++;
}
dest += pinc;
}
break;
case 2:
pinc = pitch - (xr << 1);
for (y = yr; y; y--, src += base - xr) {
for (x = xr >> 1; x; x--) {
*(uint32*)dest = palettetranslate[*(uint16*)src];
dest += 4;
src += 2;
}
dest += pinc;
}
break;
}
return;
} else if (specbuf) {
destbackup = dest;
dest = (uint8*)specbuf;
pitchbackup = pitch;
pitch = xr * sizeof(uint16);
xscale = 1;
yscale = 1;
}
if (highefx & FVB_BLUR) { // DONE
if (xscale != 1 || yscale != 1 || (highefx & FVB_SCANLINES)) { // DONE
switch (Bpp) {
case 4:
pinc = pitch - ((xr * xscale) << 2);
for (y = yr; y; y--, src += 256 - xr) {
int doo = yscale;
if (highefx & FVB_SCANLINES)
doo -= yscale >> 1;
do {
uint8 last = 0x00;
//if(doo == 1 && google) dest+=4;
for (x = xr; x; x--, src++) {
int too = xscale;
do {
*(uint32*)dest = palettetranslate[*src | (last << 8)];
dest += 4;
} while (--too);
last = *src;
}
//if(doo == 1 && google) dest-=4;
src -= xr;
dest += pinc;
} while (--doo);
src += xr;
if (highefx & FVB_SCANLINES)
dest += pitch * (yscale >> 1);
}
break;
case 3:
pinc = pitch - ((xr * xscale) * 3);
for (y = yr; y; y--, src += 256 - xr) {
int doo = yscale;
if (highefx & FVB_SCANLINES)
doo -= yscale >> 1;
do {
uint8 last = 0x00;
for (x = xr; x; x--, src++) {
int too = xscale;
do {
*(uint32*)dest = palettetranslate[*src | (last << 8)];
dest += 3;
} while (--too);
last = *src;
}
src -= xr;
dest += pinc;
} while (--doo);
src += xr;
if (highefx & FVB_SCANLINES)
dest += pitch * (yscale >> 1);
}
break;
case 2:
pinc = pitch - ((xr * xscale) << 1);
for (y = yr; y; y--, src += 256 - xr) {
int doo = yscale;
if (highefx & FVB_SCANLINES)
doo -= yscale >> 1;
do {
uint8 last = 0x00;
for (x = xr; x; x--, src++) {
int too = xscale;
do {
*(uint16*)dest = palettetranslate[*src | (last << 8)];
dest += 2;
} while (--too);
last = *src;
}
src -= xr;
dest += pinc;
} while (--doo);
src += xr;
if (highefx & FVB_SCANLINES)
dest += pitch * (yscale >> 1);
}
break;
}
} else // No scaling, no scanlines, just blurring. - DONE
switch (Bpp) {
case 4:
pinc = pitch - (xr << 2);
for (y = yr; y; y--, src += 256 - xr) {
uint8 last = 0x00;
for (x = xr; x; x--) {
*(uint32*)dest = palettetranslate[*src | (last << 8)];
last = *src;
dest += 4;
src++;
}
dest += pinc;
}
break;
case 3:
pinc = pitch - (xr + xr + xr);
for (y = yr; y; y--, src += 256 - xr) {
uint8 last = 0x00;
for (x = xr; x; x--) {
uint32 tmp = palettetranslate[*src | (last << 8)];
last = *src;
*(uint8*)dest = tmp;
*((uint8*)dest + 1) = tmp >> 8;
*((uint8*)dest + 2) = tmp >> 16;
dest += 3;
src++;
}
dest += pinc;
}
break;
case 2:
pinc = pitch - (xr << 1);
for (y = yr; y; y--, src += 256 - xr) {
uint8 last = 0x00;
for (x = xr; x; x--) {
*(uint16*)dest = palettetranslate[*src | (last << 8)];
last = *src;
dest += 2;
src++;
}
dest += pinc;
}
break;
}
} else { // No blur effects.
if (xscale != 1 || yscale != 1 || (highefx & FVB_SCANLINES)) {
switch (Bpp) {
case 4:
pinc = pitch - ((xr * xscale) << 2);
for (y = yr; y; y--, src += 256 - xr) {
int doo = yscale;
if (highefx & FVB_SCANLINES)
doo -= yscale >> 1;
do {
for (x = xr; x; x--, src++) {
int too = xscale;
do {
*(uint32*)dest = palettetranslate[*src];
dest += 4;
} while (--too);
}
src -= xr;
dest += pinc;
} while (--doo);
src += xr;
if (highefx & FVB_SCANLINES)
dest += pitch * (yscale >> 1);
}
break;
case 3:
pinc = pitch - ((xr * xscale) * 3);
for (y = yr; y; y--, src += 256 - xr) {
int doo = yscale;
if (highefx & FVB_SCANLINES)
doo -= yscale >> 1;
do {
for (x = xr; x; x--, src++) {
int too = xscale;
do {
uint32 tmp = palettetranslate[(uint32) * src];
*(uint8*)dest = tmp;
*((uint8*)dest + 1) = tmp >> 8;
*((uint8*)dest + 2) = tmp >> 16;
dest += 3;
//*(uint32 *)dest=palettetranslate[*src];
//dest+=4;
} while (--too);
}
src -= xr;
dest += pinc;
} while (--doo);
src += xr;
if (highefx & FVB_SCANLINES)
dest += pitch * (yscale >> 1);
}
break;
case 2:
pinc = pitch - ((xr * xscale) << 1);
for (y = yr; y; y--, src += 256 - xr) {
int doo = yscale;
if (highefx & FVB_SCANLINES)
doo -= yscale >> 1;
do {
for (x = xr; x; x--, src++) {
int too = xscale;
do {
*(uint16*)dest = palettetranslate[*src];
dest += 2;
} while (--too);
}
src -= xr;
dest += pinc;
} while (--doo);
src += xr;
if (highefx & FVB_SCANLINES)
dest += pitch * (yscale >> 1);
}
break;
}
} else
switch (Bpp) {
case 4:
pinc = pitch - (xr << 2);
for (y = yr; y; y--, src += 256 - xr) {
for (x = xr; x; x--) {
*(uint32*)dest = palettetranslate[(uint32) * src];
dest += 4;
src++;
}
dest += pinc;
}
break;
case 3:
pinc = pitch - (xr + xr + xr);
for (y = yr; y; y--, src += 256 - xr) {
for (x = xr; x; x--) {
uint32 tmp = palettetranslate[(uint32) * src];
*(uint8*)dest = tmp;
*((uint8*)dest + 1) = tmp >> 8;
*((uint8*)dest + 2) = tmp >> 16;
dest += 3;
src++;
}
dest += pinc;
}
break;
case 2:
pinc = pitch - (xr << 1);
for (y = yr; y; y--, src += 256 - xr) {
for (x = xr >> 1; x; x--) {
*(uint32*)dest = palettetranslate[*(uint16*)src];
dest += 4;
src += 2;
}
dest += pinc;
}
break;
}
}
if (specbuf) {
if (specbuf32bpp) {
int mult = (silt == 3) ? 3 : 2;
if (silt == 3)
hq3x_32((uint8*)specbuf, (uint8*)specbuf32bpp, xr, yr, xr * 3 * sizeof(uint32));
else
hq2x_32((uint8*)specbuf, (uint8*)specbuf32bpp, xr, yr, xr * 2 * sizeof(uint32));
if (backBpp == 2)
Blit32to16(specbuf32bpp, (uint16*)destbackup, xr * mult, yr * mult, pitchbackup, backshiftr, backshiftl);
else// == 3
Blit32to24(specbuf32bpp, (uint8*)destbackup, xr * mult, yr * mult, pitchbackup);
} else {
if (silt == 3)
hq3x_32((uint8*)specbuf, destbackup, xr, yr, pitchbackup);
else
hq2x_32((uint8*)specbuf, destbackup, xr, yr, pitchbackup);
}
}
}

View File

@@ -0,0 +1,25 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
int InitBlitToHigh(int b, uint32 rmask, uint32 gmask, uint32 bmask, int eefx, int specfilt);
void SetPaletteBlitToHigh(uint8 *src);
void KillBlitToHigh(void);
void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale, int yscale);
void Blit8To8(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale, int yscale, int efx, int special);