summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Bermond2019-06-15 01:09:40 +0000
committerDaniel Bermond2019-06-15 01:10:38 +0000
commitf8b6469c7c25655c3c593033d527e02970706c7d (patch)
tree1aa9f5586687311b16900a79562cf146f9760905
downloadaur-f8b6469c7c25655c3c593033d527e02970706c7d.tar.gz
Initial commit of dosbox-openglide-svn
-rw-r--r--.SRCINFO35
-rw-r--r--PKGBUILD74
-rw-r--r--dosbox-openglide-svn.patch2642
-rw-r--r--dosbox.desktop11
-rw-r--r--dosbox.pngbin0 -> 4691 bytes
5 files changed, 2762 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..fc2ee6ca14bb
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,35 @@
+pkgbase = dosbox-openglide-svn
+ pkgdesc = DOS emulator for running DOS games (with openglide 3D, svn version)
+ pkgver = 0.74.2.r4230
+ pkgrel = 1
+ url = https://www.dosbox.com/
+ arch = x86_64
+ license = GPL
+ makedepends = subversion
+ makedepends = mesa-libgl
+ depends = sdl_net
+ depends = zlib
+ depends = sdl_sound
+ depends = libgl
+ depends = libpng
+ depends = alsa-lib
+ depends = gcc-libs
+ depends = glu
+ depends = openglide-git
+ provides = dosbox
+ provides = dosbox-openglide
+ provides = dosbox-svn
+ conflicts = dosbox
+ source = dosbox::svn+https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk
+ source = https://raw.githubusercontent.com/voyageur/openglide/c794a6efd48351340a3606f404aaf84d90446f56/platform/dosbox/glide2x.ovl
+ source = dosbox.desktop
+ source = dosbox.png
+ source = dosbox-openglide-svn.patch
+ sha256sums = SKIP
+ sha256sums = ed391bb9fb0e7b5d33b92882356f02b05913361675712d93b4ef303d5b9f2ac9
+ sha256sums = 680c8543cb0329000a36c188bb95999c6fae159d3704a4496b54cfada360c7e5
+ sha256sums = 491c42d16fc5ef7ee2eca1b736f7801249d4ca8c0b236a001aec0d3e24504f3b
+ sha256sums = e8571c41ab3ebb29f423d8ddb39ba0237b4ee2995ee4a6a210e51b0008f620d6
+
+pkgname = dosbox-openglide-svn
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..5571bcf7762f
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,74 @@
+# Maintainer: Daniel Bermond < gmail-com: danielbermond >
+
+pkgname=dosbox-openglide-svn
+pkgver=0.74.2.r4230
+pkgrel=1
+pkgdesc='DOS emulator for running DOS games (with openglide 3D, svn version)'
+arch=('x86_64')
+url='https://www.dosbox.com/'
+license=('GPL')
+depends=(
+ # official repositories:
+ 'sdl_net' 'zlib' 'sdl_sound' 'libgl' 'libpng' 'alsa-lib' 'gcc-libs' 'glu'
+ # AUR:
+ 'openglide-git'
+)
+makedepends=('subversion' 'mesa-libgl')
+provides=('dosbox' 'dosbox-openglide' 'dosbox-svn')
+conflicts=('dosbox')
+source=('dosbox'::'svn+https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk'
+ 'https://raw.githubusercontent.com/voyageur/openglide/c794a6efd48351340a3606f404aaf84d90446f56/platform/dosbox/glide2x.ovl'
+ 'dosbox.desktop'
+ 'dosbox.png'
+ 'dosbox-openglide-svn.patch')
+sha256sums=('SKIP'
+ 'ed391bb9fb0e7b5d33b92882356f02b05913361675712d93b4ef303d5b9f2ac9'
+ '680c8543cb0329000a36c188bb95999c6fae159d3704a4496b54cfada360c7e5'
+ '491c42d16fc5ef7ee2eca1b736f7801249d4ca8c0b236a001aec0d3e24504f3b'
+ 'e8571c41ab3ebb29f423d8ddb39ba0237b4ee2995ee4a6a210e51b0008f620d6')
+
+prepare() {
+ cd dosbox
+
+ # add openglide support
+ patch -Np1 -i "${srcdir}/dosbox-openglide-svn.patch"
+
+ ./autogen.sh
+}
+
+pkgver() {
+ cd dosbox
+
+ local _version
+ local _revision
+
+ _version="$(head -n1 VERSION | sed 's/-/./g')"
+ _revision="$(svnversion | tr -d 'A-z')"
+
+ printf '%s.r%s' "$_version" "$_revision"
+}
+
+build() {
+ cd dosbox
+
+ ./configure --prefix='/usr' --sysconfdir='/etc/dosbox'
+
+ make
+}
+
+package() {
+ cd dosbox
+
+ make DESTDIR="$pkgdir" install
+
+ # glide2x.ovl
+ install -D -m644 "${srcdir}/glide2x.ovl" -t "${pkgdir}/usr/share/dosbox"
+
+ # desktop file and icon
+ install -D -m644 "${srcdir}/dosbox.desktop" -t "${pkgdir}/usr/share/applications"
+ install -D -m644 "${srcdir}/dosbox.png" -t "${pkgdir}/usr/share/pixmaps"
+
+ # docs
+ install -D -m644 README -t "${pkgdir}/usr/share/doc/dosbox"
+ install -D -m644 docs/README.video -t "${pkgdir}/usr/share/doc/dosbox"
+}
diff --git a/dosbox-openglide-svn.patch b/dosbox-openglide-svn.patch
new file mode 100644
index 000000000000..2c4ecbe636d1
--- /dev/null
+++ b/dosbox-openglide-svn.patch
@@ -0,0 +1,2642 @@
+diff -Nawurp a/configure.ac b/configure.ac
+--- a/configure.ac 2019-06-15 00:25:54.000000000 +0000
++++ b/configure.ac 2019-06-15 00:40:57.000000000 +0000
+@@ -557,7 +557,7 @@ int main(int argc,char * argv[]) {
+ dnl Some target detection and actions for them
+ case "$host" in
+ *-*-cygwin* | *-*-mingw32*)
+- LIBS="$LIBS -lwinmm"
++ LIBS="$LIBS -lwinmm -lshlwapi"
+ AC_DEFINE(C_DIRECTSERIAL, 1, [ Define to 1 if you want serial passthrough support (Win32, Posix and OS/2 only).])
+ if test x$have_sdl_net_lib = xyes -a x$have_sdl_net_h = xyes ; then
+ LIBS="$LIBS -lws2_32"
+diff -Nawurp a/include/glidedef.h b/include/glidedef.h
+--- a/include/glidedef.h 1970-01-01 00:00:00.000000000 +0000
++++ b/include/glidedef.h 2019-06-15 00:25:58.000000000 +0000
+@@ -0,0 +1,179 @@
++/*
++ * Copyright (C) 2002-2007 The DOSBox Team
++ *
++ * 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 GLIDEDEF_H
++#define GLIDEDEF_H
++
++#ifdef DOSBOX_DOSBOX_H
++struct GLIDE_Block
++{
++ bool splash;
++ bool enabled;
++ bool * fullscreen;
++ Bit16u width, height;
++ class GLIDE_PageHandler * lfb_pagehandler;
++ GLIDE_Block():enabled(false),fullscreen(0),width(0),height(0),lfb_pagehandler((GLIDE_PageHandler*)0) { }
++};
++extern GLIDE_Block glide;
++extern void GLIDE_ResetScreen(bool update=false);
++extern void GLIDE_DisableScreen(void);
++#endif
++
++#define GLIDE_LFB 0x60000000
++#define GLIDE_BUFFERS 3 /* Front, Back, AUX */
++#define GLIDE_PAGE_BITS 11 /* =2048 pages per buffer, should be enough for 1600x1200x4 */
++#define GLIDE_PAGES (GLIDE_BUFFERS*(1<<GLIDE_PAGE_BITS))
++
++#ifdef __3DFX_H__
++/* If you change these defines, don't forget to change the table in glide.h and compile a matching GLIDE2X.OVL */
++
++#define _grAADrawLine8 0 // void grAADrawLine(GrVertex *va, GrVertex *vb)
++#define _grAADrawPoint4 1 // void grAADrawPoint(GrVertex *p)
++#define _grAADrawPolygon12 2 // void grAADrawPolygon(int nVerts, const int ilist[], const GrVertex vlist[])
++#define _grAADrawPolygonVertexList8 3 // void grAADrawPolygonVertexList(int nVerts, const GrVertex vlist[])
++#define _grAADrawTriangle24 4 // void grAADrawTriangle(GrVertex *a, GrVertex *b, GrVertex *c, FxBool antialiasAB, FxBool antialiasBC, FxBool antialiasCA)
++#define _grAlphaBlendFunction16 5 // void grAlphaBlendFunction(GrAlphaBlendFnc_t rgb_sf, GrAlphaBlendFnc_t rgb_df, GrAlphaBlendFnc_t alpha_sf, GrAlphaBlendFnc_t alpha_df)
++#define _grAlphaCombine20 6 // void grAlphaCombine(GrCombineFunction_t func, GrCombineFactor_t factor, GrCombineLocal_t local, GrCombineOther_t other, FxBool invert)
++#define _grAlphaControlsITRGBLighting4 7 // void grAlphaControlsITRGBLighting(FxBool enable)
++#define _grAlphaTestFunction4 8 // void grAlphaTestFunction(GrCmpFnc_t function)
++#define _grAlphaTestReferenceValue4 9 // void grAlphaTestReferenceValue(GrAlpha_t value)
++#define _grBufferClear12 10 // void grBufferClear(GrColor_t color, GrAlpha_t alpha, FxU16 depth)
++#define _grBufferNumPending0 11 // int grBufferNumPending(void)
++#define _grBufferSwap4 12 // void grBufferSwap(int swap_interval)
++#define _grCheckForRoom4 13 // void grCheckForRoom(FxI32 n)
++#define _grChromakeyMode4 14 // void grChromakeyMode(GrChromakeyMode_t mode)
++#define _grChromakeyValue4 15 // void grChromakeyValue(GrColor_t value)
++#define _grClipWindow16 16 // void grClipWindow(FxU32 minx, FxU32 miny, FxU32 maxx, FxU32 maxy)
++#define _grColorCombine20 17 // void grColorCombine(GrCombineFunction_t func, GrCombineFactor_t factor, GrCombineLocal_t local, GrCombineOther_t other, FxBool invert)
++#define _grColorMask8 18 // void grColorMask(FxBool rgb, FxBool alpha)
++#define _grConstantColorValue416 19 // void grConstantColorValue4(float a, float r, float g, float b)
++#define _grConstantColorValue4 20 // void grConstantColorValue(GrColor_t color)
++#define _grCullMode4 21 // void grCullMode(GrCullMode_t mode)
++#define _grDepthBiasLevel4 22 // void grDepthBiasLevel(FxI16 level)
++#define _grDepthBufferFunction4 23 // void grDepthBufferFunction(GrCmpFnc_t func)
++#define _grDepthBufferMode4 24 // void grDepthBufferMode(GrDepthBufferMode_t mode)
++#define _grDepthMask4 25 // void grDepthMask(FxBool enable)
++#define _grDisableAllEffects0 26 // void grDisableAllEffects(void)
++#define _grDitherMode4 27 // void grDitherMode(GrDitherMode_t mode)
++#define _grDrawLine8 28 // void grDrawLine(const GrVertex *a, const GrVertex *b)
++#define _grDrawPlanarPolygon12 29 // void grDrawPlanarPolygon(int nVerts, int ilist[], const GrVertex vlist[])
++#define _grDrawPlanarPolygonVertexList8 30 // void grDrawPlanarPolygonVertexList(int nVerts, const GrVertex vlist[])
++#define _grDrawPoint4 31 // void grDrawPoint(const GrVertex *a)
++#define _grDrawPolygon12 32 // void grDrawPolygon(int nVerts, int ilist[], const GrVertex vlist[])
++#define _grDrawPolygonVertexList8 33 // void grDrawPolygonVertexList(int nVerts, const GrVertex vlist[])
++#define _grDrawTriangle12 34 // void grDrawTriangle(const GrVertex *a, const GrVertex *b, const GrVertex *c)
++#define _grErrorSetCallback4 35 // void grErrorSetCallback(void (*function)(const char *string, FxBool fatal))
++#define _grFogColorValue4 36 // void grFogColorValue(GrColor_t value)
++#define _grFogMode4 37 // void grFogMode(GrFogMode_t mode)
++#define _grFogTable4 38 // void grFogTable(const GrFog_t table[GR_FOG_TABLE_SIZE])
++#define _grGammaCorrectionValue4 39 // void grGammaCorrectionValue(float value)
++#define _grGlideGetState4 40 // void grGlideGetState(GrState *state)
++#define _grGlideGetVersion4 41 // void grGlideGetVersion(char version[80])
++#define _grGlideInit0 42 // void grGlideInit(void)
++#define _grGlideSetState4 43 // void grGlideSetState(const GrState *state)
++#define _grGlideShamelessPlug4 44 // void grGlideShamelessPlug(const FxBool on)
++#define _grGlideShutdown0 45 // void grGlideShutdown(void)
++#define _grHints8 46 // void grHints(GrHint_t type, FxU32 hintMask)
++#define _grLfbConstantAlpha4 47 // void grLfbConstantAlpha(GrAlpha_t alpha)
++#define _grLfbConstantDepth4 48 // void grLfbConstantDepth(FxU16 depth)
++#define _grLfbLock24 49 // FxBool grLfbLock(GrLock_t type, GrBuffer_t buffer, GrLfbWriteMode_t writeMode, GrOriginLocation_t origin, FxBool pixelPipeline, GrLfbInfo_t *info)
++#define _grLfbReadRegion28 50 // FxBool grLfbReadRegion(GrBuffer_t src_buffer, FxU32 src_x, FxU32 src_y, FxU32 src_width, FxU32 src_height, FxU32 dst_stride, void *dst_data)
++#define _grLfbUnlock8 51 // FxBool grLfbUnlock(GrLock_t type, GrBuffer_t buffer)
++#define _grLfbWriteColorFormat4 52 // void grLfbWriteColorFormat(GrColorFormat_t colorFormat)
++#define _grLfbWriteColorSwizzle8 53 // void grLfbWriteColorSwizzle(FxBool swizzleBytes, FxBool swapWords)
++#define _grLfbWriteRegion32 54 // FxBool grLfbWriteRegion(GrBuffer_t dst_buffer, FxU32 dst_x, FxU32 dst_y, GrLfbSrcFmt_t src_format, FxU32 src_width, FxU32 src_height, FxU32 src_stride, void *src_data)
++#define _grRenderBuffer4 55 // void grRenderBuffer(GrBuffer_t buffer)
++#define _grResetTriStats0 56 // void grResetTriStats()
++#define _grSplash20 57 // void grSplash(float x, float y, float width, float height, FxU32 frame)
++#define _grSstConfigPipeline12 58 //
++#define _grSstControl4 59 // FxBool grSstControl(FxU32 code)
++#define _grSstIdle0 60 // void grSstIdle(void)
++#define _grSstIsBusy0 61 // FxBool grSstIsBusy(void)
++#define _grSstOrigin4 62 // void grSstOrigin(GrOriginLocation_t origin)
++#define _grSstPerfStats4 63 // void grSstPerfStats(GrSstPerfStats_t *pStats)
++#define _grSstQueryBoards4 64 // FxBool grSstQueryBoards(GrHwConfiguration *hwConfig)
++#define _grSstQueryHardware4 65 // FxBool grSstQueryHardware(GrHwConfiguration *hwConfig)
++#define _grSstResetPerfStats0 66 // void grSstResetPerfStats(void)
++#define _grSstScreenHeight0 67 // FxU32 grSstScreenHeight(void)
++#define _grSstScreenWidth0 68 // FxU32 grSstScreenWidth(void)
++#define _grSstSelect4 69 // void grSstSelect(int which_sst)
++#define _grSstStatus0 70 // FxU32 grSstStatus(void)
++#define _grSstVRetraceOn0 71 // FxBool grSstVRetraceOn(void)
++#define _grSstVidMode8 72 //
++#define _grSstVideoLine0 73 // FxU32 grSstVideoLine(void)
++#define _grSstWinClose0 74 // void grSstWinClose(void)
++#define _grSstWinOpen28 75 // FxBool grSstWinOpen(FxU32 hwnd, GrScreenResolution_t res, GrScreenRefresh_t ref, GrColorFormat_t cformat, GrOriginLocation_t org_loc, int num_buffers, int num_aux_buffers)
++#define _grTexCalcMemRequired16 76 // FxU32 grTexCalcMemRequired(GrLOD_t smallLod, GrLOD_t largeLod, GrAspectRatio_t aspect, GrTextureFormat_t format)
++#define _grTexClampMode12 77 // void grTexClampMode(GrChipID_t tmu, GrTextureClampMode_t sClampMode, GrTextureClampMode_t tClampMode)
++#define _grTexCombine28 78 // void grTexCombine(GrChipID_t tmu, GrCombineFunction_t rgb_function, GrCombineFactor_t rgb_factor, GrCombineFunction_t alpha_function, GrCombineFactor_t alpha_factor, FxBool rgb_invert, FxBool alpha_invert)
++#define _grTexCombineFunction8 79 // void grTexCombineFunction(GrChipID_t tmu, GrTextureCombineFnc_t fnc)
++#define _grTexDetailControl16 80 // void grTexDetailControl(GrChipID_t tmu, int lodBias, FxU8 detailScale, float detailMax)
++#define _grTexDownloadMipMap16 81 // void grTexDownloadMipMap(GrChipID_t tmu, FxU32 startAddress, FxU32 evenOdd, GrTexInfo *info)
++#define _grTexDownloadMipMapLevel32 82 // void grTexDownloadMipMapLevel(GrChipID_t tmu, FxU32 startAddress, GrLOD_t thisLod, GrLOD_t largeLod, GrAspectRatio_t aspectRatio, GrTextureFormat_t format, FxU32 evenOdd, void *data)
++#define _grTexDownloadMipMapLevelPartial40 83 // void grTexDownloadMipMapLevelPartial(GrChipID_t tmu, FxU32 startAddress, GrLOD_t thisLod, GrLOD_t largeLod, GrAspectRatio_t aspectRatio, GrTextureFormat_t format, FxU32 evenOdd, void *data, int start, int end)
++#define _grTexDownloadTable12 84 // void grTexDownloadTable(GrChipID_t tmu, GrTexTable_t type, void *data)
++#define _grTexDownloadTablePartial20 85 // void grTexDownloadTablePartial(GrChipID_t tmu, GrTexTable_t type, void *data, int start, int end)
++#define _grTexFilterMode12 86 // void grTexFilterMode(GrChipID_t tmu, GrTextureFilterMode_t minFilterMode, GrTextureFilterMode_t magFilterMode)
++#define _grTexLodBiasValue8 87 // void grTexLodBiasValue(GrChipID_t tmu, float bias)
++#define _grTexMaxAddress4 88 // FxU32 grTexMaxAddress(GrChipID_t tmu)
++#define _grTexMinAddress4 89 // FxU32 grTexMinAddress(GrChipID_t tmu)
++#define _grTexMipMapMode12 90 // void grTexMipMapMode(GrChipID_t tmu, GrMipMapMode_t mode, FxBool lodBlend)
++#define _grTexMultibase8 91 // void grTexMultibase(GrChipID_t tmu, FxBool enable)
++#define _grTexMultibaseAddress20 92 // void grTexMultibaseAddress(GrChipID_t tmu, GrTexBaseRange_t range, FxU32 startAddress, FxU32 evenOdd, GrTexInfo *info)
++#define _grTexNCCTable8 93 // void grTexNCCTable(GrChipID_t tmu, GrNCCTable_t table)
++#define _grTexSource16 94 // void grTexSource(GrChipID_t tmu, FxU32 startAddress, FxU32 evenOdd, GrTexInfo *info)
++#define _grTexTextureMemRequired8 95 // FxU32 grTexTextureMemRequired(FxU32 evenOdd, GrTexInfo *info)
++#define _grTriStats8 96 // void grTriStats(FxU32 *trisProcessed, FxU32 *trisDrawn)
++#define _gu3dfGetInfo8 97 // FxBool gu3dfGetInfo(const char *filename, Gu3dfInfo *info)
++#define _gu3dfLoad8 98 // FxBool gu3dfLoad(const char *filename, Gu3dfInfo *info)
++#define _guAADrawTriangleWithClip12 99 // void guAADrawTriangleWithClip(const GrVertex *va, const GrVertex *vb, const GrVertex *vc)
++#define _guAlphaSource4 100 // void guAlphaSource(GrAlphaSource_t mode)
++#define _guColorCombineFunction4 101 // void guColorCombineFunction(GrColorCombineFnc_t func)
++#define _guDrawPolygonVertexListWithClip8 102 // void guDrawPolygonVertexListWithClip(int nverts, const GrVertex vlist[])
++#define _guDrawTriangleWithClip12 103 // void guDrawTriangleWithClip(const GrVertex *va, const GrVertex *vb, const GrVertex *vc)
++#define _guEncodeRLE1616 104 //
++#define _guEndianSwapBytes4 105 //
++#define _guEndianSwapWords4 106 //
++#define _guFogGenerateExp28 107 // void guFogGenerateExp2(GrFog_t fogTable[GR_FOG_TABLE_SIZE], float density)
++#define _guFogGenerateExp8 108 // void guFogGenerateExp(GrFog_t fogTable[GR_FOG_TABLE_SIZE], float density)
++#define _guFogGenerateLinear12 109 // void guFogGenerateLinear(GrFog_t fogTable[GR_FOG_TABLE_SIZE], float nearW, float farW)
++#define _guFogTableIndexToW4 110 // float guFogTableIndexToW(int i)
++#define _guMPDrawTriangle12 111 //
++#define _guMPInit0 112 //
++#define _guMPTexCombineFunction4 113 //
++#define _guMPTexSource8 114 //
++#define _guMovieSetName4 115 //
++#define _guMovieStart0 116 //
++#define _guMovieStop0 117 //
++#define _guTexAllocateMemory60 118 // GrMipMapId_t guTexAllocateMemory(GrChipID_t tmu, FxU8 evenOddMask, int width, int height, GrTextureFormat_t format, GrMipMapMode_t mmMode, GrLOD_t smallLod, GrLOD_t largeLod, GrAspectRatio_t aspectRatio, GrTextureClampMode_t sClampMode, GrTextureClampMode_t tClampMode, GrTextureFilterMode_t minFilterMode, GrTextureFilterMode_t magFilterMode, float lodBias, FxBool lodBlend)
++#define _guTexChangeAttributes48 119 // FxBool guTexChangeAttributes(GrMipMapID_t mmid, int width, int height, GrTextureFormat_t format, GrMipMapMode_t mmMode, GrLOD_t smallLod, GrLOD_t largeLod, GrAspectRatio_t aspectRatio, GrTextureClampMode_t sClampMode, GrTextureClampMode_t tClampMode, GrTextureFilterMode_t minFilterMode, GrTextureFilterMode_t magFilterMode)
++#define _guTexCombineFunction8 120 // void guTexCombineFunction(GrChipID_t tmu, GrTextureCombineFnc_t func)
++#define _guTexCreateColorMipMap0 121 //
++#define _guTexDownloadMipMap12 122 // void guTexDownloadMipMap(GrMipMapId_t mmid, const void *src, const GuNccTable *nccTable)
++#define _guTexDownloadMipMapLevel12 123 // void guTexDownloadMipMapLevel(GrMipMapId_t mmid, GrLOD_t lod, const void **src)
++#define _guTexGetCurrentMipMap4 124 // GrMipMapId_t guTexGetCurrentMipMap (GrChipID_t tmu)
++#define _guTexGetMipMapInfo4 125 // GrMipMapInfo *guTexGetMipMapInfo(GrMipMapId_t mmid)
++#define _guTexMemQueryAvail4 126 // FxU32 guTexMemQueryAvail(GrChipID_t tmu)
++#define _guTexMemReset0 127 // void guTexMemReset(void)
++#define _guTexSource4 128 // void guTexSource(GrMipMapId_t mmid)
++#define _ConvertAndDownloadRle64 129 // void ConvertAndDownloadRle(GrChipID_t tmu, FxU32 startAddress, GrLOD_t thisLod, GrLOD_t largeLod, GrAspectRatio_t aspectRatio, GrTextureFormat_t format, FxU32 evenOdd, FxU8 *bm_data, long bm_h, FxU32 u0, FxU32 v0, FxU32 width, FxU32 height, FxU32 dest_width, FxU32 dest_height, FxU16 *tlut)
++#define GLIDE_MAX 129
++
++#endif // __3DFX_H__
++
++#endif // GLIDEDEF_H
+diff -Nawurp a/include/glide.h b/include/glide.h
+--- a/include/glide.h 1970-01-01 00:00:00.000000000 +0000
++++ b/include/glide.h 2019-06-15 00:25:58.000000000 +0000
+@@ -0,0 +1,331 @@
++/*
++ * Copyright (C) 2002-2007 The DOSBox Team
++ *
++ * 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 DOSBOX_GLIDE_H
++#define DOSBOX_GLIDE_H
++
++#define __3DFX_H__
++
++/*
++** basic data types
++*/
++typedef Bit8u FxU8;
++typedef Bit8s FxI8;
++typedef Bit16u FxU16;
++typedef Bit16s FxI16;
++typedef Bit32u FxU32;
++typedef Bit32s FxI32;
++typedef Bit32s FxBool;
++typedef float FxFloat;
++typedef double FxDouble;
++
++/*
++** color types
++*/
++typedef Bit32u FxColor_t;
++typedef struct { float r, g, b, a; } FxColor4;
++
++/*
++** fundamental types
++*/
++#define FXTRUE 1
++#define FXFALSE 0
++
++/*
++** helper macros
++*/
++#define FXUNUSED( a ) ((void)(a))
++#define FXBIT( i ) ( 1L << (i) )
++
++#define FX_ENTRY
++#define FX_GLIDE_NO_FUNC_PROTO
++
++#if defined (WIN32)
++#define FX_CALL __stdcall
++#else
++#define FX_CALL
++#endif
++
++#include <openglide/sdk2_glide.h>
++#include "glidedef.h"
++
++// Careful with structures containing pointers
++//
++// GrTexInfo; GrLfbInfo_t; Gu3dfInfo; GrMipMapInfo;
++//
++
++// Some glide structs might have different size in guest 32-bit DOS (pointers)
++typedef struct {
++ Bit32s smallLod;
++ Bit32s largeLod;
++ Bit32s aspectRatio;
++ Bit32s format;
++ PhysPt data;
++} DBGrTexInfo;
++
++typedef struct {
++ Bit32s size;
++ PhysPt lfbPtr;
++ Bit32u strideInBytes;
++ Bit32s writeMode;
++ Bit32s origin;
++} DBGrLfbInfo_t;
++
++typedef struct {
++ Gu3dfHeader header;
++ GuTexTable table;
++ PhysPt data;
++ Bit32u mem_required;
++} DBGu3dfInfo;
++
++typedef struct {
++ const char * name;
++ const Bit8u parms;
++} GLIDE_TABLE;
++
++typedef void (FX_CALL *pfunc0) (void);
++typedef void (FX_CALL *pfunc1i) (FxU32);
++typedef void (FX_CALL *pfunc1p) (void*);
++typedef void (FX_CALL *pfunc1f) (float);
++typedef void (FX_CALL *pfunc2i) (FxU32, FxU32);
++typedef void (FX_CALL *pfunc1i1p) (FxU32, void*);
++typedef void (FX_CALL *pfunc2p) (void*, void*);
++typedef void (FX_CALL *pfunc1i1f) (FxU32, float);
++typedef void (FX_CALL *pfunc1p1f) (void*, float);
++typedef void (FX_CALL *pfunc3i) (FxU32, FxU32, FxU32);
++typedef void (FX_CALL *pfunc2i1p) (FxU32, FxU32, void*);
++typedef void (FX_CALL *pfunc1i2p) (FxU32, void*, void*);
++typedef void (FX_CALL *pfunc3p) (void*, void*, void*);
++typedef void (FX_CALL *pfunc1p2f) (void*, float, float);
++typedef void (FX_CALL *pfunc4i) (FxU32, FxU32, FxU32, FxU32);
++typedef void (FX_CALL *pfunc3i1p) (FxU32, FxU32, FxU32, void*);
++typedef void (FX_CALL *pfunc3i1f) (FxU32, FxU32, FxU32, float);
++typedef void (FX_CALL *pfunc4f) (float, float, float, float);
++typedef void (FX_CALL *pfunc5i) (FxU32, FxU32, FxU32, FxU32, FxU32);
++typedef void (FX_CALL *pfunc2i1p2i) (FxU32, FxU32, void*, FxU32, FxU32);
++typedef void (FX_CALL *pfunc4f1i) (float, float, float, float, FxU32);
++typedef void (FX_CALL *pfunc3p3i) (void*, void*, void*, FxU32, FxU32, FxU32);
++typedef void (FX_CALL *pfunc7i) (FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, FxU32);
++typedef void (FX_CALL *pfunc7i1p) (FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, void*);
++typedef void (FX_CALL *pfunc7i1p2i) (FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, void*,
++ FxU32, FxU32);
++typedef void (FX_CALL *pfunc7i1p7i1p) (FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, void*,
++ FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, void*);
++
++typedef FxU32 (FX_CALL *prfunc0) (void);
++typedef FxU32 (FX_CALL *prfunc1i) (FxU32);
++typedef FxU32 (FX_CALL *prfunc1p) (void*);
++typedef FxU32 (FX_CALL *prfunc2i) (FxU32, FxU32);
++typedef FxU32 (FX_CALL *prfunc1i1p) (FxU32, void*);
++typedef FxU32 (FX_CALL *prfunc2p) (void*, void*);
++typedef FxU32 (FX_CALL *prfunc4i) (FxU32, FxU32, FxU32, FxU32);
++typedef FxU32 (FX_CALL *prfunc5i1p) (FxU32, FxU32, FxU32, FxU32, FxU32, void*);
++typedef FxU32 (FX_CALL *prfunc7i) (FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, FxU32);
++typedef FxU32 (FX_CALL *prfunc1p6i) (void*, FxU32, FxU32, FxU32, FxU32, FxU32, FxU32);
++typedef FxU32 (FX_CALL *prfunc6i1p) (FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, void*);
++typedef FxU32 (FX_CALL *prfunc7i1p) (FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, void*);
++typedef FxU32 (FX_CALL *prfunc12i) (FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, FxU32,
++ FxU32, FxU32, FxU32, FxU32, FxU32);
++typedef FxU32 (FX_CALL *prfunc13i1f1i) (FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, FxU32, FxU32,
++ FxU32, FxU32, FxU32, FxU32, FxU32, float, FxU32);
++
++typedef void* (FX_CALL *prptfunc1i) (FxU32);
++typedef float (FX_CALL *pffunc1i) (FxU32);
++
++typedef union {
++ pfunc0 grFunction0;
++ pfunc1i grFunction1i;
++ pfunc1p grFunction1p;
++ pfunc1f grFunction1f;
++ pfunc2i grFunction2i;
++ pfunc1i1p grFunction1i1p;
++ pfunc2p grFunction2p;
++ pfunc1i1f grFunction1i1f;
++ pfunc1p1f grFunction1p1f;
++ pfunc3i grFunction3i;
++ pfunc2i1p grFunction2i1p;
++ pfunc1i2p grFunction1i2p;
++ pfunc3p grFunction3p;
++ pfunc1p2f grFunction1p2f;
++ pfunc4i grFunction4i;
++ pfunc3i1p grFunction3i1p;
++ pfunc3i1f grFunction3i1f;
++ pfunc4f grFunction4f;
++ pfunc5i grFunction5i;
++ pfunc2i1p2i grFunction2i1p2i;
++ pfunc4f1i grFunction4f1i;
++ pfunc3p3i grFunction3p3i;
++ pfunc7i grFunction7i;
++ pfunc7i1p grFunction7i1p;
++ pfunc7i1p2i grFunction7i1p2i;
++ pfunc7i1p7i1p grFunction7i1p7i1p;
++
++ prfunc0 grRFunction0;
++ prfunc1i grRFunction1i;
++ prfunc1p grRFunction1p;
++ prfunc2i grRFunction2i;
++ prfunc1i1p grRFunction1i1p;
++ prfunc2p grRFunction2p;
++ prfunc4i grRFunction4i;
++ prfunc5i1p grRFunction5i1p;
++ prfunc7i grRFunction7i;
++ prfunc1p6i grRFunction1p6i;
++ prfunc6i1p grRFunction6i1p;
++ prfunc7i1p grRFunction7i1p;
++ prfunc12i grRFunction12i;
++ prfunc13i1f1i grRFunction13i1f1i;
++
++ prptfunc1i grRPTFunction1i;
++
++ pffunc1i grFFunction1i;
++} FncPointers;
++
++static const GLIDE_TABLE grTable[] = {
++ { "grAADrawLine", 8 },
++ { "grAADrawPoint", 4 },
++ { "grAADrawPolygon", 12 },
++ { "grAADrawPolygonVertexList", 8 },
++ { "grAADrawTriangle", 24 },
++ { "grAlphaBlendFunction", 16 },
++ { "grAlphaCombine", 20 },
++ { "grAlphaControlsITRGBLighting", 4 },
++ { "grAlphaTestFunction", 4 },
++ { "grAlphaTestReferenceValue", 4 },
++ { "grBufferClear", 12 },
++ { "grBufferNumPending", 0 },
++ { "grBufferSwap", 4 },
++ { "grCheckForRoom", 4 },
++ { "grChromakeyMode", 4 },
++ { "grChromakeyValue", 4 },
++ { "grClipWindow", 16 },
++ { "grColorCombine", 20 },
++ { "grColorMask", 8 },
++ { "grConstantColorValue4", 16 },
++ { "grConstantColorValue", 4 },
++ { "grCullMode", 4 },
++ { "grDepthBiasLevel", 4 },
++ { "grDepthBufferFunction", 4 },
++ { "grDepthBufferMode", 4 },
++ { "grDepthMask", 4 },
++ { "grDisableAllEffects", 0 },
++ { "grDitherMode", 4 },
++ { "grDrawLine", 8 },
++ { "grDrawPlanarPolygon", 12 },
++ { "grDrawPlanarPolygonVertexList", 8 },
++ { "grDrawPoint", 4 },
++ { "grDrawPolygon", 12 },
++ { "grDrawPolygonVertexList", 8 },
++ { "grDrawTriangle", 12 },
++ { "grErrorSetCallback", 4 },
++ { "grFogColorValue", 4 },
++ { "grFogMode", 4 },
++ { "grFogTable", 4 },
++ { "grGammaCorrectionValue", 4 },
++ { "grGlideGetState", 4 },
++ { "grGlideGetVersion", 4 },
++ { "grGlideInit", 0 },
++ { "grGlideSetState", 4 },
++ { "grGlideShamelessPlug", 4 },
++ { "grGlideShutdown", 0 },
++ { "grHints", 8 },
++ { "grLfbConstantAlpha", 4 },
++ { "grLfbConstantDepth", 4 },
++ { "grLfbLock", 24 },
++ { "grLfbReadRegion", 28 },
++ { "grLfbUnlock", 8 },
++ { "grLfbWriteColorFormat", 4 },
++ { "grLfbWriteColorSwizzle", 8 },
++ { "grLfbWriteRegion", 32 },
++ { "grRenderBuffer", 4 },
++ { "grResetTriStats", 0 },
++ { "grSplash", 20 },
++ { "grSstConfigPipeline", 12 },
++ { "grSstControl", 4 },
++ { "grSstIdle", 0 },
++ { "grSstIsBusy", 0 },
++ { "grSstOrigin", 4 },
++ { "grSstPerfStats", 4 },
++ { "grSstQueryBoards", 4 },
++ { "grSstQueryHardware", 4 },
++ { "grSstResetPerfStats", 0 },
++ { "grSstScreenHeight", 0 },
++ { "grSstScreenWidth", 0 },
++ { "grSstSelect", 4 },
++ { "grSstStatus", 0 },
++ { "grSstVRetraceOn", 0 },
++ { "grSstVidMode", 8 },
++ { "grSstVideoLine", 0 },
++ { "grSstWinClose", 0 },
++ { "grSstWinOpen", 28 },
++ { "grTexCalcMemRequired", 16 },
++ { "grTexClampMode", 12 },
++ { "grTexCombine", 28 },
++ { "grTexCombineFunction", 8 },
++ { "grTexDetailControl", 16 },
++ { "grTexDownloadMipMap", 16 },
++ { "grTexDownloadMipMapLevel", 32 },
++ { "grTexDownloadMipMapLevelPartial", 40 },
++ { "grTexDownloadTable", 12 },
++ { "grTexDownloadTablePartial", 20 },
++ { "grTexFilterMode", 12 },
++ { "grTexLodBiasValue", 8 },
++ { "grTexMaxAddress", 4 },
++ { "grTexMinAddress", 4 },
++ { "grTexMipMapMode", 12 },
++ { "grTexMultibase", 8 },
++ { "grTexMultibaseAddress", 20 },
++ { "grTexNCCTable", 8 },
++ { "grTexSource", 16 },
++ { "grTexTextureMemRequired", 8 },
++ { "grTriStats", 8 },
++ { "gu3dfGetInfo", 8 },
++ { "gu3dfLoad", 8 },
++ { "guAADrawTriangleWithClip", 12 },
++ { "guAlphaSource", 4 },
++ { "guColorCombineFunction", 4 },
++ { "guDrawPolygonVertexListWithClip", 8 },
++ { "guDrawTriangleWithClip", 12 },
++ { "guEncodeRLE16", 16 },
++ { "guEndianSwapBytes", 4 },
++ { "guEndianSwapWords", 4 },
++ { "guFogGenerateExp2", 8 },
++ { "guFogGenerateExp", 8 },
++ { "guFogGenerateLinear", 12 },
++ { "guFogTableIndexToW", 4 },
++ { "guMPDrawTriangle", 12 },
++ { "guMPInit", 0 },
++ { "guMPTexCombineFunction", 4 },
++ { "guMPTexSource", 8 },
++ { "guMovieSetName", 4 },
++ { "guMovieStart", 0 },
++ { "guMovieStop", 0 },
++ { "guTexAllocateMemory", 60 },
++ { "guTexChangeAttributes", 48 },
++ { "guTexCombineFunction", 8 },
++ { "guTexCreateColorMipMap", 0 },
++ { "guTexDownloadMipMap", 12 },
++ { "guTexDownloadMipMapLevel", 12 },
++ { "guTexGetCurrentMipMap", 4 },
++ { "guTexGetMipMapInfo", 4 },
++ { "guTexMemQueryAvail", 4 },
++ { "guTexMemReset", 0 },
++ { "guTexSource", 4 },
++ { "ConvertAndDownloadRle", 64 }
++};
++
++#endif // DOSBOX_GLIDE_H
+diff -Nawurp a/include/mem.h b/include/mem.h
+--- a/include/mem.h 2019-06-15 00:25:57.000000000 +0000
++++ b/include/mem.h 2019-06-15 00:25:58.000000000 +0000
+@@ -152,6 +152,8 @@ static INLINE Bit32u phys_readd(PhysPt a
+
+ void MEM_BlockWrite(PhysPt pt,void const * const data,Bitu size);
+ void MEM_BlockRead(PhysPt pt,void * data,Bitu size);
++void MEM_BlockWrite32(PhysPt pt,void * data,Bitu size);
++void MEM_BlockRead32(PhysPt pt,void * data,Bitu size);
+ void MEM_BlockCopy(PhysPt dest,PhysPt src,Bitu size);
+ void MEM_StrCopy(PhysPt pt,char * data,Bitu size);
+
+diff -Nawurp a/src/dosbox.cpp b/src/dosbox.cpp
+--- a/src/dosbox.cpp 2019-06-15 00:25:56.000000000 +0000
++++ b/src/dosbox.cpp 2019-06-15 00:25:58.000000000 +0000
+@@ -81,6 +81,7 @@ void PCI_Init(Section*);
+
+ void KEYBOARD_Init(Section*); //TODO This should setup INT 16 too but ok ;)
+ void JOYSTICK_Init(Section*);
++void GLIDE_Init(Section*);
+ void MOUSE_Init(Section*);
+ void SBLASTER_Init(Section*);
+ void GUS_Init(Section*);
+@@ -744,6 +745,17 @@ void DOSBOX_Init(void) {
+ Pmulti_remain->Set_help("see serial1");
+
+
++ secprop=control->AddSection_prop("glide",&GLIDE_Init,true);
++ Pbool = secprop->Add_bool("glide",Property::Changeable::WhenIdle,false);
++ Pbool->Set_help("Enable glide emulation: true,false.");
++ //Phex = secprop->Add_hex("grport",Property::Changeable::WhenIdle,0x600);
++ //Phex->Set_help("I/O port to use for host communication.");
++ Pstring = secprop->Add_string("lfb",Property::Changeable::WhenIdle,"full_noaux");
++ Pstring->Set_help("LFB access: full,full_noaux,read,read_noaux,write,write_noaux,none.\n"
++ "OpenGlide does not support locking aux buffer, please use _noaux modes.");
++ Pbool = secprop->Add_bool("splash",Property::Changeable::WhenIdle,true);
++ Pbool->Set_help("Show 3dfx splash screen (requires 3dfxSpl2.dll).");
++
+ /* All the DOS Related stuff, which will eventually start up in the shell */
+ secprop=control->AddSection_prop("dos",&DOS_Init,false);//done
+ secprop->AddInitFunction(&XMS_Init,true);//done
+diff -Nawurp a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp
+--- a/src/gui/sdlmain.cpp 2019-06-15 00:25:54.000000000 +0000
++++ b/src/gui/sdlmain.cpp 2019-06-15 00:25:58.000000000 +0000
+@@ -49,6 +49,7 @@
+ #include "cpu.h"
+ #include "cross.h"
+ #include "control.h"
++#include "glidedef.h"
+
+ #define MAPPERFILE "mapper-" VERSION ".map"
+ //#define DISABLE_JOYSTICK
+@@ -438,6 +439,10 @@ check_gotbpp:
+
+
+ void GFX_ResetScreen(void) {
++ if(glide.enabled) {
++ GLIDE_ResetScreen(true);
++ return;
++ }
+ GFX_Stop();
+ if (sdl.draw.callback)
+ (sdl.draw.callback)( GFX_CallBackReset );
+@@ -846,6 +851,9 @@ void GFX_SwitchFullScreen(void) {
+ sticky_keys(true); //restore sticky keys to default state in windowed mode.
+ #endif
+ }
++ if (glide.enabled)
++ GLIDE_ResetScreen();
++ else
+ GFX_ResetScreen();
+ }
+
+@@ -1663,7 +1671,7 @@ void GFX_Events() {
+ throw(0);
+ break;
+ case SDL_VIDEOEXPOSE:
+- if (sdl.draw.callback) sdl.draw.callback( GFX_CallBackRedraw );
++ if ((sdl.draw.callback) && (!glide.enabled)) sdl.draw.callback( GFX_CallBackRedraw );
+ break;
+ #ifdef WIN32
+ case SDL_KEYDOWN:
+@@ -2103,6 +2111,7 @@ int main(int argc, char* argv[]) {
+ if (strcmp(sdl_drv_name,"windib")==0) LOG_MSG("SDL_Init: Starting up with SDL windib video driver.\n Try to update your video card and directx drivers!");
+ }
+ #endif
++ glide.fullscreen = &sdl.desktop.fullscreen;
+ sdl.num_joysticks=SDL_NumJoysticks();
+
+ /* Parse configuration files */
+diff -Nawurp a/src/hardware/glide.cpp b/src/hardware/glide.cpp
+--- a/src/hardware/glide.cpp 1970-01-01 00:00:00.000000000 +0000
++++ b/src/hardware/glide.cpp 2019-06-15 00:25:58.000000000 +0000
+@@ -0,0 +1,1962 @@
++/*
++ * Copyright (C) 2002-2013 The DOSBox Team
++ *
++ * 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 Library 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 "dosbox.h"
++#include "inout.h"
++#include "mem.h"
++#include "paging.h"
++#include "glide.h"
++#include "setup.h"
++#include "vga.h"
++#include "dos_inc.h" /* for Drives[] */
++#include "control.h"
++#include "../dos/drives.h"
++
++#include <iomanip>
++#include <sstream>
++using namespace std;
++
++#include "SDL.h"
++
++#if defined (WIN32)
++#include "SDL_syswm.h"
++#include <windows.h>
++#include <Shlwapi.h>
++
++#ifdef _MSC_VER
++#pragma comment( lib, "Shlwapi" )
++#endif
++
++#else // *nix
++#include <dlfcn.h>
++
++#include <dirent.h>
++#include <errno.h>
++
++#endif
++
++extern void GFX_Stop(void);
++extern void GFX_ResetScreen(void);
++extern const char* RunningProgram;
++
++static float int_to_float(const Bit32u i)
++{
++ float f;
++ Bit32u i_native = SDL_SwapLE32(i);
++ SDL_memcpy(&f, &i_native, 4);
++ return f;
++}
++
++#define SAFE_DELETE(p) { if(p) { delete p; p = NULL; } }
++
++#define G_OK 1
++#define G_FAIL 0
++
++// Print debug messages
++#define LOG_GLIDE 0
++
++void VFILE_Remove(const char *name);
++static void process_msg(Bitu);
++
++/** Global Variables **/
++GLIDE_Block glide;
++
++// Pointers to loaded routines
++static FncPointers FP;
++static void ** fn_pt=NULL;
++
++// Shared memory
++static Bit32u param[20];
++
++// Pointer to return value
++static PhysPt ret;
++static Bit16u ret_value;
++
++// Temporary texture buffer
++static Bit32u texsize=0;
++static void* texmem=NULL;
++
++static HostPt hwnd=NULL;
++static char lfbacc=0;
++
++// Tomb Rider shadow hack
++static Bit8u tomb = 0;
++static FxI32 GrOriginLocation = 0;
++
++#if defined (WIN32)
++static HINSTANCE hdll=NULL; // Handle to glide2x lib file
++#else
++static void * hdll=NULL;
++#endif
++
++#if LOG_GLIDE
++static int GLIDE_count[GLIDE_MAX+2];
++#endif
++
++static Bitu read_gl(Bitu port,Bitu iolen)
++{
++ Bitu r=ret_value;
++#if LOG_GLIDE
++ if(ret_value == G_OK)
++ LOG_MSG("Glide:Port read. Return address: 0x%x, value: %d", ret, mem_readd(ret));
++ else if(ret_value == G_FAIL)
++ LOG_MSG("Glide:Port read. Return address: 0x%x, value: %d. Writing G_FAIL to port", ret, mem_readd(ret));
++ else
++ LOG_MSG("Glide:Port read. Returning %hu", ret_value);
++#endif
++
++ ret_value = ret_value >> 8;
++
++ return r;
++}
++
++static void write_gl(Bitu port,Bitu val,Bitu iolen)
++{
++ static Bit16u glsegment = 0;
++
++ ret = 0;
++ ret_value = G_FAIL;
++ FP.grFunction0 = NULL;
++
++ // Allocate shared memory (80 bytes)
++ if(val > GLIDE_MAX) {
++ if(glsegment==0) {
++ glsegment=DOS_GetMemory(5);
++#if LOG_GLIDE
++ LOG_MSG("Glide:Memory allocated at 0x%x (segment: %hu)", glsegment<<4, glsegment);
++#endif
++ }
++ ret_value=glsegment;
++ LOG_MSG("Glide:Activated");
++ return;
++ }
++
++ // Process function parameters (80 bytes)
++ MEM_BlockRead32(PhysMake(glsegment,0), param, 80);
++ process_msg(val);
++
++// LOG_MSG("Glide:Function %s executed OK", grTable[val].name);
++}
++
++class GLIDE_PageHandler : public PageHandler {
++private:
++ PhysPt base_addr[GLIDE_BUFFERS]; // GLIDE_LFB physical address
++ PhysPt lin_addr[GLIDE_BUFFERS]; // GLIDE_LFB linear address
++ HostPt lfb_addr[GLIDE_BUFFERS]; // Address offset from base_addr for the readable/writable buffers
++
++ /* Calculate physical address for access */
++ #define LFB_getAddr(addr) (lfb_addr[((addr - base_addr[0])>>12)>>GLIDE_PAGE_BITS]+addr)
++
++public:
++
++ FxU8 locked[GLIDE_BUFFERS];
++
++ GLIDE_PageHandler(HostPt addr, PhysPt phyaddr = GLIDE_LFB) {
++
++ if(addr == NULL) {
++ LOG_MSG("Glide:NULL address passed to pagehandler!");
++ }
++
++ /* Set base addresses */
++ for(int i = 0; i < GLIDE_BUFFERS; i++) {
++ locked[i] = 0;
++ base_addr[i] = phyaddr;
++ phyaddr += ((1<<GLIDE_PAGE_BITS)<<12);
++
++ /* store offset from base address */
++ lfb_addr[i] = (addr == NULL) ? NULL : (addr - base_addr[i]);
++ }
++
++ flags=PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE;
++ PAGING_UnlinkPages(base_addr[0]>>12, GLIDE_PAGES);
++#if LOG_GLIDE
++ LOG_MSG("Glide:GLIDE_PageHandler installed at 0x%x", base_addr[0]);
++#endif
++ }
++
++ ~GLIDE_PageHandler() {
++#if LOG_GLIDE
++ LOG_MSG("Glide:Resetting page handler at 0x%x", base_addr[0]);
++#endif
++ PAGING_UnlinkPages(base_addr[0]>>12, GLIDE_PAGES);
++ }
++
++ void SetLFBAddr(HostPt addr, Bitu buffer) {
++ if(buffer >= GLIDE_BUFFERS) return;
++
++ addr = addr - base_addr[buffer]; /* Calculate offset for current buffer */
++
++ if(addr != lfb_addr[buffer]) {
++ lfb_addr[buffer] = addr;
++#if LOG_GLIDE
++ LOG_MSG("Glide:LFB for buffer %d offset set to 0x%p (addr: 0x%p), clear TLB", buffer, lfb_addr[buffer], addr+base_addr[buffer]);
++#endif
++ PAGING_UnlinkPages(base_addr[buffer]>>12, 1<<GLIDE_PAGE_BITS);
++ }
++ }
++
++ PhysPt GetPhysPt(Bitu buffer = 0) {
++ if(buffer >= GLIDE_BUFFERS) return base_addr[0];
++ return base_addr[buffer];
++ }
++
++ void SetLinPt(PhysPt linaddr) {
++ for(int i = 0; i < GLIDE_BUFFERS; i++) {
++ lin_addr[i] = linaddr;
++ linaddr += ((1<<GLIDE_PAGE_BITS)<<12);
++ }
++ }
++
++ PhysPt GetLinPt(Bitu buffer = 0) {
++ if(buffer >= GLIDE_BUFFERS) return lin_addr[0];
++ return lin_addr[buffer];
++ }
++
++ Bitu readb(PhysPt addr) {
++// LOG_MSG("Glide:Read from 0x%p", LFB_getAddr(addr));
++ return *(Bit8u *)(LFB_getAddr(addr));
++ }
++
++ Bitu readw(PhysPt addr) {
++// LOG_MSG("Glide:Read from 0x%p", LFB_getAddr(addr));
++ return *(Bit16u *)(LFB_getAddr(addr));
++ }
++
++ Bitu readd(PhysPt addr) {
++// LOG_MSG("Glide:Read from 0x%p", LFB_getAddr(addr));
++ return *(Bit32u *)(LFB_getAddr(addr));
++ }
++
++ void writeb(PhysPt addr,Bitu val) {
++// LOG_MSG("Glide:Write to 0x%p", LFB_getAddr(addr));
++ *(Bit8u *)(LFB_getAddr(addr))=(Bit8u)val;
++ }
++
++ void writew(PhysPt addr,Bitu val) {
++// LOG_MSG("Glide:Write to 0x%p", LFB_getAddr(addr));
++ *(Bit16u *)(LFB_getAddr(addr))=(Bit16u)val;
++ }
++
++ void writed(PhysPt addr,Bitu val) {
++// LOG_MSG("Glide:Write to 0x%p", LFB_getAddr(addr));
++ *(Bit32u *)(LFB_getAddr(addr))=(Bit32u)val;
++ }
++
++ HostPt GetHostReadPt(Bitu phys_page) {
++ Bitu buffer = (((phys_page<<12) - base_addr[0])>>12)>>GLIDE_PAGE_BITS;
++#if LOG_GLIDE
++ // This only makes sense if full lfb access is used...
++ if (!locked[buffer]) LOG_MSG("Glide:Read from unlocked LFB at: 0x%x", phys_page<<12);
++#endif
++// LOG_MSG("Glide:GetHostReadPt called with %d, returning 0x%p", phys_page, LFB_getAddr((phys_page*MEM_PAGESIZE)));
++ return lfb_addr[buffer]+(phys_page<<12);
++ }
++
++ HostPt GetHostWritePt(Bitu phys_page) {
++ Bitu buffer = (((phys_page<<12) - base_addr[0])>>12)>>GLIDE_PAGE_BITS;
++#if LOG_GLIDE
++ // This only makes sense if full lfb access is used...
++ if (!locked[buffer]) LOG_MSG("Glide:Write to unlocked LFB at: 0x%x", phys_page<<12);
++#endif
++// LOG_MSG("Glide:GetHostWritePt called with %d, returning 0x%p", phys_page, LFB_getAddr((phys_page*MEM_PAGESIZE)));
++ return lfb_addr[buffer]+(phys_page<<12);
++ }
++
++ #undef LFB_getAddr
++};
++
++class GLIDE: public Module_base {
++private:
++ AutoexecObject autoexecline;
++ // Glide port
++ Bitu glide_base;
++ Bit8u *ovl_data;
++public:
++ GLIDE(Section* configuration):Module_base(configuration),glide_base(0),ovl_data(NULL) {
++ Section_prop * section=static_cast<Section_prop *>(configuration);
++
++ if(!section->Get_bool("glide")) return;
++ std::string str = section->Get_string("lfb");
++ lowcase(str);
++ if(str == "none") {
++ LOG_MSG("Glide:Disabled LFB access");
++ lfbacc=0;
++ } else if(str == "read_noaux") {
++ LOG_MSG("Glide:LFB access: read-only (no aux)");
++ lfbacc=1;
++ } else if(str == "write_noaux") {
++ LOG_MSG("Glide:LFB access: write-only (no aux)");
++ lfbacc=2;
++ } else if(str == "full_noaux") {
++ LOG_MSG("Glide:LFB access: read-write (no aux)");
++ lfbacc=3;
++ } else if(str == "read") {
++ LOG_MSG("Glide:LFB access: read-only");
++ lfbacc=5;
++ } else if(str == "write") {
++ LOG_MSG("Glide:LFB access: write-only");
++ lfbacc=6;
++ } else {
++ LOG_MSG("Glide:LFB access: read-write");
++ lfbacc=7;
++ }
++
++ // Load glide2x.dll
++#if defined(WIN32)
++ hdll = LoadLibrary("glide2x.dll");
++#elif defined(MACOSX)
++ hdll = dlopen("libglide2x.dylib", RTLD_NOW);
++#else
++ hdll = dlopen("libglide2x.so", RTLD_NOW);
++#endif
++
++ if(!hdll) {
++ LOG_MSG("Glide:Unable to load glide2x library, glide emulation disabled");
++ return;
++ }
++
++ // Allocate some temporary space
++ texmem = (void*)malloc(1600*1200*4);
++ if(texmem == NULL) {
++ LOG_MSG("Glide:Unable to allocate texture memory, glide disabled");
++ return;
++ }
++
++ glide.lfb_pagehandler = new GLIDE_PageHandler((HostPt)texmem);
++ if(!glide.lfb_pagehandler) {
++ LOG_MSG("Glide:Failed to install page handler, glide disabled!");
++ free(texmem); texmem = NULL;
++ return;
++ }
++
++ // Load glide2x.ovl if possible, so it is available on the Z: drive
++ const char ovl_name[] = "glide2x.ovl";
++
++#if defined (WIN32)
++ // Windows is simple, the search is case insensitive
++ FILE * ovl = fopen(ovl_name, "rb");
++
++ // if not successful try to specifically search dosbox directory
++ if (ovl == NULL) {
++ char * path = (char*)texmem;
++ GetModuleFileName(NULL, path, 32768);
++ // strip "\dosbox.exe" from path
++ PathRemoveFileSpec(path);
++ strcat(path, "\\"); strcat(path, ovl_name);
++ ovl = fopen(path, "rb");
++ }
++
++#else
++ // Try a bit harder in *nix, perform case insensitive search and check /usr/share/dosbox as well
++ DIR * pdir; struct dirent * pfile;
++ char * path = (char*)texmem;
++ FILE * ovl = NULL;
++
++ const char * const dirname[] = { "./", "/usr/share/dosbox/", NULL };
++
++ for (int i = 0; dirname[i]; i++) {
++ if((pdir = opendir(dirname[i]))) {
++ while(pfile = readdir(pdir)) {
++ if(!strcasecmp(pfile->d_name, ovl_name)) {
++ strcpy(path, dirname[i]); strcat(path, pfile->d_name);
++ ovl = fopen(path, "rb");
++ if(ovl) break;
++ }
++ }
++ closedir(pdir);
++ if(ovl) break;
++ }
++ }
++#endif
++
++ long ovl_size = 0;
++
++ if(ovl == NULL) {
++ LOG_MSG("Glide:GLIDE2X.OVL could not be found, make sure correct (compatible) version is in the game directory!");
++ } else {
++ fseek(ovl, 0, SEEK_END);
++ ovl_size=ftell(ovl);
++ ovl_data=(Bit8u*)malloc(ovl_size);
++ fseek(ovl, 0, SEEK_SET);
++ fread(ovl_data, sizeof(char), ovl_size, ovl);
++ fclose(ovl);
++ }
++
++#if LOG_GLIDE
++ SDL_memset(GLIDE_count, 0, sizeof(GLIDE_count));
++#endif
++
++ // Allocate memory for dll pointers
++ fn_pt = (void**)malloc(sizeof(void*)*(GLIDE_MAX+1));
++ if(fn_pt == NULL) {
++ LOG_MSG("Glide:Unable to allocate memory, glide disabled");
++ free(texmem); texmem = NULL;
++ if(ovl_data) free(ovl_data); ovl_data = NULL;
++ return;
++ }
++
++ for(int i=0; i<(GLIDE_MAX+1); i++) {
++#if defined(WIN32)
++ ostringstream temp;
++ // Add function decoration
++ temp << "_" << grTable[i].name << "@" << (Bitu)grTable[i].parms;
++ fn_pt[i] = (void*)(GetProcAddress(hdll, temp.str().c_str()));
++#else
++ fn_pt[i] = (void*)(dlsym(hdll, grTable[i].name));
++#endif
++#if LOG_GLIDE
++ if(fn_pt[i] == NULL) {
++ LOG_MSG("Glide:Warning, unable to load %s from glide2x", grTable[i].name);
++ }
++#endif
++ }
++
++ //glide_base=section->Get_hex("grport");
++ glide_base=0x600; // Anybody else got a better idea?
++
++ IO_RegisterReadHandler(glide_base,read_gl,IO_MB);
++ IO_RegisterWriteHandler(glide_base,write_gl,IO_MB);
++
++ ostringstream temp;
++ temp << "SET GLIDE=" << hex << glide_base << ends;
++
++ autoexecline.Install(temp.str());
++ glide.splash = section->Get_bool("splash");
++
++#if defined (WIN32)
++ // Get hwnd information
++ SDL_SysWMinfo wmi;
++ SDL_VERSION(&wmi.version);
++ if(SDL_GetWMInfo(&wmi)) {
++ hwnd = (HostPt)wmi.window;
++ } else {
++ LOG_MSG("SDL:Error retrieving window information");
++ }
++#endif
++
++ if(ovl_data) {
++ VFILE_Register("GLIDE2X.OVL", ovl_data, ovl_size);
++ }
++ }
++
++ ~GLIDE() {
++ if(glide.enabled) {
++ // void grGlideShutdown(void)
++ FP.grFunction0 = (pfunc0)fn_pt[_grGlideShutdown0];
++ if(FP.grFunction0) FP.grFunction0();
++ glide.enabled = false;
++ }
++
++ SAFE_DELETE(glide.lfb_pagehandler);
++ if(fn_pt)
++ free(fn_pt); fn_pt = NULL;
++ if(texmem)
++ free(texmem); texmem = NULL;
++
++ if(glide_base) {
++ IO_FreeReadHandler(glide_base,IO_MB);
++ IO_FreeWriteHandler(glide_base,IO_MB);
++ }
++
++ if(hdll) {
++#if defined (WIN32)
++ FreeLibrary(hdll);
++#else
++ dlclose(hdll);
++#endif
++ hdll = NULL;
++ }
++
++ VFILE_Remove("GLIDE2X.OVL");
++ if(ovl_data) free(ovl_data);
++ }
++};
++
++static GLIDE* test;
++void GLIDE_ShutDown(Section* sec) {
++ delete test;
++}
++
++void GLIDE_Init(Section* sec) {
++ test = new GLIDE(sec);
++ sec->AddDestroyFunction(&GLIDE_ShutDown,true);
++}
++
++void GLIDE_ResetScreen(bool update)
++{
++#if LOG_GLIDE
++ LOG_MSG("Glide:ResetScreen");
++#endif
++ VGA_SetOverride(true);
++ GFX_Stop();
++
++ // OpenGlide will resize the window on it's own (using SDL)
++ if(glide.width && (
++#ifdef WIN32
++ // dgVoodoo needs a little help :)
++ // Most other wrappers render fullscreen by default
++ (GetProcAddress(hdll, "DispatchDosNT") != NULL) ||
++#endif
++ // and resize when mapper and/or GUI finish
++ update)) {
++ SDL_SetVideoMode(glide.width,glide.height,0,
++ (glide.fullscreen[0]?SDL_FULLSCREEN:0)|SDL_ANYFORMAT|SDL_SWSURFACE);
++ }
++}
++
++void GLIDE_DisableScreen(void)
++{
++ glide.enabled = false; /* if not disabled, GFX_ResetScreen() will call GLIDE_ResetScreen() */
++ VGA_SetOverride(false);
++ GFX_ResetScreen();
++}
++
++static bool GetFileName(char * filename)
++{
++ localDrive *ldp;
++ Bit8u drive;
++ char fullname[DOS_PATHLENGTH];
++
++ // Get full path
++ if(!DOS_MakeName(filename,fullname,&drive)) return false;
++
++#if LOG_GLIDE
++ LOG_MSG("Glide:Fullname: %s", fullname);
++#endif
++
++ // Get real system path
++ ldp = dynamic_cast<localDrive*>(Drives[drive]);
++ if(ldp == NULL) return false;
++
++ ldp->GetSystemFilename(filename,fullname);
++#if LOG_GLIDE
++ LOG_MSG("Glide:System path: %s", filename);
++#endif
++ return true;
++}
++
++typedef FxBool (FX_CALL *pfxSplashInit)(FxU32 hWnd, FxU32 screenWidth, FxU32 screenHeight,
++ FxU32 numColBuf, FxU32 numAuxBuf, GrColorFormat_t colorFormat);
++typedef void (FX_CALL *pfxSplash)(float x, float y, float w, float h, FxU32 frameNumber);
++
++static void grSplash(void)
++{
++#ifdef WIN32
++ FxU32 screenWidth = glide.width, screenHeight = glide.height;
++ HINSTANCE dll = LoadLibrary("3dfxSpl2.dll");
++ if(dll == NULL) {
++ return;
++ }
++
++ pfxSplashInit fxSplashInit = (pfxSplashInit)GetProcAddress(dll, "_fxSplashInit@24");
++ pfxSplash fxSplash = (pfxSplash)GetProcAddress(dll, "_fxSplash@20");
++
++ if((fxSplashInit == NULL) || (fxSplash == NULL)) {
++ FreeLibrary(dll);
++ return;
++ }
++
++ if (screenWidth == 0) {
++ screenWidth = 640;
++ screenHeight = 480;
++ }
++
++ fxSplashInit(0, screenWidth, screenHeight, 2, 1, GR_COLORFORMAT_ABGR);
++ fxSplash(0, 0, screenWidth, screenHeight, 0);
++
++ // OpenGlide does not restore this state
++ FP.grFunction1i = (pfunc1i)fn_pt[_grSstOrigin4];
++ if(FP.grFunction1i) {
++ FP.grFunction1i(GrOriginLocation);
++ }
++
++ FreeLibrary(dll);
++#endif
++}
++
++static void process_msg(Bitu value)
++{
++ GrLfbInfo_t lfbinfo;
++ DBGrLfbInfo_t dblfbinfo;
++
++ GrTexInfo texinfo;
++ DBGrTexInfo dbtexinfo;
++
++ Gu3dfInfo guinfo;
++ DBGu3dfInfo dbguinfo;
++
++ GrVertex vertex[3];
++
++ GrMipMapInfo * mipmap;
++
++ // Temporary memory used in functions
++ FxI32 * ilist = (FxI32*)texmem;
++ FxU16 * ptr16 = (FxU16*)texmem;
++
++ // Filename translation
++ char filename[512];
++
++ // Used so that the pagehandler returns the same address after buffer swap
++ static char b_swap = 0;
++
++ // Return value address
++ ret = param[0];
++ Bitu i = value;
++ Bitu buffer;
++ FxU32 j, k;
++
++ if((i > GLIDE_MAX) || (fn_pt[i] == NULL)) {
++ LOG_MSG("Glide:Invalid function pointer for call %s", (i > GLIDE_MAX) ? "(invalid)" : grTable[i].name);
++ return;
++ }
++
++#if LOG_GLIDE
++ LOG_MSG("Glide:Processing call %s (%d), return address: 0x%x", grTable[i].name, value, ret);
++ GLIDE_count[i]++;
++#endif
++
++ switch (value) {
++
++ case _grAADrawLine8:
++ // void grAADrawLine(GrVertex *va, GrVertex *vb)
++ FP.grFunction2p = (pfunc2p)fn_pt[i];
++ MEM_BlockRead32(param[1], &vertex[0], sizeof(GrVertex));
++ MEM_BlockRead32(param[2], &vertex[1], sizeof(GrVertex));
++ FP.grFunction2p(&vertex[0], &vertex[1]);
++ break;
++ case _grAADrawPoint4:
++ // void grAADrawPoint(GrVertex *p)
++ FP.grFunction1p = (pfunc1p)fn_pt[i];
++ MEM_BlockRead32(param[1], &vertex[0], sizeof(GrVertex));
++ FP.grFunction1p(&vertex[0]);
++ break;
++ case _grAADrawPolygon12:
++ // void grAADrawPolygon(int nVerts, const int ilist[], const GrVertex vlist[])
++ FP.grFunction1i2p = (pfunc1i2p)fn_pt[i];
++ i = sizeof(FxI32)*param[1];
++ MEM_BlockRead32(param[2], ilist, i);
++
++ // Find the number of vertices (?)
++ k = 0;
++ for(j = 0; j < param[1]; j++) {
++ if(ilist[j] > k)
++ k = ilist[j];
++ }
++ k++;
++
++ MEM_BlockRead32(param[3], ilist+i, sizeof(GrVertex)*k);
++ FP.grFunction1i2p(param[1], ilist, ilist+i);
++ break;
++ case _grAADrawPolygonVertexList8:
++ // void grAADrawPolygonVertexList(int nVerts, const GrVertex vlist[])
++ FP.grFunction1i1p = (pfunc1i1p)fn_pt[i];
++ MEM_BlockRead32(param[2], texmem, sizeof(GrVertex)*param[1]);
++ FP.grFunction1i1p(param[1], texmem);
++ break;
++ case _grAADrawTriangle24:
++ // void grAADrawTriangle(GrVertex *a, GrVertex *b, GrVertex *c,
++ // FxBool antialiasAB, FxBool antialiasBC, FxBool antialiasCA)
++ FP.grFunction3p3i = (pfunc3p3i)fn_pt[i];
++ MEM_BlockRead32(param[1], &vertex[0], sizeof(GrVertex));
++ MEM_BlockRead32(param[2], &vertex[1], sizeof(GrVertex));
++ MEM_BlockRead32(param[3], &vertex[2], sizeof(GrVertex));
++ FP.grFunction3p3i(&vertex[0], &vertex[1], &vertex[2], param[4], param[5], param[6]);
++ break;
++ case _grAlphaBlendFunction16:
++ // void grAlphaBlendFunction(GrAlphaBlendFnc_t rgb_sf, GrAlphaBlendFnc_t rgb_df,
++ // GrAlphaBlendFnc_t alpha_sf, GrAlphaBlendFnc_t alpha_df)
++ if(tomb == 1) {
++ if((FP.grFunction1i = (pfunc1i)fn_pt[_grConstantColorValue4]))
++ FP.grFunction1i(0x7f000000);
++ } else if(tomb == 2) {
++ float color1 = 127.0;
++ float color2 = 0.0;
++ if((FP.grFunction4f = (pfunc4f)fn_pt[_grConstantColorValue416]))
++ FP.grFunction4f(color1, color2, color2, color2);
++ }
++ FP.grFunction4i = (pfunc4i)fn_pt[i];
++ FP.grFunction4i(param[1], param[2], param[3], param[4]);
++ break;
++ case _grAlphaCombine20:
++ // void grAlphaCombine(GrCombineFunction_t func, GrCombineFactor_t factor,
++ // GrCombineLocal_t local, GrCombineOther_t other, FxBool invert)
++ FP.grFunction5i = (pfunc5i)fn_pt[i];
++ FP.grFunction5i(param[1], param[2], param[3], param[4], param[5]);
++ break;
++ case _grAlphaControlsITRGBLighting4:
++ // void grAlphaControlsITRGBLighting(FxBool enable)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grAlphaTestFunction4:
++ // void grAlphaTestFunction(GrCmpFnc_t function)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grAlphaTestReferenceValue4:
++ // void grAlphaTestReferenceValue(GrAlpha_t value)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grBufferClear12:
++ // void grBufferClear(GrColor_t color, GrAlpha_t alpha, FxU16 depth)
++ FP.grFunction3i = (pfunc3i)fn_pt[i];
++ FP.grFunction3i(param[1], param[2], param[3]);
++ break;
++ case _grBufferNumPending0:
++ // int grBufferNumPending(void)
++ FP.grRFunction0 = (prfunc0)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction0());
++ ret_value = G_OK;
++ break;
++ case _grBufferSwap4:
++ // void grBufferSwap(int swap_interval)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ /* Breaks Extreme Assault (which always writes to same address ?) */
++ //if(!(glide.lfb_pagehandler->locked[0] || glide.lfb_pagehandler->locked[1])) b_swap = !b_swap;
++#if LOG_GLIDE
++ LOG_MSG("Glide:BufferSwap (0x%x)", b_swap);
++#endif
++ break;
++ case _grCheckForRoom4:
++ // void grCheckForRoom(FxI32 n)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grChromakeyMode4:
++ // void grChromakeyMode(GrChromakeyMode_t mode)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grChromakeyValue4:
++ // void grChromakeyValue(GrColor_t value)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grClipWindow16:
++ // void grClipWindow(FxU32 minx, FxU32 miny, FxU32 maxx, FxU32 maxy)
++ FP.grFunction4i = (pfunc4i)fn_pt[i];
++ FP.grFunction4i(param[1], param[2], param[3], param[4]);
++ break;
++ case _grColorCombine20:
++ // void grColorCombine(GrCombineFunction_t func, GrCombineFactor_t factor,
++ // GrCombineLocal_t local, GrCombineOther_t other, FxBool invert)
++ FP.grFunction5i = (pfunc5i)fn_pt[i];
++ FP.grFunction5i(param[1], param[2], param[3], param[4], param[5]);
++ break;
++ case _grColorMask8:
++ // void grColorMask(FxBool rgb, FxBool alpha)
++ FP.grFunction2i = (pfunc2i)fn_pt[i];
++ FP.grFunction2i(param[1], param[2]);
++ break;
++ case _grConstantColorValue416:
++ // void grConstantColorValue4(float a, float r, float g, float b)
++ FP.grFunction4f = (pfunc4f)fn_pt[i];
++ FP.grFunction4f(int_to_float(param[1]), int_to_float(param[2]), int_to_float(param[3]), int_to_float(param[4]));
++ break;
++ case _grConstantColorValue4:
++ // void grConstantColorValue(GrColor_t color)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grCullMode4:
++ // void grCullMode(GrCullMode_t mode)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grDepthBiasLevel4:
++ // void grDepthBiasLevel(FxI16 level)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grDepthBufferFunction4:
++ // void grDepthBufferFunction(GrCmpFnc_t func)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grDepthBufferMode4:
++ // void grDepthBufferMode(GrDepthBufferMode_t mode)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grDepthMask4:
++ // void grDepthMask(FxBool enable)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grDisableAllEffects0:
++ // void grDisableAllEffects(void)
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++ break;
++ case _grDitherMode4:
++ // void grDitherMode(GrDitherMode_t mode)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grDrawLine8:
++ // void grDrawLine(const GrVertex *a, const GrVertex *b)
++ FP.grFunction2p = (pfunc2p)fn_pt[i];
++ MEM_BlockRead32(param[1], &vertex[0], sizeof(GrVertex));
++ MEM_BlockRead32(param[2], &vertex[1], sizeof(GrVertex));
++ FP.grFunction2p(&vertex[0], &vertex[1]);
++ break;
++ case _grDrawPlanarPolygon12:
++ // void grDrawPlanarPolygon(int nVerts, int ilist[], const GrVertex vlist[])
++ FP.grFunction1i2p = (pfunc1i2p)fn_pt[i];
++ i = sizeof(FxI32)*param[1];
++ MEM_BlockRead32(param[2], ilist, i);
++
++ // Find the number of vertices (?)
++ k = 0;
++ for(j = 0; j < param[1]; j++) {
++ if(ilist[j] > k)
++ k = ilist[j];
++ }
++ k++;
++
++ MEM_BlockRead32(param[3], ilist+i, sizeof(GrVertex)*k);
++ FP.grFunction1i2p(param[1], ilist, ilist+i);
++ break;
++ case _grDrawPlanarPolygonVertexList8:
++ // void grDrawPlanarPolygonVertexList(int nVertices, const GrVertex vlist[])
++ FP.grFunction1i1p = (pfunc1i1p)fn_pt[i];
++ MEM_BlockRead32(param[2], texmem, sizeof(GrVertex)*param[1]);
++ FP.grFunction1i1p(param[1], texmem);
++ break;
++ case _grDrawPoint4:
++ // void grDrawPoint(const GrVertex *a)
++ FP.grFunction1p = (pfunc1p)fn_pt[i];
++ MEM_BlockRead32(param[1], &vertex[0], sizeof(GrVertex));
++ FP.grFunction1p(&vertex[0]);
++ break;
++ case _grDrawPolygon12:
++ // void grDrawPolygon(int nVerts, int ilist[], const GrVertex vlist[])
++ FP.grFunction1i2p = (pfunc1i2p)fn_pt[i];
++ i = sizeof(FxI32)*param[1];
++ MEM_BlockRead32(param[2], ilist, i);
++
++ // Find the number of vertices (?)
++ k = 0;
++ for(j = 0; j < param[1]; j++) {
++ if(ilist[j] > k)
++ k = ilist[j];
++ }
++ k++;
++
++ MEM_BlockRead32(param[3], ilist+i, sizeof(GrVertex)*k);
++ FP.grFunction1i2p(param[1], ilist, ilist+i);
++ break;
++ case _grDrawPolygonVertexList8:
++ // void grDrawPolygonVertexList(int nVerts, const GrVertex vlist[])
++ FP.grFunction1i1p = (pfunc1i1p)fn_pt[i];
++ MEM_BlockRead32(param[2], texmem, sizeof(GrVertex)*param[1]);
++ FP.grFunction1i1p(param[1], texmem);
++ break;
++ case _grDrawTriangle12:
++ // void grDrawTriangle(const GrVertex *a, const GrVertex *b, const GrVertex *c)
++ FP.grFunction3p = (pfunc3p)fn_pt[i];
++ MEM_BlockRead32(param[1], &vertex[0], sizeof(GrVertex));
++ MEM_BlockRead32(param[2], &vertex[1], sizeof(GrVertex));
++ MEM_BlockRead32(param[3], &vertex[2], sizeof(GrVertex));
++ FP.grFunction3p(&vertex[0], &vertex[1], &vertex[2]);
++ break;
++/*
++ case _grErrorSetCallback4:
++ // void grErrorSetCallback(void (*function)(const char *string, FxBool fatal))
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(*param[1]);
++ break;
++*/
++ case _grFogColorValue4:
++ // void grFogColorValue(GrColor_t value)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grFogMode4:
++ // void grFogMode(GrFogMode_t mode)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grFogTable4:
++ // void grFogTable(const GrFog_t grTable[GR_FOG_TABLE_SIZE])
++ FP.grFunction1p = (pfunc1p)fn_pt[i];
++ MEM_BlockRead32(param[1], texmem, sizeof(GrFog_t)*GR_FOG_TABLE_SIZE);
++ FP.grFunction1p(texmem);
++ break;
++ case _grGammaCorrectionValue4:
++ // void grGammaCorrectionValue(float value)
++ FP.grFunction1f = (pfunc1f)fn_pt[i];
++ FP.grFunction1f(int_to_float(param[1]));
++ break;
++ case _grGlideGetState4:
++ // void grGlideGetState(GrState *state)
++ FP.grFunction1p = (pfunc1p)fn_pt[i];
++ MEM_BlockRead32(param[1], texmem, sizeof(GrState));
++ FP.grFunction1p(texmem);
++ MEM_BlockWrite32(param[1], texmem, sizeof(GrState));
++ break;
++ case _grGlideGetVersion4:
++ // void grGlideGetVersion(char version[80])
++ FP.grFunction1p = (pfunc1p)fn_pt[i];
++ FP.grFunction1p(filename);
++ k = 0;
++ do {
++ mem_writeb(param[1]++, filename[k++]);
++ } while(filename[k] != '\0');
++ mem_writeb(param[1], '\0');
++ break;
++ case _grGlideInit0:
++ // void grGlideInit(void)
++ if(glide.enabled) break; /* Tie Break Tennis */
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++
++ // Enable Tomb Rider displaying shadow
++ if(!strncasecmp(RunningProgram, "Tombub", 6)) tomb = 2;
++ else if(!strncasecmp(RunningProgram, "Tomb", 4)) tomb = 1;
++ else tomb = 0;
++
++ // Send LFB to the OVL (so it can map it in linear address)
++ if(mem_readd(param[1]) == 0xFFFFF1FB) { // Find LFB magic
++ mem_writed(param[1], glide.lfb_pagehandler->GetPhysPt());
++ mem_writed(param[2], GLIDE_PAGES);
++ } else {
++ LOG_MSG("Glide:Detected incompatible guest ovl/dll!");
++ }
++ break;
++ case _grGlideSetState4:
++ // void grGlideSetState(const GrState *state)
++ FP.grFunction1p = (pfunc1p)fn_pt[i];
++ MEM_BlockRead32(param[1], texmem, sizeof(GrState));
++ FP.grFunction1p(texmem);
++ MEM_BlockWrite32(param[1], texmem, sizeof(GrState));
++ break;
++ case _grGlideShamelessPlug4:
++ // void grGlideShamelessPlug(const FxBool on)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grGlideShutdown0: {
++ // void grGlideShutdown(void)
++ if(glide.enabled) {
++ FP.grFunction0 = (pfunc0)fn_pt[_grSstWinClose0];
++ FP.grFunction0();
++ GLIDE_DisableScreen();
++ }
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++
++ Section_prop *section=static_cast<Section_prop *>(control->GetSection("glide"));
++ if (section) glide.splash = section->Get_bool("splash");
++
++#if LOG_GLIDE
++ for(j=0;j<(GLIDE_MAX+1);j++) {
++ if(GLIDE_count[j]) {
++ LOG_MSG("Glide:%6d calls function %s (%d)", GLIDE_count[j], grTable[j].name, j);
++ }
++ }
++ LOG_MSG("Glide: %d framebuffer locks (%d read, %d write)", GLIDE_count[_grLfbLock24],
++ GLIDE_count[GLIDE_MAX+1], GLIDE_count[_grLfbLock24] - GLIDE_count[GLIDE_MAX+1]);
++ SDL_memset(GLIDE_count, 0, sizeof(GLIDE_count));
++#endif
++ break;
++ }
++ case _grHints8:
++ // void grHints(GrHints_t type, FxU32 hintMask)
++ FP.grFunction2i = (pfunc2i)fn_pt[i];
++ FP.grFunction2i(param[1], param[2]);
++ break;
++ case _grLfbConstantAlpha4:
++ // void grLfbConstantAlpha(GrAlpha_t alpha)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grLfbConstantDepth4:
++ // void grLfbConstantDepth(FxU16 depth)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grLfbLock24:
++ // FxBool grLfbLock(GrLock_t type, GrBuffer_t buffer, GrLfbWriteMode_t writeMode,
++ // GrOriginLocation_t origin, FxBool pixelPipeline, GrLfbInfo_t *info)
++ FP.grRFunction5i1p = (prfunc5i1p)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++
++ buffer = (Bitu)param[2];
++ if (buffer >= GLIDE_BUFFERS) {
++ LOG_MSG("Glide:Invalid buffer passed in grLfbLock (%d)", buffer);
++ return;
++ }
++
++ // Buffer address should stay the same after BufferSwap, so check which buffer to lock
++ // (currently disabled, see _grBufferSwap4)
++ //if (buffer < 2) buffer = buffer ^ b_swap;
++
++ // Read parameters
++ MEM_BlockRead32(param[6], &dblfbinfo, sizeof(DBGrLfbInfo_t));
++ lfbinfo.size = sizeof(GrLfbInfo_t);
++ lfbinfo.origin = dblfbinfo.origin;
++ lfbinfo.lfbPtr = texmem;
++
++ k = FXTRUE;
++ j = param[1]&1; j++;
++ j = j&lfbacc; // Check LFB access (j = 0 : fake lock)
++ if((buffer > 1) && (lfbacc < 4)) j = 0; // Disable access to AUX buffers
++
++ if(j) {
++ // Lock the buffer
++ k = FP.grRFunction5i1p(param[1], param[2], param[3], param[4], param[5], &lfbinfo);
++ if(k == FXTRUE) {
++ glide.lfb_pagehandler->locked[buffer]++;
++ dblfbinfo.writeMode = lfbinfo.writeMode;
++ dblfbinfo.strideInBytes = lfbinfo.strideInBytes;
++ dblfbinfo.lfbPtr = glide.lfb_pagehandler->GetLinPt(buffer);
++ MEM_BlockWrite32(param[6], &dblfbinfo, sizeof(DBGrLfbInfo_t));
++ } else {
++ LOG_MSG("Glide:LFB Lock failed!");
++ //k = FXFALSE; // Lock failed ?
++ }
++ } else {
++ // else lock is faked (texmem used for read/write)
++ if(param[3] == GR_LFBWRITEMODE_ANY) dblfbinfo.writeMode = GR_LFBWRITEMODE_565;
++ else dblfbinfo.writeMode = param[3];
++
++ if(param[4] == GR_ORIGIN_ANY) dblfbinfo.origin = GR_ORIGIN_UPPER_LEFT;
++ else dblfbinfo.origin = param[4];
++
++ dblfbinfo.strideInBytes = ((glide.width>0) ? glide.width : 1600) * 4;
++ dblfbinfo.lfbPtr = glide.lfb_pagehandler->GetLinPt(buffer);
++
++ //if(!(param[1]&GR_LFB_WRITE_ONLY)) SDL_memset(texmem, 0, 1600*1200*4); // Clear memory on read-lock
++
++ MEM_BlockWrite32(param[6], &dblfbinfo, sizeof(DBGrLfbInfo_t));
++ }
++
++ // Set LFB address for page handler to read from/write to
++ glide.lfb_pagehandler->SetLFBAddr((HostPt)lfbinfo.lfbPtr, buffer);
++ if(dblfbinfo.strideInBytes > 1600*4) LOG_MSG("Glide:WARNING LFB stride (%d) is larger than max supported: %d!", dblfbinfo.strideInBytes, 1600*4);
++
++ if(param[1]&GR_LFB_WRITE_ONLY) { // Is a write-only lock
++#if LOG_GLIDE
++ LOG_MSG("Glide:W/O lock (%d). %s LFB: 0x%p. Returning 0x%x (stride: %d)", param[2], (j ? "Real" : "Fake"),
++ lfbinfo.lfbPtr, dblfbinfo.lfbPtr, dblfbinfo.strideInBytes);
++#endif
++ } else { // Is a read-only lock
++#if LOG_GLIDE
++ LOG_MSG("Glide:R/O lock (%d). %s LFB: 0x%p. Returning 0x%x (stride: %d)", param[2], (j ? "Real" : "Fake"),
++ lfbinfo.lfbPtr, dblfbinfo.lfbPtr, dblfbinfo.strideInBytes);
++ GLIDE_count[GLIDE_MAX+1]++;
++#endif
++ }
++
++ mem_writed(ret, k);
++ ret_value = G_OK;
++ break;
++ case _grLfbReadRegion28:
++ // FxBool grLfbReadRegion(GrBuffer_t src_buffer, FxU32 src_x, FxU32 src_y, FxU32 src_width,
++ // FxU32 src_height, FxU32 dst_stride, void *dst_data)
++ FP.grRFunction6i1p = (prfunc6i1p)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction6i1p(param[1], param[2], param[3], param[4], param[5], param[6], ptr16));
++ MEM_BlockWrite(param[7], ptr16, param[5]*param[6]);
++ ret_value = G_OK;
++ break;
++ case _grLfbUnlock8:
++ // FxBool grLfbUnlock(GrLock_t type, GrBuffer_t buffer)
++ FP.grRFunction2i = (prfunc2i)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle (%d)!", _grLfbUnlock8);
++ return;
++ }
++ k = FXTRUE;
++ buffer = param[2];
++ if (buffer < 2) buffer = buffer ^ b_swap;
++#if LOG_GLIDE
++ LOG_MSG("Glide:LFB unlock buffer (%d), %d locks active", param[2], glide.lfb_pagehandler->locked[buffer]);
++#endif
++ if(glide.lfb_pagehandler->locked[buffer]) {
++ k = FP.grRFunction2i(param[1], param[2]);
++ glide.lfb_pagehandler->locked[buffer]--;
++ glide.lfb_pagehandler->SetLFBAddr((HostPt)texmem, buffer); // Reset page handler and clear TLB
++ } else {
++ //k = FXFALSE;
++ }
++ mem_writed(ret, k);
++ ret_value = G_OK;
++ break;
++ case _grLfbWriteColorFormat4:
++ // void grLfbWriteColorFormat(GrColorFormat_t colorFormat)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grLfbWriteColorSwizzle8:
++ // void grLfbWriteColorSwizzle(FxBool swizzleBytes, FxBool swapWords)
++ FP.grFunction2i = (pfunc2i)fn_pt[i];
++ FP.grFunction2i(param[1], param[2]);
++ break;
++ case _grLfbWriteRegion32:
++ // FxBool grLfbWriteRegion(GrBuffer_t dst_buffer, FxU32 dst_x, FxU32 dst_y,
++ // GrLfbSrcFmt_t src_format, FxU32 src_width, FxU32 src_height, FxU32 src_stride, void *src_data)
++ FP.grRFunction7i1p = (prfunc7i1p)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++
++ MEM_BlockRead(param[8], ptr16, param[6]*param[7]);
++ mem_writed(ret, FP.grRFunction7i1p(param[1], param[2], param[3], param[4], param[5], param[6], param[7], ptr16));
++ ret_value = G_OK;
++ break;
++ case _grRenderBuffer4:
++ // void grRenderBuffer(GrBuffer_t buffer)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grResetTriStats0:
++ // void grResetTriStats()
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++ break;
++ case _grSplash20:
++ // void grSplash(float x, float y, float width, float height, FxU32 frame)
++ FP.grFunction4f1i = (pfunc4f1i)fn_pt[i];
++ FP.grFunction4f1i(int_to_float(param[1]), int_to_float(param[2]), int_to_float(param[3]), int_to_float(param[4]), param[5]);
++ break;
++/*
++ case _grSstConfigPipeline12:
++ //
++ FP.grFunction3i = (pfunc3i)fn_pt[i];
++ FP.grFunction3i();
++ break;
++*/
++ case _grSstControl4:
++ // FxBool grSstControl(FxU32 code)
++ FP.grRFunction1i = (prfunc1i)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction1i(param[1]));
++ ret_value = G_OK;
++ break;
++ case _grSstIdle0:
++ // void grSstIdle(void)
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++ break;
++ case _grSstIsBusy0:
++ // FxBool grSstIsBusy(void)
++ FP.grRFunction0 = (prfunc0)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction0());
++ ret_value = G_OK;
++ break;
++ case _grSstOrigin4:
++ // void grSstOrigin(GrOriginLocation_t origin)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ GrOriginLocation = param[1];
++ break;
++ case _grSstPerfStats4:
++ // void grSstPerfStats(GrSstPerfStats_t *pStats)
++ FP.grFunction1p = (pfunc1p)fn_pt[i];
++ MEM_BlockRead32(param[1], texmem, sizeof(GrSstPerfStats_t));
++ FP.grFunction1p(texmem);
++ MEM_BlockWrite32(param[1], texmem, sizeof(GrSstPerfStats_t));
++ break;
++ case _grSstQueryBoards4:
++ // FxBool grSstQueryBoards(GrHwConfiguration *hwConfig)
++ FP.grRFunction1p = (prfunc1p)fn_pt[i];
++ MEM_BlockRead32(param[1], texmem, sizeof(GrHwConfiguration));
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction1p(texmem));
++ MEM_BlockWrite32(param[1], texmem, sizeof(GrHwConfiguration));
++ ret_value = G_OK;
++ break;
++ case _grSstQueryHardware4:
++ // FxBool grSstQueryHardware(GrHwConfiguration *hwConfig)
++ FP.grRFunction1p = (prfunc1p)fn_pt[i];
++ MEM_BlockRead32(param[1], texmem, sizeof(GrHwConfiguration));
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction1p(texmem));
++ MEM_BlockWrite32(param[1], texmem, sizeof(GrHwConfiguration));
++ ret_value = G_OK;
++ break;
++ case _grSstResetPerfStats0:
++ // void grSstResetPerfStats(void)
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++ break;
++ case _grSstScreenHeight0:
++ // FxU32 grSstScreenHeight(void)
++ FP.grRFunction0 = (prfunc0)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction0());
++ ret_value = G_OK;
++ break;
++ case _grSstScreenWidth0:
++ // FxU32 grSstScreenWidth(void)
++ FP.grRFunction0 = (prfunc0)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction0());
++ ret_value = G_OK;
++ break;
++ case _grSstSelect4:
++ // void grSstSelect(int which_sst)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _grSstStatus0:
++ // FxU32 grSstStatus(void)
++ FP.grRFunction0 = (prfunc0)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction0());
++ ret_value = G_OK;
++ break;
++ case _grSstVRetraceOn0:
++ // FxBool grSstVRetraceOn(void)
++ FP.grRFunction0 = (prfunc0)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction0());
++ ret_value = G_OK;
++ break;
++/*
++ case _grSstVidMode8:
++ //
++ FP.grFunction2i = (pfunc2i)fn_pt[i];
++ FP.grFunction2i();
++ break;
++*/
++ case _grSstVideoLine0:
++ // FxU32 grSstVideoLine(void)
++ FP.grRFunction0 = (prfunc0)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction0());
++ ret_value = G_OK;
++ break;
++ case _grSstWinClose0:
++ // void grSstWinClose(void)
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++ if(glide.enabled) {
++ GLIDE_DisableScreen();
++ }
++ break;
++ case _grSstWinOpen28:
++ // FxBool grSstWinOpen(FxU32 hwnd, GrScreenResolution_t res, GrScreenRefresh_t ref,
++ // GrColorFormat_t cformat, GrOriginLocation_t org_loc, int num_buffers, int num_aux_buffers)
++ FP.grRFunction1p6i = (prfunc1p6i)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++
++ /* Tie Break Tennis */
++ if(glide.enabled) {
++ LOG_MSG("Glide:grSstWinOpen called when glide is active!");
++ mem_writed(ret, FXTRUE);
++ ret_value = G_OK;
++ break;
++ }
++
++ // Check for successful memory map
++ if(mem_readd(param[10]) == 0) {
++ LOG_MSG("Glide:LFB memory map failed, using default LFB address!");
++ // Write physical address instead, it can crash but it just might work
++ mem_writed(param[10], glide.lfb_pagehandler->GetPhysPt());
++ }
++
++ glide.enabled = true;
++ glide.width = param[8];
++ glide.height = param[9];
++ GrOriginLocation = param[5];
++
++ // Resize window and disable updates
++ GLIDE_ResetScreen();
++
++ k = FP.grRFunction1p6i(hwnd, param[2], param[3], param[4], param[5], param[6], param[7]);
++ if(k == FXFALSE) {
++ LOG_MSG("Glide:grSstWinOpen failed!");
++ GLIDE_DisableScreen();
++ mem_writed(ret, FXFALSE);
++ ret_value = G_OK;
++ break;
++ }
++
++ mem_writed(ret, k);
++ if(glide.splash) {
++ grSplash();
++ glide.splash = false;
++ }
++
++ glide.lfb_pagehandler->SetLinPt(mem_readd(param[10]));
++ LOG_MSG("Glide:Resolution:%dx%d, LFB at 0x%x (physical) / 0x%x (linear)",
++ glide.width, glide.height, glide.lfb_pagehandler->GetPhysPt(), glide.lfb_pagehandler->GetLinPt());
++ ret_value = G_OK;
++ break;
++ case _grTexCalcMemRequired16:
++ // FxU32 grTexCalcMemRequired(GrLOD_t smallLod, GrLOD_t largeLod, GrAspectRatio_t aspect,
++ // GrTextureFormat_t format)
++ FP.grRFunction4i = (prfunc4i)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction4i(param[1], param[2], param[3], param[4]));
++ ret_value = G_OK;
++ break;
++ case _grTexClampMode12:
++ // void grTexClampMode(GrChipID_t tmu, GrTextureClampMode_t sClampMode, GrTextureClampMode_t tClampMode)
++ FP.grFunction3i = (pfunc3i)fn_pt[i];
++ FP.grFunction3i(param[1], param[2], param[3]);
++ break;
++ case _grTexCombine28:
++ // void grTexCombine(GrChipID_t tmu, GrCombineFunction_t rgb_function, GrCombineFactor_t rgb_factor,
++ // GrCombineFunction_t alpha_function, GrCombineFactor_t alpha_factor, FxBool rgb_invert,
++ // FxBool alpha_invert)
++ FP.grFunction7i = (pfunc7i)fn_pt[i];
++ FP.grFunction7i(param[1], param[2], param[3], param[4], param[5], param[6], param[7]);
++ break;
++ case _grTexCombineFunction8:
++ // void grTexCombineFunction(GrChipID_t tmu, GrTextureCombineFnc_t fnc)
++ FP.grFunction2i = (pfunc2i)fn_pt[i];
++ FP.grFunction2i(param[1], param[2]);
++ break;
++ case _grTexDetailControl16:
++ // void grTexDetailControl(GrChipID_t tmu, int lodBias, FxU8 detailScale, float detailMax)
++ FP.grFunction3i1f = (pfunc3i1f)fn_pt[i];
++ FP.grFunction3i1f(param[1], param[2], param[3], int_to_float(param[4]));
++ break;
++ case _grTexDownloadMipMap16:
++ // void grTexDownloadMipMap(GrChipID_t tmu, FxU32 startAddress, FxU32 evenOdd, GrTexInfo *info)
++ FP.grRFunction1i1p = (prfunc1i1p)fn_pt[_grTexTextureMemRequired8];
++ if(FP.grRFunction1i1p == NULL) {
++ LOG_MSG("Glide:Unable to get pointer to grTexTextureMemRequired");
++ return;
++ }
++
++ MEM_BlockRead32(param[4], &dbtexinfo, sizeof(DBGrTexInfo));
++
++ texinfo.smallLod = dbtexinfo.smallLod;
++ texinfo.largeLod = dbtexinfo.largeLod;
++ texinfo.aspectRatio = dbtexinfo.aspectRatio;
++ texinfo.format = dbtexinfo.format;
++ texinfo.data = NULL;
++
++ // grTexTextureMemRequired
++ texsize = FP.grRFunction1i1p(param[3], &texinfo);
++ MEM_BlockRead(dbtexinfo.data, texmem, texsize);
++ texinfo.data = texmem;
++
++ FP.grFunction3i1p = (pfunc3i1p)fn_pt[i];
++ FP.grFunction3i1p(param[1], param[2], param[3], &texinfo);
++ break;
++ case _grTexDownloadMipMapLevel32:
++ // void grTexDownloadMipMapLevel(GrChipID_t tmu, FxU32 startAddress, GrLOD_t thisLod,
++ // GrLOD_t largeLod, GrAspectRatio_t aspectRatio, GrTextureFormat_t format,
++ // FxU32 evenOdd, void *data)
++ FP.grRFunction1i1p = (prfunc1i1p)fn_pt[_grTexTextureMemRequired8];
++ if(FP.grRFunction1i1p == NULL) {
++ LOG_MSG("Glide:Unable to get pointer to grTexTextureMemRequired");
++ return;
++ }
++
++ texinfo.smallLod = param[3];
++ texinfo.largeLod = param[3]; // Calculate only thisLod
++ texinfo.aspectRatio = param[5];
++ texinfo.format = param[6];
++ texinfo.data = NULL;
++
++ // grTexTextureMemRequired
++ texsize = FP.grRFunction1i1p(param[7], &texinfo);
++ MEM_BlockRead(param[8], texmem, texsize);
++
++#if LOG_GLIDE
++ LOG_MSG("Read %d (%d %d %d %d %d) bytes of texture data", texsize, param[3], param[4], param[5], param[6], param[7]);
++#endif
++
++ FP.grFunction7i1p = (pfunc7i1p)fn_pt[i];
++ FP.grFunction7i1p(param[1], param[2], param[3], param[4], param[5], param[6], param[7], texmem);
++ break;
++ case _grTexDownloadMipMapLevelPartial40:
++ // FX_ENTRY void FX_CALL grTexDownloadMipMapLevelPartial(GrChipID_t tmu, FxU32 startAddress,
++ // GrLOD_t thisLod, GrLOD_t largeLod, GrAspectRatio_t aspectRatio, GrTextureFormat_t format,
++ // FxU32 evenOdd, void *data, int start, int end);
++ FP.grRFunction1i1p = (prfunc1i1p)fn_pt[_grTexTextureMemRequired8];
++ if(FP.grRFunction1i1p == NULL) {
++ LOG_MSG("Glide:Unable to get pointer to grTexTextureMemRequired");
++ return;
++ }
++
++ texinfo.smallLod = param[3];
++ texinfo.largeLod = param[3]; // Calculate only thisLod
++ texinfo.aspectRatio = param[5];
++ texinfo.format = param[6];
++ texinfo.data = NULL;
++
++ // grTexTextureMemRequired
++ texsize = FP.grRFunction1i1p(param[7], &texinfo);
++ MEM_BlockRead(param[8], texmem, texsize);
++
++ FP.grFunction7i1p2i = (pfunc7i1p2i)fn_pt[i];
++ FP.grFunction7i1p2i(param[1], param[2], param[3], param[4], param[5], param[6], param[7], texmem,
++ param[9], param[10]);
++ break;
++ case _grTexDownloadTable12:
++ // void grTexDownloadTable(GrChipID_t tmu, GrTexTable_t type, void *data)
++ FP.grFunction2i1p = (pfunc2i1p)fn_pt[i];
++
++ if(param[2] == GR_TEXTABLE_PALETTE) {
++ MEM_BlockRead32(param[3], texmem, sizeof(GuTexPalette));
++ } else { // GR_TEXTABLE_NCC0 or GR_TEXTABLE_NCC1
++ MEM_BlockRead32(param[3], texmem, sizeof(GuNccTable));
++ }
++
++ FP.grFunction2i1p(param[1], param[2], texmem);
++ break;
++ case _grTexDownloadTablePartial20:
++ // void grTexDownloadTablePartial(GrChipID_t tmu, GrTexTable_t type, void *data, int start, int end)
++ FP.grFunction2i1p2i = (pfunc2i1p2i)fn_pt[i];
++
++ if(param[2] == GR_TEXTABLE_PALETTE) {
++ MEM_BlockRead32(param[3], texmem, sizeof(GuTexPalette));
++ FP.grFunction2i1p2i(param[1], param[2], texmem, param[4], param[5]);
++ } else { // GR_TEXTABLE_NCC0 or GR_TEXTABLE_NCC1
++ LOG_MSG("Glide:Downloading partial NCC tables is not supported!");
++ }
++
++ break;
++ case _grTexFilterMode12:
++ // void grTexFilterMode(GrChipID_t tmu, GrTextureFilterMode_t minFilterMode,
++ // GrTextureFilterMode_t magFilterMode)
++ FP.grFunction3i = (pfunc3i)fn_pt[i];
++ FP.grFunction3i(param[1], param[2], param[3]);
++ break;
++ case _grTexLodBiasValue8:
++ // void grTexLodBiasValue(GrChipID_t tmu, float bias)
++ FP.grFunction1i1f = (pfunc1i1f)fn_pt[i];
++ FP.grFunction1i1f(param[1], int_to_float(param[2]));
++ break;
++ case _grTexMaxAddress4:
++ // FxU32 grTexMaxAddress(GrChipID_t tmu)
++ FP.grRFunction1i = (prfunc1i)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction1i(param[1]));
++ ret_value = G_OK;
++ break;
++ case _grTexMinAddress4:
++ // FxU32 grTexMinAddress(GrChipID_t tmu)
++ FP.grRFunction1i = (prfunc1i)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction1i(param[1]));
++ ret_value = G_OK;
++ break;
++ case _grTexMipMapMode12:
++ // void grTexMipMapMode(GrChipID_t tmu, GrMipMapMode_t mode, FxBool lodBlend)
++ FP.grFunction3i = (pfunc3i)fn_pt[i];
++ FP.grFunction3i(param[1], param[2], param[3]);
++ break;
++ case _grTexMultibase8:
++ // void grTexMultibase(GrChipID_t tmu, FxBool enable)
++ FP.grFunction2i = (pfunc2i)fn_pt[i];
++ FP.grFunction2i(param[1], param[2]);
++ break;
++/*
++ case _grTexMultibaseAddress20:
++ // void grTexMultibaseAddress(GrChipID_t tmu, GrTexBaseRange_t range, FxU32 startAddress,
++ // FxU32 evenOdd, GrTexInfo *info)
++ FP.grFunction4i1p = (pfunc4i1p)fn_pt[i];
++
++ // This is a bit more complicated since *info contains a pointer to data
++ texinfo = (GrTexInfo*)param[5];
++ data = (PhysPt)texinfo->data; // Store for later reference
++ texinfo->data = VIRTOREAL(data);
++#if LOG_GLIDE
++ if(log_func[value-_grAADrawLine8] == 1) {
++ LOG_MSG("Glide:Replacing pointer 0x%x with 0x%x in function %d", data, texinfo->data, _grTexMultibaseAddress20);
++ log_func[value-_grAADrawLine8] = 2;
++ }
++#endif
++ FP.grFunction20(param[1], param[2], param[3], param[4], (int)texinfo);
++ texinfo->data = (void*)data; // Change the pointer back
++ break;
++*/
++ case _grTexNCCTable8:
++ // void grTexNCCTable(GrChipID_t tmu, GrNCCTable_t table)
++ FP.grFunction2i = (pfunc2i)fn_pt[i];
++ FP.grFunction2i(param[1], param[2]);
++ break;
++ case _grTexSource16:
++ // void grTexSource(GrChipID_t tmu, FxU32 startAddress, FxU32 evenOdd, GrTexInfo *info)
++ FP.grFunction3i1p = (pfunc3i1p)fn_pt[i];
++
++ // Copy the data from DB struct
++ MEM_BlockRead32(param[4], &dbtexinfo, sizeof(DBGrTexInfo));
++
++ texinfo.smallLod = dbtexinfo.smallLod;
++ texinfo.largeLod = dbtexinfo.largeLod;
++ texinfo.aspectRatio = dbtexinfo.aspectRatio;
++ texinfo.format = dbtexinfo.format;
++ // Should the data pointer be filled ?
++
++ FP.grFunction3i1p(param[1], param[2], param[3], &texinfo);
++ break;
++ case _grTexTextureMemRequired8:
++ // FxU32 grTexTextureMemRequired(FxU32 evenOdd, GrTexInfo *info)
++ FP.grRFunction1i1p = (prfunc1i1p)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++
++ // Copy the data from DB struct
++ MEM_BlockRead32(param[2], &dbtexinfo, sizeof(DBGrTexInfo));
++
++ texinfo.smallLod = dbtexinfo.smallLod;
++ texinfo.largeLod = dbtexinfo.largeLod;
++ texinfo.aspectRatio = dbtexinfo.aspectRatio;
++ texinfo.format = dbtexinfo.format;
++
++ mem_writed(ret, FP.grRFunction1i1p(param[1], &texinfo));
++
++ ret_value = G_OK;
++ break;
++ case _grTriStats8:
++ // void grTriStats(FxU32 *trisProcessed, FxU32 *trisDrawn)
++ FP.grFunction2p = (pfunc2p)fn_pt[i];
++ MEM_BlockRead32(param[1], ilist, sizeof(FxU32));
++ MEM_BlockRead32(param[2], ilist + 1, sizeof(FxU32));
++ FP.grFunction2p(ilist, ilist + 1);
++ MEM_BlockWrite32(param[1], ilist, sizeof(FxU32));
++ MEM_BlockWrite32(param[2], ilist + 1, sizeof(FxU32));
++ break;
++ case _gu3dfGetInfo8:
++ // FxBool gu3dfGetInfo(const char *filename, Gu3dfInfo *info)
++ FP.grRFunction2p = (prfunc2p)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ MEM_StrCopy(param[1], filename, 512);
++
++#if LOG_GLIDE
++ LOG_MSG("Glide:Filename info found in gu3dfGetInfo: %s", filename);
++#endif
++ if(!GetFileName(filename)) break;
++ mem_writed(ret, FP.grRFunction2p(filename, &guinfo));
++
++ // Copy the data back to DB struct if successful
++ if(mem_readd(ret)) {
++ MEM_BlockRead32(param[2], &dbguinfo, sizeof(DBGu3dfInfo));
++ dbguinfo.header.width = (Bit32u)guinfo.header.width;
++ dbguinfo.header.height = (Bit32u)guinfo.header.height;
++ dbguinfo.header.small_lod = (Bit32s)guinfo.header.small_lod;
++ dbguinfo.header.large_lod = (Bit32s)guinfo.header.large_lod;
++ dbguinfo.header.aspect_ratio = (Bit32s)guinfo.header.aspect_ratio;
++ dbguinfo.header.format = (Bit32s)guinfo.header.format;
++ dbguinfo.mem_required = (Bit32u)guinfo.mem_required;
++ MEM_BlockWrite32(param[2], &dbguinfo, sizeof(DBGu3dfInfo));
++ }
++
++ ret_value = G_OK;
++ break;
++ case _gu3dfLoad8:
++ // FxBool gu3dfLoad(const char *filename, Gu3dfInfo *info)
++ FP.grRFunction2p = (prfunc2p)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++
++ // Although glide ref specifies *info should be filled by gu3dfGetInfo before calling gu3dfLoad,
++ // OpenGlide will re-read the header in gu3dfLoad as well
++ MEM_BlockRead32(param[2], &dbguinfo, sizeof(DBGu3dfInfo));
++ MEM_StrCopy(param[1], filename, 512);
++
++#if LOG_GLIDE
++ LOG_MSG("Glide:Filename info found in gu3dfLoad: %s", filename);
++#endif
++ if(!GetFileName(filename)) break;
++
++ guinfo.data = texmem;
++ mem_writed(ret, FP.grRFunction2p(filename, &guinfo));
++
++ // Copy the data back to DB struct if successful
++ if(mem_readd(ret)) {
++ for(j=0;j<256;j++)
++ dbguinfo.table.palette.data[j] = (Bit32u)guinfo.table.palette.data[j];
++ MEM_BlockWrite(dbguinfo.data, guinfo.data, guinfo.mem_required);
++ }
++
++ MEM_BlockWrite32(param[2], &dbguinfo, sizeof(DBGu3dfInfo));
++ ret_value = G_OK;
++ break;
++ case _guAADrawTriangleWithClip12:
++ // void guAADrawTriangleWithClip(const GrVertex *va, const GrVertex *vb, const GrVertex *vc)
++ FP.grFunction3p = (pfunc3p)fn_pt[i];
++ MEM_BlockRead32(param[1], &vertex[0], sizeof(GrVertex));
++ MEM_BlockRead32(param[2], &vertex[1], sizeof(GrVertex));
++ MEM_BlockRead32(param[3], &vertex[2], sizeof(GrVertex));
++ FP.grFunction3p(&vertex[0], &vertex[1], &vertex[2]);
++ break;
++ case _guAlphaSource4:
++ // void guAlphaSource(GrAlphaSourceMode_t mode)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _guColorCombineFunction4:
++ // void guColorCombineFunction(GrColorCombineFunction_t func)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _guDrawPolygonVertexListWithClip8:
++ // void guDrawPolygonVertexListWithClip(int nverts, const GrVertex vlist[])
++ FP.grFunction1i1p = (pfunc1i1p)fn_pt[i];
++ MEM_BlockRead32(param[2], texmem, sizeof(GrVertex)*param[1]);
++ FP.grFunction1i1p(param[1], texmem);
++ break;
++ case _guDrawTriangleWithClip12:
++ // void guDrawTriangleWithClip(const GrVertex *va, const GrVertex *vb, const GrVertex *vc)
++ FP.grFunction3p = (pfunc3p)fn_pt[i];
++ MEM_BlockRead32(param[1], &vertex[0], sizeof(GrVertex));
++ MEM_BlockRead32(param[2], &vertex[1], sizeof(GrVertex));
++ MEM_BlockRead32(param[3], &vertex[2], sizeof(GrVertex));
++ FP.grFunction3p(&vertex[0], &vertex[1], &vertex[2]);
++ break;
++/*
++ case _guEncodeRLE1616:
++ //
++ FP.grFunction16 = (pfunc16)fn_pt[i];
++ FP.grFunction16();
++ break;
++ case _guEndianSwapBytes4:
++ //
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i();
++ break;
++ case _guEndianSwapWords4:
++ //
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i();
++ break;
++*/
++ case _guFogGenerateExp28:
++ // void guFogGenerateExp2(GrFog_t fogTable[GR_FOG_TABLE_SIZE], float density)
++ FP.grFunction1p1f = (pfunc1p1f)fn_pt[i];
++ FP.grFunction1p1f(texmem, int_to_float(param[2]));
++ MEM_BlockWrite32(param[1], texmem, GR_FOG_TABLE_SIZE*sizeof(GrFog_t));
++ break;
++ case _guFogGenerateExp8:
++ // void guFogGenerateExp(GrFog_t fogTable[GR_FOG_TABLE_SIZE], float density)
++ FP.grFunction1p1f = (pfunc1p1f)fn_pt[i];
++ FP.grFunction1p1f(texmem, int_to_float(param[2]));
++ MEM_BlockWrite32(param[1], texmem, GR_FOG_TABLE_SIZE*sizeof(GrFog_t));
++ break;
++ case _guFogGenerateLinear12:
++ // void guFogGenerateLinear(GrFog_t fogTable[GR_FOG_TABLE_SIZE], float nearW, float farW)
++ FP.grFunction1p2f = (pfunc1p2f)fn_pt[i];
++ FP.grFunction1p2f(texmem, int_to_float(param[2]), int_to_float(param[3]));
++ MEM_BlockWrite32(param[1], texmem, GR_FOG_TABLE_SIZE*sizeof(GrFog_t));
++ break;
++ case _guFogTableIndexToW4: {
++ // float guFogTableIndexToW(int i)
++ FP.grFFunction1i = (pffunc1i)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ float tmp = FP.grFFunction1i(param[1]);
++ SDL_memcpy(&j, &tmp, 4);
++ mem_writed(ret, SDL_SwapLE32(j));
++ ret_value = G_OK;
++ break;
++ }
++/*
++ case _guMPDrawTriangle12:
++ //
++ FP.grFunction3i = (pfunc3i)fn_pt[i];
++ FP.grFunction3i();
++ break;
++ case _guMPInit0:
++ //
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++ break;
++ case _guMPTexCombineFunction4:
++ //
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i();
++ break;
++ case _guMPTexSource8:
++ //
++ FP.grFunction2i = (pfunc2i)fn_pt[i];
++ FP.grFunction2i();
++ break;
++ case _guMovieSetName4:
++ //
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i();
++ break;
++ case _guMovieStart0:
++ //
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++ break;
++ case _guMovieStop0:
++ //
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++ break;
++*/
++ case _guTexAllocateMemory60:
++ // GrMipMapId_t guTexAllocateMemory(GrChipID_t tmu, FxU8 evenOddMask, int width, int height,
++ // GrTextureFormat_t format, GrMipMapMode_t mmMode, GrLOD_t smallLod, GrLOD_t largeLod,
++ // GrAspectRatio_t aspectRatio, GrTextureClampMode_t sClampMode,
++ // GrTextureClampMode_t tClampMode, GrTextureFilterMode_t minFilterMode,
++ // GrTextureFilterMode_t magFilterMode, float lodBias, FxBool lodBlend)
++ FP.grRFunction13i1f1i = (prfunc13i1f1i)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction13i1f1i(param[1], param[2], param[3], param[4], param[5], param[6], param[7],
++ param[8], param[9], param[10], param[11], param[12], param[13], int_to_float(param[14]), param[15]));
++ ret_value = G_OK;
++ break;
++ case _guTexChangeAttributes48:
++ // FxBool guTexChangeAttributes(GrMipMapID_t mmid, int width, int height, GrTextureFormat_t format,
++ // GrMipMapMode_t mmMode, GrLOD_t smallLod, GrLOD_t largeLod, GrAspectRatio_t aspectRatio,
++ // GrTextureClampMode_t sClampMode, GrTextureClampMode_t tClampMode,
++ // GrTextureFilterMode_t minFilterMode, GrTextureFilterMode_t magFilterMode)
++ FP.grRFunction12i = (prfunc12i)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction12i(param[1], param[2], param[3], param[4], param[5], param[6], param[7],
++ param[8], param[9], param[10], param[11], param[12]));
++ ret_value = G_OK;
++ break;
++ case _guTexCombineFunction8:
++ // void guTexCombineFunction(GrChipID_t tmu, GrTextureCombineFnc_t func)
++ FP.grFunction2i = (pfunc2i)fn_pt[i];
++ FP.grFunction2i(param[1], param[2]);
++ break;
++/*
++ case _guTexCreateColorMipMap0:
++ //
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++ break;
++*/
++ case _guTexDownloadMipMap12:
++ // void guTexDownloadMipMap(GrMipMapId_t mmid, const void *src, const GuNccTable *nccTable)
++ FP.grRPTFunction1i = (prptfunc1i)fn_pt[_guTexGetMipMapInfo4];
++ mipmap = (GrMipMapInfo*)FP.grRPTFunction1i(param[1]);
++
++ if(mipmap) {
++ texinfo.aspectRatio = mipmap->aspect_ratio;
++ texinfo.format = mipmap->format;
++ texinfo.largeLod = mipmap->lod_max;
++ texinfo.smallLod = mipmap->lod_min;
++
++ FP.grRFunction1i1p = (prfunc1i1p)fn_pt[_grTexTextureMemRequired8];
++ if(FP.grRFunction1i1p == NULL) {
++ LOG_MSG("Glide:Unable to get pointer to grTexTextureMemRequired");
++ return;
++ }
++
++ texsize = FP.grRFunction1i1p(mipmap->odd_even_mask, &texinfo);
++
++ MEM_BlockRead(param[2], texmem, texsize);
++ MEM_BlockRead32(param[3], (Bit8u*)texmem+texsize, sizeof(GuNccTable));
++
++ FP.grFunction1i2p = (pfunc1i2p)fn_pt[i];
++ FP.grFunction1i2p(param[1], texmem, (Bit8u*)texmem+texsize);
++ } else {
++ LOG_MSG("Glide:Unable to get GrMipMapInfo pointer");
++ }
++ break;
++/*
++ case _guTexDownloadMipMapLevel12:
++ // void guTexDownloadMipMapLevel(GrMipMapId_t mmid, GrLOD_t lod, const void **src)
++ FP.grFunction2i1p = (pfunc2i1p)fn_pt[i];
++ FP.grFunction2i1p(param[1], param[2], *param[3]);
++ break;
++*/
++ case _guTexGetCurrentMipMap4:
++ // GrMipMapId_t guTexGetCurrentMipMap(GrChipID_t tmu)
++ FP.grRFunction1i = (prfunc1i)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction1i(param[1]));
++ ret_value = G_OK;
++ break;
++/*
++ case _guTexGetMipMapInfo4:
++ // GrMipMapInfo *guTexGetMipMapInfo(GrMipMapId_t mmid)
++ FP.grRFunction4 = (prfunc4)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction4(param[1]));
++ ret_value = G_OK;
++ break;
++*/
++ case _guTexMemQueryAvail4:
++ // FxU32 guTexMemQueryAvail(GrChipID_t tmu)
++ FP.grRFunction1i = (prfunc1i)fn_pt[i];
++ if(ret == 0) {
++ LOG_MSG("Glide:Invalid return value handle for %s!", grTable[i].name);
++ return;
++ }
++ mem_writed(ret, FP.grRFunction1i(param[1]));
++ ret_value = G_OK;
++ break;
++ case _guTexMemReset0:
++ // void guTexMemReset(void)
++ FP.grFunction0 = (pfunc0)fn_pt[i];
++ FP.grFunction0();
++ break;
++ case _guTexSource4:
++ // void guTexSource(GrMipMapId_t mmid)
++ FP.grFunction1i = (pfunc1i)fn_pt[i];
++ FP.grFunction1i(param[1]);
++ break;
++ case _ConvertAndDownloadRle64: {
++ // void ConvertAndDownloadRle(GrChipID_t tmu, FxU32 startAddress, GrLOD_t thisLod, GrLOD_t largeLod,
++ // GrAspectRatio_t aspectRatio, GrTextureFormat_t format, FxU32 evenOdd,
++ // FxU8 *bm_data, long bm_h, FxU32 u0, FxU32 v0, FxU32 width, FxU32 height,
++ // FxU32 dest_width, FxU32 dest_height, FxU16 *tlut)
++
++#if LOG_GLIDE
++ LOG_MSG("Glide: RLE width: %d, height: %d, bm_h: %d, u0: %d, v0: %d, dest %dx%d",
++ param[12], param[13], param[9], param[10], param[11], param[14], param[15]);
++#endif
++
++ FxU8 c;
++ FxU32 scount = 0;
++ FxU32 dcount = 0;
++
++ FxU16 * src = ptr16 + param[14]*param[15];
++ FxU32 offset = 4 + param[9];
++
++ // Line offset (v0)
++ for(j = 0; j < param[11]; j++ ) {
++ offset += mem_readb(param[8]+4+j);
++ }
++
++ // Write height lines
++ for(k = 0; k < param[13]; k++) {
++
++ // Decode one RLE line
++ scount = offset;
++ while((c = mem_readb(param[8]+scount)) != 0xE0) {
++
++ if(c > 0xE0) {
++ for(int count = 0; count < (c&0x1f); count++) {
++
++ // tlut is FxU16*
++ src[dcount] = mem_readw(param[16]+(mem_readb(param[8]+scount+1)<<1));
++ dcount++;
++ }
++ scount += 2;
++
++ } else {
++ src[dcount] = mem_readw(param[16]+(c<<1));
++ dcount++; scount++;
++ }
++ }
++
++ // Copy Line into destination texture, offset u0
++ SDL_memcpy(ptr16 + (k*param[14]), src + param[10], sizeof(FxU16)*param[14]);
++ offset += mem_readb(param[8] + 4 + j++);
++ dcount = 0;
++ }
++
++ // One additional line
++ if(param[13] < param[15])
++ SDL_memcpy(ptr16 + (k*param[14]), src + param[10], sizeof(FxU16)*param[14]);
++
++ // Download decoded texture
++ texinfo.smallLod = param[3];
++ texinfo.largeLod = param[4];
++ texinfo.aspectRatio = param[5];
++ texinfo.format = param[6];
++ texinfo.data = ptr16;
++
++ // void grTexDownloadMipMap(GrChipID_t tmu, FxU32 startAddress, FxU32 evenOdd, GrTexInfo *info)
++ FP.grFunction3i1p = (pfunc3i1p)fn_pt[_grTexDownloadMipMap16];
++ if(FP.grFunction3i1p == NULL) {
++ LOG_MSG("Glide:Unable to get pointer to grTexDownloadMipMap");
++ break;
++ }
++ FP.grFunction3i1p(param[1], param[2], param[7], &texinfo);
++ break;
++ }
++ default:
++ LOG_MSG("Glide:Unsupported glide call %s", grTable[i].name);
++ break;
++
++ } /* switch */
++} /* process_msg() */
+diff -Nawurp a/src/hardware/Makefile.am b/src/hardware/Makefile.am
+--- a/src/hardware/Makefile.am 2019-06-15 00:25:57.000000000 +0000
++++ b/src/hardware/Makefile.am 2019-06-15 00:25:58.000000000 +0000
+@@ -10,6 +10,6 @@ libhardware_a_SOURCES = adlib.cpp dma.cp
+ memory.cpp mixer.cpp pcspeaker.cpp pci_bus.cpp pic.cpp sblaster.cpp tandy_sound.cpp timer.cpp \
+ vga.cpp vga_attr.cpp vga_crtc.cpp vga_dac.cpp vga_draw.cpp vga_gfx.cpp vga_other.cpp \
+ vga_memory.cpp vga_misc.cpp vga_seq.cpp vga_xga.cpp vga_s3.cpp vga_tseng.cpp vga_paradise.cpp \
+- cmos.cpp disney.cpp gus.cpp mpu401.cpp ipx.cpp ipxserver.cpp dbopl.cpp
++ cmos.cpp disney.cpp gus.cpp mpu401.cpp ipx.cpp ipxserver.cpp dbopl.cpp glide.cpp
+
+
+diff -Nawurp a/src/hardware/memory.cpp b/src/hardware/memory.cpp
+--- a/src/hardware/memory.cpp 2019-06-15 00:25:55.000000000 +0000
++++ b/src/hardware/memory.cpp 2019-06-15 00:25:58.000000000 +0000
+@@ -23,6 +23,7 @@
+ #include "setup.h"
+ #include "paging.h"
+ #include "regs.h"
++#include "glidedef.h"
+
+ #include <string.h>
+
+@@ -140,6 +141,8 @@ PageHandler * MEM_GetPageHandler(Bitu ph
+ } else if ((phys_page>=memory.lfb.start_page+0x01000000/4096) &&
+ (phys_page<memory.lfb.start_page+0x01000000/4096+16)) {
+ return memory.lfb.mmiohandler;
++ } else if (glide.enabled && (phys_page>=(GLIDE_LFB>>12)) && (phys_page<(GLIDE_LFB>>12)+GLIDE_PAGES)) {
++ return (PageHandler*)glide.lfb_pagehandler;
+ }
+ return &illegal_page_handler;
+ }
+@@ -191,6 +194,24 @@ void MEM_BlockWrite(PhysPt pt,void const
+ }
+ }
+
++void MEM_BlockRead32(PhysPt pt,void * data,Bitu size) {
++ Bit32u * write=(Bit32u *) data;
++ size>>=2;
++ while (size--) {
++ *write++=mem_readd_inline(pt);
++ pt+=4;
++ }
++}
++
++void MEM_BlockWrite32(PhysPt pt,void * data,Bitu size) {
++ Bit32u * read=(Bit32u *) data;
++ size>>=2;
++ while (size--) {
++ mem_writed_inline(pt,*read++);
++ pt+=4;
++ }
++}
++
+ void MEM_BlockCopy(PhysPt dest,PhysPt src,Bitu size) {
+ mem_memcpy(dest,src,size);
+ }
diff --git a/dosbox.desktop b/dosbox.desktop
new file mode 100644
index 000000000000..16532ac1a586
--- /dev/null
+++ b/dosbox.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Type=Application
+Version=1.0
+Name=Dosbox
+Comment=DOS emulator for running DOS games
+Path=/usr/bin
+Exec=dosbox
+Icon=dosbox
+Terminal=false
+StartupNotify=false
+Categories=Emulator;Game;
diff --git a/dosbox.png b/dosbox.png
new file mode 100644
index 000000000000..b8a9179864a8
--- /dev/null
+++ b/dosbox.png
Binary files differ