Glide renderer

This commit is contained in:
Anders Jenbo 2026-05-02 13:32:36 +02:00
parent e939aa3ef7
commit 613c1e7339
5 changed files with 1741 additions and 0 deletions

View File

@ -90,6 +90,7 @@ cmake_dependent_option(ISLE_USE_LWS "Use libwebsockets for native multiplayer" O
cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN;NOT DOS;NOT NINTENDO_3DS;NOT NINTENDO_SWITCH;NOT WINDOWS_STORE;NOT VITA" OFF)
cmake_dependent_option(ISLE_COMPILE_SHADERS "Compile shaders" ON "SDL_SHADERCROSS_BIN;TARGET Python3::Interpreter" OFF)
cmake_dependent_option(CMAKE_POSITION_INDEPENDENT_CODE "Build with -fPIC" ON "NOT DOS;NOT VITA" OFF)
cmake_dependent_option(ISLE_USE_GLIDE "Build with 3dfx Glide support (Voodoo)" OFF "DOS" OFF)
option(ENABLE_CLANG_TIDY "Enable clang-tidy")
option(DOWNLOAD_DEPENDENCIES "Download dependencies" ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE PATH "Directory where to put executables and dll")
@ -103,6 +104,126 @@ if(DOS)
# (normally in libatomic, which DJGPP doesn't ship) are provided as simple
# non-atomic stubs in 3rdparty/djgpp_atomic64.c since DOS is single-threaded.
add_compile_options(-march=i486)
if(ISLE_USE_GLIDE)
# 3dfx Glide support for Voodoo cards.
# See: https://federicotech.wordpress.com/2024/12/19/compiling-3dfx-glide-2-and-3-in-ms-dos-with-djgpp/
set(GLIDE_VERSION "3" CACHE STRING "Glide API version: 2 or 3")
set_property(CACHE GLIDE_VERSION PROPERTY STRINGS 2 3)
set(GLIDE_HW "sst1" CACHE STRING "Target Glide hardware: sst1 (Voodoo1), sst96 (Rush), cvg (Voodoo2), h3 (Banshee), h5 (Voodoo3/4/5)")
set_property(CACHE GLIDE_HW PROPERTY STRINGS sst1 sst96 cvg h3 h5)
include(FetchContent)
FetchContent_Declare(
glide
GIT_REPOSITORY "https://github.com/sezero/glide.git"
GIT_TAG "glide-devel-sezero"
)
FetchContent_MakeAvailable(glide)
set(GLIDE_SRC_DIR "${glide_SOURCE_DIR}")
if(GLIDE_VERSION STREQUAL "3")
set(GLIDE_ROOT "${GLIDE_SRC_DIR}/glide3x")
else()
set(GLIDE_ROOT "${GLIDE_SRC_DIR}/glide2x")
endif()
# Copy swlibs into glide dir (required by the build system)
if(NOT EXISTS "${GLIDE_ROOT}/swlibs")
file(COPY "${GLIDE_SRC_DIR}/swlibs" DESTINATION "${GLIDE_ROOT}")
endif()
# Patch fxglide.h for h3/h5 builds: the P6 fence inline asm check
# fails when HOST_CC is x86_64 gcc (no __i386__ defined).
foreach(_glide_hw_dir h3 h5)
set(_fxglide "${GLIDE_ROOT}/${_glide_hw_dir}/glide/src/fxglide.h")
if(EXISTS "${_fxglide}")
file(READ "${_fxglide}" _fxglide_content)
string(FIND "${_fxglide_content}" "defined(__x86_64__)" _already_patched)
if(_already_patched EQUAL -1)
string(REPLACE
"defined(__GNUC__) && defined(__i386__)"
"defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))"
_fxglide_content "${_fxglide_content}")
file(WRITE "${_fxglide}" "${_fxglide_content}")
endif()
endif()
endforeach()
# Determine include and lib paths based on hardware target
set(_glide_subdir "glide")
if(GLIDE_VERSION STREQUAL "3")
set(_glide_subdir "glide3")
endif()
if(GLIDE_HW STREQUAL "sst1" OR GLIDE_HW STREQUAL "sst96")
set(GLIDE_INCLUDE_DIR
"${GLIDE_ROOT}/swlibs/fxmisc"
"${GLIDE_ROOT}/sst1/${_glide_subdir}/src"
"${GLIDE_ROOT}/sst1/init"
)
set(GLIDE_LIB_DIR "${GLIDE_ROOT}/sst1/lib/${GLIDE_HW}")
elseif(GLIDE_HW STREQUAL "cvg")
set(GLIDE_INCLUDE_DIR
"${GLIDE_ROOT}/swlibs/fxmisc"
"${GLIDE_ROOT}/cvg/${_glide_subdir}/src"
"${GLIDE_ROOT}/cvg/incsrc"
)
set(GLIDE_LIB_DIR "${GLIDE_ROOT}/cvg/lib")
elseif(GLIDE_HW STREQUAL "h3")
set(GLIDE_INCLUDE_DIR
"${GLIDE_ROOT}/swlibs/fxmisc"
"${GLIDE_ROOT}/h3/${_glide_subdir}/src"
"${GLIDE_ROOT}/h3/incsrc"
)
set(GLIDE_LIB_DIR "${GLIDE_ROOT}/h3/lib")
elseif(GLIDE_HW STREQUAL "h5")
set(GLIDE_INCLUDE_DIR
"${GLIDE_ROOT}/swlibs/fxmisc"
"${GLIDE_ROOT}/h5/${_glide_subdir}/src"
"${GLIDE_ROOT}/h5/incsrc"
)
set(GLIDE_LIB_DIR "${GLIDE_ROOT}/h5/lib")
endif()
# Build Glide using its native DJGPP Makefile.
# We pass CC and AR from the CMake toolchain so it uses the correct cross-compiler.
if(GLIDE_VERSION STREQUAL "3")
set(_glide_lib_name "libgld3x.a")
set(_glide_lib_var "GLIDE_LIB=libgld3x.a")
set(_glide_imp_var "GLIDE_IMP=libgld3i.a")
else()
set(_glide_lib_name "libgld2x.a")
set(_glide_lib_var "GLIDE_LIB=libgld2x.a")
set(_glide_imp_var "GLIDE_IMP=libgld2i.a")
endif()
set(GLIDE_LIB_FILE "${GLIDE_LIB_DIR}/${_glide_lib_name}")
if(NOT EXISTS "${GLIDE_LIB_FILE}")
message(STATUS "Building 3dfx Glide ${GLIDE_VERSION}.x for ${GLIDE_HW}...")
execute_process(
COMMAND make
${_glide_lib_var}
${_glide_imp_var}
FX_GLIDE_HW=${GLIDE_HW}
CC=${CMAKE_C_COMPILER}
AR=${CMAKE_AR}
HOST_CC=gcc
-f Makefile.DJ
WORKING_DIRECTORY "${GLIDE_ROOT}"
RESULT_VARIABLE GLIDE_BUILD_RESULT
)
if(NOT GLIDE_BUILD_RESULT EQUAL 0)
message(FATAL_ERROR "Failed to build Glide library. "
"You may need to build manually: cd ${GLIDE_ROOT} && make ${_glide_lib_var} FX_GLIDE_HW=${GLIDE_HW} CC=${CMAKE_C_COMPILER} AR=${CMAKE_AR} -f Makefile.DJ")
endif()
endif()
if(NOT EXISTS "${GLIDE_LIB_FILE}")
message(FATAL_ERROR "Glide library not found at ${GLIDE_LIB_FILE} after build.")
endif()
set(GLIDE_LIBRARY "${GLIDE_LIB_FILE}")
message(STATUS "3dfx Glide: ${GLIDE_HW} (${GLIDE_LIBRARY})")
endif()
endif()
message(STATUS "Isle app: ${ISLE_BUILD_APP}")

View File

@ -71,6 +71,15 @@ endif()
if(DOS)
list(REMOVE_ITEM GRAPHICS_BACKENDS USE_SDL_GPU USE_OPENGL1 USE_OPENGLES2) #USE_SDL_GPU
if(ISLE_USE_GLIDE)
target_sources(miniwin PRIVATE src/d3drm/backends/glide/renderer.cpp)
target_include_directories(miniwin PRIVATE ${GLIDE_INCLUDE_DIR})
target_link_libraries(miniwin PRIVATE ${GLIDE_LIBRARY})
if(GLIDE_VERSION STREQUAL "3")
target_compile_definitions(miniwin PRIVATE GLIDE3=1)
endif()
list(APPEND GRAPHICS_BACKENDS USE_GLIDE)
endif()
endif()
list(APPEND GRAPHICS_BACKENDS USE_PALETTE_SW_RENDER)

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,9 @@
#ifdef USE_GXM
#include "d3drmrenderer_gxm.h"
#endif
#ifdef USE_GLIDE
#include "d3drmrenderer_glide.h"
#endif
Direct3DRMRenderer* CreateDirect3DRMRenderer(
const IDirect3DMiniwin* d3d,
@ -78,6 +81,11 @@ Direct3DRMRenderer* CreateDirect3DRMRenderer(
return GXMRenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight, d3d->GetMSAASamples());
}
#endif
#ifdef USE_GLIDE
if (SDL_memcmp(guid, &GLIDE_GUID, sizeof(GUID)) == 0) {
return new Direct3DRMGlideRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#endif
#ifdef USE_PALETTE_SW_RENDER
if (SDL_memcmp(guid, &PALETTE_SW_GUID, sizeof(GUID)) == 0) {
return new Direct3DRMPaletteSWRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight);
@ -112,6 +120,9 @@ void Direct3DRMRenderer_EnumDevices(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICE
#ifdef USE_PALETTE_SW_RENDER
Direct3DRMPaletteSW_EnumDevice(cb, ctx);
#endif
#ifdef USE_GLIDE
Direct3DRMGlide_EnumDevice(cb, ctx);
#endif
#ifdef USE_GXM
GXMRenderer_EnumDevice(cb, ctx);
#endif

View File

@ -0,0 +1,110 @@
#pragma once
#include "d3drmrenderer.h"
#include "d3drmtexture_impl.h"
#include "ddraw_impl.h"
extern "C"
{
#include <glide.h>
}
#ifdef GLIDE3
// Glide 3 uses custom vertex layout - define our own struct
struct GlideVertex {
float x, y; // screen coords
float ooz; // 65535/Z (for Z-buffering)
float oow; // 1/w (for perspective correction)
float r, g, b, a; // color (0-255)
float sow, tow; // texture coords (s/w, t/w)
};
#define GR_WDEPTHVALUE_FARTHEST 0xFFFF
#else
typedef GrVertex GlideVertex;
#endif
#include <vector>
// clang-format off
DEFINE_GUID(GLIDE_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08);
// clang-format on
struct GlideTextureEntry {
IDirect3DRMTexture* texture;
Uint32 version;
GrTexInfo info;
FxU32 startAddress;
int texW; // actual power-of-2 width uploaded to Glide
int texH; // actual power-of-2 height uploaded to Glide
};
struct GlideMeshEntry {
const MeshGroup* meshGroup;
Uint32 version;
bool flat;
// Cached flattened geometry (only populated for flat-shaded meshes)
std::vector<D3DRMVERTEX> flatVertices;
std::vector<uint16_t> flatIndices;
};
class Direct3DRMGlideRenderer : public Direct3DRMRenderer {
public:
Direct3DRMGlideRenderer(int width, int height);
~Direct3DRMGlideRenderer() override;
void PushLights(const SceneLight* lights, size_t count) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
void SetFrustumPlanes(const Plane* frustumPlanes) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI = false, float scaleX = 0, float scaleY = 0) override;
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
HRESULT BeginFrame() override;
void EnableTransparency() override;
void SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
) override;
HRESULT FinalizeFrame() override;
void Resize(int width, int height, const ViewportTransform& viewportTransform) override;
void Clear(float r, float g, float b) override;
void Flip() override;
void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override;
void Download(SDL_Surface* target) override;
void SetDither(bool dither) override;
void SetPalette(SDL_Palette* palette) override;
private:
std::vector<GlideTextureEntry> m_textureCache;
std::vector<GlideMeshEntry> m_meshCache;
std::vector<SceneLight> m_lights;
D3DRMMATRIX4D m_projection;
D3DVALUE m_frontClip;
D3DVALUE m_backClip;
Plane m_frustumPlanes[6];
std::vector<D3DRMVERTEX> m_transformedVertices;
std::vector<SDL_Color> m_litColors;
bool m_transparencyEnabled;
FxU32 m_nextTextureAddress;
SDL_Palette* m_palette = nullptr;
bool m_paletteUploaded = false;
#ifdef GLIDE3
FxU32 m_glideContext = 0;
#endif
};
inline static void Direct3DRMGlide_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
{
D3DDEVICEDESC halDesc = {};
D3DDEVICEDESC helDesc = {};
halDesc.dcmColorModel = D3DCOLOR_RGB;
halDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH;
halDesc.dwDeviceZBufferBitDepth = DDBD_16;
halDesc.dwDeviceRenderBitDepth = DDBD_16;
halDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE;
halDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND;
halDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR;
EnumDevice(cb, ctx, "3dfx Glide", &halDesc, &helDesc, GLIDE_GUID);
}