Compare commits

...

27 Commits

Author SHA1 Message Date
lewa_j
7e2b51f5a3 ref: dx2: zbuffer and clear 2026-07-25 16:31:15 +03:00
lewa_j
2086dc6128 ref_dx2: hack half pixel offset 2026-07-25 16:30:23 +03:00
lewa_j
5c4dd797ce ref_dx2: rebase onto ref_api v17 2026-07-25 16:30:23 +03:00
lewa_j
e7636d580f ref: dx2: d3d transformation state. Drawing brushes! 2026-07-25 16:27:19 +03:00
lewa_j
64c1413278 ref: dx2: R_DrawWorld (WIP) 2026-07-25 16:24:59 +03:00
lewa_j
7eb1220b19 ref: dx2: Build world polygons 2026-07-25 16:24:58 +03:00
lewa_j
a260b4c143 ref: dx2: some culling cvars 2026-07-25 16:24:43 +03:00
lewa_j
cb5146bb48 ref: dx2: Display transform rotation (WIP) 2026-07-25 16:24:43 +03:00
lewa_j
0365e645df ref: dx2: d3d matrix and transform state 2026-07-25 16:24:36 +03:00
lewa_j
d1143b4b5c ref: dx2: add frustum, move Assert and some externs, get world pointer from engine 2026-07-25 16:20:16 +03:00
lewa_j
aa4bdf0732 ref: dx2: implement FillRGBA through d3d 2026-07-25 16:14:55 +03:00
lewa_j
700a5333af ref: dx2: ExecuteBuffer context 2026-07-25 16:14:55 +03:00
lewa_j
ad25458c5a ref: dx2: Move more code around (r_draw, r_main, r_surf) 2026-07-25 16:11:58 +03:00
lewa_j
8f6ff1b64f ref: dx2: PARM_STENCIL_ACTIVE 2026-07-25 16:11:57 +03:00
lewa_j
3abb39f172 ref: dx2: R_GammaChanged stub 2026-07-25 16:11:52 +03:00
lewa_j
6a02b77163 ref: dx2: Move functions around 2026-07-25 16:11:50 +03:00
lewa_j
a3c26affa3 ref: dx2: Move D3D init code to r_d3d.c 2026-07-25 16:08:57 +03:00
lewa_j
95df96e668 ref: dx2: vertex color 2026-07-25 16:02:05 +03:00
lewa_j
bdce95a31b ref: dx2: implement FreeTexture 2026-07-25 16:02:05 +03:00
lewa_j
eec9609354 ref: dx2: blend, alpha test, fix texture formats with alpha 2026-07-25 16:01:55 +03:00
lewa_j
a58f2ac13b ref: dx2: render textures 2026-07-25 16:01:06 +03:00
lewa_j
e704247f9d ref: dx2: start D3D work 2026-07-25 16:01:06 +03:00
lewa_j
07a096d04e wscript: ref_dx2 2026-07-25 15:55:14 +03:00
lewa_j
f5077a13b9 engine: client: add ref_dx2 to list 2026-07-25 15:54:25 +03:00
lewa_j
d414eeb246 ref_dx2 (WIP) 2026-07-25 15:54:24 +03:00
lewa_j
5daf686a82 engine: client: REF_D3D support 2026-07-25 15:44:24 +03:00
lewa_j
635b382c1d gl4es: msvc: suppress warning spam from CHECK_SHADER: warning C4098: 'void' function returning a value
Same flag is used in gl4es's CMakeLists
2026-07-25 15:26:25 +03:00
18 changed files with 3486 additions and 15 deletions

View File

@@ -16,6 +16,8 @@ def build(bld):
cflags = []
if bld.env.COMPILER_CC != 'msvc':
cflags += ['-w', '-fvisibility=hidden', '-std=gnu99']
else:
cflags += ['-wd4098']
bld.stlib(source = gl4es_srcdir.ant_glob(['gl/*.c', 'gl/*/*.c', 'glx/hardext.c']),
target = 'gl4es',
includes = ['gl4es/src', 'gl4es/src/gl', 'gl4es/src/glx', 'gl4es/include'],

View File

@@ -706,6 +706,9 @@ static void R_CollectRendererNames( void )
#if XASH_REF_GLES3COMPAT_ENABLED
"gles3compat",
#endif
#if XASH_REF_DX2_ENABLED
"dx2",
#endif
#if XASH_REF_SOFT_ENABLED
"soft",
#endif
@@ -729,6 +732,9 @@ static void R_CollectRendererNames( void )
#if XASH_REF_GLES3COMPAT_ENABLED
"GLES3 (gl2_shim)",
#endif
#if XASH_REF_DX2_ENABLED
"DirectX 2",
#endif
#if XASH_REF_SOFT_ENABLED
"Software",
#endif

View File

@@ -28,7 +28,7 @@ typedef struct
{
void *context; // handle to GL rendering context
ref_safegl_context_t safe;
qboolean software;
ref_graphic_apis_t type;
} glwstate_t;
extern glwstate_t glw_state;

View File

@@ -285,7 +285,7 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
if( window_mode != WINDOW_MODE_WINDOWED )
SetBits( flags, SDL_FULLSCREEN|SDL_HWSURFACE );
if( !glw_state.software )
if( glw_state.type == REF_GL )
SetBits( flags, SDL_OPENGL );
if( !VID_CreateWindowWithSafeGL( wndname, 0, 0, width, height, flags ))
@@ -381,10 +381,10 @@ qboolean R_Init_Video( ref_graphic_apis_t type )
refState.desktopBitsPixel = 16;
glw_state.type = type;
switch( type )
{
case REF_SOFTWARE:
glw_state.software = true;
break;
case REF_GL:
if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", safe ) )
@@ -399,6 +399,8 @@ qboolean R_Init_Video( ref_graphic_apis_t type )
return false;
}
break;
case REF_D3D:
break;
default:
Host_Error( "Can't initialize unknown context type %d!\n", type );
break;
@@ -417,6 +419,7 @@ qboolean R_Init_Video( ref_graphic_apis_t type )
ref.dllFuncs.GL_InitExtensions();
break;
case REF_SOFTWARE:
case REF_D3D:
default:
break;
}

View File

