Update to SDL key mappings and to mouse click-the-same-spot-mode radius
This commit is contained in:
@@ -216,7 +216,7 @@ fi
|
||||
|
||||
if [ -z "$ForceRelativeMouseMode" -o -z "$AUTO" ]; then
|
||||
echo
|
||||
echo -n "Force relative (laptop) mouse movement mode, if both on-screen keyboard and mouse are needed (y) or (n) ($ForceRelativeMouseMode): "
|
||||
echo -n "Force relative (laptop) mouse movement mode, useful when both on-screen keyboard and mouse are needed (y) or (n) ($ForceRelativeMouseMode): "
|
||||
read var
|
||||
if [ -n "$var" ] ; then
|
||||
ForceRelativeMouseMode="$var"
|
||||
@@ -308,7 +308,7 @@ echo "Redefine common keys to SDL keysyms"
|
||||
echo "MENU and BACK hardware keys and TOUCHSCREEN virtual 'key' are available on all devices, other keys may be absent"
|
||||
echo "SEARCH and CALL by default return same keycode as DPAD_CENTER - one of those keys is available on most devices"
|
||||
echo "Use word NO_REMAP if you want to preserve native functionality for certain key "
|
||||
echo "TOUCHSCREEN DPAD_CENTER VOLUMEUP VOLUMEDOWN MENU BACK CAMERA ENTER DEL SEARCH CALL - Java keycodes"
|
||||
echo "TOUCHSCREEN DPAD_CENTER/SEARCH VOLUMEUP VOLUMEDOWN MENU BACK CAMERA - Java keycodes"
|
||||
echo "$RedefinedKeys - current SDL keycodes"
|
||||
echo -n ": "
|
||||
read var
|
||||
|
||||
14
bugs.txt
14
bugs.txt
@@ -16,19 +16,10 @@ Requested features
|
||||
|
||||
- Split Settings.java into several files
|
||||
|
||||
- Option to skip startup config screen entirely, or to skip it on first run,
|
||||
separate option to hide each SDL config menu entry
|
||||
|
||||
- Possibility to redefine initial SDL config in Settings.java
|
||||
|
||||
- Show/hide screen controls with longpress on Text Edit button.
|
||||
|
||||
- There's no double-buffered SW mode, only single-buffered
|
||||
|
||||
- Support of libjnigraphics (it will disable on-screen keyboard, only SW SDL screen surface supported)
|
||||
|
||||
- Update screen keyboard text input API
|
||||
|
||||
- Floating on-screen joystick - initially invisible, it appears when you touch the screen,
|
||||
centered on your finger, then it slides with your finger if you bump the joystick edge.
|
||||
|
||||
@@ -36,8 +27,6 @@ Requested features
|
||||
|
||||
- Control screen brightness with SDL_SetGamma()
|
||||
|
||||
- Adjust Android media volume with some SDL keycode, so it can be mapped to Volume keys
|
||||
|
||||
- Zoom in-out whole screen in SW mode with some SDL key -
|
||||
much like the "On-screen magnifying glass" feature (lazy porter's golden hammer)
|
||||
|
||||
@@ -56,6 +45,3 @@ Requested features
|
||||
plus VideoView will contain some buffer to ensure the playback is smooth,
|
||||
so the data on your TV will lag halfsecond behind the data on the device screen.
|
||||
|
||||
- Somehow make this port into main libSDL repository - that's rather impossible,
|
||||
because the original sources are modified badly, plus Java code does not fit anywhere.
|
||||
|
||||
|
||||
9
build.sh
9
build.sh
@@ -6,7 +6,8 @@ NDKBUILDPATH=$PATH
|
||||
export `grep "AppFullName=" AndroidAppSettings.cfg`
|
||||
if ( grep "package $AppFullName;" project/src/Globals.java > /dev/null && \
|
||||
[ "`readlink AndroidAppSettings.cfg`" -ot "project/src/Globals.java" ] && \
|
||||
[ -z "`find project/java/* -cnewer project/src/Globals.java`" ] ) ; then true ; else
|
||||
[ -z "`find project/java/* -cnewer project/src/Globals.java`" ] && \
|
||||
[ -z "`find project/jni/application/src/AndroidData/* -cnewer project/src/Globals.java`" ] ) ; then true ; else
|
||||
./ChangeAppSettings.sh -a
|
||||
sleep 1
|
||||
touch project/src/Globals.java
|
||||
@@ -32,6 +33,6 @@ cd project && env PATH=$NDKBUILDPATH nice -n19 ndk-build -j4 V=1 && \
|
||||
cp jni/application/src/libapplication.so libs/armeabi && \
|
||||
`which ndk-build | sed 's@/ndk-build@@'`/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$MYARCH/bin/arm-linux-androideabi-strip --strip-unneeded libs/armeabi/libapplication.so \
|
||||
|| true ; } && \
|
||||
ant debug && \
|
||||
test -z "$1" && cd bin && adb uninstall `grep AppFullName ../../AndroidAppSettings.cfg | sed 's/.*=//'` && \
|
||||
adb install -r DemoActivity-debug.apk
|
||||
ant debug # && \
|
||||
# test -z "$1" && cd bin && adb uninstall `grep AppFullName ../../AndroidAppSettings.cfg | sed 's/.*=//'` && \
|
||||
# adb install -r DemoActivity-debug.apk
|
||||
|
||||
@@ -10,7 +10,7 @@ VideoDepthBpp=16
|
||||
NeedDepthBuffer=n
|
||||
NeedStencilBuffer=n
|
||||
NeedGles2=n
|
||||
SwVideoMode=y
|
||||
SwVideoMode=n
|
||||
SdlVideoResize=y
|
||||
SdlVideoResizeKeepAspect=n
|
||||
CompatibilityHacks=n
|
||||
|
||||
Binary file not shown.
@@ -19,7 +19,51 @@
|
||||
#include "SDL.h"
|
||||
#include "SDL_image.h"
|
||||
|
||||
#include "ballfield.h"
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Definitions...
|
||||
----------------------------------------------------------*/
|
||||
|
||||
#define BALLS 3000
|
||||
|
||||
#define COLORS 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Sint32 x, y, z; /* Position */
|
||||
Uint32 c; /* Color */
|
||||
} point_t;
|
||||
|
||||
|
||||
/*
|
||||
* Ballfield
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
point_t points[BALLS];
|
||||
SDL_Rect *frames;
|
||||
SDL_Surface *gfx[COLORS];
|
||||
int use_alpha;
|
||||
} ballfield_t;
|
||||
|
||||
|
||||
/*
|
||||
* Size of the screen in pixels
|
||||
*/
|
||||
#define SCREEN_W 800
|
||||
#define SCREEN_H 480
|
||||
|
||||
/*
|
||||
* Size of the biggest ball image in pixels
|
||||
*
|
||||
* Balls are scaled down and *packed*, one pixel
|
||||
* smaller for each frame down to 1x1. The actual
|
||||
* image width is (obviously...) the same as the
|
||||
* width of the first frame.
|
||||
*/
|
||||
#define BALL_W 32
|
||||
#define BALL_H 32
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -318,6 +362,7 @@ void ballfield_render(ballfield_t *bf, SDL_Surface *screen)
|
||||
*/
|
||||
void tiled_back(SDL_Surface *back, SDL_Surface *screen, int xo, int yo)
|
||||
{
|
||||
/*
|
||||
int x, y;
|
||||
SDL_Rect r;
|
||||
if(xo < 0)
|
||||
@@ -333,6 +378,15 @@ void tiled_back(SDL_Surface *back, SDL_Surface *screen, int xo, int yo)
|
||||
r.y = y;
|
||||
SDL_BlitSurface(back, NULL, screen, &r);
|
||||
}
|
||||
*/
|
||||
SDL_Rect r;
|
||||
xo %= back->w/8;
|
||||
yo %= back->h/8;
|
||||
r.x = xo - back->w/2 + screen->w/2;
|
||||
r.y = yo - back->h/2 + screen->h/2;
|
||||
r.w = back->w;
|
||||
r.h = back->h;
|
||||
SDL_BlitSurface(back, NULL, screen, &r);
|
||||
}
|
||||
|
||||
|
||||
@@ -349,7 +403,7 @@ int main(int argc, char* argv[])
|
||||
SDL_Surface *back, *logo, *font;
|
||||
SDL_Event event;
|
||||
int bpp = 16,
|
||||
flags = SDL_DOUBLEBUF | SDL_SWSURFACE,
|
||||
flags = SDL_DOUBLEBUF | SDL_HWSURFACE,
|
||||
alpha = 1;
|
||||
int x_offs = 0, y_offs = 0;
|
||||
long tick,
|
||||
@@ -384,7 +438,7 @@ int main(int argc, char* argv[])
|
||||
bpp = atoi(&argv[i][1]);
|
||||
}
|
||||
|
||||
screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, bpp, 0 /*flags*/);
|
||||
screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, bpp, flags);
|
||||
if(!screen)
|
||||
{
|
||||
fprintf(stderr, "Failed to open screen!\n");
|
||||
@@ -417,7 +471,7 @@ int main(int argc, char* argv[])
|
||||
/*
|
||||
* Load background image
|
||||
*/
|
||||
temp_image = IMG_Load("redbluestars.png");
|
||||
temp_image = IMG_Load("sun.gif");
|
||||
if(!temp_image)
|
||||
{
|
||||
fprintf(stderr, "Could not load background!\n");
|
||||
@@ -435,7 +489,7 @@ int main(int argc, char* argv[])
|
||||
fprintf(stderr, "Could not load logo!\n");
|
||||
exit(-1);
|
||||
}
|
||||
SDL_SetColorKey(temp_image, SDL_SRCCOLORKEY|SDL_RLEACCEL,
|
||||
SDL_SetColorKey(temp_image, SDL_SRCCOLORKEY,
|
||||
SDL_MapRGB(temp_image->format, 255, 0, 255));
|
||||
logo = SDL_DisplayFormat(temp_image);
|
||||
SDL_FreeSurface(temp_image);
|
||||
@@ -449,7 +503,7 @@ int main(int argc, char* argv[])
|
||||
fprintf(stderr, "Could not load font!\n");
|
||||
exit(-1);
|
||||
}
|
||||
SDL_SetColorKey(temp_image, SDL_SRCCOLORKEY|SDL_RLEACCEL,
|
||||
SDL_SetColorKey(temp_image, SDL_SRCCOLORKEY,
|
||||
SDL_MapRGB(temp_image->format, 255, 0, 255));
|
||||
font = SDL_DisplayFormat(temp_image);
|
||||
SDL_FreeSurface(temp_image);
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* "Ballfield"
|
||||
*
|
||||
* (C) David Olofson <david@olofson.net>, 2002
|
||||
*
|
||||
* This software is released under the terms of the GPL.
|
||||
*
|
||||
* Contact author for permission if you want to use this
|
||||
* software, or work derived from it, under other terms.
|
||||
*/
|
||||
|
||||
#ifndef _BALLFIELD_H_
|
||||
#define _BALLFIELD_H_
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
/*----------------------------------------------------------
|
||||
Definitions...
|
||||
----------------------------------------------------------*/
|
||||
|
||||
#define BALLS 200
|
||||
|
||||
#define COLORS 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Sint32 x, y, z; /* Position */
|
||||
Uint32 c; /* Color */
|
||||
} point_t;
|
||||
|
||||
|
||||
/*
|
||||
* Ballfield
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
point_t points[BALLS];
|
||||
SDL_Rect *frames;
|
||||
SDL_Surface *gfx[COLORS];
|
||||
int use_alpha;
|
||||
} ballfield_t;
|
||||
|
||||
|
||||
/*
|
||||
* Size of the screen in pixels
|
||||
*/
|
||||
#define SCREEN_W 320
|
||||
#define SCREEN_H 240
|
||||
|
||||
/*
|
||||
* Size of the biggest ball image in pixels
|
||||
*
|
||||
* Balls are scaled down and *packed*, one pixel
|
||||
* smaller for each frame down to 1x1. The actual
|
||||
* image width is (obviously...) the same as the
|
||||
* width of the first frame.
|
||||
*/
|
||||
#define BALL_W 32
|
||||
#define BALL_H 32
|
||||
|
||||
#endif /* _BALLFIELD_H_ */
|
||||
@@ -31,8 +31,8 @@ StartupMenuButtonTimeout=3000
|
||||
HiddenMenuOptions='KeyboardConfigMainMenu ScreenKeyboardThemeConfig ScreenKeyboardTransparencyConfig'
|
||||
FirstStartMenuOptions=''
|
||||
MultiABI=n
|
||||
AppVersionCode=250517
|
||||
AppVersionName="2505.17"
|
||||
AppVersionCode=252517
|
||||
AppVersionName="2525.17"
|
||||
CompiledLibraries="sdl_net sdl_mixer sdl_image sdl_ttf png intl"
|
||||
CustomBuildScript=n
|
||||
AppCflags='-finline-functions -O2 -DWITH_ZLIB -DWITH_MIXER -DWITH_XML -DWITH_IMAGE -DWITH_TTF -DWITH_AI=simple -DWITH_NET'
|
||||
|
||||
Binary file not shown.
@@ -1,16 +1,22 @@
|
||||
# The application settings for Android libSDL port
|
||||
AppSettingVersion=16
|
||||
AppSettingVersion=17
|
||||
LibSdlVersion=1.2
|
||||
AppName="Ur-Quan Masters"
|
||||
AppFullName=com.sourceforge.sc2
|
||||
ScreenOrientation=h
|
||||
InhibitSuspend=n
|
||||
AppDataDownloadUrl="Game data is 14 Mb|https://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/sc2-data-3.zip/download^3DO remixed music (19 Mb) - enable it in Setup->Sound Options->3DO Remixes|:addons/3domusic/3domusic.zip:https://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3domusic.zip/download^UQM music remix pack (150 Mb) - enable it in Setup->Sound Options->UQM Remixes|:addons/remix/remix.zip:https://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/remix.zip/download^3DO voice (115 Mb) - go to Setup->Sound Options and increase Voice volume from zero|:addons/3dovoice/3dovoice.zip:https://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovoice.zip/download^Russian translation|:addons/lang/shadow-content/lang.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/translations/2/russian.zip/download^Deutsch translation|:addons/lang/shadow-content/lang.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/translations/2/deutsch.zip/download^Spanish translation|:addons/lang/shadow-content/lang.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/translations/2/spanish.zip/download^Slovak translation|:addons/lang/shadow-content/lang.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/translations/2/slovak.zip/download^Finnish translation|:addons/lang/shadow-content/lang.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/translations/2/finnish.zip/download^3DO video support - after installing this pack copy all files from|https://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovideo.zip/download^your 3DO Star Control II game CD from 'duckart' dir to the SD card to dir|https://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovideo.zip/download^'app-data/com.sourceforge.sc2/addons/3dovideo', to extract files from 3DO disk use|https://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovideo.zip/download^'3DO Commander' or 'uncd-rom' apps from http://madroms.free.fr/3do/|https://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovideo.zip/download^Then from the game change 'Setup->PC/3DO compat->Cutscenes' to Movies, and restart game|https://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovideo.zip/download"
|
||||
AppDataDownloadUrl="Game data (15 Mb)|http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/sc2-data-5.zip/download^3DO remixed music (19 Mb) - enable it in Setup->Sound Options->3DO Remixes|:addons/3domusic/3domusic.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3domusic.zip/download^UQM music remix pack (150 Mb) - enable it in Setup->Sound Options->UQM Remixes|:addons/remix/remix.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/remix.zip/download^3DO voice (115 Mb) - go to Setup->Sound Options and increase Voice volume from zero|:addons/3dovoice/3dovoice.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovoice.zip/download^Russian translation|:addons/lang/shadow-content/lang.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/translations/2/russian.zip/download^Deutsch translation|:addons/lang/shadow-content/lang.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/translations/2/deutsch.zip/download^Spanish translation|:addons/lang/shadow-content/lang.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/translations/2/spanish.zip/download^Slovak translation|:addons/lang/shadow-content/lang.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/translations/2/slovak.zip/download^Finnish translation|:addons/lang/shadow-content/lang.zip:http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/translations/2/finnish.zip/download^3DO video support - after installing this pack copy all files from|http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovideo.zip/download^your 3DO Star Control II game CD from 'duckart' dir to the SD card to dir|http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovideo.zip/download^'app-data/com.sourceforge.sc2/addons/3dovideo', to extract files from 3DO disk use|http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovideo.zip/download^'3DO Commander' or 'uncd-rom' apps from http://madroms.free.fr/3do/|http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovideo.zip/download^Then from the game change 'Setup->PC/3DO compat->Cutscenes' to Movies, and restart game|http://sourceforge.net/projects/libsdl-android/files/Ur-Quan%20Masters/3dovideo.zip/download"
|
||||
VideoDepthBpp=16
|
||||
NeedDepthBuffer=n
|
||||
NeedStencilBuffer=n
|
||||
NeedGles2=n
|
||||
SwVideoMode=y
|
||||
SdlVideoResize=y
|
||||
SdlVideoResizeKeepAspect=n
|
||||
NeedDepthBuffer=n
|
||||
CompatibilityHacks=n
|
||||
AppUsesMouse=n
|
||||
AppNeedsTwoButtonMouse=n
|
||||
ForceRelativeMouseMode=n
|
||||
AppNeedsArrowKeys=y
|
||||
AppNeedsTextInput=y
|
||||
AppUsesJoystick=y
|
||||
@@ -21,14 +27,16 @@ RedefinedKeys="RETURN RSHIFT KP_PLUS KP_MINUS RCTRL F10"
|
||||
AppTouchscreenKeyboardKeysAmount=2
|
||||
AppTouchscreenKeyboardKeysAmountAutoFire=0
|
||||
RedefinedKeysScreenKb="RETURN RSHIFT KP_PLUS KP_MINUS RCTRL F10"
|
||||
StartupMenuButtonTimeout=3000
|
||||
HiddenMenuOptions=''
|
||||
FirstStartMenuOptions=''
|
||||
MultiABI=n
|
||||
AppVersionCode=06920
|
||||
AppVersionName="0.6.9.20"
|
||||
AppVersionCode=07020
|
||||
AppVersionName="0.7.0.20"
|
||||
CompiledLibraries="sdl_image tremor ogg"
|
||||
CustomBuildScript=n
|
||||
AppCflags='-O3 -DTHREADLIB_SDL=1 -DTIMELIB=SDL -DOVCODEC_TREMOR=1 -DNETPLAY=1 -DHAVE_REGEX=1 -DHAVE_GETOPT_LONG=1 -DHAVE_ZIP=1 -DHAVE_JOYSTICK=1'
|
||||
AppCflags='-O3 -DTHREADLIB_SDL=1 -DTIMELIB=SDL -DOVCODEC_TREMOR=1 -DNETPLAY=1 -DHAVE_GETOPT_LONG=1 -DHAVE_ZIP=1 -DHAVE_JOYSTICK=1'
|
||||
AppLdflags=''
|
||||
AppSubdirsBuild=''
|
||||
AppUseCrystaXToolchain=n
|
||||
AppSubdirsBuild='src src/regex src/libs/* src/uqm/*'
|
||||
AppCmdline='uqm --addon lang'
|
||||
ReadmeText='^You may press "Home" now - the data will be downloaded in background'
|
||||
|
||||
1705
project/jni/application/sc2/android.diff
Normal file
1705
project/jni/application/sc2/android.diff
Normal file
File diff suppressed because it is too large
Load Diff
1
project/jni/application/sc2/src
Symbolic link
1
project/jni/application/sc2/src
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../../sc2/sc2/src/
|
||||
@@ -1,20 +0,0 @@
|
||||
uqm_SUBDIRS="libs res uqm"
|
||||
|
||||
if [ "$uqm_HAVE_GETOPT_LONG" = 0 ]; then
|
||||
uqm_SUBDIRS="$uqm_SUBDIRS getopt"
|
||||
fi
|
||||
|
||||
case "$HOST_SYSTEM" in
|
||||
Darwin)
|
||||
uqm_SUBDIRS="$uqm_SUBDIRS darwin"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$uqm_HAVE_REGEX" = 0 ]; then
|
||||
uqm_SUBDIRS="$uqm_SUBDIRS regex"
|
||||
fi
|
||||
|
||||
uqm_CFILES="options.c port.c uqm.c"
|
||||
|
||||
test_CFILES=test.c
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/* This file contains some compile-time configuration options.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* In this case, build.sh is not run to generate a config file, so
|
||||
* we use a default file config_vc6.h instead.
|
||||
* If you want anything else than the defaults, you'll have to edit
|
||||
* that file manually. */
|
||||
# include "config_vc6.h"
|
||||
#elif defined(__SYMBIAN32__)
|
||||
# include "symbian/config.h"
|
||||
#elif defined (__MINGW32__) || defined (__CYGWIN__)
|
||||
/* If we're compiling on MS Windows using build.sh, use
|
||||
* config_win.h, generated from src/config_win.h.in. */
|
||||
# include "config_win.h"
|
||||
#else
|
||||
/* If we're compiling in unix, use config_unix.h, generated from
|
||||
* src/config_unix.h.in by build.sh. */
|
||||
# include "config_unix.h"
|
||||
#endif
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/* This file contains some compile-time configuration options for *nix
|
||||
* systems.
|
||||
* config_unix.h is generated from config_unix.h.in by build.sh
|
||||
* When building on MS Windows using build.sh (MinGW, Cygwin),
|
||||
* config_win.h is generated from src/config_win.h.in.
|
||||
* When using MSVC on MS Windows, you'll have to edit src/msvc++/config.h
|
||||
* manually if you want anything else than the defaults.
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_UNIX_H
|
||||
#define _CONFIG_UNIX_H
|
||||
|
||||
/* Directory where the UQM game data is located */
|
||||
#define CONTENTDIR ""
|
||||
|
||||
/* Directory where game data will be stored */
|
||||
#define USERDIR "config/"
|
||||
|
||||
/* Directory where config files will be stored */
|
||||
#define CONFIGDIR USERDIR
|
||||
|
||||
/* Directory where supermelee teams will be stored */
|
||||
#define MELEEDIR "teams/"
|
||||
|
||||
/* Directory where save games will be stored */
|
||||
#define SAVEDIR "save/"
|
||||
|
||||
/* Defined if words are stored with the most significant byte first */
|
||||
#ifdef __ARMEL__
|
||||
#undef WORDS_BIGENDIAN
|
||||
#endif
|
||||
|
||||
/* Defined if your system has readdir_r of its own */
|
||||
#define HAVE_READDIR_R 1
|
||||
|
||||
/* Defined if your system has setenv of its own */
|
||||
#ifndef HAVE_SETENV
|
||||
#define HAVE_SETENV 1
|
||||
#endif
|
||||
|
||||
/* Defined if your system has strupr of its own */
|
||||
#undef HAVE_STRUPR
|
||||
|
||||
/* Defined if your system has strcasecmp of its own */
|
||||
#define HAVE_STRCASECMP_UQM 1
|
||||
// Not using "HAVE_STRCASECMP" as that conflicts with SDL.
|
||||
|
||||
/* Defined if your system has stricmp of its own */
|
||||
#undef HAVE_STRICMP
|
||||
|
||||
/* Defined if your system has getopt_long */
|
||||
#define HAVE_GETOPT_LONG 1
|
||||
|
||||
/* Defined if your system has iswgraph of its own*/
|
||||
#define HAVE_ISWGRAPH 1
|
||||
|
||||
/* Defined if your system has wchar_t of its own */
|
||||
#define HAVE_WCHAR_T 1
|
||||
|
||||
/* Defined if your system has wint_t of its own */
|
||||
#define HAVE_WINT_T 1
|
||||
|
||||
/* Defined if your system has _Bool of its own */
|
||||
#define HAVE__BOOL 1
|
||||
|
||||
#endif /* _CONFIG_UNIX_H */
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/* This file contains some compile-time configuration options for *nix
|
||||
* systems.
|
||||
* config_unix.h is generated from config_unix.h.in by build.sh
|
||||
* When building on MS Windows using build.sh (MinGW, Cygwin),
|
||||
* config_win.h is generated from src/config_win.h.in.
|
||||
* When using MSVC on MS Windows, you'll have to edit src/msvc++/config.h
|
||||
* manually if you want anything else than the defaults.
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_UNIX_H
|
||||
#define _CONFIG_UNIX_H
|
||||
|
||||
/* Directory where the UQM game data is located */
|
||||
#define CONTENTDIR "@CONTENTDIR@"
|
||||
|
||||
/* Directory where game data will be stored */
|
||||
#define USERDIR "~/.uqm/"
|
||||
|
||||
/* Directory where config files will be stored */
|
||||
#define CONFIGDIR USERDIR
|
||||
|
||||
/* Directory where supermelee teams will be stored */
|
||||
#define MELEEDIR "${UQM_CONFIG_DIR}/teams/"
|
||||
|
||||
/* Directory where save games will be stored */
|
||||
#define SAVEDIR "${UQM_CONFIG_DIR}/save/"
|
||||
|
||||
/* Defined if words are stored with the most significant byte first */
|
||||
@WORDS_BIGENDIAN@
|
||||
|
||||
/* Defined if your system has readdir_r of its own */
|
||||
@HAVE_READDIR_R@
|
||||
|
||||
/* Defined if your system has setenv of its own */
|
||||
@HAVE_SETENV@
|
||||
|
||||
/* Defined if your system has strupr of its own */
|
||||
@HAVE_STRUPR@
|
||||
|
||||
/* Defined if your system has strcasecmp of its own */
|
||||
@HAVE_STRCASECMP_UQM@
|
||||
// Not using "HAVE_STRCASECMP" as that conflicts with SDL.
|
||||
|
||||
/* Defined if your system has stricmp of its own */
|
||||
@HAVE_STRICMP@
|
||||
|
||||
/* Defined if your system has getopt_long */
|
||||
@HAVE_GETOPT_LONG@
|
||||
|
||||
/* Defined if your system has iswgraph of its own*/
|
||||
@HAVE_ISWGRAPH@
|
||||
|
||||
/* Defined if your system has wchar_t of its own */
|
||||
@HAVE_WCHAR_T@
|
||||
|
||||
/* Defined if your system has wint_t of its own */
|
||||
@HAVE_WINT_T@
|
||||
|
||||
/* Defined if your system has _Bool of its own */
|
||||
@HAVE__BOOL@
|
||||
|
||||
#endif /* _CONFIG_UNIX_H */
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/* This file contains some compile-time configuration options for MS Windows
|
||||
* systems when building using MSVC.
|
||||
* Change the values below if you want anything other than the defaults.
|
||||
* For *nix systems, config_unix.h is used, which is generated by build.sh
|
||||
* from src/config_unix.h.in.
|
||||
* When building on MS Windows using build.sh (MinGW, Cygwin),
|
||||
* config_win.h is generated from src/config_win.h.in.
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
|
||||
/* Directory where the UQM game data is located */
|
||||
#define CONTENTDIR "../content/"
|
||||
|
||||
/* Directory where game data will be stored */
|
||||
//#define USERDIR "../userdata/"
|
||||
#define USERDIR "%APPDATA%/uqm/"
|
||||
|
||||
/* Directory where config files will be stored */
|
||||
#define CONFIGDIR USERDIR
|
||||
|
||||
/* Directory where supermelee teams will be stored */
|
||||
#define MELEEDIR "%UQM_CONFIG_DIR%/teams/"
|
||||
|
||||
/* Directory where save games will be stored */
|
||||
#define SAVEDIR "%UQM_CONFIG_DIR%/save/"
|
||||
|
||||
/* Define if words are stored with the most significant byte first */
|
||||
#undef WORDS_BIGENDIAN
|
||||
|
||||
/* Defined if your system has readdir_r of its own */
|
||||
#undef HAVE_READDIR_R
|
||||
|
||||
/* Defined if your system has setenv of its own */
|
||||
#undef HAVE_SETENV
|
||||
|
||||
/* Defined if your system has strupr of its own */
|
||||
#define HAVE_STRUPR
|
||||
|
||||
/* Defined if your system has strcasecmp of its own */
|
||||
#undef HAVE_STRCASECMP_UQM
|
||||
// Not using "HAVE_STRCASECMP" as that conflicts with SDL.
|
||||
|
||||
/* Defined if your system has stricmp of its own */
|
||||
#define HAVE_STRICMP
|
||||
|
||||
/* Defined if your system has getopt_long */
|
||||
#undef HAVE_GETOPT_LONG
|
||||
|
||||
/* Defined if your system has iswgraph of its own*/
|
||||
#define HAVE_ISWGRAPH
|
||||
|
||||
/* Defined if your system has wchar_t of its own */
|
||||
#define HAVE_WCHAR_T
|
||||
|
||||
/* Defined if your system has wint_t of its own */
|
||||
#define HAVE_WINT_T
|
||||
|
||||
#endif /* _CONFIG_H */
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/* This file contains some compile-time configuration options for MS Windows
|
||||
* systems when building using build.sh (MinGW, Cygwin).
|
||||
* config_win.h is generated from src/config_win.h.in by build.sh
|
||||
* For building using MSVC, you'll have to edit src/msvc++/config.h manually
|
||||
* if you want anything else than the defaults.
|
||||
* For *nix systems, config_unix.h is used, which is generated by build.sh
|
||||
* from src/config_unix.h.in.
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_WIN_H
|
||||
#define _CONFIG_WIN_H
|
||||
|
||||
/* Directory where the UQM game data is located */
|
||||
#define CONTENTDIR "../content/"
|
||||
|
||||
/* Directory where game data will be stored */
|
||||
//#define USERDIR "../userdata/"
|
||||
#define USERDIR "%APPDATA%/uqm/"
|
||||
|
||||
/* Directory where config files will be stored */
|
||||
#define CONFIGDIR USERDIR
|
||||
|
||||
/* Directory where supermelee teams will be stored */
|
||||
#define MELEEDIR "%UQM_CONFIG_DIR%/teams/"
|
||||
|
||||
/* Directory where save games will be stored */
|
||||
#define SAVEDIR "%UQM_CONFIG_DIR%/save/"
|
||||
|
||||
/* Defined if words are stored with the most significant byte first */
|
||||
@WORDS_BIGENDIAN@
|
||||
|
||||
/* Defined if your system has readdir_r of its own */
|
||||
@HAVE_READDIR_R@
|
||||
|
||||
/* Defined if your system has setenv of its own */
|
||||
@HAVE_SETENV@
|
||||
|
||||
/* Defined if your system has strupr of its own */
|
||||
@HAVE_STRUPR@
|
||||
|
||||
/* Defined if your system has strcasecmp of its own */
|
||||
@HAVE_STRCASECMP_UQM@
|
||||
// Not using "HAVE_STRCASECMP" as that conflicts with SDL.
|
||||
|
||||
/* Defined if your system has stricmp of its own */
|
||||
@HAVE_STRICMP@
|
||||
|
||||
/* Defined if your system has getopt_long */
|
||||
@HAVE_GETOPT_LONG@
|
||||
|
||||
/* Defined if your system has iswgraph of its own*/
|
||||
@HAVE_ISWGRAPH@
|
||||
|
||||
/* Defined if your system has wchar_t of its own */
|
||||
@HAVE_WCHAR_T@
|
||||
|
||||
/* Defined if your system has wint_t of its own */
|
||||
@HAVE_WINT_T@
|
||||
|
||||
/* Defined if your system has _Bool of its own */
|
||||
@HAVE__BOOL@
|
||||
|
||||
#endif /* _CONFIG_WIN_H */
|
||||
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Endian swapping, taken from SDL-1.2.5 sources and modified
|
||||
* Original copyright (C) Sam Lantinga
|
||||
*/
|
||||
|
||||
#ifndef _ENDIAN_UQM_H
|
||||
#define _ENDIAN_UQM_H
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
|
||||
#if defined (__APPLE__) && defined (__GNUC__)
|
||||
// When using the MacOS gcc compiler to build universal binaries,
|
||||
// each file will be compiled once for each platform.
|
||||
// This means that checking endianness beforehand from build.sh will not do,
|
||||
// but fortunately, gcc defines __BIG_ENDIAN__ or __LITTLE_ENDIAN__ on
|
||||
// this platform.
|
||||
# if defined(__BIG_ENDIAN__)
|
||||
# undef WORDS_BIGENDIAN
|
||||
# define WORDS_BIGENDIAN
|
||||
# elif defined(__LITTLE_ENDIAN__)
|
||||
# undef WORDS_BIGENDIAN
|
||||
# else
|
||||
// Neither __BIG_ENDIAN__ nor __LITTLE_ENDIAN__ is defined.
|
||||
// Fallback to using the build.sh defined value.
|
||||
# endif
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || \
|
||||
defined(__DMC__) || defined(__SC__) || \
|
||||
defined(__WATCOMC__) || defined(__LCC__)
|
||||
#ifndef __inline__
|
||||
#define __inline__ __inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The macros used to swap values */
|
||||
/* Try to use superfast macros on systems that support them */
|
||||
#ifdef linux
|
||||
#include <endian.h>
|
||||
#ifdef __arch__swab16
|
||||
#define UQM_Swap16 __arch__swab16
|
||||
#endif
|
||||
#ifdef __arch__swab32
|
||||
#define UQM_Swap32 __arch__swab32
|
||||
#endif
|
||||
#endif /* linux */
|
||||
/* Use inline functions for compilers that support them, and static
|
||||
functions for those that do not. Because these functions become
|
||||
static for compilers that do not support inline functions, this
|
||||
header should only be included in files that actually use them.
|
||||
*/
|
||||
#ifndef UQM_Swap16
|
||||
static __inline__ uint16 UQM_Swap16(uint16 D)
|
||||
{
|
||||
return((D<<8)|(D>>8));
|
||||
}
|
||||
#endif
|
||||
#ifndef UQM_Swap32
|
||||
static __inline__ uint32 UQM_Swap32(uint32 D)
|
||||
{
|
||||
return((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
|
||||
}
|
||||
#endif
|
||||
#ifdef UQM_INT64
|
||||
#ifndef UQM_Swap64
|
||||
static __inline__ uint64 UQM_Swap64(uint64 val)
|
||||
{
|
||||
uint32 hi, lo;
|
||||
|
||||
/* Separate into high and low 32-bit values and swap them */
|
||||
lo = (uint32)(val&0xFFFFFFFF);
|
||||
val >>= 32;
|
||||
hi = (uint32)(val&0xFFFFFFFF);
|
||||
val = UQM_Swap32(lo);
|
||||
val <<= 32;
|
||||
val |= UQM_Swap32(hi);
|
||||
return(val);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#ifndef UQM_Swap64
|
||||
/* This is mainly to keep compilers from complaining in SDL code.
|
||||
If there is no real 64-bit datatype, then compilers will complain about
|
||||
the fake 64-bit datatype that SDL provides when it compiles user code.
|
||||
*/
|
||||
#define UQM_Swap64(X) (X)
|
||||
#endif
|
||||
#endif /* UQM_INT64 */
|
||||
|
||||
|
||||
/* Byteswap item from the specified endianness to the native endianness
|
||||
* or vice versa.
|
||||
*/
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
#define UQM_SwapLE16(X) (X)
|
||||
#define UQM_SwapLE32(X) (X)
|
||||
#define UQM_SwapLE64(X) (X)
|
||||
#define UQM_SwapBE16(X) UQM_Swap16(X)
|
||||
#define UQM_SwapBE32(X) UQM_Swap32(X)
|
||||
#define UQM_SwapBE64(X) UQM_Swap64(X)
|
||||
#else
|
||||
#define UQM_SwapLE16(X) UQM_Swap16(X)
|
||||
#define UQM_SwapLE32(X) UQM_Swap32(X)
|
||||
#define UQM_SwapLE64(X) UQM_Swap64(X)
|
||||
#define UQM_SwapBE16(X) (X)
|
||||
#define UQM_SwapBE32(X) (X)
|
||||
#define UQM_SwapBE64(X) (X)
|
||||
#endif
|
||||
|
||||
#endif /* _ENDIAN_H */
|
||||
@@ -1,14 +0,0 @@
|
||||
uqm_SUBDIRS="callback decomp file graphics heap input list math memory
|
||||
resource sound strings task threads time uio video log"
|
||||
if [ -n "$uqm_USE_INTERNAL_MIKMOD" ]; then
|
||||
uqm_SUBDIRS="$uqm_SUBDIRS mikmod"
|
||||
fi
|
||||
|
||||
if [ -n "$uqm_NETPLAY" ]; then
|
||||
uqm_SUBDIRS="$uqm_SUBDIRS network"
|
||||
fi
|
||||
|
||||
#if [ "$DEBUG" = 1 ]; then
|
||||
# uqm_SUBDIRS="$UQM_SUBDIRS debug"
|
||||
#fi
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "callback/alarm.h"
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "callback/callback.h"
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
uqm_CFILES="alarm.c callback.c"
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Serge van den Boom <svdb@stack.nl>
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "alarm.h"
|
||||
|
||||
#include "libs/heap.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
Heap *alarmHeap;
|
||||
|
||||
|
||||
static inline Alarm *
|
||||
Alarm_alloc(void) {
|
||||
return malloc(sizeof (Alarm));
|
||||
}
|
||||
|
||||
static inline void
|
||||
Alarm_free(Alarm *alarm) {
|
||||
free(alarm);
|
||||
}
|
||||
|
||||
static inline int
|
||||
AlarmTime_compare(const AlarmTime t1, const AlarmTime t2) {
|
||||
if (t1 < t2)
|
||||
return -1;
|
||||
if (t2 > t2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
Alarm_compare(const Alarm *a1, const Alarm *a2) {
|
||||
return AlarmTime_compare(a1->time, a2->time);
|
||||
}
|
||||
|
||||
void
|
||||
Alarm_init(void) {
|
||||
assert(alarmHeap == NULL);
|
||||
alarmHeap = Heap_new((HeapValue_Comparator) Alarm_compare,
|
||||
4, 4, 0.8);
|
||||
}
|
||||
|
||||
void
|
||||
Alarm_uninit(void) {
|
||||
assert(alarmHeap != NULL);
|
||||
|
||||
while (Heap_hasMore(alarmHeap)) {
|
||||
Alarm *alarm = (Alarm *) Heap_pop(alarmHeap);
|
||||
Alarm_free(alarm);
|
||||
}
|
||||
Heap_delete(alarmHeap);
|
||||
alarmHeap = NULL;
|
||||
}
|
||||
|
||||
static inline AlarmTime
|
||||
AlarmTime_nowMS(void) {
|
||||
return SDL_GetTicks();
|
||||
}
|
||||
|
||||
Alarm *
|
||||
Alarm_addRelativeMs(Uint32 ms, AlarmCallback callback,
|
||||
AlarmCallbackArg arg) {
|
||||
Alarm *alarm;
|
||||
|
||||
assert(alarmHeap != NULL);
|
||||
|
||||
alarm = Alarm_alloc();
|
||||
alarm->time = AlarmTime_nowMS() + ms;
|
||||
alarm->callback = callback;
|
||||
alarm->arg = arg;
|
||||
|
||||
Heap_add(alarmHeap, (HeapValue *) alarm);
|
||||
|
||||
return alarm;
|
||||
}
|
||||
|
||||
void
|
||||
Alarm_remove(Alarm *alarm) {
|
||||
assert(alarmHeap != NULL);
|
||||
Heap_remove(alarmHeap, (HeapValue *) alarm);
|
||||
Alarm_free(alarm);
|
||||
}
|
||||
|
||||
// It is safe to call this function again from inside a callback function
|
||||
// that it called. It should not be called from multiple threads at once.
|
||||
void
|
||||
Alarm_process(void) {
|
||||
AlarmTime now;
|
||||
|
||||
assert(alarmHeap != NULL);
|
||||
|
||||
now = AlarmTime_nowMS();
|
||||
while (Heap_hasMore(alarmHeap)) {
|
||||
Alarm *alarm = (Alarm *) Heap_first(alarmHeap);
|
||||
|
||||
if (now < alarm->time)
|
||||
break;
|
||||
|
||||
Heap_pop(alarmHeap);
|
||||
alarm->callback(alarm->arg);
|
||||
Alarm_free(alarm);
|
||||
}
|
||||
}
|
||||
|
||||
Uint32
|
||||
Alarm_timeBeforeNextMs(void) {
|
||||
Alarm *alarm;
|
||||
|
||||
if (!Heap_hasMore(alarmHeap))
|
||||
return UINT32_MAX;
|
||||
|
||||
alarm = (Alarm *) Heap_first(alarmHeap);
|
||||
return alarmTimeToMsUint32(alarm->time);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Serge van den Boom <svdb@stack.nl>
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ALARM_H
|
||||
#define _ALARM_H
|
||||
|
||||
#include "port.h"
|
||||
#include "types.h"
|
||||
|
||||
#include SDL_INCLUDE(SDL.h)
|
||||
typedef Uint32 AlarmTime;
|
||||
static inline Uint32
|
||||
alarmTimeToMsUint32(AlarmTime time) {
|
||||
return (Uint32) time;
|
||||
}
|
||||
|
||||
typedef struct Alarm Alarm;
|
||||
typedef void *AlarmCallbackArg;
|
||||
typedef void (*AlarmCallback)(AlarmCallbackArg arg);
|
||||
|
||||
struct Alarm {
|
||||
size_t index;
|
||||
// For the HeapValue 'base struct'.
|
||||
|
||||
AlarmTime time;
|
||||
AlarmCallback callback;
|
||||
AlarmCallbackArg arg;
|
||||
};
|
||||
|
||||
void Alarm_init(void);
|
||||
void Alarm_uninit(void);
|
||||
Alarm *Alarm_addRelativeMs(Uint32 ms, AlarmCallback callback,
|
||||
AlarmCallbackArg arg);
|
||||
void Alarm_remove(Alarm *alarm);
|
||||
void Alarm_process(void);
|
||||
Uint32 Alarm_timeBeforeNextMs(void);
|
||||
|
||||
#endif /* _ALARM_H */
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Serge van den Boom <svdb@stack.nl>
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct CallbackLink CallbackLink;
|
||||
|
||||
#define CALLBACK_INTERNAL
|
||||
#include "callback.h"
|
||||
|
||||
struct CallbackLink {
|
||||
CallbackLink *next;
|
||||
CallbackFunction callback;
|
||||
CallbackArg arg;
|
||||
};
|
||||
|
||||
static CallbackLink *callbacks;
|
||||
static CallbackLink **callbacksEnd;
|
||||
static CallbackLink *const *callbacksProcessEnd;
|
||||
|
||||
static inline void
|
||||
CallbackList_lock(void) {
|
||||
// TODO
|
||||
// Necessary for reentrant operation
|
||||
}
|
||||
|
||||
static inline void
|
||||
CallbackList_unlock(void) {
|
||||
// TODO
|
||||
// Necessary for reentrant operation
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline bool
|
||||
CallbackList_isLocked(void) {
|
||||
// TODO
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
Callback_init(void) {
|
||||
callbacks = NULL;
|
||||
callbacksEnd = &callbacks;
|
||||
callbacksProcessEnd = &callbacks;
|
||||
}
|
||||
|
||||
// Callbacks are guaranteed to be called in the order that they are queued.
|
||||
CallbackID
|
||||
Callback_add(CallbackFunction callback, CallbackArg arg) {
|
||||
CallbackLink *link = malloc(sizeof (CallbackLink));
|
||||
link->callback = callback;
|
||||
link->arg = arg;
|
||||
link->next = NULL;
|
||||
|
||||
CallbackList_lock();
|
||||
*callbacksEnd = link;
|
||||
callbacksEnd = &link->next;
|
||||
CallbackList_unlock();
|
||||
return (CallbackID) link;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
CallbackLink_delete(CallbackLink *link) {
|
||||
free(link);
|
||||
}
|
||||
|
||||
// Pre: CallbackList is locked.
|
||||
static CallbackLink **
|
||||
CallbackLink_find(CallbackLink *link) {
|
||||
CallbackLink **ptr;
|
||||
|
||||
//assert(CallbackList_isLocked());
|
||||
for (ptr = &callbacks; *ptr != NULL; ptr = &(*ptr)->next) {
|
||||
if (*ptr == link)
|
||||
return ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
Callback_remove(CallbackID id) {
|
||||
CallbackLink *link = (CallbackLink *) id;
|
||||
CallbackLink **linkPtr;
|
||||
|
||||
CallbackList_lock();
|
||||
|
||||
linkPtr = CallbackLink_find(link);
|
||||
if (linkPtr == NULL) {
|
||||
CallbackList_unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (callbacksEnd == &(*linkPtr)->next)
|
||||
callbacksEnd = linkPtr;
|
||||
if (callbacksProcessEnd == &(*linkPtr)->next)
|
||||
callbacksProcessEnd = linkPtr;
|
||||
*linkPtr = (*linkPtr)->next;
|
||||
|
||||
CallbackList_unlock();
|
||||
|
||||
CallbackLink_delete(link);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
CallbackLink_doCallback(CallbackLink *link) {
|
||||
(link->callback)(link->arg);
|
||||
}
|
||||
|
||||
// Call all queued callbacks currently in the queue. Callbacks queued
|
||||
// from inside the called functions will not be processed until the next
|
||||
// call of Callback_process().
|
||||
// It is allowed to remove callbacks from inside the called functions.
|
||||
// NB: Callback_process() must never be called from more than one thread
|
||||
// at the same time. It's the only sensible way to ensure that the
|
||||
// callbacks are called in the order in which they were queued.
|
||||
// It is however allowed to call Callback_process() from inside the
|
||||
// callback function called by Callback_process() itself.
|
||||
void
|
||||
Callback_process(void) {
|
||||
CallbackLink *link;
|
||||
|
||||
// We set 'callbacksProcessEnd' to callbacksEnd. Callbacks added
|
||||
// from inside a callback function will be placed after
|
||||
// callbacksProcessEnd, and will hence not be processed this
|
||||
// call of Callback_process().
|
||||
CallbackList_lock();
|
||||
callbacksProcessEnd = callbacksEnd;
|
||||
CallbackList_unlock();
|
||||
|
||||
for (;;) {
|
||||
CallbackList_lock();
|
||||
if (callbacksProcessEnd == &callbacks) {
|
||||
CallbackList_unlock();
|
||||
break;
|
||||
}
|
||||
assert(callbacks != NULL);
|
||||
// If callbacks == NULL, then callbacksProcessEnd == &callbacks
|
||||
link = callbacks;
|
||||
callbacks = link->next;
|
||||
if (callbacksEnd == &link->next)
|
||||
callbacksEnd = &callbacks;
|
||||
if (callbacksProcessEnd == &link->next)
|
||||
callbacksProcessEnd = &callbacks;
|
||||
CallbackList_unlock();
|
||||
|
||||
CallbackLink_doCallback(link);
|
||||
CallbackLink_delete(link);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Serge van den Boom <svdb@stack.nl>
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _CALLBACK_H
|
||||
#define _CALLBACK_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#ifdef CALLBACK_INTERNAL
|
||||
typedef CallbackLink *CallbackID;
|
||||
#else
|
||||
typedef void *CallbackID;
|
||||
// Uniquely identifies a queued callback.
|
||||
#endif
|
||||
#define CallbackID_invalid ((CallbackID ) NULL)
|
||||
|
||||
typedef void *CallbackArg;
|
||||
typedef void (*CallbackFunction)(CallbackArg arg);
|
||||
|
||||
void Callback_init(void);
|
||||
CallbackID Callback_add(CallbackFunction callback, CallbackArg arg);
|
||||
bool Callback_remove(CallbackID id);
|
||||
void Callback_process(void);
|
||||
|
||||
#endif /* _CALLBACK_H */
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
* Nota bene: later versions of the GNU General Public License do not apply
|
||||
* to this program.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CDPLIB_H
|
||||
#define _CDPLIB_H
|
||||
|
||||
#include "cdp/cdp.h"
|
||||
|
||||
#endif /* _CDPLIB_H */
|
||||
@@ -1,89 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _COMPILER_H
|
||||
#define _COMPILER_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef uint8 BYTE;
|
||||
typedef uint8 UBYTE;
|
||||
typedef sint8 SBYTE;
|
||||
typedef uint16 UWORD;
|
||||
typedef sint16 SWORD;
|
||||
typedef uint32 DWORD;
|
||||
typedef sint32 SDWORD;
|
||||
|
||||
typedef UWORD COUNT;
|
||||
typedef SWORD SIZE;
|
||||
|
||||
typedef char UNICODE;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FALSE = 0,
|
||||
TRUE
|
||||
} BOOLEAN;
|
||||
|
||||
typedef void (*PVOIDFUNC) (void);
|
||||
typedef BOOLEAN (*PBOOLFUNC) (void);
|
||||
typedef BYTE (*PBYTEFUNC) (void);
|
||||
typedef UWORD (*PUWORDFUNC) (void);
|
||||
typedef SWORD (*PSWORDFUNC) (void);
|
||||
typedef DWORD (*PDWORDFUNC) (void);
|
||||
|
||||
#define MAKE_BYTE(lo, hi) ((BYTE) (((BYTE) (hi) << (BYTE) 4) | (BYTE) (lo)))
|
||||
#define LONIBBLE(x) ((BYTE) ((BYTE) (x) & (BYTE) 0x0F))
|
||||
#define HINIBBLE(x) ((BYTE) ((BYTE) (x) >> (BYTE) 4))
|
||||
#define MAKE_WORD(lo, hi) ((UWORD) ((BYTE) (hi) << 8) | (BYTE) (lo))
|
||||
#define LOBYTE(x) ((BYTE) ((UWORD) (x)))
|
||||
#define HIBYTE(x) ((BYTE) ((UWORD) (x) >> 8))
|
||||
#define MAKE_DWORD(lo, hi) (((DWORD) (hi) << 16) | (UWORD) (lo))
|
||||
#define LOWORD(x) ((UWORD) ((DWORD) (x)))
|
||||
#define HIWORD(x) ((UWORD) ((DWORD) (x) >> 16))
|
||||
|
||||
|
||||
// To be moved to port.h:
|
||||
// _ALIGNED_ANY specifies an alignment suitable for any type
|
||||
// _ALIGNED_ON specifies a caller-supplied alignment (should be a power of 2)
|
||||
#if defined(__GNUC__)
|
||||
# define _PACKED __attribute__((packed))
|
||||
# define _ALIGNED_ANY __attribute__((aligned))
|
||||
# define _ALIGNED_ON(bytes) __attribute__((aligned(bytes)))
|
||||
#elif defined(_MSC_VER)
|
||||
# define _ALIGNED_ANY
|
||||
//# define _ALIGNED_ON(bytes) __declspec(align(bytes))
|
||||
// __declspec(align(bytes)) expects a constant. 'sizeof (type)'
|
||||
// will not do. This is something that needs some attention,
|
||||
// once we find someone with a 64 bits Windows machine.
|
||||
// Leaving it alone for now.
|
||||
# define _PACKED
|
||||
# define _ALIGNED_ON(bytes)
|
||||
#elif defined(__ARMCC__)
|
||||
# define _PACKED __attribute__((packed))
|
||||
# define _ALIGNED_ANY __attribute__((aligned))
|
||||
# define _ALIGNED_ON(bytes) __attribute__((aligned(bytes)))
|
||||
#elif defined(__WINSCW__)
|
||||
# define _PACKED
|
||||
# define _ALIGNED_ANY
|
||||
# define _ALIGNED_ON(bytes)
|
||||
#endif
|
||||
|
||||
#endif /* _COMPILER_H */
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DECLIB_H
|
||||
#define _DECLIB_H
|
||||
|
||||
#include "libs/compiler.h"
|
||||
typedef struct _LZHCODE_DESC* DECODE_REF;
|
||||
|
||||
enum
|
||||
{
|
||||
FILE_STREAM = 0,
|
||||
MEMORY_STREAM
|
||||
};
|
||||
typedef BYTE STREAM_TYPE;
|
||||
|
||||
enum
|
||||
{
|
||||
STREAM_READ = 0,
|
||||
STREAM_WRITE
|
||||
};
|
||||
typedef BYTE STREAM_MODE;
|
||||
|
||||
extern DECODE_REF copen (void *InStream, STREAM_TYPE SType,
|
||||
STREAM_MODE SMode);
|
||||
extern DWORD cclose (DECODE_REF DecodeRef);
|
||||
extern void cfilelength (DECODE_REF DecodeRef, DWORD *pfilelen);
|
||||
extern COUNT cread (void *pStr, COUNT size, COUNT count,
|
||||
DECODE_REF DecodeRef);
|
||||
extern COUNT cwrite (const void *pStr, COUNT size, COUNT count,
|
||||
DECODE_REF DecodeRef);
|
||||
|
||||
#endif /* _DECLIB_H */
|
||||
@@ -1 +0,0 @@
|
||||
uqm_CFILES="lzdecode.c lzencode.c update.c"
|
||||
@@ -1,415 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* LZHUF.C English version 1.0
|
||||
* Based on Japanese version 29-NOV-1988
|
||||
* LZSS coded by Haruhiko OKUMURA
|
||||
* Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
|
||||
* Edited and translated to English by Kenji RIKITAKE
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "lzh.h"
|
||||
#include "libs/reslib.h"
|
||||
|
||||
PLZHCODE_DESC _lpCurCodeDesc;
|
||||
STREAM_TYPE _StreamType;
|
||||
BYTE* _Stream;
|
||||
UWORD _workbuf;
|
||||
BYTE _workbuflen;
|
||||
|
||||
/* get one bit */
|
||||
static SWORD
|
||||
GetBit (void)
|
||||
{
|
||||
SWORD i;
|
||||
|
||||
while (_workbuflen <= 8)
|
||||
{
|
||||
if ((i = InChar ()) < 0)
|
||||
i = 0;
|
||||
_workbuf |= i << (8 - _workbuflen);
|
||||
_workbuflen += 8;
|
||||
}
|
||||
i = (_workbuf & 0xFFFF) >> (16 - 1);
|
||||
_workbuf = (_workbuf << 1) & 0xFFFF;
|
||||
_workbuflen--;
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
static UWORD
|
||||
GetBits (BYTE num_bits)
|
||||
{
|
||||
SWORD i;
|
||||
|
||||
while (_workbuflen <= 8)
|
||||
{
|
||||
if ((i = InChar ()) < 0)
|
||||
i = 0;
|
||||
_workbuf |= i << (8 - _workbuflen);
|
||||
_workbuflen += 8;
|
||||
}
|
||||
i = (_workbuf & 0xFFFF) >> (16 - num_bits);
|
||||
_workbuf = (_workbuf << num_bits) & 0xFFFF;
|
||||
_workbuflen -= num_bits;
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
/* initialize freq tree */
|
||||
|
||||
void
|
||||
StartHuff (void)
|
||||
{
|
||||
COUNT i, j;
|
||||
|
||||
for (i = 0; i < N_CHAR; i++)
|
||||
{
|
||||
_lpCurCodeDesc->freq[i] = 1;
|
||||
_lpCurCodeDesc->son[i] = i + T;
|
||||
_lpCurCodeDesc->prnt[i + T] = i;
|
||||
}
|
||||
i = 0; j = N_CHAR;
|
||||
while (j <= R)
|
||||
{
|
||||
_lpCurCodeDesc->freq[j] = _lpCurCodeDesc->freq[i] + _lpCurCodeDesc->freq[i + 1];
|
||||
_lpCurCodeDesc->son[j] = i;
|
||||
_lpCurCodeDesc->prnt[i] = _lpCurCodeDesc->prnt[i + 1] = j;
|
||||
i += 2; j++;
|
||||
}
|
||||
_lpCurCodeDesc->freq[T] = 0xffff;
|
||||
_lpCurCodeDesc->prnt[R] = 0;
|
||||
}
|
||||
|
||||
DECODE_REF
|
||||
copen (void *InStream, STREAM_TYPE SType, STREAM_MODE SMode)
|
||||
{
|
||||
DWORD StreamLength;
|
||||
|
||||
_StreamType = SType;
|
||||
_Stream = InStream;
|
||||
if (SMode == STREAM_WRITE) /* writing */
|
||||
{
|
||||
OutChar (0); /* skip future StreamLength */
|
||||
OutChar (0);
|
||||
OutChar (0);
|
||||
OutChar (0);
|
||||
|
||||
StreamLength = 0;
|
||||
}
|
||||
else /* reading */
|
||||
{
|
||||
BYTE lobyte, hibyte;
|
||||
UWORD loword, hiword;
|
||||
|
||||
lobyte = (BYTE)InChar ();
|
||||
hibyte = (BYTE)InChar ();
|
||||
loword = MAKE_WORD (lobyte, hibyte);
|
||||
lobyte = (BYTE)InChar ();
|
||||
hibyte = (BYTE)InChar ();
|
||||
hiword = MAKE_WORD (lobyte, hibyte);
|
||||
|
||||
StreamLength = MAKE_DWORD (loword, hiword);
|
||||
}
|
||||
|
||||
if (StreamLength == 0xFFFFFFFF
|
||||
|| (_lpCurCodeDesc = AllocCodeDesc ()) == NULL)
|
||||
{
|
||||
FreeCodeDesc (_lpCurCodeDesc);
|
||||
_lpCurCodeDesc = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lpCurCodeDesc->Stream = _Stream;
|
||||
_lpCurCodeDesc->StreamType = _StreamType;
|
||||
_lpCurCodeDesc->StreamMode = SMode;
|
||||
_lpCurCodeDesc->StreamLength = StreamLength;
|
||||
_lpCurCodeDesc->buf_index = N - F;
|
||||
memset (&_lpCurCodeDesc->text_buf[0], ' ', N - F);
|
||||
|
||||
StartHuff ();
|
||||
}
|
||||
|
||||
return ((DECODE_REF)_lpCurCodeDesc);
|
||||
}
|
||||
|
||||
DWORD
|
||||
cclose (PLZHCODE_DESC lpCodeDesc)
|
||||
{
|
||||
_lpCurCodeDesc = lpCodeDesc;
|
||||
if (_lpCurCodeDesc)
|
||||
{
|
||||
DWORD StreamIndex;
|
||||
|
||||
if (_lpCurCodeDesc->CleanupFunc)
|
||||
(*_lpCurCodeDesc->CleanupFunc) ();
|
||||
|
||||
StreamIndex = lpCodeDesc->StreamIndex;
|
||||
FreeCodeDesc (lpCodeDesc);
|
||||
_lpCurCodeDesc = NULL;
|
||||
|
||||
return (StreamIndex);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
cfilelength (PLZHCODE_DESC lpCodeDesc, DWORD *pfilelen)
|
||||
{
|
||||
if (lpCodeDesc == 0)
|
||||
*pfilelen = 0;
|
||||
else
|
||||
*pfilelen = lpCodeDesc->StreamLength;
|
||||
}
|
||||
|
||||
/* decoder table */
|
||||
static const BYTE d_code[256] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
|
||||
0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
|
||||
0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
|
||||
0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
|
||||
0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
|
||||
0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
|
||||
0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
|
||||
0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
|
||||
0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
|
||||
0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
|
||||
0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
|
||||
0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
|
||||
0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
};
|
||||
static const BYTE d_len[256] =
|
||||
{
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
};
|
||||
|
||||
/* decode upper 6 bits from given table */
|
||||
#define DecodePosition(p) \
|
||||
{ \
|
||||
while (_workbuflen <= 8) \
|
||||
{ \
|
||||
*(p) = InChar (); \
|
||||
_workbuf |= *(p) << (8 - _workbuflen); \
|
||||
_workbuflen += 8; \
|
||||
} \
|
||||
*(p) = HIBYTE (_workbuf); \
|
||||
_workbuf = (_workbuf << 8) & 0xFFFF; \
|
||||
_workbuflen -= 8; \
|
||||
\
|
||||
/* input lower 6 bits directly */ \
|
||||
j = d_len[*(p)]; \
|
||||
*(p) = ((UWORD)d_code[*(p)] << 6) \
|
||||
| (((*(p) << j) | GetBits (j)) & 0x3f); \
|
||||
}
|
||||
|
||||
/* start searching tree from the root to leaves.
|
||||
* choose node #(son[]) if input bit == 0
|
||||
* else choose #(son[]+1) (input bit == 1)
|
||||
*/
|
||||
#define DecodeChar(c) \
|
||||
{ \
|
||||
for (*(c) = lpCodeDesc->son[R]; \
|
||||
*(c) < T; \
|
||||
*(c) = lpCodeDesc->son[*(c) + GetBit ()]) \
|
||||
; \
|
||||
_update (*(c)); \
|
||||
*(c) -= T; \
|
||||
}
|
||||
|
||||
COUNT
|
||||
cread (void *buf, COUNT size, COUNT count, PLZHCODE_DESC lpCodeDesc)
|
||||
{
|
||||
COUNT r, j, i;
|
||||
BYTE *lpStr;
|
||||
|
||||
if ((_lpCurCodeDesc = lpCodeDesc) == 0)
|
||||
return (0);
|
||||
|
||||
size *= count;
|
||||
if (lpCodeDesc->StreamIndex + size > lpCodeDesc->StreamLength)
|
||||
{
|
||||
size /= count;
|
||||
count = (COUNT)((lpCodeDesc->StreamLength
|
||||
- lpCodeDesc->StreamIndex) / size);
|
||||
|
||||
size *= count;
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
return (0);
|
||||
|
||||
lpStr = (BYTE*)buf;
|
||||
_StreamType = lpCodeDesc->StreamType;
|
||||
|
||||
_Stream = lpCodeDesc->Stream;
|
||||
_workbuf = lpCodeDesc->workbuf;
|
||||
_workbuflen = lpCodeDesc->workbuflen;
|
||||
|
||||
lpCodeDesc->StreamIndex += size;
|
||||
r = lpCodeDesc->buf_index;
|
||||
j = lpCodeDesc->bytes_left;
|
||||
if (j)
|
||||
{
|
||||
lpCodeDesc->bytes_left = 0;
|
||||
i = lpCodeDesc->restart_index;
|
||||
|
||||
goto ReenterRun;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
COUNT c;
|
||||
|
||||
DecodeChar (&c);
|
||||
|
||||
if (c < 256)
|
||||
{
|
||||
size--;
|
||||
|
||||
*lpStr++ = lpCodeDesc->text_buf[r++ & (N - 1)] = (BYTE)c;
|
||||
}
|
||||
else
|
||||
{
|
||||
COUNT copy_size;
|
||||
|
||||
//i is a COUNT;
|
||||
DecodePosition(&i);
|
||||
i = r - i - 1;
|
||||
j = c - 255 + THRESHOLD;
|
||||
ReenterRun:
|
||||
if (j > size)
|
||||
{
|
||||
lpCodeDesc->bytes_left = j - size;
|
||||
lpCodeDesc->restart_index = i + size;
|
||||
j = size;
|
||||
}
|
||||
|
||||
size -= j;
|
||||
do
|
||||
{
|
||||
COUNT loc_size;
|
||||
|
||||
i &= (N - 1);
|
||||
r &= (N - 1);
|
||||
if ((i < r && i + j > r) || (i > r && i + j > r + N))
|
||||
copy_size = (r - i) & (N - 1);
|
||||
else if ((copy_size = j) > N)
|
||||
copy_size = N;
|
||||
|
||||
loc_size = copy_size;
|
||||
if (i + loc_size > N)
|
||||
{
|
||||
COUNT k;
|
||||
|
||||
k = N - i;
|
||||
memcpy (lpStr, &lpCodeDesc->text_buf[i], k);
|
||||
lpStr += k;
|
||||
loc_size -= k;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
memcpy (lpStr, &lpCodeDesc->text_buf[i], loc_size);
|
||||
lpStr += loc_size;
|
||||
i += loc_size;
|
||||
|
||||
lpStr -= copy_size;
|
||||
|
||||
loc_size = copy_size;
|
||||
if (r + loc_size > N)
|
||||
{
|
||||
COUNT k;
|
||||
|
||||
k = N - r;
|
||||
memcpy (&lpCodeDesc->text_buf[r], lpStr, k);
|
||||
lpStr += k;
|
||||
loc_size -= k;
|
||||
r = 0;
|
||||
}
|
||||
|
||||
memcpy (&lpCodeDesc->text_buf[r], lpStr, loc_size);
|
||||
lpStr += loc_size;
|
||||
r += loc_size;
|
||||
} while (j -= copy_size);
|
||||
}
|
||||
} while (size);
|
||||
|
||||
lpCodeDesc->buf_index = r;
|
||||
lpCodeDesc->Stream = _Stream;
|
||||
lpCodeDesc->workbuf = _workbuf;
|
||||
lpCodeDesc->workbuflen = _workbuflen;
|
||||
|
||||
return (count);
|
||||
}
|
||||
|
||||
@@ -1,468 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* LZHUF.C English version 1.0
|
||||
* Based on Japanese version 29-NOV-1988
|
||||
* LZSS coded by Haruhiko OKUMURA
|
||||
* Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
|
||||
* Edited and translated to English by Kenji RIKITAKE
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "lzh.h"
|
||||
#include "libs/reslib.h"
|
||||
|
||||
static UWORD match_position, match_length;
|
||||
static SWORD *lson;
|
||||
static SWORD *rson;
|
||||
static SWORD *dad;
|
||||
static SWORD *encode_arrays;
|
||||
|
||||
#define AllocEncodeArrays() \
|
||||
HCalloc ( \
|
||||
(((N + 1) + (N + 257) + (N + 1)) \
|
||||
* sizeof (lson[0])))
|
||||
#define FreeCodeArrays HFree
|
||||
|
||||
static BOOLEAN
|
||||
InitTree (void)
|
||||
{
|
||||
if ((encode_arrays = AllocEncodeArrays ()) == NULL)
|
||||
{
|
||||
FreeCodeArrays (encode_arrays);
|
||||
encode_arrays = NULL;
|
||||
return (FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SWORD i;
|
||||
|
||||
lson = encode_arrays;
|
||||
rson = lson + (N + 1);
|
||||
dad = rson + (N + 257);
|
||||
|
||||
for (i = N + 1; i <= N + 256; i++)
|
||||
rson[i] = NIL; /* root */
|
||||
for (i = 0; i < N; i++)
|
||||
dad[i] = NIL; /* node */
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
InsertNode (SWORD r)
|
||||
{
|
||||
SWORD p, cmp;
|
||||
BYTE *lpBuf;
|
||||
|
||||
cmp = 1;
|
||||
lpBuf = _lpCurCodeDesc->text_buf;
|
||||
p = N + 1 + lpBuf[r];
|
||||
rson[r] = lson[r] = NIL;
|
||||
match_length = 0;
|
||||
for (;;)
|
||||
{
|
||||
UWORD i;
|
||||
|
||||
if (cmp >= 0)
|
||||
{
|
||||
if (rson[p] != NIL)
|
||||
p = rson[p];
|
||||
else
|
||||
{
|
||||
rson[p] = r;
|
||||
dad[r] = p;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lson[p] != NIL)
|
||||
p = lson[p];
|
||||
else
|
||||
{
|
||||
lson[p] = r;
|
||||
dad[r] = p;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
i = F;
|
||||
{
|
||||
SWORD _r, _p;
|
||||
|
||||
_r = r;
|
||||
_p = p;
|
||||
while (--i && (cmp = lpBuf[++_r] - lpBuf[++_p]) == 0)
|
||||
;
|
||||
}
|
||||
if ((i = F - i) > THRESHOLD)
|
||||
{
|
||||
if (i > match_length)
|
||||
{
|
||||
match_position = ((r - p) & (N - 1)) - 1;
|
||||
if ((match_length = i) >= F)
|
||||
break;
|
||||
}
|
||||
else if (i == match_length)
|
||||
{
|
||||
if ((i = ((r - p) & (N - 1)) - 1) < match_position)
|
||||
{
|
||||
match_position = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dad[r] = dad[p];
|
||||
lson[r] = lson[p];
|
||||
rson[r] = rson[p];
|
||||
dad[lson[p]] = r;
|
||||
dad[rson[p]] = r;
|
||||
if (rson[dad[p]] == p)
|
||||
rson[dad[p]] = r;
|
||||
else
|
||||
lson[dad[p]] = r;
|
||||
dad[p] = NIL; /* remove p */
|
||||
}
|
||||
|
||||
static void
|
||||
DeleteNode (SWORD p)
|
||||
{
|
||||
SWORD q;
|
||||
|
||||
if (dad[p] == NIL)
|
||||
return; /* unregistered */
|
||||
if (rson[p] == NIL)
|
||||
q = lson[p];
|
||||
else if (lson[p] == NIL)
|
||||
q = rson[p];
|
||||
else
|
||||
{
|
||||
q = lson[p];
|
||||
if (rson[q] != NIL)
|
||||
{
|
||||
do
|
||||
{
|
||||
q = rson[q];
|
||||
} while (rson[q] != NIL);
|
||||
rson[dad[q]] = lson[q];
|
||||
dad[lson[q]] = dad[q];
|
||||
lson[q] = lson[p];
|
||||
dad[lson[p]] = q;
|
||||
}
|
||||
rson[q] = rson[p];
|
||||
dad[rson[p]] = q;
|
||||
}
|
||||
dad[q] = dad[p];
|
||||
if (rson[dad[p]] == p)
|
||||
rson[dad[p]] = q;
|
||||
else
|
||||
lson[dad[p]] = q;
|
||||
dad[p] = NIL;
|
||||
}
|
||||
|
||||
static void
|
||||
Putcode (SWORD l, UWORD c)
|
||||
{
|
||||
_workbuf |= c >> _workbuflen;
|
||||
if ((_workbuflen += l) >= 8)
|
||||
{
|
||||
OutChar ((BYTE)(_workbuf >> 8));
|
||||
++_lpCurCodeDesc->StreamIndex;
|
||||
if ((_workbuflen -= 8) >= 8)
|
||||
{
|
||||
OutChar ((BYTE)(_workbuf));
|
||||
++_lpCurCodeDesc->StreamIndex;
|
||||
_workbuflen -= 8;
|
||||
_workbuf = c << (l - _workbuflen);
|
||||
}
|
||||
else
|
||||
{
|
||||
_workbuf <<= 8;
|
||||
}
|
||||
_workbuf &= 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
EncodeChar (UWORD c)
|
||||
{
|
||||
UWORD i;
|
||||
SWORD j, k;
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
k = _lpCurCodeDesc->prnt[c + T];
|
||||
|
||||
/* search connections from leaf node to the root */
|
||||
do
|
||||
{
|
||||
i >>= 1;
|
||||
|
||||
/*
|
||||
if node's address is odd, output 1
|
||||
else output 0
|
||||
*/
|
||||
if (k & 1)
|
||||
i += 0x8000;
|
||||
|
||||
j++;
|
||||
} while ((k = _lpCurCodeDesc->prnt[k]) != R);
|
||||
Putcode (j, i);
|
||||
_update (c + T);
|
||||
}
|
||||
|
||||
static void
|
||||
EncodePosition (UWORD c)
|
||||
{
|
||||
UWORD i;
|
||||
/*
|
||||
* Tables for encoding/decoding upper 6 bits of
|
||||
* sliding dictionary pointer
|
||||
*/
|
||||
/* encoder table */
|
||||
static const BYTE p_len[64] =
|
||||
{
|
||||
0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
|
||||
};
|
||||
|
||||
static const BYTE p_code[64] =
|
||||
{
|
||||
0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
|
||||
0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
|
||||
0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
|
||||
0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
|
||||
0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
|
||||
0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
|
||||
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};
|
||||
|
||||
/* output upper 6 bits with encoding */
|
||||
i = c >> 6;
|
||||
Putcode (p_len[i], (UWORD)p_code[i] << 8);
|
||||
|
||||
/* output lower 6 bits directly */
|
||||
Putcode (6, (c & 0x3f) << 10);
|
||||
}
|
||||
|
||||
static void
|
||||
UninitTree (void)
|
||||
{
|
||||
if (_workbuflen)
|
||||
{
|
||||
OutChar ((BYTE)(_workbuf >> 8));
|
||||
++_lpCurCodeDesc->StreamIndex;
|
||||
}
|
||||
|
||||
FreeCodeArrays (encode_arrays);
|
||||
encode_arrays = NULL;
|
||||
lson = NULL;
|
||||
rson = NULL;
|
||||
dad = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_encode_cleanup (void)
|
||||
{
|
||||
UWORD r, s, last_match_length, len;
|
||||
|
||||
_StreamType = _lpCurCodeDesc->StreamType;
|
||||
_Stream = _lpCurCodeDesc->Stream;
|
||||
_workbuf = _lpCurCodeDesc->workbuf;
|
||||
_workbuflen = _lpCurCodeDesc->workbuflen;
|
||||
|
||||
r = _lpCurCodeDesc->buf_index;
|
||||
s = _lpCurCodeDesc->restart_index;
|
||||
last_match_length = _lpCurCodeDesc->bytes_left;
|
||||
if (_lpCurCodeDesc->StreamLength >= F)
|
||||
len = F;
|
||||
else
|
||||
{
|
||||
UWORD i;
|
||||
|
||||
for (i = 1; i <= F; i++)
|
||||
InsertNode (r - i);
|
||||
InsertNode (r);
|
||||
|
||||
len = (UWORD)_lpCurCodeDesc->StreamLength;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (last_match_length--)
|
||||
{
|
||||
DeleteNode (s);
|
||||
if (--len == 0)
|
||||
{
|
||||
BYTE lobyte, hibyte;
|
||||
UWORD loword, hiword;
|
||||
|
||||
UninitTree ();
|
||||
|
||||
_lpCurCodeDesc->StreamIndex += 4;
|
||||
/* rewind */
|
||||
if (_lpCurCodeDesc->StreamType == FILE_STREAM)
|
||||
SeekResFile ((uio_Stream *)_Stream,
|
||||
-(int)_lpCurCodeDesc->StreamIndex, SEEK_CUR);
|
||||
else /* _lpCurCodeDesc->StreamType == MEMORY_STREAM */
|
||||
_Stream = (BYTE*)_Stream - _lpCurCodeDesc->StreamIndex;
|
||||
|
||||
loword = LOWORD (_lpCurCodeDesc->StreamLength);
|
||||
lobyte = LOBYTE (loword);
|
||||
hibyte = HIBYTE (loword);
|
||||
OutChar (lobyte);
|
||||
OutChar (hibyte);
|
||||
hiword = HIWORD (_lpCurCodeDesc->StreamLength);
|
||||
lobyte = LOBYTE (hiword);
|
||||
hibyte = HIBYTE (hiword);
|
||||
OutChar (lobyte);
|
||||
OutChar (hibyte);
|
||||
|
||||
return;
|
||||
}
|
||||
s = (s + 1) & (N - 1);
|
||||
r = (r + 1) & (N - 1);
|
||||
InsertNode (r);
|
||||
}
|
||||
if (match_length > len)
|
||||
match_length = len;
|
||||
if (match_length <= THRESHOLD)
|
||||
{
|
||||
match_length = 1;
|
||||
EncodeChar (_lpCurCodeDesc->text_buf[r]);
|
||||
}
|
||||
else
|
||||
{
|
||||
EncodeChar (255 - THRESHOLD + match_length);
|
||||
EncodePosition (match_position);
|
||||
}
|
||||
last_match_length = match_length;
|
||||
}
|
||||
}
|
||||
|
||||
COUNT
|
||||
cwrite (const void *buf, COUNT size, COUNT count, PLZHCODE_DESC lpCodeDesc)
|
||||
{
|
||||
UWORD r, s, last_match_length;
|
||||
BYTE *lpBuf;
|
||||
const BYTE *lpStr;
|
||||
|
||||
if ((_lpCurCodeDesc = lpCodeDesc) == 0
|
||||
|| (size *= count) == 0)
|
||||
return (0);
|
||||
|
||||
_StreamType = lpCodeDesc->StreamType;
|
||||
_Stream = lpCodeDesc->Stream;
|
||||
_workbuf = lpCodeDesc->workbuf;
|
||||
_workbuflen = lpCodeDesc->workbuflen;
|
||||
lpStr = (const BYTE *) buf;
|
||||
lpBuf = lpCodeDesc->text_buf;
|
||||
|
||||
r = lpCodeDesc->buf_index;
|
||||
s = lpCodeDesc->restart_index;
|
||||
last_match_length = lpCodeDesc->bytes_left;
|
||||
if (last_match_length)
|
||||
{
|
||||
lpCodeDesc->StreamLength += size;
|
||||
goto EncodeRestart;
|
||||
}
|
||||
else if (lpCodeDesc->StreamLength < F)
|
||||
{
|
||||
UWORD i;
|
||||
|
||||
if ((i = (UWORD)lpCodeDesc->StreamLength) == 0)
|
||||
{
|
||||
if (!InitTree ())
|
||||
return (0);
|
||||
|
||||
_lpCurCodeDesc->StreamIndex = 0;
|
||||
lpCodeDesc->CleanupFunc = _encode_cleanup;
|
||||
}
|
||||
|
||||
lpCodeDesc->StreamLength += size;
|
||||
|
||||
for (; i < F && size; ++i, --size)
|
||||
lpBuf[r + i] = *lpStr++;
|
||||
if (i < F)
|
||||
goto EncodeExit;
|
||||
|
||||
for (i = 1; i <= F; i++)
|
||||
InsertNode (r - i);
|
||||
InsertNode (r);
|
||||
if (size == 0)
|
||||
goto EncodeExit;
|
||||
}
|
||||
else
|
||||
lpCodeDesc->StreamLength += size;
|
||||
|
||||
do
|
||||
{
|
||||
if (match_length > F)
|
||||
match_length = F;
|
||||
if (match_length <= THRESHOLD)
|
||||
{
|
||||
match_length = 1;
|
||||
EncodeChar (lpBuf[r]);
|
||||
}
|
||||
else
|
||||
{
|
||||
EncodeChar (255 - THRESHOLD + match_length);
|
||||
EncodePosition (match_position);
|
||||
}
|
||||
last_match_length = match_length;
|
||||
EncodeRestart:
|
||||
while (last_match_length && size)
|
||||
{
|
||||
BYTE c;
|
||||
|
||||
--size;
|
||||
--last_match_length;
|
||||
|
||||
DeleteNode (s);
|
||||
c = *lpStr++;
|
||||
lpBuf[s] = c;
|
||||
if (s < F - 1)
|
||||
lpBuf[s + N] = c;
|
||||
s = (s + 1) & (N - 1);
|
||||
r = (r + 1) & (N - 1);
|
||||
InsertNode (r);
|
||||
}
|
||||
} while (last_match_length == 0);
|
||||
|
||||
EncodeExit:
|
||||
lpCodeDesc->buf_index = r;
|
||||
lpCodeDesc->restart_index = s;
|
||||
lpCodeDesc->bytes_left = last_match_length;
|
||||
|
||||
lpCodeDesc->Stream = _Stream;
|
||||
lpCodeDesc->workbuf = _workbuf;
|
||||
lpCodeDesc->workbuflen = _workbuflen;
|
||||
|
||||
return (count);
|
||||
}
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _LZH_H
|
||||
#define _LZH_H
|
||||
|
||||
#include "libs/declib.h"
|
||||
#include "libs/memlib.h"
|
||||
|
||||
/* LZSS Parameters */
|
||||
|
||||
#define N 4096 /* Size of string buffer */
|
||||
#define F 16 /* Size of look-ahead buffer */
|
||||
//#define F 60 /* Size of look-ahead buffer */
|
||||
#define THRESHOLD 2
|
||||
#define NIL N /* End of tree's node */
|
||||
|
||||
/* Huffman coding parameters */
|
||||
|
||||
#define N_CHAR (256 - THRESHOLD + F)
|
||||
/* character code (= 0..N_CHAR-1) */
|
||||
#define T (N_CHAR * 2 - 1) /* Size of table */
|
||||
#define R (T - 1) /* root position */
|
||||
#define MAX_FREQ 0x8000
|
||||
/* update when cumulative frequency */
|
||||
|
||||
struct _LZHCODE_DESC
|
||||
{
|
||||
COUNT buf_index, restart_index, bytes_left;
|
||||
BYTE text_buf[N + F - 1];
|
||||
/* reconstruct freq tree */
|
||||
COUNT freq[T + 1]; /* cumulative freq table */
|
||||
/*
|
||||
* pointing parent nodes.
|
||||
* area [T..(T + N_CHAR - 1)] are pointers for leaves
|
||||
*/
|
||||
COUNT prnt[T + N_CHAR];
|
||||
/* pointing children nodes (son[], son[] + 1)*/
|
||||
COUNT son[T];
|
||||
UWORD workbuf;
|
||||
BYTE workbuflen;
|
||||
|
||||
STREAM_TYPE StreamType;
|
||||
|
||||
void *Stream;
|
||||
DWORD StreamIndex, StreamLength;
|
||||
|
||||
STREAM_MODE StreamMode;
|
||||
PVOIDFUNC CleanupFunc;
|
||||
};
|
||||
|
||||
typedef struct _LZHCODE_DESC LZHCODE_DESC;
|
||||
typedef LZHCODE_DESC *PLZHCODE_DESC;
|
||||
|
||||
#define InChar() (_StreamType == FILE_STREAM ? \
|
||||
GetResFileChar ((uio_Stream *)_Stream) : \
|
||||
(int)*_Stream++)
|
||||
#define OutChar(c) (_StreamType == FILE_STREAM ? \
|
||||
PutResFileChar ((c), (uio_Stream *)_Stream) : \
|
||||
(*_Stream++ = (BYTE)(c)))
|
||||
|
||||
|
||||
#define AllocCodeDesc() HCalloc (sizeof (LZHCODE_DESC))
|
||||
#define FreeCodeDesc HFree
|
||||
|
||||
extern void _update (COUNT c);
|
||||
extern void StartHuff (void);
|
||||
|
||||
extern PLZHCODE_DESC _lpCurCodeDesc;
|
||||
extern STREAM_TYPE _StreamType;
|
||||
extern BYTE* _Stream;
|
||||
extern UWORD _workbuf;
|
||||
extern BYTE _workbuflen;
|
||||
|
||||
#endif /* _LZH_H */
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "lzh.h"
|
||||
|
||||
static void
|
||||
reconst (void)
|
||||
{
|
||||
COUNT i, j;
|
||||
|
||||
/* halven cumulative freq for leaf nodes */
|
||||
j = 0;
|
||||
for (i = 0; i < T; i++)
|
||||
{
|
||||
if (_lpCurCodeDesc->son[i] >= T)
|
||||
{
|
||||
_lpCurCodeDesc->freq[j] = (_lpCurCodeDesc->freq[i] + 1) >> 1;
|
||||
_lpCurCodeDesc->son[j] = _lpCurCodeDesc->son[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
/* make a tree : first, connect children nodes */
|
||||
for (i = 0, j = N_CHAR; j < T; i += 2, j++)
|
||||
{
|
||||
SWORD k;
|
||||
UWORD f, l;
|
||||
|
||||
k = i + 1;
|
||||
f = _lpCurCodeDesc->freq[j] = _lpCurCodeDesc->freq[i] + _lpCurCodeDesc->freq[k];
|
||||
for (k = j - 1; f < _lpCurCodeDesc->freq[k]; k--)
|
||||
;
|
||||
k++;
|
||||
l = (j - k);
|
||||
|
||||
memmove (_lpCurCodeDesc->freq + k + 1, _lpCurCodeDesc->freq + k,
|
||||
sizeof(_lpCurCodeDesc->freq[0]) * l);
|
||||
_lpCurCodeDesc->freq[k] = f;
|
||||
memmove (_lpCurCodeDesc->son + k + 1, _lpCurCodeDesc->son + k,
|
||||
sizeof(_lpCurCodeDesc->son[0]) * l);
|
||||
_lpCurCodeDesc->son[k] = i;
|
||||
}
|
||||
/* connect parent nodes */
|
||||
for (i = 0; i < T; i++)
|
||||
{
|
||||
if ((j = _lpCurCodeDesc->son[i]) >= T)
|
||||
_lpCurCodeDesc->prnt[j] = i;
|
||||
else
|
||||
_lpCurCodeDesc->prnt[j] = _lpCurCodeDesc->prnt[j + 1] = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* update freq tree */
|
||||
|
||||
void
|
||||
_update (COUNT c)
|
||||
{
|
||||
PLZHCODE_DESC lpCD;
|
||||
|
||||
if ((lpCD = _lpCurCodeDesc)->freq[R] == MAX_FREQ)
|
||||
reconst ();
|
||||
|
||||
c = lpCD->prnt[c];
|
||||
do
|
||||
{
|
||||
COUNT i, l;
|
||||
|
||||
i = ++lpCD->freq[c];
|
||||
|
||||
/* swap nodes to keep the tree freq-ordered */
|
||||
if (i > lpCD->freq[l = c + 1])
|
||||
{
|
||||
COUNT j;
|
||||
|
||||
while (i > lpCD->freq[++l])
|
||||
;
|
||||
l--;
|
||||
lpCD->freq[c] = lpCD->freq[l];
|
||||
lpCD->freq[l] = i;
|
||||
|
||||
i = lpCD->son[c];
|
||||
j = lpCD->son[l];
|
||||
lpCD->son[l] = i;
|
||||
lpCD->son[c] = j;
|
||||
|
||||
lpCD->prnt[i] = l;
|
||||
if (i < T)
|
||||
lpCD->prnt[i + 1] = l;
|
||||
|
||||
lpCD->prnt[j] = c;
|
||||
if (j < T)
|
||||
lpCD->prnt[j + 1] = c;
|
||||
|
||||
c = l;
|
||||
}
|
||||
} while ((c = lpCD->prnt[c]) != 0); /* do it until reaching the root */
|
||||
}
|
||||
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// Contains file handling code
|
||||
|
||||
#ifndef _FILE_H
|
||||
#define _FILE_H
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
|
||||
// for bool
|
||||
#include "types.h"
|
||||
|
||||
#if 0
|
||||
// from temp.h
|
||||
void initTempDir (void);
|
||||
void unInitTempDir (void);
|
||||
char *tempFilePath (const char *filename);
|
||||
extern uio_DirHandle *tempDir;
|
||||
#endif
|
||||
|
||||
|
||||
// from dirs.h
|
||||
int mkdirhier (const char *path);
|
||||
const char *getHomeDir (void);
|
||||
int createDirectory (const char *dir, int mode);
|
||||
|
||||
int expandPath (char *dest, size_t len, const char *src, int what);
|
||||
// values for 'what':
|
||||
#define EP_HOME 1
|
||||
// Expand '~' for home dirs.
|
||||
#define EP_ABSOLUTE 2
|
||||
// Make paths absolute
|
||||
#define EP_ENVVARS 4
|
||||
// Expand environment variables.
|
||||
#define EP_DOTS 8
|
||||
// Process ".." and "."
|
||||
#define EP_SLASHES 16
|
||||
// Consider backslashes as path component separators.
|
||||
// They will be replaced by slashes. Windows UNC paths will always
|
||||
// start with "\\server\share", with backslashes.
|
||||
#define EP_SINGLESEP 32
|
||||
// Replace multiple consecutive path separators by a single one.
|
||||
#define EP_ALL (EP_HOME | EP_ENVVARS | EP_ABSOLUTE | EP_DOTS | EP_SLASHES \
|
||||
EP_SINGLESEP)
|
||||
// Everything
|
||||
// Everything except Windows style backslashes on Unix Systems:
|
||||
#ifdef WIN32
|
||||
# define EP_ALL_SYSTEM (EP_HOME | EP_ENVVARS | EP_ABSOLUTE | EP_DOTS | \
|
||||
EP_SLASHES | EP_SINGLESEP)
|
||||
#else
|
||||
# define EP_ALL_SYSTEM (EP_HOME | EP_ENVVARS | EP_ABSOLUTE | EP_DOTS | \
|
||||
EP_SINGLESEP)
|
||||
#endif
|
||||
|
||||
// from files.h
|
||||
int copyFile (uio_DirHandle *srcDir, const char *srcName,
|
||||
uio_DirHandle *dstDir, const char *newName);
|
||||
bool fileExists (const char *name);
|
||||
bool fileExists2(uio_DirHandle *dir, const char *fileName);
|
||||
#ifdef HAVE_UNC_PATHS
|
||||
size_t skipUNCServerShare(const char *inPath);
|
||||
#endif /* HAVE_UNC_PATHS */
|
||||
|
||||
#ifdef HAVE_DRIVE_LETTERS
|
||||
static inline int isDriveLetter(int c)
|
||||
{
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
|
||||
}
|
||||
#endif /* HAVE_DRIVE_LETTERS */
|
||||
|
||||
#endif /* _FILE_H */
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
uqm_CFILES="dirs.c files.c"
|
||||
@@ -1,826 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// Contains code handling directories
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "port.h"
|
||||
#include "config.h"
|
||||
#include "filintrn.h"
|
||||
#include "libs/compiler.h"
|
||||
#include "libs/memlib.h"
|
||||
#include "libs/misc.h"
|
||||
#include "libs/log.h"
|
||||
|
||||
#ifdef HAVE_DRIVE_LETTERS
|
||||
# include <ctype.h>
|
||||
// For tolower()
|
||||
#endif /* HAVE_DRIVE_LETTERS */
|
||||
#ifdef WIN32
|
||||
# include <direct.h>
|
||||
// For _getdcwd()
|
||||
#else
|
||||
# include <pwd.h>
|
||||
// For getpwuid()
|
||||
#endif
|
||||
|
||||
/* Try to find a suitable value for %APPDATA% if it isn't defined on
|
||||
* Windows.
|
||||
*/
|
||||
#define APPDATA_FALLBACK
|
||||
|
||||
|
||||
static char *expandPathAbsolute (char *dest, size_t destLen, const char *src,
|
||||
size_t *skipSrc, int what);
|
||||
static char *strrchr2(const char *start, int c, const char *end);
|
||||
|
||||
|
||||
int
|
||||
createDirectory(const char *dir, int mode)
|
||||
{
|
||||
return MKDIR(dir, mode);
|
||||
}
|
||||
|
||||
// make all components of the path if they don't exist already
|
||||
// returns 0 on success, -1 on failure.
|
||||
// on failure, some parts may still have been created.
|
||||
int
|
||||
mkdirhier (const char *path)
|
||||
{
|
||||
char *buf; // buffer
|
||||
char *ptr; // end of the string in buf
|
||||
const char *pathstart; // start of a component of path
|
||||
const char *pathend; // first char past the end of a component of path
|
||||
size_t len;
|
||||
struct stat statbuf;
|
||||
|
||||
len = strlen (path);
|
||||
buf = HMalloc (len + 2); // one extra for possibly added '/'
|
||||
|
||||
ptr = buf;
|
||||
pathstart = path;
|
||||
|
||||
#ifdef HAVE_DRIVE_LETTERS
|
||||
if (isDriveLetter(pathstart[0]) && pathstart[1] == ':')
|
||||
{
|
||||
// Driveletter + semicolon on Windows.
|
||||
// Copy as is; don't try to create directories for it.
|
||||
*(ptr++) = *(pathstart++);
|
||||
*(ptr++) = *(pathstart++);
|
||||
|
||||
ptr[0] = '/';
|
||||
ptr[1] = '\0';
|
||||
if (stat (buf, &statbuf) == -1)
|
||||
{
|
||||
log_add (log_Error, "Can't stat \"%s\": %s", buf, strerror (errno));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* HAVE_DRIVE_LETTERS */
|
||||
#ifdef HAVE_UNC_PATHS
|
||||
if (pathstart[0] == '\\' && pathstart[1] == '\\')
|
||||
{
|
||||
// Universal Naming Convention path. (\\server\share\...)
|
||||
// Copy the server part as is; don't try to create directories for
|
||||
// it, or stat it. Don't create a dir for the share either.
|
||||
*(ptr++) = *(pathstart++);
|
||||
*(ptr++) = *(pathstart++);
|
||||
|
||||
// Copy the server part
|
||||
while (*pathstart != '\0' && *pathstart != '\\' && *pathstart != '/')
|
||||
*(ptr++) = *(pathstart++);
|
||||
|
||||
if (*pathstart == '\0')
|
||||
{
|
||||
log_add (log_Error, "Incomplete UNC path \"%s\"", pathstart);
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Copy the path seperator.
|
||||
*(ptr++) = *(pathstart++);
|
||||
|
||||
// Copy the share part
|
||||
while (*pathstart != '\0' && *pathstart != '\\' && *pathstart != '/')
|
||||
*(ptr++) = *(pathstart++);
|
||||
|
||||
ptr[0] = '/';
|
||||
ptr[1] = '\0';
|
||||
if (stat (buf, &statbuf) == -1)
|
||||
{
|
||||
log_add (log_Error, "Can't stat \"%s\": %s", buf, strerror (errno));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
// Making sure that there is an 'else' case if HAVE_DRIVE_LETTERS is
|
||||
// defined.
|
||||
}
|
||||
#endif /* HAVE_UNC_PATHS */
|
||||
|
||||
if (*pathstart == '/')
|
||||
*(ptr++) = *(pathstart++);
|
||||
|
||||
if (*pathstart == '\0') {
|
||||
// path exists completely, nothing more to do
|
||||
return 0;
|
||||
}
|
||||
|
||||
// walk through the path as long as the components exist
|
||||
while (1)
|
||||
{
|
||||
pathend = strchr (pathstart, '/');
|
||||
if (pathend == NULL)
|
||||
pathend = path + len;
|
||||
memcpy(ptr, pathstart, pathend - pathstart);
|
||||
ptr += pathend - pathstart;
|
||||
*ptr = '\0';
|
||||
|
||||
if (stat (buf, &statbuf) == -1)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
break;
|
||||
#ifdef __SYMBIAN32__
|
||||
// XXX: HACK: If we don't have access to a directory, we can
|
||||
// still have access to the underlying entries. We don't
|
||||
// actually know whether the entry is a directory, but I know of
|
||||
// no way to find out. We just pretend that it is; if we were
|
||||
// wrong, an error will occur when we try to do something with
|
||||
// the directory. That /should/ not be a problem, as any such
|
||||
// action should have its own error checking.
|
||||
if (errno != EACCES)
|
||||
#endif
|
||||
{
|
||||
log_add (log_Error, "Can't stat \"%s\": %s", buf,
|
||||
strerror (errno));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (*pathend == '\0')
|
||||
return 0;
|
||||
|
||||
*ptr = '/';
|
||||
ptr++;
|
||||
pathstart = pathend + 1;
|
||||
while (*pathstart == '/')
|
||||
pathstart++;
|
||||
// pathstart is the next non-slash character
|
||||
|
||||
if (*pathstart == '\0')
|
||||
return 0;
|
||||
}
|
||||
|
||||
// create all components left
|
||||
while (1)
|
||||
{
|
||||
if (createDirectory (buf, 0777) == -1)
|
||||
{
|
||||
log_add (log_Error, "Error: Can't create %s: %s", buf,
|
||||
strerror (errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (*pathend == '\0')
|
||||
break;
|
||||
|
||||
*ptr = '/';
|
||||
ptr++;
|
||||
pathstart = pathend + 1;
|
||||
while (*pathstart == '/')
|
||||
pathstart++;
|
||||
// pathstart is the next non-slash character
|
||||
|
||||
if (*pathstart == '\0')
|
||||
break;
|
||||
|
||||
pathend = strchr (pathstart, '/');
|
||||
if (pathend == NULL)
|
||||
pathend = path + len;
|
||||
|
||||
memcpy (ptr, pathstart, pathend - pathstart);
|
||||
ptr += pathend - pathstart;
|
||||
*ptr = '\0';
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
{
|
||||
int savedErrno = errno;
|
||||
HFree (buf);
|
||||
errno = savedErrno;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the user's home dir
|
||||
// returns a pointer to a static buffer from either getenv() or getpwuid().
|
||||
const char *
|
||||
getHomeDir (void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return getenv ("HOME");
|
||||
#else
|
||||
const char *home;
|
||||
struct passwd *pw;
|
||||
|
||||
home = getenv ("HOME");
|
||||
if (home != NULL)
|
||||
return home;
|
||||
|
||||
pw = getpwuid (getuid ());
|
||||
if (pw == NULL)
|
||||
return NULL;
|
||||
// NB: pw points to a static buffer.
|
||||
|
||||
return pw->pw_dir;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Performs various types of string expansions on a path.
|
||||
// 'what' is an OR'd compination of the folowing flags, which
|
||||
// specify what type of exmansions will be performed.
|
||||
// EP_HOME - Expand '~' for home dirs.
|
||||
// EP_ABSOLUTE - Make relative paths absolute
|
||||
// EP_ENVVARS - Expand environment variables
|
||||
// EP_DOTS - Process ".." and "."
|
||||
// EP_SLASHES - Consider backslashes as path component separators.
|
||||
// They will be replaced by slashes.
|
||||
// EP_SINGLESEP - Replace multiple consecutive path seperators (which POSIX
|
||||
// considers equivalent to a single one) by a single one.
|
||||
// Additionally, there's EP_ALL, which indicates all of the above,
|
||||
// and EP_ALL_SYSTEM, which does the same as EP_ALL, with the exception
|
||||
// of EP_SLASHES, which will only be included if the operating system
|
||||
// accepts backslashes as path terminators.
|
||||
// Returns 0 on success.
|
||||
// Returns -1 on failure, setting errno.
|
||||
int
|
||||
expandPath (char *dest, size_t len, const char *src, int what)
|
||||
{
|
||||
char *destptr, *destend;
|
||||
char *buf = NULL;
|
||||
char *bufptr, *bufend;
|
||||
const char *srcend;
|
||||
|
||||
#define CHECKLEN(bufname, n) \
|
||||
if (bufname##ptr + (n) >= bufname##end) \
|
||||
{ \
|
||||
errno = ENAMETOOLONG; \
|
||||
goto err; \
|
||||
} \
|
||||
else \
|
||||
(void) 0
|
||||
|
||||
destptr = dest;
|
||||
destend = dest + len;
|
||||
|
||||
if (what & EP_ENVVARS)
|
||||
{
|
||||
buf = HMalloc (len);
|
||||
bufptr = buf;
|
||||
bufend = buf + len;
|
||||
while (*src != '\0')
|
||||
{
|
||||
switch (*src)
|
||||
{
|
||||
#ifdef WIN32
|
||||
case '%':
|
||||
{
|
||||
/* Environment variable substitution in Windows */
|
||||
const char *end; // end of env var name in src
|
||||
const char *envVar;
|
||||
char *envName;
|
||||
size_t envNameLen, envVarLen;
|
||||
|
||||
src++;
|
||||
end = strchr (src, '%');
|
||||
if (end == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
envNameLen = end - src;
|
||||
envName = HMalloc (envNameLen + 1);
|
||||
memcpy (envName, src, envNameLen + 1);
|
||||
envName[envNameLen] = '\0';
|
||||
envVar = getenv (envName);
|
||||
HFree (envName);
|
||||
|
||||
if (envVar == NULL)
|
||||
{
|
||||
#ifdef APPDATA_FALLBACK
|
||||
if (strncmp (src, "APPDATA", envNameLen) != 0)
|
||||
{
|
||||
// Substitute an empty string
|
||||
src = end + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// fallback for when the APPDATA env var is not set
|
||||
// Using SHGetFolderPath or SHGetSpecialFolderPath
|
||||
// is problematic (not everywhere available).
|
||||
log_add (log_Warning, "Warning: %%APPDATA%% is not set. "
|
||||
"Falling back to \"%%USERPROFILE%%\\Application "
|
||||
"Data\"");
|
||||
envVar = getenv ("USERPROFILE");
|
||||
if (envVar != NULL)
|
||||
{
|
||||
#define APPDATA_STRING "\\Application Data"
|
||||
envVarLen = strlen (envVar);
|
||||
CHECKLEN (buf,
|
||||
envVarLen + sizeof (APPDATA_STRING) - 1);
|
||||
strcpy (bufptr, envVar);
|
||||
bufptr += envVarLen;
|
||||
strcpy (bufptr, APPDATA_STRING);
|
||||
bufptr += sizeof (APPDATA_STRING) - 1;
|
||||
src = end + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// fallback to "./userdata"
|
||||
#define APPDATA_FALLBACK_STRING ".\\userdata"
|
||||
log_add (log_Warning,
|
||||
"Warning: %%USERPROFILE%% is not set. "
|
||||
"Falling back to \"%s\" for %%APPDATA%%",
|
||||
APPDATA_FALLBACK_STRING);
|
||||
CHECKLEN (buf, sizeof (APPDATA_FALLBACK_STRING) - 1);
|
||||
strcpy (bufptr, APPDATA_FALLBACK_STRING);
|
||||
bufptr += sizeof (APPDATA_FALLBACK_STRING) - 1;
|
||||
src = end + 1;
|
||||
break;
|
||||
|
||||
#else /* !defined (APPDATA_FALLBACK) */
|
||||
// Substitute an empty string
|
||||
src = end + 1;
|
||||
break;
|
||||
#endif /* APPDATA_FALLBACK */
|
||||
}
|
||||
|
||||
envVarLen = strlen (envVar);
|
||||
CHECKLEN (buf, envVarLen);
|
||||
strcpy (bufptr, envVar);
|
||||
bufptr += envVarLen;
|
||||
src = end + 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifndef WIN32
|
||||
case '$':
|
||||
{
|
||||
const char *end;
|
||||
char *envName;
|
||||
size_t envNameLen;
|
||||
const char *envVar;
|
||||
size_t envVarLen;
|
||||
|
||||
src++;
|
||||
if (*src == '{')
|
||||
{
|
||||
src++;
|
||||
end = strchr(src, '}');
|
||||
if (end == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
envNameLen = end - src;
|
||||
end++; // Skip the '}'
|
||||
}
|
||||
else
|
||||
{
|
||||
end = src;
|
||||
while ((*end >= 'A' && *end <= 'Z') ||
|
||||
(*end >= 'a' && *end <= 'z') ||
|
||||
(*end >= '0' && *end <= '9') ||
|
||||
*end == '_')
|
||||
end++;
|
||||
envNameLen = end - src;
|
||||
}
|
||||
|
||||
envName = HMalloc (envNameLen + 1);
|
||||
memcpy (envName, src, envNameLen + 1);
|
||||
envName[envNameLen] = '\0';
|
||||
envVar = getenv (envName);
|
||||
HFree (envName);
|
||||
|
||||
if (envVar != NULL)
|
||||
{
|
||||
envVarLen = strlen (envVar);
|
||||
CHECKLEN (buf, envVarLen);
|
||||
memcpy (bufptr, envVar, envVarLen);
|
||||
bufptr += envVarLen;
|
||||
}
|
||||
|
||||
src = end;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
CHECKLEN(buf, 1);
|
||||
*(bufptr++) = *(src++);
|
||||
break;
|
||||
} // switch
|
||||
} // while
|
||||
*bufptr = '\0';
|
||||
src = buf;
|
||||
srcend = bufptr;
|
||||
} // if (what & EP_ENVVARS)
|
||||
else
|
||||
srcend = src + strlen (src);
|
||||
|
||||
if (what & EP_HOME)
|
||||
{
|
||||
if (src[0] == '~')
|
||||
{
|
||||
const char *home;
|
||||
size_t homelen;
|
||||
|
||||
if (src[1] != '/')
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
home = getHomeDir ();
|
||||
if (home == NULL)
|
||||
{
|
||||
errno = ENOENT;
|
||||
goto err;
|
||||
}
|
||||
homelen = strlen (home);
|
||||
|
||||
if (what & EP_ABSOLUTE) {
|
||||
size_t skip;
|
||||
destptr = expandPathAbsolute (dest, destend - dest,
|
||||
home, &skip, what);
|
||||
if (destptr == NULL)
|
||||
{
|
||||
// errno is set
|
||||
goto err;
|
||||
}
|
||||
home += skip;
|
||||
what &= ~EP_ABSOLUTE;
|
||||
// The part after the '~' should not be seen
|
||||
// as absolute.
|
||||
}
|
||||
|
||||
CHECKLEN (dest, homelen);
|
||||
memcpy (destptr, home, homelen);
|
||||
destptr += homelen;
|
||||
src++; /* skip the ~ */
|
||||
}
|
||||
}
|
||||
|
||||
if (what & EP_ABSOLUTE)
|
||||
{
|
||||
size_t skip;
|
||||
destptr = expandPathAbsolute (destptr, destend - destptr, src,
|
||||
&skip, what);
|
||||
if (destptr == NULL)
|
||||
{
|
||||
// errno is set
|
||||
goto err;
|
||||
}
|
||||
src += skip;
|
||||
}
|
||||
|
||||
CHECKLEN (dest, srcend - src);
|
||||
memcpy (destptr, src, srcend - src + 1);
|
||||
// The +1 is for the '\0'. It is already taken into account by
|
||||
// CHECKLEN.
|
||||
|
||||
if (what & EP_SLASHES)
|
||||
{
|
||||
/* Replacing backslashes in path by slashes. */
|
||||
destptr = dest;
|
||||
#ifdef HAVE_UNC_PATHS
|
||||
{
|
||||
// A UNC path should always start with two backslashes
|
||||
// and have a backslash in between the server and share part.
|
||||
size_t skip = skipUNCServerShare (destptr);
|
||||
if (skip != 0)
|
||||
{
|
||||
char *slash = (char *) memchr (destptr + 2, '/', skip - 2);
|
||||
if (slash)
|
||||
*slash = '\\';
|
||||
destptr += skip;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_UNC_PATHS */
|
||||
while (*destptr != '\0')
|
||||
{
|
||||
if (*destptr == '\\')
|
||||
*destptr = '/';
|
||||
destptr++;
|
||||
}
|
||||
}
|
||||
|
||||
if (what & EP_DOTS) {
|
||||
// At this point backslashes are already replaced by slashes if they
|
||||
// are specified to be path seperators.
|
||||
// Note that the path can only get smaller, so no size checks
|
||||
// need to be done.
|
||||
char *pathStart;
|
||||
// Start of the first path component, after any
|
||||
// leading slashes or drive letters.
|
||||
char *startPart;
|
||||
char *endPart;
|
||||
|
||||
pathStart = dest;
|
||||
#ifdef HAVE_DRIVE_LETTERS
|
||||
if (isDriveLetter(pathStart[0]) && (pathStart[1] == ':'))
|
||||
{
|
||||
pathStart += 2;
|
||||
}
|
||||
else
|
||||
#endif /* HAVE_DRIVE_LETTERS */
|
||||
#ifdef HAVE_UNC_PATHS
|
||||
{
|
||||
// Test for a Universal Naming Convention path.
|
||||
pathStart += skipUNCServerShare(pathStart);
|
||||
}
|
||||
#else
|
||||
{
|
||||
// Making sure that there is an 'else' case if HAVE_DRIVE_LETTERS is
|
||||
// defined.
|
||||
}
|
||||
#endif /* HAVE_UNC_PATHS */
|
||||
if (pathStart[0] == '/')
|
||||
pathStart++;
|
||||
|
||||
startPart = pathStart;
|
||||
destptr = pathStart;
|
||||
for (;;)
|
||||
{
|
||||
endPart = strchr(startPart, '/');
|
||||
if (endPart == NULL)
|
||||
endPart = startPart + strlen(startPart);
|
||||
|
||||
if (endPart - startPart == 1 && startPart[0] == '.')
|
||||
{
|
||||
// Found "." as path component. Ignore this component.
|
||||
}
|
||||
else if (endPart - startPart == 2 &&
|
||||
startPart[0] == '.' && startPart[1] == '.')
|
||||
{
|
||||
// Found ".." as path component. Remove the previous
|
||||
// component, and ignore this one.
|
||||
char *lastSlash;
|
||||
lastSlash = strrchr2(pathStart, '/', destptr - 1);
|
||||
if (lastSlash == NULL)
|
||||
{
|
||||
if (destptr == pathStart)
|
||||
{
|
||||
// We ran out of path components to back out of.
|
||||
errno = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
destptr = pathStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
destptr = lastSlash;
|
||||
if (*endPart == '/')
|
||||
destptr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// A normal path component; copy it.
|
||||
// Using memmove as source and destination may overlap.
|
||||
memmove(destptr, startPart, endPart - startPart);
|
||||
destptr += (endPart - startPart);
|
||||
if (*endPart == '/')
|
||||
{
|
||||
*destptr = '/';
|
||||
destptr++;
|
||||
}
|
||||
}
|
||||
if (*endPart == '\0')
|
||||
break;
|
||||
startPart = endPart + 1;
|
||||
}
|
||||
*destptr = '\0';
|
||||
}
|
||||
|
||||
if (what & EP_SINGLESEP)
|
||||
{
|
||||
char *srcptr;
|
||||
srcptr = dest;
|
||||
destptr = dest;
|
||||
while (*srcptr != '\0')
|
||||
{
|
||||
char ch = *srcptr;
|
||||
*(destptr++) = *(srcptr++);
|
||||
if (ch == '/')
|
||||
{
|
||||
while (*srcptr == '/')
|
||||
srcptr++;
|
||||
}
|
||||
}
|
||||
*destptr = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (buf != NULL) {
|
||||
int savedErrno = errno;
|
||||
HFree (buf);
|
||||
errno = savedErrno;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_DRIVE_LETTERS) && defined(HAVE_CWD_PER_DRIVE)
|
||||
// This code is only needed if we have a current working directory
|
||||
// per drive.
|
||||
// letter is 0 based: 0 = A, 1 = B, ...
|
||||
bool
|
||||
driveLetterExists(int letter)
|
||||
{
|
||||
unsigned long drives;
|
||||
|
||||
drives = _getdrives ();
|
||||
|
||||
return ((drives >> letter) & 1) != 0;
|
||||
}
|
||||
#endif /* if defined(HAVE_DRIVE_LETTERS) && defined(HAVE_CWD_PER_DRIVE) */
|
||||
|
||||
// helper for expandPath, expanding an absolute path
|
||||
// returns a pointer to the end of the filled in part of dest.
|
||||
static char *
|
||||
expandPathAbsolute (char *dest, size_t destLen, const char *src,
|
||||
size_t *skipSrc, int what)
|
||||
{
|
||||
const char *orgSrc;
|
||||
|
||||
if (src[0] == '/' || ((what & EP_SLASHES) && src[0] == '\\'))
|
||||
{
|
||||
// Path is already absolute; nothing to do
|
||||
*skipSrc = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
orgSrc = src;
|
||||
#ifdef HAVE_DRIVE_LETTERS
|
||||
if (isDriveLetter(src[0]) && (src[1] == ':'))
|
||||
{
|
||||
int letter;
|
||||
|
||||
if (src[2] == '/' || src[2] == '\\')
|
||||
{
|
||||
// Path is already absolute (of the form "d:/"); nothing to do
|
||||
*skipSrc = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
// Path is of the form "d:path", without a (back)slash after the
|
||||
// semicolon.
|
||||
|
||||
#ifdef REJECT_DRIVE_PATH_WITHOUT_SLASH
|
||||
// We reject paths of the form "d:foo/bar".
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
#elif defined(HAVE_CWD_PER_DRIVE)
|
||||
// Paths of the form "d:foo/bar" are treated as "foo/bar" relative
|
||||
// to the working directory of d:.
|
||||
letter = tolower(src[0]) - 'a';
|
||||
|
||||
// _getdcwd() should only be called on drives that exist.
|
||||
// This is weird though, because it means a race condition
|
||||
// in between the existance check and the call to _getdcwd()
|
||||
// cannot be avoided, unless a drive still exists for Windows
|
||||
// when the physical drive is removed.
|
||||
if (!driveLetterExists (letter))
|
||||
{
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the working directory for a specific drive.
|
||||
if (_getdcwd (letter + 1, dest, destLen) == NULL)
|
||||
{
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
|
||||
src += 2;
|
||||
#else /* if !defined(HAVE_CWD_PER_DRIVE) */
|
||||
// We treat paths of the form "d:foo/bar" as "d:/foo/bar".
|
||||
if (destLen < 3) {
|
||||
errno = ERANGE;
|
||||
return NULL;
|
||||
}
|
||||
dest[0] = src[0];
|
||||
dest[1] = ':';
|
||||
dest[2] = '/';
|
||||
*skipSrc = 2;
|
||||
dest += 3;
|
||||
return dest;
|
||||
#endif /* HAVE_CWD_PER_DRIVE */
|
||||
}
|
||||
else
|
||||
#endif /* HAVE_DRIVE_LETTERS */
|
||||
{
|
||||
// Relative dir
|
||||
if (getcwd (dest, destLen) == NULL)
|
||||
{
|
||||
// errno is set
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
size_t tempLen;
|
||||
tempLen = strlen (dest);
|
||||
if (tempLen == 0)
|
||||
{
|
||||
// getcwd() or _getdcwd() returned a 0-length string.
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
dest += tempLen;
|
||||
destLen -= tempLen;
|
||||
}
|
||||
if (dest[-1] != '/'
|
||||
#ifdef BACKSLASH_IS_PATH_SEPARATOR
|
||||
&& dest[-1] != '\\'
|
||||
#endif /* BACKSLASH_IS_PATH_SEPARATOR */
|
||||
)
|
||||
{
|
||||
// Need to add a slash.
|
||||
// There's always space, as we overwrite the '\0' that getcwd()
|
||||
// always returns.
|
||||
dest[0] = '/';
|
||||
dest++;
|
||||
destLen--;
|
||||
}
|
||||
|
||||
*skipSrc = (size_t) (src - orgSrc);
|
||||
return dest;
|
||||
}
|
||||
|
||||
// As strrchr, but starts searching from the indicated end of the string.
|
||||
static char *
|
||||
strrchr2(const char *start, int c, const char *end) {
|
||||
for (;;) {
|
||||
end--;
|
||||
if (end < start)
|
||||
return (char *) NULL;
|
||||
if (*end == c)
|
||||
return (char *) unconst(end);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_UNC_PATHS
|
||||
// returns 0 if the path is not a valid UNC path.
|
||||
// Does not skip trailing slashes.
|
||||
size_t
|
||||
skipUNCServerShare(const char *inPath) {
|
||||
const char *path = inPath;
|
||||
|
||||
// Skip the initial two backslashes.
|
||||
if (path[0] != '\\' || path[1] != '\\')
|
||||
return (size_t) 0;
|
||||
path += 2;
|
||||
|
||||
// Skip the server part.
|
||||
while (*path != '\\' && *path != '/') {
|
||||
if (*path == '\0')
|
||||
return (size_t) 0;
|
||||
path++;
|
||||
}
|
||||
|
||||
// Skip the seperator.
|
||||
path++;
|
||||
|
||||
// Skip the share part.
|
||||
while (*path != '\0' && *path != '\\' && *path != '/')
|
||||
path++;
|
||||
|
||||
return (size_t) (path - inPath);
|
||||
}
|
||||
#endif /* HAVE_UNC_PATHS */
|
||||
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// Contains code handling files
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "filintrn.h"
|
||||
#include "libs/memlib.h"
|
||||
#include "libs/log.h"
|
||||
|
||||
static int copyError(uio_Handle *srcHandle, uio_Handle *dstHandle,
|
||||
uio_DirHandle *unlinkHandle, const char *unlinkPath, uint8 *buf);
|
||||
|
||||
bool
|
||||
fileExists (const char *name)
|
||||
{
|
||||
return access (name, F_OK) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
fileExists2(uio_DirHandle *dir, const char *fileName)
|
||||
{
|
||||
uio_Stream *stream;
|
||||
|
||||
stream = uio_fopen (dir, fileName, "rb");
|
||||
if (stream == NULL)
|
||||
return 0;
|
||||
|
||||
uio_fclose (stream);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a file with path srcName to a file with name newName.
|
||||
* If the destination already exists, the operation fails.
|
||||
* Links are followed.
|
||||
* Special files (fifos, char devices, block devices, etc) will be
|
||||
* read as long as there is data available and the destination will be
|
||||
* a regular file with that data.
|
||||
* The new file will have the same permissions as the old.
|
||||
* If an error occurs during copying, an attempt will be made to
|
||||
* remove the copy.
|
||||
*/
|
||||
int
|
||||
copyFile (uio_DirHandle *srcDir, const char *srcName,
|
||||
uio_DirHandle *dstDir, const char *newName)
|
||||
{
|
||||
uio_Handle *src, *dst;
|
||||
struct stat sb;
|
||||
#define BUFSIZE 65536
|
||||
uint8 *buf, *bufPtr;
|
||||
ssize_t numInBuf, numWritten;
|
||||
|
||||
src = uio_open (srcDir, srcName, O_RDONLY
|
||||
#ifdef WIN32
|
||||
| O_BINARY
|
||||
#endif
|
||||
, 0);
|
||||
if (src == NULL)
|
||||
return -1;
|
||||
|
||||
if (uio_fstat (src, &sb) == -1)
|
||||
return copyError (src, NULL, NULL, NULL, NULL);
|
||||
|
||||
dst = uio_open (dstDir, newName, O_WRONLY | O_CREAT | O_EXCL
|
||||
#ifdef WIN32
|
||||
| O_BINARY
|
||||
#endif
|
||||
, sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
|
||||
if (dst == NULL)
|
||||
return copyError (src, NULL, NULL, NULL, NULL);
|
||||
|
||||
buf = HMalloc(BUFSIZE);
|
||||
// This was originally a statically allocated buffer,
|
||||
// but as this function might be run from a thread with
|
||||
// a small Stack, this is better.
|
||||
while (1)
|
||||
{
|
||||
numInBuf = uio_read (src, buf, BUFSIZE);
|
||||
if (numInBuf == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return copyError (src, dst, dstDir, newName, buf);
|
||||
}
|
||||
if (numInBuf == 0)
|
||||
break;
|
||||
|
||||
bufPtr = buf;
|
||||
do
|
||||
{
|
||||
numWritten = uio_write (dst, bufPtr, numInBuf);
|
||||
if (numWritten == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return copyError (src, dst, dstDir, newName, buf);
|
||||
}
|
||||
numInBuf -= numWritten;
|
||||
bufPtr += numWritten;
|
||||
} while (numInBuf > 0);
|
||||
}
|
||||
|
||||
HFree (buf);
|
||||
uio_close (src);
|
||||
uio_close (dst);
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes srcHandle if it's not -1.
|
||||
* Closes dstHandle if it's not -1.
|
||||
* Removes unlinkpath from the unlinkHandle dir if it's not NULL.
|
||||
* Frees 'buf' if not NULL.
|
||||
* Always returns -1.
|
||||
* errno is what was before the call.
|
||||
*/
|
||||
static int
|
||||
copyError(uio_Handle *srcHandle, uio_Handle *dstHandle,
|
||||
uio_DirHandle *unlinkHandle, const char *unlinkPath, uint8 *buf)
|
||||
{
|
||||
int savedErrno;
|
||||
|
||||
savedErrno = errno;
|
||||
|
||||
log_add (log_Debug, "Error while copying: %s", strerror (errno));
|
||||
|
||||
if (srcHandle != NULL)
|
||||
uio_close (srcHandle);
|
||||
|
||||
if (dstHandle != NULL)
|
||||
uio_close (dstHandle);
|
||||
|
||||
if (unlinkPath != NULL)
|
||||
uio_unlink (unlinkHandle, unlinkPath);
|
||||
|
||||
if (buf != NULL)
|
||||
HFree(buf);
|
||||
|
||||
errno = savedErrno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// Contains code handling temporary files and dirs
|
||||
|
||||
#ifndef _FILEINTRN_H
|
||||
|
||||
#include "../file.h"
|
||||
|
||||
#endif /* _FILEINTRN_H */
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// Contains code handling temporary files and dirs
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#ifdef WIN32
|
||||
# include <io.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "filintrn.h"
|
||||
#include "libs/timelib.h"
|
||||
#include "port.h"
|
||||
#include "libs/compiler.h"
|
||||
#include "libs/log.h"
|
||||
#include "libs/memlib.h"
|
||||
|
||||
static char *tempDirName;
|
||||
uio_DirHandle *tempDir;
|
||||
|
||||
static void
|
||||
removeTempDir (void)
|
||||
{
|
||||
rmdir (tempDirName);
|
||||
}
|
||||
|
||||
// Try if the null-terminated path 'dir' to a directory is valid
|
||||
// as temp path.
|
||||
// On success, 'buf' will be filled with the path, with a trailing /,
|
||||
// null-terminated, and 0 is returned.
|
||||
// On failure, EINVAL, ENAMETOOLONG, or one of the errors access() can return
|
||||
// is returned, and the contents of buf is unspecified.
|
||||
static int
|
||||
tryTempDir (char *buf, size_t buflen, const char *dir)
|
||||
{
|
||||
size_t len;
|
||||
int haveSlash;
|
||||
|
||||
if (dir == NULL)
|
||||
return EINVAL;
|
||||
|
||||
if (dir[0] == '\0')
|
||||
return EINVAL;
|
||||
|
||||
len = strlen (dir);
|
||||
haveSlash = (dir[len - 1] == '/'
|
||||
#ifdef WIN32
|
||||
|| dir[len - 1] == '\\'
|
||||
#endif
|
||||
);
|
||||
if ((haveSlash ? len : len + 1) >= buflen)
|
||||
return ENAMETOOLONG;
|
||||
|
||||
strcpy (buf, dir);
|
||||
#if 0
|
||||
//def WIN32
|
||||
{
|
||||
char *bufPtr;
|
||||
for (bufPtr = buf; *bufPtr != '\0'; bufPtr++)
|
||||
{
|
||||
if (*bufPtr == '\\')
|
||||
*bufPtr = '/';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!haveSlash)
|
||||
{
|
||||
buf[len] = '/';
|
||||
len++;
|
||||
buf[len] = '\0';
|
||||
}
|
||||
if (access (buf, R_OK | W_OK) == -1)
|
||||
return errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
getTempDir (char *buf, size_t buflen) {
|
||||
char cwd[PATH_MAX];
|
||||
|
||||
if (tryTempDir (buf, buflen, getenv("TMP")) &&
|
||||
tryTempDir (buf, buflen, getenv("TEMP")) &&
|
||||
#if !defined(WIN32) || defined (__CYGWIN__)
|
||||
tryTempDir (buf, buflen, "/tmp/") &&
|
||||
tryTempDir (buf, buflen, "/var/tmp/") &&
|
||||
#endif
|
||||
tryTempDir (buf, buflen, getcwd (cwd, sizeof cwd)))
|
||||
{
|
||||
log_add (log_Fatal, "Fatal Error: Cannot find a suitable location "
|
||||
"to store temporary files.");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the global var 'tempDir'
|
||||
static int
|
||||
mountTempDir(const char *name) {
|
||||
static uio_AutoMount *autoMount[] = { NULL };
|
||||
uio_MountHandle *tempHandle;
|
||||
extern uio_Repository *repository;
|
||||
|
||||
tempHandle = uio_mountDir (repository, "/tmp/",
|
||||
uio_FSTYPE_STDIO, NULL, NULL, name, autoMount,
|
||||
uio_MOUNT_TOP, NULL);
|
||||
if (tempHandle == NULL) {
|
||||
int saveErrno = errno;
|
||||
log_add (log_Fatal, "Fatal error: Couldn't mount temp dir '%s': "
|
||||
"%s", name, strerror (errno));
|
||||
errno = saveErrno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tempDir = uio_openDir (repository, "/tmp", 0);
|
||||
if (tempDir == NULL) {
|
||||
int saveErrno = errno;
|
||||
log_add (log_Fatal, "Fatal error: Could not open temp dir: %s",
|
||||
strerror (errno));
|
||||
errno = saveErrno;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NUM_TEMP_RETRIES 16
|
||||
// Number of files to try to open before giving up.
|
||||
void
|
||||
initTempDir (void) {
|
||||
size_t len;
|
||||
DWORD num;
|
||||
int i;
|
||||
char *tempPtr;
|
||||
// Pointer to the location in the tempDirName string where the
|
||||
// path to the temp dir ends and the dir starts.
|
||||
|
||||
tempDirName = HMalloc (PATH_MAX);
|
||||
getTempDir (tempDirName, PATH_MAX - 21);
|
||||
// reserve 8 chars for dirname, 1 for slash, and 12 for filename
|
||||
len = strlen(tempDirName);
|
||||
|
||||
num = ((DWORD) time (NULL));
|
||||
// num = GetTimeCounter () % 0xffffffff;
|
||||
tempPtr = tempDirName + len;
|
||||
for (i = 0; i < NUM_TEMP_RETRIES; i++)
|
||||
{
|
||||
sprintf (tempPtr, "%08x", num + i);
|
||||
if (createDirectory (tempDirName, 0700) == -1)
|
||||
continue;
|
||||
|
||||
// Success, we've got a temp dir.
|
||||
tempDirName = HRealloc (tempDirName, len + 9);
|
||||
atexit (removeTempDir);
|
||||
if (mountTempDir (tempDirName) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Failure, could not make a temporary directory.
|
||||
log_add (log_Fatal, "Fatal error: Cannot get a name for a temporary "
|
||||
"directory.");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void
|
||||
unInitTempDir (void) {
|
||||
uio_closeDir(tempDir);
|
||||
// the removing of the dir is handled via atexit
|
||||
}
|
||||
|
||||
// return the path to a file in the temp dir with the specified filename.
|
||||
// returns a pointer to a static buffer.
|
||||
char *
|
||||
tempFilePath (const char *filename) {
|
||||
static char file[PATH_MAX];
|
||||
|
||||
if (snprintf (file, PATH_MAX, "%s/%s", tempDirName, filename) == -1) {
|
||||
log_add (log_Fatal, "Path to temp file too long.");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,457 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _GFXLIB_H
|
||||
#define _GFXLIB_H
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/compiler.h"
|
||||
|
||||
typedef struct Color Color;
|
||||
struct Color {
|
||||
BYTE r;
|
||||
BYTE g;
|
||||
BYTE b;
|
||||
BYTE a;
|
||||
};
|
||||
|
||||
#include "libs/reslib.h"
|
||||
|
||||
typedef struct context_desc CONTEXT_DESC;
|
||||
typedef struct frame_desc FRAME_DESC;
|
||||
typedef struct font_desc FONT_DESC;
|
||||
typedef struct drawable_desc DRAWABLE_DESC;
|
||||
|
||||
typedef CONTEXT_DESC *CONTEXT;
|
||||
typedef FRAME_DESC *FRAME;
|
||||
typedef FONT_DESC *FONT;
|
||||
typedef DRAWABLE_DESC *DRAWABLE;
|
||||
|
||||
typedef UWORD TIME_VALUE;
|
||||
|
||||
#define TIME_SHIFT 8
|
||||
#define MAX_TIME_VALUE ((1 << TIME_SHIFT) + 1)
|
||||
|
||||
typedef SWORD COORD;
|
||||
|
||||
static inline bool
|
||||
sameColor(Color c1, Color c2)
|
||||
{
|
||||
return c1.r == c2.r &&
|
||||
c1.g == c2.g &&
|
||||
c1.b == c2.b &&
|
||||
c1.a == c2.a;
|
||||
}
|
||||
|
||||
// Transform a 5-bits color component to an 8-bits color component.
|
||||
// Form 1, calculates '(r5 / 31.0) * 255.0, highest value is 0xff:
|
||||
#define CC5TO8(c) (((c) << 3) | ((c) >> 2))
|
||||
// Form 2, calculates '(r5 / 32.0) * 256.0, highest value is 0xf8:
|
||||
//#define CC5TO8(c) ((c) << 3)
|
||||
|
||||
#define BUILD_COLOR(col, c256) col
|
||||
// BUILD_COLOR used to combine a 15-bit RGB color tripple with a
|
||||
// destination VGA palette index into a 32-bit value.
|
||||
// Now, it is an empty wrapper which returns the first argument,
|
||||
// which is of type Color, and ignores the second argument,
|
||||
// the palette index.
|
||||
//
|
||||
// It is a remnant of 8bpp hardware paletted display (VGA).
|
||||
// The palette index would be overwritten with the RGB value
|
||||
// and the drawing op would use this index on screen.
|
||||
// The palette indices 0-15, as used in DOS SC2, are unchanged
|
||||
// from the standard VGA palette and are identical to 16-color EGA.
|
||||
// Various frames, borders, menus, etc. frequently refer to these
|
||||
// first 16 colors and normally do not change the RGB values from
|
||||
// the standard ones (see colors.h; most likely unchanged from SC1)
|
||||
// The palette index is meaningless in UQM for the most part.
|
||||
// New code should just use index 0.
|
||||
|
||||
// Turn a 15 bits color into a 24-bits color.
|
||||
// r, g, and b are each 5-bits color components.
|
||||
static inline Color
|
||||
colorFromRgb15 (BYTE r, BYTE g, BYTE b)
|
||||
{
|
||||
Color c;
|
||||
c.r = CC5TO8 (r);
|
||||
c.g = CC5TO8 (g);
|
||||
c.b = CC5TO8 (b);
|
||||
c.a = 0xff;
|
||||
|
||||
return c;
|
||||
}
|
||||
#define MAKE_RGB15(r, g, b) colorFromRgb15 ((r), (g), (b))
|
||||
|
||||
#ifdef NOTYET /* Need C'99 support */
|
||||
#define MAKE_RGB15(r, g, b) (Color) { \
|
||||
.r = CC5TO8 (r), \
|
||||
.g = CC5TO8 (g), \
|
||||
.b = CC5TO8 (b), \
|
||||
.a = 0xff \
|
||||
}
|
||||
#endif
|
||||
|
||||
// Temporary, until we can use C'99 features. Then MAKE_RGB15 will be usable
|
||||
// anywhere.
|
||||
// This define is intended for global initialisations, where the
|
||||
// expression must be constant.
|
||||
#define MAKE_RGB15_INIT(r, g, b) { \
|
||||
CC5TO8 (r), \
|
||||
CC5TO8 (g), \
|
||||
CC5TO8 (b), \
|
||||
0xff \
|
||||
}
|
||||
|
||||
static inline Color
|
||||
buildColorRgba (BYTE r, BYTE g, BYTE b, BYTE a)
|
||||
{
|
||||
Color c;
|
||||
c.r = r;
|
||||
c.g = g;
|
||||
c.b = b;
|
||||
c.a = a;
|
||||
|
||||
return c;
|
||||
}
|
||||
#define BUILD_COLOR_RGBA(r, g, b, a) \
|
||||
buildColorRgba ((r), (g), (b), (a))
|
||||
|
||||
|
||||
typedef BYTE CREATE_FLAGS;
|
||||
// WANT_MASK is deprecated (and non-functional). It used to generate a bitmap
|
||||
// of changed pixels for a target DRAWABLE, so that DRAW_SUBTRACTIVE could
|
||||
// paint background pixels over them, i.e. a revert draw. The backgrounds
|
||||
// are fully erased now instead.
|
||||
#define WANT_MASK (CREATE_FLAGS)(1 << 0)
|
||||
#define WANT_PIXMAP (CREATE_FLAGS)(1 << 1)
|
||||
// MAPPED_TO_DISPLAY is deprecated but still checked by LoadDisplayPixmap().
|
||||
// Its former use was to indicate a pre-scaled graphic for the display.
|
||||
#define MAPPED_TO_DISPLAY (CREATE_FLAGS)(1 << 2)
|
||||
#define WANT_ALPHA (CREATE_FLAGS)(1 << 3)
|
||||
|
||||
typedef struct extent
|
||||
{
|
||||
COORD width, height;
|
||||
} EXTENT;
|
||||
|
||||
typedef struct point
|
||||
{
|
||||
COORD x, y;
|
||||
} POINT;
|
||||
|
||||
typedef struct stamp
|
||||
{
|
||||
POINT origin;
|
||||
FRAME frame;
|
||||
} STAMP;
|
||||
|
||||
typedef struct rect
|
||||
{
|
||||
POINT corner;
|
||||
EXTENT extent;
|
||||
} RECT;
|
||||
|
||||
typedef struct line
|
||||
{
|
||||
POINT first, second;
|
||||
} LINE;
|
||||
|
||||
static inline POINT
|
||||
MAKE_POINT (COORD x, COORD y)
|
||||
{
|
||||
POINT pt = {x, y};
|
||||
return pt;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
pointsEqual (POINT p1, POINT p2)
|
||||
{
|
||||
return p1.x == p2.x && p1.y == p2.y;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
extentsEqual (EXTENT e1, EXTENT e2)
|
||||
{
|
||||
return e1.width == e2.width && e1.height == e2.height;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
rectsEqual (RECT r1, RECT r2)
|
||||
{
|
||||
return pointsEqual (r1.corner, r2.corner)
|
||||
&& extentsEqual (r1.extent, r2.extent);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
pointWithinRect (RECT r, POINT p)
|
||||
{
|
||||
return p.x >= r.corner.x && p.y >= r.corner.y
|
||||
&& p.x < r.corner.x + r.extent.width
|
||||
&& p.y < r.corner.y + r.extent.height;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ALIGN_LEFT,
|
||||
ALIGN_CENTER,
|
||||
ALIGN_RIGHT
|
||||
} TEXT_ALIGN;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VALIGN_TOP,
|
||||
VALIGN_MIDDLE,
|
||||
VALIGN_BOTTOM
|
||||
} TEXT_VALIGN;
|
||||
|
||||
typedef struct text
|
||||
{
|
||||
POINT baseline;
|
||||
const UNICODE *pStr;
|
||||
TEXT_ALIGN align;
|
||||
COUNT CharCount;
|
||||
} TEXT;
|
||||
|
||||
#include "libs/strlib.h"
|
||||
|
||||
typedef STRING_TABLE COLORMAP_REF;
|
||||
typedef STRING COLORMAP;
|
||||
// COLORMAPPTR is really a pointer to colortable entry structure
|
||||
// which is documented in doc/devel/strtab, .ct files section
|
||||
typedef void *COLORMAPPTR;
|
||||
|
||||
#include "graphics/prim.h"
|
||||
|
||||
typedef BYTE BATCH_FLAGS;
|
||||
// This flag is currently unused but it might make sense to restore it
|
||||
#define BATCH_BUILD_PAGE (BATCH_FLAGS)(1 << 0)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TIME_VALUE last_time_val;
|
||||
POINT EndPoint;
|
||||
STAMP IntersectStamp;
|
||||
} INTERSECT_CONTROL;
|
||||
|
||||
typedef BYTE INTERSECT_CODE;
|
||||
|
||||
#define INTERSECT_LEFT (INTERSECT_CODE)(1 << 0)
|
||||
#define INTERSECT_TOP (INTERSECT_CODE)(1 << 1)
|
||||
#define INTERSECT_RIGHT (INTERSECT_CODE)(1 << 2)
|
||||
#define INTERSECT_BOTTOM (INTERSECT_CODE)(1 << 3)
|
||||
#define INTERSECT_NOCLIP (INTERSECT_CODE)(1 << 7)
|
||||
#define INTERSECT_ALL_SIDES (INTERSECT_CODE)(INTERSECT_LEFT | \
|
||||
INTERSECT_TOP | \
|
||||
INTERSECT_RIGHT | \
|
||||
INTERSECT_BOTTOM)
|
||||
|
||||
typedef POINT HOT_SPOT;
|
||||
|
||||
extern HOT_SPOT MAKE_HOT_SPOT (COORD, COORD);
|
||||
|
||||
extern INTERSECT_CODE BoxIntersect (RECT *pr1, RECT *pr2, RECT *printer);
|
||||
extern void BoxUnion (RECT *pr1, RECT *pr2, RECT *punion);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FadeAllToWhite = 250,
|
||||
FadeSomeToWhite,
|
||||
FadeAllToBlack,
|
||||
FadeAllToColor,
|
||||
FadeSomeToBlack,
|
||||
FadeSomeToColor
|
||||
} ScreenFadeType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DRAW_REPLACE = 0,
|
||||
// Pixels in the target FRAME are replaced entirely.
|
||||
// Non-stamp primitives with Color.a < 255 to RGB targets are
|
||||
// equivalent to DRAW_ALPHA with (DrawMode.factor = Color.a),
|
||||
// except the Text primitives.
|
||||
// DrawMode.factor: ignored
|
||||
// Text: supported (except DRAW_ALPHA via Color.a)
|
||||
// RGBA sources (WANT_ALPHA): per-pixel alpha blending performed
|
||||
// RGBA targets (WANT_ALPHA): replace directly supported
|
||||
DRAW_ADDITIVE,
|
||||
// Pixel channels of the source FRAME or Color channels of
|
||||
// a primitive are modulated by (DrawMode.factor / 255) and added
|
||||
// to the pixel channels of the target FRAME.
|
||||
// DrawMode.factor range: -32767..32767 (negative values make
|
||||
// draw subtractive); 255 = 1:1 ratio
|
||||
// Text: not yet supported
|
||||
// RGBA sources (WANT_ALPHA): alpha channel ignored
|
||||
// RGBA targets (WANT_ALPHA): not yet supported
|
||||
DRAW_ALPHA,
|
||||
// Pixel channels of the source FRAME or Color channels of
|
||||
// a primitive are modulated by (DrawMode.factor / 255) and added
|
||||
// to the pixel channels of the target FRAME, modulated by
|
||||
// (1 - DrawMode.factor / 255)
|
||||
// DrawMode.factor range: 0..255; 255 = fully opaque
|
||||
// Text: supported
|
||||
// RGBA sources (WANT_ALPHA): alpha channel ignored
|
||||
// RGBA targets (WANT_ALPHA): not yet supported
|
||||
|
||||
DRAW_DEFAULT = DRAW_REPLACE,
|
||||
} DrawKind;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE kind;
|
||||
SWORD factor;
|
||||
} DrawMode;
|
||||
|
||||
#define DRAW_REPLACE_MODE MAKE_DRAW_MODE (DRAW_REPLACE, 0)
|
||||
#define DRAW_FACTOR_1 0xff
|
||||
|
||||
static inline DrawMode
|
||||
MAKE_DRAW_MODE (DrawKind kind, SWORD factor)
|
||||
{
|
||||
DrawMode mode;
|
||||
mode.kind = kind;
|
||||
mode.factor = factor;
|
||||
return mode;
|
||||
}
|
||||
|
||||
extern CONTEXT SetContext (CONTEXT Context);
|
||||
extern Color SetContextForeGroundColor (Color Color);
|
||||
extern Color GetContextForeGroundColor (void);
|
||||
extern Color SetContextBackGroundColor (Color Color);
|
||||
extern Color GetContextBackGroundColor (void);
|
||||
extern FRAME SetContextFGFrame (FRAME Frame);
|
||||
extern FRAME GetContextFGFrame (void);
|
||||
// Context cliprect defines the drawing bounds. Additionally, all
|
||||
// drawing positions (x,y) are relative to the cliprect corner.
|
||||
extern BOOLEAN SetContextClipRect (RECT *pRect);
|
||||
// The returned rect is always filled in. If the context cliprect
|
||||
// is undefined, the returned rect has foreground frame dimensions.
|
||||
extern BOOLEAN GetContextClipRect (RECT *pRect);
|
||||
// The actual origin will be orgOffset + context ClipRect.corner
|
||||
extern POINT SetContextOrigin (POINT orgOffset);
|
||||
extern DrawMode SetContextDrawMode (DrawMode);
|
||||
extern DrawMode GetContextDrawMode (void);
|
||||
// 'area' may be NULL to copy the entire CONTEXT cliprect
|
||||
// 'area' is relative to the CONTEXT cliprect
|
||||
extern DRAWABLE CopyContextRect (const RECT* area);
|
||||
|
||||
extern TIME_VALUE DrawablesIntersect (INTERSECT_CONTROL *pControl0,
|
||||
INTERSECT_CONTROL *pControl1, TIME_VALUE max_time_val);
|
||||
extern void DrawStamp (STAMP *pStamp);
|
||||
extern void DrawFilledStamp (STAMP *pStamp);
|
||||
extern void DrawPoint (POINT *pPoint);
|
||||
extern void DrawRectangle (RECT *pRect);
|
||||
extern void DrawFilledRectangle (RECT *pRect);
|
||||
extern void DrawLine (LINE *pLine);
|
||||
extern void font_DrawText (TEXT *pText);
|
||||
extern void font_DrawTracedText (TEXT *pText, Color text, Color trace);
|
||||
extern void DrawBatch (PRIMITIVE *pBasePrim, PRIM_LINKS PrimLinks,
|
||||
BATCH_FLAGS BatchFlags);
|
||||
extern void BatchGraphics (void);
|
||||
extern void UnbatchGraphics (void);
|
||||
extern void FlushGraphics (void);
|
||||
extern void ClearDrawable (void);
|
||||
#ifdef DEBUG
|
||||
extern CONTEXT CreateContextAux (const char *name);
|
||||
#define CreateContext(name) CreateContextAux((name))
|
||||
#else /* if !defined(DEBUG) */
|
||||
extern CONTEXT CreateContextAux (void);
|
||||
#define CreateContext(name) CreateContextAux()
|
||||
#endif /* !defined(DEBUG) */
|
||||
extern BOOLEAN DestroyContext (CONTEXT ContextRef);
|
||||
extern DRAWABLE CreateDisplay (CREATE_FLAGS CreateFlags, SIZE *pwidth,
|
||||
SIZE *pheight);
|
||||
extern DRAWABLE CreateDrawable (CREATE_FLAGS CreateFlags, SIZE width,
|
||||
SIZE height, COUNT num_frames);
|
||||
extern BOOLEAN DestroyDrawable (DRAWABLE Drawable);
|
||||
extern BOOLEAN GetFrameRect (FRAME Frame, RECT *pRect);
|
||||
#ifdef DEBUG
|
||||
extern const char *GetContextName (CONTEXT context);
|
||||
extern CONTEXT GetFirstContext (void);
|
||||
extern CONTEXT GetNextContext (CONTEXT context);
|
||||
extern size_t GetContextCount (void);
|
||||
#endif /* DEBUG */
|
||||
|
||||
extern HOT_SPOT SetFrameHot (FRAME Frame, HOT_SPOT HotSpot);
|
||||
extern HOT_SPOT GetFrameHot (FRAME Frame);
|
||||
extern BOOLEAN InstallGraphicResTypes (void);
|
||||
extern DRAWABLE LoadGraphicFile (const char *pStr);
|
||||
extern FONT LoadFontFile (const char *pStr);
|
||||
extern void *LoadGraphicInstance (RESOURCE res);
|
||||
extern DRAWABLE LoadDisplayPixmap (const RECT *area, FRAME frame);
|
||||
extern FRAME SetContextFontEffect (FRAME EffectFrame);
|
||||
extern FONT SetContextFont (FONT Font);
|
||||
extern BOOLEAN DestroyFont (FONT FontRef);
|
||||
// The returned pRect is relative to the context drawing origin
|
||||
extern BOOLEAN TextRect (TEXT *pText, RECT *pRect, BYTE *pdelta);
|
||||
extern BOOLEAN GetContextFontLeading (SIZE *pheight);
|
||||
extern BOOLEAN GetContextFontLeadingWidth (SIZE *pwidth);
|
||||
extern COUNT GetFrameCount (FRAME Frame);
|
||||
extern COUNT GetFrameIndex (FRAME Frame);
|
||||
extern FRAME SetAbsFrameIndex (FRAME Frame, COUNT FrameIndex);
|
||||
extern FRAME SetRelFrameIndex (FRAME Frame, SIZE FrameOffs);
|
||||
extern FRAME SetEquFrameIndex (FRAME DstFrame, FRAME SrcFrame);
|
||||
extern FRAME IncFrameIndex (FRAME Frame);
|
||||
extern FRAME DecFrameIndex (FRAME Frame);
|
||||
extern DRAWABLE CopyFrameRect (FRAME Frame, const RECT *area);
|
||||
extern DRAWABLE CloneFrame (FRAME Frame);
|
||||
extern DRAWABLE RotateFrame (FRAME Frame, int angle_deg);
|
||||
extern DRAWABLE RescaleFrame (FRAME, int width, int height);
|
||||
// This pair works for both paletted and trucolor frames
|
||||
extern BOOLEAN ReadFramePixelColors (FRAME frame, Color *pixels,
|
||||
int width, int height);
|
||||
extern BOOLEAN WriteFramePixelColors (FRAME frame, const Color *pixels,
|
||||
int width, int height);
|
||||
// This pair only works for paletted frames
|
||||
extern BOOLEAN ReadFramePixelIndexes (FRAME frame, BYTE *pixels,
|
||||
int width, int height);
|
||||
extern BOOLEAN WriteFramePixelIndexes (FRAME frame, const BYTE *pixels,
|
||||
int width, int height);
|
||||
extern void SetFrameTransparentColor (FRAME, Color);
|
||||
|
||||
// If the frame is an active SCREEN_DRAWABLE, this call must be
|
||||
// preceeded by FlushGraphics() for draw commands to have taken effect
|
||||
extern Color GetFramePixel (FRAME, POINT pixelPt);
|
||||
|
||||
extern FRAME CaptureDrawable (DRAWABLE Drawable);
|
||||
extern DRAWABLE ReleaseDrawable (FRAME Frame);
|
||||
|
||||
extern DRAWABLE GetFrameParentDrawable (FRAME Frame);
|
||||
|
||||
extern BOOLEAN SetColorMap (COLORMAPPTR ColorMapPtr);
|
||||
extern DWORD XFormColorMap (COLORMAPPTR ColorMapPtr, SIZE TimeInterval);
|
||||
extern DWORD FadeScreen (ScreenFadeType fadeType, SIZE TimeInterval);
|
||||
extern void FlushColorXForms (void);
|
||||
#define InitColorMapResources InitStringTableResources
|
||||
#define LoadColorMapFile LoadStringTableFile
|
||||
#define LoadColorMapInstance LoadStringTableInstance
|
||||
#define CaptureColorMap CaptureStringTable
|
||||
#define ReleaseColorMap ReleaseStringTable
|
||||
#define DestroyColorMap DestroyStringTable
|
||||
#define GetColorMapRef GetStringTable
|
||||
#define GetColorMapCount GetStringTableCount
|
||||
#define GetColorMapIndex GetStringTableIndex
|
||||
#define SetAbsColorMapIndex SetAbsStringTableIndex
|
||||
#define SetRelColorMapIndex SetRelStringTableIndex
|
||||
#define GetColorMapLength GetStringLengthBin
|
||||
|
||||
extern COLORMAPPTR GetColorMapAddress (COLORMAP);
|
||||
|
||||
void SetSystemRect (const RECT *pRect);
|
||||
void ClearSystemRect (void);
|
||||
|
||||
#endif /* _GFXLIB_H */
|
||||
@@ -1,9 +0,0 @@
|
||||
if [ "$uqm_GFXMODULE" = "sdl" ]; then
|
||||
uqm_SUBDIRS="sdl"
|
||||
fi
|
||||
|
||||
uqm_CFILES="boxint.c clipline.c cmap.c context.c drawable.c filegfx.c
|
||||
bbox.c dcqueue.c gfxload.c
|
||||
font.c frame.c gfx_common.c intersec.c loaddisp.c
|
||||
pixmap.c resgfx.c tfb_draw.c tfb_prim.c widgets.c"
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/graphics/bbox.h"
|
||||
|
||||
TFB_BoundingBox TFB_BBox;
|
||||
int maxWidth;
|
||||
int maxHeight;
|
||||
|
||||
void
|
||||
TFB_BBox_Init (int width, int height)
|
||||
{
|
||||
maxWidth = width;
|
||||
maxHeight = height;
|
||||
TFB_BBox.clip.extent.width = width;
|
||||
TFB_BBox.clip.extent.height = height;
|
||||
}
|
||||
|
||||
void
|
||||
TFB_BBox_Reset (void)
|
||||
{
|
||||
TFB_BBox.valid = 0;
|
||||
}
|
||||
|
||||
void
|
||||
TFB_BBox_SetClipRect (const RECT *r)
|
||||
{
|
||||
if (!r)
|
||||
{ /* No clipping -- full rect */
|
||||
TFB_BBox.clip.corner.x = 0;
|
||||
TFB_BBox.clip.corner.y = 0;
|
||||
TFB_BBox.clip.extent.width = maxWidth;
|
||||
TFB_BBox.clip.extent.height = maxHeight;
|
||||
return;
|
||||
}
|
||||
|
||||
TFB_BBox.clip = *r;
|
||||
|
||||
/* Make sure the cliprect is sane */
|
||||
if (TFB_BBox.clip.corner.x < 0)
|
||||
TFB_BBox.clip.corner.x = 0;
|
||||
|
||||
if (TFB_BBox.clip.corner.y < 0)
|
||||
TFB_BBox.clip.corner.y = 0;
|
||||
|
||||
if (TFB_BBox.clip.corner.x + TFB_BBox.clip.extent.width > maxWidth)
|
||||
TFB_BBox.clip.extent.width = maxWidth - TFB_BBox.clip.corner.x;
|
||||
|
||||
if (TFB_BBox.clip.corner.y + TFB_BBox.clip.extent.height > maxHeight)
|
||||
TFB_BBox.clip.extent.height = maxHeight - TFB_BBox.clip.corner.y;
|
||||
}
|
||||
|
||||
void
|
||||
TFB_BBox_RegisterPoint (int x, int y)
|
||||
{
|
||||
int x1 = TFB_BBox.clip.corner.x;
|
||||
int y1 = TFB_BBox.clip.corner.y;
|
||||
int x2 = TFB_BBox.clip.corner.x + TFB_BBox.clip.extent.width - 1;
|
||||
int y2 = TFB_BBox.clip.corner.y + TFB_BBox.clip.extent.height - 1;
|
||||
|
||||
/* Constrain coordinates */
|
||||
if (x < x1) x = x1;
|
||||
if (x >= x2) x = x2;
|
||||
if (y < y1) y = y1;
|
||||
if (y >= y2) y = y2;
|
||||
|
||||
/* Is this the first point? If so, set a pixel-region and return. */
|
||||
if (!TFB_BBox.valid)
|
||||
{
|
||||
TFB_BBox.valid = 1;
|
||||
TFB_BBox.region.corner.x = x;
|
||||
TFB_BBox.region.corner.y = y;
|
||||
TFB_BBox.region.extent.width = 1;
|
||||
TFB_BBox.region.extent.height = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise expand the rectangle if necessary. */
|
||||
x1 = TFB_BBox.region.corner.x;
|
||||
y1 = TFB_BBox.region.corner.y;
|
||||
x2 = TFB_BBox.region.corner.x + TFB_BBox.region.extent.width - 1;
|
||||
y2 = TFB_BBox.region.corner.y + TFB_BBox.region.extent.height - 1;
|
||||
|
||||
if (x < x1) {
|
||||
TFB_BBox.region.corner.x = x;
|
||||
TFB_BBox.region.extent.width += x1 - x;
|
||||
}
|
||||
if (y < y1) {
|
||||
TFB_BBox.region.corner.y = y;
|
||||
TFB_BBox.region.extent.height += y1 - y;
|
||||
}
|
||||
if (x > x2) {
|
||||
TFB_BBox.region.extent.width += x - x2;
|
||||
}
|
||||
if (y > y2) {
|
||||
TFB_BBox.region.extent.height += y - y2;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TFB_BBox_RegisterRect (const RECT *r)
|
||||
{
|
||||
/* RECT will still register as a corner point of the cliprect even
|
||||
* if it does not intersect with the cliprect at all. This is not
|
||||
* a problem, as more is not less. */
|
||||
TFB_BBox_RegisterPoint (r->corner.x, r->corner.y);
|
||||
TFB_BBox_RegisterPoint (r->corner.x + r->extent.width - 1,
|
||||
r->corner.y + r->extent.height - 1);
|
||||
}
|
||||
|
||||
void
|
||||
TFB_BBox_RegisterCanvas (TFB_Canvas c, int x, int y)
|
||||
{
|
||||
RECT r;
|
||||
r.corner.x = x;
|
||||
r.corner.y = y;
|
||||
TFB_DrawCanvas_GetExtent (c, &r.extent);
|
||||
TFB_BBox_RegisterRect (&r);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef BBOX_H_INCL__
|
||||
#define BBOX_H_INCL__
|
||||
|
||||
#include "libs/gfxlib.h"
|
||||
#include "libs/graphics/tfb_draw.h"
|
||||
|
||||
/* Bounding Box operations. These operations are NOT synchronized.
|
||||
* However, they should only be accessed by TFB_FlushGraphics and
|
||||
* TFB_SwapBuffers, or the routines that they exclusively call -- all
|
||||
* of which are only callable by the thread that is permitted to touch
|
||||
* the screen. No explicit locks should therefore be required. */
|
||||
|
||||
typedef struct {
|
||||
int valid; // If zero, the next point registered becomes the region
|
||||
RECT region; // The actual modified rectangle
|
||||
RECT clip; // Points outside of this rectangle are pushed to
|
||||
// the closest border point
|
||||
} TFB_BoundingBox;
|
||||
|
||||
extern TFB_BoundingBox TFB_BBox;
|
||||
|
||||
void TFB_BBox_RegisterPoint (int x, int y);
|
||||
void TFB_BBox_RegisterRect (const RECT *r);
|
||||
void TFB_BBox_RegisterCanvas (TFB_Canvas c, int x, int y);
|
||||
|
||||
void TFB_BBox_Init (int width, int height);
|
||||
void TFB_BBox_Reset (void);
|
||||
void TFB_BBox_SetClipRect (const RECT *r);
|
||||
|
||||
#endif /* BBOX_H_INCL__ */
|
||||
@@ -1,183 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "gfxintrn.h"
|
||||
|
||||
#undef MIN
|
||||
#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
|
||||
#undef MAX
|
||||
#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
|
||||
|
||||
INTERSECT_CODE
|
||||
BoxIntersect (RECT *pr1, RECT *pr2, RECT *pinter)
|
||||
{
|
||||
INTERSECT_CODE intersect_code;
|
||||
COORD x1;
|
||||
SIZE w1, w2, delta;
|
||||
|
||||
intersect_code = INTERSECT_NOCLIP;
|
||||
|
||||
x1 = pr1->corner.x - pr2->corner.x;
|
||||
|
||||
w1 = pr1->extent.width;
|
||||
w2 = pr2->extent.width;
|
||||
if ((delta = w2 - x1) <= w1)
|
||||
{
|
||||
if (delta != w1)
|
||||
{
|
||||
w1 = delta;
|
||||
intersect_code &= ~INTERSECT_NOCLIP;
|
||||
}
|
||||
intersect_code |= INTERSECT_RIGHT;
|
||||
}
|
||||
if (x1 <= 0)
|
||||
{
|
||||
if (x1 < 0)
|
||||
{
|
||||
w1 += x1;
|
||||
x1 = 0;
|
||||
intersect_code &= ~INTERSECT_NOCLIP;
|
||||
}
|
||||
intersect_code |= INTERSECT_LEFT;
|
||||
}
|
||||
|
||||
if (w1 > 0)
|
||||
{
|
||||
#define h2 w2
|
||||
COORD y1;
|
||||
SIZE h1;
|
||||
|
||||
y1 = pr1->corner.y - pr2->corner.y;
|
||||
|
||||
h1 = pr1->extent.height;
|
||||
h2 = pr2->extent.height;
|
||||
if ((delta = h2 - y1) <= h1)
|
||||
{
|
||||
if (delta != h1)
|
||||
{
|
||||
h1 = delta;
|
||||
intersect_code &= ~INTERSECT_NOCLIP;
|
||||
}
|
||||
intersect_code |= INTERSECT_BOTTOM;
|
||||
}
|
||||
if (y1 <= 0)
|
||||
{
|
||||
if (y1 < 0)
|
||||
{
|
||||
h1 += y1;
|
||||
y1 = 0;
|
||||
intersect_code &= ~INTERSECT_NOCLIP;
|
||||
}
|
||||
intersect_code |= INTERSECT_TOP;
|
||||
}
|
||||
|
||||
if (h1 > 0)
|
||||
{
|
||||
pinter->corner.x = x1 + pr2->corner.x;
|
||||
pinter->corner.y = y1 + pr2->corner.y;
|
||||
pinter->extent.width = w1;
|
||||
pinter->extent.height = h1;
|
||||
|
||||
return (intersect_code);
|
||||
}
|
||||
#undef h2
|
||||
}
|
||||
|
||||
return ((INTERSECT_CODE)0);
|
||||
}
|
||||
|
||||
void
|
||||
BoxUnion (RECT *pr1, RECT *pr2, RECT *punion)
|
||||
{
|
||||
#if NEVER // Part of lower FIXME.
|
||||
COORD x2, y2, w2, h2;
|
||||
#endif // NEVER
|
||||
|
||||
// Union is A AND B, put together, correct? Returns a bigger box that
|
||||
// encompasses the two.
|
||||
punion->corner.x = MIN(pr1->corner.x, pr2->corner.x);
|
||||
punion->corner.y = MIN(pr1->corner.y, pr2->corner.y);
|
||||
|
||||
punion->extent.width = MAX(pr1->corner.x + pr1->extent.width,
|
||||
pr2->corner.x + pr2->extent.width) - punion->corner.x;
|
||||
punion->extent.height = MAX(pr1->corner.y + pr1->extent.height,
|
||||
pr2->corner.y + pr2->extent.height) - punion->corner.y;
|
||||
|
||||
|
||||
#if NEVER // FIXME - I think this is broken, but keeping it around for reference
|
||||
// FIXME - just in case.
|
||||
|
||||
#if 1 /* alter based on 0 widths */
|
||||
|
||||
x2 =
|
||||
(pr1->corner.x < pr2->corner.x)? pr1->corner.x : pr2->corner.x;
|
||||
|
||||
y2 =
|
||||
(pr1->corner.y < pr2->corner.y)? pr1->corner.y : pr2->corner.y;
|
||||
|
||||
w2 = (
|
||||
((pr1->corner.x + pr1->extent.width) > (pr2->corner.x + pr2->extent.width))?
|
||||
(pr1->corner.x + pr1->extent.width) : (pr2->corner.x + pr2->extent.width)
|
||||
) - punion->corner.x;
|
||||
|
||||
h2 = (
|
||||
((pr1->corner.y + pr1->extent.height) > (pr2->corner.y + pr2->extent.height))?
|
||||
(pr1->corner.y + pr1->extent.height) : (pr2->corner.y + pr2->extent.height)
|
||||
) - punion->corner.y;
|
||||
#else
|
||||
SIZE delta;
|
||||
COORD x1, y1, w1, h1;
|
||||
|
||||
x1 = pr1->corner.x;
|
||||
w1 = pr1->extent.width;
|
||||
x2 = pr2->corner.x;
|
||||
w2 = pr2->extent.width;
|
||||
if ((delta = x1 - x2) >= 0)
|
||||
w1 += delta;
|
||||
else
|
||||
{
|
||||
w2 -= delta;
|
||||
x2 += delta;
|
||||
}
|
||||
|
||||
y1 = pr1->corner.y;
|
||||
h1 = pr1->extent.height;
|
||||
y2 = pr2->corner.y;
|
||||
h2 = pr2->extent.height;
|
||||
if ((delta = y1 - y2) >= 0)
|
||||
h1 += delta;
|
||||
else
|
||||
{
|
||||
h2 -= delta;
|
||||
y2 += delta;
|
||||
}
|
||||
|
||||
if ((delta = w1 - w2) > 0)
|
||||
w2 += delta;
|
||||
if ((delta = h1 - h2) > 0)
|
||||
h2 += delta;
|
||||
#endif
|
||||
|
||||
punion->corner.x = x2;
|
||||
punion->corner.y = y2;
|
||||
punion->extent.width = w2;
|
||||
punion->extent.height = h2;
|
||||
|
||||
#endif // NEVER
|
||||
}
|
||||
|
||||
@@ -1,241 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "gfxintrn.h"
|
||||
|
||||
INTERSECT_CODE
|
||||
_clip_line (const RECT *pClipRect, BRESENHAM_LINE *pLine)
|
||||
{
|
||||
COORD p;
|
||||
COORD x0, y0, xmin, ymin, xmax, ymax;
|
||||
SIZE abs_delta_x, abs_delta_y;
|
||||
INTERSECT_CODE intersect_code;
|
||||
|
||||
xmin = pClipRect->corner.x;
|
||||
ymin = pClipRect->corner.y;
|
||||
xmax = pClipRect->corner.x + pClipRect->extent.width - 1;
|
||||
ymax = pClipRect->corner.y + pClipRect->extent.height - 1;
|
||||
if (pLine->first.x <= pLine->second.x)
|
||||
pLine->end_points_exchanged = FALSE;
|
||||
else
|
||||
{
|
||||
p = pLine->first.x;
|
||||
pLine->first.x = pLine->second.x;
|
||||
pLine->second.x = p;
|
||||
|
||||
p = pLine->first.y;
|
||||
pLine->first.y = pLine->second.y;
|
||||
pLine->second.y = p;
|
||||
|
||||
pLine->end_points_exchanged = TRUE;
|
||||
}
|
||||
|
||||
if (pLine->first.x > xmax || pLine->second.x < xmin ||
|
||||
(pLine->first.y > ymax && pLine->second.y > ymax) ||
|
||||
(pLine->first.y < ymin && pLine->second.y < ymin))
|
||||
return ((INTERSECT_CODE)0);
|
||||
|
||||
intersect_code = INTERSECT_NOCLIP;
|
||||
x0 = y0 = 0;
|
||||
abs_delta_x = (pLine->second.x - pLine->first.x) << 1;
|
||||
abs_delta_y = (pLine->second.y - pLine->first.y) << 1;
|
||||
pLine->abs_delta_x = abs_delta_x;
|
||||
pLine->abs_delta_y = abs_delta_y;
|
||||
if (abs_delta_y == 0)
|
||||
{
|
||||
if (pLine->first.x < xmin)
|
||||
{
|
||||
pLine->first.x = xmin;
|
||||
intersect_code |= INTERSECT_LEFT;
|
||||
}
|
||||
if (pLine->second.x > xmax)
|
||||
{
|
||||
pLine->second.x = xmax;
|
||||
intersect_code |= INTERSECT_RIGHT;
|
||||
}
|
||||
}
|
||||
else if (abs_delta_x == 0)
|
||||
{
|
||||
if (abs_delta_y < 0)
|
||||
{
|
||||
p = pLine->first.y;
|
||||
pLine->first.y = pLine->second.y;
|
||||
pLine->second.y = p;
|
||||
|
||||
pLine->abs_delta_y =
|
||||
abs_delta_y = -abs_delta_y;
|
||||
}
|
||||
|
||||
if (pLine->first.y < ymin)
|
||||
{
|
||||
pLine->first.y = ymin;
|
||||
intersect_code |= INTERSECT_TOP;
|
||||
}
|
||||
if (pLine->second.y > ymax)
|
||||
{
|
||||
pLine->second.y = ymax;
|
||||
intersect_code |= INTERSECT_BOTTOM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
COORD x1, y1;
|
||||
|
||||
p = pLine->first.x;
|
||||
x1 = pLine->second.x - p;
|
||||
xmin = xmin - p;
|
||||
xmax = xmax - p;
|
||||
|
||||
p = pLine->first.y;
|
||||
if (abs_delta_y > 0)
|
||||
{
|
||||
y1 = pLine->second.y - p;
|
||||
ymin = ymin - p;
|
||||
ymax = ymax - p;
|
||||
}
|
||||
else
|
||||
{
|
||||
y1 = p - pLine->second.y;
|
||||
ymin = p - ymin;
|
||||
ymax = p - ymax;
|
||||
|
||||
p = ymin;
|
||||
ymin = ymax;
|
||||
ymax = p;
|
||||
abs_delta_y = -abs_delta_y;
|
||||
}
|
||||
|
||||
if (abs_delta_x > abs_delta_y)
|
||||
{
|
||||
SIZE half_dx;
|
||||
|
||||
half_dx = abs_delta_x >> 1;
|
||||
if (x0 < xmin)
|
||||
{
|
||||
if ((y0 = (COORD)(((long)abs_delta_y *
|
||||
(x0 = xmin) + half_dx) / abs_delta_x)) > ymax)
|
||||
return ((INTERSECT_CODE)0);
|
||||
intersect_code |= INTERSECT_LEFT;
|
||||
}
|
||||
if (x1 > xmax)
|
||||
{
|
||||
if ((y1 = (COORD)(((long)abs_delta_y *
|
||||
(x1 = xmax) + half_dx) / abs_delta_x)) < ymin)
|
||||
return ((INTERSECT_CODE)0);
|
||||
intersect_code |= INTERSECT_RIGHT;
|
||||
}
|
||||
if (y0 < ymin)
|
||||
{
|
||||
if ((x0 = (COORD)(((long)abs_delta_x *
|
||||
(y0 = ymin) - half_dx + (abs_delta_y - 1)) /
|
||||
abs_delta_y)) > xmax)
|
||||
return ((INTERSECT_CODE)0);
|
||||
intersect_code |= INTERSECT_TOP;
|
||||
intersect_code &= ~INTERSECT_LEFT;
|
||||
}
|
||||
if (y1 > ymax)
|
||||
{
|
||||
if ((x1 = (COORD)(((long)abs_delta_x *
|
||||
((y1 = ymax) + 1) - half_dx + (abs_delta_y - 1)) /
|
||||
abs_delta_y) - 1) < xmin)
|
||||
return ((INTERSECT_CODE)0);
|
||||
intersect_code |= INTERSECT_BOTTOM;
|
||||
intersect_code &= ~INTERSECT_RIGHT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SIZE half_dy;
|
||||
|
||||
half_dy = abs_delta_y >> 1;
|
||||
if (y0 < ymin)
|
||||
{
|
||||
if ((x0 = (COORD)(((long)abs_delta_x *
|
||||
(y0 = ymin) + half_dy) / abs_delta_y)) > xmax)
|
||||
return ((INTERSECT_CODE)0);
|
||||
intersect_code |= INTERSECT_TOP;
|
||||
}
|
||||
if (y1 > ymax)
|
||||
{
|
||||
if ((x1 = (COORD)(((long)abs_delta_x *
|
||||
(y1 = ymax) + half_dy) / abs_delta_y)) < xmin)
|
||||
return ((INTERSECT_CODE)0);
|
||||
intersect_code |= INTERSECT_BOTTOM;
|
||||
}
|
||||
if (x0 < xmin)
|
||||
{
|
||||
if ((y0 = (COORD)(((long)abs_delta_y *
|
||||
(x0 = xmin) - half_dy + (abs_delta_x - 1)) /
|
||||
abs_delta_x)) > ymax)
|
||||
return ((INTERSECT_CODE)0);
|
||||
intersect_code |= INTERSECT_LEFT;
|
||||
intersect_code &= ~INTERSECT_TOP;
|
||||
}
|
||||
if (x1 > xmax)
|
||||
{
|
||||
if ((y1 = (COORD)(((long)abs_delta_y *
|
||||
((x1 = xmax) + 1) - half_dy + (abs_delta_x - 1)) /
|
||||
abs_delta_x) - 1) < ymin)
|
||||
return ((INTERSECT_CODE)0);
|
||||
intersect_code |= INTERSECT_RIGHT;
|
||||
intersect_code &= ~INTERSECT_BOTTOM;
|
||||
}
|
||||
}
|
||||
|
||||
pLine->second.x = pLine->first.x + x1;
|
||||
pLine->first.x += x0;
|
||||
if (pLine->abs_delta_y > 0)
|
||||
{
|
||||
pLine->second.y = pLine->first.y + y1;
|
||||
pLine->first.y += y0;
|
||||
}
|
||||
else
|
||||
{
|
||||
INTERSECT_CODE y_code;
|
||||
|
||||
pLine->second.y = pLine->first.y - y1;
|
||||
pLine->first.y -= y0;
|
||||
|
||||
y_code = (INTERSECT_CODE)(intersect_code
|
||||
& (INTERSECT_TOP | INTERSECT_BOTTOM));
|
||||
if (y_code && y_code != (INTERSECT_TOP | INTERSECT_BOTTOM))
|
||||
intersect_code ^= (INTERSECT_TOP | INTERSECT_BOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(intersect_code & INTERSECT_ALL_SIDES))
|
||||
{
|
||||
if (abs_delta_x > abs_delta_y)
|
||||
pLine->error_term = -(SIZE)(abs_delta_x >> 1);
|
||||
else
|
||||
pLine->error_term = -(SIZE)(abs_delta_y >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
intersect_code &= ~INTERSECT_NOCLIP;
|
||||
if (abs_delta_x > abs_delta_y)
|
||||
pLine->error_term = (SIZE)((x0 * (long)abs_delta_y) -
|
||||
(y0 * (long)abs_delta_x)) - (abs_delta_x >> 1);
|
||||
else
|
||||
pLine->error_term = (SIZE)((y0 * (long)abs_delta_x) -
|
||||
(x0 * (long)abs_delta_y)) - (abs_delta_y >> 1);
|
||||
}
|
||||
|
||||
return (pLine->intersect_code = intersect_code);
|
||||
}
|
||||
|
||||
@@ -1,639 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "libs/graphics/cmap.h"
|
||||
#include "libs/threadlib.h"
|
||||
#include "libs/timelib.h"
|
||||
#include "libs/inplib.h"
|
||||
#include "libs/strlib.h"
|
||||
// for GetStringAddress()
|
||||
#include "libs/log.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
typedef struct xform_control
|
||||
{
|
||||
int CMapIndex; // -1 means unused
|
||||
COLORMAPPTR CMapPtr;
|
||||
SIZE Ticks;
|
||||
DWORD StartTime;
|
||||
DWORD EndTime;
|
||||
Color OldCMap[NUMBER_OF_PLUTVALS];
|
||||
} XFORM_CONTROL;
|
||||
|
||||
#define MAX_XFORMS 16
|
||||
static struct
|
||||
{
|
||||
XFORM_CONTROL TaskControl[MAX_XFORMS];
|
||||
volatile int Highest;
|
||||
// 'pending' is Highest >= 0
|
||||
Mutex Lock;
|
||||
} XFormControl;
|
||||
|
||||
static int fadeAmount = FADE_NORMAL_INTENSITY;
|
||||
static int fadeDelta;
|
||||
static TimeCount fadeStartTime;
|
||||
static sint32 fadeInterval;
|
||||
|
||||
#define SPARE_COLORMAPS 20
|
||||
|
||||
// Colormaps are rapidly replaced in some parts of the game, so
|
||||
// it pays to have some spares on hand
|
||||
static TFB_ColorMap *poolhead;
|
||||
static int poolcount;
|
||||
|
||||
static TFB_ColorMap * colormaps[MAX_COLORMAPS];
|
||||
static int mapcount;
|
||||
Mutex maplock;
|
||||
|
||||
|
||||
void
|
||||
InitColorMaps (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// init colormaps
|
||||
maplock = CreateMutex ("Colormaps Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
|
||||
|
||||
// init xform control
|
||||
XFormControl.Highest = -1;
|
||||
XFormControl.Lock = CreateMutex ("Transform Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
|
||||
for (i = 0; i < MAX_XFORMS; ++i)
|
||||
XFormControl.TaskControl[i].CMapIndex = -1;
|
||||
}
|
||||
|
||||
void
|
||||
UninitColorMaps (void)
|
||||
{
|
||||
TFB_ColorMap *next;
|
||||
|
||||
// free spares
|
||||
for ( ; poolhead; poolhead = next)
|
||||
{
|
||||
next = poolhead->next;
|
||||
HFree (poolhead);
|
||||
}
|
||||
|
||||
// uninit xform control
|
||||
DestroyMutex (XFormControl.Lock);
|
||||
|
||||
// uninit colormaps
|
||||
DestroyMutex (maplock);
|
||||
}
|
||||
|
||||
static inline TFB_ColorMap *
|
||||
alloc_colormap (void)
|
||||
// returns an addrefed object
|
||||
{
|
||||
TFB_ColorMap *map;
|
||||
|
||||
if (poolhead)
|
||||
{ // have some spares
|
||||
map = poolhead;
|
||||
poolhead = map->next;
|
||||
--poolcount;
|
||||
}
|
||||
else
|
||||
{ // no spares, need a new one
|
||||
map = HMalloc (sizeof (*map));
|
||||
map->palette = AllocNativePalette ();
|
||||
if (!map->palette)
|
||||
{
|
||||
HFree (map);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
map->next = NULL;
|
||||
map->index = -1;
|
||||
map->refcount = 1;
|
||||
map->version = 0;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static TFB_ColorMap *
|
||||
clone_colormap (TFB_ColorMap *from, int index)
|
||||
// returns an addrefed object
|
||||
{
|
||||
TFB_ColorMap *map;
|
||||
|
||||
map = alloc_colormap ();
|
||||
if (!map)
|
||||
{
|
||||
log_add (log_Warning, "FATAL: clone_colormap(): "
|
||||
"could not allocate a map");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
else
|
||||
{ // fresh new map
|
||||
map->index = index;
|
||||
if (from)
|
||||
map->version = from->version;
|
||||
}
|
||||
map->version++;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_colormap (TFB_ColorMap *map)
|
||||
{
|
||||
if (!map)
|
||||
{
|
||||
log_add (log_Warning, "free_colormap(): tried to free a NULL map");
|
||||
return;
|
||||
}
|
||||
|
||||
if (poolcount < SPARE_COLORMAPS)
|
||||
{ // return to the spare pool
|
||||
map->next = poolhead;
|
||||
poolhead = map;
|
||||
++poolcount;
|
||||
}
|
||||
else
|
||||
{ // don't need any more spares
|
||||
FreeNativePalette (map->palette);
|
||||
HFree (map);
|
||||
}
|
||||
}
|
||||
|
||||
static inline TFB_ColorMap *
|
||||
get_colormap (int index)
|
||||
{
|
||||
TFB_ColorMap *map;
|
||||
|
||||
map = colormaps[index];
|
||||
if (!map)
|
||||
{
|
||||
log_add (log_Fatal, "BUG: get_colormap(): map not present");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
map->refcount++;
|
||||
return map;
|
||||
}
|
||||
|
||||
static inline void
|
||||
release_colormap (TFB_ColorMap *map)
|
||||
{
|
||||
if (!map)
|
||||
return;
|
||||
|
||||
if (map->refcount <= 0)
|
||||
{
|
||||
log_add (log_Warning, "BUG: release_colormap(): refcount not >0");
|
||||
return;
|
||||
}
|
||||
|
||||
map->refcount--;
|
||||
if (map->refcount == 0)
|
||||
free_colormap (map);
|
||||
}
|
||||
|
||||
void
|
||||
TFB_ReturnColorMap (TFB_ColorMap *map)
|
||||
{
|
||||
LockMutex (maplock);
|
||||
release_colormap (map);
|
||||
UnlockMutex (maplock);
|
||||
}
|
||||
|
||||
TFB_ColorMap *
|
||||
TFB_GetColorMap (int index)
|
||||
{
|
||||
TFB_ColorMap *map;
|
||||
|
||||
LockMutex (maplock);
|
||||
map = get_colormap (index);
|
||||
UnlockMutex (maplock);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
void
|
||||
GetColorMapColors (Color *colors, TFB_ColorMap *map)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!map)
|
||||
return;
|
||||
|
||||
for (i = 0; i < NUMBER_OF_PLUTVALS; ++i)
|
||||
colors[i] = GetNativePaletteColor (map->palette, i);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
SetColorMap (COLORMAPPTR map)
|
||||
{
|
||||
int start, end;
|
||||
int total_size;
|
||||
UBYTE *colors = (UBYTE*)map;
|
||||
TFB_ColorMap **mpp;
|
||||
|
||||
if (!map)
|
||||
return TRUE;
|
||||
|
||||
start = *colors++;
|
||||
end = *colors++;
|
||||
if (start > end)
|
||||
{
|
||||
log_add (log_Warning, "ERROR: SetColorMap(): "
|
||||
"starting map (%d) not less or eq ending (%d)",
|
||||
start, end);
|
||||
return FALSE;
|
||||
}
|
||||
if (start >= MAX_COLORMAPS)
|
||||
{
|
||||
log_add (log_Warning, "ERROR: SetColorMap(): "
|
||||
"starting map (%d) beyond range (0-%d)",
|
||||
start, (int)MAX_COLORMAPS - 1);
|
||||
return FALSE;
|
||||
}
|
||||
if (end >= MAX_COLORMAPS)
|
||||
{
|
||||
log_add (log_Warning, "SetColorMap(): "
|
||||
"ending map (%d) beyond range (0-%d)\n",
|
||||
end, (int)MAX_COLORMAPS - 1);
|
||||
end = MAX_COLORMAPS - 1;
|
||||
}
|
||||
|
||||
total_size = end + 1;
|
||||
|
||||
LockMutex (maplock);
|
||||
|
||||
if (total_size > mapcount)
|
||||
mapcount = total_size;
|
||||
|
||||
// parse the supplied PLUTs into our colormaps
|
||||
for (mpp = colormaps + start; start <= end; ++start, ++mpp)
|
||||
{
|
||||
int i;
|
||||
TFB_ColorMap *newmap;
|
||||
TFB_ColorMap *oldmap;
|
||||
|
||||
oldmap = *mpp;
|
||||
newmap = clone_colormap (oldmap, start);
|
||||
|
||||
for (i = 0; i < NUMBER_OF_PLUTVALS; ++i, colors += PLUTVAL_BYTE_SIZE)
|
||||
{
|
||||
Color color;
|
||||
|
||||
color.a = 0xff;
|
||||
color.r = colors[PLUTVAL_RED];
|
||||
color.g = colors[PLUTVAL_GREEN];
|
||||
color.b = colors[PLUTVAL_BLUE];
|
||||
SetNativePaletteColor (newmap->palette, i, color);
|
||||
}
|
||||
|
||||
*mpp = newmap;
|
||||
release_colormap (oldmap);
|
||||
}
|
||||
|
||||
UnlockMutex (maplock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Fade Transforms */
|
||||
|
||||
int
|
||||
GetFadeAmount (void)
|
||||
{
|
||||
int newAmount;
|
||||
|
||||
LockMutex (XFormControl.Lock);
|
||||
|
||||
if (fadeInterval)
|
||||
{ // have a pending fade
|
||||
TimeCount Now = GetTimeCounter ();
|
||||
sint32 elapsed;
|
||||
|
||||
elapsed = Now - fadeStartTime;
|
||||
if (elapsed > fadeInterval)
|
||||
elapsed = fadeInterval;
|
||||
|
||||
newAmount = fadeAmount + (long)fadeDelta * elapsed / fadeInterval;
|
||||
|
||||
if (elapsed >= fadeInterval)
|
||||
{ // fade is over
|
||||
fadeAmount = newAmount;
|
||||
fadeInterval = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // no fade pending, return the current
|
||||
newAmount = fadeAmount;
|
||||
}
|
||||
|
||||
UnlockMutex (XFormControl.Lock);
|
||||
|
||||
return newAmount;
|
||||
}
|
||||
|
||||
static void
|
||||
finishPendingFade (void)
|
||||
{
|
||||
if (fadeInterval)
|
||||
{ // end the fade immediately
|
||||
fadeAmount += fadeDelta;
|
||||
fadeInterval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
FlushFadeXForms (void)
|
||||
{
|
||||
LockMutex (XFormControl.Lock);
|
||||
finishPendingFade ();
|
||||
UnlockMutex (XFormControl.Lock);
|
||||
}
|
||||
|
||||
DWORD
|
||||
FadeScreen (ScreenFadeType fadeType, SIZE TimeInterval)
|
||||
{
|
||||
TimeCount TimeOut;
|
||||
int FadeEnd;
|
||||
|
||||
switch (fadeType)
|
||||
{
|
||||
case FadeAllToBlack:
|
||||
case FadeSomeToBlack:
|
||||
FadeEnd = FADE_NO_INTENSITY;
|
||||
break;
|
||||
case FadeAllToColor:
|
||||
case FadeSomeToColor:
|
||||
FadeEnd = FADE_NORMAL_INTENSITY;
|
||||
break;
|
||||
case FadeAllToWhite:
|
||||
case FadeSomeToWhite:
|
||||
FadeEnd = FADE_FULL_INTENSITY;
|
||||
break;
|
||||
default:
|
||||
return (GetTimeCounter ());
|
||||
}
|
||||
|
||||
// Don't make users wait for fades
|
||||
if (QuitPosted)
|
||||
TimeInterval = 0;
|
||||
|
||||
LockMutex (XFormControl.Lock);
|
||||
|
||||
finishPendingFade ();
|
||||
|
||||
if (TimeInterval <= 0)
|
||||
{ // end the fade immediately
|
||||
fadeAmount = FadeEnd;
|
||||
// cancel any pending fades
|
||||
fadeInterval = 0;
|
||||
TimeOut = GetTimeCounter ();
|
||||
}
|
||||
else
|
||||
{
|
||||
fadeInterval = TimeInterval;
|
||||
fadeDelta = FadeEnd - fadeAmount;
|
||||
fadeStartTime = GetTimeCounter ();
|
||||
TimeOut = fadeStartTime + TimeInterval + 1;
|
||||
}
|
||||
|
||||
UnlockMutex (XFormControl.Lock);
|
||||
|
||||
return TimeOut;
|
||||
}
|
||||
|
||||
/* Colormap Transforms */
|
||||
|
||||
static void
|
||||
finish_colormap_xform (int which)
|
||||
{
|
||||
SetColorMap (XFormControl.TaskControl[which].CMapPtr);
|
||||
XFormControl.TaskControl[which].CMapIndex = -1;
|
||||
// check Highest ptr
|
||||
if (which == XFormControl.Highest)
|
||||
{
|
||||
do
|
||||
--which;
|
||||
while (which >= 0 && XFormControl.TaskControl[which].CMapIndex == -1);
|
||||
|
||||
XFormControl.Highest = which;
|
||||
}
|
||||
}
|
||||
|
||||
static inline BYTE
|
||||
blendChan (BYTE c1, BYTE c2, int weight, int scale)
|
||||
{
|
||||
return c1 + ((int)c2 - c1) * weight / scale;
|
||||
}
|
||||
|
||||
/* This gives the XFormColorMap task a timeslice to do its thing
|
||||
* Only one thread should ever be allowed to be calling this at any time
|
||||
*/
|
||||
BOOLEAN
|
||||
XFormColorMap_step (void)
|
||||
{
|
||||
BOOLEAN Changed = FALSE;
|
||||
int x;
|
||||
DWORD Now = GetTimeCounter ();
|
||||
|
||||
LockMutex (XFormControl.Lock);
|
||||
|
||||
for (x = 0; x <= XFormControl.Highest; ++x)
|
||||
{
|
||||
XFORM_CONTROL *control = &XFormControl.TaskControl[x];
|
||||
int index = control->CMapIndex;
|
||||
int TicksLeft = control->EndTime - Now;
|
||||
TFB_ColorMap *curmap;
|
||||
|
||||
if (index < 0)
|
||||
continue; // unused slot
|
||||
|
||||
LockMutex (maplock);
|
||||
|
||||
curmap = colormaps[index];
|
||||
if (!curmap)
|
||||
{
|
||||
UnlockMutex (maplock);
|
||||
log_add (log_Error, "BUG: XFormColorMap_step(): no current map");
|
||||
finish_colormap_xform (x);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TicksLeft > 0)
|
||||
{
|
||||
#define XFORM_SCALE 0x10000
|
||||
TFB_ColorMap *newmap = NULL;
|
||||
UBYTE *newClr;
|
||||
Color *oldClr;
|
||||
int frac;
|
||||
int i;
|
||||
|
||||
newmap = clone_colormap (curmap, index);
|
||||
|
||||
oldClr = control->OldCMap;
|
||||
newClr = (UBYTE*)control->CMapPtr + 2;
|
||||
|
||||
frac = (int)(control->Ticks - TicksLeft) * XFORM_SCALE
|
||||
/ control->Ticks;
|
||||
|
||||
for (i = 0; i < NUMBER_OF_PLUTVALS; ++i, ++oldClr,
|
||||
newClr += PLUTVAL_BYTE_SIZE)
|
||||
{
|
||||
Color color;
|
||||
|
||||
color.a = 0xff;
|
||||
color.r = blendChan (oldClr->r, newClr[PLUTVAL_RED],
|
||||
frac, XFORM_SCALE);
|
||||
color.g = blendChan (oldClr->g, newClr[PLUTVAL_GREEN],
|
||||
frac, XFORM_SCALE);
|
||||
color.b = blendChan (oldClr->b, newClr[PLUTVAL_BLUE],
|
||||
frac, XFORM_SCALE);
|
||||
SetNativePaletteColor (newmap->palette, i, color);
|
||||
}
|
||||
|
||||
colormaps[index] = newmap;
|
||||
release_colormap (curmap);
|
||||
}
|
||||
|
||||
UnlockMutex (maplock);
|
||||
|
||||
if (TicksLeft <= 0)
|
||||
{ // asked for immediate xform or already done
|
||||
finish_colormap_xform (x);
|
||||
}
|
||||
|
||||
Changed = TRUE;
|
||||
}
|
||||
|
||||
UnlockMutex (XFormControl.Lock);
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
static void
|
||||
FlushPLUTXForms (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
LockMutex (XFormControl.Lock);
|
||||
|
||||
for (i = 0; i <= XFormControl.Highest; ++i)
|
||||
{
|
||||
if (XFormControl.TaskControl[i].CMapIndex >= 0)
|
||||
finish_colormap_xform (i);
|
||||
}
|
||||
XFormControl.Highest = -1; // all gone
|
||||
|
||||
UnlockMutex (XFormControl.Lock);
|
||||
}
|
||||
|
||||
static DWORD
|
||||
XFormPLUT (COLORMAPPTR ColorMapPtr, SIZE TimeInterval)
|
||||
{
|
||||
TFB_ColorMap *map;
|
||||
XFORM_CONTROL *control;
|
||||
int index;
|
||||
int x;
|
||||
int first_avail = -1;
|
||||
DWORD EndTime;
|
||||
DWORD Now;
|
||||
|
||||
Now = GetTimeCounter ();
|
||||
index = *(UBYTE*)ColorMapPtr;
|
||||
|
||||
LockMutex (XFormControl.Lock);
|
||||
// Find an available slot, or reuse if required
|
||||
for (x = 0; x <= XFormControl.Highest
|
||||
&& index != XFormControl.TaskControl[x].CMapIndex;
|
||||
++x)
|
||||
{
|
||||
if (first_avail == -1 && XFormControl.TaskControl[x].CMapIndex == -1)
|
||||
first_avail = x;
|
||||
}
|
||||
|
||||
if (index == XFormControl.TaskControl[x].CMapIndex)
|
||||
{ // already xforming this colormap -- cancel and reuse slot
|
||||
finish_colormap_xform (x);
|
||||
}
|
||||
else if (first_avail >= 0)
|
||||
{ // picked up a slot along the way
|
||||
x = first_avail;
|
||||
}
|
||||
else if (x >= MAX_XFORMS)
|
||||
{ // flush some xforms if the queue is full
|
||||
log_add (log_Debug, "WARNING: XFormPLUT(): no slots available");
|
||||
x = XFormControl.Highest;
|
||||
finish_colormap_xform (x);
|
||||
}
|
||||
// take next unused one
|
||||
control = &XFormControl.TaskControl[x];
|
||||
if (x > XFormControl.Highest)
|
||||
XFormControl.Highest = x;
|
||||
|
||||
// make a copy of the current map
|
||||
LockMutex (maplock);
|
||||
map = colormaps[index];
|
||||
if (!map)
|
||||
{
|
||||
UnlockMutex (maplock);
|
||||
UnlockMutex (XFormControl.Lock);
|
||||
log_add (log_Warning, "BUG: XFormPLUT(): no current map");
|
||||
return (0);
|
||||
}
|
||||
GetColorMapColors (control->OldCMap, map);
|
||||
UnlockMutex (maplock);
|
||||
|
||||
control->CMapIndex = index;
|
||||
control->CMapPtr = ColorMapPtr;
|
||||
control->Ticks = TimeInterval;
|
||||
if (control->Ticks < 0)
|
||||
control->Ticks = 0; /* prevent negative fade */
|
||||
control->StartTime = Now;
|
||||
control->EndTime = EndTime = Now + control->Ticks;
|
||||
|
||||
UnlockMutex (XFormControl.Lock);
|
||||
|
||||
return (EndTime);
|
||||
}
|
||||
|
||||
DWORD
|
||||
XFormColorMap (COLORMAPPTR ColorMapPtr, SIZE TimeInterval)
|
||||
{
|
||||
if (!ColorMapPtr)
|
||||
return (0);
|
||||
|
||||
// Don't make users wait for transforms
|
||||
if (QuitPosted)
|
||||
TimeInterval = 0;
|
||||
|
||||
return XFormPLUT (ColorMapPtr, TimeInterval);
|
||||
}
|
||||
|
||||
void
|
||||
FlushColorXForms (void)
|
||||
{
|
||||
FlushFadeXForms ();
|
||||
FlushPLUTXForms ();
|
||||
}
|
||||
|
||||
// The type conversions are implicit and will generate errors
|
||||
// or warnings if types change imcompatibly
|
||||
COLORMAPPTR
|
||||
GetColorMapAddress (COLORMAP colormap)
|
||||
{
|
||||
return GetStringAddress (colormap);
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef CMAP_H
|
||||
#define CMAP_H
|
||||
|
||||
#include "libs/gfxlib.h"
|
||||
|
||||
#define MAX_COLORMAPS 250
|
||||
|
||||
// These are pertinent to colortable file format
|
||||
// We load colormaps as binary and parse them when needed
|
||||
#define PLUTVAL_BYTE_SIZE 3
|
||||
// Channel order in colormap tables
|
||||
#define PLUTVAL_RED 0
|
||||
#define PLUTVAL_GREEN 1
|
||||
#define PLUTVAL_BLUE 2
|
||||
|
||||
#define NUMBER_OF_PLUTVALS 256
|
||||
// Size of the colormap in a colortable file
|
||||
#define PLUT_BYTE_SIZE (PLUTVAL_BYTE_SIZE * NUMBER_OF_PLUTVALS)
|
||||
|
||||
#define FADE_NO_INTENSITY 0
|
||||
#define FADE_NORMAL_INTENSITY 255
|
||||
#define FADE_FULL_INTENSITY 510
|
||||
|
||||
typedef struct NativePalette NativePalette;
|
||||
|
||||
typedef struct tfb_colormap
|
||||
{
|
||||
int index;
|
||||
// Colormap index as the game sees it
|
||||
int version;
|
||||
// Version goes up every time the colormap changes. This may
|
||||
// be due to SetColorMap() or at every transformation step
|
||||
// of XFormColorMap(). Paletted TFB_Images track the last
|
||||
// colormap version they were drawn with for optimization.
|
||||
int refcount;
|
||||
struct tfb_colormap *next;
|
||||
// for spares linking
|
||||
NativePalette *palette;
|
||||
} TFB_ColorMap;
|
||||
|
||||
extern int GetFadeAmount (void);
|
||||
|
||||
extern void InitColorMaps (void);
|
||||
extern void UninitColorMaps (void);
|
||||
|
||||
extern void GetColorMapColors (Color *colors, TFB_ColorMap *);
|
||||
|
||||
extern TFB_ColorMap * TFB_GetColorMap (int index);
|
||||
extern void TFB_ReturnColorMap (TFB_ColorMap *map);
|
||||
|
||||
extern BOOLEAN XFormColorMap_step (void);
|
||||
|
||||
// Native
|
||||
NativePalette* AllocNativePalette (void);
|
||||
void FreeNativePalette (NativePalette *);
|
||||
void SetNativePaletteColor (NativePalette *, int index, Color);
|
||||
Color GetNativePaletteColor (NativePalette *, int index);
|
||||
|
||||
#endif /* CMAP_H */
|
||||
@@ -1,398 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "gfxintrn.h"
|
||||
|
||||
GRAPHICS_STATUS _GraphicsStatusFlags;
|
||||
CONTEXT _pCurContext;
|
||||
|
||||
#ifdef DEBUG
|
||||
// We keep track of all contexts
|
||||
CONTEXT firstContext;
|
||||
// The first one in the list.
|
||||
CONTEXT *contextEnd = &firstContext;
|
||||
// Where to put the next context.
|
||||
#endif
|
||||
|
||||
PRIMITIVE _locPrim;
|
||||
|
||||
FONT _CurFontPtr;
|
||||
|
||||
#define DEFAULT_FORE_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F)
|
||||
#define DEFAULT_BACK_COLOR BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x00), 0x00)
|
||||
|
||||
#define DEFAULT_DRAW_MODE MAKE_DRAW_MODE (DRAW_DEFAULT, 255)
|
||||
|
||||
CONTEXT
|
||||
SetContext (CONTEXT Context)
|
||||
{
|
||||
CONTEXT LastContext;
|
||||
|
||||
LastContext = _pCurContext;
|
||||
if (Context != LastContext)
|
||||
{
|
||||
if (LastContext)
|
||||
{
|
||||
UnsetContextFlags (
|
||||
MAKE_WORD (0, GRAPHICS_ACTIVE | DRAWABLE_ACTIVE));
|
||||
SetContextFlags (
|
||||
MAKE_WORD (0, _GraphicsStatusFlags
|
||||
& (GRAPHICS_ACTIVE | DRAWABLE_ACTIVE)));
|
||||
|
||||
DeactivateContext ();
|
||||
}
|
||||
|
||||
_pCurContext = Context;
|
||||
if (_pCurContext)
|
||||
{
|
||||
ActivateContext ();
|
||||
|
||||
_GraphicsStatusFlags &= ~(GRAPHICS_ACTIVE | DRAWABLE_ACTIVE);
|
||||
_GraphicsStatusFlags |= HIBYTE (_get_context_flags ());
|
||||
|
||||
SetPrimColor (&_locPrim, _get_context_fg_color ());
|
||||
|
||||
_CurFramePtr = _get_context_fg_frame ();
|
||||
_CurFontPtr = _get_context_font ();
|
||||
}
|
||||
}
|
||||
|
||||
return (LastContext);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
CONTEXT
|
||||
CreateContextAux (const char *name)
|
||||
#else /* if !defined(DEBUG) */
|
||||
CONTEXT
|
||||
CreateContextAux (void)
|
||||
#endif /* !defined(DEBUG) */
|
||||
{
|
||||
CONTEXT NewContext;
|
||||
|
||||
NewContext = AllocContext ();
|
||||
if (NewContext)
|
||||
{
|
||||
/* initialize context */
|
||||
#ifdef DEBUG
|
||||
NewContext->name = name;
|
||||
NewContext->next = NULL;
|
||||
*contextEnd = NewContext;
|
||||
contextEnd = &NewContext->next;
|
||||
#endif /* DEBUG */
|
||||
|
||||
NewContext->Mode = DEFAULT_DRAW_MODE;
|
||||
NewContext->ForeGroundColor = DEFAULT_FORE_COLOR;
|
||||
NewContext->BackGroundColor = DEFAULT_BACK_COLOR;
|
||||
}
|
||||
|
||||
return NewContext;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Loop through the list of context to the pointer which points to the
|
||||
// specified context. This is either 'firstContext' or the address of
|
||||
// the 'next' field of some other context.
|
||||
static CONTEXT *
|
||||
FindContextPtr (CONTEXT context) {
|
||||
CONTEXT *ptr;
|
||||
|
||||
for (ptr = &firstContext; *ptr != NULL; ptr = &(*ptr)->next) {
|
||||
if (*ptr == context)
|
||||
break;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
BOOLEAN
|
||||
DestroyContext (CONTEXT ContextRef)
|
||||
{
|
||||
if (ContextRef == 0)
|
||||
return (FALSE);
|
||||
|
||||
if (_pCurContext && _pCurContext == ContextRef)
|
||||
SetContext ((CONTEXT)0);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Unlink the context.
|
||||
{
|
||||
CONTEXT *contextPtr = FindContextPtr (ContextRef);
|
||||
if (contextEnd == &ContextRef->next)
|
||||
contextEnd = contextPtr;
|
||||
*contextPtr = ContextRef->next;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
FreeContext (ContextRef);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Color
|
||||
SetContextForeGroundColor (Color color)
|
||||
{
|
||||
Color oldColor;
|
||||
|
||||
if (!ContextActive ())
|
||||
return DEFAULT_FORE_COLOR;
|
||||
|
||||
oldColor = _get_context_fg_color ();
|
||||
if (!sameColor(oldColor, color))
|
||||
{
|
||||
SwitchContextForeGroundColor (color);
|
||||
|
||||
if (!(_get_context_fbk_flags () & FBK_IMAGE))
|
||||
{
|
||||
SetContextFBkFlags (FBK_DIRTY);
|
||||
}
|
||||
}
|
||||
SetPrimColor (&_locPrim, color);
|
||||
|
||||
return (oldColor);
|
||||
}
|
||||
|
||||
Color
|
||||
GetContextForeGroundColor (void)
|
||||
{
|
||||
if (!ContextActive ())
|
||||
return DEFAULT_FORE_COLOR;
|
||||
|
||||
return _get_context_fg_color ();
|
||||
}
|
||||
|
||||
Color
|
||||
SetContextBackGroundColor (Color color)
|
||||
{
|
||||
Color oldColor;
|
||||
|
||||
if (!ContextActive ())
|
||||
return DEFAULT_BACK_COLOR;
|
||||
|
||||
oldColor = _get_context_bg_color ();
|
||||
if (!sameColor(oldColor, color))
|
||||
SwitchContextBackGroundColor (color);
|
||||
|
||||
return oldColor;
|
||||
}
|
||||
|
||||
Color
|
||||
GetContextBackGroundColor (void)
|
||||
{
|
||||
if (!ContextActive ())
|
||||
return DEFAULT_BACK_COLOR;
|
||||
|
||||
return _get_context_bg_color ();
|
||||
}
|
||||
|
||||
DrawMode
|
||||
SetContextDrawMode (DrawMode mode)
|
||||
{
|
||||
DrawMode oldMode;
|
||||
|
||||
if (!ContextActive ())
|
||||
return DEFAULT_DRAW_MODE;
|
||||
|
||||
oldMode = _get_context_draw_mode ();
|
||||
SwitchContextDrawMode (mode);
|
||||
|
||||
return oldMode;
|
||||
}
|
||||
|
||||
DrawMode
|
||||
GetContextDrawMode (void)
|
||||
{
|
||||
if (!ContextActive ())
|
||||
return DEFAULT_DRAW_MODE;
|
||||
|
||||
return _get_context_draw_mode ();
|
||||
}
|
||||
|
||||
// Returns a rect based at 0,0 and the size of context foreground frame
|
||||
static inline RECT
|
||||
_get_context_fg_rect (void)
|
||||
{
|
||||
RECT r = { {0, 0}, {0, 0} };
|
||||
if (_CurFramePtr)
|
||||
r.extent = GetFrameBounds (_CurFramePtr);
|
||||
return r;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
SetContextClipRect (RECT *lpRect)
|
||||
{
|
||||
if (!ContextActive ())
|
||||
return (FALSE);
|
||||
|
||||
if (lpRect)
|
||||
{
|
||||
if (rectsEqual (*lpRect, _get_context_fg_rect ()))
|
||||
{ // Cliprect is undefined to mirror GetContextClipRect()
|
||||
_pCurContext->ClipRect.extent.width = 0;
|
||||
}
|
||||
else
|
||||
{ // We have a cliprect
|
||||
_pCurContext->ClipRect = *lpRect;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Set cliprect as undefined
|
||||
_pCurContext->ClipRect.extent.width = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
GetContextClipRect (RECT *lpRect)
|
||||
{
|
||||
if (!ContextActive ())
|
||||
return (FALSE);
|
||||
|
||||
*lpRect = _pCurContext->ClipRect;
|
||||
if (!_pCurContext->ClipRect.extent.width)
|
||||
{ // Though the cliprect is undefined, drawing will be clipped
|
||||
// to the extent of the foreground frame
|
||||
*lpRect = _get_context_fg_rect ();
|
||||
}
|
||||
|
||||
return (_pCurContext->ClipRect.extent.width != 0);
|
||||
}
|
||||
|
||||
POINT
|
||||
SetContextOrigin (POINT orgOffset)
|
||||
{
|
||||
// XXX: This is a hack, kind of. But that's what the original did.
|
||||
return SetFrameHot (_CurFramePtr, orgOffset);
|
||||
}
|
||||
|
||||
FRAME
|
||||
SetContextFontEffect (FRAME EffectFrame)
|
||||
{
|
||||
FRAME LastEffect;
|
||||
|
||||
if (!ContextActive ())
|
||||
return (NULL);
|
||||
|
||||
LastEffect = _get_context_fonteff ();
|
||||
if (EffectFrame != LastEffect)
|
||||
{
|
||||
SwitchContextFontEffect (EffectFrame);
|
||||
|
||||
if (EffectFrame != 0)
|
||||
{
|
||||
SetContextFBkFlags (FBK_IMAGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnsetContextFBkFlags (FBK_IMAGE);
|
||||
}
|
||||
}
|
||||
|
||||
return LastEffect;
|
||||
}
|
||||
|
||||
void
|
||||
FixContextFontEffect (void)
|
||||
{
|
||||
SIZE w, h;
|
||||
TFB_Image* img;
|
||||
|
||||
if (!ContextActive () || (_get_context_font_backing () != 0
|
||||
&& !(_get_context_fbk_flags () & FBK_DIRTY)))
|
||||
return;
|
||||
|
||||
if (!GetContextFontLeading (&h) || !GetContextFontLeadingWidth (&w))
|
||||
return;
|
||||
|
||||
img = _pCurContext->FontBacking;
|
||||
if (img)
|
||||
TFB_DrawScreen_DeleteImage (img);
|
||||
|
||||
img = TFB_DrawImage_CreateForScreen (w, h, TRUE);
|
||||
if (_get_context_fbk_flags () & FBK_IMAGE)
|
||||
{ // image pattern backing
|
||||
FRAME EffectFrame = _get_context_fonteff ();
|
||||
|
||||
TFB_DrawImage_Image (EffectFrame->image,
|
||||
-EffectFrame->HotSpot.x, -EffectFrame->HotSpot.y,
|
||||
0, 0, NULL, DRAW_REPLACE_MODE, img);
|
||||
}
|
||||
else
|
||||
{ // solid color backing
|
||||
RECT r = { {0, 0}, {w, h} };
|
||||
Color color = _get_context_fg_color ();
|
||||
|
||||
TFB_DrawImage_Rect (&r, color, DRAW_REPLACE_MODE, img);
|
||||
}
|
||||
|
||||
_pCurContext->FontBacking = img;
|
||||
UnsetContextFBkFlags (FBK_DIRTY);
|
||||
}
|
||||
|
||||
// 'area' may be NULL to copy the entire CONTEXT cliprect
|
||||
// 'area' is relative to the CONTEXT cliprect
|
||||
DRAWABLE
|
||||
CopyContextRect (const RECT* area)
|
||||
{
|
||||
RECT clipRect;
|
||||
RECT fgRect;
|
||||
RECT r;
|
||||
|
||||
if (!ContextActive () || !_CurFramePtr)
|
||||
return NULL;
|
||||
|
||||
fgRect = _get_context_fg_rect ();
|
||||
GetContextClipRect (&clipRect);
|
||||
r = clipRect;
|
||||
if (area)
|
||||
{ // a portion of the context
|
||||
r.corner.x += area->corner.x;
|
||||
r.corner.y += area->corner.y;
|
||||
r.extent = area->extent;
|
||||
}
|
||||
// TODO: Should this take CONTEXT origin into account too?
|
||||
// validate the rect
|
||||
if (!BoxIntersect (&r, &fgRect, &r))
|
||||
return NULL;
|
||||
|
||||
if (_CurFramePtr->Type == SCREEN_DRAWABLE)
|
||||
return LoadDisplayPixmap (&r, NULL);
|
||||
else
|
||||
return CopyFrameRect (_CurFramePtr, &r);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
const char *
|
||||
GetContextName (CONTEXT context)
|
||||
{
|
||||
return context->name;
|
||||
}
|
||||
|
||||
CONTEXT
|
||||
GetFirstContext (void)
|
||||
{
|
||||
return firstContext;
|
||||
}
|
||||
|
||||
CONTEXT
|
||||
GetNextContext (CONTEXT context)
|
||||
{
|
||||
return context->next;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _CONTEXT_H
|
||||
#define _CONTEXT_H
|
||||
|
||||
#include "tfb_draw.h"
|
||||
#include "libs/memlib.h"
|
||||
|
||||
typedef UWORD FBK_FLAGS;
|
||||
#define FBK_DIRTY (1 << 0)
|
||||
#define FBK_IMAGE (1 << 1)
|
||||
|
||||
struct context_desc
|
||||
{
|
||||
UWORD Flags;
|
||||
// Low nibble currently unused
|
||||
// High nibble contains GRAPHICS_STATUS
|
||||
|
||||
Color ForeGroundColor, BackGroundColor;
|
||||
DrawMode Mode;
|
||||
FRAME ForeGroundFrame;
|
||||
FONT Font;
|
||||
|
||||
RECT ClipRect;
|
||||
|
||||
FRAME FontEffect;
|
||||
TFB_Image *FontBacking;
|
||||
FBK_FLAGS BackingFlags;
|
||||
|
||||
#ifdef DEBUG
|
||||
const char *name;
|
||||
CONTEXT next;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define AllocContext() HCalloc (sizeof (CONTEXT_DESC))
|
||||
#define FreeContext HFree
|
||||
|
||||
extern CONTEXT _pCurContext;
|
||||
extern PRIMITIVE _locPrim;
|
||||
|
||||
#define _get_context_fg_color() (_pCurContext->ForeGroundColor)
|
||||
#define _get_context_bg_color() (_pCurContext->BackGroundColor)
|
||||
#define _get_context_flags() (_pCurContext->Flags)
|
||||
#define _get_context_fg_frame() (_pCurContext->ForeGroundFrame)
|
||||
#define _get_context_font() (_pCurContext->Font)
|
||||
#define _get_context_fbk_flags() (_pCurContext->BackingFlags)
|
||||
#define _get_context_fonteff() (_pCurContext->FontEffect)
|
||||
#define _get_context_font_backing() (_pCurContext->FontBacking)
|
||||
#define _get_context_draw_mode() (_pCurContext->Mode)
|
||||
|
||||
#define SwitchContextDrawMode(m) \
|
||||
{ \
|
||||
_pCurContext->Mode = (m); \
|
||||
}
|
||||
#define SwitchContextForeGroundColor(c) \
|
||||
{ \
|
||||
_pCurContext->ForeGroundColor = (c); \
|
||||
}
|
||||
#define SwitchContextBackGroundColor(c) \
|
||||
{ \
|
||||
_pCurContext->BackGroundColor = (c); \
|
||||
}
|
||||
#define SetContextFlags(f) \
|
||||
{ \
|
||||
_pCurContext->Flags |= (f); \
|
||||
}
|
||||
#define UnsetContextFlags(f) \
|
||||
{ \
|
||||
_pCurContext->Flags &= ~(f); \
|
||||
}
|
||||
#define SwitchContextFGFrame(f) \
|
||||
{ \
|
||||
_pCurContext->ForeGroundFrame = (f); \
|
||||
}
|
||||
#define SwitchContextFont(f) \
|
||||
{ \
|
||||
_pCurContext->Font = (f); \
|
||||
SetContextFBkFlags (FBK_DIRTY); \
|
||||
}
|
||||
#define SwitchContextBGFunc(f) \
|
||||
{ \
|
||||
_pCurContext->BackGroundFunc = (f); \
|
||||
}
|
||||
#define SetContextFBkFlags(f) \
|
||||
{ \
|
||||
_pCurContext->BackingFlags |= (f); \
|
||||
}
|
||||
#define UnsetContextFBkFlags(f) \
|
||||
{ \
|
||||
_pCurContext->BackingFlags &= ~(f); \
|
||||
}
|
||||
#define SwitchContextFontEffect(f) \
|
||||
{ \
|
||||
_pCurContext->FontEffect = (f); \
|
||||
SetContextFBkFlags (FBK_DIRTY); \
|
||||
}
|
||||
|
||||
typedef BYTE GRAPHICS_STATUS;
|
||||
|
||||
extern GRAPHICS_STATUS _GraphicsStatusFlags;
|
||||
#define GRAPHICS_ACTIVE (GRAPHICS_STATUS)(1 << 0)
|
||||
#define GRAPHICS_VISIBLE (GRAPHICS_STATUS)(1 << 1)
|
||||
#define CONTEXT_ACTIVE (GRAPHICS_STATUS)(1 << 2)
|
||||
#define DRAWABLE_ACTIVE (GRAPHICS_STATUS)(1 << 3)
|
||||
#define DeactivateGraphics() (_GraphicsStatusFlags &= ~GRAPHICS_ACTIVE)
|
||||
#define ActivateGraphics() (_GraphicsStatusFlags |= GRAPHICS_ACTIVE)
|
||||
#define GraphicsActive() (_GraphicsStatusFlags & GRAPHICS_ACTIVE)
|
||||
#define DeactivateVisible() (_GraphicsStatusFlags &= ~GRAPHICS_VISIBLE)
|
||||
#define ActivateVisible() (_GraphicsStatusFlags |= GRAPHICS_VISIBLE)
|
||||
#define DeactivateContext() (_GraphicsStatusFlags &= ~CONTEXT_ACTIVE)
|
||||
#define ActivateContext() (_GraphicsStatusFlags |= CONTEXT_ACTIVE)
|
||||
#define ContextActive() (_GraphicsStatusFlags & CONTEXT_ACTIVE)
|
||||
#define DeactivateDrawable() (_GraphicsStatusFlags &= ~DRAWABLE_ACTIVE)
|
||||
#define ActivateDrawable() (_GraphicsStatusFlags |= DRAWABLE_ACTIVE)
|
||||
#define DrawableActive() (_GraphicsStatusFlags & DRAWABLE_ACTIVE)
|
||||
|
||||
#define SYSTEM_ACTIVE (GRAPHICS_STATUS)(CONTEXT_ACTIVE | DRAWABLE_ACTIVE)
|
||||
|
||||
#define GraphicsSystemActive() \
|
||||
((_GraphicsStatusFlags & SYSTEM_ACTIVE) == SYSTEM_ACTIVE)
|
||||
#define GraphicsStatus() \
|
||||
(_GraphicsStatusFlags & (GRAPHICS_STATUS)(GRAPHICS_ACTIVE \
|
||||
| GRAPHICS_VISIBLE))
|
||||
|
||||
// pValidRect or origin may be NULL
|
||||
BOOLEAN GetContextValidRect (RECT *pValidRect, POINT *origin);
|
||||
extern void FixContextFontEffect (void);
|
||||
|
||||
#endif /* _CONTEXT_H */
|
||||
|
||||
@@ -1,589 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/threadlib.h"
|
||||
#include "libs/graphics/drawcmd.h"
|
||||
#include "libs/graphics/drawable.h"
|
||||
#include "libs/graphics/context.h"
|
||||
#include "libs/graphics/dcqueue.h"
|
||||
#include "libs/graphics/gfx_common.h"
|
||||
#include "libs/graphics/bbox.h"
|
||||
#include "libs/timelib.h"
|
||||
#include "libs/log.h"
|
||||
#include "libs/misc.h"
|
||||
// for TFB_DEBUG_HALT
|
||||
|
||||
|
||||
static RecursiveMutex DCQ_Mutex;
|
||||
|
||||
CondVar RenderingCond;
|
||||
|
||||
TFB_DrawCommand DCQ[DCQ_MAX];
|
||||
|
||||
TFB_DrawCommandQueue DrawCommandQueue;
|
||||
|
||||
#define FPS_PERIOD (ONE_SECOND / 100)
|
||||
int RenderedFrames = 0;
|
||||
|
||||
|
||||
// Wait for the queue to be emptied.
|
||||
static void
|
||||
TFB_WaitForSpace (int requested_slots)
|
||||
{
|
||||
int old_depth, i;
|
||||
log_add (log_Debug, "DCQ overload (Size = %d, FullSize = %d, "
|
||||
"Requested = %d). Sleeping until renderer is done.",
|
||||
DrawCommandQueue.Size, DrawCommandQueue.FullSize,
|
||||
requested_slots);
|
||||
// Restore the DCQ locking level. I *think* this is
|
||||
// always 1, but...
|
||||
TFB_BatchReset ();
|
||||
old_depth = GetRecursiveMutexDepth (DCQ_Mutex);
|
||||
for (i = 0; i < old_depth; i++)
|
||||
UnlockRecursiveMutex (DCQ_Mutex);
|
||||
WaitCondVar (RenderingCond);
|
||||
for (i = 0; i < old_depth; i++)
|
||||
LockRecursiveMutex (DCQ_Mutex);
|
||||
log_add (log_Debug, "DCQ clear (Size = %d, FullSize = %d). Continuing.",
|
||||
DrawCommandQueue.Size, DrawCommandQueue.FullSize);
|
||||
}
|
||||
|
||||
void
|
||||
Lock_DCQ (int slots)
|
||||
{
|
||||
LockRecursiveMutex (DCQ_Mutex);
|
||||
while (DrawCommandQueue.FullSize >= DCQ_MAX - slots)
|
||||
{
|
||||
TFB_WaitForSpace (slots);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Unlock_DCQ (void)
|
||||
{
|
||||
UnlockRecursiveMutex (DCQ_Mutex);
|
||||
}
|
||||
|
||||
// Always have the DCQ locked when calling this.
|
||||
static void
|
||||
Synchronize_DCQ (void)
|
||||
{
|
||||
if (!DrawCommandQueue.Batching)
|
||||
{
|
||||
int front = DrawCommandQueue.Front;
|
||||
int back = DrawCommandQueue.InsertionPoint;
|
||||
DrawCommandQueue.Back = DrawCommandQueue.InsertionPoint;
|
||||
if (front <= back)
|
||||
{
|
||||
DrawCommandQueue.Size = (back - front);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawCommandQueue.Size = (back + DCQ_MAX - front);
|
||||
}
|
||||
DrawCommandQueue.FullSize = DrawCommandQueue.Size;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TFB_BatchGraphics (void)
|
||||
{
|
||||
LockRecursiveMutex (DCQ_Mutex);
|
||||
DrawCommandQueue.Batching++;
|
||||
UnlockRecursiveMutex (DCQ_Mutex);
|
||||
}
|
||||
|
||||
void
|
||||
TFB_UnbatchGraphics (void)
|
||||
{
|
||||
LockRecursiveMutex (DCQ_Mutex);
|
||||
if (DrawCommandQueue.Batching)
|
||||
{
|
||||
DrawCommandQueue.Batching--;
|
||||
}
|
||||
Synchronize_DCQ ();
|
||||
UnlockRecursiveMutex (DCQ_Mutex);
|
||||
}
|
||||
|
||||
// Cancel all pending batch operations, making them unbatched. This will
|
||||
// cause a small amount of flicker when invoked, but prevents
|
||||
// batching problems from freezing the game.
|
||||
void
|
||||
TFB_BatchReset (void)
|
||||
{
|
||||
LockRecursiveMutex (DCQ_Mutex);
|
||||
DrawCommandQueue.Batching = 0;
|
||||
Synchronize_DCQ ();
|
||||
UnlockRecursiveMutex (DCQ_Mutex);
|
||||
}
|
||||
|
||||
|
||||
// Draw Command Queue Stuff
|
||||
|
||||
void
|
||||
Init_DrawCommandQueue (void)
|
||||
{
|
||||
DrawCommandQueue.Back = 0;
|
||||
DrawCommandQueue.Front = 0;
|
||||
DrawCommandQueue.InsertionPoint = 0;
|
||||
DrawCommandQueue.Batching = 0;
|
||||
DrawCommandQueue.FullSize = 0;
|
||||
DrawCommandQueue.Size = 0;
|
||||
|
||||
TFB_BBox_Init (ScreenWidth, ScreenHeight);
|
||||
|
||||
DCQ_Mutex = CreateRecursiveMutex ("DCQ",
|
||||
SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
|
||||
|
||||
RenderingCond = CreateCondVar ("DCQ empty",
|
||||
SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
|
||||
}
|
||||
|
||||
void
|
||||
Uninit_DrawCommandQueue (void)
|
||||
{
|
||||
DestroyCondVar (RenderingCond);
|
||||
DestroyRecursiveMutex (DCQ_Mutex);
|
||||
}
|
||||
|
||||
void
|
||||
TFB_DrawCommandQueue_Push (TFB_DrawCommand* Command)
|
||||
{
|
||||
Lock_DCQ (1);
|
||||
DCQ[DrawCommandQueue.InsertionPoint] = *Command;
|
||||
DrawCommandQueue.InsertionPoint = (DrawCommandQueue.InsertionPoint + 1)
|
||||
% DCQ_MAX;
|
||||
DrawCommandQueue.FullSize++;
|
||||
Synchronize_DCQ ();
|
||||
Unlock_DCQ ();
|
||||
}
|
||||
|
||||
int
|
||||
TFB_DrawCommandQueue_Pop (TFB_DrawCommand *target)
|
||||
{
|
||||
LockRecursiveMutex (DCQ_Mutex);
|
||||
|
||||
if (DrawCommandQueue.Size == 0)
|
||||
{
|
||||
Unlock_DCQ ();
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (DrawCommandQueue.Front == DrawCommandQueue.Back &&
|
||||
DrawCommandQueue.Size != DCQ_MAX)
|
||||
{
|
||||
log_add (log_Debug, "Augh! Assertion failure in DCQ! "
|
||||
"Front == Back, Size != DCQ_MAX");
|
||||
DrawCommandQueue.Size = 0;
|
||||
Unlock_DCQ ();
|
||||
return (0);
|
||||
}
|
||||
|
||||
*target = DCQ[DrawCommandQueue.Front];
|
||||
DrawCommandQueue.Front = (DrawCommandQueue.Front + 1) % DCQ_MAX;
|
||||
|
||||
DrawCommandQueue.Size--;
|
||||
DrawCommandQueue.FullSize--;
|
||||
UnlockRecursiveMutex (DCQ_Mutex);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
TFB_DrawCommandQueue_Clear ()
|
||||
{
|
||||
LockRecursiveMutex (DCQ_Mutex);
|
||||
DrawCommandQueue.Size = 0;
|
||||
DrawCommandQueue.Front = 0;
|
||||
DrawCommandQueue.Back = 0;
|
||||
DrawCommandQueue.Batching = 0;
|
||||
DrawCommandQueue.FullSize = 0;
|
||||
DrawCommandQueue.InsertionPoint = 0;
|
||||
UnlockRecursiveMutex (DCQ_Mutex);
|
||||
}
|
||||
|
||||
void
|
||||
TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand)
|
||||
{
|
||||
if (TFB_DEBUG_HALT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (DrawCommand->Type <= TFB_DRAWCOMMANDTYPE_COPYTOIMAGE
|
||||
&& _CurFramePtr->Type == SCREEN_DRAWABLE)
|
||||
{
|
||||
static RECT scissor_rect;
|
||||
|
||||
// Set the clipping region.
|
||||
// We allow drawing with no current context set, so the whole screen
|
||||
if ((_pCurContext && !rectsEqual (scissor_rect, _pCurContext->ClipRect))
|
||||
|| (!_pCurContext && scissor_rect.extent.width != 0))
|
||||
{
|
||||
// Enqueue command to set the glScissor spec
|
||||
TFB_DrawCommand DC;
|
||||
|
||||
if (_pCurContext)
|
||||
scissor_rect = _pCurContext->ClipRect;
|
||||
else
|
||||
scissor_rect.extent.width = 0;
|
||||
|
||||
if (scissor_rect.extent.width)
|
||||
{
|
||||
DC.Type = TFB_DRAWCOMMANDTYPE_SCISSORENABLE;
|
||||
DC.data.scissor.rect = scissor_rect;
|
||||
}
|
||||
else
|
||||
{
|
||||
DC.Type = TFB_DRAWCOMMANDTYPE_SCISSORDISABLE;
|
||||
}
|
||||
|
||||
TFB_EnqueueDrawCommand(&DC);
|
||||
}
|
||||
}
|
||||
|
||||
TFB_DrawCommandQueue_Push (DrawCommand);
|
||||
}
|
||||
|
||||
static void
|
||||
computeFPS (void)
|
||||
{
|
||||
static TimeCount last_time;
|
||||
static TimePeriod fps_counter;
|
||||
TimeCount current_time;
|
||||
TimePeriod delta_time;
|
||||
|
||||
current_time = GetTimeCounter ();
|
||||
delta_time = current_time - last_time;
|
||||
last_time = current_time;
|
||||
|
||||
fps_counter += delta_time;
|
||||
if (fps_counter > FPS_PERIOD)
|
||||
{
|
||||
log_add (log_User, "fps %.2f, effective %.2f",
|
||||
(float)ONE_SECOND / delta_time,
|
||||
(float)ONE_SECOND * RenderedFrames / fps_counter);
|
||||
|
||||
fps_counter = 0;
|
||||
RenderedFrames = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Only call from main() thread!!
|
||||
void
|
||||
TFB_FlushGraphics (void)
|
||||
{
|
||||
int commands_handled;
|
||||
BOOLEAN livelock_deterrence;
|
||||
|
||||
// This is technically a locking violation on DrawCommandQueue.Size,
|
||||
// but it is likely to not be very destructive.
|
||||
if (DrawCommandQueue.Size == 0)
|
||||
{
|
||||
static int last_fade = 255;
|
||||
static int last_transition = 255;
|
||||
int current_fade = GetFadeAmount ();
|
||||
int current_transition = TransitionAmount;
|
||||
|
||||
if ((current_fade != 255 && current_fade != last_fade) ||
|
||||
(current_transition != 255 &&
|
||||
current_transition != last_transition) ||
|
||||
(current_fade == 255 && last_fade != 255) ||
|
||||
(current_transition == 255 && last_transition != 255))
|
||||
{
|
||||
TFB_SwapBuffers (TFB_REDRAW_FADING);
|
||||
// if fading, redraw every frame
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskSwitch ();
|
||||
}
|
||||
|
||||
last_fade = current_fade;
|
||||
last_transition = current_transition;
|
||||
BroadcastCondVar (RenderingCond);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GfxFlags & TFB_GFXFLAGS_SHOWFPS)
|
||||
computeFPS ();
|
||||
|
||||
commands_handled = 0;
|
||||
livelock_deterrence = FALSE;
|
||||
|
||||
if (DrawCommandQueue.FullSize > DCQ_FORCE_BREAK_SIZE)
|
||||
{
|
||||
TFB_BatchReset ();
|
||||
}
|
||||
|
||||
if (DrawCommandQueue.Size > DCQ_FORCE_SLOWDOWN_SIZE)
|
||||
{
|
||||
Lock_DCQ (-1);
|
||||
livelock_deterrence = TRUE;
|
||||
}
|
||||
|
||||
TFB_BBox_Reset ();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
TFB_DrawCommand DC;
|
||||
|
||||
if (!TFB_DrawCommandQueue_Pop (&DC))
|
||||
{
|
||||
// the Queue is now empty.
|
||||
break;
|
||||
}
|
||||
|
||||
++commands_handled;
|
||||
if (!livelock_deterrence && commands_handled + DrawCommandQueue.Size
|
||||
> DCQ_LIVELOCK_MAX)
|
||||
{
|
||||
// log_add (log_Debug, "Initiating livelock deterrence!");
|
||||
livelock_deterrence = TRUE;
|
||||
|
||||
Lock_DCQ (-1);
|
||||
}
|
||||
|
||||
switch (DC.Type)
|
||||
{
|
||||
case TFB_DRAWCOMMANDTYPE_SETMIPMAP:
|
||||
{
|
||||
TFB_DrawCommand_SetMipmap *cmd = &DC.data.setmipmap;
|
||||
TFB_DrawImage_SetMipmap (cmd->image, cmd->mipmap,
|
||||
cmd->hotx, cmd->hoty);
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_IMAGE:
|
||||
{
|
||||
TFB_DrawCommand_Image *cmd = &DC.data.image;
|
||||
TFB_Image *DC_image = cmd->image;
|
||||
const int x = cmd->x;
|
||||
const int y = cmd->y;
|
||||
|
||||
TFB_DrawCanvas_Image (DC_image, x, y,
|
||||
cmd->scale, cmd->scaleMode, cmd->colormap,
|
||||
cmd->drawMode,
|
||||
TFB_GetScreenCanvas (cmd->destBuffer));
|
||||
|
||||
if (cmd->destBuffer == TFB_SCREEN_MAIN)
|
||||
{
|
||||
LockMutex (DC_image->mutex);
|
||||
if (cmd->scale)
|
||||
TFB_BBox_RegisterCanvas (DC_image->ScaledImg,
|
||||
x - DC_image->last_scale_hs.x,
|
||||
y - DC_image->last_scale_hs.y);
|
||||
else
|
||||
TFB_BBox_RegisterCanvas (DC_image->NormalImg,
|
||||
x - DC_image->NormalHs.x,
|
||||
y - DC_image->NormalHs.y);
|
||||
UnlockMutex (DC_image->mutex);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_FILLEDIMAGE:
|
||||
{
|
||||
TFB_DrawCommand_FilledImage *cmd = &DC.data.filledimage;
|
||||
TFB_Image *DC_image = cmd->image;
|
||||
const int x = cmd->x;
|
||||
const int y = cmd->y;
|
||||
|
||||
TFB_DrawCanvas_FilledImage (DC_image, x, y,
|
||||
cmd->scale, cmd->scaleMode, cmd->color,
|
||||
cmd->drawMode,
|
||||
TFB_GetScreenCanvas (cmd->destBuffer));
|
||||
|
||||
if (cmd->destBuffer == TFB_SCREEN_MAIN)
|
||||
{
|
||||
LockMutex (DC_image->mutex);
|
||||
if (cmd->scale)
|
||||
TFB_BBox_RegisterCanvas (DC_image->ScaledImg,
|
||||
x - DC_image->last_scale_hs.x,
|
||||
y - DC_image->last_scale_hs.y);
|
||||
else
|
||||
TFB_BBox_RegisterCanvas (DC_image->NormalImg,
|
||||
x - DC_image->NormalHs.x,
|
||||
y - DC_image->NormalHs.y);
|
||||
UnlockMutex (DC_image->mutex);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_FONTCHAR:
|
||||
{
|
||||
TFB_DrawCommand_FontChar *cmd = &DC.data.fontchar;
|
||||
TFB_Char *DC_char = cmd->fontchar;
|
||||
const int x = cmd->x;
|
||||
const int y = cmd->y;
|
||||
|
||||
TFB_DrawCanvas_FontChar (DC_char, cmd->backing, x, y,
|
||||
cmd->drawMode, TFB_GetScreenCanvas (cmd->destBuffer));
|
||||
|
||||
if (cmd->destBuffer == TFB_SCREEN_MAIN)
|
||||
{
|
||||
RECT r;
|
||||
|
||||
r.corner.x = x - DC_char->HotSpot.x;
|
||||
r.corner.y = y - DC_char->HotSpot.y;
|
||||
r.extent.width = DC_char->extent.width;
|
||||
r.extent.height = DC_char->extent.height;
|
||||
|
||||
TFB_BBox_RegisterRect (&r);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_LINE:
|
||||
{
|
||||
TFB_DrawCommand_Line *cmd = &DC.data.line;
|
||||
|
||||
if (cmd->destBuffer == TFB_SCREEN_MAIN)
|
||||
{
|
||||
TFB_BBox_RegisterPoint (cmd->x1, cmd->y1);
|
||||
TFB_BBox_RegisterPoint (cmd->x2, cmd->y2);
|
||||
}
|
||||
TFB_DrawCanvas_Line (cmd->x1, cmd->y1, cmd->x2, cmd->y2,
|
||||
cmd->color, cmd->drawMode,
|
||||
TFB_GetScreenCanvas (cmd->destBuffer));
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_RECTANGLE:
|
||||
{
|
||||
TFB_DrawCommand_Rect *cmd = &DC.data.rect;
|
||||
|
||||
if (cmd->destBuffer == TFB_SCREEN_MAIN)
|
||||
TFB_BBox_RegisterRect (&cmd->rect);
|
||||
TFB_DrawCanvas_Rect (&cmd->rect, cmd->color, cmd->drawMode,
|
||||
TFB_GetScreenCanvas (cmd->destBuffer));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_SCISSORENABLE:
|
||||
{
|
||||
TFB_DrawCommand_Scissor *cmd = &DC.data.scissor;
|
||||
|
||||
TFB_DrawCanvas_SetClipRect (
|
||||
TFB_GetScreenCanvas (TFB_SCREEN_MAIN), &cmd->rect);
|
||||
TFB_BBox_SetClipRect (&DC.data.scissor.rect);
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_SCISSORDISABLE:
|
||||
TFB_DrawCanvas_SetClipRect (
|
||||
TFB_GetScreenCanvas (TFB_SCREEN_MAIN), NULL);
|
||||
TFB_BBox_SetClipRect (NULL);
|
||||
break;
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_COPYTOIMAGE:
|
||||
{
|
||||
TFB_DrawCommand_CopyToImage *cmd = &DC.data.copytoimage;
|
||||
TFB_Image *DC_image = cmd->image;
|
||||
const POINT dstPt = {0, 0};
|
||||
|
||||
if (DC_image == 0)
|
||||
{
|
||||
log_add (log_Debug, "DCQ ERROR: COPYTOIMAGE passed null "
|
||||
"image ptr");
|
||||
break;
|
||||
}
|
||||
LockMutex (DC_image->mutex);
|
||||
TFB_DrawCanvas_CopyRect (
|
||||
TFB_GetScreenCanvas (cmd->srcBuffer), &cmd->rect,
|
||||
DC_image->NormalImg, dstPt);
|
||||
UnlockMutex (DC_image->mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_COPY:
|
||||
{
|
||||
TFB_DrawCommand_Copy *cmd = &DC.data.copy;
|
||||
const RECT r = cmd->rect;
|
||||
|
||||
if (cmd->destBuffer == TFB_SCREEN_MAIN)
|
||||
TFB_BBox_RegisterRect (&cmd->rect);
|
||||
|
||||
TFB_DrawCanvas_CopyRect (
|
||||
TFB_GetScreenCanvas (cmd->srcBuffer), &r,
|
||||
TFB_GetScreenCanvas (cmd->destBuffer), r.corner);
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_DELETEIMAGE:
|
||||
{
|
||||
TFB_Image *DC_image = DC.data.deleteimage.image;
|
||||
TFB_DrawImage_Delete (DC_image);
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_DELETEDATA:
|
||||
{
|
||||
void *data = DC.data.deletedata.data;
|
||||
HFree (data);
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_SENDSIGNAL:
|
||||
ClearSemaphore (DC.data.sendsignal.sem);
|
||||
break;
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_REINITVIDEO:
|
||||
{
|
||||
TFB_DrawCommand_ReinitVideo *cmd = &DC.data.reinitvideo;
|
||||
int oldDriver = GraphicsDriver;
|
||||
int oldFlags = GfxFlags;
|
||||
int oldWidth = ScreenWidthActual;
|
||||
int oldHeight = ScreenHeightActual;
|
||||
if (TFB_ReInitGraphics (cmd->driver, cmd->flags,
|
||||
cmd->width, cmd->height))
|
||||
{
|
||||
log_add (log_Error, "Could not provide requested mode: "
|
||||
"reverting to last known driver.");
|
||||
// We don't know what exactly failed, so roll it all back
|
||||
if (TFB_ReInitGraphics (oldDriver, oldFlags,
|
||||
oldWidth, oldHeight))
|
||||
{
|
||||
log_add (log_Fatal,
|
||||
"Couldn't reinit at that point either. "
|
||||
"Your video has been somehow tied in knots.");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
TFB_SwapBuffers (TFB_REDRAW_YES);
|
||||
break;
|
||||
}
|
||||
|
||||
case TFB_DRAWCOMMANDTYPE_CALLBACK:
|
||||
{
|
||||
DC.data.callback.callback (DC.data.callback.arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (livelock_deterrence)
|
||||
Unlock_DCQ ();
|
||||
|
||||
TFB_SwapBuffers (TFB_REDRAW_NO);
|
||||
RenderedFrames++;
|
||||
BroadcastCondVar (RenderingCond);
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef DCQUEUE_H
|
||||
#define DCQUEUE_H
|
||||
|
||||
// Maximum size of the DCQ. The larger the DCQ, the larger frameskips
|
||||
// become tolerable before initiating livelock deterrence and game
|
||||
// slowdown. Other constants for controlling the frameskip/slowdown
|
||||
// balance may be found in sdl_common.c near TFB_FlushGraphics.
|
||||
|
||||
// Livelock deterrance constants. Because the entire screen is rarely
|
||||
// refreshed, we may not drop draw commands on the floor with abandon.
|
||||
// Furthermore, if the main program is queuing commands at a speed
|
||||
// comparable to our processing of the commands, we never finish and
|
||||
// the game freezes. Thus, if the queue starts out larger than
|
||||
// DCQ_FORCE_SLOWDOWN_SIZE, or DCQ_LIVELOCK_MAX commands find
|
||||
// themselves being processed in one go, livelock deterrence is
|
||||
// enabled, and TFB_FlushGraphics locks the DCQ until it has processed
|
||||
// all entries. If batched but pending commands exceed DCQ_FORCE_BREAK_SIZE,
|
||||
// a continuity break is performed. This will effectively slow down the
|
||||
// game logic, a fate we seek to avoid - however, it seems to be unavoidable
|
||||
// on slower machines. Even there, it's seems nonexistent outside of
|
||||
// communications screens. --Michael
|
||||
|
||||
#ifdef DCQ_OF_DOOM
|
||||
#define DCQ_MAX 512
|
||||
#define DCQ_FORCE_SLOWDOWN_SIZE 128
|
||||
#define DCQ_FORCE_BREAK_SIZE 512
|
||||
#define DCQ_LIVELOCK_MAX 256
|
||||
#else
|
||||
#define DCQ_MAX 16384
|
||||
#define DCQ_FORCE_SLOWDOWN_SIZE 4096
|
||||
#define DCQ_FORCE_BREAK_SIZE 16384
|
||||
#define DCQ_LIVELOCK_MAX 4096
|
||||
#endif
|
||||
|
||||
extern CondVar RenderingCond;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,501 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "libs/gfxlib.h"
|
||||
#include "libs/graphics/context.h"
|
||||
#include "libs/graphics/drawable.h"
|
||||
#include "libs/graphics/tfb_draw.h"
|
||||
#include "libs/memlib.h"
|
||||
#include "tfb_draw.h"
|
||||
#include <math.h>
|
||||
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
FRAME _CurFramePtr;
|
||||
|
||||
FRAME
|
||||
SetContextFGFrame (FRAME Frame)
|
||||
{
|
||||
FRAME LastFrame;
|
||||
|
||||
if (Frame != (LastFrame = (FRAME)_CurFramePtr))
|
||||
{
|
||||
if (LastFrame)
|
||||
DeactivateDrawable ();
|
||||
|
||||
_CurFramePtr = Frame;
|
||||
if (_CurFramePtr)
|
||||
ActivateDrawable ();
|
||||
|
||||
if (ContextActive ())
|
||||
{
|
||||
SwitchContextFGFrame (Frame);
|
||||
}
|
||||
}
|
||||
|
||||
return (LastFrame);
|
||||
}
|
||||
|
||||
FRAME
|
||||
GetContextFGFrame (void)
|
||||
{
|
||||
return _CurFramePtr;
|
||||
}
|
||||
|
||||
static DRAWABLE
|
||||
request_drawable (COUNT NumFrames, DRAWABLE_TYPE DrawableType,
|
||||
CREATE_FLAGS flags, SIZE width, SIZE height)
|
||||
{
|
||||
DRAWABLE Drawable;
|
||||
COUNT i;
|
||||
|
||||
Drawable = AllocDrawable (NumFrames);
|
||||
if (!Drawable)
|
||||
return NULL;
|
||||
|
||||
Drawable->Flags = flags;
|
||||
Drawable->MaxIndex = NumFrames - 1;
|
||||
|
||||
for (i = 0; i < NumFrames; ++i)
|
||||
{
|
||||
FRAME FramePtr = &Drawable->Frame[i];
|
||||
|
||||
if (DrawableType == RAM_DRAWABLE && width > 0 && height > 0)
|
||||
{
|
||||
FramePtr->image = TFB_DrawImage_New (TFB_DrawCanvas_New_TrueColor (
|
||||
width, height, (flags & WANT_ALPHA) ? TRUE : FALSE));
|
||||
}
|
||||
|
||||
FramePtr->Type = DrawableType;
|
||||
FramePtr->Index = i;
|
||||
SetFrameBounds (FramePtr, width, height);
|
||||
}
|
||||
|
||||
return Drawable;
|
||||
}
|
||||
|
||||
DRAWABLE
|
||||
CreateDisplay (CREATE_FLAGS CreateFlags, SIZE *pwidth, SIZE *pheight)
|
||||
{
|
||||
DRAWABLE Drawable;
|
||||
|
||||
// TODO: ScreenWidth and ScreenHeight should be passed in
|
||||
// instead of returned.
|
||||
Drawable = request_drawable (1, SCREEN_DRAWABLE,
|
||||
(CreateFlags & (WANT_PIXMAP | WANT_MASK)),
|
||||
ScreenWidth, ScreenHeight);
|
||||
if (Drawable)
|
||||
{
|
||||
FRAME F;
|
||||
|
||||
F = CaptureDrawable (Drawable);
|
||||
if (F == 0)
|
||||
DestroyDrawable (Drawable);
|
||||
else
|
||||
{
|
||||
*pwidth = GetFrameWidth (F);
|
||||
*pheight = GetFrameHeight (F);
|
||||
|
||||
ReleaseDrawable (F);
|
||||
return (Drawable);
|
||||
}
|
||||
}
|
||||
|
||||
*pwidth = *pheight = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
DRAWABLE
|
||||
AllocDrawable (COUNT n)
|
||||
{
|
||||
DRAWABLE Drawable;
|
||||
Drawable = (DRAWABLE) HCalloc(sizeof (DRAWABLE_DESC));
|
||||
if (Drawable)
|
||||
{
|
||||
int i;
|
||||
Drawable->Frame = (FRAME)HMalloc (sizeof (FRAME_DESC) * n);
|
||||
if (Drawable->Frame == NULL)
|
||||
{
|
||||
HFree (Drawable);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Zero out the newly allocated frames, since HMalloc doesn't have
|
||||
* MEM_ZEROINIT. */
|
||||
for (i = 0; i < n; i++) {
|
||||
FRAME F;
|
||||
F = &Drawable->Frame[i];
|
||||
F->parent = Drawable;
|
||||
F->Type = 0;
|
||||
F->Index = 0;
|
||||
F->image = 0;
|
||||
F->Bounds.width = 0;
|
||||
F->Bounds.height = 0;
|
||||
F->HotSpot.x = 0;
|
||||
F->HotSpot.y = 0;
|
||||
}
|
||||
}
|
||||
return Drawable;
|
||||
}
|
||||
|
||||
DRAWABLE
|
||||
CreateDrawable (CREATE_FLAGS CreateFlags, SIZE width, SIZE height, COUNT
|
||||
num_frames)
|
||||
{
|
||||
DRAWABLE Drawable;
|
||||
|
||||
Drawable = request_drawable (num_frames, RAM_DRAWABLE,
|
||||
(CreateFlags & (WANT_MASK | WANT_PIXMAP
|
||||
| WANT_ALPHA | MAPPED_TO_DISPLAY)),
|
||||
width, height);
|
||||
if (Drawable)
|
||||
{
|
||||
FRAME F;
|
||||
|
||||
F = CaptureDrawable (Drawable);
|
||||
if (F)
|
||||
{
|
||||
ReleaseDrawable (F);
|
||||
|
||||
return (Drawable);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
DestroyDrawable (DRAWABLE Drawable)
|
||||
{
|
||||
if (_CurFramePtr && (Drawable == _CurFramePtr->parent))
|
||||
SetContextFGFrame ((FRAME)NULL);
|
||||
|
||||
if (Drawable)
|
||||
{
|
||||
FreeDrawable (Drawable);
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
GetFrameRect (FRAME FramePtr, RECT *pRect)
|
||||
{
|
||||
if (FramePtr)
|
||||
{
|
||||
pRect->corner.x = -FramePtr->HotSpot.x;
|
||||
pRect->corner.y = -FramePtr->HotSpot.y;
|
||||
pRect->extent = GetFrameBounds (FramePtr);
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
HOT_SPOT
|
||||
SetFrameHot (FRAME FramePtr, HOT_SPOT HotSpot)
|
||||
{
|
||||
if (FramePtr)
|
||||
{
|
||||
HOT_SPOT OldHot;
|
||||
|
||||
OldHot = FramePtr->HotSpot;
|
||||
FramePtr->HotSpot = HotSpot;
|
||||
|
||||
return (OldHot);
|
||||
}
|
||||
|
||||
return (MAKE_HOT_SPOT (0, 0));
|
||||
}
|
||||
|
||||
HOT_SPOT
|
||||
GetFrameHot (FRAME FramePtr)
|
||||
{
|
||||
if (FramePtr)
|
||||
{
|
||||
return FramePtr->HotSpot;
|
||||
}
|
||||
|
||||
return (MAKE_HOT_SPOT (0, 0));
|
||||
}
|
||||
|
||||
DRAWABLE
|
||||
RotateFrame (FRAME Frame, int angle_deg)
|
||||
{
|
||||
DRAWABLE Drawable;
|
||||
FRAME RotFramePtr;
|
||||
double dx, dy;
|
||||
double d;
|
||||
double angle = angle_deg * M_PI / 180;
|
||||
|
||||
if (!Frame)
|
||||
return NULL;
|
||||
|
||||
assert (Frame->Type != SCREEN_DRAWABLE);
|
||||
|
||||
Drawable = request_drawable (1, RAM_DRAWABLE, WANT_PIXMAP, 0, 0);
|
||||
if (!Drawable)
|
||||
return 0;
|
||||
RotFramePtr = CaptureDrawable (Drawable);
|
||||
if (!RotFramePtr)
|
||||
{
|
||||
FreeDrawable (Drawable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
RotFramePtr->image = TFB_DrawImage_New_Rotated (
|
||||
Frame->image, angle_deg);
|
||||
SetFrameBounds (RotFramePtr, RotFramePtr->image->extent.width,
|
||||
RotFramePtr->image->extent.height);
|
||||
|
||||
/* now we need to rotate the hot-spot, eww */
|
||||
dx = Frame->HotSpot.x - (GetFrameWidth (Frame) / 2);
|
||||
dy = Frame->HotSpot.y - (GetFrameHeight (Frame) / 2);
|
||||
d = sqrt ((double)dx*dx + (double)dy*dy);
|
||||
if ((int)d != 0)
|
||||
{
|
||||
double organg = atan2 (-dy, dx);
|
||||
dx = cos (organg + angle) * d;
|
||||
dy = -sin (organg + angle) * d;
|
||||
}
|
||||
RotFramePtr->HotSpot.x = (GetFrameWidth (RotFramePtr) / 2) + (int)dx;
|
||||
RotFramePtr->HotSpot.y = (GetFrameHeight (RotFramePtr) / 2) + (int)dy;
|
||||
|
||||
ReleaseDrawable (RotFramePtr);
|
||||
|
||||
return Drawable;
|
||||
}
|
||||
|
||||
// color.a is ignored
|
||||
void
|
||||
SetFrameTransparentColor (FRAME frame, Color color)
|
||||
{
|
||||
TFB_Image *img;
|
||||
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
assert (frame->Type != SCREEN_DRAWABLE);
|
||||
|
||||
img = frame->image;
|
||||
LockMutex (img->mutex);
|
||||
|
||||
// TODO: This should defer to TFB_DrawImage instead
|
||||
TFB_DrawCanvas_SetTransparentColor (img->NormalImg, color, FALSE);
|
||||
|
||||
UnlockMutex (img->mutex);
|
||||
}
|
||||
|
||||
Color
|
||||
GetFramePixel (FRAME frame, POINT pixelPt)
|
||||
{
|
||||
TFB_Image *img;
|
||||
Color ret;
|
||||
|
||||
if (!frame)
|
||||
return BUILD_COLOR_RGBA (0, 0, 0, 0);
|
||||
|
||||
assert (frame->Type != SCREEN_DRAWABLE);
|
||||
|
||||
img = frame->image;
|
||||
LockMutex (img->mutex);
|
||||
|
||||
// TODO: This should defer to TFB_DrawImage instead
|
||||
ret = TFB_DrawCanvas_GetPixel (img->NormalImg, pixelPt.x, pixelPt.y);
|
||||
|
||||
UnlockMutex (img->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FRAME
|
||||
makeMatchingFrame (FRAME frame, int width, int height)
|
||||
{
|
||||
DRAWABLE drawable;
|
||||
FRAME newFrame;
|
||||
CREATE_FLAGS flags;
|
||||
|
||||
flags = GetFrameParentDrawable (frame)->Flags;
|
||||
drawable = CreateDrawable (flags, width, height, 1);
|
||||
if (!drawable)
|
||||
return NULL;
|
||||
newFrame = CaptureDrawable (drawable);
|
||||
if (!newFrame)
|
||||
{
|
||||
FreeDrawable (drawable);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return newFrame;
|
||||
}
|
||||
|
||||
// Creates an new DRAWABLE containing a copy of specified FRAME's rect
|
||||
// Source FRAME must not be a SCREEN_DRAWABLE
|
||||
DRAWABLE
|
||||
CopyFrameRect (FRAME frame, const RECT *area)
|
||||
{
|
||||
FRAME newFrame;
|
||||
POINT nullPt = MAKE_POINT (0, 0);
|
||||
|
||||
if (!frame)
|
||||
return NULL;
|
||||
|
||||
assert (frame->Type != SCREEN_DRAWABLE);
|
||||
|
||||
newFrame = makeMatchingFrame (frame, area->extent.width,
|
||||
area->extent.height);
|
||||
if (!newFrame)
|
||||
return NULL;
|
||||
|
||||
TFB_DrawImage_CopyRect (frame->image, area, newFrame->image, nullPt);
|
||||
|
||||
return ReleaseDrawable (newFrame);
|
||||
}
|
||||
|
||||
// Creates an new DRAWABLE mostly identical to specified FRAME
|
||||
// Source FRAME must not be a SCREEN_DRAWABLE
|
||||
DRAWABLE
|
||||
CloneFrame (FRAME frame)
|
||||
{
|
||||
FRAME newFrame;
|
||||
RECT r;
|
||||
|
||||
if (!frame)
|
||||
return NULL;
|
||||
|
||||
assert (frame->Type != SCREEN_DRAWABLE);
|
||||
|
||||
GetFrameRect (frame, &r);
|
||||
r.corner.x = 0;
|
||||
r.corner.y = 0;
|
||||
|
||||
newFrame = CaptureDrawable (CopyFrameRect (frame, &r));
|
||||
if (!newFrame)
|
||||
return NULL;
|
||||
|
||||
// copy the hot-spot
|
||||
newFrame->HotSpot = frame->HotSpot;
|
||||
|
||||
return ReleaseDrawable (newFrame);
|
||||
}
|
||||
|
||||
// Creates a new DRAWABLE of specified size and scales the passed
|
||||
// frame onto it. The aspect ratio is not preserved.
|
||||
DRAWABLE
|
||||
RescaleFrame (FRAME frame, int width, int height)
|
||||
{
|
||||
FRAME newFrame;
|
||||
TFB_Image *img;
|
||||
TFB_Canvas src, dst;
|
||||
|
||||
if (!frame)
|
||||
return NULL;
|
||||
|
||||
assert (frame->Type != SCREEN_DRAWABLE);
|
||||
|
||||
newFrame = makeMatchingFrame (frame, width, height);
|
||||
if (!newFrame)
|
||||
return NULL;
|
||||
|
||||
// scale the hot-spot
|
||||
newFrame->HotSpot.x = frame->HotSpot.x * width / frame->Bounds.width;
|
||||
newFrame->HotSpot.y = frame->HotSpot.y * height / frame->Bounds.height;
|
||||
|
||||
img = frame->image;
|
||||
LockMutex (img->mutex);
|
||||
// NOTE: We do not lock the target image because nothing has a
|
||||
// reference to it yet!
|
||||
src = img->NormalImg;
|
||||
dst = newFrame->image->NormalImg;
|
||||
TFB_DrawCanvas_Rescale_Nearest (src, dst, -1, NULL, NULL, NULL);
|
||||
|
||||
UnlockMutex (img->mutex);
|
||||
|
||||
return ReleaseDrawable (newFrame);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
ReadFramePixelColors (FRAME frame, Color *pixels, int width, int height)
|
||||
{
|
||||
TFB_Image *img;
|
||||
|
||||
if (!frame)
|
||||
return FALSE;
|
||||
|
||||
assert (frame->Type != SCREEN_DRAWABLE);
|
||||
|
||||
// TODO: Do we need to lock the img->mutex here?
|
||||
img = frame->image;
|
||||
return TFB_DrawCanvas_GetPixelColors (img->NormalImg, pixels,
|
||||
width, height);
|
||||
}
|
||||
|
||||
// Warning: this functions bypasses DCQ, which is why it is not a DrawXXX
|
||||
BOOLEAN
|
||||
WriteFramePixelColors (FRAME frame, const Color *pixels, int width, int height)
|
||||
{
|
||||
TFB_Image *img;
|
||||
|
||||
if (!frame)
|
||||
return FALSE;
|
||||
|
||||
assert (frame->Type != SCREEN_DRAWABLE);
|
||||
|
||||
// TODO: Do we need to lock the img->mutex here?
|
||||
img = frame->image;
|
||||
return TFB_DrawCanvas_SetPixelColors (img->NormalImg, pixels,
|
||||
width, height);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
ReadFramePixelIndexes (FRAME frame, BYTE *pixels, int width, int height)
|
||||
{
|
||||
TFB_Image *img;
|
||||
|
||||
if (!frame)
|
||||
return FALSE;
|
||||
|
||||
assert (frame->Type != SCREEN_DRAWABLE);
|
||||
|
||||
// TODO: Do we need to lock the img->mutex here?
|
||||
img = frame->image;
|
||||
return TFB_DrawCanvas_GetPixelIndexes (img->NormalImg, pixels,
|
||||
width, height);
|
||||
}
|
||||
|
||||
// Warning: this functions bypasses DCQ, which is why it is not a DrawXXX
|
||||
BOOLEAN
|
||||
WriteFramePixelIndexes (FRAME frame, const BYTE *pixels, int width, int height)
|
||||
{
|
||||
TFB_Image *img;
|
||||
|
||||
if (!frame)
|
||||
return FALSE;
|
||||
|
||||
assert (frame->Type != SCREEN_DRAWABLE);
|
||||
|
||||
// TODO: Do we need to lock the img->mutex here?
|
||||
img = frame->image;
|
||||
return TFB_DrawCanvas_SetPixelIndexes (img->NormalImg, pixels,
|
||||
width, height);
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DRAWABLE_H
|
||||
#define _DRAWABLE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "tfb_draw.h"
|
||||
|
||||
#define ValidPrimType(pt) ((pt)<NUM_PRIMS)
|
||||
|
||||
typedef struct bresenham_line
|
||||
{
|
||||
POINT first, second;
|
||||
SIZE abs_delta_x, abs_delta_y;
|
||||
SIZE error_term;
|
||||
BOOLEAN end_points_exchanged;
|
||||
INTERSECT_CODE intersect_code;
|
||||
} BRESENHAM_LINE;
|
||||
|
||||
typedef UWORD DRAWABLE_TYPE;
|
||||
#define ROM_DRAWABLE 0
|
||||
#define RAM_DRAWABLE 1
|
||||
#define SCREEN_DRAWABLE 2
|
||||
|
||||
struct frame_desc
|
||||
{
|
||||
DRAWABLE_TYPE Type;
|
||||
UWORD Index;
|
||||
HOT_SPOT HotSpot;
|
||||
EXTENT Bounds;
|
||||
TFB_Image *image;
|
||||
struct drawable_desc *parent;
|
||||
};
|
||||
|
||||
struct drawable_desc
|
||||
{
|
||||
CREATE_FLAGS Flags;
|
||||
UWORD MaxIndex;
|
||||
FRAME_DESC *Frame;
|
||||
};
|
||||
|
||||
#define GetFrameWidth(f) ((f)->Bounds.width)
|
||||
#define GetFrameHeight(f) ((f)->Bounds.height)
|
||||
#define GetFrameBounds(f) ((f)->Bounds)
|
||||
#define SetFrameBounds(f,w,h) \
|
||||
((f)->Bounds.width=(w), \
|
||||
((f))->Bounds.height=(h))
|
||||
|
||||
#define DRAWABLE_PRIORITY DEFAULT_MEM_PRIORITY
|
||||
|
||||
extern DRAWABLE AllocDrawable (COUNT num_frames);
|
||||
#define FreeDrawable(D) _ReleaseCelData (D)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
RECT Box;
|
||||
FRAME FramePtr;
|
||||
} IMAGE_BOX;
|
||||
|
||||
extern INTERSECT_CODE _clip_line (const RECT *pClipRect,
|
||||
BRESENHAM_LINE *pLine);
|
||||
|
||||
extern void *_GetCelData (uio_Stream *fp, DWORD length);
|
||||
extern BOOLEAN _ReleaseCelData (void *handle);
|
||||
|
||||
extern FRAME _CurFramePtr;
|
||||
|
||||
// ClipRect is relative to ctxOrigin
|
||||
extern void _text_blt (RECT *pClipRect, TEXT *TextPtr, POINT ctxOrigin);
|
||||
|
||||
#endif /* _DRAWABLE_H */
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef DRAWCMD_H
|
||||
#define DRAWCMD_H
|
||||
|
||||
#include "libs/graphics/tfb_draw.h"
|
||||
|
||||
enum
|
||||
{
|
||||
TFB_DRAWCOMMANDTYPE_LINE,
|
||||
TFB_DRAWCOMMANDTYPE_RECTANGLE,
|
||||
TFB_DRAWCOMMANDTYPE_IMAGE,
|
||||
TFB_DRAWCOMMANDTYPE_FILLEDIMAGE,
|
||||
TFB_DRAWCOMMANDTYPE_FONTCHAR,
|
||||
|
||||
TFB_DRAWCOMMANDTYPE_COPY,
|
||||
TFB_DRAWCOMMANDTYPE_COPYTOIMAGE,
|
||||
|
||||
TFB_DRAWCOMMANDTYPE_SCISSORENABLE,
|
||||
TFB_DRAWCOMMANDTYPE_SCISSORDISABLE,
|
||||
|
||||
TFB_DRAWCOMMANDTYPE_SETMIPMAP,
|
||||
TFB_DRAWCOMMANDTYPE_DELETEIMAGE,
|
||||
TFB_DRAWCOMMANDTYPE_DELETEDATA,
|
||||
TFB_DRAWCOMMANDTYPE_SENDSIGNAL,
|
||||
TFB_DRAWCOMMANDTYPE_REINITVIDEO,
|
||||
TFB_DRAWCOMMANDTYPE_CALLBACK,
|
||||
};
|
||||
|
||||
typedef struct tfb_dc_line
|
||||
{
|
||||
int x1, y1, x2, y2;
|
||||
Color color;
|
||||
DrawMode drawMode;
|
||||
SCREEN destBuffer;
|
||||
} TFB_DrawCommand_Line;
|
||||
|
||||
typedef struct tfb_dc_rect
|
||||
{
|
||||
RECT rect;
|
||||
Color color;
|
||||
DrawMode drawMode;
|
||||
SCREEN destBuffer;
|
||||
} TFB_DrawCommand_Rect;
|
||||
|
||||
typedef struct tfb_dc_img
|
||||
{
|
||||
TFB_Image *image;
|
||||
int x, y;
|
||||
SCREEN destBuffer;
|
||||
TFB_ColorMap *colormap;
|
||||
DrawMode drawMode;
|
||||
int scale;
|
||||
int scaleMode;
|
||||
} TFB_DrawCommand_Image;
|
||||
|
||||
typedef struct tfb_dc_filledimg
|
||||
{
|
||||
TFB_Image *image;
|
||||
int x, y;
|
||||
Color color;
|
||||
SCREEN destBuffer;
|
||||
DrawMode drawMode;
|
||||
int scale;
|
||||
int scaleMode;
|
||||
} TFB_DrawCommand_FilledImage;
|
||||
|
||||
typedef struct tfb_dc_fontchar
|
||||
{
|
||||
TFB_Char *fontchar;
|
||||
TFB_Image *backing;
|
||||
int x, y;
|
||||
DrawMode drawMode;
|
||||
SCREEN destBuffer;
|
||||
} TFB_DrawCommand_FontChar;
|
||||
|
||||
typedef struct tfb_dc_copy
|
||||
{
|
||||
RECT rect;
|
||||
SCREEN srcBuffer, destBuffer;
|
||||
} TFB_DrawCommand_Copy;
|
||||
|
||||
typedef struct tfb_dc_copyimg
|
||||
{
|
||||
TFB_Image *image;
|
||||
RECT rect;
|
||||
SCREEN srcBuffer;
|
||||
} TFB_DrawCommand_CopyToImage;
|
||||
|
||||
typedef struct tfb_dc_scissor
|
||||
{
|
||||
RECT rect;
|
||||
} TFB_DrawCommand_Scissor;
|
||||
|
||||
typedef struct tfb_dc_setmip
|
||||
{
|
||||
TFB_Image *image;
|
||||
TFB_Image *mipmap;
|
||||
int hotx, hoty;
|
||||
} TFB_DrawCommand_SetMipmap;
|
||||
|
||||
typedef struct tfb_dc_delimg
|
||||
{
|
||||
TFB_Image *image;
|
||||
} TFB_DrawCommand_DeleteImage;
|
||||
|
||||
typedef struct tfb_dc_deldata
|
||||
{
|
||||
void *data;
|
||||
// data must be a result of HXalloc() call
|
||||
} TFB_DrawCommand_DeleteData;
|
||||
|
||||
typedef struct tfb_dc_signal
|
||||
{
|
||||
Semaphore sem;
|
||||
} TFB_DrawCommand_SendSignal;
|
||||
|
||||
typedef struct tfb_dc_reinit_video
|
||||
{
|
||||
int driver, flags, width, height;
|
||||
} TFB_DrawCommand_ReinitVideo;
|
||||
|
||||
typedef struct tfb_dc_callback
|
||||
{
|
||||
void (*callback)(void *arg);
|
||||
void *arg;
|
||||
} TFB_DrawCommand_Callback;
|
||||
|
||||
typedef struct tfb_drawcommand
|
||||
{
|
||||
int Type;
|
||||
union {
|
||||
TFB_DrawCommand_Line line;
|
||||
TFB_DrawCommand_Rect rect;
|
||||
TFB_DrawCommand_Image image;
|
||||
TFB_DrawCommand_FilledImage filledimage;
|
||||
TFB_DrawCommand_FontChar fontchar;
|
||||
TFB_DrawCommand_Copy copy;
|
||||
TFB_DrawCommand_CopyToImage copytoimage;
|
||||
TFB_DrawCommand_Scissor scissor;
|
||||
TFB_DrawCommand_SetMipmap setmipmap;
|
||||
TFB_DrawCommand_DeleteImage deleteimage;
|
||||
TFB_DrawCommand_DeleteData deletedata;
|
||||
TFB_DrawCommand_SendSignal sendsignal;
|
||||
TFB_DrawCommand_ReinitVideo reinitvideo;
|
||||
TFB_DrawCommand_Callback callback;
|
||||
} data;
|
||||
} TFB_DrawCommand;
|
||||
|
||||
// Queue Stuff
|
||||
|
||||
typedef struct tfb_drawcommandqueue
|
||||
{
|
||||
int Front;
|
||||
int Back;
|
||||
int InsertionPoint;
|
||||
int Batching;
|
||||
volatile int FullSize;
|
||||
volatile int Size;
|
||||
} TFB_DrawCommandQueue;
|
||||
|
||||
void Init_DrawCommandQueue (void);
|
||||
|
||||
void Uninit_DrawCommandQueue (void);
|
||||
|
||||
void TFB_BatchGraphics (void);
|
||||
|
||||
void TFB_UnbatchGraphics (void);
|
||||
|
||||
void TFB_BatchReset (void);
|
||||
|
||||
void TFB_DrawCommandQueue_Push (TFB_DrawCommand* Command);
|
||||
|
||||
int TFB_DrawCommandQueue_Pop (TFB_DrawCommand* Command);
|
||||
|
||||
void TFB_DrawCommandQueue_Clear (void);
|
||||
|
||||
extern TFB_DrawCommandQueue DrawCommandQueue;
|
||||
|
||||
void TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand);
|
||||
|
||||
void Lock_DCQ (int slots);
|
||||
|
||||
void Unlock_DCQ (void);
|
||||
|
||||
#endif
|
||||
@@ -1,72 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "gfxintrn.h"
|
||||
#include "options.h"
|
||||
#include "libs/reslib.h"
|
||||
|
||||
|
||||
DRAWABLE
|
||||
LoadGraphicFile (const char *pStr)
|
||||
{
|
||||
uio_Stream *fp;
|
||||
|
||||
// FIXME: this theoretically needs a mechanism to prevent races
|
||||
if (_cur_resfile_name)
|
||||
// something else is loading resources atm
|
||||
return 0;
|
||||
|
||||
fp = res_OpenResFile (contentDir, pStr, "rb");
|
||||
if (fp != NULL)
|
||||
{
|
||||
DRAWABLE hData;
|
||||
|
||||
_cur_resfile_name = pStr;
|
||||
hData = (DRAWABLE)_GetCelData (fp, LengthResFile (fp));
|
||||
_cur_resfile_name = 0;
|
||||
res_CloseResFile (fp);
|
||||
return hData;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
FONT
|
||||
LoadFontFile (const char *pStr)
|
||||
{
|
||||
uio_Stream *fp;
|
||||
|
||||
// FIXME: this theoretically needs a mechanism to prevent races
|
||||
if (_cur_resfile_name)
|
||||
// something else is loading resources atm
|
||||
return 0;
|
||||
|
||||
fp = res_OpenResFile (contentDir, pStr, "rb");
|
||||
if (fp != NULL)
|
||||
{
|
||||
FONT hData;
|
||||
|
||||
_cur_resfile_name = pStr;
|
||||
hData = (FONT)_GetFontData (fp, LengthResFile (fp));
|
||||
_cur_resfile_name = 0;
|
||||
res_CloseResFile (fp);
|
||||
return hData;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -1,334 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "gfxintrn.h"
|
||||
#include "tfb_prim.h"
|
||||
#include "libs/log.h"
|
||||
|
||||
static inline TFB_Char *getCharFrame (FONT_DESC *fontPtr, UniChar ch);
|
||||
|
||||
|
||||
FONT
|
||||
SetContextFont (FONT Font)
|
||||
{
|
||||
FONT LastFont;
|
||||
|
||||
LastFont = _CurFontPtr;
|
||||
_CurFontPtr = Font;
|
||||
if (ContextActive ())
|
||||
SwitchContextFont (Font);
|
||||
|
||||
return (LastFont);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
DestroyFont (FONT FontRef)
|
||||
{
|
||||
if (FontRef == NULL)
|
||||
return (FALSE);
|
||||
|
||||
if (_CurFontPtr && _CurFontPtr == FontRef)
|
||||
SetContextFont ((FONT)NULL);
|
||||
|
||||
return (FreeFont (FontRef));
|
||||
}
|
||||
|
||||
// XXX: Should be in frame.c (renamed to something decent?)
|
||||
void
|
||||
font_DrawText (TEXT *lpText)
|
||||
{
|
||||
RECT ClipRect;
|
||||
POINT origin;
|
||||
TEXT text;
|
||||
|
||||
FixContextFontEffect ();
|
||||
if (!GraphicsSystemActive () || !GetContextValidRect (NULL, &origin))
|
||||
return;
|
||||
|
||||
// TextRect() clobbers TEXT.CharCount so we have to make a copy
|
||||
text = *lpText;
|
||||
if (!TextRect (&text, &ClipRect, NULL))
|
||||
return;
|
||||
// ClipRect is relative to origin
|
||||
_text_blt (&ClipRect, &text, origin);
|
||||
}
|
||||
|
||||
/* Draw the stroke by drawing the same text in the
|
||||
* background color one pixel shifted to all 4 directions.
|
||||
*/
|
||||
void
|
||||
font_DrawTracedText (TEXT *pText, Color text, Color trace)
|
||||
{
|
||||
// Preserve current foreground color for full correctness
|
||||
Color oldfg = SetContextForeGroundColor (trace);
|
||||
pText->baseline.x--;
|
||||
font_DrawText (pText);
|
||||
pText->baseline.x += 2;
|
||||
font_DrawText (pText);
|
||||
pText->baseline.x--;
|
||||
pText->baseline.y--;
|
||||
font_DrawText (pText);
|
||||
pText->baseline.y += 2;
|
||||
font_DrawText (pText);
|
||||
pText->baseline.y--;
|
||||
SetContextForeGroundColor (text);
|
||||
font_DrawText (pText);
|
||||
SetContextForeGroundColor (oldfg);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
GetContextFontLeading (SIZE *pheight)
|
||||
{
|
||||
if (_CurFontPtr != 0)
|
||||
{
|
||||
*pheight = (SIZE)_CurFontPtr->Leading;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
*pheight = 0;
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
GetContextFontLeadingWidth (SIZE *pwidth)
|
||||
{
|
||||
if (_CurFontPtr != 0)
|
||||
{
|
||||
*pwidth = (SIZE)_CurFontPtr->LeadingWidth;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
*pwidth = 0;
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
TextRect (TEXT *lpText, RECT *pRect, BYTE *pdelta)
|
||||
{
|
||||
BYTE char_delta_array[MAX_DELTAS];
|
||||
FONT FontPtr;
|
||||
|
||||
FontPtr = _CurFontPtr;
|
||||
if (FontPtr != 0 && lpText->CharCount != 0)
|
||||
{
|
||||
COORD top_y, bot_y;
|
||||
SIZE width;
|
||||
UniChar next_ch = 0;
|
||||
const char *pStr;
|
||||
COUNT num_chars;
|
||||
|
||||
num_chars = lpText->CharCount;
|
||||
/* At this point lpText->CharCount contains the *maximum* number of
|
||||
* characters that lpText->pStr may contain.
|
||||
* After the while loop below, it will contain the actual number.
|
||||
*/
|
||||
if (pdelta == 0)
|
||||
{
|
||||
pdelta = char_delta_array;
|
||||
if (num_chars > MAX_DELTAS)
|
||||
{
|
||||
num_chars = MAX_DELTAS;
|
||||
lpText->CharCount = MAX_DELTAS;
|
||||
}
|
||||
}
|
||||
|
||||
top_y = 0;
|
||||
bot_y = 0;
|
||||
width = 0;
|
||||
pStr = lpText->pStr;
|
||||
if (num_chars > 0)
|
||||
{
|
||||
next_ch = getCharFromString (&pStr);
|
||||
if (next_ch == '\0')
|
||||
num_chars = 0;
|
||||
}
|
||||
while (num_chars--)
|
||||
{
|
||||
UniChar ch;
|
||||
SIZE last_width;
|
||||
TFB_Char *charFrame;
|
||||
|
||||
last_width = width;
|
||||
|
||||
ch = next_ch;
|
||||
if (num_chars > 0)
|
||||
{
|
||||
next_ch = getCharFromString (&pStr);
|
||||
if (next_ch == '\0')
|
||||
{
|
||||
lpText->CharCount -= num_chars;
|
||||
num_chars = 0;
|
||||
}
|
||||
}
|
||||
|
||||
charFrame = getCharFrame (FontPtr, ch);
|
||||
if (charFrame != NULL && charFrame->disp.width)
|
||||
{
|
||||
COORD y;
|
||||
|
||||
y = -charFrame->HotSpot.y;
|
||||
if (y < top_y)
|
||||
top_y = y;
|
||||
y += charFrame->disp.height;
|
||||
if (y > bot_y)
|
||||
bot_y = y;
|
||||
|
||||
width += charFrame->disp.width;
|
||||
#if 0
|
||||
if (num_chars && next_ch < (UNICODE) MAX_CHARS
|
||||
&& !(FontPtr->KernTab[ch]
|
||||
& (FontPtr->KernTab[next_ch] >> 2)))
|
||||
width -= FontPtr->KernAmount;
|
||||
#endif
|
||||
}
|
||||
|
||||
*pdelta++ = (BYTE)(width - last_width);
|
||||
}
|
||||
|
||||
if (width > 0 && (bot_y -= top_y) > 0)
|
||||
{
|
||||
/* subtract off default character spacing */
|
||||
if (pdelta[-1] > 0)
|
||||
{
|
||||
--pdelta[-1];
|
||||
--width;
|
||||
}
|
||||
|
||||
if (lpText->align == ALIGN_LEFT)
|
||||
pRect->corner.x = 0;
|
||||
else if (lpText->align == ALIGN_CENTER)
|
||||
pRect->corner.x = -(width >> 1);
|
||||
else
|
||||
pRect->corner.x = -width;
|
||||
pRect->corner.y = top_y;
|
||||
pRect->extent.width = width;
|
||||
pRect->extent.height = bot_y;
|
||||
|
||||
pRect->corner.x += lpText->baseline.x;
|
||||
pRect->corner.y += lpText->baseline.y;
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
pRect->corner = lpText->baseline;
|
||||
pRect->extent.width = 0;
|
||||
pRect->extent.height = 0;
|
||||
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
_text_blt (RECT *pClipRect, TEXT *TextPtr, POINT ctxOrigin)
|
||||
{
|
||||
FONT FontPtr;
|
||||
COUNT num_chars;
|
||||
UniChar next_ch;
|
||||
const char *pStr;
|
||||
POINT origin;
|
||||
TFB_Image *backing;
|
||||
DrawMode mode = _get_context_draw_mode ();
|
||||
|
||||
FontPtr = _CurFontPtr;
|
||||
if (FontPtr == NULL)
|
||||
return;
|
||||
backing = _get_context_font_backing ();
|
||||
if (!backing)
|
||||
return;
|
||||
|
||||
origin.x = pClipRect->corner.x;
|
||||
origin.y = TextPtr->baseline.y;
|
||||
num_chars = TextPtr->CharCount;
|
||||
if (num_chars == 0)
|
||||
return;
|
||||
|
||||
pStr = TextPtr->pStr;
|
||||
|
||||
next_ch = getCharFromString (&pStr);
|
||||
if (next_ch == '\0')
|
||||
num_chars = 0;
|
||||
while (num_chars--)
|
||||
{
|
||||
UniChar ch;
|
||||
TFB_Char* fontChar;
|
||||
|
||||
ch = next_ch;
|
||||
if (num_chars > 0)
|
||||
{
|
||||
next_ch = getCharFromString (&pStr);
|
||||
if (next_ch == '\0')
|
||||
num_chars = 0;
|
||||
}
|
||||
|
||||
fontChar = getCharFrame (FontPtr, ch);
|
||||
if (fontChar != NULL && fontChar->disp.width)
|
||||
{
|
||||
RECT r;
|
||||
|
||||
r.corner.x = origin.x - fontChar->HotSpot.x;
|
||||
r.corner.y = origin.y - fontChar->HotSpot.y;
|
||||
r.extent.width = fontChar->disp.width;
|
||||
r.extent.height = fontChar->disp.height;
|
||||
if (BoxIntersect (&r, pClipRect, &r))
|
||||
{
|
||||
TFB_Prim_FontChar (origin, fontChar, backing, mode,
|
||||
ctxOrigin);
|
||||
}
|
||||
|
||||
origin.x += fontChar->disp.width;
|
||||
#if 0
|
||||
if (num_chars && next_ch < (UNICODE) MAX_CHARS
|
||||
&& !(FontPtr->KernTab[ch]
|
||||
& (FontPtr->KernTab[next_ch] >> 2)))
|
||||
origin.x -= FontPtr->KernAmount;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline TFB_Char *
|
||||
getCharFrame (FONT_DESC *fontPtr, UniChar ch)
|
||||
{
|
||||
UniChar pageStart = ch & CHARACTER_PAGE_MASK;
|
||||
size_t charIndex;
|
||||
|
||||
FONT_PAGE *page = fontPtr->fontPages;
|
||||
for (;;)
|
||||
{
|
||||
if (page == NULL)
|
||||
return NULL;
|
||||
|
||||
if (page->pageStart == pageStart)
|
||||
break;
|
||||
|
||||
page = page->next;
|
||||
}
|
||||
|
||||
charIndex = ch - page->firstChar;
|
||||
if (ch >= page->firstChar && charIndex < page->numChars
|
||||
&& page->charDesc[charIndex].data)
|
||||
{
|
||||
return &page->charDesc[charIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
//log_add (log_Debug, "Character %u not present", (unsigned int) ch);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _FONT_H
|
||||
#define _FONT_H
|
||||
|
||||
#include "libs/memlib.h"
|
||||
|
||||
#define MAX_DELTAS 100
|
||||
|
||||
typedef struct FontPage
|
||||
{
|
||||
struct FontPage *next;
|
||||
UniChar pageStart;
|
||||
#define CHARACTER_PAGE_MASK 0xfffff800
|
||||
UniChar firstChar;
|
||||
size_t numChars;
|
||||
TFB_Char *charDesc;
|
||||
} FONT_PAGE;
|
||||
|
||||
static inline FONT_PAGE *
|
||||
AllocFontPage (int numChars)
|
||||
{
|
||||
FONT_PAGE *result = HMalloc (sizeof (FONT_PAGE));
|
||||
result->charDesc = HCalloc (numChars * sizeof *result->charDesc);
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
FreeFontPage (FONT_PAGE *page)
|
||||
{
|
||||
HFree (page->charDesc);
|
||||
HFree (page);
|
||||
}
|
||||
|
||||
struct font_desc
|
||||
{
|
||||
UWORD Leading;
|
||||
UWORD LeadingWidth;
|
||||
FONT_PAGE *fontPages;
|
||||
};
|
||||
|
||||
#define CHAR_DESCPTR PCHAR_DESC
|
||||
|
||||
#define FONT_PRIORITY DEFAULT_MEM_PRIORITY
|
||||
|
||||
#define AllocFont(size) (FONT)HCalloc (sizeof (FONT_DESC) + (size))
|
||||
#define FreeFont _ReleaseFontData
|
||||
|
||||
extern FONT _CurFontPtr;
|
||||
|
||||
extern void *_GetFontData (uio_Stream *fp, DWORD length);
|
||||
extern BOOLEAN _ReleaseFontData (void *handle);
|
||||
|
||||
#endif /* _FONT_H */
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "gfxintrn.h"
|
||||
#include "gfx_common.h"
|
||||
#include "tfb_draw.h"
|
||||
#include "tfb_prim.h"
|
||||
|
||||
HOT_SPOT
|
||||
MAKE_HOT_SPOT (COORD x, COORD y)
|
||||
{
|
||||
HOT_SPOT hs;
|
||||
hs.x = x;
|
||||
hs.y = y;
|
||||
return hs;
|
||||
}
|
||||
|
||||
// XXX: INTERNAL_PRIMITIVE and INTERNAL_PRIM_DESC are not used
|
||||
typedef union
|
||||
{
|
||||
POINT Point;
|
||||
STAMP Stamp;
|
||||
BRESENHAM_LINE Line;
|
||||
TEXT Text;
|
||||
RECT Rect;
|
||||
} INTERNAL_PRIM_DESC;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PRIM_LINKS Links;
|
||||
GRAPHICS_PRIM Type;
|
||||
Color Color;
|
||||
INTERNAL_PRIM_DESC Object;
|
||||
} INTERNAL_PRIMITIVE;
|
||||
|
||||
|
||||
// pValidRect or origin may be NULL
|
||||
BOOLEAN
|
||||
GetContextValidRect (RECT *pValidRect, POINT *origin)
|
||||
{
|
||||
RECT tempRect;
|
||||
POINT tempPt;
|
||||
|
||||
if (!pValidRect)
|
||||
pValidRect = &tempRect;
|
||||
if (!origin)
|
||||
origin = &tempPt;
|
||||
|
||||
// Start with a rect the size of foreground frame
|
||||
pValidRect->corner.x = 0;
|
||||
pValidRect->corner.y = 0;
|
||||
pValidRect->extent = GetFrameBounds (_CurFramePtr);
|
||||
*origin = _CurFramePtr->HotSpot;
|
||||
|
||||
if (_pCurContext->ClipRect.extent.width)
|
||||
{
|
||||
// If the cliprect is completely outside of the valid frame
|
||||
// bounds we have nothing to draw
|
||||
if (!BoxIntersect (&_pCurContext->ClipRect,
|
||||
pValidRect, pValidRect))
|
||||
return (FALSE);
|
||||
|
||||
// Foreground frame hotspot defines a drawing position offset
|
||||
// WRT the context cliprect
|
||||
origin->x += _pCurContext->ClipRect.corner.x;
|
||||
origin->y += _pCurContext->ClipRect.corner.y;
|
||||
}
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
ClearBackGround (RECT *pClipRect)
|
||||
{
|
||||
RECT clearRect;
|
||||
Color color = _get_context_bg_color ();
|
||||
clearRect.corner.x = 0;
|
||||
clearRect.corner.y = 0;
|
||||
clearRect.extent = pClipRect->extent;
|
||||
TFB_Prim_FillRect (&clearRect, color, DRAW_REPLACE_MODE,
|
||||
pClipRect->corner);
|
||||
}
|
||||
|
||||
void
|
||||
DrawBatch (PRIMITIVE *lpBasePrim, PRIM_LINKS PrimLinks,
|
||||
BATCH_FLAGS BatchFlags)
|
||||
{
|
||||
RECT ValidRect;
|
||||
POINT origin;
|
||||
|
||||
if (GraphicsSystemActive () && GetContextValidRect (&ValidRect, &origin))
|
||||
{
|
||||
COUNT CurIndex;
|
||||
PRIMITIVE *lpPrim;
|
||||
DrawMode mode = _get_context_draw_mode ();
|
||||
|
||||
BatchGraphics ();
|
||||
|
||||
if (BatchFlags & BATCH_BUILD_PAGE)
|
||||
{
|
||||
ClearBackGround (&ValidRect);
|
||||
}
|
||||
|
||||
CurIndex = GetPredLink (PrimLinks);
|
||||
|
||||
for (; CurIndex != END_OF_LIST;
|
||||
CurIndex = GetSuccLink (GetPrimLinks (lpPrim)))
|
||||
{
|
||||
GRAPHICS_PRIM PrimType;
|
||||
PRIMITIVE *lpWorkPrim;
|
||||
RECT ClipRect;
|
||||
Color color;
|
||||
|
||||
lpPrim = &lpBasePrim[CurIndex];
|
||||
PrimType = GetPrimType (lpPrim);
|
||||
if (!ValidPrimType (PrimType))
|
||||
continue;
|
||||
|
||||
lpWorkPrim = lpPrim;
|
||||
|
||||
switch (PrimType)
|
||||
{
|
||||
case POINT_PRIM:
|
||||
color = GetPrimColor (lpWorkPrim);
|
||||
TFB_Prim_Point (&lpWorkPrim->Object.Point, color,
|
||||
mode, origin);
|
||||
break;
|
||||
case STAMP_PRIM:
|
||||
TFB_Prim_Stamp (&lpWorkPrim->Object.Stamp, mode, origin);
|
||||
break;
|
||||
case STAMPFILL_PRIM:
|
||||
color = GetPrimColor (lpWorkPrim);
|
||||
TFB_Prim_StampFill (&lpWorkPrim->Object.Stamp, color,
|
||||
mode, origin);
|
||||
break;
|
||||
case LINE_PRIM:
|
||||
color = GetPrimColor (lpWorkPrim);
|
||||
TFB_Prim_Line (&lpWorkPrim->Object.Line, color,
|
||||
mode, origin);
|
||||
break;
|
||||
case TEXT_PRIM:
|
||||
if (!TextRect (&lpWorkPrim->Object.Text, &ClipRect, NULL))
|
||||
continue;
|
||||
// ClipRect is relative to origin
|
||||
_text_blt (&ClipRect, &lpWorkPrim->Object.Text, origin);
|
||||
break;
|
||||
case RECT_PRIM:
|
||||
color = GetPrimColor (lpWorkPrim);
|
||||
TFB_Prim_Rect (&lpWorkPrim->Object.Rect, color,
|
||||
mode, origin);
|
||||
break;
|
||||
case RECTFILL_PRIM:
|
||||
color = GetPrimColor (lpWorkPrim);
|
||||
TFB_Prim_FillRect (&lpWorkPrim->Object.Rect, color,
|
||||
mode, origin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UnbatchGraphics ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClearDrawable (void)
|
||||
{
|
||||
RECT ValidRect;
|
||||
|
||||
if (GraphicsSystemActive () && GetContextValidRect (&ValidRect, NULL))
|
||||
{
|
||||
ClearBackGround (&ValidRect);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawPoint (POINT *lpPoint)
|
||||
{
|
||||
POINT origin;
|
||||
|
||||
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
|
||||
{
|
||||
Color color = GetPrimColor (&_locPrim);
|
||||
DrawMode mode = _get_context_draw_mode ();
|
||||
TFB_Prim_Point (lpPoint, color, mode, origin);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawRectangle (RECT *lpRect)
|
||||
{
|
||||
POINT origin;
|
||||
|
||||
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
|
||||
{
|
||||
Color color = GetPrimColor (&_locPrim);
|
||||
DrawMode mode = _get_context_draw_mode ();
|
||||
TFB_Prim_Rect (lpRect, color, mode, origin);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawFilledRectangle (RECT *lpRect)
|
||||
{
|
||||
POINT origin;
|
||||
|
||||
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
|
||||
{
|
||||
Color color = GetPrimColor (&_locPrim);
|
||||
DrawMode mode = _get_context_draw_mode ();
|
||||
TFB_Prim_FillRect (lpRect, color, mode, origin);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawLine (LINE *lpLine)
|
||||
{
|
||||
POINT origin;
|
||||
|
||||
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
|
||||
{
|
||||
Color color = GetPrimColor (&_locPrim);
|
||||
DrawMode mode = _get_context_draw_mode ();
|
||||
TFB_Prim_Line (lpLine, color, mode, origin);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawStamp (STAMP *stmp)
|
||||
{
|
||||
POINT origin;
|
||||
|
||||
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
|
||||
{
|
||||
DrawMode mode = _get_context_draw_mode ();
|
||||
TFB_Prim_Stamp (stmp, mode, origin);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawFilledStamp (STAMP *stmp)
|
||||
{
|
||||
POINT origin;
|
||||
|
||||
if (GraphicsSystemActive () && GetContextValidRect (NULL, &origin))
|
||||
{
|
||||
Color color = GetPrimColor (&_locPrim);
|
||||
DrawMode mode = _get_context_draw_mode ();
|
||||
TFB_Prim_StampFill (stmp, color, mode, origin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "gfxintrn.h"
|
||||
#include "libs/graphics/gfx_common.h"
|
||||
#include "libs/graphics/drawcmd.h"
|
||||
#include "libs/timelib.h"
|
||||
#include "libs/misc.h"
|
||||
// for TFB_DEBUG_HALT
|
||||
|
||||
|
||||
int ScreenWidth;
|
||||
int ScreenHeight;
|
||||
int ScreenWidthActual;
|
||||
int ScreenHeightActual;
|
||||
int ScreenColorDepth;
|
||||
int GraphicsDriver;
|
||||
int TFB_DEBUG_HALT = 0;
|
||||
|
||||
volatile int TransitionAmount = 255;
|
||||
RECT TransitionClipRect;
|
||||
|
||||
static int gscale = GSCALE_IDENTITY;
|
||||
static int gscale_mode = TFB_SCALE_NEAREST;
|
||||
|
||||
void
|
||||
DrawFromExtraScreen (RECT *r)
|
||||
{
|
||||
TFB_DrawScreen_Copy(r, TFB_SCREEN_EXTRA, TFB_SCREEN_MAIN);
|
||||
}
|
||||
|
||||
void
|
||||
LoadIntoExtraScreen (RECT *r)
|
||||
{
|
||||
TFB_DrawScreen_Copy(r, TFB_SCREEN_MAIN, TFB_SCREEN_EXTRA);
|
||||
}
|
||||
|
||||
int
|
||||
SetGraphicScale (int scale)
|
||||
{
|
||||
int old_scale = gscale;
|
||||
gscale = (scale ? scale : GSCALE_IDENTITY);
|
||||
return old_scale;
|
||||
}
|
||||
|
||||
int
|
||||
GetGraphicScale (void)
|
||||
{
|
||||
return gscale;
|
||||
}
|
||||
|
||||
int
|
||||
SetGraphicScaleMode (int mode)
|
||||
{
|
||||
int old_mode = gscale_mode;
|
||||
assert (mode >= TFB_SCALE_NEAREST && mode <= TFB_SCALE_TRILINEAR);
|
||||
gscale_mode = mode;
|
||||
return old_mode;
|
||||
}
|
||||
|
||||
int
|
||||
GetGraphicScaleMode (void)
|
||||
{
|
||||
return gscale_mode;
|
||||
}
|
||||
|
||||
/* Batching and Unbatching functions. A "Batch" is a collection of
|
||||
DrawCommands that will never be flipped to the screen half-rendered.
|
||||
BatchGraphics and UnbatchGraphics function vaguely like a non-blocking
|
||||
recursive lock to do this respect. */
|
||||
void
|
||||
BatchGraphics (void)
|
||||
{
|
||||
TFB_BatchGraphics ();
|
||||
}
|
||||
|
||||
void
|
||||
UnbatchGraphics (void)
|
||||
{
|
||||
TFB_UnbatchGraphics ();
|
||||
}
|
||||
|
||||
/* Sleeps this thread until all Draw Commands queued by that thread have
|
||||
been processed. */
|
||||
|
||||
void
|
||||
FlushGraphics ()
|
||||
{
|
||||
TFB_DrawScreen_WaitForSignal ();
|
||||
}
|
||||
|
||||
static void
|
||||
ExpandRect (RECT *rect, int expansion)
|
||||
{
|
||||
if (rect->corner.x - expansion >= 0)
|
||||
{
|
||||
rect->extent.width += expansion;
|
||||
rect->corner.x -= expansion;
|
||||
}
|
||||
else
|
||||
{
|
||||
rect->extent.width += rect->corner.x;
|
||||
rect->corner.x = 0;
|
||||
}
|
||||
|
||||
if (rect->corner.y - expansion >= 0)
|
||||
{
|
||||
rect->extent.height += expansion;
|
||||
rect->corner.y -= expansion;
|
||||
}
|
||||
else
|
||||
{
|
||||
rect->extent.height += rect->corner.y;
|
||||
rect->corner.y = 0;
|
||||
}
|
||||
|
||||
if (rect->corner.x + rect->extent.width + expansion <= ScreenWidth)
|
||||
rect->extent.width += expansion;
|
||||
else
|
||||
rect->extent.width = ScreenWidth - rect->corner.x;
|
||||
|
||||
if (rect->corner.y + rect->extent.height + expansion <= ScreenHeight)
|
||||
rect->extent.height += expansion;
|
||||
else
|
||||
rect->extent.height = ScreenHeight - rect->corner.y;
|
||||
}
|
||||
|
||||
void
|
||||
SetTransitionSource (const RECT *pRect)
|
||||
{
|
||||
RECT ActualRect;
|
||||
|
||||
if (pRect)
|
||||
{ /* expand the rect to accomodate scalers in OpenGL mode */
|
||||
ActualRect = *pRect;
|
||||
pRect = &ActualRect;
|
||||
ExpandRect (&ActualRect, 2);
|
||||
}
|
||||
TFB_DrawScreen_Copy (pRect, TFB_SCREEN_MAIN, TFB_SCREEN_TRANSITION);
|
||||
}
|
||||
|
||||
// ScreenTransition() is synchronous (does not return until transition done)
|
||||
void
|
||||
ScreenTransition (int TransType, const RECT *pRect)
|
||||
{
|
||||
const TimePeriod DURATION = ONE_SECOND * 31 / 60;
|
||||
TimeCount startTime;
|
||||
(void) TransType; /* dodge compiler warning */
|
||||
|
||||
if (pRect)
|
||||
{
|
||||
TransitionClipRect = *pRect;
|
||||
}
|
||||
else
|
||||
{
|
||||
TransitionClipRect.corner.x = 0;
|
||||
TransitionClipRect.corner.y = 0;
|
||||
TransitionClipRect.extent.width = ScreenWidth;
|
||||
TransitionClipRect.extent.height = ScreenHeight;
|
||||
}
|
||||
|
||||
TFB_UploadTransitionScreen ();
|
||||
|
||||
TransitionAmount = 0;
|
||||
FlushGraphics ();
|
||||
startTime = GetTimeCounter ();
|
||||
while (TransitionAmount < 255)
|
||||
{
|
||||
TimePeriod deltaT;
|
||||
int newAmount;
|
||||
|
||||
SleepThread (ONE_SECOND / 100);
|
||||
|
||||
deltaT = GetTimeCounter () - startTime;
|
||||
newAmount = deltaT * 255 / DURATION;
|
||||
if (newAmount > 255)
|
||||
newAmount = 255;
|
||||
|
||||
TransitionAmount = newAmount;
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef GFX_COMMON_H
|
||||
#define GFX_COMMON_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libs/gfxlib.h"
|
||||
|
||||
// driver for TFB_InitGraphics
|
||||
enum
|
||||
{
|
||||
TFB_GFXDRIVER_SDL_OPENGL,
|
||||
TFB_GFXDRIVER_SDL_PURE,
|
||||
};
|
||||
|
||||
// forced redraw
|
||||
enum
|
||||
{
|
||||
TFB_REDRAW_NO = 0,
|
||||
TFB_REDRAW_FADING,
|
||||
TFB_REDRAW_EXPOSE,
|
||||
TFB_REDRAW_YES
|
||||
};
|
||||
|
||||
// flags for TFB_InitGraphics
|
||||
#define TFB_GFXFLAGS_FULLSCREEN (1<<0)
|
||||
#define TFB_GFXFLAGS_SHOWFPS (1<<1)
|
||||
#define TFB_GFXFLAGS_SCANLINES (1<<2)
|
||||
#define TFB_GFXFLAGS_SCALE_BILINEAR (1<<3)
|
||||
#define TFB_GFXFLAGS_SCALE_BIADAPT (1<<4)
|
||||
#define TFB_GFXFLAGS_SCALE_BIADAPTADV (1<<5)
|
||||
#define TFB_GFXFLAGS_SCALE_TRISCAN (1<<6)
|
||||
#define TFB_GFXFLAGS_SCALE_HQXX (1<<7)
|
||||
#define TFB_GFXFLAGS_SCALE_ANY \
|
||||
( TFB_GFXFLAGS_SCALE_BILINEAR | \
|
||||
TFB_GFXFLAGS_SCALE_BIADAPT | \
|
||||
TFB_GFXFLAGS_SCALE_BIADAPTADV | \
|
||||
TFB_GFXFLAGS_SCALE_TRISCAN | \
|
||||
TFB_GFXFLAGS_SCALE_HQXX )
|
||||
#define TFB_GFXFLAGS_SCALE_SOFT_ONLY \
|
||||
( TFB_GFXFLAGS_SCALE_ANY & ~TFB_GFXFLAGS_SCALE_BILINEAR )
|
||||
|
||||
// The flag variable itself
|
||||
extern int GfxFlags;
|
||||
|
||||
// The following functions are driver-defined
|
||||
void TFB_PreInit (void);
|
||||
int TFB_InitGraphics (int driver, int flags, int width, int height);
|
||||
int TFB_ReInitGraphics (int driver, int flags, int width, int height);
|
||||
void TFB_UninitGraphics (void);
|
||||
void TFB_ProcessEvents (void);
|
||||
void TFB_SetGamma (float gamma);
|
||||
void TFB_UploadTransitionScreen (void);
|
||||
// This function should not be called directly
|
||||
void TFB_SwapBuffers (int force_full_redraw);
|
||||
|
||||
#define GSCALE_IDENTITY 256
|
||||
|
||||
typedef enum {
|
||||
TFB_SCALE_STEP, /* not really a scaler */
|
||||
TFB_SCALE_NEAREST,
|
||||
TFB_SCALE_BILINEAR,
|
||||
TFB_SCALE_TRILINEAR
|
||||
} SCALE;
|
||||
|
||||
void LoadIntoExtraScreen (RECT *r);
|
||||
void DrawFromExtraScreen (RECT *r);
|
||||
int SetGraphicScale (int scale);
|
||||
int GetGraphicScale (void);
|
||||
int SetGraphicScaleMode (int mode /* enum SCALE */);
|
||||
int GetGraphicScaleMode (void);
|
||||
void SetTransitionSource (const RECT *pRect);
|
||||
void ScreenTransition (int transition, const RECT *pRect);
|
||||
|
||||
// TODO: there should be accessor functions for these
|
||||
extern volatile int TransitionAmount;
|
||||
extern RECT TransitionClipRect;
|
||||
|
||||
extern float FrameRate;
|
||||
extern int FrameRateTickBase;
|
||||
|
||||
void TFB_FlushGraphics (void); // Only call from main thread!!
|
||||
|
||||
extern int ScreenWidth;
|
||||
extern int ScreenHeight;
|
||||
extern int ScreenWidthActual;
|
||||
extern int ScreenHeightActual;
|
||||
extern int ScreenColorDepth;
|
||||
extern int GraphicsDriver;
|
||||
|
||||
#endif
|
||||
@@ -1,32 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _GFXINTRN_H
|
||||
#define _GFXINTRN_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libs/gfxlib.h"
|
||||
#include "libs/reslib.h"
|
||||
#include "context.h"
|
||||
#include "drawable.h"
|
||||
#include "font.h"
|
||||
|
||||
#endif /* _GFXINTRN_H */
|
||||
|
||||
@@ -1,605 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
#include "libs/reslib.h"
|
||||
// for _cur_resfile_name
|
||||
#include "libs/log.h"
|
||||
#include "libs/memlib.h"
|
||||
#include "libs/graphics/tfb_draw.h"
|
||||
#include "libs/graphics/drawable.h"
|
||||
#include "libs/graphics/font.h"
|
||||
|
||||
|
||||
typedef struct anidata
|
||||
{
|
||||
int transparent_color;
|
||||
int colormap_index;
|
||||
int hotspot_x;
|
||||
int hotspot_y;
|
||||
} AniData;
|
||||
|
||||
extern uio_Repository *repository;
|
||||
static uio_AutoMount *autoMount[] = { NULL };
|
||||
|
||||
static void
|
||||
process_image (FRAME FramePtr, TFB_Canvas img[], AniData *ani, int cel_ct)
|
||||
{
|
||||
TFB_Image *tfbimg;
|
||||
int hx, hy;
|
||||
|
||||
FramePtr->Type = ROM_DRAWABLE;
|
||||
FramePtr->Index = cel_ct;
|
||||
|
||||
// handle transparency cases
|
||||
if (TFB_DrawCanvas_IsPaletted (img[cel_ct]))
|
||||
{ // indexed color image
|
||||
if (ani[cel_ct].transparent_color >= 0)
|
||||
{
|
||||
TFB_DrawCanvas_SetTransparentIndex (img[cel_ct],
|
||||
ani[cel_ct].transparent_color, FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // special transparency cases for truecolor images
|
||||
if (ani[cel_ct].transparent_color == 0)
|
||||
{ // make RGB=0,0,0 transparent
|
||||
Color color = {0, 0, 0, 0};
|
||||
TFB_DrawCanvas_SetTransparentColor (img[cel_ct], color, FALSE);
|
||||
}
|
||||
}
|
||||
if (ani[cel_ct].transparent_color == -1)
|
||||
{ // enforce -1 to mean 'no transparency'
|
||||
TFB_DrawCanvas_SetTransparentIndex (img[cel_ct], -1, FALSE);
|
||||
// set transparent_color == -2 to use PNG tRNS transparency
|
||||
}
|
||||
|
||||
hx = ani[cel_ct].hotspot_x;
|
||||
hy = ani[cel_ct].hotspot_y;
|
||||
|
||||
FramePtr->image = TFB_DrawImage_New (img[cel_ct]);
|
||||
|
||||
tfbimg = FramePtr->image;
|
||||
tfbimg->colormap_index = ani[cel_ct].colormap_index;
|
||||
img[cel_ct] = tfbimg->NormalImg;
|
||||
|
||||
FramePtr->HotSpot = MAKE_HOT_SPOT (hx, hy);
|
||||
SetFrameBounds (FramePtr, tfbimg->extent.width, tfbimg->extent.height);
|
||||
|
||||
#ifdef CLIPDEBUG
|
||||
{
|
||||
/* for debugging clipping:
|
||||
draws white (or most matching color from palette) pixels to
|
||||
every corner of the image
|
||||
*/
|
||||
Color color = {0xff, 0xff, 0xff, 0xff};
|
||||
RECT r = {{0, 0}, {1, 1}};
|
||||
if (tfbimg->extent.width > 2 && tfbimg->extent.height > 2)
|
||||
{
|
||||
TFB_DrawImage_Rect (&r, color, tfbimg);
|
||||
r.corner.x = tfbimg->extent.width - 1;
|
||||
TFB_DrawImage_Rect (&r, color, tfbimg);
|
||||
r.corner.y = tfbimg->extent.height - 1;
|
||||
TFB_DrawImage_Rect (&r, color, tfbimg);
|
||||
r.corner.x = 0;
|
||||
TFB_DrawImage_Rect (&r, color, tfbimg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
processFontChar (TFB_Char* CharPtr, TFB_Canvas canvas)
|
||||
{
|
||||
BYTE* newdata;
|
||||
size_t dpitch;
|
||||
|
||||
TFB_DrawCanvas_GetExtent (canvas, &CharPtr->extent);
|
||||
|
||||
// Currently, each font char has its own separate data
|
||||
// but that can change to common mem area
|
||||
dpitch = CharPtr->extent.width;
|
||||
newdata = HMalloc (dpitch * CharPtr->extent.height * sizeof (BYTE));
|
||||
TFB_DrawCanvas_GetFontCharData (canvas, newdata, dpitch);
|
||||
|
||||
CharPtr->data = newdata;
|
||||
CharPtr->pitch = dpitch;
|
||||
CharPtr->disp.width = CharPtr->extent.width + 1;
|
||||
CharPtr->disp.height = CharPtr->extent.height + 1;
|
||||
// XXX: why the +1?
|
||||
// I brought it into this function from the only calling
|
||||
// function, but I don't know why it was there in the first
|
||||
// place.
|
||||
// XXX: the +1 appears to be for character and line spacing
|
||||
// text_blt just adds the frame width to move to the next char
|
||||
|
||||
{
|
||||
// This tunes the font positioning to be about what it should
|
||||
// TODO: prolly needs a little tweaking still
|
||||
|
||||
int tune_amount = 0;
|
||||
|
||||
if (CharPtr->extent.height == 8)
|
||||
tune_amount = -1;
|
||||
else if (CharPtr->extent.height == 9)
|
||||
tune_amount = -2;
|
||||
else if (CharPtr->extent.height > 9)
|
||||
tune_amount = -3;
|
||||
|
||||
CharPtr->HotSpot = MAKE_HOT_SPOT (0,
|
||||
CharPtr->extent.height + tune_amount);
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
_GetCelData (uio_Stream *fp, DWORD length)
|
||||
{
|
||||
int cel_total, cel_index, n;
|
||||
DWORD opos;
|
||||
char CurrentLine[1024], filename[PATH_MAX];
|
||||
TFB_Canvas *img;
|
||||
AniData *ani;
|
||||
DRAWABLE Drawable;
|
||||
uio_MountHandle *aniMount = 0;
|
||||
uio_DirHandle *aniDir = 0;
|
||||
uio_Stream *aniFile = 0;
|
||||
|
||||
opos = uio_ftell (fp);
|
||||
|
||||
{
|
||||
char *s1, *s2;
|
||||
char aniDirName[PATH_MAX];
|
||||
const char *aniFileName;
|
||||
uint8 buf[4] = { 0, 0, 0, 0 };
|
||||
uint32 header;
|
||||
|
||||
if (_cur_resfile_name == 0
|
||||
|| (((s2 = 0), (s1 = strrchr (_cur_resfile_name, '/')) == 0)
|
||||
&& (s2 = strrchr (_cur_resfile_name, '\\')) == 0))
|
||||
{
|
||||
n = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s2 > s1)
|
||||
s1 = s2;
|
||||
n = s1 - _cur_resfile_name + 1;
|
||||
}
|
||||
|
||||
uio_fread(buf, 4, 1, fp);
|
||||
header = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
if (_cur_resfile_name && header == 0x04034b50)
|
||||
{
|
||||
// zipped ani file
|
||||
if (n)
|
||||
{
|
||||
strncpy (aniDirName, _cur_resfile_name, n - 1);
|
||||
aniDirName[n - 1] = 0;
|
||||
aniFileName = _cur_resfile_name + n;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(aniDirName, ".");
|
||||
aniFileName = _cur_resfile_name;
|
||||
}
|
||||
aniDir = uio_openDir (repository, aniDirName, 0);
|
||||
aniMount = uio_mountDir (repository, aniDirName, uio_FSTYPE_ZIP,
|
||||
aniDir, aniFileName, "/", autoMount,
|
||||
uio_MOUNT_RDONLY | uio_MOUNT_TOP,
|
||||
NULL);
|
||||
aniFile = uio_fopen (aniDir, aniFileName, "r");
|
||||
opos = 0;
|
||||
n = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unpacked ani file
|
||||
strncpy (filename, _cur_resfile_name, n);
|
||||
aniFile = fp;
|
||||
aniDir = contentDir;
|
||||
}
|
||||
}
|
||||
|
||||
cel_total = 0;
|
||||
uio_fseek (aniFile, opos, SEEK_SET);
|
||||
while (uio_fgets (CurrentLine, sizeof (CurrentLine), aniFile))
|
||||
{
|
||||
++cel_total;
|
||||
}
|
||||
|
||||
img = HMalloc (sizeof (TFB_Canvas) * cel_total);
|
||||
ani = HMalloc (sizeof (AniData) * cel_total);
|
||||
if (!img || !ani)
|
||||
{
|
||||
log_add (log_Warning, "Couldn't allocate space for '%s'", _cur_resfile_name);
|
||||
if (aniMount)
|
||||
{
|
||||
uio_fclose(aniFile);
|
||||
uio_closeDir(aniDir);
|
||||
uio_unmountDir(aniMount);
|
||||
}
|
||||
HFree (img);
|
||||
HFree (ani);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cel_index = 0;
|
||||
uio_fseek (aniFile, opos, SEEK_SET);
|
||||
while (uio_fgets (CurrentLine, sizeof (CurrentLine), aniFile) && cel_index < cel_total)
|
||||
{
|
||||
sscanf (CurrentLine, "%s %d %d %d %d", &filename[n],
|
||||
&ani[cel_index].transparent_color, &ani[cel_index].colormap_index,
|
||||
&ani[cel_index].hotspot_x, &ani[cel_index].hotspot_y);
|
||||
|
||||
img[cel_index] = TFB_DrawCanvas_LoadFromFile (aniDir, filename);
|
||||
if (img[cel_index] == NULL)
|
||||
{
|
||||
const char *err;
|
||||
|
||||
err = TFB_DrawCanvas_GetError ();
|
||||
log_add (log_Warning, "_GetCelData: Unable to load image!");
|
||||
if (err != NULL)
|
||||
log_add (log_Warning, "Gfx Driver reports: %s", err);
|
||||
}
|
||||
else
|
||||
{
|
||||
++cel_index;
|
||||
}
|
||||
|
||||
if ((int)uio_ftell (aniFile) - (int)opos >= (int)length)
|
||||
break;
|
||||
}
|
||||
|
||||
Drawable = NULL;
|
||||
if (cel_index && (Drawable = AllocDrawable (cel_index)))
|
||||
{
|
||||
if (!Drawable)
|
||||
{
|
||||
while (cel_index--)
|
||||
TFB_DrawCanvas_Delete (img[cel_index]);
|
||||
|
||||
HFree (Drawable);
|
||||
Drawable = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
FRAME FramePtr;
|
||||
|
||||
Drawable->Flags = WANT_PIXMAP;
|
||||
Drawable->MaxIndex = cel_index - 1;
|
||||
|
||||
FramePtr = &Drawable->Frame[cel_index];
|
||||
while (--FramePtr, cel_index--)
|
||||
process_image (FramePtr, img, ani, cel_index);
|
||||
}
|
||||
}
|
||||
|
||||
if (Drawable == NULL)
|
||||
log_add (log_Warning, "Couldn't get cel data for '%s'",
|
||||
_cur_resfile_name);
|
||||
|
||||
if (aniMount)
|
||||
{
|
||||
uio_fclose(aniFile);
|
||||
uio_closeDir(aniDir);
|
||||
uio_unmountDir(aniMount);
|
||||
}
|
||||
|
||||
HFree (img);
|
||||
HFree (ani);
|
||||
return Drawable;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
_ReleaseCelData (void *handle)
|
||||
{
|
||||
DRAWABLE DrawablePtr;
|
||||
int cel_ct;
|
||||
FRAME FramePtr = NULL;
|
||||
|
||||
if ((DrawablePtr = handle) == 0)
|
||||
return (FALSE);
|
||||
|
||||
cel_ct = DrawablePtr->MaxIndex + 1;
|
||||
|
||||
if (DrawablePtr->Frame)
|
||||
{
|
||||
FramePtr = DrawablePtr->Frame;
|
||||
if (FramePtr->Type == SCREEN_DRAWABLE)
|
||||
{
|
||||
FramePtr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HFree (handle);
|
||||
if (FramePtr)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cel_ct; i++)
|
||||
{
|
||||
TFB_Image *img = FramePtr[i].image;
|
||||
if (img)
|
||||
{
|
||||
FramePtr[i].image = NULL;
|
||||
TFB_DrawScreen_DeleteImage (img);
|
||||
}
|
||||
}
|
||||
HFree (FramePtr);
|
||||
}
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
typedef struct BuildCharDesc
|
||||
{
|
||||
TFB_Canvas canvas;
|
||||
UniChar index;
|
||||
} BuildCharDesc;
|
||||
|
||||
static int
|
||||
compareBCDIndex (const void *arg1, const void *arg2)
|
||||
{
|
||||
const BuildCharDesc *bcd1 = (const BuildCharDesc *) arg1;
|
||||
const BuildCharDesc *bcd2 = (const BuildCharDesc *) arg2;
|
||||
|
||||
return (int) bcd1->index - (int) bcd2->index;
|
||||
}
|
||||
|
||||
void *
|
||||
_GetFontData (uio_Stream *fp, DWORD length)
|
||||
{
|
||||
COUNT numDirEntries;
|
||||
DIRENTRY fontDir = NULL;
|
||||
BuildCharDesc *bcds = NULL;
|
||||
size_t numBCDs = 0;
|
||||
int dirEntryI;
|
||||
uio_DirHandle *fontDirHandle = NULL;
|
||||
uio_MountHandle *fontMount = NULL;
|
||||
FONT fontPtr = NULL;
|
||||
|
||||
if (_cur_resfile_name == 0)
|
||||
goto err;
|
||||
|
||||
if (fp != (uio_Stream*)~0)
|
||||
{
|
||||
// font is zipped instead of being in a directory
|
||||
|
||||
char *s1, *s2;
|
||||
int n;
|
||||
const char *fontZipName;
|
||||
char fontDirName[PATH_MAX];
|
||||
|
||||
if ((((s2 = 0), (s1 = strrchr (_cur_resfile_name, '/')) == 0)
|
||||
&& (s2 = strrchr (_cur_resfile_name, '\\')) == 0))
|
||||
{
|
||||
strcpy(fontDirName, ".");
|
||||
fontZipName = _cur_resfile_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s2 > s1)
|
||||
s1 = s2;
|
||||
n = s1 - _cur_resfile_name + 1;
|
||||
strncpy (fontDirName, _cur_resfile_name, n - 1);
|
||||
fontDirName[n - 1] = 0;
|
||||
fontZipName = _cur_resfile_name + n;
|
||||
}
|
||||
|
||||
fontDirHandle = uio_openDir (repository, fontDirName, 0);
|
||||
fontMount = uio_mountDir (repository, _cur_resfile_name, uio_FSTYPE_ZIP,
|
||||
fontDirHandle, fontZipName, "/", autoMount,
|
||||
uio_MOUNT_RDONLY | uio_MOUNT_TOP,
|
||||
NULL);
|
||||
uio_closeDir (fontDirHandle);
|
||||
}
|
||||
|
||||
fontDir = CaptureDirEntryTable (LoadDirEntryTable (contentDir,
|
||||
_cur_resfile_name, ".", match_MATCH_SUBSTRING));
|
||||
if (fontDir == 0)
|
||||
goto err;
|
||||
numDirEntries = GetDirEntryTableCount (fontDir);
|
||||
|
||||
fontDirHandle = uio_openDirRelative (contentDir, _cur_resfile_name, 0);
|
||||
if (fontDirHandle == NULL)
|
||||
goto err;
|
||||
|
||||
bcds = HMalloc (numDirEntries * sizeof (BuildCharDesc));
|
||||
if (bcds == NULL)
|
||||
goto err;
|
||||
|
||||
// Load the surfaces for all dir Entries
|
||||
for (dirEntryI = 0; dirEntryI < numDirEntries; dirEntryI++)
|
||||
{
|
||||
char *char_name;
|
||||
unsigned int charIndex;
|
||||
TFB_Canvas canvas;
|
||||
EXTENT size;
|
||||
|
||||
char_name = GetDirEntryAddress (SetAbsDirEntryTableIndex (
|
||||
fontDir, dirEntryI));
|
||||
if (sscanf (char_name, "%x.", &charIndex) != 1)
|
||||
continue;
|
||||
|
||||
if (charIndex > 0xffff)
|
||||
continue;
|
||||
|
||||
canvas = TFB_DrawCanvas_LoadFromFile (fontDirHandle, char_name);
|
||||
if (canvas == NULL)
|
||||
continue;
|
||||
|
||||
TFB_DrawCanvas_GetExtent (canvas, &size);
|
||||
if (size.width == 0 || size.height == 0)
|
||||
{
|
||||
TFB_DrawCanvas_Delete (canvas);
|
||||
continue;
|
||||
}
|
||||
|
||||
bcds[numBCDs].canvas = canvas;
|
||||
bcds[numBCDs].index = charIndex;
|
||||
numBCDs++;
|
||||
}
|
||||
uio_closeDir (fontDirHandle);
|
||||
DestroyDirEntryTable (ReleaseDirEntryTable (fontDir));
|
||||
if (fontMount != 0)
|
||||
uio_unmountDir(fontMount);
|
||||
|
||||
#if 0
|
||||
if (numBCDs == 0)
|
||||
goto err;
|
||||
#endif
|
||||
|
||||
// sort on the character index
|
||||
qsort (bcds, numBCDs, sizeof (BuildCharDesc), compareBCDIndex);
|
||||
|
||||
fontPtr = AllocFont (0);
|
||||
if (fontPtr == NULL)
|
||||
goto err;
|
||||
|
||||
fontPtr->Leading = 0;
|
||||
fontPtr->LeadingWidth = 0;
|
||||
|
||||
{
|
||||
size_t startBCD = 0;
|
||||
UniChar pageStart;
|
||||
FONT_PAGE **pageEndPtr = &fontPtr->fontPages;
|
||||
while (startBCD < numBCDs)
|
||||
{
|
||||
// Process one character page.
|
||||
size_t endBCD;
|
||||
pageStart = bcds[startBCD].index & CHARACTER_PAGE_MASK;
|
||||
|
||||
endBCD = startBCD;
|
||||
while (endBCD < numBCDs &&
|
||||
(bcds[endBCD].index & CHARACTER_PAGE_MASK) == pageStart)
|
||||
endBCD++;
|
||||
|
||||
{
|
||||
size_t bcdI;
|
||||
int numChars = bcds[endBCD - 1].index + 1
|
||||
- bcds[startBCD].index;
|
||||
FONT_PAGE *page = AllocFontPage (numChars);
|
||||
page->pageStart = pageStart;
|
||||
page->firstChar = bcds[startBCD].index;
|
||||
page->numChars = numChars;
|
||||
*pageEndPtr = page;
|
||||
pageEndPtr = &page->next;
|
||||
|
||||
for (bcdI = startBCD; bcdI < endBCD; bcdI++)
|
||||
{
|
||||
// Process one character.
|
||||
BuildCharDesc *bcd = &bcds[bcdI];
|
||||
TFB_Char *destChar =
|
||||
&page->charDesc[bcd->index - page->firstChar];
|
||||
|
||||
if (destChar->data != NULL)
|
||||
{
|
||||
// There's already an image for this character.
|
||||
log_add (log_Debug, "Duplicate image for character %d "
|
||||
"for font %s.", (int) bcd->index,
|
||||
_cur_resfile_name);
|
||||
TFB_DrawCanvas_Delete (bcd->canvas);
|
||||
continue;
|
||||
}
|
||||
|
||||
processFontChar (destChar, bcd->canvas);
|
||||
TFB_DrawCanvas_Delete (bcd->canvas);
|
||||
|
||||
if (destChar->disp.height > fontPtr->Leading)
|
||||
fontPtr->Leading = destChar->disp.height;
|
||||
if (destChar->disp.width > fontPtr->LeadingWidth)
|
||||
fontPtr->LeadingWidth = destChar->disp.width;
|
||||
}
|
||||
}
|
||||
|
||||
startBCD = endBCD;
|
||||
}
|
||||
*pageEndPtr = NULL;
|
||||
}
|
||||
|
||||
fontPtr->Leading++;
|
||||
|
||||
HFree (bcds);
|
||||
|
||||
(void) fp; /* Satisfying compiler (unused parameter) */
|
||||
(void) length; /* Satisfying compiler (unused parameter) */
|
||||
return fontPtr;
|
||||
|
||||
err:
|
||||
if (fontPtr != 0)
|
||||
HFree (fontPtr);
|
||||
|
||||
if (bcds != NULL)
|
||||
{
|
||||
size_t bcdI;
|
||||
for (bcdI = 0; bcdI < numBCDs; bcdI++)
|
||||
TFB_DrawCanvas_Delete (bcds[bcdI].canvas);
|
||||
HFree (bcds);
|
||||
}
|
||||
|
||||
if (fontDirHandle != NULL)
|
||||
uio_closeDir (fontDirHandle);
|
||||
|
||||
if (fontDir != 0)
|
||||
DestroyDirEntryTable (ReleaseDirEntryTable (fontDir));
|
||||
|
||||
if (fontMount != 0)
|
||||
uio_unmountDir(fontMount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
_ReleaseFontData (void *handle)
|
||||
{
|
||||
FONT font = (FONT) handle;
|
||||
if (font == NULL)
|
||||
return FALSE;
|
||||
|
||||
{
|
||||
FONT_PAGE *page;
|
||||
FONT_PAGE *nextPage;
|
||||
|
||||
for (page = font->fontPages; page != NULL; page = nextPage)
|
||||
{
|
||||
size_t charI;
|
||||
for (charI = 0; charI < page->numChars; charI++)
|
||||
{
|
||||
TFB_Char *c = &page->charDesc[charI];
|
||||
|
||||
if (c->data == NULL)
|
||||
continue;
|
||||
|
||||
// XXX: fix this if fonts get per-page data
|
||||
// rather than per-char
|
||||
TFB_DrawScreen_DeleteData (c->data);
|
||||
}
|
||||
|
||||
nextPage = page->next;
|
||||
FreeFontPage (page);
|
||||
}
|
||||
}
|
||||
|
||||
HFree (font);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1,415 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "libs/graphics/context.h"
|
||||
#include "libs/graphics/drawable.h"
|
||||
#include "libs/graphics/tfb_draw.h"
|
||||
#include "libs/log.h"
|
||||
|
||||
//#define DEBUG_INTERSEC
|
||||
|
||||
static inline BOOLEAN
|
||||
images_intersect (IMAGE_BOX *box1, IMAGE_BOX *box2, const RECT *rect)
|
||||
{
|
||||
return TFB_DrawImage_Intersect (box1->FramePtr->image, box1->Box.corner,
|
||||
box2->FramePtr->image, box2->Box.corner, rect);
|
||||
}
|
||||
|
||||
static TIME_VALUE
|
||||
frame_intersect (INTERSECT_CONTROL *pControl0, RECT *pr0,
|
||||
INTERSECT_CONTROL *pControl1, RECT *pr1, TIME_VALUE t0,
|
||||
TIME_VALUE t1)
|
||||
{
|
||||
SIZE time_error0, time_error1;
|
||||
SIZE cycle0, cycle1;
|
||||
SIZE dx_0, dy_0, dx_1, dy_1;
|
||||
SIZE xincr0, yincr0, xincr1, yincr1;
|
||||
SIZE xerror0, xerror1, yerror0, yerror1;
|
||||
RECT r_intersect;
|
||||
IMAGE_BOX IB0, IB1;
|
||||
BOOLEAN check0, check1;
|
||||
|
||||
IB0.FramePtr = pControl0->IntersectStamp.frame;
|
||||
IB0.Box.corner = pr0->corner;
|
||||
IB0.Box.extent.width = GetFrameWidth (IB0.FramePtr);
|
||||
IB0.Box.extent.height = GetFrameHeight (IB0.FramePtr);
|
||||
IB1.FramePtr = pControl1->IntersectStamp.frame;
|
||||
IB1.Box.corner = pr1->corner;
|
||||
IB1.Box.extent.width = GetFrameWidth (IB1.FramePtr);
|
||||
IB1.Box.extent.height = GetFrameHeight (IB1.FramePtr);
|
||||
|
||||
dx_0 = pr0->extent.width;
|
||||
dy_0 = pr0->extent.height;
|
||||
if (dx_0 >= 0)
|
||||
xincr0 = 1;
|
||||
else
|
||||
{
|
||||
xincr0 = -1;
|
||||
dx_0 = -dx_0;
|
||||
}
|
||||
if (dy_0 >= 0)
|
||||
yincr0 = 1;
|
||||
else
|
||||
{
|
||||
yincr0 = -1;
|
||||
dy_0 = -dy_0;
|
||||
}
|
||||
if (dx_0 >= dy_0)
|
||||
cycle0 = dx_0;
|
||||
else
|
||||
cycle0 = dy_0;
|
||||
xerror0 = yerror0 = cycle0;
|
||||
|
||||
dx_1 = pr1->extent.width;
|
||||
dy_1 = pr1->extent.height;
|
||||
if (dx_1 >= 0)
|
||||
xincr1 = 1;
|
||||
else
|
||||
{
|
||||
xincr1 = -1;
|
||||
dx_1 = -dx_1;
|
||||
}
|
||||
if (dy_1 >= 0)
|
||||
yincr1 = 1;
|
||||
else
|
||||
{
|
||||
yincr1 = -1;
|
||||
dy_1 = -dy_1;
|
||||
}
|
||||
if (dx_1 >= dy_1)
|
||||
cycle1 = dx_1;
|
||||
else
|
||||
cycle1 = dy_1;
|
||||
xerror1 = yerror1 = cycle1;
|
||||
|
||||
check0 = check1 = FALSE;
|
||||
if (t0 <= 1)
|
||||
{
|
||||
time_error0 = time_error1 = 0;
|
||||
if (t0 == 0)
|
||||
{
|
||||
++t0;
|
||||
goto CheckFirstIntersection;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SIZE delta;
|
||||
COUNT start;
|
||||
long error;
|
||||
|
||||
start = (COUNT)cycle0 * (COUNT)(t0 - 1);
|
||||
time_error0 = start & ((1 << TIME_SHIFT) - 1);
|
||||
if ((start >>= (COUNT)TIME_SHIFT) > 0)
|
||||
{
|
||||
if ((error = (long)xerror0
|
||||
- (long)dx_0 * (long)start) > 0)
|
||||
xerror0 = (SIZE)error;
|
||||
else
|
||||
{
|
||||
delta = -(SIZE)(error / (long)cycle0) + 1;
|
||||
IB0.Box.corner.x += xincr0 * delta;
|
||||
xerror0 = (SIZE)(error + (long)cycle0 * (long)delta);
|
||||
}
|
||||
if ((error = (long)yerror0
|
||||
- (long)dy_0 * (long)start) > 0)
|
||||
yerror0 = (SIZE)error;
|
||||
else
|
||||
{
|
||||
delta = -(SIZE)(error / (long)cycle0) + 1;
|
||||
IB0.Box.corner.y += yincr0 * delta;
|
||||
yerror0 = (SIZE)(error + (long)cycle0 * (long)delta);
|
||||
}
|
||||
pr0->corner = IB0.Box.corner;
|
||||
}
|
||||
|
||||
start = (COUNT)cycle1 * (COUNT)(t0 - 1);
|
||||
time_error1 = start & ((1 << TIME_SHIFT) - 1);
|
||||
if ((start >>= (COUNT)TIME_SHIFT) > 0)
|
||||
{
|
||||
if ((error = (long)xerror1
|
||||
- (long)dx_1 * (long)start) > 0)
|
||||
xerror1 = (SIZE)error;
|
||||
else
|
||||
{
|
||||
delta = -(SIZE)(error / (long)cycle1) + 1;
|
||||
IB1.Box.corner.x += xincr1 * delta;
|
||||
xerror1 = (SIZE)(error + (long)cycle1 * (long)delta);
|
||||
}
|
||||
if ((error = (long)yerror1
|
||||
- (long)dy_1 * (long)start) > 0)
|
||||
yerror1 = (SIZE)error;
|
||||
else
|
||||
{
|
||||
delta = -(SIZE)(error / (long)cycle1) + 1;
|
||||
IB1.Box.corner.y += yincr1 * delta;
|
||||
yerror1 = (SIZE)(error + (long)cycle1 * (long)delta);
|
||||
}
|
||||
pr1->corner = IB1.Box.corner;
|
||||
}
|
||||
}
|
||||
|
||||
pControl0->last_time_val = pControl1->last_time_val = t0;
|
||||
do
|
||||
{
|
||||
++t0;
|
||||
if ((time_error0 += cycle0) >= (1 << TIME_SHIFT))
|
||||
{
|
||||
if ((xerror0 -= dx_0) <= 0)
|
||||
{
|
||||
IB0.Box.corner.x += xincr0;
|
||||
xerror0 += cycle0;
|
||||
}
|
||||
if ((yerror0 -= dy_0) <= 0)
|
||||
{
|
||||
IB0.Box.corner.y += yincr0;
|
||||
yerror0 += cycle0;
|
||||
}
|
||||
|
||||
check0 = TRUE;
|
||||
time_error0 -= (1 << TIME_SHIFT);
|
||||
}
|
||||
|
||||
if ((time_error1 += cycle1) >= (1 << TIME_SHIFT))
|
||||
{
|
||||
if ((xerror1 -= dx_1) <= 0)
|
||||
{
|
||||
IB1.Box.corner.x += xincr1;
|
||||
xerror1 += cycle1;
|
||||
}
|
||||
if ((yerror1 -= dy_1) <= 0)
|
||||
{
|
||||
IB1.Box.corner.y += yincr1;
|
||||
yerror1 += cycle1;
|
||||
}
|
||||
|
||||
check1 = TRUE;
|
||||
time_error1 -= (1 << TIME_SHIFT);
|
||||
}
|
||||
|
||||
if (check0 || check1)
|
||||
{ /* if check0 && check1, this may not be quite right --
|
||||
* if shapes had a pixel's separation to begin with
|
||||
* and both moved toward each other, you would actually
|
||||
* get a pixel overlap but since the last positions were
|
||||
* separated by a pixel, the shapes wouldn't be touching
|
||||
* each other.
|
||||
*/
|
||||
CheckFirstIntersection:
|
||||
if (BoxIntersect (&IB0.Box, &IB1.Box, &r_intersect)
|
||||
&& images_intersect (&IB0, &IB1, &r_intersect))
|
||||
return (t0);
|
||||
|
||||
if (check0)
|
||||
{
|
||||
pr0->corner = IB0.Box.corner;
|
||||
pControl0->last_time_val = t0;
|
||||
check0 = FALSE;
|
||||
}
|
||||
if (check1)
|
||||
{
|
||||
pr1->corner = IB1.Box.corner;
|
||||
pControl1->last_time_val = t0;
|
||||
check1 = FALSE;
|
||||
}
|
||||
}
|
||||
} while (t0 <= t1);
|
||||
|
||||
return ((TIME_VALUE)0);
|
||||
}
|
||||
|
||||
TIME_VALUE
|
||||
DrawablesIntersect (INTERSECT_CONTROL *pControl0,
|
||||
INTERSECT_CONTROL *pControl1, TIME_VALUE max_time_val)
|
||||
{
|
||||
SIZE dy;
|
||||
SIZE time_y_0, time_y_1;
|
||||
RECT r0, r1;
|
||||
FRAME FramePtr0, FramePtr1;
|
||||
|
||||
if (!ContextActive () || max_time_val == 0)
|
||||
return ((TIME_VALUE)0);
|
||||
else if (max_time_val > MAX_TIME_VALUE)
|
||||
max_time_val = MAX_TIME_VALUE;
|
||||
|
||||
pControl0->last_time_val = pControl1->last_time_val = 0;
|
||||
|
||||
r0.corner = pControl0->IntersectStamp.origin;
|
||||
r1.corner = pControl1->IntersectStamp.origin;
|
||||
|
||||
r0.extent.width = pControl0->EndPoint.x - r0.corner.x;
|
||||
r0.extent.height = pControl0->EndPoint.y - r0.corner.y;
|
||||
r1.extent.width = pControl1->EndPoint.x - r1.corner.x;
|
||||
r1.extent.height = pControl1->EndPoint.y - r1.corner.y;
|
||||
|
||||
FramePtr0 = pControl0->IntersectStamp.frame;
|
||||
if (FramePtr0 == 0)
|
||||
return(0);
|
||||
r0.corner.x -= FramePtr0->HotSpot.x;
|
||||
r0.corner.y -= FramePtr0->HotSpot.y;
|
||||
|
||||
FramePtr1 = pControl1->IntersectStamp.frame;
|
||||
if (FramePtr1 == 0)
|
||||
return(0);
|
||||
r1.corner.x -= FramePtr1->HotSpot.x;
|
||||
r1.corner.y -= FramePtr1->HotSpot.y;
|
||||
|
||||
dy = r1.corner.y - r0.corner.y;
|
||||
time_y_0 = dy - GetFrameHeight (FramePtr0) + 1;
|
||||
time_y_1 = dy + GetFrameHeight (FramePtr1) - 1;
|
||||
dy = r0.extent.height - r1.extent.height;
|
||||
|
||||
if ((time_y_0 <= 0 && time_y_1 >= 0)
|
||||
|| (time_y_0 > 0 && dy >= time_y_0)
|
||||
|| (time_y_1 < 0 && dy <= time_y_1))
|
||||
{
|
||||
SIZE dx;
|
||||
SIZE time_x_0, time_x_1;
|
||||
|
||||
dx = r1.corner.x - r0.corner.x;
|
||||
time_x_0 = dx - GetFrameWidth (FramePtr0) + 1;
|
||||
time_x_1 = dx + GetFrameWidth (FramePtr1) - 1;
|
||||
dx = r0.extent.width - r1.extent.width;
|
||||
|
||||
if ((time_x_0 <= 0 && time_x_1 >= 0)
|
||||
|| (time_x_0 > 0 && dx >= time_x_0)
|
||||
|| (time_x_1 < 0 && dx <= time_x_1))
|
||||
{
|
||||
TIME_VALUE intersect_time;
|
||||
|
||||
if (dx == 0 && dy == 0)
|
||||
time_y_0 = time_y_1 = 0;
|
||||
else
|
||||
{
|
||||
SIZE t;
|
||||
long time_beg, time_end, fract;
|
||||
|
||||
if (time_y_1 < 0)
|
||||
{
|
||||
t = time_y_0;
|
||||
time_y_0 = -time_y_1;
|
||||
time_y_1 = -t;
|
||||
}
|
||||
else if (time_y_0 <= 0)
|
||||
{
|
||||
if (dy < 0)
|
||||
time_y_1 = -time_y_0;
|
||||
time_y_0 = 0;
|
||||
}
|
||||
if (dy < 0)
|
||||
dy = -dy;
|
||||
if (dy < time_y_1)
|
||||
time_y_1 = dy;
|
||||
/* just to be safe, widen search area */
|
||||
--time_y_0;
|
||||
++time_y_1;
|
||||
|
||||
if (time_x_1 < 0)
|
||||
{
|
||||
t = time_x_0;
|
||||
time_x_0 = -time_x_1;
|
||||
time_x_1 = -t;
|
||||
}
|
||||
else if (time_x_0 <= 0)
|
||||
{
|
||||
if (dx < 0)
|
||||
time_x_1 = -time_x_0;
|
||||
time_x_0 = 0;
|
||||
}
|
||||
if (dx < 0)
|
||||
dx = -dx;
|
||||
if (dx < time_x_1)
|
||||
time_x_1 = dx;
|
||||
/* just to be safe, widen search area */
|
||||
--time_x_0;
|
||||
++time_x_1;
|
||||
|
||||
#ifdef DEBUG_INTERSEC
|
||||
log_add (log_Debug, "FramePtr0<%d, %d> --> <%d, %d>",
|
||||
GetFrameWidth (FramePtr0), GetFrameHeight (FramePtr0),
|
||||
r0.corner.x, r0.corner.y);
|
||||
log_add (log_Debug, "FramePtr1<%d, %d> --> <%d, %d>",
|
||||
GetFrameWidth (FramePtr1), GetFrameHeight (FramePtr1),
|
||||
r1.corner.x, r1.corner.y);
|
||||
log_add (log_Debug, "time_x(%d, %d)-%d, time_y(%d, %d)-%d",
|
||||
time_x_0, time_x_1, dx, time_y_0, time_y_1, dy);
|
||||
#endif /* DEBUG_INTERSEC */
|
||||
if (dx == 0)
|
||||
{
|
||||
time_beg = time_y_0;
|
||||
time_end = time_y_1;
|
||||
fract = dy;
|
||||
}
|
||||
else if (dy == 0)
|
||||
{
|
||||
time_beg = time_x_0;
|
||||
time_end = time_x_1;
|
||||
fract = dx;
|
||||
}
|
||||
else
|
||||
{
|
||||
long time_x, time_y;
|
||||
|
||||
time_x = (long)time_x_0 * (long)dy;
|
||||
time_y = (long)time_y_0 * (long)dx;
|
||||
time_beg = time_x < time_y ? time_y : time_x;
|
||||
|
||||
time_x = (long)time_x_1 * (long)dy;
|
||||
time_y = (long)time_y_1 * (long)dx;
|
||||
time_end = time_x > time_y ? time_y : time_x;
|
||||
|
||||
fract = (long)dx * (long)dy;
|
||||
}
|
||||
|
||||
if ((time_beg <<= TIME_SHIFT) < fract)
|
||||
time_y_0 = 0;
|
||||
else
|
||||
time_y_0 = (SIZE)(time_beg / fract);
|
||||
|
||||
if (time_end >= fract /* just in case of overflow */
|
||||
|| (time_end <<= TIME_SHIFT) >=
|
||||
fract * (long)max_time_val)
|
||||
time_y_1 = max_time_val - 1;
|
||||
else
|
||||
time_y_1 = (SIZE)((time_end + fract - 1) / fract) - 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_INTERSEC
|
||||
log_add (log_Debug, "start_time = %d, end_time = %d",
|
||||
time_y_0, time_y_1);
|
||||
#endif /* DEBUG_INTERSEC */
|
||||
if (time_y_0 <= time_y_1
|
||||
&& (intersect_time = frame_intersect (
|
||||
pControl0, &r0, pControl1, &r1,
|
||||
(TIME_VALUE)time_y_0, (TIME_VALUE)time_y_1)))
|
||||
{
|
||||
FramePtr0 = pControl0->IntersectStamp.frame;
|
||||
pControl0->EndPoint.x = r0.corner.x + FramePtr0->HotSpot.x;
|
||||
pControl0->EndPoint.y = r0.corner.y + FramePtr0->HotSpot.y;
|
||||
FramePtr1 = pControl1->IntersectStamp.frame;
|
||||
pControl1->EndPoint.x = r1.corner.x + FramePtr1->HotSpot.x;
|
||||
pControl1->EndPoint.y = r1.corner.y + FramePtr1->HotSpot.y;
|
||||
|
||||
return (intersect_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ((TIME_VALUE)0);
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "libs/gfxlib.h"
|
||||
#include "libs/graphics/drawable.h"
|
||||
#include "libs/log.h"
|
||||
|
||||
|
||||
// Reads a piece of screen into a passed FRAME or a newly created one
|
||||
DRAWABLE
|
||||
LoadDisplayPixmap (const RECT *area, FRAME frame)
|
||||
{
|
||||
// TODO: This should just return a FRAME instead of DRAWABLE
|
||||
DRAWABLE buffer = GetFrameParentDrawable (frame);
|
||||
COUNT index;
|
||||
|
||||
if (!buffer)
|
||||
{ // asked to create a new DRAWABLE instead
|
||||
buffer = CreateDrawable (WANT_PIXMAP | MAPPED_TO_DISPLAY,
|
||||
area->extent.width, area->extent.height, 1);
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = GetFrameIndex (frame);
|
||||
}
|
||||
|
||||
frame = SetAbsFrameIndex (CaptureDrawable (buffer), index);
|
||||
|
||||
if (_CurFramePtr->Type != SCREEN_DRAWABLE
|
||||
|| frame->Type == SCREEN_DRAWABLE
|
||||
|| !(GetFrameParentDrawable (frame)->Flags & MAPPED_TO_DISPLAY))
|
||||
{
|
||||
log_add (log_Warning, "Unimplemented function activated: "
|
||||
"LoadDisplayPixmap()");
|
||||
}
|
||||
else
|
||||
{
|
||||
TFB_Image *img = frame->image;
|
||||
TFB_DrawScreen_CopyToImage (img, area, TFB_SCREEN_MAIN);
|
||||
}
|
||||
|
||||
ReleaseDrawable (frame);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "gfxintrn.h"
|
||||
#include "libs/log.h"
|
||||
|
||||
DRAWABLE
|
||||
GetFrameParentDrawable (FRAME f)
|
||||
{
|
||||
if (f != NULL)
|
||||
{
|
||||
return f->parent;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FRAME
|
||||
CaptureDrawable (DRAWABLE DrawablePtr)
|
||||
{
|
||||
if (DrawablePtr)
|
||||
{
|
||||
return &DrawablePtr->Frame[0];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DRAWABLE
|
||||
ReleaseDrawable (FRAME FramePtr)
|
||||
{
|
||||
if (FramePtr != 0)
|
||||
{
|
||||
DRAWABLE Drawable;
|
||||
|
||||
Drawable = GetFrameParentDrawable (FramePtr);
|
||||
|
||||
return (Drawable);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
COUNT
|
||||
GetFrameCount (FRAME FramePtr)
|
||||
{
|
||||
DRAWABLE_DESC *DrawablePtr;
|
||||
|
||||
if (FramePtr == 0)
|
||||
return (0);
|
||||
|
||||
DrawablePtr = GetFrameParentDrawable (FramePtr);
|
||||
return DrawablePtr->MaxIndex + 1;
|
||||
}
|
||||
|
||||
COUNT
|
||||
GetFrameIndex (FRAME FramePtr)
|
||||
{
|
||||
if (FramePtr == 0)
|
||||
return (0);
|
||||
|
||||
return FramePtr->Index;
|
||||
}
|
||||
|
||||
FRAME
|
||||
SetAbsFrameIndex (FRAME FramePtr, COUNT FrameIndex)
|
||||
{
|
||||
if (FramePtr != 0)
|
||||
{
|
||||
DRAWABLE_DESC *DrawablePtr;
|
||||
|
||||
DrawablePtr = GetFrameParentDrawable (FramePtr);
|
||||
|
||||
FrameIndex = FrameIndex % (DrawablePtr->MaxIndex + 1);
|
||||
FramePtr = &DrawablePtr->Frame[FrameIndex];
|
||||
}
|
||||
|
||||
return FramePtr;
|
||||
}
|
||||
|
||||
FRAME
|
||||
SetRelFrameIndex (FRAME FramePtr, SIZE FrameOffs)
|
||||
{
|
||||
if (FramePtr != 0)
|
||||
{
|
||||
COUNT num_frames;
|
||||
DRAWABLE_DESC *DrawablePtr;
|
||||
|
||||
DrawablePtr = GetFrameParentDrawable (FramePtr);
|
||||
num_frames = DrawablePtr->MaxIndex + 1;
|
||||
if (FrameOffs < 0)
|
||||
{
|
||||
while ((FrameOffs += num_frames) < 0)
|
||||
;
|
||||
}
|
||||
|
||||
FrameOffs = ((SWORD)FramePtr->Index + FrameOffs) % num_frames;
|
||||
FramePtr = &DrawablePtr->Frame[FrameOffs];
|
||||
}
|
||||
|
||||
return FramePtr;
|
||||
}
|
||||
|
||||
FRAME
|
||||
SetEquFrameIndex (FRAME DstFramePtr, FRAME SrcFramePtr)
|
||||
{
|
||||
COUNT Index;
|
||||
|
||||
if (!DstFramePtr || !SrcFramePtr)
|
||||
return 0;
|
||||
|
||||
Index = GetFrameIndex (SrcFramePtr);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
DRAWABLE_DESC *DrawablePtr = GetFrameParentDrawable (DstFramePtr);
|
||||
if (Index > DrawablePtr->MaxIndex)
|
||||
log_add (log_Debug, "SetEquFrameIndex: source index (%d) beyond "
|
||||
"destination range (%d)", (int)Index,
|
||||
(int)DrawablePtr->MaxIndex);
|
||||
}
|
||||
#endif
|
||||
|
||||
return SetAbsFrameIndex (DstFramePtr, Index);
|
||||
}
|
||||
|
||||
FRAME
|
||||
IncFrameIndex (FRAME FramePtr)
|
||||
{
|
||||
DRAWABLE_DESC *DrawablePtr;
|
||||
|
||||
if (FramePtr == 0)
|
||||
return (0);
|
||||
|
||||
DrawablePtr = GetFrameParentDrawable (FramePtr);
|
||||
if (FramePtr->Index < DrawablePtr->MaxIndex)
|
||||
return ++FramePtr;
|
||||
else
|
||||
return DrawablePtr->Frame;
|
||||
}
|
||||
|
||||
FRAME
|
||||
DecFrameIndex (FRAME FramePtr)
|
||||
{
|
||||
if (FramePtr == 0)
|
||||
return (0);
|
||||
|
||||
if (FramePtr->Index > 0)
|
||||
return --FramePtr;
|
||||
else
|
||||
{
|
||||
DRAWABLE_DESC *DrawablePtr;
|
||||
|
||||
DrawablePtr = GetFrameParentDrawable (FramePtr);
|
||||
return &DrawablePtr->Frame[DrawablePtr->MaxIndex];
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef _PRIM_H
|
||||
#define _PRIM_H
|
||||
|
||||
enum gfx_object
|
||||
{
|
||||
POINT_PRIM = 0,
|
||||
STAMP_PRIM,
|
||||
STAMPFILL_PRIM,
|
||||
LINE_PRIM,
|
||||
TEXT_PRIM,
|
||||
RECT_PRIM,
|
||||
RECTFILL_PRIM,
|
||||
|
||||
NUM_PRIMS
|
||||
};
|
||||
typedef BYTE GRAPHICS_PRIM;
|
||||
|
||||
typedef union
|
||||
{
|
||||
POINT Point;
|
||||
STAMP Stamp;
|
||||
LINE Line;
|
||||
TEXT Text;
|
||||
RECT Rect;
|
||||
} PRIM_DESC;
|
||||
|
||||
typedef DWORD PRIM_LINKS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PRIM_LINKS Links;
|
||||
GRAPHICS_PRIM Type;
|
||||
Color color;
|
||||
PRIM_DESC Object;
|
||||
} PRIMITIVE;
|
||||
|
||||
#define END_OF_LIST ((COUNT)0xFFFF)
|
||||
|
||||
#define GetPredLink(l) LOWORD(l)
|
||||
#define GetSuccLink(l) HIWORD(l)
|
||||
#define MakeLinks MAKE_DWORD
|
||||
#define SetPrimLinks(pPrim,p,s) ((pPrim)->Links = MakeLinks (p, s))
|
||||
#define GetPrimLinks(pPrim) ((pPrim)->Links)
|
||||
#define SetPrimType(pPrim,t) ((pPrim)->Type = t)
|
||||
#define GetPrimType(pPrim) ((pPrim)->Type)
|
||||
#define SetPrimColor(pPrim,c) ((pPrim)->color = c)
|
||||
#define GetPrimColor(pPrim) ((pPrim)->color)
|
||||
|
||||
static inline void
|
||||
SetPrimNextLink (PRIMITIVE *pPrim, COUNT Link)
|
||||
{
|
||||
SetPrimLinks (pPrim, END_OF_LIST, Link);
|
||||
}
|
||||
|
||||
|
||||
static inline COUNT
|
||||
GetPrimNextLink (PRIMITIVE *pPrim)
|
||||
{
|
||||
return GetSuccLink (GetPrimLinks (pPrim));
|
||||
}
|
||||
|
||||
|
||||
#endif /* PRIM_H */
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "gfxintrn.h"
|
||||
|
||||
static void
|
||||
GetCelFileData (const char *pathname, RESOURCE_DATA *resdata)
|
||||
{
|
||||
resdata->ptr = LoadResourceFromPath (pathname, _GetCelData);
|
||||
}
|
||||
|
||||
static void
|
||||
GetFontFileData (const char *pathname, RESOURCE_DATA *resdata)
|
||||
{
|
||||
resdata->ptr = LoadResourceFromPath (pathname, _GetFontData);
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
InstallGraphicResTypes (void)
|
||||
{
|
||||
InstallResTypeVectors ("GFXRES", GetCelFileData, _ReleaseCelData, NULL);
|
||||
InstallResTypeVectors ("FONTRES", GetFontFileData, _ReleaseFontData, NULL);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/* Needs to be void * because it could be either a DRAWABLE or a FONT. */
|
||||
void *
|
||||
LoadGraphicInstance (RESOURCE res)
|
||||
{
|
||||
void *hData;
|
||||
|
||||
hData = res_GetResource (res);
|
||||
if (hData)
|
||||
res_DetachResource (res);
|
||||
|
||||
return (hData);
|
||||
}
|
||||
|
||||
@@ -1,260 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
#include "types.h"
|
||||
#include "scalers.h"
|
||||
#include "scaleint.h"
|
||||
#include "2xscalers.h"
|
||||
|
||||
|
||||
// Scaler function lookup table
|
||||
//
|
||||
const Scale_FuncDef_t
|
||||
Scale_C_Functions[] =
|
||||
{
|
||||
{TFB_GFXFLAGS_SCALE_BILINEAR, Scale_BilinearFilter},
|
||||
{TFB_GFXFLAGS_SCALE_BIADAPT, Scale_BiAdaptFilter},
|
||||
{TFB_GFXFLAGS_SCALE_BIADAPTADV, Scale_BiAdaptAdvFilter},
|
||||
{TFB_GFXFLAGS_SCALE_TRISCAN, Scale_TriScanFilter},
|
||||
{TFB_GFXFLAGS_SCALE_HQXX, Scale_HqFilter},
|
||||
// Default
|
||||
{0, Scale_Nearest}
|
||||
};
|
||||
|
||||
// See
|
||||
// nearest2x.c -- Nearest Neighboor scaling
|
||||
// bilinear2x.c -- Bilinear scaling
|
||||
// biadv2x.c -- Advanced Biadapt scaling
|
||||
// triscan2x.c -- Triscan scaling
|
||||
|
||||
// Biadapt scaling to 2x
|
||||
void
|
||||
SCALE_(BiAdaptFilter) (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
||||
{
|
||||
int x, y;
|
||||
const int w = src->w, h = src->h;
|
||||
int xend, yend;
|
||||
int dsrc, ddst;
|
||||
SDL_Rect *region = r;
|
||||
SDL_Rect limits;
|
||||
SDL_PixelFormat *fmt = dst->format;
|
||||
const int sp = src->pitch, dp = dst->pitch;
|
||||
const int bpp = fmt->BytesPerPixel;
|
||||
const int slen = sp / bpp, dlen = dp / bpp;
|
||||
Uint32 *src_p = (Uint32 *)src->pixels;
|
||||
Uint32 *dst_p = (Uint32 *)dst->pixels;
|
||||
Uint32 pixval_tl, pixval_tr, pixval_bl, pixval_br;
|
||||
|
||||
// these macros are for clarity; they make the current pixel (0,0)
|
||||
// and allow to access pixels in all directions
|
||||
#define SRC(x, y) (src_p + (x) + ((y) * slen))
|
||||
|
||||
SCALE_(PlatInit) ();
|
||||
|
||||
// expand updated region if necessary
|
||||
// pixels neighbooring the updated region may
|
||||
// change as a result of updates
|
||||
limits.x = 0;
|
||||
limits.y = 0;
|
||||
limits.w = src->w;
|
||||
limits.h = src->h;
|
||||
Scale_ExpandRect (region, 2, &limits);
|
||||
|
||||
xend = region->x + region->w;
|
||||
yend = region->y + region->h;
|
||||
dsrc = slen - region->w;
|
||||
ddst = (dlen - region->w) * 2;
|
||||
|
||||
// move ptrs to the first updated pixel
|
||||
src_p += slen * region->y + region->x;
|
||||
dst_p += (dlen * region->y + region->x) * 2;
|
||||
|
||||
for (y = region->y; y < yend; ++y, dst_p += ddst, src_p += dsrc)
|
||||
{
|
||||
for (x = region->x; x < xend; ++x, ++src_p, ++dst_p)
|
||||
{
|
||||
pixval_tl = SCALE_GETPIX (SRC (0, 0));
|
||||
|
||||
SCALE_SETPIX (dst_p, pixval_tl);
|
||||
|
||||
if (y + 1 < h)
|
||||
{
|
||||
// check pixel below the current one
|
||||
pixval_bl = SCALE_GETPIX (SRC (0, 1));
|
||||
|
||||
if (pixval_tl == pixval_bl)
|
||||
SCALE_SETPIX (dst_p + dlen, pixval_tl);
|
||||
else
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
|
||||
pixval_tl, pixval_bl)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// last pixel in column - propagate
|
||||
SCALE_SETPIX (dst_p + dlen, pixval_tl);
|
||||
pixval_bl = pixval_tl;
|
||||
}
|
||||
++dst_p;
|
||||
|
||||
if (x + 1 >= w)
|
||||
{
|
||||
// last pixel in row - propagate
|
||||
SCALE_SETPIX (dst_p, pixval_tl);
|
||||
|
||||
if (pixval_tl == pixval_bl)
|
||||
SCALE_SETPIX (dst_p + dlen, pixval_tl);
|
||||
else
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
|
||||
pixval_tl, pixval_bl)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check pixel to the right from the current one
|
||||
pixval_tr = SCALE_GETPIX (SRC (1, 0));
|
||||
|
||||
if (pixval_tl == pixval_tr)
|
||||
SCALE_SETPIX (dst_p, pixval_tr);
|
||||
else
|
||||
SCALE_SETPIX (dst_p, Scale_Blend_11 (
|
||||
pixval_tl, pixval_tr)
|
||||
);
|
||||
|
||||
if (y + 1 >= h)
|
||||
{
|
||||
// last pixel in column - propagate
|
||||
SCALE_SETPIX (dst_p + dlen, pixval_tl);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check pixel to the bottom-right
|
||||
pixval_br = SCALE_GETPIX (SRC (1, 1));
|
||||
|
||||
if (pixval_tl == pixval_br && pixval_tr == pixval_bl)
|
||||
{
|
||||
int cl, cr;
|
||||
Uint32 clr;
|
||||
|
||||
if (pixval_tl == pixval_tr)
|
||||
{
|
||||
// all 4 are equal - propagate
|
||||
SCALE_SETPIX (dst_p + dlen, pixval_tl);
|
||||
continue;
|
||||
}
|
||||
|
||||
// both pairs are equal, have to resolve the pixel
|
||||
// race; we try detecting which color is
|
||||
// the background by looking for a line or an edge
|
||||
// examine 8 pixels surrounding the current quad
|
||||
|
||||
cl = cr = 1;
|
||||
|
||||
if (x > 0)
|
||||
{
|
||||
clr = SCALE_GETPIX (SRC (-1, 0));
|
||||
if (clr == pixval_tl)
|
||||
cl++;
|
||||
else if (clr == pixval_tr)
|
||||
cr++;
|
||||
|
||||
clr = SCALE_GETPIX (SRC (-1, 1));
|
||||
if (clr == pixval_tl)
|
||||
cl++;
|
||||
else if (clr == pixval_tr)
|
||||
cr++;
|
||||
}
|
||||
|
||||
if (y > 0)
|
||||
{
|
||||
clr = SCALE_GETPIX (SRC (0, -1));
|
||||
if (clr == pixval_tl)
|
||||
cl++;
|
||||
else if (clr == pixval_tr)
|
||||
cr++;
|
||||
|
||||
clr = SCALE_GETPIX (SRC (1, -1));
|
||||
if (clr == pixval_tl)
|
||||
cl++;
|
||||
else if (clr == pixval_tr)
|
||||
cr++;
|
||||
}
|
||||
|
||||
if (x + 2 < w)
|
||||
{
|
||||
clr = SCALE_GETPIX (SRC (2, 0));
|
||||
if (clr == pixval_tl)
|
||||
cl++;
|
||||
else if (clr == pixval_tr)
|
||||
cr++;
|
||||
|
||||
clr = SCALE_GETPIX (SRC (2, 1));
|
||||
if (clr == pixval_tl)
|
||||
cl++;
|
||||
else if (clr == pixval_tr)
|
||||
cr++;
|
||||
}
|
||||
|
||||
if (y + 2 < h)
|
||||
{
|
||||
clr = SCALE_GETPIX (SRC (0, 2));
|
||||
if (clr == pixval_tl)
|
||||
cl++;
|
||||
else if (clr == pixval_tr)
|
||||
cr++;
|
||||
|
||||
clr = SCALE_GETPIX (SRC (1, 2));
|
||||
if (clr == pixval_tl)
|
||||
cl++;
|
||||
else if (clr == pixval_tr)
|
||||
cr++;
|
||||
}
|
||||
|
||||
// least count wins
|
||||
if (cl > cr)
|
||||
SCALE_SETPIX (dst_p + dlen, pixval_tr);
|
||||
else if (cr > cl)
|
||||
SCALE_SETPIX (dst_p + dlen, pixval_tl);
|
||||
else
|
||||
SCALE_SETPIX (dst_p + dlen,
|
||||
Scale_Blend_11 (pixval_tl, pixval_tr));
|
||||
}
|
||||
else if (pixval_tl == pixval_br)
|
||||
{
|
||||
// main diagonal is same color
|
||||
// use its value
|
||||
SCALE_SETPIX (dst_p + dlen, pixval_tl);
|
||||
}
|
||||
else if (pixval_tr == pixval_bl)
|
||||
{
|
||||
// 2nd diagonal is same color
|
||||
// use its value
|
||||
SCALE_SETPIX (dst_p + dlen, pixval_tr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// blend all 4
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_1111 (
|
||||
pixval_tl, pixval_bl, pixval_tr, pixval_br
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCALE_(PlatDone) ();
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _2XSCALERS_H_
|
||||
#define _2XSCALERS_H_
|
||||
|
||||
void Scale_Nearest (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_BiAdaptFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_BiAdaptAdvFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_TriScanFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_HqFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
|
||||
extern const Scale_FuncDef_t Scale_C_Functions[];
|
||||
|
||||
|
||||
#endif /* _2XSCALERS_H_ */
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/platform.h"
|
||||
|
||||
#if defined(MMX_ASM)
|
||||
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
#include "types.h"
|
||||
#include "scalers.h"
|
||||
#include "scaleint.h"
|
||||
#include "2xscalers.h"
|
||||
#include "2xscalers_mmx.h"
|
||||
|
||||
// 3DNow! name for all functions
|
||||
#undef SCALE_
|
||||
#define SCALE_(name) Scale ## _3DNow_ ## name
|
||||
|
||||
// Tell them which opcodes we want to support
|
||||
#undef USE_MOVNTQ
|
||||
#define USE_PREFETCH AMD_PREFETCH
|
||||
#undef USE_PSADBW
|
||||
// Bring in inline asm functions
|
||||
#include "scalemmx.h"
|
||||
|
||||
|
||||
// Scaler function lookup table
|
||||
//
|
||||
const Scale_FuncDef_t
|
||||
Scale_3DNow_Functions[] =
|
||||
{
|
||||
{TFB_GFXFLAGS_SCALE_BILINEAR, Scale_3DNow_BilinearFilter},
|
||||
{TFB_GFXFLAGS_SCALE_BIADAPT, Scale_BiAdaptFilter},
|
||||
{TFB_GFXFLAGS_SCALE_BIADAPTADV, Scale_MMX_BiAdaptAdvFilter},
|
||||
{TFB_GFXFLAGS_SCALE_TRISCAN, Scale_MMX_TriScanFilter},
|
||||
{TFB_GFXFLAGS_SCALE_HQXX, Scale_MMX_HqFilter},
|
||||
// Default
|
||||
{0, Scale_3DNow_Nearest}
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
Scale_3DNow_PrepPlatform (const SDL_PixelFormat* fmt)
|
||||
{
|
||||
Scale_MMX_PrepPlatform (fmt);
|
||||
}
|
||||
|
||||
// Nearest Neighbor scaling to 2x
|
||||
// void Scale_3DNow_Nearest (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "nearest2x.c"
|
||||
|
||||
|
||||
// Bilinear scaling to 2x
|
||||
// void Scale_3DNow_BilinearFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "bilinear2x.c"
|
||||
|
||||
|
||||
#if 0 && NO_IMPROVEMENT
|
||||
|
||||
// Advanced Biadapt scaling to 2x
|
||||
// void Scale_3DNow_BiAdaptAdvFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "biadv2x.c"
|
||||
|
||||
|
||||
// Triscan scaling to 2x
|
||||
// derivative of scale2x -- scale2x.sf.net
|
||||
// void Scale_3DNow_TriScanFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "triscan2x.c"
|
||||
|
||||
// Hq2x scaling
|
||||
// (adapted from 'hq2x' by Maxim Stepin -- www.hiend3d.com/hq2x.html)
|
||||
// void Scale_3DNow_HqFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "hq2x.c"
|
||||
|
||||
#endif /* NO_IMPROVEMENT */
|
||||
|
||||
#endif /* MMX_ASM */
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/platform.h"
|
||||
|
||||
#if defined(MMX_ASM)
|
||||
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
#include "types.h"
|
||||
#include "scalers.h"
|
||||
#include "scaleint.h"
|
||||
#include "2xscalers.h"
|
||||
#include "2xscalers_mmx.h"
|
||||
|
||||
// MMX name for all functions
|
||||
#undef SCALE_
|
||||
#define SCALE_(name) Scale ## _MMX_ ## name
|
||||
|
||||
// Tell them which opcodes we want to support
|
||||
#undef USE_MOVNTQ
|
||||
#undef USE_PREFETCH
|
||||
#undef USE_PSADBW
|
||||
// And Bring in inline asm functions
|
||||
#include "scalemmx.h"
|
||||
|
||||
|
||||
// Scaler function lookup table
|
||||
//
|
||||
const Scale_FuncDef_t
|
||||
Scale_MMX_Functions[] =
|
||||
{
|
||||
{TFB_GFXFLAGS_SCALE_BILINEAR, Scale_MMX_BilinearFilter},
|
||||
{TFB_GFXFLAGS_SCALE_BIADAPT, Scale_BiAdaptFilter},
|
||||
{TFB_GFXFLAGS_SCALE_BIADAPTADV, Scale_MMX_BiAdaptAdvFilter},
|
||||
{TFB_GFXFLAGS_SCALE_TRISCAN, Scale_MMX_TriScanFilter},
|
||||
{TFB_GFXFLAGS_SCALE_HQXX, Scale_MMX_HqFilter},
|
||||
// Default
|
||||
{0, Scale_MMX_Nearest}
|
||||
};
|
||||
|
||||
// MMX transformation multipliers
|
||||
Uint64 mmx_888to555_mult;
|
||||
Uint64 mmx_Y_mult;
|
||||
Uint64 mmx_U_mult;
|
||||
Uint64 mmx_V_mult;
|
||||
// Uint64 mmx_YUV_threshold = 0x00300706; original hq2x threshold
|
||||
//Uint64 mmx_YUV_threshold = 0x0030100e;
|
||||
Uint64 mmx_YUV_threshold = 0x0040120c;
|
||||
|
||||
void
|
||||
Scale_MMX_PrepPlatform (const SDL_PixelFormat* fmt)
|
||||
{
|
||||
// prepare the channel-shuffle multiplier
|
||||
mmx_888to555_mult = ((Uint64)0x0400) << (fmt->Rshift * 2)
|
||||
| ((Uint64)0x0020) << (fmt->Gshift * 2)
|
||||
| ((Uint64)0x0001) << (fmt->Bshift * 2);
|
||||
|
||||
// prepare the RGB->YUV multipliers
|
||||
mmx_Y_mult = ((Uint64)(uint16)YUV_matrix[YUV_XFORM_R][YUV_XFORM_Y])
|
||||
<< (fmt->Rshift * 2)
|
||||
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_G][YUV_XFORM_Y])
|
||||
<< (fmt->Gshift * 2)
|
||||
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_B][YUV_XFORM_Y])
|
||||
<< (fmt->Bshift * 2);
|
||||
|
||||
mmx_U_mult = ((Uint64)(uint16)YUV_matrix[YUV_XFORM_R][YUV_XFORM_U])
|
||||
<< (fmt->Rshift * 2)
|
||||
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_G][YUV_XFORM_U])
|
||||
<< (fmt->Gshift * 2)
|
||||
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_B][YUV_XFORM_U])
|
||||
<< (fmt->Bshift * 2);
|
||||
|
||||
mmx_V_mult = ((Uint64)(uint16)YUV_matrix[YUV_XFORM_R][YUV_XFORM_V])
|
||||
<< (fmt->Rshift * 2)
|
||||
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_G][YUV_XFORM_V])
|
||||
<< (fmt->Gshift * 2)
|
||||
| ((Uint64)(uint16)YUV_matrix[YUV_XFORM_B][YUV_XFORM_V])
|
||||
<< (fmt->Bshift * 2);
|
||||
|
||||
mmx_YUV_threshold = (SCALE_DIFFYUV_TY << 16) | (SCALE_DIFFYUV_TU << 8)
|
||||
| SCALE_DIFFYUV_TV;
|
||||
}
|
||||
|
||||
|
||||
// Nearest Neighbor scaling to 2x
|
||||
// void Scale_MMX_Nearest (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "nearest2x.c"
|
||||
|
||||
|
||||
// Bilinear scaling to 2x
|
||||
// void Scale_MMX_BilinearFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "bilinear2x.c"
|
||||
|
||||
|
||||
// Advanced Biadapt scaling to 2x
|
||||
// void Scale_MMX_BiAdaptAdvFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "biadv2x.c"
|
||||
|
||||
|
||||
// Triscan scaling to 2x
|
||||
// derivative of 'scale2x' -- scale2x.sf.net
|
||||
// void Scale_MMX_TriScanFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "triscan2x.c"
|
||||
|
||||
// Hq2x scaling
|
||||
// (adapted from 'hq2x' by Maxim Stepin -- www.hiend3d.com/hq2x.html)
|
||||
// void Scale_MMX_HqFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "hq2x.c"
|
||||
|
||||
|
||||
#endif /* MMX_ASM */
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _2XSCALERS_MMX_H_
|
||||
#define _2XSCALERS_MMX_H_
|
||||
|
||||
// MMX versions
|
||||
void Scale_MMX_PrepPlatform (const SDL_PixelFormat* fmt);
|
||||
|
||||
void Scale_MMX_Nearest (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_MMX_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_MMX_BiAdaptAdvFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_MMX_TriScanFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_MMX_HqFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
|
||||
extern const Scale_FuncDef_t Scale_MMX_Functions[];
|
||||
|
||||
|
||||
// SSE (Intel)/MMX Ext (Athlon) versions
|
||||
void Scale_SSE_PrepPlatform (const SDL_PixelFormat* fmt);
|
||||
|
||||
void Scale_SSE_Nearest (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_SSE_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_SSE_BiAdaptAdvFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_SSE_TriScanFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_SSE_HqFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
|
||||
extern const Scale_FuncDef_t Scale_SSE_Functions[];
|
||||
|
||||
|
||||
// 3DNow (AMD K6/Athlon) versions
|
||||
void Scale_3DNow_PrepPlatform (const SDL_PixelFormat* fmt);
|
||||
|
||||
void Scale_3DNow_Nearest (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_3DNow_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_3DNow_BiAdaptAdvFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_3DNow_TriScanFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
void Scale_3DNow_HqFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r);
|
||||
|
||||
extern const Scale_FuncDef_t Scale_3DNow_Functions[];
|
||||
|
||||
|
||||
#endif /* _2XSCALERS_MMX_H_ */
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/platform.h"
|
||||
|
||||
#if defined(MMX_ASM)
|
||||
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
#include "types.h"
|
||||
#include "scalers.h"
|
||||
#include "scaleint.h"
|
||||
#include "2xscalers.h"
|
||||
#include "2xscalers_mmx.h"
|
||||
|
||||
// SSE name for all functions
|
||||
#undef SCALE_
|
||||
#define SCALE_(name) Scale ## _SSE_ ## name
|
||||
|
||||
// Tell them which opcodes we want to support
|
||||
#define USE_MOVNTQ
|
||||
#define USE_PREFETCH INTEL_PREFETCH
|
||||
#define USE_PSADBW
|
||||
// Bring in inline asm functions
|
||||
#include "scalemmx.h"
|
||||
|
||||
|
||||
// Scaler function lookup table
|
||||
//
|
||||
const Scale_FuncDef_t
|
||||
Scale_SSE_Functions[] =
|
||||
{
|
||||
{TFB_GFXFLAGS_SCALE_BILINEAR, Scale_SSE_BilinearFilter},
|
||||
{TFB_GFXFLAGS_SCALE_BIADAPT, Scale_BiAdaptFilter},
|
||||
{TFB_GFXFLAGS_SCALE_BIADAPTADV, Scale_SSE_BiAdaptAdvFilter},
|
||||
{TFB_GFXFLAGS_SCALE_TRISCAN, Scale_SSE_TriScanFilter},
|
||||
{TFB_GFXFLAGS_SCALE_HQXX, Scale_MMX_HqFilter},
|
||||
// Default
|
||||
{0, Scale_SSE_Nearest}
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
Scale_SSE_PrepPlatform (const SDL_PixelFormat* fmt)
|
||||
{
|
||||
Scale_MMX_PrepPlatform (fmt);
|
||||
}
|
||||
|
||||
// Nearest Neighbor scaling to 2x
|
||||
// void Scale_SSE_Nearest (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "nearest2x.c"
|
||||
|
||||
|
||||
// Bilinear scaling to 2x
|
||||
// void Scale_SSE_BilinearFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "bilinear2x.c"
|
||||
|
||||
|
||||
// Advanced Biadapt scaling to 2x
|
||||
// void Scale_SSE_BiAdaptAdvFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "biadv2x.c"
|
||||
|
||||
|
||||
// Triscan scaling to 2x
|
||||
// derivative of scale2x -- scale2x.sf.net
|
||||
// void Scale_SSE_TriScanFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "triscan2x.c"
|
||||
|
||||
#if 0 && NO_IMPROVEMENT
|
||||
// Hq2x scaling
|
||||
// (adapted from 'hq2x' by Maxim Stepin -- www.hiend3d.com/hq2x.html)
|
||||
// void Scale_SSE_HqFilter (SDL_Surface *src,
|
||||
// SDL_Surface *dst, SDL_Rect *r)
|
||||
|
||||
#include "hq2x.c"
|
||||
#endif
|
||||
|
||||
#endif /* MMX_ASM */
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
uqm_CFILES="opengl.c palette.c primitives.c pure.c sdl_common.c
|
||||
scalers.c 2xscalers.c
|
||||
2xscalers_mmx.c 2xscalers_sse.c 2xscalers_3dnow.c
|
||||
nearest2x.c bilinear2x.c biadv2x.c triscan2x.c hq2x.c
|
||||
canvas.c sdluio.c rotozoom.c"
|
||||
@@ -1,532 +0,0 @@
|
||||
/*
|
||||
* Portions Copyright (C) 2003-2005 Alex Volkov (codepro@usa.net)
|
||||
*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// Core algorithm of the Advanced BiAdaptive screen scaler
|
||||
// Template
|
||||
// When this file is built standalone is produces a plain C version
|
||||
// Also #included by 2xscalers_mmx.c for an MMX version
|
||||
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
#include "types.h"
|
||||
#include "scalers.h"
|
||||
#include "scaleint.h"
|
||||
#include "2xscalers.h"
|
||||
|
||||
|
||||
// Advanced biadapt scaling to 2x
|
||||
// The name expands to either
|
||||
// Scale_BiAdaptAdvFilter (for plain C) or
|
||||
// Scale_MMX_BiAdaptAdvFilter (for MMX)
|
||||
// [others when platforms are added]
|
||||
void
|
||||
SCALE_(BiAdaptAdvFilter) (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
||||
{
|
||||
int x, y;
|
||||
const int w = src->w, h = src->h;
|
||||
int xend, yend;
|
||||
int dsrc, ddst;
|
||||
SDL_Rect *region = r;
|
||||
SDL_Rect limits;
|
||||
SDL_PixelFormat *fmt = dst->format;
|
||||
const int sp = src->pitch, dp = dst->pitch;
|
||||
const int bpp = fmt->BytesPerPixel;
|
||||
const int slen = sp / bpp, dlen = dp / bpp;
|
||||
// for clarity purposes, the 'pixels' array here is transposed
|
||||
Uint32 pixels[4][4];
|
||||
static int resolve_coord[][2] =
|
||||
{
|
||||
{0, -1}, {1, -1}, { 2, 0}, { 2, 1},
|
||||
{1, 2}, {0, 2}, {-1, 1}, {-1, 0},
|
||||
{100, 100} // term
|
||||
};
|
||||
Uint32 *src_p = (Uint32 *)src->pixels;
|
||||
Uint32 *dst_p = (Uint32 *)dst->pixels;
|
||||
|
||||
// these macros are for clarity; they make the current pixel (0,0)
|
||||
// and allow to access pixels in all directions
|
||||
#define PIX(x, y) (pixels[1 + (x)][1 + (y)])
|
||||
#define SRC(x, y) (src_p + (x) + ((y) * slen))
|
||||
// commonly used operations, for clarity also
|
||||
// others are defined at their respective bpp levels
|
||||
#define BIADAPT_RGBHIGH 8000
|
||||
#define BIADAPT_YUVLOW 30
|
||||
#define BIADAPT_YUVMED 70
|
||||
#define BIADAPT_YUVHIGH 130
|
||||
|
||||
// high tolerance pixel comparison
|
||||
#define BIADAPT_CMPRGB_HIGH(p1, p2) \
|
||||
(p1 == p2 || SCALE_CMPRGB (p1, p2) <= BIADAPT_RGBHIGH)
|
||||
|
||||
// low tolerance pixel comparison
|
||||
#define BIADAPT_CMPYUV_LOW(p1, p2) \
|
||||
(p1 == p2 || SCALE_CMPYUV (p1, p2, BIADAPT_YUVLOW))
|
||||
// medium tolerance pixel comparison
|
||||
#define BIADAPT_CMPYUV_MED(p1, p2) \
|
||||
(p1 == p2 || SCALE_CMPYUV (p1, p2, BIADAPT_YUVMED))
|
||||
// high tolerance pixel comparison
|
||||
#define BIADAPT_CMPYUV_HIGH(p1, p2) \
|
||||
(p1 == p2 || SCALE_CMPYUV (p1, p2, BIADAPT_YUVHIGH))
|
||||
|
||||
SCALE_(PlatInit) ();
|
||||
|
||||
// expand updated region if necessary
|
||||
// pixels neighbooring the updated region may
|
||||
// change as a result of updates
|
||||
limits.x = 0;
|
||||
limits.y = 0;
|
||||
limits.w = src->w;
|
||||
limits.h = src->h;
|
||||
Scale_ExpandRect (region, 2, &limits);
|
||||
|
||||
xend = region->x + region->w;
|
||||
yend = region->y + region->h;
|
||||
dsrc = slen - region->w;
|
||||
ddst = (dlen - region->w) * 2;
|
||||
|
||||
#define SCALE_GETPIX(p) ( *(Uint32 *)(p) )
|
||||
#define SCALE_SETPIX(p, c) ( *(Uint32 *)(p) = (c) )
|
||||
|
||||
// move ptrs to the first updated pixel
|
||||
src_p += slen * region->y + region->x;
|
||||
dst_p += (dlen * region->y + region->x) * 2;
|
||||
|
||||
for (y = region->y; y < yend; ++y, dst_p += ddst, src_p += dsrc)
|
||||
{
|
||||
for (x = region->x; x < xend; ++x, ++src_p, ++dst_p)
|
||||
{
|
||||
// pixel equality counter
|
||||
int cmatch;
|
||||
|
||||
// most pixels will fall into 'all 4 equal'
|
||||
// pattern, so we check it first
|
||||
cmatch = 0;
|
||||
|
||||
PIX (0, 0) = SCALE_GETPIX (SRC (0, 0));
|
||||
|
||||
SCALE_SETPIX (dst_p, PIX (0, 0));
|
||||
|
||||
if (y + 1 < h)
|
||||
{
|
||||
// check pixel below the current one
|
||||
PIX (0, 1) = SCALE_GETPIX (SRC (0, 1));
|
||||
|
||||
if (PIX (0, 0) == PIX (0, 1))
|
||||
{
|
||||
SCALE_SETPIX (dst_p + dlen, PIX (0, 0));
|
||||
cmatch |= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// last pixel in column - propagate
|
||||
PIX (0, 1) = PIX (0, 0);
|
||||
SCALE_SETPIX (dst_p + dlen, PIX (0, 0));
|
||||
cmatch |= 1;
|
||||
|
||||
}
|
||||
|
||||
if (x + 1 < w)
|
||||
{
|
||||
// check pixel to the right from the current one
|
||||
PIX (1, 0) = SCALE_GETPIX (SRC (1, 0));
|
||||
|
||||
if (PIX (0, 0) == PIX (1, 0))
|
||||
{
|
||||
SCALE_SETPIX (dst_p + 1, PIX (0, 0));
|
||||
cmatch |= 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// last pixel in row - propagate
|
||||
PIX (1, 0) = PIX (0, 0);
|
||||
SCALE_SETPIX (dst_p + 1, PIX (0, 0));
|
||||
cmatch |= 2;
|
||||
}
|
||||
|
||||
if (cmatch == 3)
|
||||
{
|
||||
if (y + 1 >= h || x + 1 >= w)
|
||||
{
|
||||
// last pixel in row/column and nearest
|
||||
// neighboor is identical
|
||||
dst_p++;
|
||||
SCALE_SETPIX (dst_p + dlen, PIX (0, 0));
|
||||
continue;
|
||||
}
|
||||
|
||||
// check pixel to the bottom-right
|
||||
PIX (1, 1) = SCALE_GETPIX (SRC (1, 1));
|
||||
|
||||
if (PIX (0, 0) == PIX (1, 1))
|
||||
{
|
||||
// all 4 are equal - propagate
|
||||
dst_p++;
|
||||
SCALE_SETPIX (dst_p + dlen, PIX (0, 0));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// some neighboors are different, lets check them
|
||||
|
||||
if (x > 0)
|
||||
PIX (-1, 0) = SCALE_GETPIX (SRC (-1, 0));
|
||||
else
|
||||
PIX (-1, 0) = PIX (0, 0);
|
||||
|
||||
if (x + 2 < w)
|
||||
PIX (2, 0) = SCALE_GETPIX (SRC (2, 0));
|
||||
else
|
||||
PIX (2, 0) = PIX (1, 0);
|
||||
|
||||
if (y + 1 < h)
|
||||
{
|
||||
if (x > 0)
|
||||
PIX (-1, 1) = SCALE_GETPIX (SRC (-1, 1));
|
||||
else
|
||||
PIX (-1, 1) = PIX (0, 1);
|
||||
|
||||
if (x + 2 < w)
|
||||
{
|
||||
PIX (1, 1) = SCALE_GETPIX (SRC (1, 1));
|
||||
PIX (2, 1) = SCALE_GETPIX (SRC (2, 1));
|
||||
}
|
||||
else if (x + 1 < w)
|
||||
{
|
||||
PIX (1, 1) = SCALE_GETPIX (SRC (1, 1));
|
||||
PIX (2, 1) = PIX (1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
PIX (1, 1) = PIX (0, 1);
|
||||
PIX (2, 1) = PIX (0, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// last pixel in column
|
||||
PIX (-1, 1) = PIX (-1, 0);
|
||||
PIX (1, 1) = PIX (1, 0);
|
||||
PIX (2, 1) = PIX (2, 0);
|
||||
}
|
||||
|
||||
if (y + 2 < h)
|
||||
{
|
||||
PIX (0, 2) = SCALE_GETPIX (SRC (0, 2));
|
||||
|
||||
if (x > 0)
|
||||
PIX (-1, 2) = SCALE_GETPIX (SRC (-1, 2));
|
||||
else
|
||||
PIX (-1, 2) = PIX (0, 2);
|
||||
|
||||
if (x + 2 < w)
|
||||
{
|
||||
PIX (1, 2) = SCALE_GETPIX (SRC (1, 2));
|
||||
PIX (2, 2) = SCALE_GETPIX (SRC (2, 2));
|
||||
}
|
||||
else if (x + 1 < w)
|
||||
{
|
||||
PIX (1, 2) = SCALE_GETPIX (SRC (1, 2));
|
||||
PIX (2, 2) = PIX (1, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
PIX (1, 2) = PIX (0, 2);
|
||||
PIX (2, 2) = PIX (0, 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// last pixel in column
|
||||
PIX (-1, 2) = PIX (-1, 1);
|
||||
PIX (0, 2) = PIX (0, 1);
|
||||
PIX (1, 2) = PIX (1, 1);
|
||||
PIX (2, 2) = PIX (2, 1);
|
||||
}
|
||||
|
||||
if (y > 0)
|
||||
{
|
||||
PIX (0, -1) = SCALE_GETPIX (SRC (0, -1));
|
||||
|
||||
if (x > 0)
|
||||
PIX (-1, -1) = SCALE_GETPIX (SRC (-1, -1));
|
||||
else
|
||||
PIX (-1, -1) = PIX (0, -1);
|
||||
|
||||
if (x + 2 < w)
|
||||
{
|
||||
PIX (1, -1) = SCALE_GETPIX (SRC (1, -1));
|
||||
PIX (2, -1) = SCALE_GETPIX (SRC (2, -1));
|
||||
}
|
||||
else if (x + 1 < w)
|
||||
{
|
||||
PIX (1, -1) = SCALE_GETPIX (SRC (1, -1));
|
||||
PIX (2, -1) = PIX (1, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
PIX (1, -1) = PIX (0, -1);
|
||||
PIX (2, -1) = PIX (0, -1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PIX (-1, -1) = PIX (-1, 0);
|
||||
PIX (0, -1) = PIX (0, 0);
|
||||
PIX (1, -1) = PIX (1, 0);
|
||||
PIX (2, -1) = PIX (2, 0);
|
||||
}
|
||||
|
||||
// check pixel below the current one
|
||||
if (!(cmatch & 1))
|
||||
{
|
||||
if (SCALE_CMPYUV (PIX (0, 0), PIX (0, 1), BIADAPT_YUVLOW))
|
||||
{
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
|
||||
PIX (0, 0), PIX (0, 1))
|
||||
);
|
||||
cmatch |= 1;
|
||||
}
|
||||
// detect a 2:1 line going across the current pixel
|
||||
else if ( (PIX (0, 0) == PIX (-1, 0)
|
||||
&& PIX (0, 0) == PIX (1, 1)
|
||||
&& PIX (0, 0) == PIX (2, 1) &&
|
||||
|
||||
((!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, 0))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, 0))) ||
|
||||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, 2))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, 2))))) ||
|
||||
|
||||
(PIX (0, 0) == PIX (1, 0)
|
||||
&& PIX (0, 0) == PIX (-1, 1)
|
||||
&& PIX (0, 0) == PIX (2, -1) &&
|
||||
|
||||
((!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 0))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, -1))) ||
|
||||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 2))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, 1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, 0))))) )
|
||||
{
|
||||
SCALE_SETPIX (dst_p + dlen, PIX (0, 0));
|
||||
}
|
||||
// detect a 2:1 line going across the pixel below current
|
||||
else if ( (PIX (0, 1) == PIX (-1, 0)
|
||||
&& PIX (0, 1) == PIX (1, 1)
|
||||
&& PIX (0, 1) == PIX (2, 2) &&
|
||||
|
||||
((!BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (-1, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (1, 0))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (2, 1))) ||
|
||||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (-1, 1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (0, 2))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (1, 2))))) ||
|
||||
|
||||
(PIX (0, 1) == PIX (1, 0)
|
||||
&& PIX (0, 1) == PIX (-1, 1)
|
||||
&& PIX (0, 1) == PIX (2, 0) &&
|
||||
|
||||
((!BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (-1, 0))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (1, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (2, -1))) ||
|
||||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (-1, 2))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (0, 2))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (1, 1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 1), PIX (2, 1))))) )
|
||||
{
|
||||
SCALE_SETPIX (dst_p + dlen, PIX (0, 1));
|
||||
}
|
||||
else
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
|
||||
PIX (0, 0), PIX (0, 1))
|
||||
);
|
||||
}
|
||||
|
||||
dst_p++;
|
||||
|
||||
// check pixel to the right from the current one
|
||||
if (!(cmatch & 2))
|
||||
{
|
||||
if (SCALE_CMPYUV (PIX (0, 0), PIX (1, 0), BIADAPT_YUVLOW))
|
||||
{
|
||||
SCALE_SETPIX (dst_p, Scale_Blend_11 (
|
||||
PIX (0, 0), PIX (1, 0))
|
||||
);
|
||||
cmatch |= 2;
|
||||
}
|
||||
// detect a 1:2 line going across the current pixel
|
||||
else if ( (PIX (0, 0) == PIX (1, -1)
|
||||
&& PIX (0, 0) == PIX (0, 1)
|
||||
&& PIX (0, 0) == PIX (-1, 2) &&
|
||||
|
||||
((!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 0))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 1))) ||
|
||||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, 1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, 2))))) ||
|
||||
|
||||
(PIX (0, 0) == PIX (0, -1)
|
||||
&& PIX (0, 0) == PIX (1, 1)
|
||||
&& PIX (0, 0) == PIX (1, 2) &&
|
||||
|
||||
((!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (-1, 0))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, 1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (0, 2))) ||
|
||||
(!BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (1, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, 1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (0, 0), PIX (2, 2))))) )
|
||||
|
||||
{
|
||||
SCALE_SETPIX (dst_p, PIX (0, 0));
|
||||
}
|
||||
// detect a 1:2 line going across the pixel to the right
|
||||
else if ( (PIX (1, 0) == PIX (1, -1)
|
||||
&& PIX (1, 0) == PIX (0, 1)
|
||||
&& PIX (1, 0) == PIX (0, 2) &&
|
||||
|
||||
((!BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (0, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (-1, 1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (-1, 2))) ||
|
||||
(!BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (2, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (2, 0))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (1, 1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (1, 2))))) ||
|
||||
|
||||
(PIX (1, 0) == PIX (0, -1)
|
||||
&& PIX (1, 0) == PIX (1, 1)
|
||||
&& PIX (1, 0) == PIX (2, 2) &&
|
||||
|
||||
((!BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (-1, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (0, 1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (1, 2))) ||
|
||||
(!BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (1, -1))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (2, 0))
|
||||
&& !BIADAPT_CMPRGB_HIGH (PIX (1, 0), PIX (2, 1))))) )
|
||||
{
|
||||
SCALE_SETPIX (dst_p, PIX (1, 0));
|
||||
}
|
||||
else
|
||||
SCALE_SETPIX (dst_p, Scale_Blend_11 (
|
||||
PIX (0, 0), PIX (1, 0))
|
||||
);
|
||||
}
|
||||
|
||||
if (PIX (0, 0) == PIX (1, 1) && PIX (1, 0) == PIX (0, 1))
|
||||
{
|
||||
// diagonals are equal
|
||||
int *coord;
|
||||
int cl, cr;
|
||||
Uint32 clr;
|
||||
|
||||
// both pairs are equal, have to resolve the pixel
|
||||
// race; we try detecting which color is
|
||||
// the background by looking for a line or an edge
|
||||
// examine 8 pixels surrounding the current quad
|
||||
|
||||
cl = cr = 2;
|
||||
for (coord = resolve_coord[0]; *coord < 100; coord += 2)
|
||||
{
|
||||
clr = PIX (coord[0], coord[1]);
|
||||
|
||||
if (BIADAPT_CMPYUV_MED (clr, PIX (0, 0)))
|
||||
cl++;
|
||||
else if (BIADAPT_CMPYUV_MED (clr, PIX (1, 0)))
|
||||
cr++;
|
||||
}
|
||||
|
||||
// least count wins
|
||||
if (cl > cr)
|
||||
clr = PIX (1, 0);
|
||||
else if (cr > cl)
|
||||
clr = PIX (0, 0);
|
||||
else
|
||||
clr = Scale_Blend_11 (PIX (0, 0), PIX (1, 0));
|
||||
|
||||
SCALE_SETPIX (dst_p + dlen, clr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmatch == 3
|
||||
|| (BIADAPT_CMPYUV_LOW (PIX (1, 0), PIX (0, 1))
|
||||
&& BIADAPT_CMPYUV_LOW (PIX (1, 0), PIX (1, 1))))
|
||||
{
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
|
||||
PIX (0, 1), PIX (1, 0))
|
||||
);
|
||||
continue;
|
||||
}
|
||||
else if (cmatch && BIADAPT_CMPYUV_LOW (PIX (0, 0), PIX (1, 1)))
|
||||
{
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
|
||||
PIX (0, 0), PIX (1, 1))
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check pixel to the bottom-right
|
||||
if (BIADAPT_CMPYUV_HIGH (PIX (0, 0), PIX (1, 1))
|
||||
&& BIADAPT_CMPYUV_HIGH (PIX (1, 0), PIX (0, 1)))
|
||||
{
|
||||
if (SCALE_GETY (PIX (0, 0)) > SCALE_GETY (PIX (1, 0)))
|
||||
{
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
|
||||
PIX (0, 0), PIX (1, 1))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
|
||||
PIX (1, 0), PIX (0, 1))
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (BIADAPT_CMPYUV_HIGH (PIX (0, 0), PIX (1, 1)))
|
||||
{
|
||||
// main diagonal is same color
|
||||
// use its value
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
|
||||
PIX (0, 0), PIX (1, 1))
|
||||
);
|
||||
}
|
||||
else if (BIADAPT_CMPYUV_HIGH (PIX (1, 0), PIX (0, 1)))
|
||||
{
|
||||
// 2nd diagonal is same color
|
||||
// use its value
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
|
||||
PIX (1, 0), PIX (0, 1))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// blend all 4
|
||||
SCALE_SETPIX (dst_p + dlen, Scale_Blend_1111 (
|
||||
PIX (0, 0), PIX (0, 1),
|
||||
PIX (1, 0), PIX (1, 1)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCALE_(PlatDone) ();
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// Core algorithm of the BiLinear screen scaler
|
||||
// Template
|
||||
// When this file is built standalone is produces a plain C version
|
||||
// Also #included by 2xscalers_mmx.c for an MMX version
|
||||
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
#include "types.h"
|
||||
#include "scalers.h"
|
||||
#include "scaleint.h"
|
||||
#include "2xscalers.h"
|
||||
|
||||
|
||||
// Bilinear scaling to 2x
|
||||
// The name expands to either
|
||||
// Scale_BilinearFilter (for plain C) or
|
||||
// Scale_MMX_BilinearFilter (for MMX)
|
||||
// Scale_SSE_BilinearFilter (for SSE)
|
||||
// [others when platforms are added]
|
||||
void
|
||||
SCALE_(BilinearFilter) (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
||||
{
|
||||
int x, y;
|
||||
const int w = src->w, h = src->h;
|
||||
int xend, yend;
|
||||
int dsrc, ddst;
|
||||
SDL_Rect *region = r;
|
||||
SDL_Rect limits;
|
||||
SDL_PixelFormat *fmt = dst->format;
|
||||
const int pitch = src->pitch, dp = dst->pitch;
|
||||
const int bpp = fmt->BytesPerPixel;
|
||||
const int len = pitch / bpp, dlen = dp / bpp;
|
||||
Uint32 p[4]; // influential pixels array
|
||||
Uint32 *srow0 = (Uint32 *) src->pixels;
|
||||
Uint32 *dst_p = (Uint32 *) dst->pixels;
|
||||
|
||||
SCALE_(PlatInit) ();
|
||||
|
||||
// expand updated region if necessary
|
||||
// pixels neighbooring the updated region may
|
||||
// change as a result of updates
|
||||
limits.x = 0;
|
||||
limits.y = 0;
|
||||
limits.w = w;
|
||||
limits.h = h;
|
||||
Scale_ExpandRect (region, 1, &limits);
|
||||
|
||||
xend = region->x + region->w;
|
||||
yend = region->y + region->h;
|
||||
dsrc = len - region->w;
|
||||
ddst = (dlen - region->w) * 2;
|
||||
|
||||
// move ptrs to the first updated pixel
|
||||
srow0 += len * region->y + region->x;
|
||||
dst_p += (dlen * region->y + region->x) * 2;
|
||||
|
||||
for (y = region->y; y < yend; ++y, dst_p += ddst, srow0 += dsrc)
|
||||
{
|
||||
Uint32 *srow1;
|
||||
|
||||
SCALE_(Prefetch) (srow0 + 16);
|
||||
SCALE_(Prefetch) (srow0 + 32);
|
||||
|
||||
if (y < h - 1)
|
||||
srow1 = srow0 + len;
|
||||
else
|
||||
srow1 = srow0;
|
||||
|
||||
SCALE_(Prefetch) (srow1 + 16);
|
||||
SCALE_(Prefetch) (srow1 + 32);
|
||||
|
||||
for (x = region->x; x < xend; ++x, ++srow0, ++srow1, dst_p += 2)
|
||||
{
|
||||
if (x < w - 1)
|
||||
{ // can blend directly from pixels
|
||||
SCALE_BILINEAR_BLEND4 (srow0, srow1, dst_p, dlen);
|
||||
}
|
||||
else
|
||||
{ // need to make temp pixel rows
|
||||
p[0] = srow0[0];
|
||||
p[1] = p[0];
|
||||
p[2] = srow1[0];
|
||||
p[3] = p[2];
|
||||
|
||||
SCALE_BILINEAR_BLEND4 (&p[0], &p[2], dst_p, dlen);
|
||||
}
|
||||
}
|
||||
|
||||
SCALE_(Prefetch) (srow0 + dsrc);
|
||||
SCALE_(Prefetch) (srow0 + dsrc + 16);
|
||||
SCALE_(Prefetch) (srow1 + dsrc);
|
||||
SCALE_(Prefetch) (srow1 + dsrc + 16);
|
||||
}
|
||||
|
||||
SCALE_(PlatDone) ();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// Core algorithm of the BiLinear screen scaler
|
||||
// Template
|
||||
// When this file is built standalone is produces a plain C version
|
||||
// Also #included by 2xscalers_mmx.c for an MMX version
|
||||
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
#include "types.h"
|
||||
#include "scalers.h"
|
||||
#include "scaleint.h"
|
||||
#include "2xscalers.h"
|
||||
|
||||
// Nearest Neighbor scaling to 2x
|
||||
// The name expands to
|
||||
// Scale_Nearest (for plain C)
|
||||
// Scale_MMX_Nearest (for MMX)
|
||||
// Scale_SSE_Nearest (for SSE)
|
||||
// [others when platforms are added]
|
||||
void
|
||||
SCALE_(Nearest) (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
||||
{
|
||||
int y;
|
||||
const int rw = r->w, rh = r->h;
|
||||
const int sp = src->pitch, dp = dst->pitch;
|
||||
const int bpp = dst->format->BytesPerPixel;
|
||||
const int slen = sp / bpp, dlen = dp / bpp;
|
||||
const int dsrc = slen-rw, ddst = (dlen-rw) * 2;
|
||||
|
||||
Uint32 *src_p = (Uint32 *)src->pixels;
|
||||
Uint32 *dst_p = (Uint32 *)dst->pixels;
|
||||
|
||||
// guard asm code against such atrocities
|
||||
if (rw == 0 || rh == 0)
|
||||
return;
|
||||
|
||||
SCALE_(PlatInit) ();
|
||||
|
||||
// move ptrs to the first updated pixel
|
||||
src_p += slen * r->y + r->x;
|
||||
dst_p += (dlen * r->y + r->x) * 2;
|
||||
|
||||
#if defined(MMX_ASM) && defined(MSVC_ASM)
|
||||
// Just about everything has to be done in asm for MSVC
|
||||
// to actually take advantage of asm here
|
||||
// MSVC does not support beautiful GCC-like asm templates
|
||||
|
||||
y = rh;
|
||||
__asm
|
||||
{
|
||||
// setup vars
|
||||
mov esi, src_p
|
||||
mov edi, dst_p
|
||||
|
||||
PREFETCH (esi + 0x40)
|
||||
PREFETCH (esi + 0x80)
|
||||
PREFETCH (esi + 0xc0)
|
||||
|
||||
mov edx, dlen
|
||||
lea edx, [edx * 4]
|
||||
mov eax, dsrc
|
||||
lea eax, [eax * 4]
|
||||
mov ebx, ddst
|
||||
lea ebx, [ebx * 4]
|
||||
|
||||
mov ecx, rw
|
||||
loop_y:
|
||||
test ecx, 1
|
||||
jz even_x
|
||||
|
||||
// one-pixel transfer
|
||||
movd mm1, [esi]
|
||||
punpckldq mm1, mm1 // pix1 | pix1 -> mm1
|
||||
add esi, 4
|
||||
MOVNTQ (edi, mm1)
|
||||
add edi, 8
|
||||
MOVNTQ (edi - 8 + edx, mm1)
|
||||
|
||||
even_x:
|
||||
shr ecx, 1 // x = rw / 2
|
||||
jz end_x // rw was 1
|
||||
|
||||
loop_x:
|
||||
// two-pixel transfer
|
||||
movq mm1, [esi]
|
||||
movq mm2, mm1
|
||||
PREFETCH (esi + 0x100)
|
||||
punpckldq mm1, mm1 // pix1 | pix1 -> mm1
|
||||
add esi, 8
|
||||
MOVNTQ (edi, mm1)
|
||||
punpckhdq mm2, mm2 // pix2 | pix2 -> mm2
|
||||
MOVNTQ (edi + edx, mm1)
|
||||
add edi, 16
|
||||
MOVNTQ (edi - 8, mm2)
|
||||
MOVNTQ (edi - 8 + edx, mm2)
|
||||
|
||||
dec ecx
|
||||
jnz loop_x
|
||||
|
||||
end_x:
|
||||
// try to prefetch as early as possible to have it on time
|
||||
PREFETCH (esi + eax)
|
||||
|
||||
mov ecx, rw
|
||||
add esi, eax
|
||||
|
||||
PREFETCH (esi + 0x40)
|
||||
PREFETCH (esi + 0x80)
|
||||
PREFETCH (esi + 0xc0)
|
||||
|
||||
add edi, ebx
|
||||
|
||||
dec y
|
||||
jnz loop_y
|
||||
}
|
||||
|
||||
#elif defined(MMX_ASM) && defined(GCC_ASM)
|
||||
|
||||
SCALE_(Prefetch) (src_p + 16);
|
||||
SCALE_(Prefetch) (src_p + 32);
|
||||
SCALE_(Prefetch) (src_p + 48);
|
||||
|
||||
for (y = rh; y; --y)
|
||||
{
|
||||
int x = rw;
|
||||
|
||||
if (x & 1)
|
||||
{ // one-pixel transfer
|
||||
__asm__ (
|
||||
"movd (%0), %%mm1 \n\t"
|
||||
"punpckldq %%mm1, %%mm1 \n\t"
|
||||
MOVNTQ (%%mm1, (%1)) "\n\t"
|
||||
MOVNTQ (%%mm1, (%1,%2)) "\n\t"
|
||||
|
||||
: /* nothing */
|
||||
: /*0*/"r" (src_p), /*1*/"r" (dst_p), /*2*/"r" (dlen*sizeof(Uint32))
|
||||
);
|
||||
|
||||
++src_p;
|
||||
dst_p += 2;
|
||||
--x;
|
||||
}
|
||||
|
||||
for (x >>= 1; x; --x, src_p += 2, dst_p += 4)
|
||||
{ // two-pixel transfer
|
||||
__asm__ (
|
||||
"movq (%0), %%mm1 \n\t"
|
||||
"movq %%mm1, %%mm2 \n\t"
|
||||
PREFETCH (0x100(%0)) "\n\t"
|
||||
"punpckldq %%mm1, %%mm1 \n\t"
|
||||
MOVNTQ (%%mm1, (%1)) "\n\t"
|
||||
MOVNTQ (%%mm1, (%1,%2)) "\n\t"
|
||||
"punpckhdq %%mm2, %%mm2 \n\t"
|
||||
MOVNTQ (%%mm2, 8(%1)) "\n\t"
|
||||
MOVNTQ (%%mm2, 8(%1,%2)) "\n\t"
|
||||
|
||||
: /* nothing */
|
||||
: /*0*/"r" (src_p), /*1*/"r" (dst_p), /*2*/"r" (dlen*sizeof(Uint32))
|
||||
);
|
||||
}
|
||||
|
||||
src_p += dsrc;
|
||||
// try to prefetch as early as possible to have it on time
|
||||
SCALE_(Prefetch) (src_p);
|
||||
|
||||
dst_p += ddst;
|
||||
|
||||
SCALE_(Prefetch) (src_p + 16);
|
||||
SCALE_(Prefetch) (src_p + 32);
|
||||
SCALE_(Prefetch) (src_p + 48);
|
||||
}
|
||||
|
||||
#else
|
||||
// Plain C version
|
||||
for (y = 0; y < rh; ++y)
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < rw; ++x, ++src_p, dst_p += 2)
|
||||
{
|
||||
Uint32 pix = *src_p;
|
||||
dst_p[0] = pix;
|
||||
dst_p[1] = pix;
|
||||
dst_p[dlen] = pix;
|
||||
dst_p[dlen + 1] = pix;
|
||||
}
|
||||
dst_p += ddst;
|
||||
src_p += dsrc;
|
||||
}
|
||||
#endif
|
||||
|
||||
SCALE_(PlatDone) ();
|
||||
}
|
||||
|
||||
@@ -1,581 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_OPENGL
|
||||
|
||||
#include "libs/graphics/sdl/opengl.h"
|
||||
#include "libs/graphics/bbox.h"
|
||||
#include "scalers.h"
|
||||
#include "options.h"
|
||||
#include "libs/log.h"
|
||||
|
||||
typedef struct _gl_screeninfo {
|
||||
SDL_Surface *scaled;
|
||||
GLuint texture;
|
||||
BOOLEAN dirty, active;
|
||||
SDL_Rect updated;
|
||||
} TFB_GL_SCREENINFO;
|
||||
|
||||
static TFB_GL_SCREENINFO GL_Screens[TFB_GFX_NUMSCREENS];
|
||||
|
||||
static int ScreenFilterMode;
|
||||
|
||||
static TFB_ScaleFunc scaler = NULL;
|
||||
static BOOLEAN first_init = TRUE;
|
||||
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
#define R_MASK 0xff000000
|
||||
#define G_MASK 0x00ff0000
|
||||
#define B_MASK 0x0000ff00
|
||||
#define A_MASK 0x000000ff
|
||||
#else
|
||||
#define R_MASK 0x000000ff
|
||||
#define G_MASK 0x0000ff00
|
||||
#define B_MASK 0x00ff0000
|
||||
#define A_MASK 0xff000000
|
||||
#endif
|
||||
|
||||
static void TFB_GL_Preprocess (int force_full_redraw, int transition_amount, int fade_amount);
|
||||
static void TFB_GL_Postprocess (void);
|
||||
static void TFB_GL_Scaled_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect);
|
||||
static void TFB_GL_Unscaled_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect);
|
||||
static void TFB_GL_ColorLayer (Uint8 r, Uint8 g, Uint8 b, Uint8 a, SDL_Rect *rect);
|
||||
|
||||
static TFB_GRAPHICS_BACKEND opengl_scaled_backend = {
|
||||
TFB_GL_Preprocess,
|
||||
TFB_GL_Postprocess,
|
||||
TFB_GL_Scaled_ScreenLayer,
|
||||
TFB_GL_ColorLayer };
|
||||
|
||||
static TFB_GRAPHICS_BACKEND opengl_unscaled_backend = {
|
||||
TFB_GL_Preprocess,
|
||||
TFB_GL_Postprocess,
|
||||
TFB_GL_Unscaled_ScreenLayer,
|
||||
TFB_GL_ColorLayer };
|
||||
|
||||
|
||||
static SDL_Surface *
|
||||
Create_Screen (SDL_Surface *template, int w, int h)
|
||||
{
|
||||
SDL_Surface *newsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
|
||||
template->format->BitsPerPixel,
|
||||
template->format->Rmask, template->format->Gmask,
|
||||
template->format->Bmask, 0);
|
||||
if (newsurf == 0) {
|
||||
log_add (log_Error, "Couldn't create screen buffers: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
return newsurf;
|
||||
}
|
||||
|
||||
static int
|
||||
ReInit_Screen (SDL_Surface **screen, SDL_Surface *template, int w, int h)
|
||||
{
|
||||
if (*screen)
|
||||
SDL_FreeSurface (*screen);
|
||||
*screen = Create_Screen (template, w, h);
|
||||
|
||||
return *screen == 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
AttemptColorDepth (int flags, int width, int height, int bpp)
|
||||
{
|
||||
int videomode_flags;
|
||||
ScreenColorDepth = bpp;
|
||||
ScreenWidthActual = width;
|
||||
ScreenHeightActual = height;
|
||||
|
||||
switch (bpp) {
|
||||
case 15:
|
||||
SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
|
||||
SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
|
||||
SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
|
||||
SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 6);
|
||||
SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
|
||||
break;
|
||||
|
||||
case 24:
|
||||
SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8);
|
||||
break;
|
||||
|
||||
case 32:
|
||||
SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 0);
|
||||
SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
|
||||
|
||||
videomode_flags = SDL_OPENGL;
|
||||
if (flags & TFB_GFXFLAGS_FULLSCREEN)
|
||||
videomode_flags |= SDL_FULLSCREEN;
|
||||
videomode_flags |= SDL_ANYFORMAT;
|
||||
|
||||
SDL_Video = SDL_SetVideoMode (ScreenWidthActual, ScreenHeightActual,
|
||||
bpp, videomode_flags);
|
||||
if (SDL_Video == NULL)
|
||||
{
|
||||
log_add (log_Error, "Couldn't set OpenGL %ix%ix%i video mode: %s",
|
||||
ScreenWidthActual, ScreenHeightActual, bpp,
|
||||
SDL_GetError ());
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_add (log_Info, "Set the resolution to: %ix%ix%i"
|
||||
" (surface reports %ix%ix%i)",
|
||||
width, height, bpp,
|
||||
SDL_GetVideoSurface()->w, SDL_GetVideoSurface()->h,
|
||||
SDL_GetVideoSurface()->format->BitsPerPixel);
|
||||
|
||||
log_add (log_Info, "OpenGL renderer: %s version: %s",
|
||||
glGetString (GL_RENDERER), glGetString (GL_VERSION));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
TFB_GL_ConfigureVideo (int driver, int flags, int width, int height, int togglefullscreen)
|
||||
{
|
||||
int i, texture_width, texture_height;
|
||||
GraphicsDriver = driver;
|
||||
|
||||
if (AttemptColorDepth (flags, width, height, 32) &&
|
||||
AttemptColorDepth (flags, width, height, 24) &&
|
||||
AttemptColorDepth (flags, width, height, 16))
|
||||
{
|
||||
log_add (log_Error, "Couldn't set any OpenGL %ix%i video mode!",
|
||||
width, height);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!togglefullscreen)
|
||||
{
|
||||
if (format_conv_surf)
|
||||
SDL_FreeSurface (format_conv_surf);
|
||||
format_conv_surf = SDL_CreateRGBSurface (SDL_SWSURFACE, 0, 0, 32,
|
||||
R_MASK, G_MASK, B_MASK, A_MASK);
|
||||
if (format_conv_surf == NULL)
|
||||
{
|
||||
log_add (log_Error, "Couldn't create format_conv_surf: %s",
|
||||
SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
|
||||
{
|
||||
if (0 != ReInit_Screen (&SDL_Screens[i], format_conv_surf,
|
||||
ScreenWidth, ScreenHeight))
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_Screen = SDL_Screens[0];
|
||||
TransitionScreen = SDL_Screens[2];
|
||||
|
||||
if (first_init)
|
||||
{
|
||||
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
|
||||
{
|
||||
GL_Screens[i].scaled = NULL;
|
||||
GL_Screens[i].dirty = TRUE;
|
||||
GL_Screens[i].active = TRUE;
|
||||
}
|
||||
GL_Screens[1].active = FALSE;
|
||||
first_init = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (GfxFlags & TFB_GFXFLAGS_SCALE_SOFT_ONLY)
|
||||
{
|
||||
if (!togglefullscreen)
|
||||
{
|
||||
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
|
||||
{
|
||||
if (!GL_Screens[i].active)
|
||||
continue;
|
||||
if (0 != ReInit_Screen (&GL_Screens[i].scaled, format_conv_surf,
|
||||
ScreenWidth * 2, ScreenHeight * 2))
|
||||
return -1;
|
||||
}
|
||||
scaler = Scale_PrepPlatform (flags, SDL_Screen->format);
|
||||
}
|
||||
|
||||
texture_width = 1024;
|
||||
texture_height = 512;
|
||||
|
||||
graphics_backend = &opengl_scaled_backend;
|
||||
}
|
||||
else
|
||||
{
|
||||
texture_width = 512;
|
||||
texture_height = 256;
|
||||
|
||||
scaler = NULL;
|
||||
graphics_backend = &opengl_unscaled_backend;
|
||||
}
|
||||
|
||||
|
||||
if (GfxFlags & TFB_GFXFLAGS_SCALE_ANY)
|
||||
ScreenFilterMode = GL_LINEAR;
|
||||
else
|
||||
ScreenFilterMode = GL_NEAREST;
|
||||
|
||||
glViewport (0, 0, ScreenWidthActual, ScreenHeightActual);
|
||||
glClearColor (0,0,0,0);
|
||||
glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
|
||||
SDL_GL_SwapBuffers ();
|
||||
glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
|
||||
glDisable (GL_DITHER);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
|
||||
{
|
||||
if (!GL_Screens[i].active)
|
||||
continue;
|
||||
glGenTextures (1, &GL_Screens[i].texture);
|
||||
glBindTexture (GL_TEXTURE_2D, GL_Screens[i].texture);
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, texture_width, texture_height,
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
TFB_GL_InitGraphics (int driver, int flags, int width, int height)
|
||||
{
|
||||
char VideoName[256];
|
||||
|
||||
log_add (log_Info, "Initializing SDL with OpenGL support.");
|
||||
|
||||
SDL_VideoDriverName (VideoName, sizeof (VideoName));
|
||||
log_add (log_Info, "SDL driver used: %s", VideoName);
|
||||
log_add (log_Info, "SDL initialized.");
|
||||
log_add (log_Info, "Initializing Screen.");
|
||||
|
||||
ScreenWidth = 320;
|
||||
ScreenHeight = 240;
|
||||
|
||||
if (TFB_GL_ConfigureVideo (driver, flags, width, height, 0))
|
||||
{
|
||||
log_add (log_Fatal, "Could not initialize video: "
|
||||
"no fallback at start of program!");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Initialize scalers (let them precompute whatever)
|
||||
Scale_Init ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TFB_GL_UploadTransitionScreen (void)
|
||||
{
|
||||
GL_Screens[TFB_SCREEN_TRANSITION].updated.x = 0;
|
||||
GL_Screens[TFB_SCREEN_TRANSITION].updated.y = 0;
|
||||
GL_Screens[TFB_SCREEN_TRANSITION].updated.w = ScreenWidth;
|
||||
GL_Screens[TFB_SCREEN_TRANSITION].updated.h = ScreenHeight;
|
||||
GL_Screens[TFB_SCREEN_TRANSITION].dirty = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
TFB_GL_ScanLines (void)
|
||||
{
|
||||
int y;
|
||||
|
||||
glDisable (GL_TEXTURE_2D);
|
||||
glEnable (GL_BLEND);
|
||||
glBlendFunc (GL_DST_COLOR, GL_ZERO);
|
||||
glColor3f (0.85f, 0.85f, 0.85f);
|
||||
for (y = 0; y < ScreenHeightActual; y += 2)
|
||||
{
|
||||
glBegin (GL_LINES);
|
||||
glVertex2i (0, y);
|
||||
glVertex2i (ScreenWidthActual, y);
|
||||
glEnd ();
|
||||
}
|
||||
|
||||
glBlendFunc (GL_DST_COLOR, GL_ONE);
|
||||
glColor3f (0.2f, 0.2f, 0.2f);
|
||||
for (y = 1; y < ScreenHeightActual; y += 2)
|
||||
{
|
||||
glBegin (GL_LINES);
|
||||
glVertex2i (0, y);
|
||||
glVertex2i (ScreenWidthActual, y);
|
||||
glEnd ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TFB_GL_DrawQuad (SDL_Rect *r)
|
||||
{
|
||||
BOOLEAN keep_aspect_ratio = optKeepAspectRatio;
|
||||
int x1 = 0, y1 = 0, x2 = ScreenWidthActual, y2 = ScreenHeightActual;
|
||||
int sx = 0, sy = 0;
|
||||
int sw, sh;
|
||||
float sx_multiplier = 1;
|
||||
float sy_multiplier = 1;
|
||||
|
||||
if (keep_aspect_ratio)
|
||||
{
|
||||
float threshold = 0.75f;
|
||||
float ratio = ScreenHeightActual / (float)ScreenWidthActual;
|
||||
|
||||
if (ratio > threshold)
|
||||
{
|
||||
// screen is narrower than 4:3
|
||||
int height = (int)(ScreenWidthActual * threshold);
|
||||
y1 = (ScreenHeightActual - height) / 2;
|
||||
y2 = ScreenHeightActual - y1;
|
||||
|
||||
if (r != NULL)
|
||||
{
|
||||
sx_multiplier = ScreenWidthActual / (float)ScreenWidth;
|
||||
sy_multiplier = height / (float)ScreenHeight;
|
||||
sx = (int)(r->x * sx_multiplier);
|
||||
sy = (int)(((ScreenHeight - (r->y + r->h)) * sy_multiplier) + y1);
|
||||
}
|
||||
}
|
||||
else if (ratio < threshold)
|
||||
{
|
||||
// screen is wider than 4:3
|
||||
int width = (int)(ScreenHeightActual / threshold);
|
||||
x1 = (ScreenWidthActual - width) / 2;
|
||||
x2 = ScreenWidthActual - x1;
|
||||
|
||||
if (r != NULL)
|
||||
{
|
||||
sx_multiplier = width / (float)ScreenWidth;
|
||||
sy_multiplier = ScreenHeightActual / (float)ScreenHeight;
|
||||
sx = (int)((r->x * sx_multiplier) + x1);
|
||||
sy = (int)((ScreenHeight - (r->y + r->h)) * sy_multiplier);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// screen is 4:3
|
||||
keep_aspect_ratio = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (r != NULL)
|
||||
{
|
||||
if (!keep_aspect_ratio)
|
||||
{
|
||||
sx_multiplier = ScreenWidthActual / (float)ScreenWidth;
|
||||
sy_multiplier = ScreenHeightActual / (float)ScreenHeight;
|
||||
sx = (int)(r->x * sx_multiplier);
|
||||
sy = (int)((ScreenHeight - (r->y + r->h)) * sy_multiplier);
|
||||
}
|
||||
sw = (int)(r->w * sx_multiplier);
|
||||
sh = (int)(r->h * sy_multiplier);
|
||||
glScissor (sx, sy, sw, sh);
|
||||
glEnable (GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
glBegin (GL_TRIANGLE_FAN);
|
||||
glTexCoord2f (0, 0);
|
||||
glVertex2i (x1, y1);
|
||||
glTexCoord2f (ScreenWidth / 512.0f, 0);
|
||||
glVertex2i (x2, y1);
|
||||
glTexCoord2f (ScreenWidth / 512.0f, ScreenHeight / 256.0f);
|
||||
glVertex2i (x2, y2);
|
||||
glTexCoord2f (0, ScreenHeight / 256.0f);
|
||||
glVertex2i (x1, y2);
|
||||
glEnd ();
|
||||
if (r != NULL)
|
||||
{
|
||||
glDisable (GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TFB_GL_Preprocess (int force_full_redraw, int transition_amount, int fade_amount)
|
||||
{
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadIdentity ();
|
||||
glOrtho (0,ScreenWidthActual,ScreenHeightActual, 0, -1, 1);
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glLoadIdentity ();
|
||||
if (optKeepAspectRatio)
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
|
||||
(void) transition_amount;
|
||||
(void) fade_amount;
|
||||
|
||||
if (force_full_redraw == TFB_REDRAW_YES)
|
||||
{
|
||||
GL_Screens[TFB_SCREEN_MAIN].updated.x = 0;
|
||||
GL_Screens[TFB_SCREEN_MAIN].updated.y = 0;
|
||||
GL_Screens[TFB_SCREEN_MAIN].updated.w = ScreenWidth;
|
||||
GL_Screens[TFB_SCREEN_MAIN].updated.h = ScreenHeight;
|
||||
GL_Screens[TFB_SCREEN_MAIN].dirty = TRUE;
|
||||
}
|
||||
else if (TFB_BBox.valid)
|
||||
{
|
||||
GL_Screens[TFB_SCREEN_MAIN].updated.x = TFB_BBox.region.corner.x;
|
||||
GL_Screens[TFB_SCREEN_MAIN].updated.y = TFB_BBox.region.corner.y;
|
||||
GL_Screens[TFB_SCREEN_MAIN].updated.w = TFB_BBox.region.extent.width;
|
||||
GL_Screens[TFB_SCREEN_MAIN].updated.h = TFB_BBox.region.extent.height;
|
||||
GL_Screens[TFB_SCREEN_MAIN].dirty = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TFB_GL_Unscaled_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect)
|
||||
{
|
||||
glBindTexture (GL_TEXTURE_2D, GL_Screens[screen].texture);
|
||||
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
if (GL_Screens[screen].dirty)
|
||||
{
|
||||
int PitchWords = SDL_Screens[screen]->pitch / 4;
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, PitchWords);
|
||||
/* Matrox OpenGL drivers do not handle GL_UNPACK_SKIP_*
|
||||
correctly */
|
||||
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
|
||||
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
|
||||
SDL_LockSurface (SDL_Screens[screen]);
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0, GL_Screens[screen].updated.x,
|
||||
GL_Screens[screen].updated.y,
|
||||
GL_Screens[screen].updated.w,
|
||||
GL_Screens[screen].updated.h,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
(Uint32 *)SDL_Screens[screen]->pixels +
|
||||
(GL_Screens[screen].updated.y * PitchWords +
|
||||
GL_Screens[screen].updated.x));
|
||||
SDL_UnlockSurface (SDL_Screens[screen]);
|
||||
GL_Screens[screen].dirty = FALSE;
|
||||
}
|
||||
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ScreenFilterMode);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ScreenFilterMode);
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
|
||||
if (a == 255)
|
||||
{
|
||||
glDisable (GL_BLEND);
|
||||
glColor4f (1, 1, 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
float a_f = a / 255.0f;
|
||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable (GL_BLEND);
|
||||
glColor4f (1, 1, 1, a_f);
|
||||
}
|
||||
|
||||
TFB_GL_DrawQuad (rect);
|
||||
}
|
||||
|
||||
static void
|
||||
TFB_GL_Scaled_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect)
|
||||
{
|
||||
glBindTexture (GL_TEXTURE_2D, GL_Screens[screen].texture);
|
||||
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
if (GL_Screens[screen].dirty)
|
||||
{
|
||||
int PitchWords = GL_Screens[screen].scaled->pitch / 4;
|
||||
scaler (SDL_Screens[screen], GL_Screens[screen].scaled, &GL_Screens[screen].updated);
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, PitchWords);
|
||||
|
||||
/* Matrox OpenGL drivers do not handle GL_UNPACK_SKIP_*
|
||||
correctly */
|
||||
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
|
||||
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
|
||||
SDL_LockSurface (GL_Screens[screen].scaled);
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0, GL_Screens[screen].updated.x * 2,
|
||||
GL_Screens[screen].updated.y * 2,
|
||||
GL_Screens[screen].updated.w * 2,
|
||||
GL_Screens[screen].updated.h * 2,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
(Uint32 *)GL_Screens[screen].scaled->pixels +
|
||||
(GL_Screens[screen].updated.y * 2 * PitchWords +
|
||||
GL_Screens[screen].updated.x * 2));
|
||||
SDL_UnlockSurface (GL_Screens[screen].scaled);
|
||||
GL_Screens[screen].dirty = FALSE;
|
||||
}
|
||||
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ScreenFilterMode);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ScreenFilterMode);
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
|
||||
if (a == 255)
|
||||
{
|
||||
glDisable (GL_BLEND);
|
||||
glColor4f (1, 1, 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
float a_f = a / 255.0f;
|
||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable (GL_BLEND);
|
||||
glColor4f (1, 1, 1, a_f);
|
||||
}
|
||||
|
||||
TFB_GL_DrawQuad (rect);
|
||||
}
|
||||
|
||||
static void
|
||||
TFB_GL_ColorLayer (Uint8 r, Uint8 g, Uint8 b, Uint8 a, SDL_Rect *rect)
|
||||
{
|
||||
float r_f = r / 255.0f;
|
||||
float g_f = g / 255.0f;
|
||||
float b_f = b / 255.0f;
|
||||
float a_f = a / 255.0f;
|
||||
glColor4f(r_f, g_f, b_f, a_f);
|
||||
|
||||
glDisable (GL_TEXTURE_2D);
|
||||
if (a != 255)
|
||||
{
|
||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable (GL_BLEND);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable (GL_BLEND);
|
||||
}
|
||||
|
||||
TFB_GL_DrawQuad (rect);
|
||||
}
|
||||
|
||||
static void
|
||||
TFB_GL_Postprocess (void)
|
||||
{
|
||||
if (GfxFlags & TFB_GFXFLAGS_SCANLINES)
|
||||
TFB_GL_ScanLines ();
|
||||
|
||||
SDL_GL_SwapBuffers ();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,88 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef OPENGL_H
|
||||
#define OPENGL_H
|
||||
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
|
||||
int TFB_GL_InitGraphics (int driver, int flags, int width, int height);
|
||||
int TFB_GL_ConfigureVideo (int driver, int flags, int width, int height, int togglefullscreen);
|
||||
void TFB_GL_UploadTransitionScreen (void);
|
||||
|
||||
#ifdef HAVE_OPENGL
|
||||
#ifdef WIN32
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment (lib, "opengl32.lib")
|
||||
#pragma comment (lib, "glu32.lib")
|
||||
#endif
|
||||
|
||||
/* To avoid including windows.h,
|
||||
Win32's <GL/gl.h> needs APIENTRY and WINGDIAPI defined properly. */
|
||||
|
||||
#ifndef APIENTRY
|
||||
#define GLUT_APIENTRY_DEFINED
|
||||
#if __MINGW32__ || (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
|
||||
#define APIENTRY __stdcall
|
||||
#else
|
||||
#define APIENTRY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef WINAPI
|
||||
#define GLUT_WINAPI_DEFINED
|
||||
#if __MINGW32__ || (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
|
||||
#define WINAPI __stdcall
|
||||
#else
|
||||
#define WINAPI
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* This is from Win32's <winnt.h> */
|
||||
#ifndef CALLBACK
|
||||
#if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS)
|
||||
#define CALLBACK __stdcall
|
||||
#else
|
||||
#define CALLBACK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* This is from Win32's <wingdi.h> and <winnt.h> */
|
||||
#ifndef WINGDIAPI
|
||||
#define GLUT_WINGDIAPI_DEFINED
|
||||
#define WINGDIAPI __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
/* This is from Win32's <ctype.h> */
|
||||
#ifndef _WCHAR_T_DEFINED
|
||||
typedef unsigned short wchar_t;
|
||||
#define _WCHAR_T_DEFINED
|
||||
#endif
|
||||
|
||||
#include "GL/glu.h"
|
||||
|
||||
#else /* !defined(WIN32) */
|
||||
|
||||
#include "port.h"
|
||||
#include SDL_INCLUDE(SDL_opengl.h)
|
||||
|
||||
#endif /* WIN32 */
|
||||
#endif /* HAVE_OPENGL */
|
||||
|
||||
#endif
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009 Alex Volkov <codepro@usa.net>
|
||||
*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "palette.h"
|
||||
#include "libs/memlib.h"
|
||||
#include "libs/log.h"
|
||||
|
||||
NativePalette *
|
||||
AllocNativePalette (void)
|
||||
{
|
||||
return HCalloc (sizeof (NativePalette));
|
||||
}
|
||||
|
||||
void
|
||||
FreeNativePalette (NativePalette *palette)
|
||||
{
|
||||
HFree (palette);
|
||||
}
|
||||
|
||||
void
|
||||
SetNativePaletteColor (NativePalette *palette, int index, Color color)
|
||||
{
|
||||
assert (index < NUMBER_OF_PLUTVALS);
|
||||
palette->colors[index] = ColorToNative (color);
|
||||
}
|
||||
|
||||
Color
|
||||
GetNativePaletteColor (NativePalette *palette, int index)
|
||||
{
|
||||
assert (index < NUMBER_OF_PLUTVALS);
|
||||
return NativeToColor (palette->colors[index]);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009 Alex Volkov <codepro@usa.net>
|
||||
*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef PALETTE_H_INCL__
|
||||
#define PALETTE_H_INCL__
|
||||
|
||||
#include "port.h"
|
||||
#include SDL_INCLUDE(SDL.h)
|
||||
#include "libs/graphics/cmap.h"
|
||||
|
||||
struct NativePalette
|
||||
{
|
||||
SDL_Color colors[NUMBER_OF_PLUTVALS];
|
||||
};
|
||||
|
||||
static inline Color
|
||||
NativeToColor (SDL_Color native)
|
||||
{
|
||||
Color color;
|
||||
color.r = native.r;
|
||||
color.g = native.g;
|
||||
color.b = native.b;
|
||||
color.a = 0xff; // fully opaque
|
||||
return color;
|
||||
}
|
||||
|
||||
static inline SDL_Color
|
||||
ColorToNative (Color color)
|
||||
{
|
||||
SDL_Color native;
|
||||
native.r = color.r;
|
||||
native.g = color.g;
|
||||
native.b = color.b;
|
||||
native.unused = 0;
|
||||
return native;
|
||||
}
|
||||
|
||||
#endif /* PALETTE_H_INCL__ */
|
||||
@@ -1,635 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
#include "sdl_common.h"
|
||||
#include "primitives.h"
|
||||
|
||||
|
||||
// Pixel drawing routines
|
||||
|
||||
static Uint32
|
||||
getpixel_8(SDL_Surface *surface, int x, int y)
|
||||
{
|
||||
/* Here p is the address to the pixel we want to retrieve */
|
||||
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x;
|
||||
return *p;
|
||||
}
|
||||
|
||||
static void
|
||||
putpixel_8(SDL_Surface *surface, int x, int y, Uint32 pixel)
|
||||
{
|
||||
/* Here p is the address to the pixel we want to set */
|
||||
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 1;
|
||||
*p = pixel;
|
||||
}
|
||||
|
||||
static Uint32
|
||||
getpixel_16(SDL_Surface *surface, int x, int y)
|
||||
{
|
||||
/* Here p is the address to the pixel we want to retrieve */
|
||||
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 2;
|
||||
return *(Uint16 *)p;
|
||||
}
|
||||
|
||||
static void
|
||||
putpixel_16(SDL_Surface *surface, int x, int y, Uint32 pixel)
|
||||
{
|
||||
/* Here p is the address to the pixel we want to set */
|
||||
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 2;
|
||||
*(Uint16 *)p = pixel;
|
||||
}
|
||||
|
||||
static Uint32
|
||||
getpixel_24_be(SDL_Surface *surface, int x, int y)
|
||||
{
|
||||
/* Here p is the address to the pixel we want to retrieve */
|
||||
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
|
||||
return p[0] << 16 | p[1] << 8 | p[2];
|
||||
}
|
||||
|
||||
static void
|
||||
putpixel_24_be(SDL_Surface *surface, int x, int y, Uint32 pixel)
|
||||
{
|
||||
/* Here p is the address to the pixel we want to set */
|
||||
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
|
||||
p[0] = (pixel >> 16) & 0xff;
|
||||
p[1] = (pixel >> 8) & 0xff;
|
||||
p[2] = pixel & 0xff;
|
||||
}
|
||||
|
||||
static Uint32
|
||||
getpixel_24_le(SDL_Surface *surface, int x, int y)
|
||||
{
|
||||
/* Here p is the address to the pixel we want to retrieve */
|
||||
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
|
||||
return p[0] | p[1] << 8 | p[2] << 16;
|
||||
}
|
||||
|
||||
static void
|
||||
putpixel_24_le(SDL_Surface *surface, int x, int y, Uint32 pixel)
|
||||
{
|
||||
/* Here p is the address to the pixel we want to set */
|
||||
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
|
||||
p[0] = pixel & 0xff;
|
||||
p[1] = (pixel >> 8) & 0xff;
|
||||
p[2] = (pixel >> 16) & 0xff;
|
||||
}
|
||||
|
||||
static Uint32
|
||||
getpixel_32(SDL_Surface *surface, int x, int y)
|
||||
{
|
||||
/* Here p is the address to the pixel we want to retrieve */
|
||||
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 4;
|
||||
return *(Uint32 *)p;
|
||||
}
|
||||
|
||||
static void
|
||||
putpixel_32(SDL_Surface *surface, int x, int y, Uint32 pixel)
|
||||
{
|
||||
/* Here p is the address to the pixel we want to set */
|
||||
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 4;
|
||||
*(Uint32 *)p = pixel;
|
||||
}
|
||||
|
||||
GetPixelFn
|
||||
getpixel_for(SDL_Surface *surface)
|
||||
{
|
||||
int bpp = surface->format->BytesPerPixel;
|
||||
switch (bpp) {
|
||||
case 1:
|
||||
return &getpixel_8;
|
||||
case 2:
|
||||
return &getpixel_16;
|
||||
case 3:
|
||||
if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
|
||||
return &getpixel_24_be;
|
||||
} else {
|
||||
return &getpixel_24_le;
|
||||
}
|
||||
case 4:
|
||||
return &getpixel_32;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PutPixelFn
|
||||
putpixel_for(SDL_Surface *surface)
|
||||
{
|
||||
int bpp = surface->format->BytesPerPixel;
|
||||
switch (bpp) {
|
||||
case 1:
|
||||
return &putpixel_8;
|
||||
case 2:
|
||||
return &putpixel_16;
|
||||
case 3:
|
||||
if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
|
||||
return &putpixel_24_be;
|
||||
} else {
|
||||
return &putpixel_24_le;
|
||||
}
|
||||
case 4:
|
||||
return &putpixel_32;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
renderpixel_replace(SDL_Surface *surface, int x, int y, Uint32 pixel,
|
||||
int factor)
|
||||
{
|
||||
(void) factor; // ignored
|
||||
putpixel_32(surface, x, y, pixel);
|
||||
}
|
||||
|
||||
static inline Uint8
|
||||
clip_channel(int c)
|
||||
{
|
||||
if (c < 0)
|
||||
c = 0;
|
||||
else if (c > 255)
|
||||
c = 255;
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline Uint8
|
||||
modulated_sum(Uint8 dc, Uint8 sc, int factor)
|
||||
{
|
||||
// We use >> 8 instead of / 255 because it is faster, but it does
|
||||
// not work 100% correctly. It should be safe because this should
|
||||
// not be called for factor==255
|
||||
int b = dc + ((sc * factor) >> 8);
|
||||
return clip_channel(b);
|
||||
}
|
||||
|
||||
static inline Uint8
|
||||
alpha_blend(Uint8 dc, Uint8 sc, int alpha)
|
||||
{
|
||||
// We use >> 8 instead of / 255 because it is faster, but it does
|
||||
// not work 100% correctly. It should be safe because this should
|
||||
// not be called for alpha==255
|
||||
// No need to clip since we should never get values outside of 0..255
|
||||
// range, unless alpha is over 255, which is not supported.
|
||||
return (((sc - dc) * alpha) >> 8) + dc;
|
||||
}
|
||||
|
||||
// Assumes 8 bits/channel, a safe assumption for 32bpp surfaces
|
||||
#define UNPACK_PIXEL_32(p, fmt, r, g, b) \
|
||||
do { \
|
||||
(r) = ((p) >> (fmt)->Rshift) & 0xff; \
|
||||
(g) = ((p) >> (fmt)->Gshift) & 0xff; \
|
||||
(b) = ((p) >> (fmt)->Bshift) & 0xff; \
|
||||
} while (0)
|
||||
|
||||
// Assumes the channels already clipped to 8 bits
|
||||
static inline Uint32
|
||||
PACK_PIXEL_32(const SDL_PixelFormat *fmt,
|
||||
Uint8 r, Uint8 g, Uint8 b)
|
||||
{
|
||||
return ((Uint32)r << fmt->Rshift) | ((Uint32)g << fmt->Gshift)
|
||||
| ((Uint32)b << fmt->Bshift);
|
||||
}
|
||||
|
||||
static void
|
||||
renderpixel_additive(SDL_Surface *surface, int x, int y, Uint32 pixel,
|
||||
int factor)
|
||||
{
|
||||
const SDL_PixelFormat *fmt = surface->format;
|
||||
Uint32 *p;
|
||||
Uint32 sp;
|
||||
Uint8 sr, sg, sb;
|
||||
int r, g, b;
|
||||
|
||||
p = (Uint32 *) ((Uint8 *)surface->pixels + y * surface->pitch + x * 4);
|
||||
sp = *p;
|
||||
UNPACK_PIXEL_32(sp, fmt, sr, sg, sb);
|
||||
UNPACK_PIXEL_32(pixel, fmt, r, g, b);
|
||||
|
||||
// TODO: We may need a special case for factor == -ADDITIVE_FACTOR_1 too,
|
||||
// but it is not important enough right now to care ;)
|
||||
if (factor == ADDITIVE_FACTOR_1)
|
||||
{ // no need to modulate the 'pixel', and modulation does not
|
||||
// work correctly with factor==255 anyway
|
||||
sr = clip_channel(sr + r);
|
||||
sg = clip_channel(sg + g);
|
||||
sb = clip_channel(sb + b);
|
||||
}
|
||||
else
|
||||
{
|
||||
sr = modulated_sum(sr, r, factor);
|
||||
sg = modulated_sum(sg, g, factor);
|
||||
sb = modulated_sum(sb, b, factor);
|
||||
}
|
||||
|
||||
*p = PACK_PIXEL_32(fmt, sr, sg, sb);
|
||||
}
|
||||
|
||||
static void
|
||||
renderpixel_alpha(SDL_Surface *surface, int x, int y, Uint32 pixel,
|
||||
int factor)
|
||||
{
|
||||
const SDL_PixelFormat *fmt = surface->format;
|
||||
Uint32 *p;
|
||||
Uint32 sp;
|
||||
Uint8 sr, sg, sb;
|
||||
int r, g, b;
|
||||
|
||||
if (factor == FULLY_OPAQUE_ALPHA)
|
||||
{ // alpha == 255 is equivalent to 'replace' and blending does not
|
||||
// work correctly anyway because we use >> 8 instead of / 255
|
||||
putpixel_32(surface, x, y, pixel);
|
||||
return;
|
||||
}
|
||||
|
||||
p = (Uint32 *) ((Uint8 *)surface->pixels + y * surface->pitch + x * 4);
|
||||
sp = *p;
|
||||
UNPACK_PIXEL_32(sp, fmt, sr, sg, sb);
|
||||
UNPACK_PIXEL_32(pixel, fmt, r, g, b);
|
||||
sr = alpha_blend(sr, r, factor);
|
||||
sg = alpha_blend(sg, g, factor);
|
||||
sb = alpha_blend(sb, b, factor);
|
||||
*p = PACK_PIXEL_32(fmt, sr, sg, sb);
|
||||
}
|
||||
|
||||
RenderPixelFn
|
||||
renderpixel_for(SDL_Surface *surface, RenderKind kind)
|
||||
{
|
||||
const SDL_PixelFormat *fmt = surface->format;
|
||||
|
||||
// The only supported rendering is to 32bpp surfaces
|
||||
if (fmt->BytesPerPixel != 4)
|
||||
return NULL;
|
||||
|
||||
// Rendering other than REPLACE is not supported on RGBA surfaces
|
||||
if (fmt->Amask != 0 && kind != renderReplace)
|
||||
return NULL;
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case renderReplace:
|
||||
return &renderpixel_replace;
|
||||
case renderAdditive:
|
||||
return &renderpixel_additive;
|
||||
case renderAlpha:
|
||||
return &renderpixel_alpha;
|
||||
}
|
||||
// should not ever get here
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Line drawing routine
|
||||
* Adapted from Paul Heckbert's implementation of Bresenham's algorithm,
|
||||
* 3 Sep 85; taken from Graphics Gems I */
|
||||
|
||||
void
|
||||
line_prim(int x1, int y1, int x2, int y2, Uint32 color, RenderPixelFn plot,
|
||||
int factor, SDL_Surface *dst)
|
||||
{
|
||||
int d, x, y, ax, ay, sx, sy, dx, dy;
|
||||
SDL_Rect clip_r;
|
||||
|
||||
SDL_GetClipRect (dst, &clip_r);
|
||||
if (!clip_line (&x1, &y1, &x2, &y2, &clip_r))
|
||||
return; // line is completely outside clipping rectangle
|
||||
|
||||
dx = x2-x1;
|
||||
ax = ((dx < 0) ? -dx : dx) << 1;
|
||||
sx = (dx < 0) ? -1 : 1;
|
||||
dy = y2-y1;
|
||||
ay = ((dy < 0) ? -dy : dy) << 1;
|
||||
sy = (dy < 0) ? -1 : 1;
|
||||
|
||||
x = x1;
|
||||
y = y1;
|
||||
if (ax > ay) {
|
||||
d = ay - (ax >> 1);
|
||||
for (;;) {
|
||||
(*plot)(dst, x, y, color, factor);
|
||||
if (x == x2)
|
||||
return;
|
||||
if (d >= 0) {
|
||||
y += sy;
|
||||
d -= ax;
|
||||
}
|
||||
x += sx;
|
||||
d += ay;
|
||||
}
|
||||
} else {
|
||||
d = ax - (ay >> 1);
|
||||
for (;;) {
|
||||
(*plot)(dst, x, y, color, factor);
|
||||
if (y == y2)
|
||||
return;
|
||||
if (d >= 0) {
|
||||
x += sx;
|
||||
d -= ay;
|
||||
}
|
||||
y += sy;
|
||||
d += ax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Clips line against rectangle using Cohen-Sutherland algorithm
|
||||
|
||||
enum {C_TOP = 0x1, C_BOTTOM = 0x2, C_RIGHT = 0x4, C_LEFT = 0x8};
|
||||
|
||||
static int
|
||||
compute_code (float x, float y, float xmin, float ymin, float xmax, float ymax)
|
||||
{
|
||||
int c = 0;
|
||||
if (y > ymax)
|
||||
c |= C_TOP;
|
||||
else if (y < ymin)
|
||||
c |= C_BOTTOM;
|
||||
if (x > xmax)
|
||||
c |= C_RIGHT;
|
||||
else if (x < xmin)
|
||||
c |= C_LEFT;
|
||||
return c;
|
||||
}
|
||||
|
||||
int
|
||||
clip_line (int *lx1, int *ly1, int *lx2, int *ly2, const SDL_Rect *r)
|
||||
{
|
||||
int C0, C1, C;
|
||||
float x, y, x0, y0, x1, y1, xmin, ymin, xmax, ymax;
|
||||
|
||||
x0 = (float)*lx1;
|
||||
y0 = (float)*ly1;
|
||||
x1 = (float)*lx2;
|
||||
y1 = (float)*ly2;
|
||||
|
||||
xmin = (float)r->x;
|
||||
ymin = (float)r->y;
|
||||
xmax = (float)r->x + r->w - 1;
|
||||
ymax = (float)r->y + r->h - 1;
|
||||
|
||||
C0 = compute_code (x0, y0, xmin, ymin, xmax, ymax);
|
||||
C1 = compute_code (x1, y1, xmin, ymin, xmax, ymax);
|
||||
|
||||
for (;;) {
|
||||
/* trivial accept: both ends in rectangle */
|
||||
if ((C0 | C1) == 0)
|
||||
{
|
||||
*lx1 = (int)x0;
|
||||
*ly1 = (int)y0;
|
||||
*lx2 = (int)x1;
|
||||
*ly2 = (int)y1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* trivial reject: both ends on the external side of the rectangle */
|
||||
if ((C0 & C1) != 0)
|
||||
return 0;
|
||||
|
||||
/* normal case: clip end outside rectangle */
|
||||
C = C0 ? C0 : C1;
|
||||
if (C & C_TOP)
|
||||
{
|
||||
x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0);
|
||||
y = ymax;
|
||||
}
|
||||
else if (C & C_BOTTOM)
|
||||
{
|
||||
x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0);
|
||||
y = ymin;
|
||||
}
|
||||
else if (C & C_RIGHT)
|
||||
{
|
||||
x = xmax;
|
||||
y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = xmin;
|
||||
y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0);
|
||||
}
|
||||
|
||||
/* set new end point and iterate */
|
||||
if (C == C0)
|
||||
{
|
||||
x0 = x; y0 = y;
|
||||
C0 = compute_code (x0, y0, xmin, ymin, xmax, ymax);
|
||||
}
|
||||
else
|
||||
{
|
||||
x1 = x; y1 = y;
|
||||
C1 = compute_code (x1, y1, xmin, ymin, xmax, ymax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fillrect_prim(SDL_Rect r, Uint32 color, RenderPixelFn plot, int factor,
|
||||
SDL_Surface *dst)
|
||||
{
|
||||
int x, y;
|
||||
int x1, y1;
|
||||
SDL_Rect clip_r;
|
||||
|
||||
SDL_GetClipRect (dst, &clip_r);
|
||||
if (!clip_rect (&r, &clip_r))
|
||||
return; // rect is completely outside clipping rectangle
|
||||
|
||||
// TODO: calculate destination pointer directly instead of
|
||||
// using the plot(x,y) version
|
||||
x1 = r.x + r.w;
|
||||
y1 = r.y + r.h;
|
||||
for (y = r.y; y < y1; ++y)
|
||||
{
|
||||
for (x = r.x; x < x1; ++x)
|
||||
plot(dst, x, y, color, factor);
|
||||
}
|
||||
}
|
||||
|
||||
// clip the rectangle against the clip rectangle
|
||||
int
|
||||
clip_rect(SDL_Rect *r, const SDL_Rect *clip_r)
|
||||
{
|
||||
// NOTE: the following clipping code is copied in part
|
||||
// from SDL-1.2.4 sources
|
||||
int dx, dy;
|
||||
int w = r->w;
|
||||
int h = r->h;
|
||||
// SDL_Rect.w and .h are unsigned, we need signed
|
||||
|
||||
dx = clip_r->x - r->x;
|
||||
if (dx > 0)
|
||||
{
|
||||
w -= dx;
|
||||
r->x += dx;
|
||||
}
|
||||
dx = r->x + w - clip_r->x - clip_r->w;
|
||||
if (dx > 0)
|
||||
w -= dx;
|
||||
|
||||
dy = clip_r->y - r->y;
|
||||
if (dy > 0)
|
||||
{
|
||||
h -= dy;
|
||||
r->y += dy;
|
||||
}
|
||||
dy = r->y + h - clip_r->y - clip_r->h;
|
||||
if (dy > 0)
|
||||
h -= dy;
|
||||
|
||||
if (w <= 0 || h <= 0)
|
||||
{
|
||||
r->w = 0;
|
||||
r->h = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r->w = w;
|
||||
r->h = h;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
blt_prim(SDL_Surface *src, SDL_Rect src_r, RenderPixelFn plot, int factor,
|
||||
SDL_Surface *dst, SDL_Rect dst_r)
|
||||
{
|
||||
SDL_PixelFormat *srcfmt = src->format;
|
||||
SDL_Palette *srcpal = srcfmt->palette;
|
||||
SDL_PixelFormat *dstfmt = dst->format;
|
||||
Uint32 mask = 0;
|
||||
Uint32 key = ~0;
|
||||
GetPixelFn getpix = getpixel_for(src);
|
||||
SDL_Rect clip_r;
|
||||
int x, y;
|
||||
|
||||
SDL_GetClipRect (dst, &clip_r);
|
||||
if (!clip_blt_rects (&src_r, &dst_r, &clip_r))
|
||||
return; // rect is completely outside clipping rectangle
|
||||
|
||||
if (src_r.x >= src->w || src_r.y >= src->h)
|
||||
return; // rect is completely outside source bounds
|
||||
|
||||
if (src_r.x + src_r.w > src->w)
|
||||
src_r.w = src->w - src_r.x;
|
||||
if (src_r.y + src_r.h > src->h)
|
||||
src_r.h = src->h - src_r.y;
|
||||
|
||||
// use colorkeys where appropriate
|
||||
if (srcfmt->Amask)
|
||||
{ // alpha transparency
|
||||
mask = srcfmt->Amask;
|
||||
key = 0;
|
||||
}
|
||||
else if (src->flags & SDL_SRCCOLORKEY)
|
||||
{ // colorkey transparency
|
||||
mask = ~srcfmt->Amask;
|
||||
key = srcfmt->colorkey & mask;
|
||||
}
|
||||
|
||||
// TODO: calculate the source and destination pointers directly
|
||||
// instead of using the plot(x,y) version
|
||||
for (y = 0; y < src_r.h; ++y)
|
||||
{
|
||||
for (x = 0; x < src_r.w; ++x)
|
||||
{
|
||||
Uint8 r, g, b, a;
|
||||
Uint32 p;
|
||||
|
||||
p = getpix(src, src_r.x + x, src_r.y + y);
|
||||
if (srcpal)
|
||||
{ // source is paletted, colorkey does not use mask
|
||||
if (p == key)
|
||||
continue; // transparent pixel
|
||||
}
|
||||
else
|
||||
{ // source is RGB(A), colorkey uses mask
|
||||
if ((p & mask) == key)
|
||||
continue; // transparent pixel
|
||||
}
|
||||
|
||||
// convert pixel format to destination
|
||||
SDL_GetRGBA(p, srcfmt, &r, &g, &b, &a);
|
||||
// TODO: handle source pixel alpha; plot() should probably
|
||||
// get a source alpha parameter
|
||||
p = SDL_MapRGBA(dstfmt, r, g, b, a);
|
||||
|
||||
plot(dst, dst_r.x + x, dst_r.y + y, p, factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clip the source and destination rectangles against the clip rectangle
|
||||
int
|
||||
clip_blt_rects(SDL_Rect *src_r, SDL_Rect *dst_r, const SDL_Rect *clip_r)
|
||||
{
|
||||
// NOTE: the following clipping code is copied in part
|
||||
// from SDL-1.2.4 sources
|
||||
int w, h;
|
||||
int dx, dy;
|
||||
|
||||
// clip the source rectangle to the source surface
|
||||
w = src_r->w;
|
||||
if (src_r->x < 0)
|
||||
{
|
||||
w += src_r->x;
|
||||
dst_r->x -= src_r->x;
|
||||
src_r->x = 0;
|
||||
}
|
||||
|
||||
h = src_r->h;
|
||||
if (src_r->y < 0)
|
||||
{
|
||||
h += src_r->y;
|
||||
dst_r->y -= src_r->y;
|
||||
src_r->y = 0;
|
||||
}
|
||||
|
||||
// clip the destination rectangle against the clip rectangle,
|
||||
// minding the source rectangle in the process
|
||||
dx = clip_r->x - dst_r->x;
|
||||
if (dx > 0)
|
||||
{
|
||||
w -= dx;
|
||||
dst_r->x += dx;
|
||||
src_r->x += dx;
|
||||
}
|
||||
dx = dst_r->x + w - clip_r->x - clip_r->w;
|
||||
if (dx > 0)
|
||||
w -= dx;
|
||||
|
||||
dy = clip_r->y - dst_r->y;
|
||||
if (dy > 0)
|
||||
{
|
||||
h -= dy;
|
||||
dst_r->y += dy;
|
||||
src_r->y += dy;
|
||||
}
|
||||
dy = dst_r->y + h - clip_r->y - clip_r->h;
|
||||
if (dy > 0)
|
||||
h -= dy;
|
||||
|
||||
if (w <= 0 || h <= 0)
|
||||
{
|
||||
src_r->w = 0;
|
||||
src_r->h = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
src_r->w = w;
|
||||
src_r->h = h;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef PRIMITIVES_H
|
||||
#define PRIMITIVES_H
|
||||
|
||||
/* Function types for the pixel functions */
|
||||
|
||||
typedef Uint32 (*GetPixelFn)(SDL_Surface *, int x, int y);
|
||||
// 'pixel' is in destination surface format
|
||||
typedef void (*PutPixelFn)(SDL_Surface *, int x, int y, Uint32 pixel);
|
||||
|
||||
GetPixelFn getpixel_for(SDL_Surface *surface);
|
||||
PutPixelFn putpixel_for(SDL_Surface *surface);
|
||||
|
||||
// This currently matches gfxlib.h:DrawKind for simplicity
|
||||
typedef enum
|
||||
{
|
||||
renderReplace = 0,
|
||||
renderAdditive,
|
||||
renderAlpha,
|
||||
} RenderKind;
|
||||
|
||||
#define FULLY_OPAQUE_ALPHA 255
|
||||
#define ADDITIVE_FACTOR_1 255
|
||||
|
||||
// 'pixel' is in destination surface format
|
||||
// See gfxlib.h:DrawKind for 'factor' spec
|
||||
typedef void (*RenderPixelFn)(SDL_Surface *, int x, int y, Uint32 pixel,
|
||||
int factor);
|
||||
|
||||
RenderPixelFn renderpixel_for(SDL_Surface *surface, RenderKind);
|
||||
|
||||
void line_prim(int x1, int y1, int x2, int y2, Uint32 color,
|
||||
RenderPixelFn plot, int factor, SDL_Surface *dst);
|
||||
void fillrect_prim(SDL_Rect r, Uint32 color,
|
||||
RenderPixelFn plot, int factor, SDL_Surface *dst);
|
||||
void blt_prim(SDL_Surface *src, SDL_Rect src_r,
|
||||
RenderPixelFn plot, int factor,
|
||||
SDL_Surface *dst, SDL_Rect dst_r);
|
||||
|
||||
int clip_line(int *lx1, int *ly1, int *lx2, int *ly2, const SDL_Rect *clip_r);
|
||||
int clip_rect(SDL_Rect *r, const SDL_Rect *clip_r);
|
||||
int clip_blt_rects(SDL_Rect *src_r, SDL_Rect *dst_r, const SDL_Rect *clip_r);
|
||||
|
||||
|
||||
#endif /* PRIMITIVES_H */
|
||||
@@ -1,484 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "pure.h"
|
||||
#include "libs/graphics/bbox.h"
|
||||
#include "scalers.h"
|
||||
#include "libs/log.h"
|
||||
|
||||
static SDL_Surface *fade_color_surface = NULL;
|
||||
static SDL_Surface *fade_temp = NULL;
|
||||
static SDL_Surface *scaled_display = NULL;
|
||||
|
||||
static TFB_ScaleFunc scaler = NULL;
|
||||
|
||||
static Uint32 fade_color;
|
||||
|
||||
static void TFB_Pure_Scaled_Preprocess (int force_full_redraw, int transition_amount, int fade_amount);
|
||||
static void TFB_Pure_Scaled_Postprocess (void);
|
||||
static void TFB_Pure_Unscaled_Preprocess (int force_full_redraw, int transition_amount, int fade_amount);
|
||||
static void TFB_Pure_Unscaled_Postprocess (void);
|
||||
static void TFB_Pure_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect);
|
||||
static void TFB_Pure_ColorLayer (Uint8 r, Uint8 g, Uint8 b, Uint8 a, SDL_Rect *rect);
|
||||
|
||||
static TFB_GRAPHICS_BACKEND pure_scaled_backend = {
|
||||
TFB_Pure_Scaled_Preprocess,
|
||||
TFB_Pure_Scaled_Postprocess,
|
||||
TFB_Pure_ScreenLayer,
|
||||
TFB_Pure_ColorLayer };
|
||||
|
||||
static TFB_GRAPHICS_BACKEND pure_unscaled_backend = {
|
||||
TFB_Pure_Unscaled_Preprocess,
|
||||
TFB_Pure_Unscaled_Postprocess,
|
||||
TFB_Pure_ScreenLayer,
|
||||
TFB_Pure_ColorLayer };
|
||||
|
||||
static SDL_Surface *
|
||||
Create_Screen (SDL_Surface *template, int w, int h)
|
||||
{
|
||||
SDL_Surface *newsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
|
||||
template->format->BitsPerPixel,
|
||||
template->format->Rmask, template->format->Gmask,
|
||||
template->format->Bmask, 0);
|
||||
if (newsurf == 0) {
|
||||
log_add (log_Error, "Couldn't create screen buffers: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
return newsurf;
|
||||
}
|
||||
|
||||
static int
|
||||
ReInit_Screen (SDL_Surface **screen, SDL_Surface *template, int w, int h)
|
||||
{
|
||||
if (*screen)
|
||||
SDL_FreeSurface (*screen);
|
||||
*screen = Create_Screen (template, w, h);
|
||||
|
||||
return *screen == 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
// We cannot rely on SDL_DisplayFormatAlpha() anymore. It can return
|
||||
// formats that we do not expect (SDL v1.2.14 on Mac OSX). Mac likes
|
||||
// ARGB surfaces, but SDL_DisplayFormatAlpha thinks that only RGBA are fast.
|
||||
// This is a generic replacement that gives what we want.
|
||||
static void
|
||||
CalcAlphaFormat (const SDL_PixelFormat* video, SDL_PixelFormat* ours)
|
||||
{
|
||||
int valid = 0;
|
||||
|
||||
// We use 32-bit surfaces internally
|
||||
ours->BitsPerPixel = 32;
|
||||
|
||||
// Try to get as close to the video format as possible
|
||||
if (video->BitsPerPixel == 15 || video->BitsPerPixel == 16)
|
||||
{ // At least match the channel order
|
||||
ours->Rshift = video->Rshift / 5 * 8;
|
||||
ours->Gshift = video->Gshift / 5 * 8;
|
||||
ours->Bshift = video->Bshift / 5 * 8;
|
||||
valid = 1;
|
||||
}
|
||||
else if (video->BitsPerPixel == 24 || video->BitsPerPixel == 32)
|
||||
{
|
||||
// We can only use channels aligned on byte boundary
|
||||
if (video->Rshift % 8 == 0 && video->Gshift % 8 == 0
|
||||
&& video->Bshift % 8 == 0)
|
||||
{ // Match RGB in video
|
||||
ours->Rshift = video->Rshift;
|
||||
ours->Gshift = video->Gshift;
|
||||
ours->Bshift = video->Bshift;
|
||||
valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid)
|
||||
{ // For alpha, use the unoccupied byte
|
||||
ours->Ashift = 48 - (ours->Rshift + ours->Gshift + ours->Bshift);
|
||||
// Set channels according to byte positions
|
||||
ours->Rmask = 0xff << ours->Rshift;
|
||||
ours->Gmask = 0xff << ours->Gshift;
|
||||
ours->Bmask = 0xff << ours->Bshift;
|
||||
ours->Amask = 0xff << ours->Ashift;
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback case. It does not matter what we set, but SDL likes
|
||||
// Alpha to be the highest.
|
||||
ours->Rmask = 0x000000ff;
|
||||
ours->Gmask = 0x0000ff00;
|
||||
ours->Bmask = 0x00ff0000;
|
||||
ours->Amask = 0xff000000;
|
||||
}
|
||||
|
||||
int
|
||||
TFB_Pure_ConfigureVideo (int driver, int flags, int width, int height, int togglefullscreen)
|
||||
{
|
||||
int i, videomode_flags;
|
||||
SDL_PixelFormat conv_fmt;
|
||||
int BPP = 32;
|
||||
|
||||
GraphicsDriver = driver;
|
||||
|
||||
// must use SDL_SWSURFACE, HWSURFACE doesn't work properly
|
||||
// with fades/scaling
|
||||
if (width == 320 && height == 240)
|
||||
{
|
||||
videomode_flags = SDL_SWSURFACE;
|
||||
ScreenWidthActual = 320;
|
||||
ScreenHeightActual = 240;
|
||||
graphics_backend = &pure_unscaled_backend;
|
||||
}
|
||||
else
|
||||
{
|
||||
videomode_flags = SDL_SWSURFACE;
|
||||
ScreenWidthActual = 640;
|
||||
ScreenHeightActual = 480;
|
||||
graphics_backend = &pure_scaled_backend;
|
||||
|
||||
if (width != 640 || height != 480)
|
||||
log_add (log_Error, "Screen resolution of %dx%d not supported "
|
||||
"under pure SDL, using 640x480", width, height);
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
videomode_flags = SDL_SWSURFACE;
|
||||
ScreenWidthActual = 320;
|
||||
ScreenHeightActual = 240;
|
||||
graphics_backend = &pure_unscaled_backend;
|
||||
BPP = 16;
|
||||
#endif
|
||||
|
||||
videomode_flags |= SDL_ANYFORMAT;
|
||||
if (flags & TFB_GFXFLAGS_FULLSCREEN)
|
||||
videomode_flags |= SDL_FULLSCREEN;
|
||||
|
||||
/* We'll ask for a 32bpp frame, but it doesn't really matter, because we've set
|
||||
SDL_ANYFORMAT */
|
||||
SDL_Video = SDL_SetVideoMode (ScreenWidthActual, ScreenHeightActual,
|
||||
BPP, videomode_flags);
|
||||
|
||||
if (SDL_Video == NULL)
|
||||
{
|
||||
log_add (log_Error, "Couldn't set %ix%i video mode: %s",
|
||||
ScreenWidthActual, ScreenHeightActual,
|
||||
SDL_GetError ());
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
const SDL_Surface *video = SDL_GetVideoSurface ();
|
||||
const SDL_PixelFormat* fmt = video->format;
|
||||
|
||||
ScreenColorDepth = fmt->BitsPerPixel;
|
||||
log_add (log_Info, "Set the resolution to: %ix%ix%i",
|
||||
video->w, video->h, ScreenColorDepth);
|
||||
log_add (log_Info, " Video: R %08x, G %08x, B %08x, A %08x",
|
||||
fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask);
|
||||
|
||||
if (togglefullscreen)
|
||||
{
|
||||
// NOTE: We cannot change the format_conv_surf now because we
|
||||
// have already loaded lots of graphics and changing it now
|
||||
// will only lead to chaos.
|
||||
// Just check if channel order has changed significantly
|
||||
CalcAlphaFormat (fmt, &conv_fmt);
|
||||
fmt = format_conv_surf->format;
|
||||
if (conv_fmt.Rmask != fmt->Rmask || conv_fmt.Bmask != fmt->Bmask)
|
||||
log_add (log_Warning, "Warning: pixel format has changed "
|
||||
"significantly. Rendering will be slow.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a 32bpp surface in a compatible format which will supply
|
||||
// the format information to all other surfaces used in the game
|
||||
if (format_conv_surf)
|
||||
{
|
||||
SDL_FreeSurface (format_conv_surf);
|
||||
format_conv_surf = NULL;
|
||||
}
|
||||
CalcAlphaFormat (SDL_Video->format, &conv_fmt);
|
||||
format_conv_surf = SDL_CreateRGBSurface (SDL_SWSURFACE, 0, 0,
|
||||
conv_fmt.BitsPerPixel, conv_fmt.Rmask, conv_fmt.Gmask,
|
||||
conv_fmt.Bmask, conv_fmt.Amask);
|
||||
if (!format_conv_surf)
|
||||
{
|
||||
log_add (log_Error, "Couldn't create format_conv_surf: %s",
|
||||
SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
const SDL_PixelFormat* fmt = format_conv_surf->format;
|
||||
log_add (log_Info, " Internal: R %08x, G %08x, B %08x, A %08x",
|
||||
fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask);
|
||||
}
|
||||
|
||||
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
|
||||
{
|
||||
if (0 != ReInit_Screen (&SDL_Screens[i], format_conv_surf,
|
||||
ScreenWidth, ScreenHeight))
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_Screen = SDL_Screens[0];
|
||||
TransitionScreen = SDL_Screens[2];
|
||||
|
||||
if (0 != ReInit_Screen (&fade_color_surface, format_conv_surf,
|
||||
ScreenWidth, ScreenHeight))
|
||||
return -1;
|
||||
fade_color = SDL_MapRGB (fade_color_surface->format, 0, 0, 0);
|
||||
SDL_FillRect (fade_color_surface, NULL, fade_color);
|
||||
|
||||
if (0 != ReInit_Screen (&fade_temp, format_conv_surf,
|
||||
ScreenWidth, ScreenHeight))
|
||||
return -1;
|
||||
|
||||
if (ScreenWidthActual > ScreenWidth || ScreenHeightActual > ScreenHeight)
|
||||
{
|
||||
if (0 != ReInit_Screen (&scaled_display, format_conv_surf,
|
||||
ScreenWidthActual, ScreenHeightActual))
|
||||
return -1;
|
||||
|
||||
scaler = Scale_PrepPlatform (flags, SDL_Screen->format);
|
||||
}
|
||||
else
|
||||
{ // no need to scale
|
||||
scaler = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
TFB_Pure_InitGraphics (int driver, int flags, int width, int height)
|
||||
{
|
||||
char VideoName[256];
|
||||
|
||||
log_add (log_Info, "Initializing Pure-SDL graphics.");
|
||||
|
||||
SDL_VideoDriverName (VideoName, sizeof (VideoName));
|
||||
log_add (log_Info, "SDL driver used: %s", VideoName);
|
||||
// Set the environment variable SDL_VIDEODRIVER to override
|
||||
// For Linux: x11 (default), dga, fbcon, directfb, svgalib,
|
||||
// ggi, aalib
|
||||
// For Windows: directx (default), windib
|
||||
|
||||
log_add (log_Info, "SDL initialized.");
|
||||
log_add (log_Info, "Initializing Screen.");
|
||||
|
||||
ScreenWidth = 320;
|
||||
ScreenHeight = 240;
|
||||
|
||||
if (TFB_Pure_ConfigureVideo (driver, flags, width, height, 0))
|
||||
{
|
||||
log_add (log_Fatal, "Could not initialize video: "
|
||||
"no fallback at start of program!");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Initialize scalers (let them precompute whatever)
|
||||
Scale_Init ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ScanLines (SDL_Surface *dst, SDL_Rect *r)
|
||||
{
|
||||
const int rw = r->w * 2;
|
||||
const int rh = r->h * 2;
|
||||
SDL_PixelFormat *fmt = dst->format;
|
||||
const int pitch = dst->pitch;
|
||||
const int len = pitch / fmt->BytesPerPixel;
|
||||
int ddst;
|
||||
Uint32 *p = (Uint32 *) dst->pixels;
|
||||
int x, y;
|
||||
|
||||
p += len * (r->y * 2) + (r->x * 2);
|
||||
ddst = len + len - rw;
|
||||
|
||||
for (y = rh; y; y -= 2, p += ddst)
|
||||
{
|
||||
for (x = rw; x; --x, ++p)
|
||||
{
|
||||
// we ignore the lower bits as the difference
|
||||
// of 1 in 255 is negligible
|
||||
*p = ((*p >> 1) & 0x7f7f7f7f) + ((*p >> 2) & 0x3f3f3f3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_Surface *backbuffer = NULL, *scalebuffer = NULL;
|
||||
static SDL_Rect updated;
|
||||
|
||||
static void
|
||||
TFB_Pure_Scaled_Preprocess (int force_full_redraw, int transition_amount, int fade_amount)
|
||||
{
|
||||
if (force_full_redraw != TFB_REDRAW_NO)
|
||||
{
|
||||
updated.x = updated.y = 0;
|
||||
updated.w = ScreenWidth;
|
||||
updated.h = ScreenHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
updated.x = TFB_BBox.region.corner.x;
|
||||
updated.y = TFB_BBox.region.corner.y;
|
||||
updated.w = TFB_BBox.region.extent.width;
|
||||
updated.h = TFB_BBox.region.extent.height;
|
||||
}
|
||||
|
||||
if (transition_amount == 255 && fade_amount == 255)
|
||||
backbuffer = SDL_Screens[TFB_SCREEN_MAIN];
|
||||
else
|
||||
backbuffer = fade_temp;
|
||||
|
||||
// we can scale directly onto SDL_Video if video is compatible
|
||||
if (SDL_Video->format->BitsPerPixel == SDL_Screen->format->BitsPerPixel
|
||||
&& SDL_Video->format->Rmask == SDL_Screen->format->Rmask
|
||||
&& SDL_Video->format->Bmask == SDL_Screen->format->Bmask)
|
||||
scalebuffer = SDL_Video;
|
||||
else
|
||||
scalebuffer = scaled_display;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
TFB_Pure_Unscaled_Preprocess (int force_full_redraw, int transition_amount, int fade_amount)
|
||||
{
|
||||
if (force_full_redraw != TFB_REDRAW_NO)
|
||||
{
|
||||
updated.x = updated.y = 0;
|
||||
updated.w = ScreenWidth;
|
||||
updated.h = ScreenHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
updated.x = TFB_BBox.region.corner.x;
|
||||
updated.y = TFB_BBox.region.corner.y;
|
||||
updated.w = TFB_BBox.region.extent.width;
|
||||
updated.h = TFB_BBox.region.extent.height;
|
||||
}
|
||||
|
||||
backbuffer = SDL_Video;
|
||||
(void)transition_amount;
|
||||
(void)fade_amount;
|
||||
}
|
||||
|
||||
static void
|
||||
TFB_Pure_Scaled_Postprocess (void)
|
||||
{
|
||||
SDL_LockSurface (scalebuffer);
|
||||
SDL_LockSurface (backbuffer);
|
||||
|
||||
if (scaler)
|
||||
scaler (backbuffer, scalebuffer, &updated);
|
||||
|
||||
if (GfxFlags & TFB_GFXFLAGS_SCANLINES)
|
||||
ScanLines (scalebuffer, &updated);
|
||||
|
||||
SDL_UnlockSurface (backbuffer);
|
||||
SDL_UnlockSurface (scalebuffer);
|
||||
|
||||
updated.x *= 2;
|
||||
updated.y *= 2;
|
||||
updated.w *= 2;
|
||||
updated.h *= 2;
|
||||
if (scalebuffer != SDL_Video)
|
||||
SDL_BlitSurface (scalebuffer, &updated, SDL_Video, &updated);
|
||||
|
||||
SDL_UpdateRects (SDL_Video, 1, &updated);
|
||||
}
|
||||
|
||||
static void
|
||||
TFB_Pure_Unscaled_Postprocess (void)
|
||||
{
|
||||
SDL_UpdateRect (SDL_Video, updated.x, updated.y,
|
||||
updated.w, updated.h);
|
||||
}
|
||||
|
||||
static void
|
||||
TFB_Pure_ScreenLayer (SCREEN screen, Uint8 a, SDL_Rect *rect)
|
||||
{
|
||||
if (SDL_Screens[screen] == backbuffer)
|
||||
return;
|
||||
SDL_SetAlpha (SDL_Screens[screen], SDL_SRCALPHA, a);
|
||||
SDL_BlitSurface (SDL_Screens[screen], rect, backbuffer, rect);
|
||||
}
|
||||
|
||||
static void
|
||||
TFB_Pure_ColorLayer (Uint8 r, Uint8 g, Uint8 b, Uint8 a, SDL_Rect *rect)
|
||||
{
|
||||
Uint32 col = SDL_MapRGB (fade_color_surface->format, r, g, b);
|
||||
if (col != fade_color)
|
||||
{
|
||||
fade_color = col;
|
||||
SDL_FillRect (fade_color_surface, NULL, fade_color);
|
||||
}
|
||||
SDL_SetAlpha (fade_color_surface, SDL_SRCALPHA, a);
|
||||
SDL_BlitSurface (fade_color_surface, rect, backbuffer, rect);
|
||||
}
|
||||
|
||||
void
|
||||
Scale_PerfTest (void)
|
||||
{
|
||||
TimeCount TimeStart, TimeIn;
|
||||
TimeCount Now = 0;
|
||||
SDL_Rect updated = {0, 0, ScreenWidth, ScreenHeight};
|
||||
int i;
|
||||
|
||||
if (!scaler)
|
||||
{
|
||||
log_add (log_Error, "No scaler configured! "
|
||||
"Run with larger resolution, please");
|
||||
return;
|
||||
}
|
||||
if (!scaled_display)
|
||||
{
|
||||
log_add (log_Error, "Run scaler performance tests "
|
||||
"in Pure mode, please");
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_LockSurface (SDL_Screen);
|
||||
SDL_LockSurface (scaled_display);
|
||||
|
||||
TimeStart = TimeIn = SDL_GetTicks ();
|
||||
|
||||
for (i = 1; i < 1001; ++i) // run for 1000 frames
|
||||
{
|
||||
scaler (SDL_Screen, scaled_display, &updated);
|
||||
|
||||
if (GfxFlags & TFB_GFXFLAGS_SCANLINES)
|
||||
ScanLines (scaled_display, &updated);
|
||||
|
||||
if (i % 100 == 0)
|
||||
{
|
||||
Now = SDL_GetTicks ();
|
||||
log_add (log_Debug, "%03d(%04u) ", 100*1000 / (Now - TimeIn),
|
||||
Now - TimeIn);
|
||||
TimeIn = Now;
|
||||
}
|
||||
}
|
||||
|
||||
log_add (log_Debug, "Full frames scaled: %d; over %u ms; %d fps\n",
|
||||
(i - 1), Now - TimeStart, i * 1000 / (Now - TimeStart));
|
||||
|
||||
SDL_UnlockSurface (scaled_display);
|
||||
SDL_UnlockSurface (SDL_Screen);
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef PURE_H
|
||||
#define PURE_H
|
||||
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
|
||||
int TFB_Pure_InitGraphics (int driver, int flags, int width, int height);
|
||||
int TFB_Pure_ConfigureVideo (int driver, int flags, int width, int height, int togglefullscreen);
|
||||
void Scale_PerfTest (void);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
|
||||
rotozoom.h - rotozoomer for 32bit or 8bit surfaces
|
||||
LGPL (c) A. Schiffler
|
||||
|
||||
Note by sc2 developers:
|
||||
Taken from SDL_gfx library and modified, original code can be downloaded
|
||||
from http://www.ferzkopp.net/Software/SDL_gfx-2.0/
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ROTOZOOM_H
|
||||
#define ROTOZOOM_H
|
||||
|
||||
#include <math.h>
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592654
|
||||
#endif
|
||||
|
||||
#include "port.h"
|
||||
#include SDL_INCLUDE(SDL.h)
|
||||
|
||||
|
||||
/* ---- Defines */
|
||||
|
||||
#define SMOOTHING_OFF 0
|
||||
#define SMOOTHING_ON 1
|
||||
|
||||
/* ---- Structures */
|
||||
|
||||
typedef struct tColorRGBA {
|
||||
Uint8 r;
|
||||
Uint8 g;
|
||||
Uint8 b;
|
||||
Uint8 a;
|
||||
} tColorRGBA;
|
||||
|
||||
typedef struct tColorY {
|
||||
Uint8 y;
|
||||
} tColorY;
|
||||
|
||||
|
||||
/* ---- Prototypes */
|
||||
|
||||
/*
|
||||
zoomSurfaceRGBA()
|
||||
|
||||
Zoom the src surface into dst. The zoom amount is determined
|
||||
by the dimensions of src and dst
|
||||
|
||||
*/
|
||||
int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int smooth);
|
||||
|
||||
/*
|
||||
|
||||
rotozoomSurface()
|
||||
|
||||
Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
|
||||
'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
|
||||
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
|
||||
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
|
||||
|
||||
*/
|
||||
|
||||
SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom,
|
||||
int smooth);
|
||||
|
||||
int rotateSurface(SDL_Surface * src, SDL_Surface * dst, double angle,
|
||||
int smooth);
|
||||
|
||||
/* Returns the size of the target surface for a rotozoomSurface() call */
|
||||
|
||||
void rotozoomSurfaceSize(int width, int height, double angle, double zoom,
|
||||
int *dstwidth, int *dstheight);
|
||||
|
||||
/*
|
||||
|
||||
zoomSurface()
|
||||
|
||||
Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
|
||||
'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
|
||||
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
|
||||
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
|
||||
|
||||
*/
|
||||
|
||||
SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy,
|
||||
int smooth);
|
||||
|
||||
/* Returns the size of the target surface for a zoomSurface() call */
|
||||
|
||||
void zoomSurfaceSize(int width, int height, double zoomx, double zoomy,
|
||||
int *dstwidth, int *dstheight);
|
||||
|
||||
#endif
|
||||
@@ -1,433 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alex Volkov (codepro@usa.net)
|
||||
*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// Scalers Internals
|
||||
|
||||
#ifndef SCALEINT_H_
|
||||
#define SCALEINT_H_
|
||||
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
#include "types.h"
|
||||
|
||||
|
||||
// Plain C names
|
||||
#define SCALE_(name) Scale ## _ ## name
|
||||
|
||||
// These are defaults
|
||||
#define SCALE_GETPIX(p) ( *(Uint32 *)(p) )
|
||||
#define SCALE_SETPIX(p, c) ( *(Uint32 *)(p) = (c) )
|
||||
|
||||
// Plain C defaults
|
||||
#define SCALE_CMPRGB(p1, p2) \
|
||||
SCALE_(GetRGBDelta) (fmt, p1, p2)
|
||||
|
||||
#define SCALE_TOYUV(p) \
|
||||
SCALE_(RGBtoYUV) (fmt, p)
|
||||
|
||||
#define SCALE_CMPYUV(p1, p2, toler) \
|
||||
SCALE_(CmpYUV) (fmt, p1, p2, toler)
|
||||
|
||||
#define SCALE_DIFFYUV(p1, p2) \
|
||||
SCALE_(DiffYUV) (p1, p2)
|
||||
#define SCALE_DIFFYUV_TY 0x40
|
||||
#define SCALE_DIFFYUV_TU 0x12
|
||||
#define SCALE_DIFFYUV_TV 0x0c
|
||||
|
||||
#define SCALE_GETY(p) \
|
||||
SCALE_(GetPixY) (fmt, p)
|
||||
|
||||
#define SCALE_BILINEAR_BLEND4(r0, r1, dst, dlen) \
|
||||
SCALE_(Blend_bilinear) (r0, r1, dst, dlen)
|
||||
|
||||
#define NO_PREFETCH 0
|
||||
#define INTEL_PREFETCH 1
|
||||
#define AMD_PREFETCH 2
|
||||
|
||||
typedef enum
|
||||
{
|
||||
YUV_XFORM_R = 0,
|
||||
YUV_XFORM_G = 1,
|
||||
YUV_XFORM_B = 2,
|
||||
YUV_XFORM_Y = 0,
|
||||
YUV_XFORM_U = 1,
|
||||
YUV_XFORM_V = 2
|
||||
} RGB_YUV_INDEX;
|
||||
|
||||
extern const int YUV_matrix[3][3];
|
||||
|
||||
// pre-computed transformations for 8 bits per channel
|
||||
extern int RGB_to_YUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 256];
|
||||
extern sint16 dRGB_to_dYUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 512];
|
||||
|
||||
typedef Uint32 YUV_VECTOR;
|
||||
// pre-computed transformations for RGB555
|
||||
extern YUV_VECTOR RGB15_to_YUV[0x8000];
|
||||
|
||||
|
||||
// Platform+Scaler function lookups
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
int flag;
|
||||
TFB_ScaleFunc func;
|
||||
} Scale_FuncDef_t;
|
||||
|
||||
|
||||
// expands the given rectangle in all directions by 'expansion'
|
||||
// guarded by 'limits'
|
||||
extern void Scale_ExpandRect (SDL_Rect* rect, int expansion,
|
||||
const SDL_Rect* limits);
|
||||
|
||||
|
||||
// Standard plain C versions of support functions
|
||||
|
||||
// Initialize various platform-specific features
|
||||
static inline void
|
||||
SCALE_(PlatInit) (void)
|
||||
{
|
||||
}
|
||||
|
||||
// Finish with various platform-specific features
|
||||
static inline void
|
||||
SCALE_(PlatDone) (void)
|
||||
{
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline void
|
||||
SCALE_(Prefetch) (const void* p)
|
||||
{
|
||||
/* no-op in pure C */
|
||||
(void)p;
|
||||
}
|
||||
#else
|
||||
# define Scale_Prefetch(p)
|
||||
#endif
|
||||
|
||||
// compute the RGB distance squared between 2 pixels
|
||||
// Plain C version
|
||||
static inline int
|
||||
SCALE_(GetRGBDelta) (const SDL_PixelFormat* fmt, Uint32 pix1, Uint32 pix2)
|
||||
{
|
||||
int c;
|
||||
int delta;
|
||||
|
||||
c = ((pix1 >> fmt->Rshift) & 0xff) - ((pix2 >> fmt->Rshift) & 0xff);
|
||||
delta = c * c;
|
||||
|
||||
c = ((pix1 >> fmt->Gshift) & 0xff) - ((pix2 >> fmt->Gshift) & 0xff);
|
||||
delta += c * c;
|
||||
|
||||
c = ((pix1 >> fmt->Bshift) & 0xff) - ((pix2 >> fmt->Bshift) & 0xff);
|
||||
delta += c * c;
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
// retrieve the Y (intensity) component of pixel's YUV
|
||||
// Plain C version
|
||||
static inline int
|
||||
SCALE_(GetPixY) (const SDL_PixelFormat* fmt, Uint32 pix)
|
||||
{
|
||||
Uint32 r, g, b;
|
||||
|
||||
r = (pix >> fmt->Rshift) & 0xff;
|
||||
g = (pix >> fmt->Gshift) & 0xff;
|
||||
b = (pix >> fmt->Bshift) & 0xff;
|
||||
|
||||
return RGB_to_YUV [YUV_XFORM_R][YUV_XFORM_Y][r]
|
||||
+ RGB_to_YUV [YUV_XFORM_G][YUV_XFORM_Y][g]
|
||||
+ RGB_to_YUV [YUV_XFORM_B][YUV_XFORM_Y][b];
|
||||
}
|
||||
|
||||
static inline YUV_VECTOR
|
||||
SCALE_(RGBtoYUV) (const SDL_PixelFormat* fmt, Uint32 pix)
|
||||
{
|
||||
return RGB15_to_YUV[
|
||||
(((pix >> (fmt->Rshift + 3)) & 0x1f) << 10) |
|
||||
(((pix >> (fmt->Gshift + 3)) & 0x1f) << 5) |
|
||||
(((pix >> (fmt->Bshift + 3)) & 0x1f) )
|
||||
];
|
||||
}
|
||||
|
||||
// compare 2 pixels with respect to their YUV representations
|
||||
// tolerance set by toler arg
|
||||
// returns true: close; false: distant (-gt toler)
|
||||
// Plain C version
|
||||
static inline bool
|
||||
SCALE_(CmpYUV) (const SDL_PixelFormat* fmt, Uint32 pix1, Uint32 pix2, int toler)
|
||||
#if 1
|
||||
{
|
||||
int dr, dg, db;
|
||||
int delta;
|
||||
|
||||
dr = ((pix1 >> fmt->Rshift) & 0xff) - ((pix2 >> fmt->Rshift) & 0xff) + 255;
|
||||
dg = ((pix1 >> fmt->Gshift) & 0xff) - ((pix2 >> fmt->Gshift) & 0xff) + 255;
|
||||
db = ((pix1 >> fmt->Bshift) & 0xff) - ((pix2 >> fmt->Bshift) & 0xff) + 255;
|
||||
|
||||
// compute Y delta
|
||||
delta = abs (dRGB_to_dYUV [YUV_XFORM_R][YUV_XFORM_Y][dr]
|
||||
+ dRGB_to_dYUV [YUV_XFORM_G][YUV_XFORM_Y][dg]
|
||||
+ dRGB_to_dYUV [YUV_XFORM_B][YUV_XFORM_Y][db]);
|
||||
if (delta > toler)
|
||||
return false;
|
||||
|
||||
// compute U delta
|
||||
delta += abs (dRGB_to_dYUV [YUV_XFORM_R][YUV_XFORM_U][dr]
|
||||
+ dRGB_to_dYUV [YUV_XFORM_G][YUV_XFORM_U][dg]
|
||||
+ dRGB_to_dYUV [YUV_XFORM_B][YUV_XFORM_U][db]);
|
||||
if (delta > toler)
|
||||
return false;
|
||||
|
||||
// compute V delta
|
||||
delta += abs (dRGB_to_dYUV [YUV_XFORM_R][YUV_XFORM_V][dr]
|
||||
+ dRGB_to_dYUV [YUV_XFORM_G][YUV_XFORM_V][dg]
|
||||
+ dRGB_to_dYUV [YUV_XFORM_B][YUV_XFORM_V][db]);
|
||||
|
||||
return delta <= toler;
|
||||
}
|
||||
#else
|
||||
{
|
||||
int delta;
|
||||
Uint32 yuv1, yuv2;
|
||||
|
||||
yuv1 = RGB15_to_YUV[
|
||||
(((pix1 >> (fmt->Rshift + 3)) & 0x1f) << 10) |
|
||||
(((pix1 >> (fmt->Gshift + 3)) & 0x1f) << 5) |
|
||||
(((pix1 >> (fmt->Bshift + 3)) & 0x1f) )
|
||||
];
|
||||
|
||||
yuv2 = RGB15_to_YUV[
|
||||
(((pix2 >> (fmt->Rshift + 3)) & 0x1f) << 10) |
|
||||
(((pix2 >> (fmt->Gshift + 3)) & 0x1f) << 5) |
|
||||
(((pix2 >> (fmt->Bshift + 3)) & 0x1f) )
|
||||
];
|
||||
|
||||
// compute Y delta
|
||||
delta = abs ((yuv1 & 0xff0000) - (yuv2 & 0xff0000)) >> 16;
|
||||
if (delta > toler)
|
||||
return false;
|
||||
|
||||
// compute U delta
|
||||
delta += abs ((yuv1 & 0x00ff00) - (yuv2 & 0x00ff00)) >> 8;
|
||||
if (delta > toler)
|
||||
return false;
|
||||
|
||||
// compute V delta
|
||||
delta += abs ((yuv1 & 0x0000ff) - (yuv2 & 0x0000ff));
|
||||
|
||||
return delta <= toler;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check if 2 pixels are different with respect to their
|
||||
// YUV representations
|
||||
// returns 0: close; ~0: distant
|
||||
static inline int
|
||||
SCALE_(DiffYUV) (Uint32 yuv1, Uint32 yuv2)
|
||||
{
|
||||
// non-branching version -- assumes 2's complement integers
|
||||
// delta math only needs 25 bits and we have 32 available;
|
||||
// only interested in the sign bits after subtraction
|
||||
sint32 delta, ret;
|
||||
|
||||
if (yuv1 == yuv2)
|
||||
return 0;
|
||||
|
||||
// compute Y delta
|
||||
delta = abs ((yuv1 & 0xff0000) - (yuv2 & 0xff0000));
|
||||
ret = (SCALE_DIFFYUV_TY << 16) - delta; // save sign bit
|
||||
|
||||
// compute U delta
|
||||
delta = abs ((yuv1 & 0x00ff00) - (yuv2 & 0x00ff00));
|
||||
ret |= (SCALE_DIFFYUV_TU << 8) - delta; // save sign bit
|
||||
|
||||
// compute V delta
|
||||
delta = abs ((yuv1 & 0x0000ff) - (yuv2 & 0x0000ff));
|
||||
ret |= SCALE_DIFFYUV_TV - delta; // save sign bit
|
||||
|
||||
return (ret >> 31);
|
||||
}
|
||||
|
||||
// blends two pixels with 1:1 ratio
|
||||
static inline Uint32
|
||||
SCALE_(Blend_11) (Uint32 pix1, Uint32 pix2)
|
||||
{
|
||||
/* (pix1 + pix2) >> 1 */
|
||||
return
|
||||
/* lower bits can be safely ignored - the error is minimal
|
||||
expression that calcs them is left for posterity
|
||||
(pix1 & pix2 & low_mask) +
|
||||
*/
|
||||
((pix1 & 0xfefefefe) >> 1) + ((pix2 & 0xfefefefe) >> 1);
|
||||
}
|
||||
|
||||
// blends four pixels with 1:1:1:1 ratio
|
||||
static inline Uint32
|
||||
SCALE_(Blend_1111) (Uint32 pix1, Uint32 pix2,
|
||||
Uint32 pix3, Uint32 pix4)
|
||||
{
|
||||
/* (pix1 + pix2 + pix3 + pix4) >> 2 */
|
||||
return
|
||||
/* lower bits can be safely ignored - the error is minimal
|
||||
expression that calcs them is left for posterity
|
||||
((((pix1 & low_mask) + (pix2 & low_mask) +
|
||||
(pix3 & low_mask) + (pix4 & low_mask)
|
||||
) >> 2) & low_mask) +
|
||||
*/
|
||||
((pix1 & 0xfcfcfcfc) >> 2) + ((pix2 & 0xfcfcfcfc) >> 2) +
|
||||
((pix3 & 0xfcfcfcfc) >> 2) + ((pix4 & 0xfcfcfcfc) >> 2);
|
||||
}
|
||||
|
||||
// blends pixels with 3:1 ratio
|
||||
static inline Uint32
|
||||
Scale_Blend_31 (Uint32 pix1, Uint32 pix2)
|
||||
{
|
||||
/* (pix1 * 3 + pix2) / 4 */
|
||||
/* lower bits can be safely ignored - the error is minimal */
|
||||
return ((pix1 & 0xfefefefe) >> 1) + ((pix1 & 0xfcfcfcfc) >> 2) +
|
||||
((pix2 & 0xfcfcfcfc) >> 2);
|
||||
}
|
||||
|
||||
// blends pixels with 2:1:1 ratio
|
||||
static inline Uint32
|
||||
Scale_Blend_211 (Uint32 pix1, Uint32 pix2, Uint32 pix3)
|
||||
{
|
||||
/* (pix1 * 2 + pix2 + pix3) / 4 */
|
||||
/* lower bits can be safely ignored - the error is minimal */
|
||||
return ((pix1 & 0xfefefefe) >> 1) +
|
||||
((pix2 & 0xfcfcfcfc) >> 2) +
|
||||
((pix3 & 0xfcfcfcfc) >> 2);
|
||||
}
|
||||
|
||||
// blends pixels with 5:2:1 ratio
|
||||
static inline Uint32
|
||||
Scale_Blend_521 (Uint32 pix1, Uint32 pix2, Uint32 pix3)
|
||||
{
|
||||
/* (pix1 * 5 + pix2 * 2 + pix3) / 8 */
|
||||
/* lower bits can be safely ignored - the error is minimal */
|
||||
return ((pix1 & 0xfefefefe) >> 1) + ((pix1 & 0xf8f8f8f8) >> 3) +
|
||||
((pix2 & 0xfcfcfcfc) >> 2) +
|
||||
((pix3 & 0xf8f8f8f8) >> 3) +
|
||||
0x02020202 /* half-error */;
|
||||
}
|
||||
|
||||
// blends pixels with 6:1:1 ratio
|
||||
static inline Uint32
|
||||
Scale_Blend_611 (Uint32 pix1, Uint32 pix2, Uint32 pix3)
|
||||
{
|
||||
/* (pix1 * 6 + pix2 + pix3) / 8 */
|
||||
/* lower bits can be safely ignored - the error is minimal */
|
||||
return ((pix1 & 0xfefefefe) >> 1) + ((pix1 & 0xfcfcfcfc) >> 2) +
|
||||
((pix2 & 0xf8f8f8f8) >> 3) +
|
||||
((pix3 & 0xf8f8f8f8) >> 3) +
|
||||
0x02020202 /* half-error */;
|
||||
}
|
||||
|
||||
// blends pixels with 2:3:3 ratio
|
||||
static inline Uint32
|
||||
Scale_Blend_233 (Uint32 pix1, Uint32 pix2, Uint32 pix3)
|
||||
{
|
||||
/* (pix1 * 2 + pix2 * 3 + pix3 * 3) / 8 */
|
||||
/* lower bits can be safely ignored - the error is minimal */
|
||||
return ((pix1 & 0xfcfcfcfc) >> 2) +
|
||||
((pix2 & 0xfcfcfcfc) >> 2) + ((pix2 & 0xf8f8f8f8) >> 3) +
|
||||
((pix3 & 0xfcfcfcfc) >> 2) + ((pix3 & 0xf8f8f8f8) >> 3) +
|
||||
0x02020202 /* half-error */;
|
||||
}
|
||||
|
||||
// blends pixels with 14:1:1 ratio
|
||||
static inline Uint32
|
||||
Scale_Blend_e11 (Uint32 pix1, Uint32 pix2, Uint32 pix3)
|
||||
{
|
||||
/* (pix1 * 14 + pix2 + pix3) >> 4 */
|
||||
/* lower bits can be safely ignored - the error is minimal */
|
||||
return ((pix1 & 0xfefefefe) >> 1) + ((pix1 & 0xfcfcfcfc) >> 2) +
|
||||
((pix1 & 0xf8f8f8f8) >> 3) +
|
||||
((pix2 & 0xf0f0f0f0) >> 4) +
|
||||
((pix3 & 0xf0f0f0f0) >> 4) +
|
||||
0x03030303 /* half-error */;
|
||||
}
|
||||
|
||||
// Halfs the pixel's intensity
|
||||
static inline Uint32
|
||||
SCALE_(HalfPixel) (Uint32 pix)
|
||||
{
|
||||
return ((pix & 0xfefefefe) >> 1);
|
||||
}
|
||||
|
||||
|
||||
// Bilinear weighted blend of four pixels
|
||||
// Function produces 4 blended pixels and writes them
|
||||
// out to the surface (in 2x2 matrix)
|
||||
// Pixels are computed using expanded weight matrix like so:
|
||||
// ('sp' - source pixel, 'dp' - destination pixel)
|
||||
// dp[0] = (9*sp[0] + 3*sp[1] + 3*sp[2] + 1*sp[3]) / 16
|
||||
// dp[1] = (3*sp[0] + 9*sp[1] + 1*sp[2] + 3*sp[3]) / 16
|
||||
// dp[2] = (3*sp[0] + 1*sp[1] + 9*sp[2] + 3*sp[3]) / 16
|
||||
// dp[3] = (1*sp[0] + 3*sp[1] + 3*sp[2] + 9*sp[3]) / 16
|
||||
static inline void
|
||||
SCALE_(Blend_bilinear) (const Uint32* row0, const Uint32* row1,
|
||||
Uint32* dst_p, Uint32 dlen)
|
||||
{
|
||||
// We loose some lower bits here and try to compensate for
|
||||
// that by adding half-error values.
|
||||
// In general, the error is minimal (+-7)
|
||||
// The >>4 reduction is achieved gradually
|
||||
# define BL_PACKED_HALF(p) \
|
||||
(((p) & 0xfefefefe) >> 1)
|
||||
# define BL_SUM(p1, p2) \
|
||||
(BL_PACKED_HALF(p1) + BL_PACKED_HALF(p2))
|
||||
# define BL_HALF_ERR 0x01010101
|
||||
# define BL_SUM_WERR(p1, p2) \
|
||||
(BL_PACKED_HALF(p1) + BL_PACKED_HALF(p2) + BL_HALF_ERR)
|
||||
|
||||
Uint32 sum1111, sum1331, sum3113;
|
||||
|
||||
// cache p[0] + 3*(p[1] + p[2]) + p[3] in sum1331
|
||||
// cache p[1] + 3*(p[0] + p[3]) + p[2] in sum3113
|
||||
sum1331 = BL_SUM (row0[1], row1[0]);
|
||||
sum3113 = BL_SUM (row0[0], row1[1]);
|
||||
|
||||
// cache p[0] + p[1] + p[2] + p[3] in sum1111
|
||||
sum1111 = BL_SUM_WERR (sum1331, sum3113);
|
||||
|
||||
sum1331 = BL_SUM_WERR (sum1331, sum1111);
|
||||
sum1331 = BL_PACKED_HALF (sum1331);
|
||||
sum3113 = BL_SUM_WERR (sum3113, sum1111);
|
||||
sum3113 = BL_PACKED_HALF (sum3113);
|
||||
|
||||
// pixel 0 math -- (9*p[0] + 3*(p[1] + p[2]) + p[3]) / 16
|
||||
dst_p[0] = BL_PACKED_HALF (row0[0]) + sum1331;
|
||||
|
||||
// pixel 1 math -- (9*p[1] + 3*(p[0] + p[3]) + p[2]) / 16
|
||||
dst_p[1] = BL_PACKED_HALF (row0[1]) + sum3113;
|
||||
|
||||
// pixel 2 math -- (9*p[2] + 3*(p[0] + p[3]) + p[1]) / 16
|
||||
dst_p[dlen] = BL_PACKED_HALF (row1[0]) + sum3113;
|
||||
|
||||
// pixel 3 math -- (9*p[3] + 3*(p[1] + p[2]) + p[0]) / 16
|
||||
dst_p[dlen + 1] = BL_PACKED_HALF (row1[1]) + sum1331;
|
||||
|
||||
# undef BL_PACKED_HALF
|
||||
# undef BL_SUM
|
||||
# undef BL_HALF_ERR
|
||||
# undef BL_SUM_WERR
|
||||
}
|
||||
|
||||
#endif /* SCALEINT_H_ */
|
||||
@@ -1,793 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alex Volkov (codepro@usa.net)
|
||||
*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef SCALEMMX_H_
|
||||
#define SCALEMMX_H_
|
||||
|
||||
#if !defined(SCALE_)
|
||||
# error Please define SCALE_(name) before including scalemmx.h
|
||||
#endif
|
||||
|
||||
#if !defined(MSVC_ASM) && !defined(GCC_ASM)
|
||||
# error Please define target assembler (MSVC_ASM, GCC_ASM) before including scalemmx.h
|
||||
#endif
|
||||
|
||||
// MMX defaults (no Format param)
|
||||
#undef SCALE_CMPRGB
|
||||
#define SCALE_CMPRGB(p1, p2) \
|
||||
SCALE_(GetRGBDelta) (p1, p2)
|
||||
|
||||
#undef SCALE_TOYUV
|
||||
#define SCALE_TOYUV(p) \
|
||||
SCALE_(RGBtoYUV) (p)
|
||||
|
||||
#undef SCALE_CMPYUV
|
||||
#define SCALE_CMPYUV(p1, p2, toler) \
|
||||
SCALE_(CmpYUV) (p1, p2, toler)
|
||||
|
||||
#undef SCALE_GETY
|
||||
#define SCALE_GETY(p) \
|
||||
SCALE_(GetPixY) (p)
|
||||
|
||||
// MMX transformation multipliers
|
||||
extern Uint64 mmx_888to555_mult;
|
||||
extern Uint64 mmx_Y_mult;
|
||||
extern Uint64 mmx_U_mult;
|
||||
extern Uint64 mmx_V_mult;
|
||||
extern Uint64 mmx_YUV_threshold;
|
||||
|
||||
#define USE_YUV_LOOKUP
|
||||
|
||||
#if defined(MSVC_ASM)
|
||||
// MSVC inline assembly versions
|
||||
|
||||
#if defined(USE_MOVNTQ)
|
||||
# define MOVNTQ(addr, val) movntq [addr], val
|
||||
#else
|
||||
# define MOVNTQ(addr, val) movq [addr], val
|
||||
#endif
|
||||
|
||||
#if USE_PREFETCH == INTEL_PREFETCH
|
||||
// using Intel SSE non-temporal prefetch
|
||||
# define PREFETCH(addr) prefetchnta [addr]
|
||||
# define HAVE_PREFETCH
|
||||
#elif USE_PREFETCH == AMD_PREFETCH
|
||||
// using AMD 3DNOW! prefetch
|
||||
# define PREFETCH(addr) prefetch [addr]
|
||||
# define HAVE_PREFETCH
|
||||
#else
|
||||
// no prefetch -- too bad for poor MMX-only souls
|
||||
# define PREFETCH(addr)
|
||||
# undef HAVE_PREFETCH
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||
# pragma warning( disable : 4799 )
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
SCALE_(PlatInit) (void)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
// mm0 will be kept == 0 throughout
|
||||
// 0 is needed for bytes->words unpack instructions
|
||||
pxor mm0, mm0
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
SCALE_(PlatDone) (void)
|
||||
{
|
||||
// finish with MMX registers and yield them to FPU
|
||||
__asm
|
||||
{
|
||||
emms
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_PREFETCH)
|
||||
static inline void
|
||||
SCALE_(Prefetch) (const void* p)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, p
|
||||
PREFETCH (eax)
|
||||
}
|
||||
}
|
||||
|
||||
#else /* Not HAVE_PREFETCH */
|
||||
|
||||
static inline void
|
||||
SCALE_(Prefetch) (const void* p)
|
||||
{
|
||||
(void)p; // silence compiler
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
#endif /* HAVE_PREFETCH */
|
||||
|
||||
// compute the RGB distance squared between 2 pixels
|
||||
static inline int
|
||||
SCALE_(GetRGBDelta) (Uint32 pix1, Uint32 pix2)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
// load pixels
|
||||
movd mm1, pix1
|
||||
punpcklbw mm1, mm0
|
||||
movd mm2, pix2
|
||||
punpcklbw mm2, mm0
|
||||
// get the difference between RGBA components
|
||||
psubw mm1, mm2
|
||||
// squared and sumed
|
||||
pmaddwd mm1, mm1
|
||||
// finish suming the squares
|
||||
movq mm2, mm1
|
||||
punpckhdq mm2, mm0
|
||||
paddd mm1, mm2
|
||||
// store result
|
||||
movd eax, mm1
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve the Y (intensity) component of pixel's YUV
|
||||
static inline int
|
||||
SCALE_(GetPixY) (Uint32 pix)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
// load pixel
|
||||
movd mm1, pix
|
||||
punpcklbw mm1, mm0
|
||||
// process
|
||||
pmaddwd mm1, mmx_Y_mult // RGB * Yvec
|
||||
movq mm2, mm1 // finish suming
|
||||
punpckhdq mm2, mm0 // ditto
|
||||
paddd mm1, mm2 // ditto
|
||||
// store result
|
||||
movd eax, mm1
|
||||
shr eax, 14
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_YUV_LOOKUP
|
||||
|
||||
// convert pixel RGB vector into YUV representation vector
|
||||
static inline YUV_VECTOR
|
||||
SCALE_(RGBtoYUV) (Uint32 pix)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
// convert RGB888 to 555
|
||||
movd mm1, pix
|
||||
punpcklbw mm1, mm0
|
||||
psrlw mm1, 3 // 8->5 bit
|
||||
pmaddwd mm1, mmx_888to555_mult // shuffle into the right channel order
|
||||
movq mm2, mm1 // finish shuffling
|
||||
punpckhdq mm2, mm0 // ditto
|
||||
por mm1, mm2 // ditto
|
||||
|
||||
// lookup the YUV vector
|
||||
movd eax, mm1
|
||||
mov eax, [RGB15_to_YUV + eax * 4]
|
||||
}
|
||||
}
|
||||
|
||||
// compare 2 pixels with respect to their YUV representations
|
||||
// tolerance set by toler arg
|
||||
// returns true: close; false: distant (-gt toler)
|
||||
static inline bool
|
||||
SCALE_(CmpYUV) (Uint32 pix1, Uint32 pix2, int toler)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
// convert RGB888 to 555
|
||||
movd mm1, pix1
|
||||
punpcklbw mm1, mm0
|
||||
psrlw mm1, 3 // 8->5 bit
|
||||
movd mm3, pix2
|
||||
punpcklbw mm3, mm0
|
||||
psrlw mm3, 3 // 8->5 bit
|
||||
pmaddwd mm1, mmx_888to555_mult // shuffle into the right channel order
|
||||
movq mm2, mm1 // finish shuffling
|
||||
pmaddwd mm3, mmx_888to555_mult // shuffle into the right channel order
|
||||
movq mm4, mm3 // finish shuffling
|
||||
punpckhdq mm2, mm0 // ditto
|
||||
por mm1, mm2 // ditto
|
||||
punpckhdq mm4, mm0 // ditto
|
||||
por mm3, mm4 // ditto
|
||||
|
||||
// lookup the YUV vector
|
||||
movd eax, mm1
|
||||
movd edx, mm3
|
||||
movd mm1, [RGB15_to_YUV + eax * 4]
|
||||
movq mm4, mm1
|
||||
movd mm2, [RGB15_to_YUV + edx * 4]
|
||||
|
||||
// get abs difference between YUV components
|
||||
#ifdef USE_PSADBW
|
||||
// we can use PSADBW and save us some grief
|
||||
psadbw mm1, mm2
|
||||
movd edx, mm1
|
||||
#else
|
||||
// no PSADBW -- have to do it the hard way
|
||||
psubusb mm1, mm2
|
||||
psubusb mm2, mm4
|
||||
por mm1, mm2
|
||||
|
||||
// sum the differences
|
||||
// XXX: technically, this produces a MAX diff of 510
|
||||
// but we do not need anything bigger, currently
|
||||
movq mm2, mm1
|
||||
psrlq mm2, 8
|
||||
paddusb mm1, mm2
|
||||
psrlq mm2, 8
|
||||
paddusb mm1, mm2
|
||||
movd edx, mm1
|
||||
and edx, 0xff
|
||||
#endif /* USE_PSADBW */
|
||||
xor eax, eax
|
||||
shl edx, 1
|
||||
cmp edx, toler
|
||||
// store result
|
||||
setle al
|
||||
}
|
||||
}
|
||||
|
||||
#else /* Not USE_YUV_LOOKUP */
|
||||
|
||||
// convert pixel RGB vector into YUV representation vector
|
||||
static inline YUV_VECTOR
|
||||
SCALE_(RGBtoYUV) (Uint32 pix)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
movd mm1, pix
|
||||
punpcklbw mm1, mm0
|
||||
|
||||
movq mm2, mm1
|
||||
|
||||
// Y vector multiply
|
||||
pmaddwd mm1, mmx_Y_mult
|
||||
movq mm4, mm1
|
||||
punpckhdq mm4, mm0
|
||||
punpckldq mm1, mm0 // clear out the high dword
|
||||
paddd mm1, mm4
|
||||
psrad mm1, 15
|
||||
|
||||
movq mm3, mm2
|
||||
|
||||
// U vector multiply
|
||||
pmaddwd mm2, mmx_U_mult
|
||||
psrad mm2, 10
|
||||
|
||||
// V vector multiply
|
||||
pmaddwd mm3, mmx_V_mult
|
||||
psrad mm3, 10
|
||||
|
||||
// load (1|1|1|1) into mm4
|
||||
pcmpeqw mm4, mm4
|
||||
psrlw mm4, 15
|
||||
|
||||
packssdw mm3, mm2
|
||||
pmaddwd mm3, mm4
|
||||
psrad mm3, 5
|
||||
|
||||
// load (64|64) into mm4
|
||||
punpcklwd mm4, mm0
|
||||
pslld mm4, 6
|
||||
paddd mm3, mm4
|
||||
|
||||
packssdw mm3, mm1
|
||||
packuswb mm3, mm0
|
||||
|
||||
movd eax, mm3
|
||||
}
|
||||
}
|
||||
|
||||
// compare 2 pixels with respect to their YUV representations
|
||||
// tolerance set by toler arg
|
||||
// returns true: close; false: distant (-gt toler)
|
||||
static inline bool
|
||||
SCALE_(CmpYUV) (Uint32 pix1, Uint32 pix2, int toler)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
movd mm1, pix1
|
||||
punpcklbw mm1, mm0
|
||||
movd mm2, pix2
|
||||
punpcklbw mm2, mm0
|
||||
|
||||
psubw mm1, mm2
|
||||
movq mm2, mm1
|
||||
|
||||
// Y vector multiply
|
||||
pmaddwd mm1, mmx_Y_mult
|
||||
movq mm4, mm1
|
||||
punpckhdq mm4, mm0
|
||||
paddd mm1, mm4
|
||||
// abs()
|
||||
movq mm4, mm1
|
||||
psrad mm4, 31
|
||||
pxor mm4, mm1
|
||||
psubd mm1, mm4
|
||||
|
||||
movq mm3, mm2
|
||||
|
||||
// U vector multiply
|
||||
pmaddwd mm2, mmx_U_mult
|
||||
movq mm4, mm2
|
||||
punpckhdq mm4, mm0
|
||||
paddd mm2, mm4
|
||||
// abs()
|
||||
movq mm4, mm2
|
||||
psrad mm4, 31
|
||||
pxor mm4, mm2
|
||||
psubd mm2, mm4
|
||||
|
||||
paddd mm1, mm2
|
||||
|
||||
// V vector multiply
|
||||
pmaddwd mm3, mmx_V_mult
|
||||
movq mm4, mm3
|
||||
punpckhdq mm3, mm0
|
||||
paddd mm3, mm4
|
||||
// abs()
|
||||
movq mm4, mm3
|
||||
psrad mm4, 31
|
||||
pxor mm4, mm3
|
||||
psubd mm3, mm4
|
||||
|
||||
paddd mm1, mm3
|
||||
|
||||
movd edx, mm1
|
||||
xor eax, eax
|
||||
shr edx, 14
|
||||
cmp edx, toler
|
||||
// store result
|
||||
setle al
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_YUV_LOOKUP */
|
||||
|
||||
// Check if 2 pixels are different with respect to their
|
||||
// YUV representations
|
||||
// returns 0: close; ~0: distant
|
||||
static inline int
|
||||
SCALE_(DiffYUV) (Uint32 yuv1, Uint32 yuv2)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
// load YUV pixels
|
||||
movd mm1, yuv1
|
||||
movq mm4, mm1
|
||||
movd mm2, yuv2
|
||||
// abs difference between channels
|
||||
psubusb mm1, mm2
|
||||
psubusb mm2, mm4
|
||||
por mm1, mm2
|
||||
// compare to threshold
|
||||
psubusb mm1, mmx_YUV_threshold
|
||||
|
||||
movd edx, mm1
|
||||
// transform eax to 0 or ~0
|
||||
xor eax, eax
|
||||
or edx, edx
|
||||
setz al
|
||||
dec eax
|
||||
}
|
||||
}
|
||||
|
||||
// bilinear weighted blend of four pixels
|
||||
// MSVC asm version
|
||||
static inline void
|
||||
SCALE_(Blend_bilinear) (const Uint32* row0, const Uint32* row1,
|
||||
Uint32* dst_p, Uint32 dlen)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
// EL0: setup vars
|
||||
mov ebx, row0 // EL0
|
||||
|
||||
// EL0: load pixels
|
||||
movq mm1, [ebx] // EL0
|
||||
movq mm2, mm1 // EL0: p[1] -> mm2
|
||||
PREFETCH (ebx + 0x80)
|
||||
punpckhbw mm2, mm0 // EL0: p[1] -> mm2
|
||||
mov ebx, row1
|
||||
punpcklbw mm1, mm0 // EL0: p[0] -> mm1
|
||||
movq mm3, [ebx]
|
||||
movq mm4, mm3 // EL0: p[3] -> mm4
|
||||
movq mm6, mm2 // EL1.1: p[1] -> mm6
|
||||
PREFETCH (ebx + 0x80)
|
||||
punpcklbw mm3, mm0 // EL0: p[2] -> mm3
|
||||
movq mm5, mm1 // EL1.1: p[0] -> mm5
|
||||
punpckhbw mm4, mm0 // EL0: p[3] -> mm4
|
||||
|
||||
mov edi, dst_p // EL0
|
||||
|
||||
// EL1: cache p[0] + 3*(p[1] + p[2]) + p[3] in mm6
|
||||
paddw mm6, mm3 // EL1.2: p[1] + p[2] -> mm6
|
||||
// EL1: cache p[0] + p[1] + p[2] + p[3] in mm7
|
||||
movq mm7, mm6 // EL1.3: p[1] + p[2] -> mm7
|
||||
// EL1: cache p[1] + 3*(p[0] + p[3]) + p[2] in mm5
|
||||
paddw mm5, mm4 // EL1.2: p[0] + p[3] -> mm5
|
||||
psllw mm6, 1 // EL1.4: 2*(p[1] + p[2]) -> mm6
|
||||
paddw mm7, mm5 // EL1.4: sum(p[]) -> mm7
|
||||
psllw mm5, 1 // EL1.5: 2*(p[0] + p[3]) -> mm5
|
||||
paddw mm6, mm7 // EL1.5: p[0] + 3*(p[1] + p[2]) + p[3] -> mm6
|
||||
paddw mm5, mm7 // EL1.6: p[1] + 3*(p[0] + p[3]) + p[2] -> mm5
|
||||
|
||||
// EL2: pixel 0 math -- (9*p[0] + 3*(p[1] + p[2]) + p[3]) / 16
|
||||
psllw mm1, 3 // EL2.1: 8*p[0] -> mm1
|
||||
paddw mm1, mm6 // EL2.2: 9*p[0] + 3*(p[1] + p[2]) + p[3] -> mm1
|
||||
psrlw mm1, 4 // EL2.3: sum[0]/16 -> mm1
|
||||
|
||||
mov edx, dlen // EL0
|
||||
|
||||
// EL3: pixel 1 math -- (9*p[1] + 3*(p[0] + p[3]) + p[2]) / 16
|
||||
psllw mm2, 3 // EL3.1: 8*p[1] -> mm2
|
||||
paddw mm2, mm5 // EL3.2: 9*p[1] + 3*(p[0] + p[3]) + p[2] -> mm2
|
||||
psrlw mm2, 4 // EL3.3: sum[1]/16 -> mm5
|
||||
|
||||
// EL2/3: store pixels 0 & 1
|
||||
packuswb mm1, mm2 // EL2/3: pack into bytes
|
||||
MOVNTQ (edi, mm1) // EL2/3: store 2 pixels
|
||||
|
||||
// EL4: pixel 2 math -- (9*p[2] + 3*(p[0] + p[3]) + p[1]) / 16
|
||||
psllw mm3, 3 // EL4.1: 8*p[2] -> mm3
|
||||
paddw mm3, mm5 // EL4.2: 9*p[2] + 3*(p[0] + p[3]) + p[1] -> mm3
|
||||
psrlw mm3, 4 // EL4.3: sum[2]/16 -> mm3
|
||||
|
||||
// EL5: pixel 3 math -- (9*p[3] + 3*(p[1] + p[2]) + p[0]) / 16
|
||||
psllw mm4, 3 // EL5.1: 8*p[3] -> mm4
|
||||
paddw mm4, mm6 // EL5.2: 9*p[3] + 3*(p[1] + p[2]) + p[0] -> mm4
|
||||
psrlw mm4, 4 // EL5.3: sum[3]/16 -> mm4
|
||||
|
||||
// EL4/5: store pixels 2 & 3
|
||||
packuswb mm3, mm4 // EL4/5: pack into bytes
|
||||
MOVNTQ (edi + edx*4, mm3) // EL4/5: store 2 pixels
|
||||
}
|
||||
}
|
||||
// End MSVC_ASM
|
||||
|
||||
#elif defined(GCC_ASM)
|
||||
// GCC inline assembly versions
|
||||
|
||||
#if defined(USE_MOVNTQ)
|
||||
# define MOVNTQ(val, addr) "movntq " #val "," #addr
|
||||
#else
|
||||
# define MOVNTQ(val, addr) "movq " #val "," #addr
|
||||
#endif
|
||||
|
||||
#if USE_PREFETCH == INTEL_PREFETCH
|
||||
// using Intel SSE non-temporal prefetch
|
||||
# define PREFETCH(addr) "prefetchnta " #addr
|
||||
#elif USE_PREFETCH == AMD_PREFETCH
|
||||
// using AMD 3DNOW! prefetch
|
||||
# define PREFETCH(addr) "prefetch " #addr
|
||||
#else
|
||||
// no prefetch -- too bad for poor MMX-only souls
|
||||
# define PREFETCH(addr)
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__)
|
||||
# define A_REG "rax"
|
||||
# define D_REG "rdx"
|
||||
# define CLR_UPPER32(r) "xor " "%%" r "," "%%" r
|
||||
#else
|
||||
# define A_REG "eax"
|
||||
# define D_REG "edx"
|
||||
# define CLR_UPPER32(r)
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
SCALE_(PlatInit) (void)
|
||||
{
|
||||
__asm__ (
|
||||
// mm0 will be kept == 0 throughout
|
||||
// 0 is needed for bytes->words unpack instructions
|
||||
"pxor %%mm0, %%mm0 \n\t"
|
||||
|
||||
: /* nothing */
|
||||
: /* nothing */
|
||||
);
|
||||
}
|
||||
|
||||
static inline void
|
||||
SCALE_(PlatDone) (void)
|
||||
{
|
||||
// finish with MMX registers and yield them to FPU
|
||||
__asm__ (
|
||||
"emms \n\t"
|
||||
: /* nothing */ : /* nothing */
|
||||
);
|
||||
}
|
||||
|
||||
static inline void
|
||||
SCALE_(Prefetch) (const void* p)
|
||||
{
|
||||
__asm__ __volatile__ ("" PREFETCH (%0) : /*nothing*/ : "m" (p) );
|
||||
}
|
||||
|
||||
// compute the RGB distance squared between 2 pixels
|
||||
static inline int
|
||||
SCALE_(GetRGBDelta) (Uint32 pix1, Uint32 pix2)
|
||||
{
|
||||
int res;
|
||||
|
||||
__asm__ (
|
||||
// load pixels
|
||||
"movd %1, %%mm1 \n\t"
|
||||
"punpcklbw %%mm0, %%mm1 \n\t"
|
||||
"movd %2, %%mm2 \n\t"
|
||||
"punpcklbw %%mm0, %%mm2 \n\t"
|
||||
// get the difference between RGBA components
|
||||
"psubw %%mm2, %%mm1 \n\t"
|
||||
// squared and sumed
|
||||
"pmaddwd %%mm1, %%mm1 \n\t"
|
||||
// finish suming the squares
|
||||
"movq %%mm1, %%mm2 \n\t"
|
||||
"punpckhdq %%mm0, %%mm2 \n\t"
|
||||
"paddd %%mm2, %%mm1 \n\t"
|
||||
// store result
|
||||
"movd %%mm1, %0 \n\t"
|
||||
|
||||
: /*0*/"=rm" (res)
|
||||
: /*1*/"rm" (pix1), /*2*/"rm" (pix2)
|
||||
);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// retrieve the Y (intensity) component of pixel's YUV
|
||||
static inline int
|
||||
SCALE_(GetPixY) (Uint32 pix)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ (
|
||||
// load pixel
|
||||
"movd %1, %%mm1 \n\t"
|
||||
"punpcklbw %%mm0, %%mm1 \n\t"
|
||||
// process
|
||||
"pmaddwd %2, %%mm1 \n\t" // R,G,B * Yvec
|
||||
"movq %%mm1, %%mm2 \n\t" // finish suming
|
||||
"punpckhdq %%mm0, %%mm2 \n\t" // ditto
|
||||
"paddd %%mm2, %%mm1 \n\t" // ditto
|
||||
// store index
|
||||
"movd %%mm1, %0 \n\t"
|
||||
|
||||
: /*0*/"=r" (ret)
|
||||
: /*1*/"rm" (pix), /*2*/"m" (mmx_Y_mult)
|
||||
);
|
||||
return ret >> 14;
|
||||
}
|
||||
|
||||
#ifdef USE_YUV_LOOKUP
|
||||
|
||||
// convert pixel RGB vector into YUV representation vector
|
||||
static inline YUV_VECTOR
|
||||
SCALE_(RGBtoYUV) (Uint32 pix)
|
||||
{
|
||||
int i;
|
||||
|
||||
__asm__ (
|
||||
// convert RGB888 to 555
|
||||
"movd %1, %%mm1 \n\t"
|
||||
"punpcklbw %%mm0, %%mm1 \n\t"
|
||||
"psrlw $3, %%mm1 \n\t" // 8->5 bit
|
||||
"pmaddwd %2, %%mm1 \n\t" // shuffle into the right channel order
|
||||
"movq %%mm1, %%mm2 \n\t" // finish shuffling
|
||||
"punpckhdq %%mm0, %%mm2 \n\t" // ditto
|
||||
"por %%mm2, %%mm1 \n\t" // ditto
|
||||
"movd %%mm1, %0 \n\t"
|
||||
|
||||
: /*0*/"=rm" (i)
|
||||
: /*1*/"rm" (pix), /*2*/"m" (mmx_888to555_mult)
|
||||
);
|
||||
return RGB15_to_YUV[i];
|
||||
}
|
||||
|
||||
// compare 2 pixels with respect to their YUV representations
|
||||
// tolerance set by toler arg
|
||||
// returns true: close; false: distant (-gt toler)
|
||||
static inline bool
|
||||
SCALE_(CmpYUV) (Uint32 pix1, Uint32 pix2, int toler)
|
||||
{
|
||||
int delta;
|
||||
|
||||
__asm__ (
|
||||
"movd %1, %%mm1 \n\t"
|
||||
"movd %2, %%mm3 \n\t"
|
||||
|
||||
// convert RGB888 to 555
|
||||
// this is somewhat parallelized
|
||||
"punpcklbw %%mm0, %%mm1 \n\t"
|
||||
CLR_UPPER32 (A_REG) "\n\t"
|
||||
"psrlw $3, %%mm1 \n\t" // 8->5 bit
|
||||
"punpcklbw %%mm0, %%mm3 \n\t"
|
||||
"psrlw $3, %%mm3 \n\t" // 8->5 bit
|
||||
"pmaddwd %4, %%mm1 \n\t" // shuffle into the right channel order
|
||||
"movq %%mm1, %%mm2 \n\t" // finish shuffling
|
||||
"pmaddwd %4, %%mm3 \n\t" // shuffle into the right channel order
|
||||
CLR_UPPER32 (D_REG) "\n\t"
|
||||
"movq %%mm3, %%mm4 \n\t" // finish shuffling
|
||||
"punpckhdq %%mm0, %%mm2 \n\t" // ditto
|
||||
"por %%mm2, %%mm1 \n\t" // ditto
|
||||
"punpckhdq %%mm0, %%mm4 \n\t" // ditto
|
||||
"por %%mm4, %%mm3 \n\t" // ditto
|
||||
|
||||
// lookup the YUV vector
|
||||
"movd %%mm1, %%eax \n\t"
|
||||
"movd %%mm3, %%edx \n\t"
|
||||
"movd (%3, %%" A_REG ", 4), %%mm1 \n\t"
|
||||
"movq %%mm1, %%mm4 \n\t"
|
||||
"movd (%3, %%" D_REG ", 4), %%mm2 \n\t"
|
||||
|
||||
// get abs difference between YUV components
|
||||
#ifdef USE_PSADBW
|
||||
// we can use PSADBW and save us some grief
|
||||
"psadbw %%mm2, %%mm1 \n\t"
|
||||
"movd %%mm1, %0 \n\t"
|
||||
#else
|
||||
// no PSADBW -- have to do it the hard way
|
||||
"psubusb %%mm2, %%mm1 \n\t"
|
||||
"psubusb %%mm4, %%mm2 \n\t"
|
||||
"por %%mm2, %%mm1 \n\t"
|
||||
|
||||
// sum the differences
|
||||
// technically, this produces a MAX diff of 510
|
||||
// but we do not need anything bigger, currently
|
||||
"movq %%mm1, %%mm2 \n\t"
|
||||
"psrlq $8, %%mm2 \n\t"
|
||||
"paddusb %%mm2, %%mm1 \n\t"
|
||||
"psrlq $8, %%mm2 \n\t"
|
||||
"paddusb %%mm2, %%mm1 \n\t"
|
||||
// store intermediate delta
|
||||
"movd %%mm1, %0 \n\t"
|
||||
"andl $0xff, %0 \n\t"
|
||||
#endif /* USE_PSADBW */
|
||||
: /*0*/"=rm" (delta)
|
||||
: /*1*/"rm" (pix1), /*2*/"rm" (pix2),
|
||||
/*3*/ "r" (RGB15_to_YUV),
|
||||
/*4*/"m" (mmx_888to555_mult)
|
||||
: "%" A_REG, "%" D_REG, "cc"
|
||||
);
|
||||
|
||||
return (delta << 1) <= toler;
|
||||
}
|
||||
|
||||
#endif /* USE_YUV_LOOKUP */
|
||||
|
||||
// Check if 2 pixels are different with respect to their
|
||||
// YUV representations
|
||||
// returns 0: close; ~0: distant
|
||||
static inline int
|
||||
SCALE_(DiffYUV) (Uint32 yuv1, Uint32 yuv2)
|
||||
{
|
||||
sint32 ret;
|
||||
|
||||
__asm__ (
|
||||
// load YUV pixels
|
||||
"movd %1, %%mm1 \n\t"
|
||||
"movq %%mm1, %%mm4 \n\t"
|
||||
"movd %2, %%mm2 \n\t"
|
||||
// abs difference between channels
|
||||
"psubusb %%mm2, %%mm1 \n\t"
|
||||
"psubusb %%mm4, %%mm2 \n\t"
|
||||
CLR_UPPER32(D_REG) "\n\t"
|
||||
"por %%mm2, %%mm1 \n\t"
|
||||
// compare to threshold
|
||||
"psubusb %3, %%mm1 \n\t"
|
||||
|
||||
"movd %%mm1, %%edx \n\t"
|
||||
// transform eax to 0 or ~0
|
||||
"xor %%" A_REG ", %%" A_REG "\n\t"
|
||||
"or %%" D_REG ", %%" D_REG "\n\t"
|
||||
"setz %%al \n\t"
|
||||
"dec %%" A_REG " \n\t"
|
||||
|
||||
: /*0*/"=a" (ret)
|
||||
: /*1*/"rm" (yuv1), /*2*/"rm" (yuv2),
|
||||
/*3*/"m" (mmx_YUV_threshold)
|
||||
: "%" D_REG, "cc"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Bilinear weighted blend of four pixels
|
||||
// Function produces 4 blended pixels (in 2x2 matrix) and writes them
|
||||
// out to the surface
|
||||
// Last version
|
||||
static inline void
|
||||
SCALE_(Blend_bilinear) (const Uint32* row0, const Uint32* row1,
|
||||
Uint32* dst_p, Uint32 dlen)
|
||||
{
|
||||
__asm__ (
|
||||
// EL0: load pixels
|
||||
"movq %0, %%mm1 \n\t" // EL0
|
||||
"movq %%mm1, %%mm2 \n\t" // EL0: p[1] -> mm2
|
||||
PREFETCH (0x80%0) "\n\t"
|
||||
"punpckhbw %%mm0, %%mm2 \n\t" // EL0: p[1] -> mm2
|
||||
"punpcklbw %%mm0, %%mm1 \n\t" // EL0: p[0] -> mm1
|
||||
"movq %1, %%mm3 \n\t"
|
||||
"movq %%mm3, %%mm4 \n\t" // EL0: p[3] -> mm4
|
||||
"movq %%mm2, %%mm6 \n\t" // EL1.1: p[1] -> mm6
|
||||
PREFETCH (0x80%1) "\n\t"
|
||||
"punpcklbw %%mm0, %%mm3 \n\t" // EL0: p[2] -> mm3
|
||||
"movq %%mm1, %%mm5 \n\t" // EL1.1: p[0] -> mm5
|
||||
"punpckhbw %%mm0, %%mm4 \n\t" // EL0: p[3] -> mm4
|
||||
|
||||
// EL1: cache p[0] + 3*(p[1] + p[2]) + p[3] in mm6
|
||||
"paddw %%mm3, %%mm6 \n\t" // EL1.2: p[1] + p[2] -> mm6
|
||||
// EL1: cache p[0] + p[1] + p[2] + p[3] in mm7
|
||||
"movq %%mm6, %%mm7 \n\t" // EL1.3: p[1] + p[2] -> mm7
|
||||
// EL1: cache p[1] + 3*(p[0] + p[3]) + p[2] in mm5
|
||||
"paddw %%mm4, %%mm5 \n\t" // EL1.2: p[0] + p[3] -> mm5
|
||||
"psllw $1, %%mm6 \n\t" // EL1.4: 2*(p[1] + p[2]) -> mm6
|
||||
"paddw %%mm5, %%mm7 \n\t" // EL1.4: sum(p[]) -> mm7
|
||||
"psllw $1, %%mm5 \n\t" // EL1.5: 2*(p[0] + p[3]) -> mm5
|
||||
"paddw %%mm7, %%mm6 \n\t" // EL1.5: p[0] + 3*(p[1] + p[2]) + p[3] -> mm6
|
||||
"paddw %%mm7, %%mm5 \n\t" // EL1.6: p[1] + 3*(p[0] + p[3]) + p[2] -> mm5
|
||||
|
||||
// EL2: pixel 0 math -- (9*p[0] + 3*(p[1] + p[2]) + p[3]) / 16
|
||||
"psllw $3, %%mm1 \n\t" // EL2.1: 8*p[0] -> mm1
|
||||
"paddw %%mm6, %%mm1 \n\t" // EL2.2: 9*p[0] + 3*(p[1] + p[2]) + p[3] -> mm1
|
||||
"psrlw $4, %%mm1 \n\t" // EL2.3: sum[0]/16 -> mm1
|
||||
|
||||
// EL3: pixel 1 math -- (9*p[1] + 3*(p[0] + p[3]) + p[2]) / 16
|
||||
"psllw $3, %%mm2 \n\t" // EL3.1: 8*p[1] -> mm2
|
||||
"paddw %%mm5, %%mm2 \n\t" // EL3.2: 9*p[1] + 3*(p[0] + p[3]) + p[2] -> mm5
|
||||
"psrlw $4, %%mm2 \n\t" // EL3.3: sum[1]/16 -> mm5
|
||||
|
||||
// EL2/4: store pixels 0 & 1
|
||||
"packuswb %%mm2, %%mm1 \n\t" // EL2/4: pack into bytes
|
||||
MOVNTQ (%%mm1, (%2)) "\n\t" // EL2/4: store 2 pixels
|
||||
|
||||
// EL4: pixel 2 math -- (9*p[2] + 3*(p[0] + p[3]) + p[1]) / 16
|
||||
"psllw $3, %%mm3 \n\t" // EL4.1: 8*p[2] -> mm3
|
||||
"paddw %%mm5, %%mm3 \n\t" // EL4.2: 9*p[2] + 3*(p[0] + p[3]) + p[1] -> mm3
|
||||
"psrlw $4, %%mm3 \n\t" // EL4.3: sum[2]/16 -> mm3
|
||||
|
||||
// EL5: pixel 3 math -- (9*p[3] + 3*(p[1] + p[2]) + p[0]) / 16
|
||||
"psllw $3, %%mm4 \n\t" // EL5.1: 8*p[3] -> mm4
|
||||
"paddw %%mm6, %%mm4 \n\t" // EL5.2: 9*p[3] + 3*(p[1] + p[2]) + p[0] -> mm4
|
||||
"psrlw $4, %%mm4 \n\t" // EL5.3: sum[3]/16 -> mm4
|
||||
|
||||
// EL4/5: store pixels 2 & 3
|
||||
"packuswb %%mm4, %%mm3 \n\t" // EL4/5: pack into bytes
|
||||
MOVNTQ (%%mm3, (%2,%3,4)) "\n\t" // EL4/5: store 2 pixels
|
||||
|
||||
: /* nothing */
|
||||
: /*0*/"m" (*row0), /*1*/"m" (*row1), /*2*/"r" (dst_p),
|
||||
/*3*/"r" ((unsigned long)dlen) /* 'long' is for proper reg alloc on amd64 */
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#undef A_REG
|
||||
#undef D_REG
|
||||
#undef CLR_UPPER32
|
||||
|
||||
#endif // GCC_ASM
|
||||
|
||||
#endif /* SCALEMMX_H_ */
|
||||
@@ -1,286 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
#include "libs/platform.h"
|
||||
#include "libs/log.h"
|
||||
#include "scalers.h"
|
||||
#include "scaleint.h"
|
||||
#include "2xscalers.h"
|
||||
#ifdef USE_PLATFORM_ACCEL
|
||||
# ifndef __APPLE__
|
||||
// MacOS X framework has no SDL_cpuinfo.h for some reason
|
||||
# include SDL_INCLUDE(SDL_cpuinfo.h)
|
||||
# endif
|
||||
# ifdef MMX_ASM
|
||||
# include "2xscalers_mmx.h"
|
||||
# endif /* MMX_ASM */
|
||||
#endif /* USE_PLATFORM_ACCEL */
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SCALEPLAT_NULL = PLATFORM_NULL,
|
||||
SCALEPLAT_C = PLATFORM_C,
|
||||
SCALEPLAT_MMX = PLATFORM_MMX,
|
||||
SCALEPLAT_SSE = PLATFORM_SSE,
|
||||
SCALEPLAT_3DNOW = PLATFORM_3DNOW,
|
||||
SCALEPLAT_ALTIVEC = PLATFORM_ALTIVEC,
|
||||
|
||||
SCALEPLAT_C_RGBA,
|
||||
SCALEPLAT_C_BGRA,
|
||||
SCALEPLAT_C_ARGB,
|
||||
SCALEPLAT_C_ABGR,
|
||||
|
||||
} Scale_PlatType_t;
|
||||
|
||||
|
||||
// RGB -> YUV transformation
|
||||
// the RGB vector is multiplied by the transformation matrix
|
||||
// to get the YUV vector
|
||||
#if 0
|
||||
// original table -- not used
|
||||
const int YUV_matrix[3][3] =
|
||||
{
|
||||
/* Y U V */
|
||||
/* R */ {0.2989, -0.1687, 0.5000},
|
||||
/* G */ {0.5867, -0.3312, -0.4183},
|
||||
/* B */ {0.1144, 0.5000, -0.0816}
|
||||
};
|
||||
#else
|
||||
// scaled up by a 2^14 factor, with Y doubled
|
||||
const int YUV_matrix[3][3] =
|
||||
{
|
||||
/* Y U V */
|
||||
/* R */ { 9794, -2764, 8192},
|
||||
/* G */ {19224, -5428, -6853},
|
||||
/* B */ { 3749, 8192, -1339}
|
||||
};
|
||||
#endif
|
||||
|
||||
// pre-computed transformations for 8 bits per channel
|
||||
int RGB_to_YUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 256];
|
||||
sint16 dRGB_to_dYUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 512];
|
||||
|
||||
// pre-computed transformations for RGB555
|
||||
YUV_VECTOR RGB15_to_YUV[0x8000];
|
||||
|
||||
PLATFORM_TYPE force_platform = PLATFORM_NULL;
|
||||
Scale_PlatType_t Scale_Platform = SCALEPLAT_NULL;
|
||||
|
||||
|
||||
// pre-compute the RGB->YUV transformations
|
||||
void
|
||||
Scale_Init (void)
|
||||
{
|
||||
int i1, i2, i3;
|
||||
|
||||
for (i1 = 0; i1 < 3; i1++) // enum R,G,B
|
||||
for (i2 = 0; i2 < 3; i2++) // enum Y,U,V
|
||||
for (i3 = 0; i3 < 256; i3++) // enum possible channel vals
|
||||
{
|
||||
RGB_to_YUV[i1][i2][i3] =
|
||||
(YUV_matrix[i1][i2] * i3) >> 14;
|
||||
}
|
||||
|
||||
for (i1 = 0; i1 < 3; i1++) // enum R,G,B
|
||||
for (i2 = 0; i2 < 3; i2++) // enum Y,U,V
|
||||
for (i3 = -255; i3 < 256; i3++) // enum possible channel delta vals
|
||||
{
|
||||
dRGB_to_dYUV[i1][i2][i3 + 255] =
|
||||
(YUV_matrix[i1][i2] * i3) >> 14;
|
||||
}
|
||||
|
||||
for (i1 = 0; i1 < 32; ++i1)
|
||||
for (i2 = 0; i2 < 32; ++i2)
|
||||
for (i3 = 0; i3 < 32; ++i3)
|
||||
{
|
||||
int y, u, v;
|
||||
// adding upper bits halved for error correction
|
||||
int r = (i1 << 3) | (i1 >> 3);
|
||||
int g = (i2 << 3) | (i2 >> 3);
|
||||
int b = (i3 << 3) | (i3 >> 3);
|
||||
|
||||
y = ( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_Y]
|
||||
+ g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_Y]
|
||||
+ b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_Y]
|
||||
) >> 15; // we dont need Y doubled, need Y to fit 8 bits
|
||||
|
||||
// U and V are half the importance of Y
|
||||
u = 64+(( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_U]
|
||||
+ g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_U]
|
||||
+ b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_U]
|
||||
) >> 15); // halved
|
||||
|
||||
v = 64+(( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_V]
|
||||
+ g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_V]
|
||||
+ b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_V]
|
||||
) >> 15); // halved
|
||||
|
||||
RGB15_to_YUV[(i1 << 10) | (i2 << 5) | i3] = (y << 16) | (u << 8) | v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// expands the given rectangle in all directions by 'expansion'
|
||||
// guarded by 'limits'
|
||||
void
|
||||
Scale_ExpandRect (SDL_Rect* rect, int expansion, const SDL_Rect* limits)
|
||||
{
|
||||
if (rect->x - expansion >= limits->x)
|
||||
{
|
||||
rect->w += expansion;
|
||||
rect->x -= expansion;
|
||||
}
|
||||
else
|
||||
{
|
||||
rect->w += rect->x - limits->x;
|
||||
rect->x = limits->x;
|
||||
}
|
||||
|
||||
if (rect->y - expansion >= limits->y)
|
||||
{
|
||||
rect->h += expansion;
|
||||
rect->y -= expansion;
|
||||
}
|
||||
else
|
||||
{
|
||||
rect->h += rect->y - limits->y;
|
||||
rect->y = limits->y;
|
||||
}
|
||||
|
||||
if (rect->x + rect->w + expansion <= limits->w)
|
||||
rect->w += expansion;
|
||||
else
|
||||
rect->w = limits->w - rect->x;
|
||||
|
||||
if (rect->y + rect->h + expansion <= limits->h)
|
||||
rect->h += expansion;
|
||||
else
|
||||
rect->h = limits->h - rect->y;
|
||||
}
|
||||
|
||||
|
||||
// Platform+Scaler function lookups
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Scale_PlatType_t platform;
|
||||
const Scale_FuncDef_t* funcdefs;
|
||||
} Scale_PlatDef_t;
|
||||
|
||||
|
||||
static const Scale_PlatDef_t
|
||||
Scale_PlatDefs[] =
|
||||
{
|
||||
#if defined(MMX_ASM)
|
||||
{SCALEPLAT_SSE, Scale_SSE_Functions},
|
||||
{SCALEPLAT_3DNOW, Scale_3DNow_Functions},
|
||||
{SCALEPLAT_MMX, Scale_MMX_Functions},
|
||||
#endif /* MMX_ASM */
|
||||
// Default
|
||||
{SCALEPLAT_NULL, Scale_C_Functions}
|
||||
};
|
||||
|
||||
|
||||
TFB_ScaleFunc
|
||||
Scale_PrepPlatform (int flags, const SDL_PixelFormat* fmt)
|
||||
{
|
||||
const Scale_PlatDef_t* pdef;
|
||||
const Scale_FuncDef_t* fdef;
|
||||
|
||||
(void)flags;
|
||||
|
||||
Scale_Platform = SCALEPLAT_NULL;
|
||||
|
||||
// first match wins
|
||||
// add better platform techs to the top
|
||||
#ifdef MMX_ASM
|
||||
if ( (!force_platform && (SDL_HasSSE () || SDL_HasMMXExt ()))
|
||||
|| force_platform == SCALEPLAT_SSE)
|
||||
{
|
||||
log_add (log_Info, "Screen scalers are using SSE/MMX-Ext/MMX code");
|
||||
Scale_Platform = SCALEPLAT_SSE;
|
||||
|
||||
Scale_SSE_PrepPlatform (fmt);
|
||||
}
|
||||
else
|
||||
if ( (!force_platform && SDL_HasAltiVec ())
|
||||
|| force_platform == SCALEPLAT_ALTIVEC)
|
||||
{
|
||||
log_add (log_Info, "Screen scalers would use AltiVec code "
|
||||
"if someone actually wrote it");
|
||||
//Scale_Platform = SCALEPLAT_ALTIVEC;
|
||||
}
|
||||
else
|
||||
if ( (!force_platform && SDL_Has3DNow ())
|
||||
|| force_platform == SCALEPLAT_3DNOW)
|
||||
{
|
||||
log_add (log_Info, "Screen scalers are using 3DNow/MMX code");
|
||||
Scale_Platform = SCALEPLAT_3DNOW;
|
||||
|
||||
Scale_3DNow_PrepPlatform (fmt);
|
||||
}
|
||||
else
|
||||
if ( (!force_platform && SDL_HasMMX ())
|
||||
|| force_platform == SCALEPLAT_MMX)
|
||||
{
|
||||
log_add (log_Info, "Screen scalers are using MMX code");
|
||||
Scale_Platform = SCALEPLAT_MMX;
|
||||
|
||||
Scale_MMX_PrepPlatform (fmt);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Scale_Platform == SCALEPLAT_NULL)
|
||||
{ // Plain C versions
|
||||
if (fmt->Rmask == 0xff000000 && fmt->Bmask == 0x0000ff00)
|
||||
Scale_Platform = SCALEPLAT_C_RGBA;
|
||||
else if (fmt->Rmask == 0x00ff0000 && fmt->Bmask == 0x000000ff)
|
||||
Scale_Platform = SCALEPLAT_C_ARGB;
|
||||
else if (fmt->Rmask == 0x0000ff00 && fmt->Bmask == 0xff000000)
|
||||
Scale_Platform = SCALEPLAT_C_BGRA;
|
||||
else if (fmt->Rmask == 0x000000ff && fmt->Bmask == 0x00ff0000)
|
||||
Scale_Platform = SCALEPLAT_C_ABGR;
|
||||
else
|
||||
{ // use slowest default
|
||||
log_add (log_Warning, "Scale_PrepPlatform(): unknown masks "
|
||||
"(Red %08x, Blue %08x)", fmt->Rmask, fmt->Bmask);
|
||||
Scale_Platform = SCALEPLAT_C;
|
||||
}
|
||||
|
||||
if (Scale_Platform == SCALEPLAT_C)
|
||||
log_add (log_Info, "Screen scalers are using slow generic C code");
|
||||
else
|
||||
log_add (log_Info, "Screen scalers are using optimized C code");
|
||||
}
|
||||
|
||||
// Lookup the scaling function
|
||||
// First find the right platform
|
||||
for (pdef = Scale_PlatDefs;
|
||||
pdef->platform != Scale_Platform && pdef->platform != SCALEPLAT_NULL;
|
||||
++pdef)
|
||||
;
|
||||
// Next find the right function
|
||||
for (fdef = pdef->funcdefs;
|
||||
(flags & fdef->flag) != fdef->flag;
|
||||
++fdef)
|
||||
;
|
||||
|
||||
return fdef->func;
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef SCALERS_H_
|
||||
#define SCALERS_H_
|
||||
|
||||
void Scale_Init (void);
|
||||
|
||||
typedef void (* TFB_ScaleFunc) (SDL_Surface *src, SDL_Surface *dst,
|
||||
SDL_Rect *r);
|
||||
|
||||
TFB_ScaleFunc Scale_PrepPlatform (int flags, const SDL_PixelFormat* fmt);
|
||||
|
||||
#endif /* SCALERS_H_ */
|
||||
@@ -1,629 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "sdl_common.h"
|
||||
#include "opengl.h"
|
||||
#include "pure.h"
|
||||
#include "primitives.h"
|
||||
#include "options.h"
|
||||
#include "uqmversion.h"
|
||||
#include "libs/graphics/drawcmd.h"
|
||||
#include "libs/graphics/dcqueue.h"
|
||||
#include "libs/graphics/cmap.h"
|
||||
#include "libs/input/sdl/input.h"
|
||||
// for ProcessInputEvent()
|
||||
#include "libs/graphics/bbox.h"
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
#include "libs/log.h"
|
||||
#include "libs/memlib.h"
|
||||
#include "libs/vidlib.h"
|
||||
#include SDL_INCLUDE(SDL_thread.h)
|
||||
|
||||
SDL_Surface *SDL_Video;
|
||||
SDL_Surface *SDL_Screen;
|
||||
SDL_Surface *TransitionScreen;
|
||||
|
||||
SDL_Surface *SDL_Screens[TFB_GFX_NUMSCREENS];
|
||||
|
||||
SDL_Surface *format_conv_surf = NULL;
|
||||
|
||||
static volatile BOOLEAN abortFlag = FALSE;
|
||||
|
||||
int GfxFlags = 0;
|
||||
|
||||
TFB_GRAPHICS_BACKEND *graphics_backend = NULL;
|
||||
|
||||
volatile int QuitPosted = 0;
|
||||
volatile int GameActive = 1; // Track the SDL_ACTIVEEVENT state SDL_APPACTIVE
|
||||
|
||||
#ifdef ANDROID
|
||||
extern void ResumeMusic (void);
|
||||
extern void PauseMusic (void);
|
||||
|
||||
void AndroidGamePaused()
|
||||
{
|
||||
GameActive = 0;
|
||||
SDL_ANDROID_PauseAudioPlayback();
|
||||
PauseMusic();
|
||||
}
|
||||
|
||||
void AndroidGameResumed()
|
||||
{
|
||||
GameActive = 1;
|
||||
SDL_ANDROID_ResumeAudioPlayback();
|
||||
ResumeMusic();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
TFB_PreInit (void)
|
||||
{
|
||||
log_add (log_Info, "Initializing base SDL functionality.");
|
||||
log_add (log_Info, "Using SDL version %d.%d.%d (compiled with "
|
||||
"%d.%d.%d)", SDL_Linked_Version ()->major,
|
||||
SDL_Linked_Version ()->minor, SDL_Linked_Version ()->patch,
|
||||
SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);
|
||||
#if 0
|
||||
if (SDL_Linked_Version ()->major != SDL_MAJOR_VERSION ||
|
||||
SDL_Linked_Version ()->minor != SDL_MINOR_VERSION ||
|
||||
SDL_Linked_Version ()->patch != SDL_PATCHLEVEL) {
|
||||
log_add (log_Warning, "The used SDL library is not the same version "
|
||||
"as the one used to compile The Ur-Quan Masters with! "
|
||||
"If you experience any crashes, this would be an excellent "
|
||||
"suspect.");
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((SDL_Init (SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) == -1))
|
||||
{
|
||||
log_add (log_Fatal, "Could not initialize SDL: %s.", SDL_GetError ());
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
#ifdef ANDROID
|
||||
SDL_ANDROID_SetApplicationPutToBackgroundCallback(&AndroidGamePaused, &AndroidGameResumed);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
TFB_ReInitGraphics (int driver, int flags, int width, int height)
|
||||
{
|
||||
int result;
|
||||
int togglefullscreen = 0;
|
||||
char caption[200];
|
||||
|
||||
if (GfxFlags == (flags ^ TFB_GFXFLAGS_FULLSCREEN) &&
|
||||
driver == GraphicsDriver &&
|
||||
width == ScreenWidthActual && height == ScreenHeightActual)
|
||||
{
|
||||
togglefullscreen = 1;
|
||||
}
|
||||
|
||||
GfxFlags = flags;
|
||||
|
||||
if (driver == TFB_GFXDRIVER_SDL_OPENGL)
|
||||
{
|
||||
#ifdef HAVE_OPENGL
|
||||
result = TFB_GL_ConfigureVideo (driver, flags, width, height,
|
||||
togglefullscreen);
|
||||
#else
|
||||
driver = TFB_GFXDRIVER_SDL_PURE;
|
||||
log_add (log_Warning, "OpenGL support not compiled in,"
|
||||
" so using pure SDL driver");
|
||||
result = TFB_Pure_ConfigureVideo (driver, flags, width, height,
|
||||
togglefullscreen);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
result = TFB_Pure_ConfigureVideo (driver, flags, width, height,
|
||||
togglefullscreen);
|
||||
}
|
||||
|
||||
sprintf (caption, "The Ur-Quan Masters v%d.%d.%d%s",
|
||||
UQM_MAJOR_VERSION, UQM_MINOR_VERSION,
|
||||
UQM_PATCH_VERSION, UQM_EXTRA_VERSION);
|
||||
SDL_WM_SetCaption (caption, NULL);
|
||||
|
||||
if (flags & TFB_GFXFLAGS_FULLSCREEN)
|
||||
SDL_ShowCursor (SDL_DISABLE);
|
||||
else
|
||||
SDL_ShowCursor (SDL_ENABLE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
TFB_InitGraphics (int driver, int flags, int width, int height)
|
||||
{
|
||||
int result, i;
|
||||
char caption[200];
|
||||
|
||||
/* Null out screen pointers the first time */
|
||||
for (i = 0; i < TFB_GFX_NUMSCREENS; i++)
|
||||
{
|
||||
SDL_Screens[i] = NULL;
|
||||
}
|
||||
|
||||
GfxFlags = flags;
|
||||
|
||||
if (driver == TFB_GFXDRIVER_SDL_OPENGL)
|
||||
{
|
||||
#ifdef HAVE_OPENGL
|
||||
result = TFB_GL_InitGraphics (driver, flags, width, height);
|
||||
#else
|
||||
driver = TFB_GFXDRIVER_SDL_PURE;
|
||||
log_add (log_Warning, "OpenGL support not compiled in,"
|
||||
" so using pure SDL driver");
|
||||
result = TFB_Pure_InitGraphics (driver, flags, width, height);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
result = TFB_Pure_InitGraphics (driver, flags, width, height);
|
||||
}
|
||||
|
||||
sprintf (caption, "The Ur-Quan Masters v%d.%d.%d%s",
|
||||
UQM_MAJOR_VERSION, UQM_MINOR_VERSION,
|
||||
UQM_PATCH_VERSION, UQM_EXTRA_VERSION);
|
||||
SDL_WM_SetCaption (caption, NULL);
|
||||
|
||||
if (flags & TFB_GFXFLAGS_FULLSCREEN)
|
||||
SDL_ShowCursor (SDL_DISABLE);
|
||||
|
||||
Init_DrawCommandQueue ();
|
||||
|
||||
TFB_DrawCanvas_Initialize ();
|
||||
|
||||
atexit (TFB_UninitGraphics);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
TFB_UninitGraphics (void)
|
||||
{
|
||||
Uninit_DrawCommandQueue ();
|
||||
// TODO: Uninit whatever the drivers have set up for us
|
||||
SDL_Quit ();
|
||||
}
|
||||
|
||||
void
|
||||
TFB_ProcessEvents ()
|
||||
{
|
||||
SDL_Event Event;
|
||||
|
||||
while (SDL_PollEvent (&Event))
|
||||
{
|
||||
/* Run through the InputEvent filter. */
|
||||
ProcessInputEvent (&Event);
|
||||
/* Handle graphics and exposure events. */
|
||||
switch (Event.type) {
|
||||
case SDL_ACTIVEEVENT: /* Lose/gain visibility or focus */
|
||||
/* Up to three different state changes can occur in one event. */
|
||||
/* Here, disregard least significant change (mouse focus). */
|
||||
#if 0 /* Currently disabled in mainline */
|
||||
// This controls the automatic sleep/pause when minimized.
|
||||
// On small displays (e.g. mobile devices), APPINPUTFOCUS would
|
||||
// be an appropriate substitution for APPACTIVE:
|
||||
// if (Event.active.state & SDL_APPINPUTFOCUS)
|
||||
if (Event.active.state & SDL_APPACTIVE)
|
||||
GameActive = Event.active.gain;
|
||||
#endif
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
QuitPosted = 1;
|
||||
break;
|
||||
case SDL_VIDEORESIZE: /* User resized video mode */
|
||||
// TODO
|
||||
break;
|
||||
case SDL_VIDEOEXPOSE: /* Screen needs to be redrawn */
|
||||
TFB_SwapBuffers (TFB_REDRAW_EXPOSE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOLEAN system_box_active = 0;
|
||||
static SDL_Rect system_box;
|
||||
|
||||
void
|
||||
SetSystemRect (const RECT *r)
|
||||
{
|
||||
system_box_active = TRUE;
|
||||
system_box.x = r->corner.x;
|
||||
system_box.y = r->corner.y;
|
||||
system_box.w = r->extent.width;
|
||||
system_box.h = r->extent.height;
|
||||
}
|
||||
|
||||
void
|
||||
ClearSystemRect (void)
|
||||
{
|
||||
system_box_active = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
TFB_SwapBuffers (int force_full_redraw)
|
||||
{
|
||||
static int last_fade_amount = 255, last_transition_amount = 255;
|
||||
static int fade_amount = 255, transition_amount = 255;
|
||||
|
||||
fade_amount = GetFadeAmount ();
|
||||
transition_amount = TransitionAmount;
|
||||
|
||||
if (force_full_redraw == TFB_REDRAW_NO && !TFB_BBox.valid &&
|
||||
fade_amount == 255 && transition_amount == 255 &&
|
||||
last_fade_amount == 255 && last_transition_amount == 255)
|
||||
return;
|
||||
|
||||
if (force_full_redraw == TFB_REDRAW_NO &&
|
||||
(fade_amount != 255 || transition_amount != 255 ||
|
||||
last_fade_amount != 255 || last_transition_amount != 255))
|
||||
force_full_redraw = TFB_REDRAW_FADING;
|
||||
|
||||
last_fade_amount = fade_amount;
|
||||
last_transition_amount = transition_amount;
|
||||
|
||||
graphics_backend->preprocess (force_full_redraw, transition_amount,
|
||||
fade_amount);
|
||||
graphics_backend->screen (TFB_SCREEN_MAIN, 255, NULL);
|
||||
|
||||
if (transition_amount != 255)
|
||||
{
|
||||
SDL_Rect r;
|
||||
r.x = TransitionClipRect.corner.x;
|
||||
r.y = TransitionClipRect.corner.y;
|
||||
r.w = TransitionClipRect.extent.width;
|
||||
r.h = TransitionClipRect.extent.height;
|
||||
graphics_backend->screen (TFB_SCREEN_TRANSITION,
|
||||
255 - transition_amount, &r);
|
||||
}
|
||||
|
||||
if (fade_amount != 255)
|
||||
{
|
||||
if (fade_amount < 255)
|
||||
{
|
||||
graphics_backend->color (0, 0, 0, 255 - fade_amount, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
graphics_backend->color (255, 255, 255,
|
||||
fade_amount - 255, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (system_box_active)
|
||||
{
|
||||
graphics_backend->screen (TFB_SCREEN_MAIN, 255, &system_box);
|
||||
}
|
||||
|
||||
graphics_backend->postprocess ();
|
||||
}
|
||||
|
||||
/* Probably ought to clean this away at some point. */
|
||||
SDL_Surface *
|
||||
TFB_DisplayFormatAlpha (SDL_Surface *surface)
|
||||
{
|
||||
SDL_Surface* newsurf;
|
||||
SDL_PixelFormat* dstfmt;
|
||||
const SDL_PixelFormat* srcfmt = surface->format;
|
||||
|
||||
// figure out what format to use (alpha/no alpha)
|
||||
if (surface->format->Amask)
|
||||
dstfmt = format_conv_surf->format;
|
||||
else
|
||||
dstfmt = SDL_Screen->format;
|
||||
|
||||
if (srcfmt->BytesPerPixel == dstfmt->BytesPerPixel &&
|
||||
srcfmt->Rmask == dstfmt->Rmask &&
|
||||
srcfmt->Gmask == dstfmt->Gmask &&
|
||||
srcfmt->Bmask == dstfmt->Bmask &&
|
||||
srcfmt->Amask == dstfmt->Amask)
|
||||
return surface; // no conversion needed
|
||||
|
||||
newsurf = SDL_ConvertSurface (surface, dstfmt, surface->flags);
|
||||
// SDL_SRCCOLORKEY and SDL_SRCALPHA cannot work at the same time,
|
||||
// so we need to disable one of them
|
||||
if ((surface->flags & SDL_SRCCOLORKEY) && newsurf
|
||||
&& (newsurf->flags & SDL_SRCCOLORKEY)
|
||||
&& (newsurf->flags & SDL_SRCALPHA))
|
||||
SDL_SetAlpha (newsurf, 0, 255);
|
||||
|
||||
return newsurf;
|
||||
}
|
||||
|
||||
// This function should only be called from the graphics thread,
|
||||
// like from a TFB_DrawCommand_Callback command.
|
||||
TFB_Canvas
|
||||
TFB_GetScreenCanvas (SCREEN screen)
|
||||
{
|
||||
return SDL_Screens[screen];
|
||||
}
|
||||
|
||||
void
|
||||
TFB_BlitSurface (SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst,
|
||||
SDL_Rect *dstrect, int blend_numer, int blend_denom)
|
||||
{
|
||||
BOOLEAN has_colorkey;
|
||||
int x, y, x1, y1, x2, y2, dst_x2, dst_y2, nr, ng, nb;
|
||||
int srcx, srcy, w, h;
|
||||
Uint8 sr, sg, sb, dr, dg, db;
|
||||
Uint32 src_pixval, dst_pixval, colorkey;
|
||||
GetPixelFn src_getpix, dst_getpix;
|
||||
PutPixelFn putpix;
|
||||
SDL_Rect fulldst;
|
||||
|
||||
if (blend_numer == blend_denom)
|
||||
{
|
||||
// normal blit: dst = src
|
||||
|
||||
// log_add (log_Debug, "normal blit\n");
|
||||
SDL_BlitSurface (src, srcrect, dst, dstrect);
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: following clipping code is copied from SDL-1.2.4 sources
|
||||
|
||||
// If the destination rectangle is NULL, use the entire dest surface
|
||||
if (dstrect == NULL)
|
||||
{
|
||||
fulldst.x = fulldst.y = 0;
|
||||
dstrect = &fulldst;
|
||||
}
|
||||
|
||||
// clip the source rectangle to the source surface
|
||||
if (srcrect)
|
||||
{
|
||||
int maxw, maxh;
|
||||
|
||||
srcx = srcrect->x;
|
||||
w = srcrect->w;
|
||||
if (srcx < 0)
|
||||
{
|
||||
w += srcx;
|
||||
dstrect->x -= srcx;
|
||||
srcx = 0;
|
||||
}
|
||||
maxw = src->w - srcx;
|
||||
if (maxw < w)
|
||||
w = maxw;
|
||||
|
||||
srcy = srcrect->y;
|
||||
h = srcrect->h;
|
||||
if (srcy < 0)
|
||||
{
|
||||
h += srcy;
|
||||
dstrect->y -= srcy;
|
||||
srcy = 0;
|
||||
}
|
||||
maxh = src->h - srcy;
|
||||
if (maxh < h)
|
||||
h = maxh;
|
||||
}
|
||||
else
|
||||
{
|
||||
srcx = 0;
|
||||
srcy = 0;
|
||||
w = src->w;
|
||||
h = src->h;
|
||||
}
|
||||
|
||||
// clip the destination rectangle against the clip rectangle
|
||||
{
|
||||
SDL_Rect *clip = &dst->clip_rect;
|
||||
int dx, dy;
|
||||
|
||||
dx = clip->x - dstrect->x;
|
||||
if (dx > 0)
|
||||
{
|
||||
w -= dx;
|
||||
dstrect->x += dx;
|
||||
srcx += dx;
|
||||
}
|
||||
dx = dstrect->x + w - clip->x - clip->w;
|
||||
if (dx > 0)
|
||||
w -= dx;
|
||||
|
||||
dy = clip->y - dstrect->y;
|
||||
if (dy > 0)
|
||||
{
|
||||
h -= dy;
|
||||
dstrect->y += dy;
|
||||
srcy += dy;
|
||||
}
|
||||
dy = dstrect->y + h - clip->y - clip->h;
|
||||
if (dy > 0)
|
||||
h -= dy;
|
||||
}
|
||||
|
||||
dstrect->w = w;
|
||||
dstrect->h = h;
|
||||
|
||||
if (w <= 0 || h <= 0)
|
||||
return;
|
||||
|
||||
x1 = srcx;
|
||||
y1 = srcy;
|
||||
x2 = srcx + w;
|
||||
y2 = srcy + h;
|
||||
|
||||
if (src->flags & SDL_SRCCOLORKEY)
|
||||
{
|
||||
has_colorkey = TRUE;
|
||||
colorkey = src->format->colorkey;
|
||||
}
|
||||
else
|
||||
{
|
||||
has_colorkey = FALSE;
|
||||
colorkey = 0; /* Satisfying compiler */
|
||||
}
|
||||
|
||||
src_getpix = getpixel_for (src);
|
||||
dst_getpix = getpixel_for (dst);
|
||||
putpix = putpixel_for (dst);
|
||||
|
||||
if (blend_denom < 0)
|
||||
{
|
||||
// additive blit: dst = src + dst
|
||||
#if 0
|
||||
log_add (log_Debug, "additive blit %d %d, src %d %d %d %d dst %d %d,"
|
||||
" srcbpp %d", blend_numer, blend_denom, x1, y1, x2, y2,
|
||||
dstrect->x, dstrect->y, src->format->BitsPerPixel);
|
||||
#endif
|
||||
for (y = y1; y < y2; ++y)
|
||||
{
|
||||
dst_y2 = dstrect->y + (y - y1);
|
||||
for (x = x1; x < x2; ++x)
|
||||
{
|
||||
dst_x2 = dstrect->x + (x - x1);
|
||||
src_pixval = src_getpix (src, x, y);
|
||||
|
||||
if (has_colorkey && src_pixval == colorkey)
|
||||
continue;
|
||||
|
||||
dst_pixval = dst_getpix (dst, dst_x2, dst_y2);
|
||||
|
||||
SDL_GetRGB (src_pixval, src->format, &sr, &sg, &sb);
|
||||
SDL_GetRGB (dst_pixval, dst->format, &dr, &dg, &db);
|
||||
|
||||
nr = sr + dr;
|
||||
ng = sg + dg;
|
||||
nb = sb + db;
|
||||
|
||||
if (nr > 255)
|
||||
nr = 255;
|
||||
if (ng > 255)
|
||||
ng = 255;
|
||||
if (nb > 255)
|
||||
nb = 255;
|
||||
|
||||
putpix (dst, dst_x2, dst_y2,
|
||||
SDL_MapRGB (dst->format, nr, ng, nb));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (blend_numer < 0)
|
||||
{
|
||||
// subtractive blit: dst = src - dst
|
||||
#if 0
|
||||
log_add (log_Debug, "subtractive blit %d %d, src %d %d %d %d"
|
||||
" dst %d %d, srcbpp %d", blend_numer, blend_denom,
|
||||
x1, y1, x2, y2, dstrect->x, dstrect->y,
|
||||
src->format->BitsPerPixel);
|
||||
#endif
|
||||
for (y = y1; y < y2; ++y)
|
||||
{
|
||||
dst_y2 = dstrect->y + (y - y1);
|
||||
for (x = x1; x < x2; ++x)
|
||||
{
|
||||
dst_x2 = dstrect->x + (x - x1);
|
||||
src_pixval = src_getpix (src, x, y);
|
||||
|
||||
if (has_colorkey && src_pixval == colorkey)
|
||||
continue;
|
||||
|
||||
dst_pixval = dst_getpix (dst, dst_x2, dst_y2);
|
||||
|
||||
SDL_GetRGB (src_pixval, src->format, &sr, &sg, &sb);
|
||||
SDL_GetRGB (dst_pixval, dst->format, &dr, &dg, &db);
|
||||
|
||||
nr = sr - dr;
|
||||
ng = sg - dg;
|
||||
nb = sb - db;
|
||||
|
||||
if (nr < 0)
|
||||
nr = 0;
|
||||
if (ng < 0)
|
||||
ng = 0;
|
||||
if (nb < 0)
|
||||
nb = 0;
|
||||
|
||||
putpix (dst, dst_x2, dst_y2,
|
||||
SDL_MapRGB (dst->format, nr, ng, nb));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// modulated blit: dst = src * (blend_numer / blend_denom)
|
||||
|
||||
float f = blend_numer / (float)blend_denom;
|
||||
#if 0
|
||||
log_add (log_Debug, "modulated blit %d %d, f %f, src %d %d %d %d"
|
||||
" dst %d %d, srcbpp %d\n", blend_numer, blend_denom, f,
|
||||
x1, y1, x2, y2, dstrect->x, dstrect->y,
|
||||
src->format->BitsPerPixel);
|
||||
#endif
|
||||
for (y = y1; y < y2; ++y)
|
||||
{
|
||||
dst_y2 = dstrect->y + (y - y1);
|
||||
for (x = x1; x < x2; ++x)
|
||||
{
|
||||
dst_x2 = dstrect->x + (x - x1);
|
||||
src_pixval = src_getpix (src, x, y);
|
||||
|
||||
if (has_colorkey && src_pixval == colorkey)
|
||||
continue;
|
||||
|
||||
SDL_GetRGB (src_pixval, src->format, &sr, &sg, &sb);
|
||||
|
||||
nr = (int)(sr * f);
|
||||
ng = (int)(sg * f);
|
||||
nb = (int)(sb * f);
|
||||
|
||||
if (nr > 255)
|
||||
nr = 255;
|
||||
if (ng > 255)
|
||||
ng = 255;
|
||||
if (nb > 255)
|
||||
nb = 255;
|
||||
|
||||
putpix (dst, dst_x2, dst_y2,
|
||||
SDL_MapRGB (dst->format, nr, ng, nb));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TFB_UploadTransitionScreen (void)
|
||||
{
|
||||
#ifdef HAVE_OPENGL
|
||||
if (GraphicsDriver == TFB_GFXDRIVER_SDL_OPENGL)
|
||||
{
|
||||
TFB_GL_UploadTransitionScreen ();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
TFB_SetGamma (float gamma)
|
||||
{
|
||||
if (SDL_SetGamma (gamma, gamma, gamma) == -1)
|
||||
{
|
||||
log_add (log_Warning, "Unable to set gamma correction.");
|
||||
}
|
||||
else
|
||||
{
|
||||
log_add (log_Info, "Gamma correction set to %1.4f.", gamma);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef SDL_COMMON_H
|
||||
#define SDL_COMMON_H
|
||||
|
||||
#include "port.h"
|
||||
#include SDL_INCLUDE(SDL.h)
|
||||
#include SDL_INCLUDE(SDL_byteorder.h)
|
||||
#include SDL_IMAGE_INCLUDE(SDL_image.h)
|
||||
|
||||
#include "../gfxintrn.h"
|
||||
#include "libs/graphics/tfb_draw.h"
|
||||
#include "libs/graphics/gfx_common.h"
|
||||
|
||||
// The Graphics Backend vtable
|
||||
typedef struct _tfb_graphics_backend {
|
||||
void (*preprocess) (int force_redraw, int transition_amount, int fade_amount);
|
||||
void (*postprocess) (void);
|
||||
void (*screen) (SCREEN screen, Uint8 alpha, SDL_Rect *rect);
|
||||
void (*color) (Uint8 r, Uint8 g, Uint8 b, Uint8 a, SDL_Rect *rect);
|
||||
} TFB_GRAPHICS_BACKEND;
|
||||
|
||||
extern TFB_GRAPHICS_BACKEND *graphics_backend;
|
||||
|
||||
extern SDL_Surface *SDL_Video;
|
||||
extern SDL_Surface *SDL_Screen;
|
||||
extern SDL_Surface *TransitionScreen;
|
||||
|
||||
extern SDL_Surface *SDL_Screens[TFB_GFX_NUMSCREENS];
|
||||
|
||||
extern SDL_Surface *format_conv_surf;
|
||||
|
||||
SDL_Surface* TFB_DisplayFormatAlpha (SDL_Surface *surface);
|
||||
|
||||
#endif
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "sdluio.h"
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
#include SDL_INCLUDE(SDL.h)
|
||||
#include SDL_INCLUDE(SDL_error.h)
|
||||
#include SDL_INCLUDE(SDL_rwops.h)
|
||||
#include SDL_IMAGE_INCLUDE(SDL_image.h)
|
||||
#include "libs/memlib.h"
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static SDL_RWops *sdluio_makeRWops (uio_Stream *stream);
|
||||
|
||||
#if 0
|
||||
// For use for initialisation, using structure assignment.
|
||||
static SDL_RWops sdluio_templateRWops =
|
||||
{
|
||||
.seek = sdluio_seek,
|
||||
.read = sdluio_read,
|
||||
.write = sdluio_write,
|
||||
.close = sdluio_close,
|
||||
};
|
||||
#endif
|
||||
|
||||
SDL_Surface *
|
||||
sdluio_loadImage (uio_DirHandle *dir, const char *fileName) {
|
||||
uio_Stream *stream;
|
||||
SDL_RWops *rwops;
|
||||
SDL_Surface *result;
|
||||
|
||||
stream = uio_fopen (dir, fileName, "rb");
|
||||
if (stream == NULL)
|
||||
{
|
||||
SDL_SetError ("Couldn't open '%s': %s", fileName,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
rwops = sdluio_makeRWops (stream);
|
||||
result = IMG_Load_RW (rwops, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sdluio_seek (SDL_RWops *context, int offset, int whence) {
|
||||
if (uio_fseek ((uio_Stream *) context->hidden.unknown.data1, offset,
|
||||
whence) == -1)
|
||||
{
|
||||
SDL_SetError ("Error seeking in uio_Stream: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return uio_ftell ((uio_Stream *) context->hidden.unknown.data1);
|
||||
}
|
||||
|
||||
int
|
||||
sdluio_read (SDL_RWops *context, void *ptr, int size, int maxnum) {
|
||||
size_t numRead;
|
||||
|
||||
numRead = uio_fread (ptr, (size_t) size, (size_t) maxnum,
|
||||
(uio_Stream *) context->hidden.unknown.data1);
|
||||
if (numRead == 0 && uio_ferror ((uio_Stream *)
|
||||
context->hidden.unknown.data1))
|
||||
{
|
||||
SDL_SetError ("Error reading from uio_Stream: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
return (int) numRead;
|
||||
}
|
||||
|
||||
int
|
||||
sdluio_write (SDL_RWops *context, const void *ptr, int size, int num) {
|
||||
size_t numWritten;
|
||||
|
||||
numWritten = uio_fwrite (ptr, (size_t) size, (size_t) num,
|
||||
(uio_Stream *) context->hidden.unknown.data1);
|
||||
if (numWritten == 0 && uio_ferror ((uio_Stream *)
|
||||
context->hidden.unknown.data1))
|
||||
{
|
||||
SDL_SetError ("Error writing to uio_Stream: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
return (size_t) numWritten;
|
||||
}
|
||||
|
||||
int
|
||||
sdluio_close (SDL_RWops *context) {
|
||||
int result;
|
||||
|
||||
result = uio_fclose ((uio_Stream *) context->hidden.unknown.data1);
|
||||
HFree (context);
|
||||
return result;
|
||||
}
|
||||
|
||||
static SDL_RWops *
|
||||
sdluio_makeRWops (uio_Stream *stream) {
|
||||
SDL_RWops *result;
|
||||
|
||||
result = HMalloc (sizeof (SDL_RWops));
|
||||
#if 0
|
||||
*(struct SDL_RWops *) result = sdluio_templateRWops;
|
||||
// structure assignment
|
||||
#endif
|
||||
result->seek = sdluio_seek;
|
||||
result->read = sdluio_read;
|
||||
result->write = sdluio_write;
|
||||
result->close = sdluio_close;
|
||||
result->hidden.unknown.data1 = stream;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _SDLUIO_H
|
||||
#define _SDLUIO_H
|
||||
|
||||
#include "port.h"
|
||||
#include "libs/uio.h"
|
||||
#include SDL_INCLUDE(SDL.h)
|
||||
#include SDL_INCLUDE(SDL_rwops.h)
|
||||
|
||||
SDL_Surface *sdluio_loadImage (uio_DirHandle *dir, const char *fileName);
|
||||
int sdluio_seek (SDL_RWops *context, int offset, int whence);
|
||||
int sdluio_read (SDL_RWops *context, void *ptr, int size, int maxnum);
|
||||
int sdluio_write (SDL_RWops *context, const void *ptr, int size, int num);
|
||||
int sdluio_close (SDL_RWops *context);
|
||||
|
||||
|
||||
#endif /* _SDLUIO_H */
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// Core algorithm of the Triscan screen scaler (based on Scale2x)
|
||||
// (for scale2x please see http://scale2x.sf.net)
|
||||
// Template
|
||||
// When this file is built standalone is produces a plain C version
|
||||
// Also #included by 2xscalers_mmx.c for an MMX version
|
||||
|
||||
#include "libs/graphics/sdl/sdl_common.h"
|
||||
#include "types.h"
|
||||
#include "scalers.h"
|
||||
#include "scaleint.h"
|
||||
#include "2xscalers.h"
|
||||
|
||||
|
||||
// Triscan scaling to 2x
|
||||
// derivative of scale2x -- scale2x.sf.net
|
||||
// The name expands to either
|
||||
// Scale_TriScanFilter (for plain C) or
|
||||
// Scale_MMX_TriScanFilter (for MMX)
|
||||
// [others when platforms are added]
|
||||
void
|
||||
SCALE_(TriScanFilter) (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
||||
{
|
||||
int x, y;
|
||||
const int w = src->w, h = src->h;
|
||||
int xend, yend;
|
||||
int dsrc, ddst;
|
||||
SDL_Rect *region = r;
|
||||
SDL_Rect limits;
|
||||
SDL_PixelFormat *fmt = dst->format;
|
||||
const int sp = src->pitch, dp = dst->pitch;
|
||||
const int bpp = fmt->BytesPerPixel;
|
||||
const int slen = sp / bpp, dlen = dp / bpp;
|
||||
// for clarity purposes, the 'pixels' array here is transposed
|
||||
Uint32 pixels[3][3];
|
||||
Uint32 *src_p = (Uint32 *)src->pixels;
|
||||
Uint32 *dst_p = (Uint32 *)dst->pixels;
|
||||
|
||||
int prevline, nextline;
|
||||
|
||||
// these macros are for clarity; they make the current pixel (0,0)
|
||||
// and allow to access pixels in all directions
|
||||
#define PIX(x, y) (pixels[1 + (x)][1 + (y)])
|
||||
|
||||
#define TRISCAN_YUV_MED 100
|
||||
// medium tolerance pixel comparison
|
||||
#define TRISCAN_CMPYUV(p1, p2) \
|
||||
(PIX p1 == PIX p2 || SCALE_CMPYUV (PIX p1, PIX p2, TRISCAN_YUV_MED))
|
||||
|
||||
|
||||
SCALE_(PlatInit) ();
|
||||
|
||||
// expand updated region if necessary
|
||||
// pixels neighbooring the updated region may
|
||||
// change as a result of updates
|
||||
limits.x = 0;
|
||||
limits.y = 0;
|
||||
limits.w = src->w;
|
||||
limits.h = src->h;
|
||||
Scale_ExpandRect (region, 1, &limits);
|
||||
|
||||
xend = region->x + region->w;
|
||||
yend = region->y + region->h;
|
||||
dsrc = slen - region->w;
|
||||
ddst = (dlen - region->w) * 2;
|
||||
|
||||
// move ptrs to the first updated pixel
|
||||
src_p += slen * region->y + region->x;
|
||||
dst_p += (dlen * region->y + region->x) * 2;
|
||||
|
||||
for (y = region->y; y < yend; ++y, dst_p += ddst, src_p += dsrc)
|
||||
{
|
||||
if (y > 0)
|
||||
prevline = -slen;
|
||||
else
|
||||
prevline = 0;
|
||||
|
||||
if (y < h - 1)
|
||||
nextline = slen;
|
||||
else
|
||||
nextline = 0;
|
||||
|
||||
// prime the (tiny) sliding-window pixel arrays
|
||||
PIX( 1, 0) = src_p[0];
|
||||
|
||||
if (region->x > 0)
|
||||
PIX( 0, 0) = src_p[-1];
|
||||
else
|
||||
PIX( 0, 0) = PIX( 1, 0);
|
||||
|
||||
for (x = region->x; x < xend; ++x, ++src_p, dst_p += 2)
|
||||
{
|
||||
// slide the window
|
||||
PIX(-1, 0) = PIX( 0, 0);
|
||||
|
||||
PIX( 0, -1) = src_p[prevline];
|
||||
PIX( 0, 0) = PIX( 1, 0);
|
||||
PIX( 0, 1) = src_p[nextline];
|
||||
|
||||
if (x < w - 1)
|
||||
PIX( 1, 0) = src_p[1];
|
||||
else
|
||||
PIX( 1, 0) = PIX( 0, 0);
|
||||
|
||||
if (!TRISCAN_CMPYUV (( 0, -1), ( 0, 1)) &&
|
||||
!TRISCAN_CMPYUV ((-1, 0), ( 1, 0)))
|
||||
{
|
||||
if (TRISCAN_CMPYUV ((-1, 0), ( 0, -1)))
|
||||
dst_p[0] = Scale_Blend_11 (PIX(-1, 0), PIX(0, -1));
|
||||
else
|
||||
dst_p[0] = PIX(0, 0);
|
||||
|
||||
if (TRISCAN_CMPYUV (( 1, 0), ( 0, -1)))
|
||||
dst_p[1] = Scale_Blend_11 (PIX(1, 0), PIX(0, -1));
|
||||
else
|
||||
dst_p[1] = PIX(0, 0);
|
||||
|
||||
if (TRISCAN_CMPYUV ((-1, 0), ( 0, 1)))
|
||||
dst_p[dlen] = Scale_Blend_11 (PIX(-1, 0), PIX(0, 1));
|
||||
else
|
||||
dst_p[dlen] = PIX(0, 0);
|
||||
|
||||
if (TRISCAN_CMPYUV (( 1, 0), ( 0, 1)))
|
||||
dst_p[dlen+1] = Scale_Blend_11 (PIX(1, 0), PIX(0, 1));
|
||||
else
|
||||
dst_p[dlen+1] = PIX(0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
dst_p[0] = PIX(0, 0);
|
||||
dst_p[1] = PIX(0, 0);
|
||||
dst_p[dlen] = PIX(0, 0);
|
||||
dst_p[dlen+1] = PIX(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCALE_(PlatDone) ();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user