@@ -359,7 +359,7 @@ void GL_UpdateSwapInterval( void )
{
ClearBits( gl_vsync.flags, FCVAR_CHANGED );
if( SDL_GL_SetSwapInterval( gl_vsync.value ) < 0 )
if( glw_state.context && SDL_GL_SetSwapInterval( gl_vsync.value ) < 0 )
Con_Reportf( S_ERROR "SDL_GL_SetSwapInterval: %s\n", SDL_GetError( ));
}
}
@@ -386,7 +386,7 @@ static void VID_GetWindowSizeInPixels( SDL_Window *window, SDL_Renderer *rendere
#if SDL_VERSION_ATLEAST( 2, 26, 0 )
SDL_GetWindowSizeInPixels( window, w, h );
#else
if( glw_state.software )
if( glw_state.type != REF_GL )
SDL_GetRendererOutputSize( renderer, w, h );
else
SDL_GL_GetDrawableSize( window, w, h );
@@ -669,7 +669,7 @@ static rserr_t VID_CreateWindow( const int input_width, const int input_height,
SetBits( flags, SDL_WINDOW_ALLOW_HIGHDPI );
#endif // !XASH_WIN32
if( !glw_state.software )
if( glw_state.type == REF_GL )
SetBits( flags, SDL_WINDOW_OPENGL );
if( vid_maximized.value )
@@ -681,7 +681,7 @@ static rserr_t VID_CreateWindow( const int input_width, const int input_height,
if( !host.hWnd )
{
err = glw_state.software ? rserr_unknown : rserr_invalid_context;
err = (glw_state.type == REF_GL) ? rserr_invalid_context : rserr_unknown;
goto cleanup;
}
@@ -698,7 +698,7 @@ static rserr_t VID_CreateWindow( const int input_width, const int input_height,
SDL_ShowWindow( host.hWnd );
SDL_RaiseWindow( host.hWnd );
if( glw_state.software )
if( glw_state.type == REF_SOFTWARE )
{
char cmd[64];
@@ -720,7 +720,7 @@ static rserr_t VID_CreateWindow( const int input_width, const int input_height,
Con_Printf( "SDL_Renderer %s initialized\n", info.name );
}
}
else
else if( glw_state.type == REF_GL )
{
glw_state.context = SDL_GL_CreateContext( host.hWnd );
@@ -917,10 +917,10 @@ qboolean R_Init_Video( ref_graphic_apis_t type )
SDL_SetHint( SDL_HINT_VIDEO_X11_XRANDR, "1" );
SDL_SetHint( SDL_HINT_VIDEO_X11_XVIDMODE, "1" );
glw_state.type = type;
switch( type )
{
case REF_SOFTWARE:
glw_state.software = true;
break;
case REF_GL:
if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", safe ) )
@@ -935,6 +935,8 @@ qboolean R_Init_Video( ref_graphic_apis_t type )
return false;
}
break;
case REF_D3D:
break;
default:
Host_Error( "Can't initialize unknown context type %d!\n", type );
break;
@@ -950,6 +952,7 @@ qboolean R_Init_Video( ref_graphic_apis_t type )
ref.dllFuncs.GL_InitExtensions();
break;
case REF_SOFTWARE:
case REF_D3D:
default:
break;
}

View File

@@ -113,7 +113,7 @@ static qboolean VID_CreateWindow( const int input_width, const int input_height,
SDL_Rect rect = { SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, input_width, input_height };
Uint32 flags = SDL_WINDOW_RESIZABLE;
if( !glw_state.software )
if( glw_state.type == REF_GL )
SetBits( flags, SDL_WINDOW_OPENGL );
// probe true fullscreen first, if it fails, try borderless next
@@ -168,12 +168,12 @@ static qboolean VID_CreateWindow( const int input_width, const int input_height,
VID_SetWindowIcon( host.hWnd );
if( glw_state.software )
if( glw_state.type == REF_SOFTWARE )
{
// no support yet
return false;
}
else
else if ( glw_state.type == REF_GL )
{
glw_state.context = SDL_GL_CreateContext( host.hWnd );
@@ -337,10 +337,10 @@ qboolean R_Init_Video( ref_graphic_apis_t type )
if( Sys_CheckParm( "-egl" ))
Con_Printf( S_WARN "%s: -egl option is deprecated\n", __func__ );
glw_state.type = type;
switch( type )
{
case REF_SOFTWARE:
glw_state.software = true;
break;
case REF_GL:
{
@@ -357,6 +357,8 @@ qboolean R_Init_Video( ref_graphic_apis_t type )
break;
}
case REF_D3D:
break;
default:
Host_Error( "Can't initialize unknown context type %d!\n", type );
break;

19
ref/dx2/dllmain.cpp Normal file
View File

@@ -0,0 +1,19 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "windows.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

481
ref/dx2/r_context.c Normal file
View File

@@ -0,0 +1,481 @@
/*
r_context.c -- dx2 renderer context
Copyright (C) 2023-2024 a1batross
Copyright (C) 2025-2026 lewa_j
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 3 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.
*/
#define INITGUID
#include "r_local.h"
#include "xash3d_mathlib.h"
#include "crtlib.h"
#include "r_studioint.h"
//#pragma comment(lib, "ddraw.lib")
//TODO COM_GetProcAddress
static void R_SimpleStub( void )
{
;
}
static void R_SimpleStubInt( int unused )
{
;
}
static void R_SimpleStubUInt( unsigned int unused )
{
;
}
static const char *R_GetConfigName( void )
{
return "ref_dx2";
}
static qboolean R_SetDisplayTransform( ref_screen_rotation_t rotate, int offset_x, int offset_y, float scale_x, float scale_y )
{
qboolean ret = true;
tr.rotation = rotate;
if( offset_x || offset_y )
{
gEngfuncs.Con_Printf("offset transform not supported\n");
ret = false;
}
if( scale_x != 1.0f || scale_y != 1.0f )
{
gEngfuncs.Con_Printf("scale transform not supported\n");
ret = false;
}
return ret;
}
void GL_BackendStartFrame( void )
{
}
void GL_BackendEndFrame( void )
{
}
void GL_SetRenderMode( int mode )
{
dxc.renderMode = mode;
}
static void R_ProcessEntData( qboolean allocate, cl_entity_t *entities, unsigned int max_entities )
{
if (!allocate)
{
tr.draw_list->num_solid_entities = 0;
tr.draw_list->num_trans_entities = 0;
tr.draw_list->num_beam_entities = 0;
tr.max_entities = 0;
tr.entities = NULL;
}
else
{
tr.max_entities = max_entities;
tr.entities = entities;
}
if (gEngfuncs.drawFuncs->R_ProcessEntData)
gEngfuncs.drawFuncs->R_ProcessEntData(allocate);
}
static void R_SetupSky( int *skytextures )
{
;
}
static qboolean VID_ScreenShot( const char *filename, int shot_type )
{
return false;
}
static qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qboolean skyshot )
{
return false;
}
static colorVec R_LightPoint( const float *p )
{
colorVec c = { 0 };
return c;
}
static void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, float scale )
{
;
}
static int R_CreateDecalList( struct decallist_s *pList )
{
return 0;
}
static float R_StudioEstimateFrame( cl_entity_t *e, mstudioseqdesc_t *pseqdesc, double time )
{
return 0.0f;
}
static void R_StudioLerpMovement( cl_entity_t *e, double time, vec3_t origin, vec3_t angles )
{
;
}
static qboolean R_StudioFillAPI( struct engine_studio_api_s *api, struct r_studio_interface_s *pDefaultDraw )
{
return false;
}
static r_studio_interface_t *pStudioDraw;
static void R_StudioSetDrawInterface( struct r_studio_interface_s *pDraw )
{
pStudioDraw = pDraw;
}
static void R_SetSkyCloudsTextures( int solidskyTexture, int alphaskyTexture )
{
;
}
static void CL_RunLightStyles( lightstyle_t *ls )
{
}
static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buffer, size_t buffersize )
{
gEngfuncs.Con_Printf("Mod_ProcessRenderData(%p(%s), %d, %p, %zu)\n", mod, mod->name, create, buffer, buffersize);
return true;
}
static void Mod_StudioLoadTextures( model_t *mod, void *data )
{
;
}
static void CL_DrawParticles( double frametime, particle_t *particles, float partsize )
{
;
}
static void CL_DrawTracers( double frametime, particle_t *tracers )
{
;
}
static void CL_DrawBeams( int fTrans, BEAM *beams )
{
;
}
static intptr_t RefGetParm( int parm, int arg )
{
dx_texture_t *glt;
switch (parm)
{
case PARM_TEX_WIDTH:
glt = R_GetTexture(arg);
return glt->width;
case PARM_TEX_HEIGHT:
glt = R_GetTexture(arg);
return glt->height;
case PARM_TEX_SRC_WIDTH:
glt = R_GetTexture(arg);
return glt->srcWidth;
case PARM_TEX_SRC_HEIGHT:
glt = R_GetTexture(arg);
return glt->srcHeight;
case PARM_TEX_GLFORMAT:
glt = R_GetTexture(arg);
return 0;
case PARM_TEX_ENCODE:
glt = R_GetTexture(arg);
return 0;
case PARM_TEX_MIPCOUNT:
glt = R_GetTexture(arg);
return glt->numMips;
case PARM_TEX_DEPTH:
glt = R_GetTexture(arg);
return 1;
#if 0
case PARM_TEX_SKYBOX:
Assert(arg >= 0 && arg < 6);
return tr.skyboxTextures[arg];
#endif
case PARM_TEX_SKYTEXNUM:
return tr.skytexturenum;
#if 0
case PARM_TEX_LIGHTMAP:
arg = bound(0, arg, MAX_LIGHTMAPS - 1);
return tr.lightmapTextures[arg];
#endif
case PARM_TEX_TARGET:
glt = R_GetTexture(arg);
return 0;
case PARM_TEX_TEXNUM:
glt = R_GetTexture(arg);
return arg;
case PARM_TEX_FLAGS:
glt = R_GetTexture(arg);
return glt->flags;
#if 0
case PARM_TEX_MEMORY:
return GL_TexMemory();
case PARM_ACTIVE_TMU:
return glState.activeTMU;
#endif
case PARM_LIGHTSTYLEVALUE:
arg = bound(0, arg, MAX_LIGHTSTYLES - 1);
return g_lightstylevalue[arg];
#if 0
case PARM_MAX_IMAGE_UNITS:
return GL_MaxTextureUnits();
case PARM_REBUILD_GAMMA:
return glConfig.softwareGammaUpdate;
case PARM_GL_CONTEXT_TYPE:
return glConfig.context;
case PARM_GLES_WRAPPER:
return glConfig.wrapper;
#endif
case PARM_STENCIL_ACTIVE:
return 0;//No stencil in dx2
case PARM_TEX_FILTERING:
return 0;
#if 0
if (arg < 0)
return gl_texture_nearest.value == 0.0f;
return GL_TextureFilteringEnabled(R_GetTexture(arg));
#endif
case PARM_GET_STUDIO_HDR:
//return (intptr_t)R_StudioGetHeader();
return 0;
default:
return (*gEngfuncs.EngineGetParm)(parm, arg);
}
return 0;
}
void GL_Bind( int tmu, unsigned int texnum )
{
const dx_texture_t *texture;
// missed or invalid texture?
if( texnum <= 0 || texnum >= MAX_TEXTURES )
{
if( texnum != 0 )
gEngfuncs.Con_DPrintf( S_ERROR "%s: invalid texturenum %d\n", __func__, texnum );
texnum = tr.defaultTexture;
}
texture = R_GetTexture( texnum );
//if( dxc.currentTexture == texture->d3dHandle )
// return;
dxc.currentTexture = texture->d3dHandle;
}
static qboolean R_SpeedsMessage( char *out, size_t size )
{
return false;
}
static void R_NewMap( void )
{
tr.worldmodel = gp_cl->models[1];
// clear out efrags in case the level hasn't been reloaded
for( int i = 0; i < tr.worldmodel->numleafs; i++ )
tr.worldmodel->leafs[i+1].efrags = NULL;
tr.skytexturenum = -1;
// clearing texture chains
for( int i = 0; i < tr.worldmodel->numtextures; i++ )
{
if( !tr.worldmodel->textures[i] )
continue;
texture_t *tx = tr.worldmodel->textures[i];
if( !Q_strncmp( tx->name, "sky", 3 ) && tx->width == ( tx->height * 2 ))
tr.skytexturenum = i;
tx->texturechain = NULL;
}
GL_BuildLightmaps();
if( gEngfuncs.drawFuncs->R_NewMap != NULL )
gEngfuncs.drawFuncs->R_NewMap();
}
static void Color4f( float r, float g, float b, float a )
{
Vector4Set(dxc.currentColor, r, g, b, a);
}
static void Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
{
Vector4Set(dxc.currentColor, r/255.f, g/255.f, b/255.f, a/255.f);
}
static void Vertex3fv( const float *worldPnt )
{
;
}
static void Vertex3f( float x, float y, float z )
{
;
}
static void CullFace( TRICULLSTYLE mode )
{
;
}
static void VGUI_SetupDrawing( qboolean rect )
{
;
}
static void R_FillRenderAPI( render_api_t *api )
{
;
}
static void R_FillTriAPI( triangleapi_t *api )
{
;
}
const ref_interface_t gReffuncs =
{
.R_Init = R_Init,
.R_Shutdown = R_Shutdown,
.R_GetConfigName = R_GetConfigName,
.R_SetDisplayTransform = R_SetDisplayTransform,
.GL_SetupAttributes = GL_SetupAttributes,
.GL_InitExtensions = GL_InitExtensions,
.GL_ClearExtensions = GL_ClearExtensions,
.R_GammaChanged = R_GammaChanged,
.R_BeginFrame = R_BeginFrame,
.R_RenderScene = R_RenderScene,
.R_EndFrame = R_EndFrame,
.R_PushScene = R_SimpleStub,
.R_PopScene = R_SimpleStub,
.GL_BackendStartFrame = GL_BackendStartFrame,
.GL_BackendEndFrame = GL_BackendEndFrame,
.R_ClearScreen = R_SimpleStub,
.R_AllowFog = R_AllowFog,
.GL_SetRenderMode = GL_SetRenderMode,
.R_AddEntity = R_AddEntity,
.R_ProcessEntData = R_ProcessEntData,
.R_ShowTextures = R_ShowTextures,
.R_GetTextureOriginalBuffer = R_GetTextureOriginalBuffer,
.GL_LoadTextureFromBuffer = GL_LoadTextureFromBuffer,
.GL_ProcessTexture = GL_ProcessTexture,
.R_SetupSky = R_SetupSky,
.R_Set2DMode = R_Set2DMode,
.R_DrawStretchPic = R_DrawStretchPic,
.FillRGBA = FillRGBA,
.WorldToScreen = WorldToScreen,
.VID_ScreenShot = VID_ScreenShot,
.VID_CubemapShot = VID_CubemapShot,
.R_LightPoint = R_LightPoint,
.R_DecalShoot = R_DecalShoot,
.R_DecalRemoveAll = R_SimpleStubInt,
.R_CreateDecalList = R_CreateDecalList,
.R_ClearAllDecals = R_SimpleStub,
.R_StudioEstimateFrame = R_StudioEstimateFrame,
.R_StudioLerpMovement = R_StudioLerpMovement,
.R_StudioFillAPI = R_StudioFillAPI,
.R_StudioSetDrawInterface = R_StudioSetDrawInterface,
.R_SetSkyCloudsTextures = R_SetSkyCloudsTextures,
.GL_SubdivideSurface = GL_SubdivideSurface,
.CL_RunLightStyles = CL_RunLightStyles,
.Mod_ProcessRenderData = Mod_ProcessRenderData,
.Mod_StudioLoadTextures = Mod_StudioLoadTextures,
.CL_DrawParticles = CL_DrawParticles,
.CL_DrawTracers = CL_DrawTracers,
.CL_DrawBeams = CL_DrawBeams,
.RefGetParm = RefGetParm,
.R_GetDetailScaleForTexture = R_GetDetailScaleForTexture,
.R_SetDetailScaleForTexture = R_SetDetailScaleForTexture,
.GL_CreateTexture = GL_CreateTexture,
.GL_FindTexture = GL_FindTexture,
.GL_TextureName = GL_TextureName,
.GL_TextureData = GL_TextureData,
.GL_LoadTexture = GL_LoadTexture,
.GL_FreeTexture = GL_FreeTexture,
.R_OverrideTextureSourceSize = R_OverrideTextureSourceSize,
.GL_UpdateTexture = GL_UpdateTexture,
.GL_Bind = GL_Bind,
.GL_RenderFrame = R_RenderFrame,
.GL_OrthoBounds = GL_OrthoBounds,
.R_SpeedsMessage = R_SpeedsMessage,
.Mod_GetCurrentVis = Mod_GetCurrentVis,
.R_NewMap = R_NewMap,
.R_ClearScene = R_ClearScene,
.TriRenderMode = R_SimpleStubInt,
.Begin = R_SimpleStubInt,
.End = R_SimpleStub,
.Color4f = Color4f,
.Color4ub = Color4ub,
.Vertex3fv = Vertex3fv,
.Vertex3f = Vertex3f,
.CullFace = CullFace,
.R_FillRenderAPI = R_FillRenderAPI,
.R_FillTriAPI = R_FillTriAPI,
.VGUI_SetupDrawing = VGUI_SetupDrawing,
};

559
ref/dx2/r_d3d.c Normal file
View File

@@ -0,0 +1,559 @@
/*
r_d3d.c -- dx2 renderer d3d related code
Copyright (C) 2025-2026 lewa_j
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 3 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.
*/
#include "r_local.h"
#include "xash3d_mathlib.h"
CVAR_DEFINE_AUTO( r_novis, "0", 0, "ignore vis information (perfomance test)" );
CVAR_DEFINE_AUTO( r_nocull, "0", 0, "ignore frustrum culling (perfomance test)" );
CVAR_DEFINE_AUTO( r_lockpvs, "0", FCVAR_CHEAT, "lockpvs area at current point (pvs test)" );
CVAR_DEFINE_AUTO( r_lockfrustum, "0", FCVAR_CHEAT, "lock frustrum area at current point (cull test)" );
dx_globals_t tr;
dx_context_t dxc;
const char *dxResultToStr( HRESULT r )
{
if( r == DD_OK )
return "DD_OK";
if( r == DDERR_INVALIDPARAMS )
return "DDERR_INVALIDPARAMS";
if( r == DDERR_INVALIDOBJECT )
return "DDERR_INVALIDOBJECT";
if( r == DDERR_UNSUPPORTED )
return "DDERR_UNSUPPORTED";
if( r == DDERR_NOCOOPERATIVELEVELSET )
return "DDERR_NOCOOPERATIVELEVELSET";
if( r == DDERR_INVALIDCAPS )
return "DDERR_INVALIDCAPS";
if( r == DDERR_INCOMPATIBLEPRIMARY )
return "DDERR_INCOMPATIBLEPRIMARY";
if( r == DDERR_NOEXCLUSIVEMODE )
return "DDERR_NOEXCLUSIVEMODE";
if( r == DDERR_NOFLIPHW )
return "DDERR_NOFLIPHW";
if( r == DDERR_OUTOFVIDEOMEMORY )
return "DDERR_OUTOFVIDEOMEMORY";
if( r == DDERR_PRIMARYSURFACEALREADYEXISTS )
return "DDERR_PRIMARYSURFACEALREADYEXISTS";
if( r == DDERR_UNSUPPORTEDMODE )
return "DDERR_UNSUPPORTEDMODE";
if( r == DDERR_NOTFOUND )
return "DDERR_NOTFOUND";
if( r == DDERR_INVALIDRECT )
return "DDERR_INVALIDRECT";
if( r == D3DERR_VIEWPORTDATANOTSET )
return "D3DERR_VIEWPORTDATANOTSET";
if( r == D3DERR_VIEWPORTHASNODEVICE )
return "D3DERR_VIEWPORTHASNODEVICE";
if( r == D3DERR_SURFACENOTINVIDMEM )
return "D3DERR_SURFACENOTINVIDMEM";
return "UNKNOWN";
}
static qboolean DD_CreatePrimarySurface( void )
{
DDSURFACEDESC ddsd = { 0 };
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
DXCheck(IDirectDraw_CreateSurface(dxc.pdd, &ddsd, &dxc.pddsPrimary, NULL));
printf("IDirectDraw::CreateSurface(PRIMARY) %p\n", dxc.pddsPrimary);
if (!dxc.pddsPrimary)
return false;
DXCheck(IDirectDraw_CreateClipper(dxc.pdd, 0, &dxc.pddClipper, NULL));
gEngfuncs.Con_Printf("IDirectDraw::CreateClipper %p\n", dxc.pddClipper);
if (!dxc.pddClipper)
return false;
DXCheck(IDirectDrawClipper_SetHWnd(dxc.pddClipper, 0, dxc.window));
DXCheck(IDirectDrawSurface_SetClipper(dxc.pddsPrimary, dxc.pddClipper));
return true;
}
static qboolean DD_CreateBackSurface( void )
{
DDCAPS ddcaps =
{
.dwSize = sizeof(ddcaps)
};
DDCAPS helcaps =
{
.dwSize = sizeof(helcaps)
};
DXCheck(IDirectDraw_GetCaps(dxc.pdd, &ddcaps, &helcaps));
gEngfuncs.Con_Printf("IDirectDraw::GetCaps\n");
gEngfuncs.Con_Printf("ZBUFFER: %s\n", (ddcaps.ddsCaps.dwCaps & DDSCAPS_ZBUFFER) ? "- ^2enabled" : "- ^1failed");
if (ddcaps.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
gEngfuncs.Con_Printf("ZBufferBitDepths: 0x%X\n", ddcaps.dwZBufferBitDepths);
if (helcaps.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
gEngfuncs.Con_Printf("HEL ZBufferBitDepths: 0x%X\n", helcaps.dwZBufferBitDepths);
DDSURFACEDESC ddsd = { 0 };
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY;
ddsd.dwWidth = dxc.windowWidth;
ddsd.dwHeight = dxc.windowHeight;
DXCheck(IDirectDraw_CreateSurface(dxc.pdd, &ddsd, &dxc.pddsBack, NULL));
gEngfuncs.Con_Printf("IDirectDraw::CreateSurface(BACK) %p\n", dxc.pddsBack);
if (!dxc.pddsBack)
return false;
DXCheck(IDirectDraw_CreateClipper(dxc.pdd, 0, &dxc.pddBackClipper, NULL));
gEngfuncs.Con_Printf("IDirectDraw::CreateClipper(BACK) %p\n", dxc.pddBackClipper);
if (!dxc.pddBackClipper)
return false;
struct region_t
{
RGNDATAHEADER rdh;
RECT rect;
} region;
region.rdh.dwSize = sizeof(region.rdh);
region.rdh.iType = RDH_RECTANGLES;
region.rdh.nCount = 1;
region.rdh.nRgnSize = sizeof(RECT);
region.rdh.rcBound.left = 0;
region.rdh.rcBound.top = 0;
region.rdh.rcBound.right = dxc.windowWidth;
region.rdh.rcBound.bottom = dxc.windowHeight;
memcpy(&region.rect, &region.rdh.rcBound, sizeof(region.rdh.rcBound));
DXCheck(IDirectDrawClipper_SetClipList(dxc.pddBackClipper, (RGNDATA *)&region, 0));
DXCheck(IDirectDrawSurface_SetClipper(dxc.pddsBack, dxc.pddBackClipper));
int bitDepths = ddcaps.dwZBufferBitDepths;
if (!bitDepths)
bitDepths = helcaps.dwZBufferBitDepths;
if( (ddcaps.ddsCaps.dwCaps & DDSCAPS_ZBUFFER) && bitDepths )
{
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_ZBUFFERBITDEPTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY;
ddsd.dwWidth = dxc.windowWidth;
ddsd.dwHeight = dxc.windowHeight;
ddsd.dwZBufferBitDepth = 16;
if(bitDepths & DDBD_16 )
ddsd.dwZBufferBitDepth = 16;
else if(bitDepths & DDBD_24 )
ddsd.dwZBufferBitDepth = 24;
else if(bitDepths & DDBD_32 )
ddsd.dwZBufferBitDepth = 32;
DXCheck(IDirectDraw_CreateSurface(dxc.pdd, &ddsd, &dxc.pddsZBuffer, NULL));
gEngfuncs.Con_Printf("IDirectDraw::CreateSurface(ZBUFFER %dbit) %p\n", ddsd.dwZBufferBitDepth, dxc.pddsZBuffer);
if( !dxc.pddsZBuffer )
return false;
DXCheck(IDirectDrawSurface_AddAttachedSurface(dxc.pddsBack, dxc.pddsZBuffer));
}
return true;
}
static qboolean D3D_Init( void )
{
DXCheck(IDirectDraw_QueryInterface(dxc.pdd, &IID_IDirect3D, (void**)&dxc.pd3d));
gEngfuncs.Con_Printf("IDirectDraw::QueryInterface(IID_IDirect3D) %p\n", dxc.pd3d);
if( !dxc.pd3d )
return false;
DXCheck(IDirect3D_CreateViewport(dxc.pd3d, &dxc.viewport, NULL));
gEngfuncs.Con_Printf("IDirect3D::CreateViewport %p\n", dxc.viewport);
if( !dxc.viewport )
return false;
return true;
}
static qboolean D3D_InitDevice( void )
{
if( !dxc.pd3d )
return false;
D3DFINDDEVICESEARCH search = { 0 };
memset(&search, 0, sizeof(search));
search.dwSize = sizeof(search);
search.dwFlags = D3DFDS_COLORMODEL;
search.dcmColorModel = D3DCOLOR_RGB;
#if 0
search.dwFlags |= D3DFDS_HARDWARE;
search.bHardware = FALSE;
#endif
D3DFINDDEVICERESULT result = { 0 };
memset(&result, 0, sizeof(result));
result.dwSize = sizeof(result);
DXCheck(IDirect3D_FindDevice(dxc.pd3d, &search, &result));
DXCheck(IDirectDrawSurface_QueryInterface(dxc.pddsBack, &result.guid, (void**)&dxc.pd3dd));
gEngfuncs.Con_Printf("IDirectDrawSurface::QueryInterface(IDirect3DDevice) %p\n", dxc.pd3dd);
gEngfuncs.Con_Printf("DeviceZBufferBitDepth: 0x%X\n", result.ddHwDesc.dwDeviceZBufferBitDepth);
gEngfuncs.Con_Printf("SW DeviceZBufferBitDepth: 0x%X\n", result.ddSwDesc.dwDeviceZBufferBitDepth);
if( !dxc.pd3dd )
return false;
D3DDEVICEDESC d3ddesc =
{
.dwSize = sizeof(d3ddesc)
};
D3DDEVICEDESC held3ddesc =
{
.dwSize = sizeof(held3ddesc)
};
DXCheck(IDirect3DDevice_GetCaps(dxc.pd3dd, &d3ddesc, &held3ddesc));
gEngfuncs.Con_Printf("IDirect3DDevice::GetCaps\n");
gEngfuncs.Con_Printf("DeviceZBufferBitDepth: 0x%X\n", result.ddHwDesc.dwDeviceZBufferBitDepth);
gEngfuncs.Con_Printf("HEL DeviceZBufferBitDepth: 0x%X\n", result.ddSwDesc.dwDeviceZBufferBitDepth);
D3DEXECUTEBUFFERDESC ebd = { 0 };
memset(&ebd, 0, sizeof(ebd));
ebd.dwSize = sizeof(ebd);
ebd.dwFlags = D3DDEB_BUFSIZE;
ebd.dwBufferSize = 1024 * 64;
DXCheck(IDirect3DDevice_CreateExecuteBuffer(dxc.pd3dd, &ebd, &dxc.pd3deb, NULL));
gEngfuncs.Con_Printf("IDirect3DDevice::CreateExecuteBuffer %p\n", dxc.pd3deb);
if (!dxc.pd3deb)
return false;
if (!dxc.viewport)
return false;
DXCheck(IDirect3DDevice_AddViewport(dxc.pd3dd, dxc.viewport));
DDSURFACEDESC desc = { 0 };
memset(&desc, 0, sizeof(desc));
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
DXCheck(IDirectDrawSurface_GetSurfaceDesc(dxc.pddsBack, &desc));
D3DVIEWPORT viewport = { 0 };
viewport.dwSize = sizeof(viewport);
viewport.dwX = 0;
viewport.dwY = 0;
viewport.dwWidth = desc.dwWidth;
viewport.dwHeight = desc.dwHeight;
viewport.dvScaleX = 0.5 * viewport.dwWidth;
viewport.dvScaleY = 0.5f * viewport.dwHeight;
viewport.dvMaxX = 1;
viewport.dvMaxY = 1;
viewport.dvMinZ = 0;
viewport.dvMaxZ = 1;
DXCheck(IDirect3DViewport_SetViewport(dxc.viewport, &viewport));
DXCheck(IDirect3DDevice_CreateMatrix(dxc.pd3dd, &dxc.mtxWorld));
DXCheck(IDirect3DDevice_CreateMatrix(dxc.pd3dd, &dxc.mtxProjection));
//set transform state
{
d3dEBContext_t ebc = { 0 };
if (!D3D_StartExecuteBuffer(&ebc))
return false;
void *cur = ebc.data;
D3D_PutInstruction(&cur, D3DOP_STATETRANSFORM, sizeof(D3DSTATE), 2);
D3D_PutTransformState(&cur, D3DTRANSFORMSTATE_WORLD, dxc.mtxWorld);
D3D_PutTransformState(&cur, D3DTRANSFORMSTATE_PROJECTION, dxc.mtxProjection);
D3D_PutInstruction(&cur, D3DOP_STATERENDER, sizeof(D3DSTATE), 2);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ZENABLE, FALSE);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ZWRITEENABLE, FALSE);
D3D_PutInstruction(&cur, D3DOP_EXIT, 0, 0);
ebc.vertCount = 0;
ebc.insOffset = 0;
ebc.insLength = ((char *)cur - (char *)ebc.data);
if (!D3D_EndExecuteBuffer(&ebc))
return false;
DXCheck(IDirect3DDevice_BeginScene(dxc.pd3dd));
DXCheck(IDirect3DDevice_Execute(dxc.pd3dd, ebc.pd3deb, dxc.viewport, D3DEXECUTE_CLIPPED));
DXCheck(IDirect3DDevice_EndScene(dxc.pd3dd));
D3D_ReleaseExecuteBuffer(&ebc);
}
return true;
}
qboolean R_Init( void )
{
memset(&dxc, 0, sizeof(dxc));
gEngfuncs.Cvar_RegisterVariable( &r_novis );
gEngfuncs.Cvar_RegisterVariable( &r_nocull );
gEngfuncs.Cvar_RegisterVariable( &r_lockpvs );
gEngfuncs.Cvar_RegisterVariable( &r_lockfrustum );
// init draw stack
tr.draw_list = &tr.draw_stack[0];
tr.draw_stack_pos = 0;
r_temppool = Mem_AllocPool("Render Zone");
// create the window
if (!gEngfuncs.R_Init_Video(REF_D3D))
{
Mem_FreePool(&r_temppool);
return false;
}
void *handle = NULL;
ref_window_type_t wt = gEngfuncs.R_GetWindowHandle( &handle, REF_WINDOW_TYPE_WIN32 );
gEngfuncs.Con_Printf( "R_Init: WindowHandle %p type %d\n", handle, wt );
if (wt != REF_WINDOW_TYPE_WIN32 || !handle)
{
Mem_FreePool(&r_temppool);
return false;
}
dxc.window = (HWND)handle;
RECT dstRect = { 0 };
GetClientRect(dxc.window, &dstRect);
dxc.windowWidth = dstRect.right - dstRect.left;
dxc.windowHeight = dstRect.bottom - dstRect.top;
DXCheck(DirectDrawCreate(NULL, &dxc.pdd, NULL));
gEngfuncs.Con_Reportf("DirectDrawCreate %p\n", dxc.pdd);
if (!dxc.pdd)
{
Mem_FreePool(&r_temppool);
return false;
}
DXCheck(IDirectDraw_SetCooperativeLevel(dxc.pdd, dxc.window, DDSCL_NORMAL));
if (!DD_CreatePrimarySurface())
{
Mem_FreePool(&r_temppool);
return false;
}
if (!DD_CreateBackSurface())
{
Mem_FreePool(&r_temppool);
return false;
}
if (!D3D_Init())
{
Mem_FreePool(&r_temppool);
return false;
}
if (!D3D_InitDevice())
{
Mem_FreePool(&r_temppool);
return false;
}
// see R_ProcessEntData for tr.entities initialization
tr.world = (struct world_static_s *)ENGINE_GET_PARM( PARM_GET_WORLD_PTR );
tr.viewent = (cl_entity_t *)ENGINE_GET_PARM( PARM_GET_VIEWENT_PTR );
dxc.renderMode = kRenderNormal;
Vector4Set(dxc.currentColor, 1, 1, 1, 1);
R_InitImages();
return true;
}
void R_Shutdown( void )
{
gEngfuncs.Con_Printf("ref: R_Shutdown()\n");
Mem_FreePool(&r_temppool);
gEngfuncs.R_Free_Video();
}
void D3D_Resize( int width, int height )
{
dxc.windowWidth = width;
dxc.windowHeight = height;
if( dxc.pd3deb )
IDirect3DExecuteBuffer_Release(dxc.pd3deb);
dxc.pd3deb = NULL;
if( dxc.pd3dd )
IDirect3DDevice_Release(dxc.pd3dd);
dxc.pd3dd = NULL;
if( dxc.pddsBack )
IDirectDrawSurface_Release(dxc.pddsBack);
dxc.pddsBack = NULL;
if( dxc.pddsZBuffer )
IDirectDrawSurface_Release(dxc.pddsZBuffer);
dxc.pddsZBuffer = NULL;
if( dxc.pddBackClipper )
IDirectDrawClipper_Release(dxc.pddBackClipper);
dxc.pddBackClipper = NULL;
if( DD_CreateBackSurface() )
{
if( D3D_InitDevice() )
{
}
}
}
void GL_SetupAttributes( int safegl )
{
;
}
void GL_InitExtensions( void )
{
tr.framecount = tr.visframecount = 1;
}
void GL_ClearExtensions( void )
{
;
}
#define DX2_CREATE_EB 0
qboolean D3D_StartExecuteBuffer( d3dEBContext_t *ctx )
{
#if DX2_CREATE_EB
ctx->pd3deb = NULL;
D3DEXECUTEBUFFERDESC ebd = { 0 };
memset(&ebd, 0, sizeof(ebd));
ebd.dwSize = sizeof(ebd);
ebd.dwFlags = D3DDEB_BUFSIZE;
ebd.dwBufferSize = 512;
DXCheck(IDirect3DDevice_CreateExecuteBuffer(dxc.pd3dd, &ebd, &ctx->pd3deb, NULL));
#else
ctx->pd3deb = dxc.pd3deb;
#endif
if (!ctx->pd3deb)
return false;
D3DEXECUTEBUFFERDESC ebDesc = { 0 };
memset(&ebDesc, 0, sizeof(ebDesc));
ebDesc.dwSize = sizeof(ebDesc);
ebDesc.dwFlags = D3DDEB_LPDATA;
HRESULT r = D3D_OK;
DXCheckRet(r, IDirect3DExecuteBuffer_Lock(ctx->pd3deb, &ebDesc));
if (r != D3D_OK)
return false;
//gEngfuncs.Con_Printf("IDirect3DExecuteBuffer_Lock size %lu data %p\n", ebDesc.dwBufferSize, ebDesc.lpData);
ctx->bufferSize = ebDesc.dwBufferSize;
ctx->data = ebDesc.lpData;
return true;
}
qboolean D3D_EndExecuteBuffer( d3dEBContext_t *ctx )
{
HRESULT r = D3D_OK;
DXCheckRet(r, IDirect3DExecuteBuffer_Unlock(ctx->pd3deb));
if( r != D3D_OK )
return false;
D3DEXECUTEDATA exData = { 0 };
memset(&exData, 0, sizeof(exData));
exData.dwSize = sizeof(exData);
exData.dwVertexCount = ctx->vertCount;
exData.dwVertexOffset = 0;
exData.dwInstructionOffset = ctx->insOffset;
exData.dwInstructionLength = ctx->insLength;
DXCheckRet(r, IDirect3DExecuteBuffer_SetExecuteData(ctx->pd3deb, &exData));
return r == D3D_OK;
}
void D3D_ReleaseExecuteBuffer( d3dEBContext_t *ctx )
{
#if DX2_CREATE_EB
if( ctx->pd3deb && ctx->pd3deb != dxc.pd3deb )
IDirect3DExecuteBuffer_Release( ctx->pd3deb );
#endif
}
void D3D_SetVertTL( D3DTLVERTEX* v, float x, float y, float z, float w, float tu, float tv )
{
v->sx = x;
v->sy = y;
v->sz = z;
v->rhw = w;
//v->color = RGBA_MAKE(250, 10, 10, 255);
v->tu = tu;
v->tv = tv;
}
void D3D_SetTri( D3DTRIANGLE *t, int v1, int v2, int v3 )
{
t->v1 = v1;
t->v2 = v2;
t->v3 = v3;
t->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
}
void D3D_PutInstruction( void **dst, BYTE opcode, BYTE size, WORD count )
{
D3DINSTRUCTION* inst = (D3DINSTRUCTION*)*dst;
inst->bOpcode = opcode;
inst->bSize = size;
inst->wCount = count;
*dst = (void*)(((D3DINSTRUCTION*)*dst) + 1);
}
void D3D_PutProcessVertices( void** dst, DWORD flags, WORD start, WORD count )
{
D3D_PutInstruction(dst, D3DOP_PROCESSVERTICES, sizeof(D3DPROCESSVERTICES), 1);
D3DPROCESSVERTICES* pv = (D3DPROCESSVERTICES*)*dst;
pv->dwFlags = flags;
pv->wStart = start;
pv->wDest = start;
pv->dwCount = count;
pv->dwReserved = 0;
*dst = (void*)(((D3DPROCESSVERTICES*)*dst) + 1);
}
void D3D_PutRenderState( void** dst, D3DRENDERSTATETYPE type, DWORD arg )
{
D3DSTATE* s = (D3DSTATE*)*dst;
s->drstRenderStateType = type;
s->dwArg[0] = arg;
*dst = (void*)(((D3DSTATE*)*dst) + 1);
}
void D3D_PutTransformState( void** dst, D3DTRANSFORMSTATETYPE type, DWORD arg )
{
D3DSTATE* s = (D3DSTATE*)*dst;
s->dtstTransformStateType = type;
s->dwArg[0] = arg;
*dst = (void*)(((D3DSTATE*)*dst) + 1);
}

204
ref/dx2/r_draw.c Normal file
View File

@@ -0,0 +1,204 @@
/*
r_draw.c -- dx2 2D drawing
Copyright (C) 2025-2026 lewa_j
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 3 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.
*/
#include "r_local.h"
#include "xash3d_mathlib.h"
void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum )
{
if (texnum <= 0 || texnum >= MAX_TEXTURES)
return;
dx_texture_t *tex = R_GetTexture(texnum);
if (!tex->dds)
return;
#if 0
RECT dstRect = { x, y, x + w, y + h };
RECT srcRect = { s1 * tex->width, t1 * tex->height, s2 * tex->width, t2 * tex->height};
if (dxc.renderMode == kRenderNormal)
{
DXCheck(IDirectDrawSurface_Blt(dxc.pddsBack, &dstRect, tex->dds, &srcRect, DDBLT_WAIT, NULL));
}
else
{
DDCOLORKEY ddck;
ddck.dwColorSpaceLowValue = 0;
ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue;
DXCheck(IDirectDrawSurface_SetColorKey(tex->dds, DDCKEY_SRCBLT, &ddck));
DXCheck(IDirectDrawSurface_Blt(dxc.pddsBack, &dstRect, tex->dds, &srcRect, DDBLT_WAIT | DDBLT_KEYSRC, NULL));
}
#else
if (!dxc.pd3dd)
return;
d3dEBContext_t ebc = { 0 };
{
if( !D3D_StartExecuteBuffer( &ebc ))
return;
void *cur = ebc.data;
const int vertCount = 4;
D3DTLVERTEX* verts = (D3DTLVERTEX*)cur;
// fix for half coordinate pixel centers in d3d compared to gl
x -= 0.5;
y -= 0.5;
#define VecToD3DCOLOR(v) D3DRGBA(v[0], v[1], v[2], v[3])
verts[0].color = VecToD3DCOLOR(dxc.currentColor);
D3D_SetVertTL(verts, x, y, 0.5, 1, s1, t1);
verts[1].color = verts[0].color;
D3D_SetVertTL(verts + 1, x + w, y, 0.5, 1, s2, t1);
verts[2].color = verts[0].color;
D3D_SetVertTL(verts + 2, x + w, y + h, 0.5, 1, s2, t2);
verts[3].color = verts[0].color;
D3D_SetVertTL(verts + 3, x, y + h, 0.5, 1, s1, t2);
cur = (void*)(((D3DTLVERTEX*)cur) + vertCount);
void* insStart = cur;
D3D_PutProcessVertices(&cur, D3DPROCESSVERTICES_COPY | D3DPROCESSVERTICES_UPDATEEXTENTS, 0, vertCount);
D3D_PutInstruction(&cur, D3DOP_STATERENDER, sizeof(D3DSTATE), 3);
// TODO disable when == tr.whiteTexture
D3D_PutRenderState(&cur, D3DRENDERSTATE_TEXTUREHANDLE, tex->d3dHandle);
//D3D_PutRenderState(&cur, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_DECAL);
if (dxc.renderMode == kRenderTransAlpha)
{
D3D_PutRenderState(&cur, D3DRENDERSTATE_BLENDENABLE, FALSE);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ALPHATESTENABLE, TRUE);
}
else if (dxc.renderMode == kRenderGlow ||
dxc.renderMode == kRenderTransAdd)
{
D3D_PutRenderState(&cur, D3DRENDERSTATE_BLENDENABLE, TRUE);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
D3D_PutInstruction(&cur, D3DOP_STATERENDER, sizeof(D3DSTATE), 2);
D3D_PutRenderState(&cur, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
D3D_PutRenderState(&cur, D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE);
}
else if (dxc.renderMode == kRenderTransColor || dxc.renderMode == kRenderTransTexture)
{
D3D_PutRenderState(&cur, D3DRENDERSTATE_BLENDENABLE, TRUE);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
D3D_PutInstruction(&cur, D3DOP_STATERENDER, sizeof(D3DSTATE), 2);
D3D_PutRenderState(&cur, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
D3D_PutRenderState(&cur, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
}
else// if (dxc.renderMode == kRenderNormal)
{
D3D_PutRenderState(&cur, D3DRENDERSTATE_BLENDENABLE, FALSE);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
}
// align
if (((ULONG)cur) & 7) {
D3D_PutInstruction(&cur, D3DOP_TRIANGLE, sizeof(D3DTRIANGLE), 0);
}
D3D_PutInstruction(&cur, D3DOP_TRIANGLE, sizeof(D3DTRIANGLE), 2);
D3DTRIANGLE* tris = (D3DTRIANGLE*)cur;
D3D_SetTri(tris, 0, 1, 2);
D3D_SetTri(tris + 1, 0, 2, 3);
cur = (void*)(((D3DTRIANGLE*)cur) + 2);
D3D_PutInstruction(&cur, D3DOP_EXIT, 0, 0);
ebc.vertCount = 4;
ebc.insOffset = ((char*)insStart - (char*)ebc.data);
ebc.insLength = ((char*)cur - (char*)insStart);
if( !D3D_EndExecuteBuffer( &ebc ))
return;
}
DXCheck(IDirect3DDevice_BeginScene(dxc.pd3dd));
DXCheck(IDirect3DDevice_Execute(dxc.pd3dd, ebc.pd3deb, dxc.viewport, D3DEXECUTE_CLIPPED));
DXCheck(IDirect3DDevice_EndScene(dxc.pd3dd));
D3D_ReleaseExecuteBuffer( &ebc );
#endif
}
void FillRGBA( int rendermode, float x, float y, float w, float h, byte r, byte g, byte b, byte a )
{
#if 0
RECT dstRect = { x, y, x + w, y + h };
DDBLTFX bltFx = { 0 };
bltFx.dwSize = sizeof(bltFx);
bltFx.dwFillColor = RGBA_MAKE(r, g, b, a);
DXCheck(IDirectDrawSurface_Blt(dxc.pddsBack, &dstRect, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &bltFx));
#else
// TODO Restore after?
GL_SetRenderMode( (rendermode == kRenderTransAdd) ? rendermode : kRenderTransColor);
Vector4Set( dxc.currentColor, r / 255.f, g / 255.f, b / 255.f, a / 255.f );
R_DrawStretchPic( x, y, w, h, 0, 0, 0, 0, tr.whiteTexture );
#endif
}
void R_Set2DMode( qboolean enable )
{
if( enable && dxc.in2DMode )
return;
dxc.in2DMode = enable;
d3dEBContext_t ebc = { 0 };
if( !D3D_StartExecuteBuffer( &ebc ))
return;
void *cur = ebc.data;
if( enable )
{
D3D_PutInstruction(&cur, D3DOP_STATERENDER, sizeof(D3DSTATE), 4);
D3D_PutRenderState(&cur, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ZENABLE, FALSE);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ZWRITEENABLE, FALSE);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ALPHATESTENABLE, TRUE);
Vector4Set( dxc.currentColor, 1.0f, 1.0f, 1.0f, 1.0f );
RI.currententity = NULL;
RI.currentmodel = NULL;
}
else
{
D3D_PutInstruction(&cur, D3DOP_STATERENDER, sizeof(D3DSTATE), 3);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ZENABLE, TRUE);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ZWRITEENABLE, TRUE);
D3D_PutRenderState(&cur, D3DRENDERSTATE_CULLMODE, D3DCULL_CCW);
}
ebc.vertCount = 0;
ebc.insOffset = 0;
ebc.insLength = ((char *)cur - (char *)ebc.data);
if (!D3D_EndExecuteBuffer(&ebc))
return;
DXCheck(IDirect3DDevice_BeginScene(dxc.pd3dd));
DXCheck(IDirect3DDevice_Execute(dxc.pd3dd, ebc.pd3deb, dxc.viewport, D3DEXECUTE_CLIPPED));
DXCheck(IDirect3DDevice_EndScene(dxc.pd3dd));
D3D_ReleaseExecuteBuffer(&ebc);
}

185
ref/dx2/r_frustum.c Normal file
View File

@@ -0,0 +1,185 @@
/*
r_frustum.c - frustum test implementation
Copyright (C) 2016 Uncle Mike
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 3 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.
*/
#include "r_local.h"
#include "xash3d_mathlib.h"
static void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist )
{
Assert( side >= 0 && side < FRUSTUM_PLANES );
out->planes[side].type = PlaneTypeForNormal( vecNormal );
out->planes[side].signbits = SignbitsForPlane( vecNormal );
VectorCopy( vecNormal, out->planes[side].normal );
out->planes[side].dist = flDist;
SetBits( out->clipFlags, BIT( side ));
}
void GL_FrustumInitProj( gl_frustum_t *out, float flZNear, float flZFar, float flFovX, float flFovY )
{
float xs, xc;
vec3_t farpoint, nearpoint;
vec3_t normal, iforward;
// horizontal fov used for left and right planes
SinCos( DEG2RAD( flFovX ) * 0.5f, &xs, &xc );
// setup left plane
VectorMAM( xs, RI.cull_vforward, -xc, RI.cull_vright, normal );
GL_FrustumSetPlane( out, FRUSTUM_LEFT, normal, DotProduct( RI.cullorigin, normal ));
// setup right plane
VectorMAM( xs, RI.cull_vforward, xc, RI.cull_vright, normal );
GL_FrustumSetPlane( out, FRUSTUM_RIGHT, normal, DotProduct( RI.cullorigin, normal ));
// vertical fov used for top and bottom planes
SinCos( DEG2RAD( flFovY ) * 0.5f, &xs, &xc );
VectorNegate( RI.cull_vforward, iforward );
// setup bottom plane
VectorMAM( xs, RI.cull_vforward, -xc, RI.cull_vup, normal );
GL_FrustumSetPlane( out, FRUSTUM_BOTTOM, normal, DotProduct( RI.cullorigin, normal ));
// setup top plane
VectorMAM( xs, RI.cull_vforward, xc, RI.cull_vup, normal );
GL_FrustumSetPlane( out, FRUSTUM_TOP, normal, DotProduct( RI.cullorigin, normal ));
// setup far plane
VectorMA( RI.cullorigin, flZFar, RI.cull_vforward, farpoint );
GL_FrustumSetPlane( out, FRUSTUM_FAR, iforward, DotProduct( iforward, farpoint ));
// no need to setup backplane for general view.
if( flZNear == 0.0f ) return;
// setup near plane
VectorMA( RI.cullorigin, flZNear, RI.cull_vforward, nearpoint );
GL_FrustumSetPlane( out, FRUSTUM_NEAR, RI.cull_vforward, DotProduct( RI.cull_vforward, nearpoint ));
}
void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yTop, float yBottom, float flZNear, float flZFar )
{
vec3_t iforward, iright, iup;
// setup the near and far planes
float orgOffset = DotProduct( RI.cullorigin, RI.cull_vforward );
VectorNegate( RI.cull_vforward, iforward );
// because quake ortho is inverted and far and near should be swaped
GL_FrustumSetPlane( out, FRUSTUM_FAR, iforward, -flZNear - orgOffset );
GL_FrustumSetPlane( out, FRUSTUM_NEAR, RI.cull_vforward, flZFar + orgOffset );
// setup left and right planes
orgOffset = DotProduct( RI.cullorigin, RI.cull_vright );
VectorNegate( RI.cull_vright, iright );
GL_FrustumSetPlane( out, FRUSTUM_LEFT, RI.cull_vright, xLeft + orgOffset );
GL_FrustumSetPlane( out, FRUSTUM_RIGHT, iright, -xRight - orgOffset );
// setup top and buttom planes
orgOffset = DotProduct( RI.cullorigin, RI.cull_vup );
VectorNegate( RI.cull_vup, iup );
GL_FrustumSetPlane( out, FRUSTUM_TOP, RI.cull_vup, yTop + orgOffset );
GL_FrustumSetPlane( out, FRUSTUM_BOTTOM, iup, -yBottom - orgOffset );
}
// cull methods
qboolean GL_FrustumCullBox( const gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags )
{
int iClipFlags;
int i, bit;
if( r_nocull.value )
return false;
if( userClipFlags != 0 )
iClipFlags = userClipFlags;
else iClipFlags = out->clipFlags;
for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 )
{
const mplane_t *p = &out->planes[FRUSTUM_PLANES - i];
if( !FBitSet( iClipFlags, bit ))
continue;
switch( p->signbits )
{
case 0:
if( p->normal[0] * maxs[0] + p->normal[1] * maxs[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 1:
if( p->normal[0] * mins[0] + p->normal[1] * maxs[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 2:
if( p->normal[0] * maxs[0] + p->normal[1] * mins[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 3:
if( p->normal[0] * mins[0] + p->normal[1] * mins[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 4:
if( p->normal[0] * maxs[0] + p->normal[1] * maxs[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 5:
if( p->normal[0] * mins[0] + p->normal[1] * maxs[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 6:
if( p->normal[0] * maxs[0] + p->normal[1] * mins[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 7:
if( p->normal[0] * mins[0] + p->normal[1] * mins[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
default:
return false;
}
}
return false;
}
qboolean GL_FrustumCullSphere( const gl_frustum_t *out, const vec3_t center, float radius, int userClipFlags )
{
int iClipFlags;
int i, bit;
if( r_nocull.value )
return false;
if( userClipFlags != 0 )
iClipFlags = userClipFlags;
else iClipFlags = out->clipFlags;
for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 )
{
const mplane_t *p = &out->planes[FRUSTUM_PLANES - i];
if( !FBitSet( iClipFlags, bit ))
continue;
if( DotProduct( center, p->normal ) - p->dist <= -radius )
return true;
}
return false;
}

41
ref/dx2/r_frustum.h Normal file
View File

@@ -0,0 +1,41 @@
/*
r_frustum.h - frustum test implementation
Copyright (C) 2016 Uncle Mike
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 3 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.
*/
#ifndef GL_FRUSTUM_H
#define GL_FRUSTUM_H
// don't change this order
#define FRUSTUM_LEFT 0
#define FRUSTUM_RIGHT 1
#define FRUSTUM_BOTTOM 2
#define FRUSTUM_TOP 3
#define FRUSTUM_FAR 4
#define FRUSTUM_NEAR 5
#define FRUSTUM_PLANES 6
typedef struct gl_frustum_s
{
mplane_t planes[FRUSTUM_PLANES];
unsigned int clipFlags;
} gl_frustum_t;
void GL_FrustumInitProj( gl_frustum_t *out, float flZNear, float flZFar, float flFovX, float flFovY );
void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yTop, float yBottom, float flZNear, float flZFar );
// cull methods
qboolean GL_FrustumCullBox( const gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags );
qboolean GL_FrustumCullSphere( const gl_frustum_t *out, const vec3_t centre, float radius, int userClipFlags );
#endif//GL_FRUSTUM_H

622
ref/dx2/r_image.c Normal file
View File

@@ -0,0 +1,622 @@
/*
r_context.c -- dx2 renderer texture uploading and processing
Copyright (C) 2010 Uncle Mike
Copyright (C) 2025 lewa_j
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 3 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.
*/
#include "r_local.h"
#include "xash3d_mathlib.h"
#include "crtlib.h"
#include "crclib.h"
static dx_texture_t dx_textures[MAX_TEXTURES];
static dx_texture_t *dx_texturesHashTable[TEXTURES_HASH_SIZE];
static uint dx_numTextures;
void R_InitImages( void )
{
memset(dx_textures, 0, sizeof(dx_textures));
memset(dx_texturesHashTable, 0, sizeof(dx_texturesHashTable));
dx_numTextures = 0;
// create unused 0-entry
Q_strncpy(dx_textures->name, "*unused*", sizeof(dx_textures->name));
dx_textures->hashValue = COM_HashKey(dx_textures->name, TEXTURES_HASH_SIZE);
dx_textures->nextHash = dx_texturesHashTable[dx_textures->hashValue];
dx_texturesHashTable[dx_textures->hashValue] = dx_textures;
dx_numTextures = 1;
}
dx_texture_t *R_GetTexture( unsigned int texnum )
{
Assert(texnum < MAX_TEXTURES);
return &dx_textures[texnum];
}
void R_ShowTextures( void )
{
}
const byte *R_GetTextureOriginalBuffer( unsigned int idx )
{
return NULL;
}
static qboolean GL_CheckTexName( const char *name )
{
int len;
if( COM_StringEmptyOrNULL( name ))
return false;
len = Q_strlen( name );
// because multi-layered textures can exceed name string
if( len >= sizeof( dx_textures->name ))
{
gEngfuncs.Con_Printf( S_ERROR "LoadTexture: too long name %s (%d)\n", name, len );
return false;
}
return true;
}
static dx_texture_t *GL_TextureForName( const char *name )
{
dx_texture_t *tex;
uint hash;
// find the texture in array
hash = COM_HashKey(name, TEXTURES_HASH_SIZE);
for (tex = dx_texturesHashTable[hash]; tex != NULL; tex = tex->nextHash)
{
if (!Q_stricmp(tex->name, name))
return tex;
}
return NULL;
}
static dx_texture_t *GL_AllocTexture( const char *name, texFlags_t flags )
{
dx_texture_t *tex = NULL;
// find a free texture_t slot
uint i;
//skip 0
for (i = 1; i < MAX_TEXTURES; i++)
{
if (dx_textures[i].used)
continue;
tex = &dx_textures[i];
break;
}
if (tex == NULL)
{
gEngfuncs.Host_Error("%s: MAX_TEXTURES limit exceeds\n", __func__);
return NULL;
}
// copy initial params
Q_strncpy(tex->name, name, sizeof(tex->name));
tex->used = 1;
tex->flags = flags;
// increase counter
dx_numTextures = Q_max((tex - dx_textures) + 1, dx_numTextures);
// add to hash table
tex->hashValue = COM_HashKey(name, TEXTURES_HASH_SIZE);
tex->nextHash = dx_texturesHashTable[tex->hashValue];
dx_texturesHashTable[tex->hashValue] = tex;
return tex;
}
static void GL_ProcessImage( dx_texture_t *tex, rgbdata_t *pic )
{
uint img_flags = 0;
// force upload texture as RGB or RGBA (detail textures requires this)
if (tex->flags & TF_FORCE_COLOR) pic->flags |= IMAGE_HAS_COLOR;
if (pic->flags & IMAGE_HAS_ALPHA) tex->flags |= TF_HAS_ALPHA;
if (ImageCompressed(pic->type))
{
if (!pic->numMips)
tex->flags |= TF_NOMIPMAP; // disable mipmapping by user request
// clear all the unsupported flags
tex->flags &= ~TF_KEEP_SOURCE;
}
else
{
// copy flag about luma pixels
if (pic->flags & IMAGE_HAS_LUMA)
tex->flags |= TF_HAS_LUMA;
if (pic->flags & IMAGE_QUAKEPAL)
tex->flags |= TF_QUAKEPAL;
// create luma texture from quake texture
if (tex->flags & TF_MAKELUMA)
{
img_flags |= IMAGE_MAKE_LUMA;
tex->flags &= ~TF_MAKELUMA;
}
if (!FBitSet(tex->flags, TF_IMG_UPLOADED) && FBitSet(tex->flags, TF_KEEP_SOURCE))
tex->original = gEngfuncs.FS_CopyImage(pic); // because current pic will be expanded to rgba
// we need to expand image into RGBA buffer
if (pic->type == PF_INDEXED_24 || pic->type == PF_INDEXED_32)
img_flags |= IMAGE_FORCE_RGBA;
// processing image before uploading (force to rgba, make luma etc)
if (pic->buffer) gEngfuncs.Image_Process(&pic, 0, 0, img_flags, 0);
if (FBitSet(tex->flags, TF_LUMINANCE))
ClearBits(pic->flags, IMAGE_HAS_COLOR);
}
}
static int GL_CalcMipmapCount( dx_texture_t *tex, qboolean haveBuffer )
{
int width, height;
int mipcount;
Assert(tex != NULL);
//TEMP
return 1;
if (!haveBuffer)
return 1;
// generate mip-levels by user request
if (FBitSet(tex->flags, TF_NOMIPMAP))
return 1;
// mip-maps can't exceeds 16
for (mipcount = 0; mipcount < 16; mipcount++)
{
width = Q_max(1, (tex->width >> mipcount));
height = Q_max(1, (tex->height >> mipcount));
if (width == 1 && height == 1)
break;
}
return mipcount + 1;
}
static void GL_TextureImageRAW( dx_texture_t *tex, int width, int height, int type, const char *data )
{
if (!data)
return;
DDSURFACEDESC ddsd = {};
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_LPSURFACE;
DXCheck(IDirectDrawSurface_Lock(tex->dds, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR, NULL));
int pitch = ddsd.lPitch;
if (!pitch)
pitch = ddsd.dwWidth * 4;
char *dst = (char *)ddsd.lpSurface;
for (int j = 0; j < (int)ddsd.dwHeight; j++)
{
//RGBA to BGRA
if (type == PF_RGBA_32)
{
for (int i = 0; i < ddsd.dwWidth; i++)
{
dst[i * 4 + 0] = data[i * 4 + 2];
dst[i * 4 + 1] = data[i * 4 + 1];
dst[i * 4 + 2] = data[i * 4 + 0];
dst[i * 4 + 3] = data[i * 4 + 3];
}
}
else if (type == PF_BGRA_32)
{
memcpy(dst, data, ddsd.dwWidth * 4);
}
dst += pitch;
data += ddsd.dwWidth * 4;
}
DXCheck(IDirectDrawSurface_Unlock(tex->dds, ddsd.lpSurface));
}
static qboolean GL_UploadTexture( dx_texture_t *tex, rgbdata_t *pic )
{
byte *buf, *data;
size_t size;
uint width, height;
uint j;
qboolean normalMap;
const byte *bufend;
// dedicated server
if (!dxc.window)
return true;
Assert(pic != NULL);
Assert(tex != NULL);
qboolean supported = true;
if (FBitSet(pic->flags, IMAGE_CUBEMAP))
supported = false;
else if (FBitSet(pic->flags, IMAGE_MULTILAYER) && pic->depth >= 1)
supported = false;
else if (pic->width > 1 && pic->height > 1 && pic->depth > 1)
supported = false;
else if (FBitSet(tex->flags, TF_RECTANGLE))
supported = false;
else if (FBitSet(tex->flags, TF_MULTISAMPLE))
supported = false;
// make sure what target is correct
if (!supported)
{
gEngfuncs.Con_DPrintf(S_ERROR "%s: %s is not supported\n", __func__, tex->name);
return false;
}
//if (pic->type == PF_BC6H_SIGNED || pic->type == PF_BC6H_UNSIGNED || pic->type == PF_BC7_UNORM || pic->type == PF_BC7_SRGB)
if (ImageCompressed(pic->type))
{
gEngfuncs.Con_DPrintf(S_ERROR "%s: compressed textures are not supported\n", __func__);
return false;
}
// store original sizes
tex->srcWidth = pic->width;
tex->srcHeight = pic->height;
// set the texture dimensions
{
int step = 0;// (int)gl_round_down.value;
int scaled_width, scaled_height;
for (scaled_width = 1; scaled_width < pic->width; scaled_width <<= 1);
if (step > 0 && pic->width < scaled_width && (step == 1 || (scaled_width - pic->width) > (scaled_width >> step)))
scaled_width >>= 1;
for (scaled_height = 1; scaled_height < pic->height; scaled_height <<= 1);
if (step > 0 && pic->height < scaled_height && (step == 1 || (scaled_height - pic->height) > (scaled_height >> step)))
scaled_height >>= 1;
tex->width = Q_max(1, scaled_width);
tex->height = Q_max(1, scaled_height);
}
DDSURFACEDESC ddsd = {};
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
//if (pic->numMips > 1)
// ddsd.ddsCaps.dwCaps |= DDSCAPS_MIPMAP | DDSCAPS_COMPLEX;
ddsd.dwWidth = tex->width;
ddsd.dwHeight = tex->height;
#if 1
//BGRA8
ddsd.dwFlags |= DDSD_PIXELFORMAT;
ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
if(FBitSet(pic->flags, IMAGE_HAS_ALPHA))
ddsd.ddpfPixelFormat.dwFlags |= DDPF_ALPHAPIXELS;
ddsd.ddpfPixelFormat.dwRGBBitCount = 32;
ddsd.ddpfPixelFormat.dwBBitMask = 0xFF;
ddsd.ddpfPixelFormat.dwGBitMask = 0xFF00;
ddsd.ddpfPixelFormat.dwRBitMask = 0xFF0000;
ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0xFF000000;
#endif
DXCheck(IDirectDraw_CreateSurface(dxc.pdd, &ddsd, &tex->dds, NULL));
DXCheck(IDirectDrawSurface_QueryInterface(tex->dds, &IID_IDirect3DTexture, (void**)&tex->d3dTex));
DXCheck(IDirect3DTexture_GetHandle(tex->d3dTex, dxc.pd3dd, &tex->d3dHandle));
tex->fogParams[0] = pic->fogParams[0];
tex->fogParams[1] = pic->fogParams[1];
tex->fogParams[2] = pic->fogParams[2];
tex->fogParams[3] = pic->fogParams[3];
buf = pic->buffer;
bufend = pic->buffer + pic->size; // total image size include all the layers, cube sides, mipmaps
normalMap = FBitSet(tex->flags, TF_NORMALMAP) ? true : false;
if (Q_max(1, pic->numMips) > 1) // not-compressed DDS
{
//TEMP
j = 0;
//for (j = 0; j < Q_max(1, pic->numMips); j++)
{
// track the buffer bounds
if (buf != NULL && buf >= bufend)
gEngfuncs.Host_Error("%s: %s image buffer overflow\n", __func__, tex->name);
width = Q_max(1, (tex->width >> j));
height = Q_max(1, (tex->height >> j));
size = gEngfuncs.Image_CalcImageSize(pic->type, width, height, 1);
GL_TextureImageRAW(tex, width, height, pic->type, buf);
buf += size; // move pointer
tex->numMips++;
}
}
else // RGBA32
{
// track the buffer bounds
if (buf != NULL && buf >= bufend)
gEngfuncs.Host_Error("%s: %s image buffer overflow\n", __func__, tex->name);
int mipCount = GL_CalcMipmapCount(tex, (buf != NULL));
// NOTE: only single uncompressed textures can be resamples, no mips, no layers, no sides
if (((pic->width != tex->width) || (pic->height != tex->height)))
data = GL_ResampleTexture(buf, pic->width, pic->height, tex->width, tex->height, normalMap);
else data = buf;
//if (!ImageCompressed(pic->type) && !FBitSet(tex->flags, TF_NOMIPMAP) && FBitSet(pic->flags, IMAGE_ONEBIT_ALPHA))
// data = GL_ApplyFilter(data, tex->width, tex->height);
// mips will be auto-generated if desired
for (j = 0; j < mipCount; j++)
{
width = Q_max(1, (tex->width >> j));
height = Q_max(1, (tex->height >> j));
size = gEngfuncs.Image_CalcImageSize(pic->type, width, height, 1);
GL_TextureImageRAW(tex, width, height, pic->type, data);
//if (mipCount > 1)
// GL_BuildMipMap(data, width, height, tex->depth, tex->flags);
tex->numMips++;
}
}
SetBits(tex->flags, TF_IMG_UPLOADED); // done
return true;
}
int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update )
{
dx_texture_t *tex;
if (!GL_CheckTexName(name))
return 0;
// see if already loaded
if ((tex = GL_TextureForName(name)) && !update)
return (tex - dx_textures);
// couldn't loading image
if (!pic) return 0;
if (update)
{
if (tex == NULL)
gEngfuncs.Host_Error("%s: couldn't find texture %s for update\n", __func__, name);
SetBits(tex->flags, flags);
}
else
{
// allocate the new one
tex = GL_AllocTexture(name, flags);
}
GL_ProcessImage(tex, pic);
if (!GL_UploadTexture(tex, pic))
{
memset(tex, 0, sizeof(dx_texture_t));
return 0;
}
return (tex - dx_textures);
}
int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags )
{
qboolean update = FBitSet( flags, TF_UPDATE ) ? true : false;
int datasize = 1;
rgbdata_t r_empty;
if( FBitSet( flags, TF_ARB_16BIT ))
datasize = 2;
else if( FBitSet( flags, TF_ARB_FLOAT ))
datasize = 4;
ClearBits( flags, TF_UPDATE );
memset( &r_empty, 0, sizeof( r_empty ));
r_empty.width = width;
r_empty.height = height;
r_empty.type = PF_RGBA_32;
r_empty.size = r_empty.width * r_empty.height * datasize * 4;
r_empty.buffer = (byte *)buffer;
// clear invalid combinations
ClearBits( flags, TF_TEXTURE_3D );
// if image not luminance and not alphacontrast it will have color
if( !FBitSet( flags, TF_LUMINANCE ) && !FBitSet( flags, TF_ALPHACONTRAST ))
SetBits( r_empty.flags, IMAGE_HAS_COLOR );
if( FBitSet( flags, TF_HAS_ALPHA ))
SetBits( r_empty.flags, IMAGE_HAS_ALPHA );
if( FBitSet( flags, TF_CUBEMAP ))
{
// no cubemaps in dx2
return 0;
}
int texnum = GL_LoadTextureFromBuffer( name, &r_empty, flags, update );
if( !Q_strcmp( name, REF_DEFAULT_TEXTURE ))
tr.defaultTexture = texnum;
else if( !Q_strcmp( name, REF_PARTICLE_TEXTURE ))
tr.particleTexture = texnum;
else if( !Q_strcmp( name, REF_WHITE_TEXTURE ))
tr.whiteTexture = texnum;
else if( !Q_strcmp( name, REF_GRAY_TEXTURE ))
tr.grayTexture = texnum;
else if( !Q_strcmp( name, REF_BLACK_TEXTURE ))
tr.blackTexture = texnum;
return texnum;
}
void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor )
{
;
}
void R_GetDetailScaleForTexture( int texture, float *xScale, float *yScale )
{
*xScale = *yScale = 1.0f;
}
void R_SetDetailScaleForTexture( int texture, float xScale, float yScale )
{
;
}
int GL_FindTexture( const char *name )
{
gEngfuncs.Con_Printf("GL_FindTexture(%s)\n", name);
return 0;
}
const char *GL_TextureName( unsigned int texnum )
{
return NULL;
}
const byte *GL_TextureData( unsigned int texnum )
{
return NULL;
}
int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
{
dx_texture_t *tex;
rgbdata_t *pic;
uint picFlags = 0;
if (!GL_CheckTexName(name))
return 0;
// see if already loaded
if ((tex = GL_TextureForName(name)))
return (tex - dx_textures);
gEngfuncs.Con_Printf("GL_LoadTexture(%s, %p, %zu, %X)\n", name, buf, size, flags);
if (FBitSet(flags, TF_NOFLIP_TGA))
SetBits(picFlags, IL_DONTFLIP_TGA);
if (FBitSet(flags, TF_KEEP_SOURCE) && !FBitSet(flags, TF_EXPAND_SOURCE))
SetBits(picFlags, IL_KEEP_8BIT);
// set some image flags
gEngfuncs.Image_SetForceFlags(picFlags);
pic = gEngfuncs.FS_LoadImage(name, buf, size);
if (!pic) return 0; // couldn't loading image
// allocate the new one
tex = GL_AllocTexture(name, flags);
GL_ProcessImage(tex, pic);
if (!GL_UploadTexture(tex, pic))
{
memset(tex, 0, sizeof(dx_texture_t));
gEngfuncs.FS_FreeImage(pic); // release source texture
return 0;
}
//GL_ApplyTextureParams(tex); // update texture filter, wrap etc
gEngfuncs.FS_FreeImage(pic); // release source texture
// NOTE: always return texnum as index in array or engine will stop work !!!
return tex - dx_textures;
}
void GL_FreeTexture( unsigned int texnum )
{
if (texnum <= 0 || texnum >= MAX_TEXTURES)
return;
gEngfuncs.Con_Printf("GL_FreeTexture(%d) %s\n", texnum, dx_textures[texnum].name);
dx_texture_t* tex = R_GetTexture(texnum);
if (!tex->dds)
return;
// debug
if (!tex->name[0])
{
gEngfuncs.Con_Printf(S_ERROR "%s: trying to free unnamed texture with handle %X\n", __func__, tex->d3dHandle);
return;
}
// remove from hash table
dx_texture_t **prev = &dx_texturesHashTable[tex->hashValue];
while (1)
{
dx_texture_t *cur = *prev;
if (!cur) break;
if (cur == tex)
{
*prev = cur->nextHash;
break;
}
prev = &cur->nextHash;
}
// TODO invalidate texture state
// release source
if (tex->original)
gEngfuncs.FS_FreeImage(tex->original);
if (tex->d3dTex)
IDirect3DTexture_Release(tex->d3dTex);
if (tex->dds)
IDirectDrawSurface_Release(tex->dds);
memset(tex, 0, sizeof(*tex));
}
void R_OverrideTextureSourceSize( unsigned int textnum, unsigned int srcWidth, unsigned int srcHeight )
{
}
void GL_UpdateTexture( int texnum, int cols, int rows, int width, int height, const byte *buffer, pixformat_t fmt )
{
;
}

319
ref/dx2/r_local.h Normal file
View File

@@ -0,0 +1,319 @@
/*
r_local.h - renderer local declarations
Copyright (C) 2010 Uncle Mike
Copyright (C) 2025-2026 lewa_j
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 3 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.
*/
#pragma once
#include "ref_common.h"
#include "ref_api.h"
#include "r_frustum.h"
#include "ref_params.h"
#include "mod_local.h"
#include "com_strings.h"
#include "pmove.h"
#define DIRECTDRAW_VERSION 0x0200
#define DIRECT3D_VERSION 0x0500//D3DCOLORMODEL bug
#include <ddraw.h>
#include <d3d.h>
#define MAX_TEXTURES 8192
#define TEXTURES_HASH_SIZE (MAX_TEXTURES >> 2)
#define MAX_DRAW_STACK 2 // normal view and menu view
#define CULL_VISIBLE 0 // not culled
#define CULL_BACKSIDE 1 // backside of transparent wall
#define CULL_FRUSTUM 2 // culled by frustum
#define CULL_VISFRAME 3 // culled by PVS
#define CULL_OTHER 4 // culled by other reason
typedef struct dx_texture_s
{
char name[256]; // game path, including extension (can be store image programs)
word srcWidth; // keep unscaled sizes
word srcHeight;
word width; // upload width\height
word height;
byte numMips; // mipmap count
int used;
texFlags_t flags;
rgba_t fogParams; // some water textures
// contain info about underwater fog
rgbdata_t *original; // keep original image
#if 0
word depth; // texture depth or count of layers for 2D_ARRAY
GLuint target; // glTarget
GLuint texnum; // gl texture binding
GLint format; // uploaded format
// debug info
size_t size; // upload size for debug targets
// detail textures stuff
float xscale;
float yscale;
#endif
IDirectDrawSurface *dds;
IDirect3DTexture *d3dTex;
D3DTEXTUREHANDLE d3dHandle;
uint hashValue;
struct dx_texture_s *nextHash;
} dx_texture_t;
typedef struct d3dEBContext_s
{
IDirect3DExecuteBuffer *pd3deb;
DWORD bufferSize;
void *data;
DWORD vertCount;
DWORD insOffset;
DWORD insLength;
} d3dEBContext_t;
typedef struct
{
ref_viewpass_t rvp;
cl_entity_t *currententity;
model_t *currentmodel;
cl_entity_t *currentbeam; // same as above but for beams
gl_frustum_t frustum;
mleaf_t *viewleaf;
mleaf_t *oldviewleaf;
vec3_t vforward;
vec3_t vright;
vec3_t vup;
vec3_t cullorigin;
vec3_t cull_vforward;
vec3_t cull_vright;
vec3_t cull_vup;
float farClip;
qboolean fogCustom;
qboolean fogEnabled;
qboolean fogSkybox;
vec4_t fogColor;
float fogDensity;
float fogStart;
float fogEnd;
int cached_contents; // in water
int cached_waterlevel; // was in water
float skyMins[2][SKYBOX_MAX_SIDES];
float skyMaxs[2][SKYBOX_MAX_SIDES];
matrix4x4 objectMatrix; // currententity matrix
matrix4x4 worldviewMatrix; // modelview for world
matrix4x4 modelviewMatrix; // worldviewMatrix * objectMatrix
matrix4x4 projectionMatrix;
matrix4x4 worldviewProjectionMatrix; // worldviewMatrix * projectionMatrix
byte visbytes[( MAX_MAP_LEAFS + 7 ) / 8];// actual PVS for current frame
float viewplanedist;
mplane_t clipPlane;
} ref_instance_t;
typedef struct
{
cl_entity_t *solid_entities[MAX_VISIBLE_PACKET]; // opaque moving or alpha brushes
cl_entity_t *trans_entities[MAX_VISIBLE_PACKET]; // translucent brushes
cl_entity_t *beam_entities[MAX_VISIBLE_PACKET];
uint num_solid_entities;
uint num_trans_entities;
uint num_beam_entities;
} draw_list_t;
typedef struct
{
int defaultTexture; // use for bad textures
int particleTexture;
int whiteTexture;
int grayTexture;
int blackTexture;
int skytexturenum; // index into model_t::textures
// entity lists
draw_list_t draw_stack[MAX_DRAW_STACK];
int draw_stack_pos;
draw_list_t *draw_list;
// matrix states
qboolean modelviewIdentity;
int visframecount; // PVS frame
int dlightframecount; // dynamic light frame
int realframecount; // not including viewpasses
int framecount;
qboolean fCustomRendering;
qboolean fResetVis;
double frametime; // special frametime for multipass rendering (will set to 0 on a nextview)
float blend; // global blend value
// cull info
vec3_t modelorg; // relative to viewpoint
// get from engine
model_t *worldmodel;
world_static_t *world;
cl_entity_t *entities;
cl_entity_t *viewent;
uint max_entities;
ref_screen_rotation_t rotation;
} dx_globals_t;
struct dx_context_s
{
HWND window;
int windowWidth;
int windowHeight;
IDirectDraw *pdd;
IDirectDrawSurface *pddsPrimary;
IDirectDrawSurface *pddsBack;
IDirectDrawSurface *pddsZBuffer;
IDirectDrawClipper *pddClipper;
IDirectDrawClipper *pddBackClipper;
IDirect3D *pd3d;
IDirect3DDevice *pd3dd;
IDirect3DExecuteBuffer *pd3deb;
IDirect3DViewport *viewport;
D3DMATRIXHANDLE mtxWorld;
D3DMATRIXHANDLE mtxProjection;
qboolean in2DMode;
int renderMode;
vec4_t currentColor;
D3DTEXTUREHANDLE currentTexture;
D3DTEXTUREHANDLE lastBoundTexture;
};
typedef struct dx_context_s dx_context_t;
extern ref_instance_t RI;
extern dx_globals_t tr;
extern dx_context_t dxc;
static inline cl_entity_t *CL_GetEntityByIndex( int index )
{
if( unlikely( index < 0 || index >= tr.max_entities || !tr.entities ))
return NULL;
return &tr.entities[index];
}
static inline model_t *CL_ModelHandle( int index )
{
if( unlikely( index < 0 || index >= gp_cl->nummodels ))
return NULL;
return gp_cl->models[index];
}
const char *dxResultToStr( HRESULT r );
#define DXCheckRet(DST, CALL) \
(DST) = (CALL);\
if ((DST) != DD_OK)\
gEngfuncs.Con_Printf( S_ERROR "%s():%s:%d: DirectX error %X(%d 0x%X %d) %s at \"" #CALL "\"\n", __FUNCTION__, __FILE__, __LINE__, (DST), ( (DST) >> 31 ) & 1, ( (DST) >> 16 ) & 0x7FFF, (DST) & 0xFFFF, dxResultToStr( r ));
#define DXCheck(CALL) \
{\
HRESULT r = DD_OK;\
DXCheckRet(r, CALL)\
}
void GL_SetRenderMode( int mode );
void GL_Bind( int tmu, unsigned int texnum );
// r_d3d.c
qboolean R_Init( void );
void R_Shutdown( void );
void GL_SetupAttributes( int safegl );
void GL_InitExtensions( void );
void GL_ClearExtensions( void );
void D3D_Resize( int width, int height );
qboolean D3D_StartExecuteBuffer( d3dEBContext_t *ctx );
qboolean D3D_EndExecuteBuffer( d3dEBContext_t *ctx );
void D3D_ReleaseExecuteBuffer( d3dEBContext_t *ctx );
void D3D_SetVertTL( D3DTLVERTEX *v, float x, float y, float z, float w, float tu, float tv );
void D3D_SetTri( D3DTRIANGLE *t, int v1, int v2, int v3 );
void D3D_PutInstruction( void **dst, BYTE opcode, BYTE size, WORD count );
void D3D_PutProcessVertices( void **dst, DWORD flags, WORD start, WORD count );
void D3D_PutRenderState( void **dst, D3DRENDERSTATETYPE type, DWORD arg );
void D3D_PutTransformState( void **dst, D3DTRANSFORMSTATETYPE type, DWORD arg );
// r_main.c
void R_GammaChanged( qboolean do_reset_gamma );
void R_BeginFrame( qboolean clearScene );
void R_RenderScene( void );
void R_EndFrame( void );
void R_AllowFog( qboolean allowed );
void R_RenderFrame( const struct ref_viewpass_s *rvp );
qboolean R_AddEntity( struct cl_entity_s *clent, int type );
void R_ClearScene( void );
int WorldToScreen( const vec3_t world, vec3_t screen );
void R_LoadIdentity( void );
void R_SetupD3D( qboolean set_state );
// r_draw.c
void R_Set2DMode( qboolean enable );
void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum );
void FillRGBA( int rendermode, float x, float y, float w, float h, byte r, byte g, byte b, byte a );
// r_image.c
void R_InitImages( void );
dx_texture_t *R_GetTexture( unsigned int texnum );
void R_ShowTextures( void );
const byte *R_GetTextureOriginalBuffer( unsigned int idx );
int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update );
void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor );
void R_GetDetailScaleForTexture( int texture, float *xScale, float *yScale );
void R_SetDetailScaleForTexture( int texture, float xScale, float yScale );
int GL_FindTexture( const char *name );
const char *GL_TextureName( unsigned int texnum );
const byte *GL_TextureData( unsigned int texnum );
int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags );
int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags );
void GL_FreeTexture( unsigned int texnum );
void R_OverrideTextureSourceSize( unsigned int textnum, unsigned int srcWidth, unsigned int srcHeight );
void GL_UpdateTexture( int texnum, int cols, int rows, int width, int height, const byte *buffer, pixformat_t fmt );
// r_surf.c
void GL_SubdivideSurface( model_t *mod, msurface_t *fa );
void GL_OrthoBounds( const float *mins, const float *maxs );
byte *Mod_GetCurrentVis( void );
void R_DrawWorld( void );
void R_MarkLeaves( void );
void GL_BuildLightmaps( void );
extern convar_t r_novis;
extern convar_t r_nocull;
extern convar_t r_lockpvs;
extern convar_t r_lockfrustum;

380
ref/dx2/r_main.c Normal file
View File

@@ -0,0 +1,380 @@
/*
r_main.c -- dx2 renderer main loop
Copyright (C) 2010 Uncle Mike
Copyright (C) 2025-2026 lewa_j
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 3 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.
*/
#include "r_local.h"
#include "ref_params.h"
#include "xash3d_mathlib.h"
ref_instance_t RI;
static void R_Clear( int bitMask )
{
int bits = D3DCLEAR_ZBUFFER;
//bits &= bitMask;
D3DRECT rect = {
.x1 = 0,
.y1 = 0,
.x2 = dxc.windowWidth,
.y2 = dxc.windowHeight,
};
DXCheck(IDirect3DViewport_Clear(dxc.viewport, 1, &rect, bits));
}
static float R_GetFarClip( void )
{
if( tr.worldmodel && FBitSet( RI.rvp.flags, RF_DRAW_WORLD ) )
return gp_movevars->zmax * 1.73f;
return 2048.0f;
}
void R_SetupFrustum( void )
{
// build the transformation matrix for the given view angles
AngleVectors( RI.rvp.viewangles, RI.vforward, RI.vright, RI.vup );
if( !r_lockfrustum.value )
{
VectorCopy( RI.rvp.vieworigin, RI.cullorigin );
VectorCopy( RI.vforward, RI.cull_vforward );
VectorCopy( RI.vright, RI.cull_vright );
VectorCopy( RI.vup, RI.cull_vup );
}
if( FBitSet( RI.rvp.flags, RF_DRAW_OVERVIEW ))
{
const ref_overview_t *ov = gEngfuncs.GetOverviewParms();
GL_FrustumInitOrtho( &RI.frustum, ov->xLeft, ov->xRight, ov->yTop, ov->yBottom, ov->zNear, ov->zFar );
}
else
{
GL_FrustumInitProj( &RI.frustum, 0.0f, R_GetFarClip(), RI.rvp.fov_x, RI.rvp.fov_y ); // NOTE: we ignore nearplane here (mirrors only)
}
}
static void R_SetupProjectionMatrix( matrix4x4 m )
{
float xMin, xMax, yMin, yMax, zNear, zFar;
if( FBitSet( RI.rvp.flags, RF_DRAW_OVERVIEW ))
{
const ref_overview_t *ov = gEngfuncs.GetOverviewParms();
Matrix4x4_CreateOrtho( m, ov->xLeft, ov->xRight, ov->yTop, ov->yBottom, ov->zNear, ov->zFar );
return;
}
RI.farClip = R_GetFarClip();
zNear = 4.0f;
zFar = Q_max( 256.0f, RI.farClip );
yMax = zNear * tan( RI.rvp.fov_y * M_PI_F / 360.0f );
yMin = -yMax;
xMax = zNear * tan( RI.rvp.fov_x * M_PI_F / 360.0f );
xMin = -xMax;
if( tr.rotation & 1 )
{
Matrix4x4_CreateProjection( m, yMax, yMin, xMax, xMin, zNear, zFar );
}
else
{
Matrix4x4_CreateProjection( m, xMax, xMin, yMax, yMin, zNear, zFar );
}
}
/*
=============
R_SetupModelviewMatrix
=============
*/
static void R_SetupModelviewMatrix( matrix4x4 m )
{
Matrix4x4_CreateModelview( m );
if( tr.rotation & 1 )
{
Matrix4x4_ConcatRotate( m, anglemod( -RI.rvp.viewangles[2] + 90 ), 1, 0, 0 );
Matrix4x4_ConcatRotate( m, -RI.rvp.viewangles[0], 0, 1, 0 );
Matrix4x4_ConcatRotate( m, -RI.rvp.viewangles[1], 0, 0, 1 );
}
else
{
Matrix4x4_ConcatRotate( m, -RI.rvp.viewangles[2], 1, 0, 0 );
Matrix4x4_ConcatRotate( m, -RI.rvp.viewangles[0], 0, 1, 0 );
Matrix4x4_ConcatRotate( m, -RI.rvp.viewangles[1], 0, 0, 1 );
}
Matrix4x4_ConcatTranslate( m, -RI.rvp.vieworigin[0], -RI.rvp.vieworigin[1], -RI.rvp.vieworigin[2] );
}
void R_LoadIdentity( void )
{
if( tr.modelviewIdentity ) return;
Matrix4x4_LoadIdentity( RI.objectMatrix );
Matrix4x4_Copy( RI.modelviewMatrix, RI.worldviewMatrix );
//TODO GL_LoadMatrix( MODELVIEW, RI.modelviewMatrix );
tr.modelviewIdentity = true;
}
void R_GammaChanged( qboolean do_reset_gamma )
{
if( do_reset_gamma )
{
// paranoia cubemap rendering
if( gEngfuncs.drawFuncs->GL_BuildLightmaps )
gEngfuncs.drawFuncs->GL_BuildLightmaps( );
}
else
{
//GL_RebuildLightmaps();
}
}
void R_BeginFrame( qboolean clearScene )
{
if(( gl_clear->value || ENGINE_GET_PARM( PARM_DEV_OVERVIEW )) &&
clearScene && ENGINE_GET_PARM( PARM_CONNSTATE ) != ca_cinematic )
{
D3DRECT rect = {
.x1 = 0,
.y1 = 0,
.x2 = dxc.windowWidth,
.y2 = dxc.windowHeight,
};
DXCheck(IDirect3DViewport_Clear(dxc.viewport, 1, &rect, D3DCLEAR_TARGET));
}
R_Set2DMode( true );
gEngfuncs.CL_ExtraUpdate();
}
static void R_DrawEntitiesOnList( void )
{
}
void R_RenderScene( void )
{
if( !tr.worldmodel && FBitSet( RI.rvp.flags, RF_DRAW_WORLD ) )
gEngfuncs.Host_Error("%s: NULL worldmodel\n", __func__);
// frametime is valid only for normal pass
if( !FBitSet( RI.rvp.flags, RF_DRAW_CUBEMAP ))
tr.frametime = gp_cl->time - gp_cl->oldtime;
else tr.frametime = 0.0;
// begin a new frame
tr.framecount++;
tr.dlightframecount = R_PushDlights( tr.worldmodel, tr.framecount );
R_SetupFrustum();
#if 0
R_SetupFrame();
#endif
R_SetupD3D(true);
R_Clear(~0);
R_MarkLeaves();
#if 0
R_DrawFog();
if( FBitSet( RI.rvp.flags, RF_DRAW_WORLD ))
R_AnimateRipples();
R_CheckGLFog();
#endif
R_DrawWorld();
// R_CheckFog();
gEngfuncs.CL_ExtraUpdate(); // don't let sound get messed up if going slow
R_DrawEntitiesOnList();
// R_DrawWaterSurfaces();
}
void R_EndFrame( void )
{
if (!dxc.window)
return;
R_Set2DMode( false );
//swap
if (dxc.pddsBack)
{
RECT dstRect = { 0 };
POINT point = { 0,0 };
ClientToScreen(dxc.window, &point);
GetClientRect(dxc.window, &dstRect);
OffsetRect(&dstRect, point.x, point.y);
RECT srcRect = { 0,0,dxc.windowWidth,dxc.windowHeight };
DXCheck(IDirectDrawSurface_Blt(dxc.pddsPrimary, &dstRect, dxc.pddsBack, &srcRect, DDBLT_WAIT, NULL));
}
//resize
RECT rect = { 0 };
GetClientRect(dxc.window, &rect);
int w = rect.right - rect.left;
int h = rect.bottom - rect.top;
if (w != dxc.windowWidth || h != dxc.windowHeight)
{
D3D_Resize(w, h);
}
}
void R_AllowFog( qboolean allowed )
{
}
static void R_SetupRefParams( const ref_viewpass_t *rvp )
{
RI.rvp = *rvp;
RI.farClip = 0;
}
void R_RenderFrame( const ref_viewpass_t *rvp )
{
if( r_norefresh->value )
return;
// setup the initial render params
R_SetupRefParams( rvp );
// completely override rendering
if( gEngfuncs.drawFuncs->GL_RenderFrame != NULL )
{
tr.fCustomRendering = true;
if( gEngfuncs.drawFuncs->GL_RenderFrame( rvp ))
{
R_GatherPlayerLight( tr.viewent );
tr.realframecount++;
tr.fResetVis = true;
return;
}
}
tr.fCustomRendering = false;
#if 0
if( !FBitSet( RI.rvp.flags, RF_ONLY_CLIENTDRAW ))
R_RunViewmodelEvents();
#endif
tr.realframecount++; // right called after viewmodel events
R_RenderScene();
}
qboolean R_AddEntity( struct cl_entity_s *clent, int type )
{
return true;
}
void R_ClearScene( void )
{
tr.draw_list->num_solid_entities = 0;
tr.draw_list->num_trans_entities = 0;
tr.draw_list->num_beam_entities = 0;
// clear the scene befor start new frame
if (gEngfuncs.drawFuncs->R_ClearScene != NULL)
gEngfuncs.drawFuncs->R_ClearScene();
}
int WorldToScreen( const vec3_t world, vec3_t screen )
{
VectorClear( screen );
return 0;
}
void R_SetupD3D( qboolean set_state )
{
R_SetupModelviewMatrix( RI.worldviewMatrix );
R_SetupProjectionMatrix( RI.projectionMatrix );
Matrix4x4_Concat( RI.worldviewProjectionMatrix, RI.projectionMatrix, RI.worldviewMatrix );
if( !set_state ) return;
D3DVIEWPORT viewport = { 0 };
viewport.dwSize = sizeof(viewport);
if( !FBitSet( RI.rvp.flags, RF_DRAW_CUBEMAP ))
{
int x, x2, y, y2;
// set up viewport (main, playersetup)
x = floor( RI.rvp.viewport[0] * gpGlobals->width / gpGlobals->width );
x2 = ceil( (RI.rvp.viewport[0] + RI.rvp.viewport[2]) * gpGlobals->width / gpGlobals->width );
y = floor( gpGlobals->height - RI.rvp.viewport[1] * gpGlobals->height / gpGlobals->height );
y2 = ceil( gpGlobals->height - (RI.rvp.viewport[1] + RI.rvp.viewport[3]) * gpGlobals->height / gpGlobals->height );
if( tr.rotation & 1 )
{
viewport.dwX = y2;
viewport.dwY = x;
viewport.dwWidth = y - y2;
viewport.dwHeight = x2 - x;
}
else
{
viewport.dwX = x;
viewport.dwY = y2;
viewport.dwWidth = x2 - x;
viewport.dwHeight = y - y2;
}
}
else
{
// envpass, mirrorpass
viewport.dwX = RI.rvp.viewport[0];
viewport.dwY = RI.rvp.viewport[1];
viewport.dwWidth = RI.rvp.viewport[2];
viewport.dwHeight = RI.rvp.viewport[3];
}
viewport.dvScaleX = 0.5f * viewport.dwWidth;
viewport.dvScaleY = 0.5f * viewport.dwHeight;
viewport.dvMaxX = 1;//calc for partial views
viewport.dvMaxY = 1;
viewport.dvMinZ = 0;
viewport.dvMaxZ = 1;
DXCheck(IDirect3DViewport_SetViewport(dxc.viewport, &viewport));
{
float dest[16];
Matrix4x4_ToArrayFloatGL(RI.projectionMatrix, dest);
DXCheck(IDirect3DDevice_SetMatrix(dxc.pd3dd, dxc.mtxProjection, (D3DMATRIX *)&dest));
Matrix4x4_ToArrayFloatGL(RI.worldviewMatrix, dest);
DXCheck(IDirect3DDevice_SetMatrix(dxc.pd3dd, dxc.mtxWorld, (D3DMATRIX *)&dest));
}
}

625
ref/dx2/r_surf.c Normal file
View File

@@ -0,0 +1,625 @@
/*
r_surf.c - surface-related refresh code
Copyright (C) 2025-2026 lewa_j
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 3 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.
*/
#include "r_local.h"
#include "xash3d_mathlib.h"
void GL_OrthoBounds( const float *mins, const float *maxs )
{
;
}
byte *Mod_GetCurrentVis( void )
{
return NULL;
}
void R_LightmapCoord( const vec3_t v, const msurface_t *surf, const float sample_size, vec2_t coords )
{
const mextrasurf_t *info = surf->info;
float s, t;
#define BLOCK_SIZE 256
s = DotProduct( v, info->lmvecs[0] ) + info->lmvecs[0][3] - info->lightmapmins[0];
s += surf->light_s * sample_size;
s += sample_size * 0.5f;
s /= BLOCK_SIZE * sample_size;
t = DotProduct( v, info->lmvecs[1] ) + info->lmvecs[1][3] - info->lightmapmins[1];
t += surf->light_t * sample_size;
t += sample_size * 0.5f;
t /= BLOCK_SIZE * sample_size;
#undef BLOCK_SIZE
Vector2Set( coords, s, t );
}
static void R_TextureCoord( const vec3_t v, const msurface_t *surf, vec2_t coords )
{
const mtexinfo_t *info = surf->texinfo;
float s, t;
s = DotProduct( v, info->vecs[0] );
t = DotProduct( v, info->vecs[1] );
if( !FBitSet( surf->flags, SURF_DRAWTURB ))
{
s = ( s + info->vecs[0][3] ) / info->texture->width;
t = ( t + info->vecs[1][3] ) / info->texture->height;
}
Vector2Set( coords, s, t );
}
static void R_GetEdgePosition( const model_t *mod, const msurface_t *fa, int i, vec3_t vec )
{
const int lindex = mod->surfedges[fa->firstedge + i];
if( FBitSet( mod->flags, MODEL_QBSP2 ))
{
const medge32_t *pedges = mod->edges32;
if( lindex > 0 )
VectorCopy( mod->vertexes[pedges[lindex].v[0]].position, vec );
else
VectorCopy( mod->vertexes[pedges[-lindex].v[1]].position, vec );
}
else
{
const medge16_t *pedges = mod->edges16;
if( lindex > 0 )
VectorCopy( mod->vertexes[pedges[lindex].v[0]].position, vec );
else
VectorCopy( mod->vertexes[pedges[-lindex].v[1]].position, vec );
}
}
void GL_SubdivideSurface( model_t *mod, msurface_t *fa )
{
;
}
/*
================
GL_BuildPolygonFromSurface
================
*/
static int GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa )
{
int i, lnumverts, nColinElim = 0;
float sample_size;
texture_t *tex;
dx_texture_t *dxt;
glpoly2_t *poly;
if( !mod || !fa->texinfo || !fa->texinfo->texture )
return nColinElim; // bad polygon ?
if( FBitSet( fa->flags, SURF_CONVEYOR ) && fa->texinfo->texture->gl_texturenum != 0 )
{
dxt = R_GetTexture( fa->texinfo->texture->gl_texturenum );
tex = fa->texinfo->texture;
Assert( dxt != NULL && tex != NULL );
// update conveyor widths for keep properly speed of scrolling
dxt->srcWidth = tex->width;
dxt->srcHeight = tex->height;
}
sample_size = gEngfuncs.Mod_SampleSizeForFace( fa );
// reconstruct the polygon
lnumverts = fa->numedges;
// detach if already created, reconstruct again
poly = fa->polys;
fa->polys = NULL;
// quake simple models (healthkits etc) need to be reconstructed their polys because LM coords has changed after the map change
poly = Mem_Realloc( mod->mempool, poly, sizeof( glpoly2_t ) + lnumverts * VERTEXSIZE * sizeof( float ));
poly->next = fa->polys;
poly->flags = fa->flags;
fa->polys = poly;
poly->numverts = lnumverts;
for( i = 0; i < lnumverts; i++ )
{
R_GetEdgePosition( mod, fa, i, poly->verts[i] );
R_TextureCoord( poly->verts[i], fa, &poly->verts[i][3] );
R_LightmapCoord( poly->verts[i], fa, sample_size, &poly->verts[i][5] );
}
// TODO or not TODO gl_keeptjunctions?
poly->numverts = lnumverts;
return nColinElim;
}
/*
===============
R_TextureAnimation
Returns the proper texture for a given time and surface
===============
*/
static texture_t *R_TextureAnimation( msurface_t *s )
{
texture_t *base = s->texinfo->texture;
// TODO
return base;
}
static void DrawGLPoly( glpoly2_t *p, float xScale, float yScale )
{
float *v;
float sOffset, sy;
float tOffset, cy;
cl_entity_t *e = RI.currententity;
int i, hasScale = false;
if( !p ) return;
{
sOffset = tOffset = 0.0f;
}
if( xScale != 0.0f && yScale != 0.0f )
hasScale = true;
d3dEBContext_t ebc = { 0 };
if( !D3D_StartExecuteBuffer( &ebc ))
return;
void *cur = ebc.data;
D3DLVERTEX* verts = (D3DLVERTEX*)cur;
for( i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE )
{
D3DLVERTEX *dv = verts + i;
if( hasScale )
{
dv->tu = ( v[3] + sOffset ) * xScale;
dv->tv = ( v[4] + tOffset ) * yScale;
}
else
{
dv->tu = v[3] + sOffset;
dv->tv = v[4] + tOffset;
}
dv->x = v[0];
dv->y = v[1];
dv->z = v[2];
dv->color = 0xFFFFFFFF;
}
cur = (void*)(((D3DTLVERTEX*)cur) + p->numverts);
void* insStart = cur;
D3D_PutProcessVertices(&cur, D3DPROCESSVERTICES_TRANSFORM | D3DPROCESSVERTICES_UPDATEEXTENTS, 0, p->numverts);
D3D_PutInstruction(&cur, D3DOP_STATERENDER, sizeof(D3DSTATE), 4);
D3D_PutRenderState(&cur, D3DRENDERSTATE_TEXTUREHANDLE, dxc.currentTexture);
D3D_PutRenderState(&cur, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_DECAL);
D3D_PutRenderState(&cur, D3DRENDERSTATE_BLENDENABLE, FALSE);
D3D_PutRenderState(&cur, D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
// align
if (((ULONG)cur) & 7) {
D3D_PutInstruction(&cur, D3DOP_TRIANGLE, sizeof(D3DTRIANGLE), 0);
}
D3D_PutInstruction(&cur, D3DOP_TRIANGLE, sizeof(D3DTRIANGLE), p->numverts - 2);
for (i = 0; i < p->numverts; i++)
{
D3D_SetTri(cur, 0, i + 1, i + 2);
cur = (void*)(((D3DTRIANGLE*)cur) + 1);
}
D3D_PutInstruction(&cur, D3DOP_EXIT, 0, 0);
ebc.vertCount = p->numverts;
ebc.insOffset = ((char*)insStart - (char*)ebc.data);
ebc.insLength = ((char*)cur - (char*)insStart);
if( !D3D_EndExecuteBuffer( &ebc ))
return;
DXCheck(IDirect3DDevice_BeginScene(dxc.pd3dd));
DXCheck(IDirect3DDevice_Execute(dxc.pd3dd, ebc.pd3deb, dxc.viewport, D3DEXECUTE_CLIPPED));
DXCheck(IDirect3DDevice_EndScene(dxc.pd3dd));
D3D_ReleaseExecuteBuffer( &ebc );
//
//if( FBitSet( p->flags, SURF_DRAWTILED ))
// GL_SetupFogColorForSurfaces();
}
static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
{
texture_t *t;
//r_stats.c_world_polys++;
if( fa->flags & SURF_DRAWSKY )
return; // already handled
t = R_TextureAnimation( fa );
GL_Bind( XASH_TEXTURE0, t->gl_texturenum );
DrawGLPoly( fa->polys, 0.0f, 0.0f );
}
static void R_DrawTextureChains( void )
{
int i;
msurface_t *s;
texture_t *t;
// make sure what color is reset
Vector4Set( dxc.currentColor, 1, 1, 1, 1 );
R_LoadIdentity(); // set identity matrix
//GL_SetupFogColorForSurfaces();
// restore worldmodel
RI.currententity = CL_GetEntityByIndex( 0 );
RI.currentmodel = RI.currententity->model;
for( i = 0; i < tr.worldmodel->numtextures; i++ )
{
t = tr.worldmodel->textures[i];
if( !t ) continue;
s = t->texturechain;
if( !s || ( i == tr.skytexturenum ))
continue;
for( ; s != NULL; s = s->texturechain )
R_RenderBrushPoly( s, CULL_VISIBLE );
t->texturechain = NULL;
}
}
/*
=================
R_CullSurface
cull invisible surfaces
=================
*/
static int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags )
{
cl_entity_t *e = RI.currententity;
if( !surf || !surf->texinfo || !surf->texinfo->texture )
return CULL_OTHER;
//TODO
return CULL_VISIBLE;
}
static void R_RecursiveWorldNode( mnode_t *node, uint clipflags )
{
int i, clipped;
msurface_t *surf, **mark;
mleaf_t *pleaf;
int c, side;
float dot;
mnode_t *children[2];
int numsurfaces, firstsurface;
loc0:
if( node->contents == CONTENTS_SOLID )
return; // hit a solid leaf
if( node->visframe != tr.visframecount )
return;
if( clipflags && !r_nocull.value )
{
for( i = 0; i < 6; i++ )
{
const mplane_t *p = &RI.frustum.planes[i];
if( !FBitSet( clipflags, BIT( i )))
continue;
clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, p );
if( clipped == 2 ) return;
if( clipped == 1 ) ClearBits( clipflags, BIT( i ));
}
}
// if a leaf node, draw stuff
if( node->contents < 0 )
{
pleaf = (mleaf_t *)node;
mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces;
if( c )
{
do
{
(*mark)->visframe = tr.framecount;
mark++;
} while( --c );
}
// deal with model fragments in this leaf
if( pleaf->efrags )
gEngfuncs.R_StoreEfrags( &pleaf->efrags, tr.realframecount );
// r_stats.c_world_leafs++;
return;
}
// node is just a decision point, so go down the apropriate sides
// find which side of the node we are on
dot = PlaneDiff( tr.modelorg, node->plane );
side = (dot >= 0.0f) ? 0 : 1;
// recurse down the children, front side first
node_children( children, node, tr.worldmodel );
R_RecursiveWorldNode( children[side], clipflags );
firstsurface = node_firstsurface( node, tr.worldmodel );
numsurfaces = node_numsurfaces( node, tr.worldmodel );
// draw stuff
for( c = numsurfaces, surf = tr.worldmodel->surfaces + firstsurface; c; c--, surf++ )
{
if( R_CullSurface( surf, &RI.frustum, clipflags ))
continue;
if( surf->flags & SURF_DRAWSKY )
{
#if 0
// make sky chain to right clip the skybox
surf->texturechain = skychain;
skychain = surf;
#endif
}
else
{
surf->texturechain = surf->texinfo->texture->texturechain;
surf->texinfo->texture->texturechain = surf;
}
}
// recurse down the back side
node = children[!side];
goto loc0;
}
void R_DrawWorld( void )
{
double start, end;
// paranoia issues: when gl_renderer is "0" we need have something valid for currententity
// to prevent crashing until HeadShield drawing.
RI.currententity = CL_GetEntityByIndex( 0 );
if( !RI.currententity )
return;
RI.currentmodel = RI.currententity->model;
if( !FBitSet( RI.rvp.flags, RF_DRAW_WORLD ) || FBitSet( RI.rvp.flags, RF_ONLY_CLIENTDRAW ))
return;
VectorCopy( RI.cullorigin, tr.modelorg );
//memset( gl_lms.lightmap_surfaces, 0, sizeof( gl_lms.lightmap_surfaces ));
//memset( fullbright_surfaces, 0, sizeof( fullbright_surfaces ));
//memset( detail_surfaces, 0, sizeof( detail_surfaces ));
//gl_lms.dynamic_surfaces = NULL;
tr.blend = 1.0f;
//R_ClearSkyBox ();
start = gEngfuncs.pfnTime();
if( FBitSet( RI.rvp.flags, RF_DRAW_OVERVIEW ))
{
//R_DrawWorldTopView( tr.worldmodel->nodes, RI.frustum.clipFlags );
}
else R_RecursiveWorldNode( tr.worldmodel->nodes, RI.frustum.clipFlags );
end = gEngfuncs.pfnTime();
//r_stats.t_world_node = end - start;
start = gEngfuncs.pfnTime();
R_DrawTextureChains();
end = gEngfuncs.pfnTime();
//r_stats.t_world_draw = end - start;
//tr.num_draw_decals = 0;
//skychain = NULL;
gEngfuncs.R_DrawWorldHull();
}
/*
===============
R_MarkLeaves
Mark the leaves and nodes that are in the PVS for the current leaf
===============
*/
void R_MarkLeaves( void )
{
qboolean novis = false;
qboolean force = false;
mleaf_t *leaf = NULL;
mnode_t *node;
vec3_t test;
int i;
if( !FBitSet( RI.rvp.flags, RF_DRAW_WORLD ) ) return;
if( FBitSet( r_novis.flags, FCVAR_CHANGED ) || tr.fResetVis )
{
// force recalc viewleaf
ClearBits( r_novis.flags, FCVAR_CHANGED );
tr.fResetVis = false;
RI.viewleaf = NULL;
}
VectorCopy( RI.rvp.vieworigin, test );
if( RI.viewleaf != NULL )
{
// merge two leafs that can be a crossed-line contents
if( RI.viewleaf->contents == CONTENTS_EMPTY )
VectorSet( test, RI.rvp.vieworigin[0], RI.rvp.vieworigin[1], RI.rvp.vieworigin[2] - 16.0f );
else
VectorSet( test, RI.rvp.vieworigin[0], RI.rvp.vieworigin[1], RI.rvp.vieworigin[2] + 16.0f );
leaf = gEngfuncs.Mod_PointInLeaf( test, tr.worldmodel->nodes, tr.worldmodel );
if(( leaf->contents != CONTENTS_SOLID ) && ( RI.viewleaf != leaf ))
force = true;
}
if( RI.viewleaf == RI.oldviewleaf && RI.viewleaf != NULL && !force )
return;
// development aid to let you run around
// and see exactly where the pvs ends
if( r_lockpvs.value ) return;
RI.oldviewleaf = RI.viewleaf;
tr.visframecount++;
if( r_novis.value || FBitSet( RI.rvp.flags, RF_DRAW_OVERVIEW ) || !RI.viewleaf || !tr.worldmodel->visdata )
novis = true;
gEngfuncs.R_FatPVS( RI.rvp.vieworigin, r_pvs_radius->value, RI.visbytes, false, novis );
if( force && !novis )
gEngfuncs.R_FatPVS( test, r_pvs_radius->value, RI.visbytes, true, novis );
for( i = 0; i < tr.worldmodel->numleafs; i++ )
{
if( CHECKVISBIT( RI.visbytes, i ))
{
node = (mnode_t *)&tr.worldmodel->leafs[i+1];
do
{
if( node->visframe == tr.visframecount )
break;
node->visframe = tr.visframecount;
node = node->parent;
} while( node );
}
}
}
/*
==================
GL_BuildLightmaps
Builds the lightmap texture
with all the surfaces from all brush models
==================
*/
void GL_BuildLightmaps( void )
{
int i, j, nColinElim = 0;
model_t *m;
#if 0
// release old lightmaps
for( i = 0; i < MAX_LIGHTMAPS; i++ )
{
if( !tr.lightmapTextures[i] ) break;
GL_FreeTexture( tr.lightmapTextures[i] );
}
memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures ));
#endif
memset( &RI, 0, sizeof( RI ));
#if 0
// update the lightmap blocksize
if( FBitSet( gp_host->features, ENGINE_LARGE_LIGHTMAPS ) || tr.world->version == QBSP2_VERSION || r_large_lightmaps.value )
tr.block_size = BLOCK_SIZE_MAX;
else tr.block_size = BLOCK_SIZE_DEFAULT;
skychain = NULL;
#endif
tr.framecount = tr.visframecount = 1; // no dlight cache
//gl_lms.current_lightmap_texture = 0;
tr.modelviewIdentity = false;
tr.realframecount = 1;
#if 0
// setup the texture for dlights
R_InitDlightTexture();
// setup all the lightstyles
CL_RunLightStyles((lightstyle_t *)ENGINE_GET_PARM( PARM_GET_LIGHTSTYLES_PTR ));
LM_InitBlock();
#endif
for( i = 0; i < gp_cl->nummodels; i++ )
{
if(( m = CL_ModelHandle( i + 1 )) == NULL )
continue;
if( m->name[0] == '*' || m->type != mod_brush )
continue;
for( j = 0; j < m->numsurfaces; j++ )
{
// clearing all decal chains
m->surfaces[j].pdecals = NULL;
m->surfaces[j].visframe = 0;
//GL_CreateSurfaceLightmap( m->surfaces + j, m );
if( m->surfaces[j].flags & SURF_DRAWTURB )
continue;
nColinElim += GL_BuildPolygonFromSurface( m, m->surfaces + j );
}
// clearing visframe
for( j = 0; j < m->numleafs; j++ )
m->leafs[j+1].visframe = 0;
for( j = 0; j < m->numnodes; j++ )
m->nodes[j].visframe = 0;
}
//LM_UploadBlock( false );
if( gEngfuncs.drawFuncs->GL_BuildLightmaps )
{
// build lightmaps on the client-side
gEngfuncs.drawFuncs->GL_BuildLightmaps( );
}
}

18
ref/dx2/wscript Normal file
View File

@@ -0,0 +1,18 @@
#! /usr/bin/env python
# encoding: utf-8
# mittorn, 2018
def options(opt):
pass
def configure(conf):
pass
def build(bld):
bld.shlib(
source = ['r_context.c', 'r_image.c', 'r_d3d.c', 'r_main.c', 'r_draw.c', 'r_surf.c', 'r_frustum.c'],
target = 'ref_dx2',
defines = 'REF_DLL',
use = 'ref_common engine_includes sdk_includes werror public USER32 DDRAW',
install_path = bld.env.LIBDIR
)

View File

@@ -118,6 +118,7 @@ SUBDIRS = [
Subproject('ref/common', lambda x: x.env.CLIENT),
Subproject('ref/gl', lambda x: x.env.CLIENT and (x.env.GL or x.env.NANOGL or x.env.GLWES or x.env.GL4ES or x.env.GLES3COMPAT)),
Subproject('ref/soft', lambda x: x.env.CLIENT and x.env.SOFT),
Subproject('ref/dx2', lambda x: x.env.CLIENT and x.env.DX2),
Subproject('ref/null', lambda x: x.env.CLIENT and x.env.NULL),
Subproject('3rdparty/bzip2', lambda x: x.env.CLIENT and not x.env.HAVE_SYSTEM_BZ2),
Subproject('3rdparty/mbedtls'),
@@ -151,6 +152,7 @@ REFDLLS = [
RefDll('gl4es', False),
RefDll('gles3compat', False, 'GLES3COMPAT'),
RefDll('null', False),
RefDll('dx2', False),
]
def options(opt):
@@ -495,7 +497,7 @@ def configure(conf):
# Don't check them more than once, to save time
# Usually, they are always available
# but we need them in uselib
a = [ 'user32', 'shell32', 'gdi32', 'advapi32', 'dbghelp', 'psapi', 'ws2_32', 'bcrypt' ]
a = [ 'user32', 'shell32', 'gdi32', 'advapi32', 'dbghelp', 'psapi', 'ws2_32', 'bcrypt', 'ddraw' ]
if conf.env.COMPILER_CC == 'msvc':
for i in a:
conf.start_msg('Checking for MSVC library')