Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 1392-2-2-15-attempting-to-draw-a-hud-graphic-with-the-same-lump-name-as-a-lua-script-crashes-the
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2214-pre1
  • 2214-pre2
  • 2214-pre3
  • 2214-pre4
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • acs
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • cleanup-opengl
  • cleanupmusic
  • clipmidtex
  • cmake-valgrind
  • crawlacommander-sprites
  • custom-map-names
  • custom-teams
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delfile2
  • deprecate-lua-dedicated-server
  • dpl-2
  • dropshadows-spawning
  • dynabsp
  • emblem-drawing
  • exchndl-xp-fix
  • extra-textures
  • few-kart-lua-changes
  • ffloorclip
  • fix-167
  • fix-cvar-conflicts
  • fix-opengl-parameter-crash
  • fix-opengl-shear-roll
  • flipfuncpointers
  • fof-lightlist-fixes
  • font-FUCK
  • frictionrefactor
  • fuck-macros-1
  • gamepad-luakeydown
  • gamepad-morefixes
  • gamepad_experiments
  • gametype-refactor
  • gametype-refactor-1
  • gametype-refactor-player-spawns
  • ghost-networking
  • gif-splitting
  • grr-lj
  • hitboxviewer
  • hwr-texture-cache-refactor
  • hwrender2
  • improve-439
  • increase-maxconditionsets
  • increase-packet-tics
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • just-in-case
  • keycodes-only
  • ksf-wadfiles
  • ld413-mp-fix
  • levelstruct
  • libpng-version-support
  • linedef-actions
  • lj-test
  • lol-states
  • loopedsounds
  • lower-unpegged-fix
  • lua-change-gametype
  • lua-command-netids
  • lua-gfx-2
  • lua-gfx-sprites
  • lua-local
  • makefile-auto-mingw-gcc
  • makefile-tinkering
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.12
  • SRB2_release_2.2.13
  • SRB2_release_2.2.15
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
142 results

Target

Select target project
  • STJr/SRB2
  • Sryder/SRB2
  • wolfy852/SRB2
  • Alpha2244/SRB2
  • Inuyasha/SRB2
  • yoshibot/SRB2
  • TehRealSalt/SRB2
  • PrisimaTF/SRB2
  • Hatninja/SRB2
  • SteelT/SRB2
  • james/SRB2
  • ShaderWraith/SRB2
  • SinnamonLat/SRB2
  • mazmazz_/SRB2
  • filpAM/SRB2
  • chaoloveicemdboy/SRB2
  • Whooa21/SRB2
  • Machturne/SRB2
  • Golden/SRB2
  • Tatsuru/SRB2
  • Snu/SRB2
  • Zwip-Zwap_Zapony/SRB2
  • fickleheart/SRB2
  • alphaRexJames/SRB2
  • JJK/SRB2
  • diskpoppy/SRB2
  • Hannu_Hanhi/SRB2
  • ZipperQR/SRB2
  • kays/SRB2
  • spherallic/SRB2
  • Zippy_Zolton/SRB2
  • namiishere/SRB2
  • Ors/SRB2
  • SMS_Alfredo/SRB2
  • sonic_edge/SRB2
  • lavla/SRB2
  • ashi/SRB2
  • X.organic/SRB2
  • Fafabis/SRB2
  • Meziu/SRB2
  • v-rob/SRB2
  • tertu/SRB2
  • bitten2up/SRB2
  • flarn2006/SRB2
  • Krabs/SRB2
  • clairebun/SRB2
  • Lactozilla/SRB2
  • thehackstack/SRB2
  • Spice/SRB2
  • win8linux/SRB2
  • JohnFrostFox/SRB2
  • talktoneon726/SRB2
  • Wane/SRB2
  • Lamibe/SRB2
  • spectrumuk2/srb-2
  • nerdyminer18/srb-2
  • 256nil/SRB2
  • ARJr/SRB2
  • Alam/SRB2
  • Zenya/srb-2-marathon-demos
  • Acelite/srb-2-archivedmodifications
  • MIDIMan/SRB2
  • Lach/SRB2
  • Frostiikin/bounce-tweaks
  • Jaden/SRB2
  • Tyron/SRB2
  • Astronight/SRB2
  • Mari0shi06/SRB2
  • aiire/SRB2
  • Galactice/SRB2
  • srb2-ports/srb2-dreamcast
  • sdasdas/SRB2
  • chreas/srb-2-vr
  • StarManiaKG/the-story-of-sinically-rocketing-and-botching-the-2nd
  • LoganAir/SRB2
  • NepDisk/srb-2
  • alufolie91/SRB2
  • Felicia.iso/SRB2
  • twi/SRB2
  • BarrelsOFun/SRB2
  • Speed2411/SRB2
  • Leather_Realms/SRB2
  • Ayemar/SRB2
  • Acelite/SRB2
  • VladDoc/SRB2
  • kaldrum/model-features
  • strawberryfox417/SRB2
  • Lugent/SRB2
  • Rem/SRB2
  • Refrag/SRB2
  • Henry_3230/srb-3230
  • TehPuertoRicanSpartan2/tprs-srb2
  • Leminn/srb-2-marathon-stuff
  • chromaticpipe2/SRB2
  • MiguelGustavo15/SRB2
  • Maru/srb-2-tests
  • SilicDev/SRB2
  • UnmatchedBracket/SRB2
  • HybridDog/SRB2
  • xordspar0/SRB2
  • jsjhbewfhh/SRB2
  • Fancy2209/SRB2
  • Lorsoen/SRB2
  • shindoukin/SRB2
  • GamerOfDays/SRB2
  • Craftyawesome/SRB2
  • tenshi-tensai-tennoji/SRB2
  • Scarfdudebalder/SRB2
  • luigi-budd/srb-2-fix-interplag-lockon
  • mskluesner/SRB2
  • johnpetersa19/SRB2
  • Pheazant/SRB2
  • chromaticpipe2/srb2classic
  • romoney5/SRB2
  • PAS/SRB2Classic
  • BlueStaggo/SRB2
  • Jisk/srb-2-beef-jerky
117 results
Select Git revision
  • 1168-accessing-an-invalid-variable-in-ticcmd_t-crashes-the-game
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • batocera
  • blend-locking
  • blentran
  • blockmap-links
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • cleanup-opengl
  • cleanupmusic
  • cmake-valgrind
  • crawlacommander-sprites
  • custom-map-names
  • custom-teams
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delfile2
  • deprecate-lua-dedicated-server
  • dpl-2
  • dropshadows-spawning
  • dynabsp
  • emblem-drawing
  • exchndl-xp-fix
  • few-kart-lua-changes
  • ffloorclip
  • fix-1183
  • fix-cvar-conflicts
  • fix-opengl-shear-roll
  • fix-slope-plane-distortion
  • fix-sw-polyobject-interpolation
  • fix-table-key-archiving
  • flipfuncpointers
  • fof-lightlist-fixes
  • font-FUCK
  • font_drawer
  • frictionrefactor
  • fruits-clipper
  • fuck-macros-1
  • gamepad-luakeydown
  • gamepad-morefixes
  • gamepad_experiments
  • gametype-refactor
  • gametype-refactor-1
  • gametype-refactor-player-spawns
  • ghost-networking
  • gif-splitting
  • gitlab-ci
  • grr-lj
  • hitboxviewer
  • hwr-texture-cache-refactor
  • hwrender2
  • improve-439
  • increase-packet-tics
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • keycodes-only
  • ksf-wadfiles
  • ld413-mp-fix
  • levelstruct
  • libpng-version-support
  • linedef-actions
  • lj-test
  • lol-states
  • loopedsounds
  • lower-unpegged-fix
  • lua-change-gametype
  • lua-command-netids
  • lua-gfx-2
  • lua-gfx-sprites
  • lua-local
  • lugstuff
  • makefile-auto-mingw-gcc
  • makefile-tinkering
  • map-components-signedness-fixes
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.12
  • SRB2_release_2.2.13
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
141 results
Show changes
Showing
with 6187 additions and 6132 deletions
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -18,6 +18,12 @@
#define ZCLIP_PLANE 4.0f // Used for the actual game drawing
#define NZCLIP_PLANE 0.9f // Seems to be only used for the HUD and screen textures
// The width/height/depth of the palette lookup table used by palette rendering.
// Changing this also requires changing the shader code!
// Also assumed to be a power of two in some parts of the code.
// 64 seems to work perfectly for the vanilla palette.
#define HWR_PALETTE_LUT_SIZE 64
// ==========================================================================
// SIMPLE TYPES
// ==========================================================================
......@@ -122,33 +128,31 @@ typedef struct
} FOutVector;
#ifdef GL_SHADERS
// Predefined shader types
// Shader targets used to render specific types of geometry.
// A shader target is resolved to an actual shader with HWR_GetShaderFromTarget.
// The shader returned may be a base shader or a custom shader.
enum
{
SHADER_NONE = -1,
SHADER_DEFAULT = 0,
SHADER_FLOOR,
SHADER_FLOOR = 0,
SHADER_WALL,
SHADER_SPRITE,
SHADER_MODEL, SHADER_MODEL_LIGHTING,
SHADER_MODEL,
SHADER_WATER,
SHADER_FOG,
SHADER_SKY,
SHADER_PALETTE_POSTPROCESS,
SHADER_UI_COLORMAP_FADE,
SHADER_UI_TINTED_WIPE,
NUMBASESHADERS,
NUMSHADERTARGETS
};
// Maximum amount of shader programs
// Must be higher than NUMBASESHADERS
#define HWR_MAXSHADERS 16
// Shader sources (vertex and fragment)
typedef struct
{
char *vertex;
char *fragment;
} shadersource_t;
// Must be at least NUMSHADERTARGETS*2 to fit base and custom shaders for each shader target.
#define HWR_MAXSHADERS NUMSHADERTARGETS*2
// Custom shader reference table
typedef struct
......@@ -242,7 +246,7 @@ enum ETextureFlags
TF_WRAPX = 0x00000001, // wrap around X
TF_WRAPY = 0x00000002, // wrap around Y
TF_WRAPXY = TF_WRAPY|TF_WRAPX, // very common so use alias is more easy
TF_CHROMAKEYED = 0x00000010,
TF_CHROMAKEYED = 0x00000010, // Used only for flats with pixels that have palette index 255
TF_TRANSPARENT = 0x00000040, // texture with some alpha == 0
};
......@@ -272,11 +276,15 @@ struct FSurfaceInfo
RGBA_t PolyColor;
RGBA_t TintColor;
RGBA_t FadeColor;
UINT32 LightTableId;
FLightInfo LightInfo;
};
typedef struct FSurfaceInfo FSurfaceInfo;
//Hurdler: added for backward compatibility
#define GL_DEFAULTMIX 0x00000000
#define GL_DEFAULTFOG 0xFF000000
// Various settings and states for the rendering backend.
enum hwdsetspecialstate
{
HWD_SET_MODEL_LIGHTING = 1,
......@@ -289,15 +297,13 @@ enum hwdsetspecialstate
typedef enum hwdsetspecialstate hwdspecialstate_t;
// Lactozilla: Shader options
enum hwdshaderoption
enum hwdshaderstage
{
HWD_SHADEROPTION_OFF,
HWD_SHADEROPTION_ON,
HWD_SHADEROPTION_NOCUSTOM,
HWD_SHADERSTAGE_VERTEX,
HWD_SHADERSTAGE_FRAGMENT,
};
typedef enum hwdshaderoption hwdshaderoption_t;
typedef enum hwdshaderstage hwdshaderstage_t;
// Lactozilla: Shader info
// Generally set at the start of the frame.
......@@ -318,5 +324,18 @@ enum hwdfiltermode
HWD_SET_TEXTUREFILTER_MIXED3,
};
// Screen texture slots
enum hwdscreentexture
{
HWD_SCREENTEXTURE_WIPE_START, // source image for the wipe/fade effect
HWD_SCREENTEXTURE_WIPE_END, // destination image for the wipe/fade effect
HWD_SCREENTEXTURE_GENERIC1, // underwater/heat effect, intermission background
HWD_SCREENTEXTURE_GENERIC2, // palette-based colormap fade, screen before palette rendering's postprocessing
HWD_SCREENTEXTURE_GENERIC3, // screen after palette rendering's postprocessing
NUMSCREENTEXTURES, // (generic3 is unused if palette rendering is disabled)
};
typedef enum hwdscreentexture hwdscreentexture_t;
#endif //_HWR_DEFS_
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -22,7 +22,6 @@
#include "hw_drv.h"
#include "../m_misc.h" //FIL_WriteFile()
#include "../r_draw.h" //viewborderlump
#include "../r_main.h"
#include "../w_wad.h"
#include "../z_zone.h"
......@@ -30,13 +29,10 @@
#include "../st_stuff.h"
#include "../p_local.h" // stplyr
#include "../g_game.h" // players
#include "../f_finale.h" // fade color factors
#include <fcntl.h>
#include "../i_video.h" // for rendermode != render_glide
#ifndef O_BINARY
#define O_BINARY 0
#endif
#include "../i_video.h"
#if defined(_MSC_VER)
#pragma pack(1)
......@@ -62,63 +58,6 @@ static UINT8 softwaretranstogl[11] = { 0, 25, 51, 76,102,127,153,178,204,229
static UINT8 softwaretranstogl_hi[11] = { 0, 51,102,153,204,255,255,255,255,255,255};
static UINT8 softwaretranstogl_lo[11] = { 0, 12, 24, 36, 48, 60, 71, 83, 95,111,127};
//
// -----------------+
// HWR_DrawPatch : Draw a 'tile' graphic
// Notes : x,y : positions relative to the original Doom resolution
// : textes(console+score) + menus + status bar
// -----------------+
void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option)
{
FOutVector v[4];
FBITFIELD flags;
GLPatch_t *hwrPatch;
// 3--2
// | /|
// |/ |
// 0--1
float sdup = FIXED_TO_FLOAT(vid.fdup)*2.0f;
float pdup = FIXED_TO_FLOAT(vid.fdup)*2.0f;
// make patch ready in hardware cache
HWR_GetPatch(gpatch);
hwrPatch = ((GLPatch_t *)gpatch->hardware);
switch (option & V_SCALEPATCHMASK)
{
case V_NOSCALEPATCH:
pdup = 2.0f;
break;
case V_SMALLSCALEPATCH:
pdup = 2.0f * FIXED_TO_FLOAT(vid.fsmalldup);
break;
case V_MEDSCALEPATCH:
pdup = 2.0f * FIXED_TO_FLOAT(vid.fmeddup);
break;
}
if (option & V_NOSCALESTART)
sdup = 2.0f;
v[0].x = v[3].x = (x*sdup-(gpatch->leftoffset)*pdup)/vid.width - 1;
v[2].x = v[1].x = (x*sdup+(gpatch->width-gpatch->leftoffset)*pdup)/vid.width - 1;
v[0].y = v[1].y = 1-(y*sdup-(gpatch->topoffset)*pdup)/vid.height;
v[2].y = v[3].y = 1-(y*sdup+(gpatch->height-gpatch->topoffset)*pdup)/vid.height;
v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
v[0].s = v[3].s = 0.0f;
v[2].s = v[1].s = hwrPatch->max_s;
v[0].t = v[1].t = 0.0f;
v[2].t = v[3].t = hwrPatch->max_t;
flags = PF_Translucent|PF_NoDepthTest;
// clip it since it is used for bunny scroll in doom I
HWD.pfnDrawPolygon(NULL, v, 4, flags);
}
void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap)
{
FOutVector v[4];
......@@ -317,8 +256,8 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p
}
// positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1
cx = -1 + (cx / (vid.width/2));
cy = 1 - (cy / (vid.height/2));
cx = -1.0f + (cx / (vid.width / 2.0f));
cy = 1.0f - (cy / (vid.height / 2.0f));
// fwidth and fheight are similar
fwidth /= vid.width / 2;
......@@ -659,43 +598,76 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
// --------------------------------------------------------------------------
// Fills a box of pixels using a flat texture as a pattern
// Fixed to properly align like the other draw functions -luigi budd
// --------------------------------------------------------------------------
void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum)
void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum)
{
FOutVector v[4];
const size_t len = W_LumpLength(flatlumpnum);
UINT16 flatflag = R_GetFlatSize(len) - 1;
double dflatsize = (double)(flatflag + 1);
UINT16 flatflag = R_GetFlatSize(len);
double dflatsize = (double)(flatflag);
// compilers are COOL!
float dup = (float)vid.dup;
float fx = (float)x * dup;
float fy = (float)y * dup;
float fw = (float)w * dup;
float fh = (float)h * dup;
/*
fx *= dup;
fy *= dup;
fw *= dup;
fh *= dup;
*/
if (fw <= 0 || fh <= 0)
return;
if (fabsf((float)vid.width - (float)BASEVIDWIDTH * vid.dup) > 1.0E-36f)
{
fx += ((float)vid.width - ((float)BASEVIDWIDTH * vid.dup)) / 2;
}
if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * vid.dup) > 1.0E-36f)
{
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * vid.dup)) / 2;
}
if (fx >= vid.width || fy >= vid.height)
return;
fx = -1.0f + (fx / (vid.width / 2.0f));
fy = 1.0f - (fy / (vid.height / 2.0f));
fw /= vid.width / 2;
fh /= vid.height / 2;
// 3--2
// | /|
// |/ |
// 0--1
// position vertices
v[0].x = v[3].x = fx;
v[2].x = v[1].x = fx + fw;
v[0].x = v[3].x = (x - 160.0f)/160.0f;
v[2].x = v[1].x = ((x+w) - 160.0f)/160.0f;
v[0].y = v[1].y = -(y - 100.0f)/100.0f;
v[2].y = v[3].y = -((y+h) - 100.0f)/100.0f;
v[0].y = v[1].y = fy;
v[2].y = v[3].y = fy - fh;
v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
v[0].s = v[3].s = (float)((x & flatflag)/dflatsize);
v[2].s = v[1].s = (float)(v[0].s + w/dflatsize);
v[0].t = v[1].t = (float)((y & flatflag)/dflatsize);
v[2].t = v[3].t = (float)(v[0].t + h/dflatsize);
// sides
v[0].s = v[3].s = (float)(flatflag/dflatsize) * 2;
v[2].s = v[1].s = (float)(v[0].s + w/dflatsize) * 2;
HWR_GetRawFlat(flatlumpnum);
// top/bottom
v[0].t = v[1].t = (float)(flatflag/dflatsize) * 2;
v[2].t = v[3].t = (float)(v[0].t + h/dflatsize) * 2;
//Hurdler: Boris, the same comment as above... but maybe for pics
// it not a problem since they don't have any transparent pixel
// if I'm right !?
// BTW, I see we put 0 for PFs, and If I'm right, that
// means we take the previous PFs as default
// how can we be sure they are ok?
// needed to texture the poly
HWR_GetRawFlat(flatlumpnum);
HWD.pfnDrawPolygon(NULL, v, 4, PF_NoDepthTest); //PF_Translucent);
}
// --------------------------------------------------------------------------
// Fade down the screen so that the menu drawn on top of it looks brighter
// --------------------------------------------------------------------------
......@@ -707,6 +679,7 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength)
{
FOutVector v[4];
FSurfaceInfo Surf;
FBITFIELD poly_flags = PF_NoTexture|PF_Modulated|PF_NoDepthTest;
v[0].x = v[3].x = -1.0f;
v[2].x = v[1].x = 1.0f;
......@@ -719,17 +692,59 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength)
v[0].t = v[1].t = 1.0f;
v[2].t = v[3].t = 0.0f;
if (color & 0xFF00) // Do COLORMAP fade.
if (color & 0xFF00) // Special fade options
{
Surf.PolyColor.rgba = UINT2RGBA(0x01010160);
Surf.PolyColor.s.alpha = (strength*8);
UINT16 option = color & 0x0F00;
if (option == 0x0A00 || option == 0x0B00) // Tinted fades
{
INT32 r, g, b;
int fade = strength * 8;
r = FADEREDFACTOR*fade/10;
g = FADEGREENFACTOR*fade/10;
b = FADEBLUEFACTOR*fade/10;
Surf.PolyColor.s.red = min(r, 255);
Surf.PolyColor.s.green = min(g, 255);
Surf.PolyColor.s.blue = min(b, 255);
Surf.PolyColor.s.alpha = 255;
if (option == 0x0A00) // Tinted subtractive fade
poly_flags |= PF_ReverseSubtract;
else if (option == 0x0B00) // Tinted additive fade
poly_flags |= PF_Additive;
}
else // COLORMAP fade
{
if (HWR_ShouldUsePaletteRendering())
{
const hwdscreentexture_t scr_tex = HWD_SCREENTEXTURE_GENERIC2;
Surf.LightTableId = HWR_GetLightTableID(NULL);
Surf.LightInfo.light_level = strength;
HWD.pfnMakeScreenTexture(scr_tex);
HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_UI_COLORMAP_FADE));
HWD.pfnDrawScreenTexture(scr_tex, &Surf, PF_ColorMapped|PF_NoDepthTest);
HWD.pfnUnSetShader();
return;
}
else
{
Surf.PolyColor.rgba = UINT2RGBA(0x01010160);
Surf.PolyColor.s.alpha = (strength*8);
poly_flags |= PF_Translucent;
}
}
}
else // Do TRANSMAP** fade.
{
Surf.PolyColor.rgba = V_GetColor(color).rgba;
RGBA_t *palette = HWR_GetTexturePalette();
Surf.PolyColor.rgba = palette[color&0xFF].rgba;
Surf.PolyColor.s.alpha = softwaretranstogl[strength];
poly_flags |= PF_Translucent;
}
HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
HWD.pfnDrawPolygon(&Surf, v, 4, poly_flags);
}
// -----------------+
......@@ -897,7 +912,8 @@ void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 ac
}
else // Do TRANSMAP** fade.
{
Surf.PolyColor.rgba = V_GetColor(actualcolor).rgba;
RGBA_t *palette = HWR_GetTexturePalette();
Surf.PolyColor.rgba = palette[actualcolor&0xFF].rgba;
Surf.PolyColor.s.alpha = softwaretranstogl[strength];
}
HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
......@@ -960,136 +976,6 @@ void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight)
HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
}
// ==========================================================================
// R_DRAW.C STUFF
// ==========================================================================
// ------------------
// HWR_DrawViewBorder
// Fill the space around the view window with a Doom flat texture, draw the
// beveled edges.
// 'clearlines' is useful to clear the heads up messages, when the view
// window is reduced, it doesn't refresh all the view borders.
// ------------------
void HWR_DrawViewBorder(INT32 clearlines)
{
INT32 x, y;
INT32 top, side;
INT32 baseviewwidth, baseviewheight;
INT32 basewindowx, basewindowy;
patch_t *patch;
// if (gl_viewwidth == vid.width)
// return;
if (!clearlines)
clearlines = BASEVIDHEIGHT; // refresh all
// calc view size based on original game resolution
baseviewwidth = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewwidth), vid.fdup)); //(cv_viewsize.value * BASEVIDWIDTH/10)&~7;
baseviewheight = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewheight), vid.fdup));
top = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_baseviewwindowy), vid.fdup));
side = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewwindowx), vid.fdup));
// top
HWR_DrawFlatFill(0, 0,
BASEVIDWIDTH, (top < clearlines ? top : clearlines),
st_borderpatchnum);
// left
if (top < clearlines)
HWR_DrawFlatFill(0, top, side,
(clearlines-top < baseviewheight ? clearlines-top : baseviewheight),
st_borderpatchnum);
// right
if (top < clearlines)
HWR_DrawFlatFill(side + baseviewwidth, top, side,
(clearlines-top < baseviewheight ? clearlines-top : baseviewheight),
st_borderpatchnum);
// bottom
if (top + baseviewheight < clearlines)
HWR_DrawFlatFill(0, top + baseviewheight,
BASEVIDWIDTH, BASEVIDHEIGHT, st_borderpatchnum);
//
// draw the view borders
//
basewindowx = (BASEVIDWIDTH - baseviewwidth)>>1;
if (baseviewwidth == BASEVIDWIDTH)
basewindowy = 0;
else
basewindowy = top;
// top edge
if (clearlines > basewindowy - 8)
{
patch = W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH);
for (x = 0; x < baseviewwidth; x += 8)
HWR_DrawPatch(patch, basewindowx + x, basewindowy - 8,
0);
}
// bottom edge
if (clearlines > basewindowy + baseviewheight)
{
patch = W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH);
for (x = 0; x < baseviewwidth; x += 8)
HWR_DrawPatch(patch, basewindowx + x,
basewindowy + baseviewheight, 0);
}
// left edge
if (clearlines > basewindowy)
{
patch = W_CachePatchNum(viewborderlump[BRDR_L], PU_PATCH);
for (y = 0; y < baseviewheight && basewindowy + y < clearlines;
y += 8)
{
HWR_DrawPatch(patch, basewindowx - 8, basewindowy + y,
0);
}
}
// right edge
if (clearlines > basewindowy)
{
patch = W_CachePatchNum(viewborderlump[BRDR_R], PU_PATCH);
for (y = 0; y < baseviewheight && basewindowy+y < clearlines;
y += 8)
{
HWR_DrawPatch(patch, basewindowx + baseviewwidth,
basewindowy + y, 0);
}
}
// Draw beveled corners.
if (clearlines > basewindowy - 8)
HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TL],
PU_PATCH),
basewindowx - 8, basewindowy - 8, 0);
if (clearlines > basewindowy - 8)
HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TR],
PU_PATCH),
basewindowx + baseviewwidth, basewindowy - 8, 0);
if (clearlines > basewindowy+baseviewheight)
HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BL],
PU_PATCH),
basewindowx - 8, basewindowy + baseviewheight, 0);
if (clearlines > basewindowy + baseviewheight)
HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BR],
PU_PATCH),
basewindowx + baseviewwidth,
basewindowy + baseviewheight, 0);
}
// ==========================================================================
// AM_MAP.C DRAWING STUFF
// ==========================================================================
......@@ -1102,8 +988,9 @@ void HWR_drawAMline(const fline_t *fl, INT32 color)
{
F2DCoord v1, v2;
RGBA_t color_rgba;
RGBA_t *palette = HWR_GetTexturePalette();
color_rgba = V_GetColor(color);
color_rgba = palette[color&0xFF];
v1.x = ((float)fl->a.x-(vid.width/2.0f))*(2.0f/vid.width);
v1.y = ((float)fl->a.y-(vid.height/2.0f))*(2.0f/vid.height);
......@@ -1288,6 +1175,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
FOutVector v[4];
FSurfaceInfo Surf;
float fx, fy, fw, fh;
RGBA_t *palette = HWR_GetTexturePalette();
UINT8 alphalevel = ((color & V_ALPHAMASK) >> V_ALPHASHIFT);
UINT8 perplayershuffle = 0;
......@@ -1374,7 +1262,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
{
if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
{
RGBA_t rgbaColour = V_GetColor(color);
RGBA_t rgbaColour = palette[color&0xFF];
FRGBAFloat clearColour;
clearColour.red = (float)rgbaColour.s.red / 255;
clearColour.green = (float)rgbaColour.s.green / 255;
......@@ -1451,7 +1339,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
v[0].t = v[1].t = 0.0f;
v[2].t = v[3].t = 1.0f;
Surf.PolyColor = V_GetColor(color);
Surf.PolyColor = palette[color&0xFF];
if (alphalevel)
{
......@@ -1499,7 +1387,7 @@ static inline boolean saveTGA(const char *file_name, void *buffer,
INT32 i;
UINT8 *buf8 = buffer;
fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
return false;
......@@ -1539,11 +1427,12 @@ static inline boolean saveTGA(const char *file_name, void *buffer,
UINT8 *HWR_GetScreenshot(void)
{
UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf));
int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2;
if (!buf)
return NULL;
// returns 24bit 888 RGB
HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf);
HWD.pfnReadScreenTexture(tex, (void *)buf);
return buf;
}
......@@ -1551,6 +1440,7 @@ boolean HWR_Screenshot(const char *pathname)
{
boolean ret;
UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf));
int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2;
if (!buf)
{
......@@ -1559,7 +1449,7 @@ boolean HWR_Screenshot(const char *pathname)
}
// returns 24bit 888 RGB
HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf);
HWD.pfnReadScreenTexture(tex, (void *)buf);
#ifdef USE_PNG
ret = M_SavePNG(pathname, buf, vid.width, vid.height, NULL);
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -29,10 +29,7 @@ EXPORT boolean HWRAPI(Init) (void);
#ifndef HAVE_SDL
EXPORT void HWRAPI(Shutdown) (void);
#endif
#ifdef _WINDOWS
EXPORT void HWRAPI(GetModeList) (vmode_t **pvidmodes, INT32 *numvidmodes);
#endif
EXPORT void HWRAPI(SetPalette) (RGBA_t *ppal);
EXPORT void HWRAPI(SetTexturePalette) (RGBA_t *ppal);
EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl);
EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color);
EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags);
......@@ -43,11 +40,10 @@ EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFl
EXPORT void HWRAPI(SetTexture) (GLMipmap_t *TexInfo);
EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *TexInfo);
EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *TexInfo);
EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data);
EXPORT void HWRAPI(ReadScreenTexture) (int tex, UINT8 *dst_data);
EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip);
EXPORT void HWRAPI(ClearMipMapCache) (void);
//Hurdler: added for backward compatibility
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value);
//Hurdler: added for new development
......@@ -57,24 +53,27 @@ EXPORT void HWRAPI(SetTransform) (FTransform *ptransform);
EXPORT INT32 HWRAPI(GetTextureUsed) (void);
EXPORT void HWRAPI(FlushScreenTextures) (void);
EXPORT void HWRAPI(StartScreenWipe) (void);
EXPORT void HWRAPI(EndScreenWipe) (void);
EXPORT void HWRAPI(DoScreenWipe) (void);
EXPORT void HWRAPI(DrawIntermissionBG) (void);
EXPORT void HWRAPI(MakeScreenTexture) (void);
EXPORT void HWRAPI(MakeScreenFinalTexture) (void);
EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height);
EXPORT void HWRAPI(DoScreenWipe) (int wipeStart, int wipeEnd, FSurfaceInfo *surf, FBITFIELD polyFlags);
EXPORT void HWRAPI(DrawScreenTexture) (int tex, FSurfaceInfo *surf, FBITFIELD polyflags);
EXPORT void HWRAPI(MakeScreenTexture) (int tex);
EXPORT void HWRAPI(DrawScreenFinalTexture) (int tex, int width, int height);
#define SCREENVERTS 10
EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]);
EXPORT boolean HWRAPI(CompileShaders) (void);
EXPORT void HWRAPI(CleanShaders) (void);
EXPORT void HWRAPI(SetShader) (int type);
EXPORT boolean HWRAPI(InitShaders) (void);
EXPORT void HWRAPI(LoadShader) (int slot, char *code, hwdshaderstage_t stage);
EXPORT boolean HWRAPI(CompileShader) (int slot);
EXPORT void HWRAPI(SetShader) (int slot);
EXPORT void HWRAPI(UnSetShader) (void);
EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value);
EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boolean isfragment);
EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut);
EXPORT UINT32 HWRAPI(CreateLightTable)(RGBA_t *hw_lighttable);
EXPORT void HWRAPI(UpdateLightTable)(UINT32 id, RGBA_t *hw_lighttable);
EXPORT void HWRAPI(ClearLightTables)(void);
EXPORT void HWRAPI(SetScreenPalette)(RGBA_t *palette);
// ==========================================================================
// HWR DRIVER OBJECT, FOR CLIENT PROGRAM
......@@ -85,7 +84,7 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boole
struct hwdriver_s
{
Init pfnInit;
SetPalette pfnSetPalette;
SetTexturePalette pfnSetTexturePalette;
FinishUpdate pfnFinishUpdate;
Draw2DLine pfnDraw2DLine;
DrawPolygon pfnDrawPolygon;
......@@ -96,10 +95,10 @@ struct hwdriver_s
SetTexture pfnSetTexture;
UpdateTexture pfnUpdateTexture;
DeleteTexture pfnDeleteTexture;
ReadRect pfnReadRect;
ReadScreenTexture pfnReadScreenTexture;
GClipRect pfnGClipRect;
ClearMipMapCache pfnClearMipMapCache;
SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility
SetSpecialState pfnSetSpecialState;
DrawModel pfnDrawModel;
CreateModelVBOs pfnCreateModelVBOs;
SetTransform pfnSetTransform;
......@@ -112,21 +111,24 @@ struct hwdriver_s
#endif
PostImgRedraw pfnPostImgRedraw;
FlushScreenTextures pfnFlushScreenTextures;
StartScreenWipe pfnStartScreenWipe;
EndScreenWipe pfnEndScreenWipe;
DoScreenWipe pfnDoScreenWipe;
DrawIntermissionBG pfnDrawIntermissionBG;
DrawScreenTexture pfnDrawScreenTexture;
MakeScreenTexture pfnMakeScreenTexture;
MakeScreenFinalTexture pfnMakeScreenFinalTexture;
DrawScreenFinalTexture pfnDrawScreenFinalTexture;
CompileShaders pfnCompileShaders;
CleanShaders pfnCleanShaders;
InitShaders pfnInitShaders;
LoadShader pfnLoadShader;
CompileShader pfnCompileShader;
SetShader pfnSetShader;
UnSetShader pfnUnSetShader;
SetShaderInfo pfnSetShaderInfo;
LoadCustomShader pfnLoadCustomShader;
SetPaletteLookup pfnSetPaletteLookup;
CreateLightTable pfnCreateLightTable;
UpdateLightTable pfnUpdateLightTable;
ClearLightTables pfnClearLightTables;
SetScreenPalette pfnSetScreenPalette;
};
extern struct hwdriver_s hwdriver;
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -107,6 +107,8 @@ void HWR_FreeExtraSubsectors(void);
// --------
// hw_cache.c
// --------
RGBA_t *HWR_GetTexturePalette(void);
void HWR_InitMapTextures(void);
void HWR_LoadMapTextures(size_t pnumtextures);
void HWR_FreeMapTextures(void);
......@@ -117,10 +119,9 @@ patch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum);
void HWR_GetPatch(patch_t *patch);
void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap);
void HWR_GetFadeMask(lumpnum_t fademasklumpnum);
patch_t *HWR_GetPic(lumpnum_t lumpnum);
GLMapTexture_t *HWR_GetTexture(INT32 tex);
void HWR_GetLevelFlat(levelflat_t *levelflat);
GLMapTexture_t *HWR_GetTexture(INT32 tex, boolean chromakeyed);
void HWR_GetLevelFlat(levelflat_t *levelflat, boolean chromakeyed);
void HWR_GetRawFlat(lumpnum_t flatlumpnum);
void HWR_FreeTexture(patch_t *patch);
......@@ -131,6 +132,11 @@ void HWR_FreeColormapCache(void);
void HWR_UnlockCachedPatch(GLPatch_t *gpatch);
void HWR_SetPalette(RGBA_t *palette);
void HWR_SetMapPalette(void);
UINT32 HWR_CreateLightTable(UINT8 *lighttable, RGBA_t *hw_lighttable);
void HWR_UpdateLightTable(UINT32 id, UINT8 *lighttable, RGBA_t *hw_lighttable);
UINT32 HWR_GetLightTableID(extracolormap_t *colormap);
void HWR_ClearLightTables(void);
// --------
......@@ -139,4 +145,18 @@ void HWR_SetPalette(RGBA_t *palette);
extern INT32 patchformat;
extern INT32 textureformat;
// --------
// hw_shaders.c
// --------
boolean HWR_InitShaders(void);
void HWR_CompileShaders(void);
int HWR_GetShaderFromTarget(int shader_target);
void HWR_LoadAllCustomShaders(void);
void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3);
const char *HWR_GetShaderName(INT32 shader);
extern customshaderxlat_t shaderxlat[];
#endif //_HW_GLOB_
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -395,6 +395,8 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_XMS4
&lspr[NOLIGHT], // SPR_XMS5
&lspr[NOLIGHT], // SPR_XMS6
&lspr[NOLIGHT], // SPR_SNTT
&lspr[NOLIGHT], // SPR_SSTT
&lspr[NOLIGHT], // SPR_FHZI
&lspr[NOLIGHT], // SPR_ROSY
......@@ -428,6 +430,8 @@ light_t *t_lspr[NUMSPRITES] =
// Misc Scenery
&lspr[NOLIGHT], // SPR_STLG
&lspr[NOLIGHT], // SPR_DBAL
&lspr[NOLIGHT], // SPR_GINE
&lspr[NOLIGHT], // SPR_PPAL
// Powerup Indicators
&lspr[NOLIGHT], // SPR_ARMA
......@@ -614,6 +618,9 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_GWLG
&lspr[NOLIGHT], // SPR_GWLR
// LJ Knuckles
&lspr[NOLIGHT], // SPR_OLDK,
// Free slots
&lspr[NOLIGHT],
&lspr[NOLIGHT],
......@@ -1055,7 +1062,7 @@ void HWR_DoCoronasLighting(FOutVector *outVerts, gl_vissprite_t *spr)
light[3].y = cy+size*1.33f+p_lspr->light_yoffset;
light[3].s = 0.0f; light[3].t = 1.0f;
HWR_GetPic(coronalumpnum); /// \todo use different coronas
// HWR_GetPic(coronalumpnum); /// \todo use different coronas
HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_Corona | PF_NoDepthTest);
}
......@@ -1071,7 +1078,7 @@ void HWR_DrawCoronas(void)
if (!cv_glcoronas.value || dynlights->nb <= 0 || coronalumpnum == LUMPERROR)
return;
HWR_GetPic(coronalumpnum); /// \todo use different coronas
// HWR_GetPic(coronalumpnum); /// \todo use different coronas
for (j = 0;j < dynlights->nb;j++)
{
FOutVector light[4];
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -19,8 +19,10 @@
#include "hw_light.h"
#include "hw_drv.h"
#include "hw_batching.h"
#include "hw_md2.h"
#include "hw_clip.h"
#include "../i_video.h" // for rendermode == render_glide
#include "../i_video.h"
#include "../v_video.h"
#include "../p_local.h"
#include "../p_setup.h"
......@@ -42,15 +44,6 @@
#include "../r_translation.h"
#include "../d_main.h"
#include "../p_slopes.h"
#include "hw_md2.h"
#ifdef NEWCLIP
#include "hw_clip.h"
#endif
#define R_FAKEFLOORS
#define HWPRECIP
//#define POLYSKY
// ==========================================================================
// the hardware driver object
......@@ -61,95 +54,27 @@ struct hwdriver_s hwdriver;
// PROTOS
// ==========================================================================
static void HWR_AddSprites(sector_t *sec);
static void HWR_ProjectSprite(mobj_t *thing);
#ifdef HWPRECIP
static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing);
#endif
static void HWR_ProjectBoundingBox(mobj_t *thing);
void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap);
void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, boolean chromakeyed, extracolormap_t *planecolormap);
void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap);
boolean drawsky = true;
// ==========================================================================
// VIEW GLOBALS
// ==========================================================================
// Fineangles in the SCREENWIDTH wide window.
#define FIELDOFVIEW ANGLE_90
#define ABS(x) ((x) < 0 ? -(x) : (x))
static angle_t gl_clipangle;
// The viewangletox[viewangle + FINEANGLES/4] lookup
// maps the visible view angles to screen X coordinates,
// flattening the arc to a flat projection plane.
// There will be many angles mapped to the same X.
static INT32 gl_viewangletox[FINEANGLES/2];
// The xtoviewangleangle[] table maps a screen pixel
// to the lowest viewangle that maps back to x ranges
// from clipangle to -clipangle.
static angle_t gl_xtoviewangle[MAXVIDWIDTH+1];
static boolean drawsky = true;
// ==========================================================================
// GLOBALS
// ==========================================================================
// uncomment to remove the plane rendering
#define DOPLANES
//#define DOWALLS
// test of drawing sky by polygons like in software with visplane, unfortunately
// this doesn't work since we must have z for pixel and z for texture (not like now with z = oow)
//#define POLYSKY
// test change fov when looking up/down but bsp projection messup :(
//#define NOCRAPPYMLOOK
// base values set at SetViewSize
static float gl_basecentery;
float gl_baseviewwindowy, gl_basewindowcentery;
float gl_viewwidth, gl_viewheight; // viewport clipping boundaries (screen coords)
float gl_viewwindowx;
static float gl_centerx, gl_centery;
static float gl_viewwindowy; // top left corner of view window
static float gl_windowcenterx; // center of view window, for projection
static float gl_windowcentery;
static float gl_pspritexscale, gl_pspriteyscale;
static seg_t *gl_curline;
static side_t *gl_sidedef;
static line_t *gl_linedef;
static sector_t *gl_frontsector;
static sector_t *gl_backsector;
// --------------------------------------------------------------------------
// STUFF FOR THE PROJECTION CODE
// --------------------------------------------------------------------------
FTransform atransform;
// duplicates of the main code, set after R_SetupFrame() passed them into sharedstruct,
// copied here for local use
static fixed_t dup_viewx, dup_viewy, dup_viewz;
static angle_t dup_viewangle;
static float gl_viewx, gl_viewy, gl_viewz;
float gl_viewsin, gl_viewcos;
// Maybe not necessary with the new T&L code (needs to be checked!)
static float gl_viewludsin, gl_viewludcos; // look up down kik test
static float gl_fovlud;
static angle_t gl_aimingangle;
static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox);
// Render stats
ps_metric_t ps_hw_skyboxtime = {0};
ps_metric_t ps_hw_nodesorttime = {0};
......@@ -170,13 +95,35 @@ ps_metric_t ps_hw_batchdrawtime = {0};
boolean gl_init = false;
boolean gl_maploaded = false;
boolean gl_shadersavailable = true;
boolean gl_sessioncommandsadded = false;
// false if shaders have not been initialized yet, or if shaders are not available
boolean gl_shadersavailable = false;
// Whether the internal state is set to palette rendering or not.
static boolean gl_palette_rendering_state = false;
// --------------------------------------------------------------------------
// STUFF FOR THE PROJECTION CODE
// --------------------------------------------------------------------------
FTransform atransform;
static float gl_viewx, gl_viewy, gl_viewz;
float gl_viewsin, gl_viewcos;
// For HWR_RotateSpritePolyToAim
static float gl_viewludsin, gl_viewludcos;
static float gl_fovlud;
static angle_t gl_aimingangle;
static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox);
// ==========================================================================
// Lighting
// ==========================================================================
static boolean HWR_UseShader(void)
// Returns true if shaders can be used.
boolean HWR_UseShader(void)
{
return (cv_glshaders.value && gl_shadersavailable);
}
......@@ -242,6 +189,11 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col
Surface->LightInfo.light_level = light_level;
Surface->LightInfo.fade_start = (colormap != NULL) ? colormap->fadestart : 0;
Surface->LightInfo.fade_end = (colormap != NULL) ? colormap->fadeend : 31;
if (HWR_ShouldUsePaletteRendering())
Surface->LightTableId = HWR_GetLightTableID(colormap);
else
Surface->LightTableId = 0;
}
UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work
......@@ -357,12 +309,47 @@ static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta)
return (FUINT)finallight;
}
static UINT8 HWR_SideLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light +
((side->lightabsolute) ? 0 : base_lightlevel)));
}
/* TODO: implement per-texture lighting
static UINT8 HWR_TopLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light_top +
((side->lightabsolute_top) ? 0 : HWR_SideLightLevel(side, base_lightlevel))));
}
static UINT8 HWR_MidLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light_mid +
((side->lightabsolute_mid) ? 0 : HWR_SideLightLevel(side, base_lightlevel))));
}
static UINT8 HWR_BottomLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light_bottom +
((side->lightabsolute_bottom) ? 0 : HWR_SideLightLevel(side, base_lightlevel))));
}
*/
static UINT8 HWR_FloorLightLevel(sector_t *sector, INT16 base_lightlevel)
{
return max(0, min(255, sector->floorlightlevel +
((sector->floorlightabsolute) ? 0 : base_lightlevel)));
}
static UINT8 HWR_CeilingLightLevel(sector_t *sector, INT16 base_lightlevel)
{
return max(0, min(255, sector->ceilinglightlevel +
((sector->ceilinglightabsolute) ? 0 : base_lightlevel)));
}
// ==========================================================================
// FLOOR/CEILING GENERATION FROM SUBSECTORS
// ==========================================================================
#ifdef DOPLANES
// -----------------+
// HWR_RenderPlane : Render a floor or ceiling convex polygon
// -----------------+
......@@ -372,7 +359,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
FOutVector *v3d;
polyvertex_t *pv;
pslope_t *slope = NULL;
INT32 shader = SHADER_DEFAULT;
INT32 shader = SHADER_NONE;
size_t nrPlaneVerts;
INT32 i;
......@@ -389,6 +376,9 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
static FOutVector *planeVerts = NULL;
static UINT16 numAllocedPlaneVerts = 0;
if (!r_renderfloors)
return;
// no convex poly were generated for this subsector
if (!xsub->planepoly)
return;
......@@ -551,7 +541,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
for (i = 0; i < subsector->numlines; i++, line++)
{
if (!line->glseg && line->linedef->special == SPECIAL_HORIZON_LINE && R_PointOnSegSide(dup_viewx, dup_viewy, line) == 0)
if (!line->glseg && line->linedef->special == SPECIAL_HORIZON_LINE && R_PointOnSegSide(viewx, viewy, line) == 0)
{
P_ClosestPointOnLine(viewx, viewy, line->linedef, &v);
dist = FIXED_TO_FLOAT(R_PointToDist(v.x, v.y));
......@@ -630,52 +620,6 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
#endif
}
#ifdef POLYSKY
// this don't draw anything it only update the z-buffer so there isn't problem with
// wall/things upper that sky (map12)
static void HWR_RenderSkyPlane(extrasubsector_t *xsub, fixed_t fixedheight)
{
polyvertex_t *pv;
float height; //constant y for all points on the convex flat polygon
FOutVector *v3d;
INT32 nrPlaneVerts; //verts original define of convex flat polygon
INT32 i;
// no convex poly were generated for this subsector
if (!xsub->planepoly)
return;
height = FIXED_TO_FLOAT(fixedheight);
pv = xsub->planepoly->pts;
nrPlaneVerts = xsub->planepoly->numpts;
if (nrPlaneVerts < 3) // not even a triangle?
return;
if (nrPlaneVerts > MAXPLANEVERTICES) // FIXME: exceeds plVerts size
{
CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, MAXPLANEVERTICES);
return;
}
// transform
v3d = planeVerts;
for (i = 0; i < nrPlaneVerts; i++,v3d++,pv++)
{
v3d->s = 0.0f;
v3d->t = 0.0f;
v3d->x = pv->x;
v3d->y = height;
v3d->z = pv->y;
}
HWD.pfnDrawPolygon(NULL, planeVerts, nrPlaneVerts, PF_Invisible|PF_NoTexture|PF_Occlude);
}
#endif //polysky
#endif //doplanes
FBITFIELD HWR_GetBlendModeFlag(INT32 style)
{
switch (style)
......@@ -759,7 +703,10 @@ static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, I
//
static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap)
{
INT32 shader = SHADER_DEFAULT;
INT32 shader = SHADER_NONE;
if (!r_renderwalls)
return;
HWR_Lighting(pSurf, lightlevel, wallcolormap);
......@@ -776,41 +723,6 @@ static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIEL
// BSP, CULL, ETC..
// ==========================================================================
// return the frac from the interception of the clipping line
// (in fact a clipping plane that has a constant, so can clip with simple 2d)
// with the wall segment
//
#ifndef NEWCLIP
static float HWR_ClipViewSegment(INT32 x, polyvertex_t *v1, polyvertex_t *v2)
{
float num, den;
float v1x, v1y, v1dx, v1dy, v2dx, v2dy;
angle_t pclipangle = gl_xtoviewangle[x];
// a segment of a polygon
v1x = v1->x;
v1y = v1->y;
v1dx = (v2->x - v1->x);
v1dy = (v2->y - v1->y);
// the clipping line
pclipangle = pclipangle + dup_viewangle; //back to normal angle (non-relative)
v2dx = FIXED_TO_FLOAT(FINECOSINE(pclipangle>>ANGLETOFINESHIFT));
v2dy = FIXED_TO_FLOAT(FINESINE(pclipangle>>ANGLETOFINESHIFT));
den = v2dy*v1dx - v2dx*v1dy;
if (den == 0)
return -1; // parallel
// calc the frac along the polygon segment,
//num = (v2x - v1x)*v2dy + (v1y - v2y)*v2dx;
//num = -v1x * v2dy + v1y * v2dx;
num = (gl_viewx - v1x)*v2dy + (v1y - gl_viewy)*v2dx;
return num / den;
}
#endif
// SoM: split up and light walls according to the lightlist.
// This may also include leaving out parts of the wall that can't be seen
static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor, FBITFIELD polyflags)
......@@ -830,10 +742,14 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum,
fixed_t v2x = FloatToFixed(wallVerts[1].x);
fixed_t v2y = FloatToFixed(wallVerts[1].z);
FUINT lightnum = HWR_SideLightLevel(gl_sidedef, sector->lightlevel);
const UINT8 alpha = Surf->PolyColor.s.alpha;
FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y);
lightnum = HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y);
extracolormap_t *colormap = NULL;
if (!r_renderwalls)
return;
realtop = top = wallVerts[3].y;
realbot = bot = wallVerts[0].y;
diff = top - bot;
......@@ -872,13 +788,15 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum,
{
if (pfloor && (pfloor->fofflags & FOF_FOG))
{
lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y);
lightnum = HWR_SideLightLevel(gl_sidedef, pfloor->master->frontsector->lightlevel);
colormap = pfloor->master->frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y);
}
else
{
lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y);
lightnum = HWR_SideLightLevel(gl_sidedef, *list[i].lightlevel);
colormap = *list[i].extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y);
}
}
......@@ -998,7 +916,7 @@ static void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf)
// PF_Occlude is set in HWR_ProjectWall to draw into the depth buffer
}
// Returns true if the midtexture is visible, and false if... it isn't...
// Returns true if the midtexture is visible, false if not
static boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf)
{
FUINT blendmode = PF_Masked;
......@@ -1034,14 +952,204 @@ static boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf)
return true;
}
//
// HWR_ProcessSeg
// A portion or all of a wall segment will be drawn, from startfrac to endfrac,
// where 0 is the start of the segment, 1 the end of the segment
// Anything between means the wall segment has been clipped with solidsegs,
// reducing wall overdraw to a minimum
//
static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
static void HWR_RenderMidtexture(INT32 gl_midtexture, float cliplow, float cliphigh, fixed_t worldtop, fixed_t worldbottom, fixed_t worldhigh, fixed_t worldlow, fixed_t worldtopslope, fixed_t worldbottomslope, fixed_t worldhighslope, fixed_t worldlowslope, UINT32 lightnum, FOutVector *inWallVerts)
{
sector_t *front, *back;
FOutVector wallVerts[4];
FSurfaceInfo Surf;
Surf.PolyColor.s.alpha = 255;
// Determine if it's visible
if (!HWR_BlendMidtextureSurface(&Surf))
return;
if (gl_linedef->frontsector->heightsec != -1)
front = &sectors[gl_linedef->frontsector->heightsec];
else
front = gl_linedef->frontsector;
if (gl_linedef->backsector->heightsec != -1)
back = &sectors[gl_linedef->backsector->heightsec];
else
back = gl_linedef->backsector;
fixed_t texheight = FixedDiv(textureheight[gl_midtexture], abs(gl_sidedef->scaley_mid));
INT32 repeats;
if (gl_sidedef->repeatcnt)
repeats = 1 + gl_sidedef->repeatcnt;
else if (gl_linedef->flags & ML_WRAPMIDTEX)
{
fixed_t high, low;
if (front->ceilingheight > back->ceilingheight)
high = back->ceilingheight;
else
high = front->ceilingheight;
if (front->floorheight > back->floorheight)
low = front->floorheight;
else
low = back->floorheight;
repeats = (high - low) / texheight;
if ((high - low) % texheight)
repeats++; // tile an extra time to fill the gap -- Monster Iestyn
}
else
repeats = 1;
GLMapTexture_t *grTex = HWR_GetTexture(gl_midtexture, true);
float xscale = FixedToFloat(gl_sidedef->scalex_mid);
float yscale = FixedToFloat(gl_sidedef->scaley_mid);
// SoM: a little note: popentop and popenbottom
// record the limits the texture can be displayed in.
// polytop and polybottom, are the ideal (i.e. unclipped)
// heights of the polygon, and h & l, are the final (clipped)
// poly coords.
fixed_t popentop, popenbottom, polytop, polybottom, lowcut, highcut;
fixed_t popentopslope, popenbottomslope, polytopslope, polybottomslope, lowcutslope, highcutslope;
// NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to,
// you must use the linedef's backsector to be correct
// From CB
if (gl_curline->polyseg)
{
// Change this when polyobjects support slopes
popentop = popentopslope = back->ceilingheight;
popenbottom = popenbottomslope = back->floorheight;
}
else
{
popentop = min(worldtop, worldhigh);
popenbottom = max(worldbottom, worldlow);
popentopslope = min(worldtopslope, worldhighslope);
popenbottomslope = max(worldbottomslope, worldlowslope);
}
// Find the wall's coordinates
fixed_t midtexheight = texheight * repeats;
fixed_t rowoffset = FixedDiv(gl_sidedef->rowoffset + gl_sidedef->offsety_mid, abs(gl_sidedef->scaley_mid));
// Texture is not skewed
if (gl_linedef->flags & ML_NOSKEW)
{
// Peg it to the floor
if (gl_linedef->flags & ML_MIDPEG)
{
polybottom = max(gl_frontsector->floorheight, gl_backsector->floorheight) + rowoffset;
polytop = polybottom + midtexheight;
}
// Peg it to the ceiling
else
{
polytop = min(gl_frontsector->ceilingheight, gl_backsector->ceilingheight) + rowoffset;
polybottom = polytop - midtexheight;
}
// The right side's coordinates are the the same as the left side
polytopslope = polytop;
polybottomslope = polybottom;
}
// Skew the texture, but peg it to the floor
else if (gl_linedef->flags & ML_MIDPEG)
{
polybottom = popenbottom + rowoffset;
polytop = polybottom + midtexheight;
polybottomslope = popenbottomslope + rowoffset;
polytopslope = polybottomslope + midtexheight;
}
// Skew it according to the ceiling's slope
else
{
polytop = popentop + rowoffset;
polybottom = polytop - midtexheight;
polytopslope = popentopslope + rowoffset;
polybottomslope = polytopslope - midtexheight;
}
// The cut-off values of a linedef can always be constant, since every line has an absoulute front and or back sector
if (gl_curline->polyseg)
{
lowcut = polybottom;
highcut = polytop;
lowcutslope = polybottomslope;
highcutslope = polytopslope;
}
else
{
lowcut = popenbottom;
highcut = popentop;
lowcutslope = popenbottomslope;
highcutslope = popentopslope;
}
fixed_t h = min(highcut, polytop);
fixed_t l = max(polybottom, lowcut);
fixed_t hS = min(highcutslope, polytopslope);
fixed_t lS = max(polybottomslope, lowcutslope);
// PEGGING
fixed_t texturevpeg, texturevpegslope;
if (gl_linedef->flags & ML_MIDPEG)
{
texturevpeg = midtexheight - h + polybottom;
texturevpegslope = midtexheight - hS + polybottomslope;
}
else
{
texturevpeg = polytop - h;
texturevpegslope = polytopslope - hS;
}
memcpy(wallVerts, inWallVerts, sizeof(wallVerts));
// Left side
wallVerts[3].t = texturevpeg * yscale * grTex->scaleY;
wallVerts[0].t = (h - l + texturevpeg) * yscale * grTex->scaleY;
wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->textureoffset + gl_sidedef->offsetx_mid) * grTex->scaleX;
// Right side
wallVerts[2].t = texturevpegslope * yscale * grTex->scaleY;
wallVerts[1].t = (hS - lS + texturevpegslope) * yscale * grTex->scaleY;
wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->textureoffset + gl_sidedef->offsetx_mid) * grTex->scaleX;
// set top/bottom coords
// Take the texture peg into account, rather than changing the offsets past
// where the polygon might not be.
wallVerts[3].y = FIXED_TO_FLOAT(h);
wallVerts[0].y = FIXED_TO_FLOAT(l);
wallVerts[2].y = FIXED_TO_FLOAT(hS);
wallVerts[1].y = FIXED_TO_FLOAT(lS);
// TODO: Actually use the surface's flags so that I don't have to do this
FUINT blendmode = Surf.PolyFlags;
// Render midtextures on two-sided lines with a z-buffer offset.
// This will cause the midtexture appear on top, if a FOF overlaps with it.
blendmode |= PF_Decal;
extracolormap_t *colormap = gl_frontsector->extra_colormap;
if (gl_frontsector->numlights)
{
if (!(blendmode & PF_Masked))
HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FOF_TRANSLUCENT, NULL, blendmode);
else
HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FOF_CUTLEVEL, NULL, blendmode);
}
else if (!(blendmode & PF_Masked))
HWR_AddTransparentWall(wallVerts, &Surf, gl_midtexture, blendmode, false, lightnum, colormap);
else
HWR_ProjectWall(wallVerts, &Surf, blendmode, lightnum, colormap);
}
// Sort of like GLWall::Process in GZDoom
static void HWR_ProcessSeg(void)
{
FOutVector wallVerts[4];
v2d_t vs, ve; // start, end vertices of 2d line (view from above)
......@@ -1105,12 +1213,12 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
wallVerts[2].z = wallVerts[1].z = ve.y;
// x offset the texture
fixed_t texturehpeg = gl_sidedef->textureoffset + gl_curline->offset;
float cliplow = (float)texturehpeg;
float cliphigh = (float)(texturehpeg + (gl_curline->flength*FRACUNIT));
float cliplow = (float)gl_curline->offset;
float cliphigh = cliplow + (gl_curline->flength * FRACUNIT);
FUINT lightnum = HWR_CalcWallLight(gl_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
FUINT lightnum = HWR_SideLightLevel(gl_sidedef, gl_frontsector->lightlevel);
extracolormap_t *colormap = gl_frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y);
FSurfaceInfo Surf;
Surf.PolyColor.s.alpha = 255;
......@@ -1122,6 +1230,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
if (gl_backsector)
{
INT32 gl_toptexture = 0, gl_bottomtexture = 0;
fixed_t texturevpeg;
SLOPEPARAMS(gl_backsector->c_slope, worldhigh, worldhighslope, gl_backsector->ceilingheight)
......@@ -1150,31 +1259,47 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
// check TOP TEXTURE
if ((worldhighslope < worldtopslope || worldhigh < worldtop) && gl_toptexture)
{
grTex = HWR_GetTexture(gl_toptexture);
xscale = FixedToFloat(gl_sidedef->scalex_top);
yscale = FixedToFloat(gl_sidedef->scaley_top);
grTex = HWR_GetTexture(gl_toptexture, false);
xscale = FixedToFloat(abs(gl_sidedef->scalex_top));
yscale = FixedToFloat(abs(gl_sidedef->scaley_top));
fixed_t offsetx_top = gl_sidedef->textureoffset + gl_sidedef->offsetx_top;
float left = cliplow * xscale;
float right = cliphigh * xscale;
if (gl_sidedef->scalex_top < 0)
{
left = -left;
right = -right;
offsetx_top = -offsetx_top;
}
fixed_t texheight = FixedDiv(textureheight[gl_toptexture], gl_sidedef->scaley_top);
fixed_t texheight = textureheight[gl_toptexture];
fixed_t texheightscaled = FixedDiv(texheight, abs(gl_sidedef->scaley_top));
// PEGGING
// FIXME: This is probably not correct?
if (gl_linedef->flags & ML_DONTPEGTOP)
texturevpeg = 0;
else if (gl_linedef->flags & ML_SKEWTD)
texturevpeg = worldhigh + texheight - worldtop;
else
texturevpeg = gl_backsector->ceilingheight + texheight - gl_frontsector->ceilingheight;
texturevpeg = gl_backsector->ceilingheight + texheightscaled - gl_frontsector->ceilingheight;
texturevpeg *= yscale;
texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_top;
if (gl_sidedef->scaley_top < 0)
texturevpeg -= gl_sidedef->rowoffset + gl_sidedef->offsety_top;
else
texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_top;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpeg %= texheight;
texturevpeg %= texheightscaled;
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpeg + (gl_frontsector->ceilingheight - gl_backsector->ceilingheight) * yscale) * grTex->scaleY;
wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->offsetx_top) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->offsetx_top) * grTex->scaleX;
wallVerts[0].s = wallVerts[3].s = (left + offsetx_top) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = (right + offsetx_top) * grTex->scaleX;
// Adjust t value for sloped walls
if (!(gl_linedef->flags & ML_SKEWTD))
......@@ -1199,6 +1324,14 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
wallVerts[2].t = wallVerts[1].t - (worldtopslope - worldhighslope) * yscale * grTex->scaleY;
}
if (gl_sidedef->scaley_top < 0)
{
wallVerts[0].t = -wallVerts[0].t;
wallVerts[1].t = -wallVerts[1].t;
wallVerts[2].t = -wallVerts[2].t;
wallVerts[3].t = -wallVerts[3].t;
}
// set top/bottom coords
wallVerts[3].y = FIXED_TO_FLOAT(worldtop);
wallVerts[0].y = FIXED_TO_FLOAT(worldhigh);
......@@ -1216,9 +1349,20 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
// check BOTTOM TEXTURE
if ((worldlowslope > worldbottomslope || worldlow > worldbottom) && gl_bottomtexture)
{
grTex = HWR_GetTexture(gl_bottomtexture);
xscale = FixedToFloat(gl_sidedef->scalex_bottom);
yscale = FixedToFloat(gl_sidedef->scaley_bottom);
grTex = HWR_GetTexture(gl_bottomtexture, false);
xscale = FixedToFloat(abs(gl_sidedef->scalex_bottom));
yscale = FixedToFloat(abs(gl_sidedef->scaley_bottom));
fixed_t offsetx_bottom = gl_sidedef->textureoffset + gl_sidedef->offsetx_bottom;
float left = cliplow * xscale;
float right = cliphigh * xscale;
if (gl_sidedef->scalex_bottom < 0)
{
left = -left;
right = -right;
offsetx_bottom = -offsetx_bottom;
}
// PEGGING
if (!(gl_linedef->flags & ML_DONTPEGBOTTOM))
......@@ -1230,15 +1374,18 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
texturevpeg *= yscale;
texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_bottom;
if (gl_sidedef->scaley_bottom < 0)
texturevpeg -= gl_sidedef->rowoffset + gl_sidedef->offsety_bottom;
else
texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_bottom;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpeg %= FixedDiv(textureheight[gl_bottomtexture], gl_sidedef->scaley_bottom);
texturevpeg %= FixedDiv(textureheight[gl_bottomtexture], abs(gl_sidedef->scaley_bottom));
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpeg + (gl_backsector->floorheight - gl_frontsector->floorheight) * yscale) * grTex->scaleY;
wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->offsetx_bottom) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->offsetx_bottom) * grTex->scaleX;
wallVerts[0].s = wallVerts[3].s = (left + offsetx_bottom) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = (right + offsetx_bottom) * grTex->scaleX;
// Adjust t value for sloped walls
if (!(gl_linedef->flags & ML_SKEWTD))
......@@ -1262,6 +1409,14 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
wallVerts[1].t = (texturevpeg + (worldlowslope - worldbottomslope) * yscale) * grTex->scaleY;
}
if (gl_sidedef->scaley_bottom < 0)
{
wallVerts[0].t = -wallVerts[0].t;
wallVerts[1].t = -wallVerts[1].t;
wallVerts[2].t = -wallVerts[2].t;
wallVerts[3].t = -wallVerts[3].t;
}
// set top/bottom coords
wallVerts[3].y = FIXED_TO_FLOAT(worldlow);
wallVerts[0].y = FIXED_TO_FLOAT(worldbottom);
......@@ -1276,241 +1431,59 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
}
// Render midtexture if there's one. Determine if it's visible first, though
if (gl_midtexture && HWR_BlendMidtextureSurface(&Surf))
{
sector_t *front, *back;
fixed_t texheight = FixedDiv(textureheight[gl_midtexture], gl_sidedef->scaley_mid);
INT32 repeats;
if (gl_linedef->frontsector->heightsec != -1)
front = &sectors[gl_linedef->frontsector->heightsec];
else
front = gl_linedef->frontsector;
if (gl_linedef->backsector->heightsec != -1)
back = &sectors[gl_linedef->backsector->heightsec];
else
back = gl_linedef->backsector;
// Render midtexture if there's one
if (gl_midtexture)
HWR_RenderMidtexture(gl_midtexture, cliplow, cliphigh, worldtop, worldbottom, worldhigh, worldlow, worldtopslope, worldbottomslope, worldhighslope, worldlowslope, lightnum, wallVerts);
if (gl_sidedef->repeatcnt)
repeats = 1 + gl_sidedef->repeatcnt;
else if (gl_linedef->flags & ML_WRAPMIDTEX)
if (!gl_curline->polyseg) // Don't do it for polyobjects
{
// Sky culling
// No longer so much a mess as before!
if (gl_frontsector->ceilingpic == skyflatnum
&& gl_backsector->ceilingpic != skyflatnum) // don't cull if back sector is also sky
{
fixed_t high, low;
if (front->ceilingheight > back->ceilingheight)
high = back->ceilingheight;
else
high = front->ceilingheight;
if (front->floorheight > back->floorheight)
low = front->floorheight;
else
low = back->floorheight;
repeats = (high - low) / texheight;
if ((high - low) % texheight)
repeats++; // tile an extra time to fill the gap -- Monster Iestyn
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(INT32_MAX); // draw to top of map space
wallVerts[0].y = FIXED_TO_FLOAT(worldtop);
wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope);
HWR_DrawSkyWall(wallVerts, &Surf);
}
else
repeats = 1;
grTex = HWR_GetTexture(gl_midtexture);
if (gl_frontsector->floorpic == skyflatnum
&& gl_backsector->floorpic != skyflatnum) // same thing here
{
wallVerts[3].y = FIXED_TO_FLOAT(worldbottom);
wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope);
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN); // draw to bottom of map space
HWR_DrawSkyWall(wallVerts, &Surf);
}
}
}
else
{
// Single sided line... Deal only with the middletexture (if one exists)
if (gl_midtexture && gl_linedef->special != SPECIAL_HORIZON_LINE) // (Ignore horizon line for OGL)
{
grTex = HWR_GetTexture(gl_midtexture, false);
xscale = FixedToFloat(gl_sidedef->scalex_mid);
yscale = FixedToFloat(gl_sidedef->scaley_mid);
// SoM: a little note: popentop and popenbottom
// record the limits the texture can be displayed in.
// polytop and polybottom, are the ideal (i.e. unclipped)
// heights of the polygon, and h & l, are the final (clipped)
// poly coords.
fixed_t popentop, popenbottom, polytop, polybottom, lowcut, highcut;
fixed_t popentopslope, popenbottomslope, polytopslope, polybottomslope, lowcutslope, highcutslope;
// NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to,
// you must use the linedef's backsector to be correct
// From CB
if (gl_curline->polyseg)
{
popentop = popentopslope = back->ceilingheight;
popenbottom = popenbottomslope = back->floorheight;
}
fixed_t texturevpeg;
// PEGGING
if ((gl_linedef->flags & (ML_DONTPEGBOTTOM|ML_NOSKEW)) == (ML_DONTPEGBOTTOM|ML_NOSKEW))
texturevpeg = (gl_frontsector->floorheight + textureheight[gl_sidedef->midtexture] - gl_frontsector->ceilingheight) * yscale;
else if (gl_linedef->flags & ML_DONTPEGBOTTOM)
texturevpeg = (worldbottom + textureheight[gl_sidedef->midtexture] - worldtop) * yscale;
else
{
popentop = min(worldtop, worldhigh);
popenbottom = max(worldbottom, worldlow);
popentopslope = min(worldtopslope, worldhighslope);
popenbottomslope = max(worldbottomslope, worldlowslope);
}
// top of texture at top
texturevpeg = 0;
// Find the wall's coordinates
fixed_t midtexheight = texheight * repeats;
texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
fixed_t rowoffset = FixedDiv(gl_sidedef->rowoffset + gl_sidedef->offsety_mid, gl_sidedef->scaley_mid);
// Texture is not skewed
if (gl_linedef->flags & ML_NOSKEW)
{
// Peg it to the floor
if (gl_linedef->flags & ML_MIDPEG)
{
polybottom = max(front->floorheight, back->floorheight) + rowoffset;
polytop = polybottom + midtexheight;
}
// Peg it to the ceiling
else
{
polytop = min(front->ceilingheight, back->ceilingheight) + rowoffset;
polybottom = polytop - midtexheight;
}
// The right side's coordinates are the the same as the left side
polytopslope = polytop;
polybottomslope = polybottom;
}
// Skew the texture, but peg it to the floor
else if (gl_linedef->flags & ML_MIDPEG)
{
polybottom = popenbottom + rowoffset;
polytop = polybottom + midtexheight;
polybottomslope = popenbottomslope + rowoffset;
polytopslope = polybottomslope + midtexheight;
}
// Skew it according to the ceiling's slope
else
{
polytop = popentop + rowoffset;
polybottom = polytop - midtexheight;
polytopslope = popentopslope + rowoffset;
polybottomslope = polytopslope - midtexheight;
}
// CB
// NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to,
// you must use the linedef's backsector to be correct
if (gl_curline->polyseg)
{
lowcut = polybottom;
highcut = polytop;
lowcutslope = polybottomslope;
highcutslope = polytopslope;
}
else
{
// The cut-off values of a linedef can always be constant, since every line has an absoulute front and or back sector
lowcut = popenbottom;
highcut = popentop;
lowcutslope = popenbottomslope;
highcutslope = popentopslope;
}
h = min(highcut, polytop);
l = max(polybottom, lowcut);
hS = min(highcutslope, polytopslope);
lS = max(polybottomslope, lowcutslope);
// PEGGING
fixed_t texturevpegslope;
if (gl_linedef->flags & ML_MIDPEG)
{
texturevpeg = midtexheight - h + polybottom;
texturevpegslope = midtexheight - hS + polybottomslope;
}
else
{
texturevpeg = polytop - h;
texturevpegslope = polytopslope - hS;
}
// Left side
wallVerts[3].t = texturevpeg * yscale * grTex->scaleY;
wallVerts[0].t = (h - l + texturevpeg) * yscale * grTex->scaleY;
wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->offsetx_mid) * grTex->scaleX;
// Right side
wallVerts[2].t = texturevpegslope * yscale * grTex->scaleY;
wallVerts[1].t = (hS - lS + texturevpegslope) * yscale * grTex->scaleY;
wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->offsetx_mid) * grTex->scaleX;
// set top/bottom coords
// Take the texture peg into account, rather than changing the offsets past
// where the polygon might not be.
wallVerts[3].y = FIXED_TO_FLOAT(h);
wallVerts[0].y = FIXED_TO_FLOAT(l);
wallVerts[2].y = FIXED_TO_FLOAT(hS);
wallVerts[1].y = FIXED_TO_FLOAT(lS);
// TODO: Actually use the surface's flags so that I don't have to do this
FUINT blendmode = Surf.PolyFlags;
// Render midtextures on two-sided lines with a z-buffer offset.
// This will cause the midtexture appear on top, if a FOF overlaps with it.
blendmode |= PF_Decal;
if (gl_frontsector->numlights)
{
if (!(blendmode & PF_Masked))
HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FOF_TRANSLUCENT, NULL, blendmode);
else
HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FOF_CUTLEVEL, NULL, blendmode);
}
else if (!(blendmode & PF_Masked))
HWR_AddTransparentWall(wallVerts, &Surf, gl_midtexture, blendmode, false, lightnum, colormap);
else
HWR_ProjectWall(wallVerts, &Surf, blendmode, lightnum, colormap);
}
// Sky culling
// No longer so much a mess as before!
if (!gl_curline->polyseg) // Don't do it for polyobjects
{
if (gl_frontsector->ceilingpic == skyflatnum
&& gl_backsector->ceilingpic != skyflatnum) // don't cull if back sector is also sky
{
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(INT32_MAX); // draw to top of map space
wallVerts[0].y = FIXED_TO_FLOAT(worldtop);
wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope);
HWR_DrawSkyWall(wallVerts, &Surf);
}
if (gl_frontsector->floorpic == skyflatnum
&& gl_backsector->floorpic != skyflatnum) // same thing here
{
wallVerts[3].y = FIXED_TO_FLOAT(worldbottom);
wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope);
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN); // draw to bottom of map space
HWR_DrawSkyWall(wallVerts, &Surf);
}
}
}
else
{
// Single sided line... Deal only with the middletexture (if one exists)
if (gl_midtexture && gl_linedef->special != SPECIAL_HORIZON_LINE) // (Ignore horizon line for OGL)
{
grTex = HWR_GetTexture(gl_midtexture);
xscale = FixedToFloat(gl_sidedef->scalex_mid);
yscale = FixedToFloat(gl_sidedef->scaley_mid);
fixed_t texturevpeg;
// PEGGING
if ((gl_linedef->flags & (ML_DONTPEGBOTTOM|ML_NOSKEW)) == (ML_DONTPEGBOTTOM|ML_NOSKEW))
texturevpeg = (gl_frontsector->floorheight + textureheight[gl_sidedef->midtexture] - gl_frontsector->ceilingheight) * yscale;
else if (gl_linedef->flags & ML_DONTPEGBOTTOM)
texturevpeg = (worldbottom + textureheight[gl_sidedef->midtexture] - worldtop) * yscale;
else
// top of texture at top
texturevpeg = 0;
texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_frontsector->floorheight) * grTex->scaleY;
wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->offsetx_mid) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->offsetx_mid) * grTex->scaleX;
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_frontsector->floorheight) * grTex->scaleY;
wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->textureoffset + gl_sidedef->offsetx_mid) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->textureoffset + gl_sidedef->offsetx_mid) * grTex->scaleX;
// Texture correction for slopes
if (gl_linedef->flags & ML_NOSKEW) {
......@@ -1573,8 +1546,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
// Used for height comparisons and etc across FOFs and slopes
fixed_t high1, highslope1, low1, lowslope1;
fixed_t texturehpeg = gl_sidedef->textureoffset + gl_sidedef->offsetx_mid;
INT32 texnum;
line_t * newline = NULL; // Multi-Property FOF
lowcut = max(worldbottom, worldlow);
highcut = min(worldtop, worldhigh);
......@@ -1608,16 +1582,14 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope))
continue;
side_t *side = &sides[rover->master->sidenum[0]];
side_t *side = R_GetFFloorSide(gl_curline->linedef, rover, gl_backsector);
boolean do_texture_skew;
boolean dont_peg_bottom;
if (rover->master->flags & ML_TFERLINE)
{
size_t linenum = gl_curline->linedef-gl_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum;
side = &sides[newline->sidenum[0]];
line_t *newline = R_GetFFloorLine(gl_curline->linedef, rover, gl_backsector);
do_texture_skew = newline->flags & ML_SKEWTD;
dont_peg_bottom = newline->flags & ML_DONTPEGBOTTOM;
}
......@@ -1665,7 +1637,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
// -- Monster Iestyn 26/06/18
fixed_t texturevpeg = side->rowoffset + side->offsety_mid;
grTex = HWR_GetTexture(texnum);
grTex = HWR_GetTexture(texnum, true);
xscale = FixedToFloat(side->scalex_mid);
yscale = FixedToFloat(side->scaley_mid);
......@@ -1695,20 +1667,21 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
}
}
wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + side->offsetx_mid) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + side->offsetx_mid) * grTex->scaleX;
wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + texturehpeg + side->offsetx_mid) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + texturehpeg + side->offsetx_mid) * grTex->scaleX;
}
FBITFIELD blendmode;
if (rover->fofflags & FOF_FOG)
{
FBITFIELD blendmode;
blendmode = PF_Fog|PF_NoTexture;
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
lightnum = HWR_SideLightLevel(gl_sidedef, rover->master->frontsector->lightlevel);
colormap = rover->master->frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y);
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(HWR_SideLightLevel(gl_sidedef, rover->master->frontsector->lightlevel), rover->master->frontsector->extra_colormap);
if (gl_frontsector->numlights)
HWR_SplitWall(gl_frontsector, wallVerts, 0, &Surf, rover->fofflags, rover, blendmode);
......@@ -1717,9 +1690,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
}
else
{
FBITFIELD blendmode = PF_Masked;
blendmode = PF_Masked;
if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend)
if ((rover->fofflags & FOF_TRANSLUCENT && !((rover->fofflags & FOF_SPLAT) && rover->alpha >= 255)) || rover->blend)
{
blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent;
Surf.PolyColor.s.alpha = max(0, min(rover->alpha, 255));
......@@ -1765,13 +1738,21 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope))
continue;
side_t *side = &sides[rover->master->sidenum[0]];
side_t *side = R_GetFFloorSide(gl_curline->linedef, rover, gl_backsector);
boolean do_texture_skew;
boolean dont_peg_bottom;
if (rover->master->flags & ML_TFERLINE)
{
size_t linenum = gl_curline->linedef-gl_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum;
side = &sides[newline->sidenum[0]];
line_t *newline = R_GetFFloorLine(gl_curline->linedef, rover, gl_backsector);
do_texture_skew = newline->flags & ML_SKEWTD;
dont_peg_bottom = newline->flags & ML_DONTPEGBOTTOM;
}
else
{
do_texture_skew = rover->master->flags & ML_SKEWTD;
dont_peg_bottom = gl_curline->linedef->flags & ML_DONTPEGBOTTOM;
}
texnum = R_GetTextureNum(side->midtexture);
......@@ -1808,27 +1789,54 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
}
else
{
grTex = HWR_GetTexture(texnum);
// Wow, how was this missing from OpenGL for so long?
// ...Oh well, anyway, Lower Unpegged now changes pegging of FOFs like in software
// -- Monster Iestyn 26/06/18
fixed_t texturevpeg = side->rowoffset + side->offsety_mid;
grTex = HWR_GetTexture(texnum, true);
xscale = FixedToFloat(side->scalex_mid);
yscale = FixedToFloat(side->scaley_mid);
fixed_t diff = (*rover->topheight - h) * yscale;
if (!do_texture_skew) // no skewing
{
if (dont_peg_bottom)
texturevpeg -= (*rover->topheight - *rover->bottomheight) * yscale;
wallVerts[3].t = wallVerts[2].t = (diff + side->rowoffset + side->offsety_mid) * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (((h - l) * yscale) + (diff + side->rowoffset + side->offsety_mid)) * grTex->scaleY;
wallVerts[3].t = (((*rover->topheight - h) * yscale) + texturevpeg) * grTex->scaleY;
wallVerts[2].t = (((*rover->topheight - hS) * yscale) + texturevpeg) * grTex->scaleY;
wallVerts[0].t = (((*rover->topheight - l) * yscale) + texturevpeg) * grTex->scaleY;
wallVerts[1].t = (((*rover->topheight - lS) * yscale) + texturevpeg) * grTex->scaleY;
}
else
{
if (!dont_peg_bottom) // skew by top
{
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = (((h - l) * yscale) + texturevpeg) * grTex->scaleY;
wallVerts[1].t = (((hS - lS) * yscale) + texturevpeg) * grTex->scaleY;
}
else // skew by bottom
{
wallVerts[0].t = wallVerts[1].t = texturevpeg * grTex->scaleY;
wallVerts[3].t = wallVerts[0].t - ((h - l) * yscale) * grTex->scaleY;
wallVerts[2].t = wallVerts[1].t - ((hS - lS) * yscale) * grTex->scaleY;
}
}
wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + side->offsetx_mid) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + side->offsetx_mid) * grTex->scaleX;
wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + texturehpeg + side->offsetx_mid) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + texturehpeg + side->offsetx_mid) * grTex->scaleX;
}
FBITFIELD blendmode;
if (rover->fofflags & FOF_FOG)
{
FBITFIELD blendmode;
blendmode = PF_Fog|PF_NoTexture;
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
lightnum = HWR_SideLightLevel(gl_sidedef, rover->master->frontsector->lightlevel);
colormap = rover->master->frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y);
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
......@@ -1839,9 +1847,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
}
else
{
FBITFIELD blendmode = PF_Masked;
blendmode = PF_Masked;
if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend)
if ((rover->fofflags & FOF_TRANSLUCENT && !((rover->fofflags & FOF_SPLAT) && rover->alpha >= 255)) || rover->blend)
{
blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent;
Surf.PolyColor.s.alpha = max(0, min(rover->alpha, 255));
......@@ -1868,8 +1876,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
//
// e6y: Check whether the player can look beyond this line
//
#ifdef NEWCLIP
boolean checkforemptylines = true;
static boolean checkforemptylines = true;
// Don't modify anything here, just check
// Kalaron: Modified for sloped linedefs
static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacksector)
......@@ -1961,295 +1969,6 @@ static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacks
return false;
}
#else
//Hurdler: just like in r_bsp.c
#if 1
#define MAXSEGS MAXVIDWIDTH/2+1
#else
//Alam_GBC: Or not (may cause overflow)
#define MAXSEGS 128
#endif
// hw_newend is one past the last valid seg
static cliprange_t * hw_newend;
static cliprange_t gl_solidsegs[MAXSEGS];
// needs fix: walls are incorrectly clipped one column less
static consvar_t cv_glclipwalls = CVAR_INIT ("gr_clipwalls", "Off", 0, CV_OnOff, NULL);
static void printsolidsegs(void)
{
cliprange_t * start;
if (!hw_newend)
return;
for (start = gl_solidsegs;start != hw_newend;start++)
{
CONS_Debug(DBG_RENDER, "%d-%d|",start->first,start->last);
}
CONS_Debug(DBG_RENDER, "\n\n");
}
//
//
//
static void HWR_ClipSolidWallSegment(INT32 first, INT32 last)
{
cliprange_t *next, *start;
float lowfrac, highfrac;
boolean poorhack = false;
// Find the first range that touches the range
// (adjacent pixels are touching).
start = gl_solidsegs;
while (start->last < first-1)
start++;
if (first < start->first)
{
if (last < start->first-1)
{
// Post is entirely visible (above start),
// so insert a new clippost.
HWR_StoreWallRange(first, last);
next = hw_newend;
hw_newend++;
while (next != start)
{
*next = *(next-1);
next--;
}
next->first = first;
next->last = last;
printsolidsegs();
return;
}
// There is a fragment above *start.
if (!cv_glclipwalls.value)
{
if (!poorhack) HWR_StoreWallRange(first, last);
poorhack = true;
}
else
{
highfrac = HWR_ClipViewSegment(start->first+1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
HWR_StoreWallRange(0, highfrac);
}
// Now adjust the clip size.
start->first = first;
}
// Bottom contained in start?
if (last <= start->last)
{
printsolidsegs();
return;
}
next = start;
while (last >= (next+1)->first-1)
{
// There is a fragment between two posts.
if (!cv_glclipwalls.value)
{
if (!poorhack) HWR_StoreWallRange(first,last);
poorhack = true;
}
else
{
lowfrac = HWR_ClipViewSegment(next->last-1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
highfrac = HWR_ClipViewSegment((next+1)->first+1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
HWR_StoreWallRange(lowfrac, highfrac);
}
next++;
if (last <= next->last)
{
// Bottom is contained in next.
// Adjust the clip size.
start->last = next->last;
goto crunch;
}
}
if (first == next->first+1) // 1 line texture
{
if (!cv_glclipwalls.value)
{
if (!poorhack) HWR_StoreWallRange(first,last);
poorhack = true;
}
else
HWR_StoreWallRange(0, 1);
}
else
{
// There is a fragment after *next.
if (!cv_glclipwalls.value)
{
if (!poorhack) HWR_StoreWallRange(first,last);
poorhack = true;
}
else
{
lowfrac = HWR_ClipViewSegment(next->last-1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
HWR_StoreWallRange(lowfrac, 1);
}
}
// Adjust the clip size.
start->last = last;
// Remove start+1 to next from the clip list,
// because start now covers their area.
crunch:
if (next == start)
{
printsolidsegs();
// Post just extended past the bottom of one post.
return;
}
while (next++ != hw_newend)
{
// Remove a post.
*++start = *next;
}
hw_newend = start;
printsolidsegs();
}
//
// handle LineDefs with upper and lower texture (windows)
//
static void HWR_ClipPassWallSegment(INT32 first, INT32 last)
{
cliprange_t *start;
float lowfrac, highfrac;
//to allow noclipwalls but still solidseg reject of non-visible walls
boolean poorhack = false;
// Find the first range that touches the range
// (adjacent pixels are touching).
start = gl_solidsegs;
while (start->last < first - 1)
start++;
if (first < start->first)
{
if (last < start->first-1)
{
// Post is entirely visible (above start).
HWR_StoreWallRange(0, 1);
return;
}
// There is a fragment above *start.
if (!cv_glclipwalls.value)
{ //20/08/99: Changed by Hurdler (taken from faB's code)
if (!poorhack) HWR_StoreWallRange(0, 1);
poorhack = true;
}
else
{
highfrac = HWR_ClipViewSegment(min(start->first + 1,
start->last), (polyvertex_t *)gl_curline->pv1,
(polyvertex_t *)gl_curline->pv2);
HWR_StoreWallRange(0, highfrac);
}
}
// Bottom contained in start?
if (last <= start->last)
return;
while (last >= (start+1)->first-1)
{
// There is a fragment between two posts.
if (!cv_glclipwalls.value)
{
if (!poorhack) HWR_StoreWallRange(0, 1);
poorhack = true;
}
else
{
lowfrac = HWR_ClipViewSegment(max(start->last-1,start->first), (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
highfrac = HWR_ClipViewSegment(min((start+1)->first+1,(start+1)->last), (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
HWR_StoreWallRange(lowfrac, highfrac);
}
start++;
if (last <= start->last)
return;
}
if (first == start->first+1) // 1 line texture
{
if (!cv_glclipwalls.value)
{
if (!poorhack) HWR_StoreWallRange(0, 1);
poorhack = true;
}
else
HWR_StoreWallRange(0, 1);
}
else
{
// There is a fragment after *next.
if (!cv_glclipwalls.value)
{
if (!poorhack) HWR_StoreWallRange(0,1);
poorhack = true;
}
else
{
lowfrac = HWR_ClipViewSegment(max(start->last - 1,
start->first), (polyvertex_t *)gl_curline->pv1,
(polyvertex_t *)gl_curline->pv2);
HWR_StoreWallRange(lowfrac, 1);
}
}
}
// --------------------------------------------------------------------------
// HWR_ClipToSolidSegs check if it is hide by wall (solidsegs)
// --------------------------------------------------------------------------
static boolean HWR_ClipToSolidSegs(INT32 first, INT32 last)
{
cliprange_t * start;
// Find the first range that touches the range
// (adjacent pixels are touching).
start = gl_solidsegs;
while (start->last < first-1)
start++;
if (first < start->first)
return true;
// Bottom contained in start?
if (last <= start->last)
return false;
return true;
}
//
// HWR_ClearClipSegs
//
static void HWR_ClearClipSegs(void)
{
gl_solidsegs[0].first = -0x7fffffff;
gl_solidsegs[0].last = -1;
gl_solidsegs[1].first = vid.width; //viewwidth;
gl_solidsegs[1].last = 0x7fffffff;
hw_newend = gl_solidsegs+2;
}
#endif // NEWCLIP
// -----------------+
// HWR_AddLine : Clips the given segment and adds any visible pieces to the line list.
......@@ -2259,11 +1978,6 @@ static void HWR_ClearClipSegs(void)
static void HWR_AddLine(seg_t * line)
{
angle_t angle1, angle2;
#ifndef NEWCLIP
INT32 x1, x2;
angle_t span, tspan;
boolean bothceilingssky = false, bothfloorssky = false;
#endif
// SoM: Backsector needs to be run through R_FakeFlat
static sector_t tempsec;
......@@ -2299,8 +2013,7 @@ static void HWR_AddLine(seg_t * line)
angle1 = R_PointToAngle64(v1x, v1y);
angle2 = R_PointToAngle64(v2x, v2y);
#ifdef NEWCLIP
// PrBoom: Back side, i.e. backface culling - read: endAngle >= startAngle!
// PrBoom: Back side, i.e. backface culling - read: endAngle >= startAngle!
if (angle2 - angle1 < ANGLE_180)
return;
......@@ -2312,91 +2025,10 @@ static void HWR_AddLine(seg_t * line)
}
checkforemptylines = true;
#else
// Clip to view edges.
span = angle1 - angle2;
// backface culling : span is < ANGLE_180 if ang1 > ang2 : the seg is facing
if (span >= ANGLE_180)
return;
// Global angle needed by segcalc.
//rw_angle1 = angle1;
angle1 -= dup_viewangle;
angle2 -= dup_viewangle;
tspan = angle1 + gl_clipangle;
if (tspan > 2*gl_clipangle)
{
tspan -= 2*gl_clipangle;
// Totally off the left edge?
if (tspan >= span)
return;
angle1 = gl_clipangle;
}
tspan = gl_clipangle - angle2;
if (tspan > 2*gl_clipangle)
{
tspan -= 2*gl_clipangle;
// Totally off the left edge?
if (tspan >= span)
return;
angle2 = (angle_t)-(signed)gl_clipangle;
}
#if 0
{
float fx1,fx2,fy1,fy2;
//BP: test with a better projection than viewangletox[R_PointToAngle(angle)]
// do not enable this at release 4 mul and 2 div
fx1 = ((polyvertex_t *)(line->pv1))->x-gl_viewx;
fy1 = ((polyvertex_t *)(line->pv1))->y-gl_viewy;
fy2 = (fx1 * gl_viewcos + fy1 * gl_viewsin);
if (fy2 < 0)
// the point is back
fx1 = 0;
else
fx1 = gl_windowcenterx + (fx1 * gl_viewsin - fy1 * gl_viewcos) * gl_centerx / fy2;
fx2 = ((polyvertex_t *)(line->pv2))->x-gl_viewx;
fy2 = ((polyvertex_t *)(line->pv2))->y-gl_viewy;
fy1 = (fx2 * gl_viewcos + fy2 * gl_viewsin);
if (fy1 < 0)
// the point is back
fx2 = vid.width;
else
fx2 = gl_windowcenterx + (fx2 * gl_viewsin - fy2 * gl_viewcos) * gl_centerx / fy1;
x1 = fx1+0.5f;
x2 = fx2+0.5f;
}
#else
// The seg is in the view range,
// but not necessarily visible.
angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT;
angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT;
x1 = gl_viewangletox[angle1];
x2 = gl_viewangletox[angle2];
#endif
// Does not cross a pixel?
// if (x1 == x2)
/* {
// BP: HERE IS THE MAIN PROBLEM !
//CONS_Debug(DBG_RENDER, "tineline\n");
return;
}
*/
#endif
gl_backsector = line->backsector;
bothceilingssky = bothfloorssky = false;
#ifdef NEWCLIP
if (!line->backsector)
{
gld_clipper_SafeAddClipRange(angle2, angle1);
......@@ -2439,115 +2071,6 @@ static void HWR_AddLine(seg_t * line)
}
HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D
return;
#else
// Single sided line?
if (!gl_backsector)
goto clipsolid;
gl_backsector = R_FakeFlat(gl_backsector, &tempsec, NULL, NULL, true);
if (gl_backsector->ceilingpic == skyflatnum && gl_frontsector->ceilingpic == skyflatnum)
bothceilingssky = true;
if (gl_backsector->floorpic == skyflatnum && gl_frontsector->floorpic == skyflatnum)
bothfloorssky = true;
if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then
{
if (!line->polyseg &&
!line->sidedef->midtexture
&& ((!gl_frontsector->ffloors && !gl_backsector->ffloors)
|| Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags)))
return; // line is empty, don't even bother
goto clippass; // treat like wide open window instead
}
if (gl_frontsector->f_slope || gl_frontsector->c_slope || gl_backsector->f_slope || gl_backsector->c_slope)
{
fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends
fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends
#define SLOPEPARAMS(slope, end1, end2, normalheight) \
end1 = P_GetZAt(slope, v1x, v1y, normalheight); \
end2 = P_GetZAt(slope, v2x, v2y, normalheight);
SLOPEPARAMS(gl_frontsector->f_slope, frontf1, frontf2, gl_frontsector-> floorheight)
SLOPEPARAMS(gl_frontsector->c_slope, frontc1, frontc2, gl_frontsector->ceilingheight)
SLOPEPARAMS( gl_backsector->f_slope, backf1, backf2, gl_backsector-> floorheight)
SLOPEPARAMS( gl_backsector->c_slope, backc1, backc2, gl_backsector->ceilingheight)
#undef SLOPEPARAMS
// if both ceilings are skies, consider it always "open"
// same for floors
if (!bothceilingssky && !bothfloorssky)
{
// Closed door.
if ((backc1 <= frontf1 && backc2 <= frontf2)
|| (backf1 >= frontc1 && backf2 >= frontc2))
{
goto clipsolid;
}
// Check for automap fix.
if (backc1 <= backf1 && backc2 <= backf2
&& ((backc1 >= frontc1 && backc2 >= frontc2) || gl_curline->sidedef->toptexture)
&& ((backf1 <= frontf1 && backf2 >= frontf2) || gl_curline->sidedef->bottomtexture))
goto clipsolid;
}
// Window.
if (!bothceilingssky) // ceilings are always the "same" when sky
if (backc1 != frontc1 || backc2 != frontc2)
goto clippass;
if (!bothfloorssky) // floors are always the "same" when sky
if (backf1 != frontf1 || backf2 != frontf2)
goto clippass;
}
else
{
// if both ceilings are skies, consider it always "open"
// same for floors
if (!bothceilingssky && !bothfloorssky)
{
// Closed door.
if (gl_backsector->ceilingheight <= gl_frontsector->floorheight ||
gl_backsector->floorheight >= gl_frontsector->ceilingheight)
goto clipsolid;
// Check for automap fix.
if (gl_backsector->ceilingheight <= gl_backsector->floorheight
&& ((gl_backsector->ceilingheight >= gl_frontsector->ceilingheight) || gl_curline->sidedef->toptexture)
&& ((gl_backsector->floorheight <= gl_backsector->floorheight) || gl_curline->sidedef->bottomtexture))
goto clipsolid;
}
// Window.
if (!bothceilingssky) // ceilings are always the "same" when sky
if (gl_backsector->ceilingheight != gl_frontsector->ceilingheight)
goto clippass;
if (!bothfloorssky) // floors are always the "same" when sky
if (gl_backsector->floorheight != gl_frontsector->floorheight)
goto clippass;
}
// Reject empty lines used for triggers and special events.
// Identical floor and ceiling on both sides,
// identical light levels on both sides,
// and no middle texture.
if (R_IsEmptyLine(gl_curline, gl_frontsector, gl_backsector))
return;
clippass:
if (x1 == x2)
{ x2++;x1 -= 2; }
HWR_ClipPassWallSegment(x1, x2-1);
return;
clipsolid:
if (x1 == x2)
goto clippass;
HWR_ClipSolidWallSegment(x1, x2-1);
#endif
}
// HWR_CheckBBox
......@@ -2562,23 +2085,19 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord)
INT32 boxpos;
fixed_t px1, py1, px2, py2;
angle_t angle1, angle2;
#ifndef NEWCLIP
INT32 sx1, sx2;
angle_t span, tspan;
#endif
// Find the corners of the box
// that define the edges from current viewpoint.
if (dup_viewx <= bspcoord[BOXLEFT])
if (viewx <= bspcoord[BOXLEFT])
boxpos = 0;
else if (dup_viewx < bspcoord[BOXRIGHT])
else if (viewx < bspcoord[BOXRIGHT])
boxpos = 1;
else
boxpos = 2;
if (dup_viewy >= bspcoord[BOXTOP])
if (viewy >= bspcoord[BOXTOP])
boxpos |= 0;
else if (dup_viewy > bspcoord[BOXBOTTOM])
else if (viewy > bspcoord[BOXBOTTOM])
boxpos |= 1<<2;
else
boxpos |= 2<<2;
......@@ -2591,59 +2110,9 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord)
px2 = bspcoord[checkcoord[boxpos][2]];
py2 = bspcoord[checkcoord[boxpos][3]];
#ifdef NEWCLIP
angle1 = R_PointToAngle64(px1, py1);
angle2 = R_PointToAngle64(px2, py2);
return gld_clipper_SafeCheckRange(angle2, angle1);
#else
// check clip list for an open space
angle1 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px1>>1, py1>>1) - dup_viewangle;
angle2 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px2>>1, py2>>1) - dup_viewangle;
span = angle1 - angle2;
// Sitting on a line?
if (span >= ANGLE_180)
return true;
tspan = angle1 + gl_clipangle;
if (tspan > 2*gl_clipangle)
{
tspan -= 2*gl_clipangle;
// Totally off the left edge?
if (tspan >= span)
return false;
angle1 = gl_clipangle;
}
tspan = gl_clipangle - angle2;
if (tspan > 2*gl_clipangle)
{
tspan -= 2*gl_clipangle;
// Totally off the left edge?
if (tspan >= span)
return false;
angle2 = (angle_t)-(signed)gl_clipangle;
}
// Find the first clippost
// that touches the source post
// (adjacent pixels are touching).
angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT;
angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT;
sx1 = gl_viewangletox[angle1];
sx2 = gl_viewangletox[angle2];
// Does not cross a pixel.
if (sx1 == sx2)
return false;
return HWR_ClipToSolidSegs(sx1, sx2 - 1);
#endif
}
//
......@@ -2656,36 +2125,14 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord)
static inline void HWR_AddPolyObjectSegs(void)
{
size_t i, j;
seg_t *gl_fakeline = Z_Calloc(sizeof(seg_t), PU_STATIC, NULL);
polyvertex_t *pv1 = Z_Calloc(sizeof(polyvertex_t), PU_STATIC, NULL);
polyvertex_t *pv2 = Z_Calloc(sizeof(polyvertex_t), PU_STATIC, NULL);
// Sort through all the polyobjects
for (i = 0; i < numpolys; ++i)
{
// Render the polyobject's lines
for (j = 0; j < po_ptrs[i]->segCount; ++j)
{
// Copy the info of a polyobject's seg, then convert it to OpenGL floating point
M_Memcpy(gl_fakeline, po_ptrs[i]->segs[j], sizeof(seg_t));
// Now convert the line to float and add it to be rendered
pv1->x = FIXED_TO_FLOAT(gl_fakeline->v1->x);
pv1->y = FIXED_TO_FLOAT(gl_fakeline->v1->y);
pv2->x = FIXED_TO_FLOAT(gl_fakeline->v2->x);
pv2->y = FIXED_TO_FLOAT(gl_fakeline->v2->y);
gl_fakeline->pv1 = pv1;
gl_fakeline->pv2 = pv2;
HWR_AddLine(gl_fakeline);
}
HWR_AddLine(po_ptrs[i]->segs[j]);
}
// Free temporary data no longer needed
Z_Free(pv2);
Z_Free(pv1);
Z_Free(gl_fakeline);
}
static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
......@@ -2694,7 +2141,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling,
{
FSurfaceInfo Surf;
FOutVector *v3d;
INT32 shader = SHADER_DEFAULT;
INT32 shader = SHADER_NONE;
size_t nrPlaneVerts = polysector->numVertices;
INT32 i;
......@@ -2710,13 +2157,8 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling,
static FOutVector *planeVerts = NULL;
static UINT16 numAllocedPlaneVerts = 0;
if (nrPlaneVerts < 3) // Not even a triangle?
if (!r_renderfloors || nrPlaneVerts < 3) // Not even a triangle?
return;
else if (nrPlaneVerts > (size_t)UINT16_MAX) // FIXME: exceeds plVerts size
{
CONS_Debug(DBG_RENDER, "polygon size of %s exceeds max value of %d vertices\n", sizeu1(nrPlaneVerts), UINT16_MAX);
return;
}
// Allocate plane-vertex buffer if we need to
if (!planeVerts || nrPlaneVerts > numAllocedPlaneVerts)
......@@ -2859,7 +2301,7 @@ static void HWR_AddPolyObjectPlanes(void)
}
else
{
HWR_GetLevelFlat(&levelflats[polyobjsector->floorpic]);
HWR_GetLevelFlat(&levelflats[polyobjsector->floorpic], false);
HWR_RenderPolyObjectPlane(po_ptrs[i], false, polyobjsector->floorheight, PF_Occlude,
(light == -1 ? gl_frontsector->lightlevel : *gl_frontsector->lightlist[light].lightlevel), &levelflats[polyobjsector->floorpic],
polyobjsector, 255, (light == -1 ? gl_frontsector->extra_colormap : *gl_frontsector->lightlist[light].extra_colormap));
......@@ -2882,7 +2324,7 @@ static void HWR_AddPolyObjectPlanes(void)
}
else
{
HWR_GetLevelFlat(&levelflats[polyobjsector->ceilingpic]);
HWR_GetLevelFlat(&levelflats[polyobjsector->ceilingpic], false);
HWR_RenderPolyObjectPlane(po_ptrs[i], true, polyobjsector->ceilingheight, PF_Occlude,
(light == -1 ? gl_frontsector->lightlevel : *gl_frontsector->lightlist[light].lightlevel), &levelflats[polyobjsector->ceilingpic],
polyobjsector, 255, (light == -1 ? gl_frontsector->extra_colormap : *gl_frontsector->lightlist[light].extra_colormap));
......@@ -3005,15 +2447,14 @@ static void HWR_Subsector(size_t num)
sub->sector->extra_colormap = gl_frontsector->extra_colormap;
// render floor ?
#ifdef DOPLANES
// yeah, easy backface cull! :)
if (cullFloorHeight < dup_viewz)
if (cullFloorHeight < viewz)
{
if (gl_frontsector->floorpic != skyflatnum)
{
if (sub->validcount != validcount)
{
HWR_GetLevelFlat(&levelflats[gl_frontsector->floorpic]);
HWR_GetLevelFlat(&levelflats[gl_frontsector->floorpic], false);
HWR_RenderPlane(sub, &extrasubsectors[num], false,
// Hack to make things continue to work around slopes.
locFloorHeight == cullFloorHeight ? locFloorHeight : gl_frontsector->floorheight,
......@@ -3021,21 +2462,15 @@ static void HWR_Subsector(size_t num)
PF_Occlude, floorlightlevel, &levelflats[gl_frontsector->floorpic], NULL, 255, floorcolormap);
}
}
else
{
#ifdef POLYSKY
HWR_RenderSkyPlane(&extrasubsectors[num], locFloorHeight);
#endif
}
}
if (cullCeilingHeight > dup_viewz)
if (cullCeilingHeight > viewz)
{
if (gl_frontsector->ceilingpic != skyflatnum)
{
if (sub->validcount != validcount)
{
HWR_GetLevelFlat(&levelflats[gl_frontsector->ceilingpic]);
HWR_GetLevelFlat(&levelflats[gl_frontsector->ceilingpic], false);
HWR_RenderPlane(sub, &extrasubsectors[num], true,
// Hack to make things continue to work around slopes.
locCeilingHeight == cullCeilingHeight ? locCeilingHeight : gl_frontsector->ceilingheight,
......@@ -3043,21 +2478,12 @@ static void HWR_Subsector(size_t num)
PF_Occlude, ceilinglightlevel, &levelflats[gl_frontsector->ceilingpic], NULL, 255, ceilingcolormap);
}
}
else
{
#ifdef POLYSKY
HWR_RenderSkyPlane(&extrasubsectors[num], locCeilingHeight);
#endif
}
}
#ifndef POLYSKY
// Moved here because before, when above the ceiling and the floor does not have the sky flat, it doesn't draw the sky
if (gl_frontsector->ceilingpic == skyflatnum || gl_frontsector->floorpic == skyflatnum)
drawsky = true;
#endif
#ifdef R_FAKEFLOORS
if (gl_frontsector->ffloors)
{
/// \todo fix light, xoffs, yoffs, extracolormap ?
......@@ -3070,14 +2496,14 @@ static void HWR_Subsector(size_t num)
continue;
if (sub->validcount == validcount)
continue;
// rendering heights for bottom and top planes
bottomCullHeight = P_GetFFloorBottomZAt(rover, viewx, viewy);
topCullHeight = P_GetFFloorTopZAt(rover, viewx, viewy);
if (gl_frontsector->cullheight)
{
if (HWR_DoCulling(gl_frontsector->cullheight, viewsector->cullheight, gl_viewz, FIXED_TO_FLOAT(bottomCullHeight), FIXED_TO_FLOAT(topCullHeight)))
if (HWR_DoCulling(gl_frontsector->cullheight, viewsector->cullheight, gl_viewz, FIXED_TO_FLOAT(*rover->bottomheight), FIXED_TO_FLOAT(*rover->topheight)))
continue;
}
......@@ -3086,43 +2512,44 @@ static void HWR_Subsector(size_t num)
if (centerHeight <= locCeilingHeight &&
centerHeight >= locFloorHeight &&
((dup_viewz < bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(dup_viewz > bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
((viewz < bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(viewz > bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
{
if (rover->fofflags & FOF_FOG)
{
UINT8 alpha;
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < bottomCullHeight ? true : false);
alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false);
alpha = HWR_FogBlockAlpha(HWR_FloorLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel), rover->master->frontsector->extra_colormap);
HWR_AddTransparentFloor(0,
&extrasubsectors[num],
false,
*rover->bottomheight,
*gl_frontsector->lightlist[light].lightlevel,
HWR_FloorLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
true, rover->master->frontsector->extra_colormap);
true, false, rover->master->frontsector->extra_colormap);
}
else if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) // SoM: Flags are more efficient
else if ((rover->fofflags & FOF_TRANSLUCENT && !((rover->fofflags & FOF_SPLAT) && rover->alpha >= 255)) || rover->blend) // SoM: Flags are more efficient
{
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < bottomCullHeight ? true : false);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false);
HWR_AddTransparentFloor(&levelflats[*rover->bottompic],
&extrasubsectors[num],
false,
*rover->bottomheight,
*gl_frontsector->lightlist[light].lightlevel,
HWR_FloorLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
max(0, min(rover->alpha, 255)), rover->master->frontsector,
HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent),
false, *gl_frontsector->lightlist[light].extra_colormap);
false, rover->fofflags & FOF_SPLAT, *gl_frontsector->lightlist[light].extra_colormap);
}
else
{
HWR_GetLevelFlat(&levelflats[*rover->bottompic]);
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < bottomCullHeight ? true : false);
HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic],
rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
HWR_GetLevelFlat(&levelflats[*rover->bottompic], rover->fofflags & FOF_SPLAT);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false);
HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude,
HWR_FloorLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
&levelflats[*rover->bottompic], rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
}
}
......@@ -3131,49 +2558,48 @@ static void HWR_Subsector(size_t num)
if (centerHeight >= locFloorHeight &&
centerHeight <= locCeilingHeight &&
((dup_viewz > topCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(dup_viewz < topCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
((viewz > topCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(viewz < topCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
{
if (rover->fofflags & FOF_FOG)
{
UINT8 alpha;
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < topCullHeight ? true : false);
alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false);
alpha = HWR_FogBlockAlpha(HWR_CeilingLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel), rover->master->frontsector->extra_colormap);
HWR_AddTransparentFloor(0,
&extrasubsectors[num],
true,
*rover->topheight,
*gl_frontsector->lightlist[light].lightlevel,
HWR_CeilingLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
true, rover->master->frontsector->extra_colormap);
true, false, rover->master->frontsector->extra_colormap);
}
else if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend)
else if ((rover->fofflags & FOF_TRANSLUCENT && !((rover->fofflags & FOF_SPLAT) && rover->alpha >= 255)) || rover->blend)
{
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < topCullHeight ? true : false);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false);
HWR_AddTransparentFloor(&levelflats[*rover->toppic],
&extrasubsectors[num],
true,
*rover->topheight,
*gl_frontsector->lightlist[light].lightlevel,
HWR_CeilingLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
max(0, min(rover->alpha, 255)), rover->master->frontsector,
HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent),
false, *gl_frontsector->lightlist[light].extra_colormap);
false, rover->fofflags & FOF_SPLAT, *gl_frontsector->lightlist[light].extra_colormap);
}
else
{
HWR_GetLevelFlat(&levelflats[*rover->toppic]);
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < topCullHeight ? true : false);
HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic],
rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
HWR_GetLevelFlat(&levelflats[*rover->toppic], rover->fofflags & FOF_SPLAT);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false);
HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude,
HWR_CeilingLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
&levelflats[*rover->toppic], rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
}
}
}
}
#endif
#endif //doplanes
// Draw all the polyobjects in this subsector
if (sub->polyList)
......@@ -3205,10 +2631,10 @@ static void HWR_Subsector(size_t num)
}
}
// Hurder ici se passe les choses INT32�essantes!
// on vient de tracer le sol et le plafond
// on trace �pr�ent d'abord les sprites et ensuite les murs
// hurdler: faux: on ajoute seulement les sprites, le murs sont trac� d'abord
// Hurdler: here interesting things are happening!
// we have just drawn the floor and ceiling
// we now draw the sprites first and then the walls
// hurdler: false: we only add the sprites, the walls are drawn first
if (line)
{
// draw sprites first, coz they are clipped to the solidsegs of
......@@ -3240,192 +2666,36 @@ static void HWR_Subsector(size_t num)
// traversing subtree recursively.
// Just call with BSP root.
#ifdef coolhack
//t;b;l;r
static fixed_t hackbbox[4];
//BOXTOP,
//BOXBOTTOM,
//BOXLEFT,
//BOXRIGHT
static boolean HWR_CheckHackBBox(fixed_t *bb)
{
if (bb[BOXTOP] < hackbbox[BOXBOTTOM]) //y up
return false;
if (bb[BOXBOTTOM] > hackbbox[BOXTOP])
return false;
if (bb[BOXLEFT] > hackbbox[BOXRIGHT])
return false;
if (bb[BOXRIGHT] < hackbbox[BOXLEFT])
return false;
return true;
}
#endif
// BP: big hack for a test in lighning ref : 1249753487AB
fixed_t *hwbbox;
static void HWR_RenderBSPNode(INT32 bspnum)
{
/*//GZDoom code
if(bspnum == -1)
{
HWR_Subsector(subsectors);
return;
}
while(!((size_t)bspnum&(~NF_SUBSECTOR))) // Keep going until found a subsector
{
node_t *bsp = &nodes[bspnum];
// Decide which side the view point is on
INT32 side = R_PointOnSide(dup_viewx, dup_viewy, bsp);
// Recursively divide front space (toward the viewer)
HWR_RenderBSPNode(bsp->children[side]);
// Possibly divide back space (away from viewer)
side ^= 1;
if (!HWR_CheckBBox(bsp->bbox[side]))
return;
bspnum = bsp->children[side];
}
HWR_Subsector(bspnum-1);
*/
node_t *bsp = &nodes[bspnum];
// Decide which side the view point is on
node_t *bsp;
INT32 side;
ps_numbspcalls.value.i++;
// Found a subsector?
if (bspnum & NF_SUBSECTOR)
while (!(bspnum & NF_SUBSECTOR)) // Found a subsector?
{
if (bspnum == -1)
{
//*(gl_drawsubsector_p++) = 0;
HWR_Subsector(0);
}
else
{
//*(gl_drawsubsector_p++) = bspnum&(~NF_SUBSECTOR);
HWR_Subsector(bspnum&(~NF_SUBSECTOR));
}
return;
}
// Decide which side the view point is on.
side = R_PointOnSide(dup_viewx, dup_viewy, bsp);
// BP: big hack for a test in lighning ref : 1249753487AB
hwbbox = bsp->bbox[side];
// Recursively divide front space.
HWR_RenderBSPNode(bsp->children[side]);
bsp = &nodes[bspnum];
// Possibly divide back space.
if (HWR_CheckBBox(bsp->bbox[side^1]))
{
// Decide which side the view point is on.
side = R_PointOnSide(viewx, viewy, bsp);
// BP: big hack for a test in lighning ref : 1249753487AB
hwbbox = bsp->bbox[side^1];
HWR_RenderBSPNode(bsp->children[side^1]);
}
}
/*
//
// Clear 'stack' of subsectors to draw
//
static void HWR_ClearDrawSubsectors(void)
{
gl_drawsubsector_p = gl_drawsubsectors;
}
//
// Draw subsectors pushed on the drawsubsectors 'stack', back to front
//
static void HWR_RenderSubsectors(void)
{
while (gl_drawsubsector_p > gl_drawsubsectors)
{
HWR_RenderBSPNode(
lastsubsec->nextsubsec = bspnum & (~NF_SUBSECTOR);
}
}
*/
// ==========================================================================
// FROM R_MAIN.C
// ==========================================================================
//BP : exactely the same as R_InitTextureMapping
void HWR_InitTextureMapping(void)
{
angle_t i;
INT32 x;
INT32 t;
fixed_t focallength;
fixed_t grcenterx;
fixed_t grcenterxfrac;
INT32 grviewwidth;
#define clipanglefov (FIELDOFVIEW>>ANGLETOFINESHIFT)
grviewwidth = vid.width;
grcenterx = grviewwidth/2;
grcenterxfrac = grcenterx<<FRACBITS;
// Use tangent table to generate viewangletox:
// viewangletox will give the next greatest x
// after the view angle.
//
// Calc focallength
// so FIELDOFVIEW angles covers SCREENWIDTH.
focallength = FixedDiv(grcenterxfrac,
FINETANGENT(FINEANGLES/4+clipanglefov/2));
for (i = 0; i < FINEANGLES/2; i++)
{
if (FINETANGENT(i) > FRACUNIT*2)
t = -1;
else if (FINETANGENT(i) < -FRACUNIT*2)
t = grviewwidth+1;
else
{
t = FixedMul(FINETANGENT(i), focallength);
t = (grcenterxfrac - t+FRACUNIT-1)>>FRACBITS;
if (t < -1)
t = -1;
else if (t > grviewwidth+1)
t = grviewwidth+1;
}
gl_viewangletox[i] = t;
}
hwbbox = bsp->bbox[side];
// Recursively divide front space.
HWR_RenderBSPNode(bsp->children[side]);
// Scan viewangletox[] to generate xtoviewangle[]:
// xtoviewangle will give the smallest view angle
// that maps to x.
for (x = 0; x <= grviewwidth; x++)
{
i = 0;
while (gl_viewangletox[i]>x)
i++;
gl_xtoviewangle[x] = (i<<ANGLETOFINESHIFT) - ANGLE_90;
}
// Possibly divide back space.
// Take out the fencepost cases from viewangletox.
for (i = 0; i < FINEANGLES/2; i++)
{
if (gl_viewangletox[i] == -1)
gl_viewangletox[i] = 0;
else if (gl_viewangletox[i] == grviewwidth+1)
gl_viewangletox[i] = grviewwidth;
if (!HWR_CheckBBox(bsp->bbox[side^1]))
return;
bspnum = bsp->children[side^1];
}
gl_clipangle = gl_xtoviewangle[0];
HWR_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR);
}
// ==========================================================================
......@@ -3527,7 +2797,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
float fscale; float fx; float fy; float offset;
extracolormap_t *colormap = NULL;
FBITFIELD blendmode = PF_Translucent|PF_Modulated;
INT32 shader = SHADER_DEFAULT;
INT32 shader = SHADER_NONE;
UINT8 i;
INT32 heightsec, phs;
SINT8 flip = P_MobjFlip(thing);
......@@ -3647,7 +2917,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
}
HWR_Lighting(&sSurf, 0, colormap);
sSurf.PolyColor.s.alpha = alpha;
sSurf.PolyColor.s.alpha = FixedMul(thing->alpha, alpha);
if (HWR_UseShader())
{
......@@ -3735,7 +3005,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
boolean lightset = true;
FBITFIELD blend = 0;
FBITFIELD occlusion;
INT32 shader = SHADER_DEFAULT;
INT32 shader = SHADER_NONE;
boolean use_linkdraw_hack = false;
UINT8 alpha;
......@@ -3822,10 +3092,15 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
// co-ordinates
memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts));
fixed_t newalpha = spr->mobj->alpha;
// if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude)
// this will result in sprites drawn afterwards to be drawn on top like intended when using linkdraw.
if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
{
newalpha = spr->mobj->tracer->alpha;
occlusion = 0;
}
else
occlusion = PF_Occlude;
......@@ -3862,6 +3137,8 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
if (!occlusion) use_linkdraw_hack = true;
}
Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
if (HWR_UseShader())
{
shader = SHADER_SPRITE;
......@@ -4058,7 +3335,7 @@ static void HWR_DrawBoundingBox(gl_vissprite_t *vis)
v[15].y = v[16].y = v[17].y = v[21].y = v[22].y = v[23].y = vis->gzt; // top
Surf.PolyColor = V_GetColor(R_GetBoundingBoxColor(vis->mobj));
HWR_ProcessPolygon(&Surf, v, 24, (cv_renderhitboxgldepth.value ? 0 : PF_NoDepthTest)|PF_Modulated|PF_NoTexture|PF_WireFrame, SHADER_NONE, false);
}
......@@ -4306,15 +3583,19 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
}
{
INT32 shader = SHADER_DEFAULT;
INT32 shader = SHADER_NONE;
FBITFIELD blend = 0;
FBITFIELD occlusion;
boolean use_linkdraw_hack = false;
fixed_t newalpha = spr->mobj->alpha;
// if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude)
// this will result in sprites drawn afterwards to be drawn on top like intended when using linkdraw.
if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
{
occlusion = 0;
newalpha = spr->mobj->tracer->alpha;
}
else
occlusion = PF_Occlude;
......@@ -4351,6 +3632,8 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
if (!occlusion) use_linkdraw_hack = true;
}
Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
if (spr->renderflags & RF_SHADOWEFFECTS)
{
INT32 alpha = Surf.PolyColor.s.alpha;
......@@ -4376,11 +3659,10 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
}
}
#ifdef HWPRECIP
// Sprite drawer for precipitation
static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
{
INT32 shader = SHADER_DEFAULT;
INT32 shader = SHADER_NONE;
FBITFIELD blend = 0;
FOutVector wallVerts[4];
patch_t *gpatch;
......@@ -4477,7 +3759,6 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false);
}
#endif
// --------------------------------------------------------------------------
// Sort vissprites by distance
......@@ -4604,6 +3885,7 @@ typedef struct
sector_t *FOFSector;
FBITFIELD blend;
boolean fogplane;
boolean chromakeyed;
extracolormap_t *planecolormap;
INT32 drawcount;
} planeinfo_t;
......@@ -4645,7 +3927,7 @@ static INT32 drawcount = 0;
#define MAX_TRANSPARENTFLOOR 512
// This will likely turn into a copy of HWR_Add3DWater and replace it.
void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap)
void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, boolean chromakeyed, extracolormap_t *planecolormap)
{
static size_t allocedplanes = 0;
......@@ -4661,13 +3943,14 @@ void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boo
planeinfo[numplanes].isceiling = isceiling;
planeinfo[numplanes].fixedheight = fixedheight;
planeinfo[numplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? 255 : lightlevel;
planeinfo[numplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? lightlevel : 255; // TODO: 2.3: Make transparent FOF planes always use light level
planeinfo[numplanes].levelflat = levelflat;
planeinfo[numplanes].xsub = xsub;
planeinfo[numplanes].alpha = alpha;
planeinfo[numplanes].FOFSector = FOFSector;
planeinfo[numplanes].blend = blend;
planeinfo[numplanes].fogplane = fogplane;
planeinfo[numplanes].chromakeyed = chromakeyed;
planeinfo[numplanes].planecolormap = planecolormap;
planeinfo[numplanes].drawcount = drawcount++;
......@@ -4692,7 +3975,7 @@ void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polyse
polyplaneinfo[numpolyplanes].isceiling = isceiling;
polyplaneinfo[numpolyplanes].fixedheight = fixedheight;
polyplaneinfo[numpolyplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? 255 : lightlevel;
polyplaneinfo[numpolyplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? lightlevel : 255; // TODO: 2.3: Make transparent polyobject planes always use light level
polyplaneinfo[numpolyplanes].levelflat = levelflat;
polyplaneinfo[numpolyplanes].polysector = polysector;
polyplaneinfo[numpolyplanes].alpha = alpha;
......@@ -4741,7 +4024,7 @@ static int CompareDrawNodePlanes(const void *p1, const void *p2)
size_t n2 = *(const size_t*)p2;
if (!sortnode[n1].plane) I_Error("CompareDrawNodePlanes: Uh.. This isn't a plane! (n1)");
if (!sortnode[n2].plane) I_Error("CompareDrawNodePlanes: Uh.. This isn't a plane! (n2)");
return ABS(sortnode[n2].plane->fixedheight - viewz) - ABS(sortnode[n1].plane->fixedheight - viewz);
return abs(sortnode[n2].plane->fixedheight - viewz) - abs(sortnode[n1].plane->fixedheight - viewz);
}
//
......@@ -4825,7 +4108,6 @@ static void HWR_CreateDrawNodes(void)
// Okay! Let's draw it all! Woo!
HWD.pfnSetTransform(&atransform);
HWD.pfnSetShader(SHADER_DEFAULT);
for (i = 0; i < p; i++)
{
......@@ -4835,7 +4117,7 @@ static void HWR_CreateDrawNodes(void)
gl_frontsector = NULL;
if (!(sortnode[sortindex[i]].plane->blend & PF_NoTexture))
HWR_GetLevelFlat(sortnode[sortindex[i]].plane->levelflat);
HWR_GetLevelFlat(sortnode[sortindex[i]].plane->levelflat, sortnode[sortindex[i]].plane->chromakeyed);
HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->isceiling, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
sortnode[sortindex[i]].plane->levelflat, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->planecolormap);
}
......@@ -4844,15 +4126,17 @@ static void HWR_CreateDrawNodes(void)
// We aren't traversing the BSP tree, so make gl_frontsector null to avoid crashes.
gl_frontsector = NULL;
polyobj_t *po = sortnode[sortindex[i]].polyplane->polysector;
if (!(sortnode[sortindex[i]].polyplane->blend & PF_NoTexture))
HWR_GetLevelFlat(sortnode[sortindex[i]].polyplane->levelflat);
HWR_RenderPolyObjectPlane(sortnode[sortindex[i]].polyplane->polysector, sortnode[sortindex[i]].polyplane->isceiling, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel,
HWR_GetLevelFlat(sortnode[sortindex[i]].polyplane->levelflat, po->flags & POF_SPLAT);
HWR_RenderPolyObjectPlane(po, sortnode[sortindex[i]].polyplane->isceiling, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel,
sortnode[sortindex[i]].polyplane->levelflat, sortnode[sortindex[i]].polyplane->FOFSector, sortnode[sortindex[i]].polyplane->alpha, sortnode[sortindex[i]].polyplane->planecolormap);
}
else if (sortnode[sortindex[i]].wall)
{
if (!(sortnode[sortindex[i]].wall->blend & PF_NoTexture))
HWR_GetTexture(sortnode[sortindex[i]].wall->texnum);
HWR_GetTexture(sortnode[sortindex[i]].wall->texnum, true);
HWR_RenderWall(sortnode[sortindex[i]].wall->wallVerts, &sortnode[sortindex[i]].wall->Surf, sortnode[sortindex[i]].wall->blend, sortnode[sortindex[i]].wall->fogwall,
sortnode[sortindex[i]].wall->lightlevel, sortnode[sortindex[i]].wall->wallcolormap);
}
......@@ -4884,12 +4168,9 @@ static void HWR_DrawSprites(void)
gl_vissprite_t *spr = gl_vsprorder[i];
if (spr->bbox)
HWR_DrawBoundingBox(spr);
else
#ifdef HWPRECIP
if (spr->precip)
else if (spr->precip)
HWR_DrawPrecipitationSprite(spr);
else
#endif
{
if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value && !skipshadow)
{
......@@ -4960,9 +4241,7 @@ static UINT8 sectorlight;
static void HWR_AddSprites(sector_t *sec)
{
mobj_t *thing;
#ifdef HWPRECIP
precipmobj_t *precipthing;
#endif
fixed_t limit_dist, hoop_limit_dist;
// BSP is traversed by subsector.
......@@ -4995,7 +4274,6 @@ static void HWR_AddSprites(sector_t *sec)
}
}
#ifdef HWPRECIP
// no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off
if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS))
{
......@@ -5005,7 +4283,6 @@ static void HWR_AddSprites(sector_t *sec)
HWR_ProjectPrecipitationSprite(precipthing);
}
}
#endif
}
// --------------------------------------------------------------------------
......@@ -5058,6 +4335,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
// uncapped/interpolation
interpmobjstate_t interp = {0};
if (!r_renderthings)
return;
if (!thing)
return;
......@@ -5134,9 +4414,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
//Fab : 02-08-98: 'skin' override spritedef currently used for skin
if (thing->skin && thing->sprite == SPR_PLAY)
{
sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
sprdef = P_GetSkinSpritedef(thing->skin, thing->sprite2);
#ifdef ROTSPRITE
sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
sprinfo = P_GetSkinSpriteInfo(thing->skin, thing->sprite2);
#endif
}
else
......@@ -5502,7 +4782,6 @@ static void HWR_ProjectSprite(mobj_t *thing)
vis->angle = interp.angle;
}
#ifdef HWPRECIP
// Precipitation projector for hardware mode
static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
{
......@@ -5631,7 +4910,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
thing->precipflags |= PCF_THUNK;
}
}
#endif
static void HWR_ProjectBoundingBox(mobj_t *thing)
{
......@@ -5838,53 +5116,31 @@ static void HWR_DrawSkyBackground(player_t *player)
HWD.pfnSetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated);
HWR_GetTexture(texturetranslation[skytexture], false);
if (cv_glskydome.value)
{
FTransform dometransform;
const float fpov = FixedToFloat(R_GetPlayerFov(player));
postimg_t *type;
if (splitscreen && player == &players[secondarydisplayplayer])
type = &postimgtype2;
else
type = &postimgtype;
memcpy(&dometransform, &atransform, sizeof(FTransform));
memset(&dometransform, 0x00, sizeof(FTransform));
dometransform.x = 0.0;
dometransform.y = 0.0;
dometransform.z = 0.0;
//04/01/2000: Hurdler: added for T&L
// It should replace all other gl_viewxxx when finished
HWR_SetTransformAiming(&dometransform, player, false);
dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
if (*type == postimg_flip)
dometransform.flip = true;
else
dometransform.flip = false;
dometransform.scalex = 1;
dometransform.scaley = (float)vid.width/vid.height;
dometransform.scalez = 1;
dometransform.fovxangle = fpov; // Tails
dometransform.fovyangle = fpov; // Tails
if (player->viewrollangle != 0)
{
fixed_t rol = AngleFixed(player->viewrollangle);
dometransform.rollangle = FIXED_TO_FLOAT(rol);
dometransform.roll = true;
dometransform.rollx = 1.0f;
dometransform.rollz = 0.0f;
}
dometransform.splitscreen = splitscreen;
HWR_GetTexture(texturetranslation[skytexture]);
if (gl_sky.texture != texturetranslation[skytexture])
{
HWR_ClearSkyDome();
HWR_BuildSkyDome();
}
HWD.pfnSetShader(SHADER_SKY); // sky shader
if (HWR_UseShader())
HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_SKY));
HWD.pfnSetTransform(&dometransform);
HWD.pfnRenderSkyDome(&gl_sky);
}
......@@ -5896,7 +5152,6 @@ static void HWR_DrawSkyBackground(player_t *player)
float aspectratio;
float angleturn;
HWR_GetTexture(texturetranslation[skytexture]);
aspectratio = (float)vid.width/(float)vid.height;
//Hurdler: the sky is the only texture who need 4.0f instead of 1.0
......@@ -5921,7 +5176,7 @@ static void HWR_DrawSkyBackground(player_t *player)
// software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly
// The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture
angle = (dup_viewangle + gl_xtoviewangle[0]);
angle = (viewangle + xtoviewangle[0]);
dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f);
......@@ -5970,8 +5225,6 @@ static void HWR_DrawSkyBackground(player_t *player)
HWD.pfnUnSetShader();
HWD.pfnDrawPolygon(NULL, v, 4, 0);
}
HWD.pfnSetShader(SHADER_DEFAULT);
}
......@@ -5987,10 +5240,10 @@ static inline void HWR_ClearView(void)
/// \bug faB - enable depth mask, disable color mask
HWD.pfnGClipRect((INT32)gl_viewwindowx,
(INT32)gl_viewwindowy,
(INT32)(gl_viewwindowx + gl_viewwidth),
(INT32)(gl_viewwindowy + gl_viewheight),
HWD.pfnGClipRect((INT32)viewwindowx,
(INT32)viewwindowy,
(INT32)(viewwindowx + viewwidth),
(INT32)(viewwindowy + viewheight),
ZCLIP_PLANE);
HWD.pfnClearBuffer(false, true, 0);
......@@ -6005,32 +5258,6 @@ static inline void HWR_ClearView(void)
// -----------------+
void HWR_SetViewSize(void)
{
// setup view size
gl_viewwidth = (float)vid.width;
gl_viewheight = (float)vid.height;
if (splitscreen)
gl_viewheight /= 2;
gl_centerx = gl_viewwidth / 2;
gl_basecentery = gl_viewheight / 2; //note: this is (gl_centerx * gl_viewheight / gl_viewwidth)
gl_viewwindowx = (vid.width - gl_viewwidth) / 2;
gl_windowcenterx = (float)(vid.width / 2);
if (fabsf(gl_viewwidth - vid.width) < 1.0E-36f)
{
gl_baseviewwindowy = 0;
gl_basewindowcentery = gl_viewheight / 2; // window top left corner at 0,0
}
else
{
gl_baseviewwindowy = (vid.height-gl_viewheight) / 2;
gl_basewindowcentery = (float)(vid.height / 2);
}
gl_pspritexscale = gl_viewwidth / BASEVIDWIDTH;
gl_pspriteyscale = ((vid.height*gl_pspritexscale*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width;
HWD.pfnFlushScreenTextures();
}
......@@ -6043,7 +5270,9 @@ static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean
if (cv_glshearing.value == 1 || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))
{
fixed_t fixedaiming = AIMINGTODY(aimingangle);
trans->viewaiming = FIXED_TO_FLOAT(fixedaiming);
trans->viewaiming = FIXED_TO_FLOAT(fixedaiming) * ((float)vid.width / vid.height) / ((float)BASEVIDWIDTH / BASEVIDHEIGHT);
if (splitscreen)
trans->viewaiming *= 2.125; // splitscreen adjusts fov with 0.8, so compensate (but only halfway, since splitscreen means only half the screen is used)
trans->shearing = true;
gl_aimingangle = 0;
}
......@@ -6061,21 +5290,11 @@ static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean
//
static void HWR_SetShaderState(void)
{
hwdshaderoption_t state = cv_glshaders.value;
if (!cv_glallowshaders.value)
state = (cv_glshaders.value == HWD_SHADEROPTION_ON ? HWD_SHADEROPTION_NOCUSTOM : cv_glshaders.value);
HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)state);
HWD.pfnSetShader(SHADER_DEFAULT);
HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)HWR_UseShader());
}
// ==========================================================================
// Same as rendering the player view, but from the skybox object
// ==========================================================================
void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
static void HWR_SetupView(player_t *player, INT32 viewnumber, float fpov, boolean skybox)
{
const float fpov = FixedToFloat(R_GetPlayerFov(player));
postimg_t *type;
if (splitscreen && player == &players[secondarydisplayplayer])
......@@ -6083,6 +5302,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
else
type = &postimgtype;
if (!HWR_ShouldUsePaletteRendering())
{
// do we really need to save player (is it not the same)?
player_t *saved_player = stplyr;
......@@ -6091,55 +5311,41 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
stplyr = saved_player;
#ifdef ALAM_LIGHTING
HWR_SetLights(viewnumber);
#else
(void)viewnumber;
#endif
}
// note: sets viewangle, viewx, viewy, viewz
R_SkyboxFrame(player);
// copy view cam position for local use
dup_viewx = viewx;
dup_viewy = viewy;
dup_viewz = viewz;
dup_viewangle = viewangle;
// set window position
gl_centery = gl_basecentery;
gl_viewwindowy = gl_baseviewwindowy;
gl_windowcentery = gl_basewindowcentery;
if (splitscreen && viewnumber == 1)
{
gl_viewwindowy += (vid.height/2);
gl_windowcentery += (vid.height/2);
}
// check for new console commands.
NetUpdate();
if (skybox)
R_SkyboxFrame(player);
else
R_SetupFrame(player);
gl_viewx = FIXED_TO_FLOAT(dup_viewx);
gl_viewy = FIXED_TO_FLOAT(dup_viewy);
gl_viewz = FIXED_TO_FLOAT(dup_viewz);
gl_viewsin = FIXED_TO_FLOAT(viewsin);
gl_viewcos = FIXED_TO_FLOAT(viewcos);
gl_viewx = FixedToFloat(viewx);
gl_viewy = FixedToFloat(viewy);
gl_viewz = FixedToFloat(viewz);
gl_viewsin = FixedToFloat(viewsin);
gl_viewcos = FixedToFloat(viewcos);
//04/01/2000: Hurdler: added for T&L
// It should replace all other gl_viewxxx when finished
memset(&atransform, 0x00, sizeof(FTransform));
HWR_SetTransformAiming(&atransform, player, true);
HWR_SetTransformAiming(&atransform, player, skybox);
atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
gl_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT));
gl_viewludcos = FIXED_TO_FLOAT(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT));
gl_viewludsin = FixedToFloat(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT));
gl_viewludcos = FixedToFloat(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT));
if (*type == postimg_flip)
atransform.flip = true;
else
atransform.flip = false;
atransform.x = gl_viewx; // FIXED_TO_FLOAT(viewx)
atransform.y = gl_viewy; // FIXED_TO_FLOAT(viewy)
atransform.z = gl_viewz; // FIXED_TO_FLOAT(viewz)
atransform.x = gl_viewx;
atransform.y = gl_viewy;
atransform.z = gl_viewz;
atransform.scalex = 1;
atransform.scaley = (float)vid.width/vid.height;
atransform.scalez = 1;
......@@ -6149,7 +5355,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
if (player->viewrollangle != 0)
{
fixed_t rol = AngleFixed(player->viewrollangle);
atransform.rollangle = FIXED_TO_FLOAT(rol);
atransform.rollangle = FixedToFloat(rol);
atransform.roll = true;
atransform.rollx = 1.0f;
atransform.rollz = 0.0f;
......@@ -6157,6 +5363,19 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
atransform.splitscreen = splitscreen;
gl_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
}
// ==========================================================================
// Same as rendering the player view, but from the skybox object
// ==========================================================================
void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
{
const float fpov = FixedToFloat(R_GetPlayerFov(player));
HWR_SetupView(player, viewnumber, fpov, true);
// check for new console commands.
NetUpdate();
//------------------------------------------------------------------------
HWR_ClearView();
......@@ -6171,19 +5390,15 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
drawcount = 0;
#ifdef NEWCLIP
if (rendermode == render_opengl)
{
angle_t a1 = gld_FrustumAngle(gl_aimingangle);
angle_t a1 = gld_FrustumAngle(fpov, gl_aimingangle);
gld_clipper_Clear();
gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1);
#ifdef HAVE_SPHEREFRUSTRUM
gld_FrustrumSetup();
#endif
}
#else
HWR_ClearClipSegs();
#endif
//04/01/2000: Hurdler: added for T&L
// Actually it only works on Walls and Planes
......@@ -6248,17 +5463,11 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
{
const float fpov = FixedToFloat(R_GetPlayerFov(player));
postimg_t *type;
const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on
FRGBAFloat ClearColor;
if (splitscreen && player == &players[secondarydisplayplayer])
type = &postimgtype2;
else
type = &postimgtype;
ClearColor.red = 0.0f;
ClearColor.green = 0.0f;
ClearColor.blue = 0.0f;
......@@ -6275,82 +5484,13 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind
PS_STOP_TIMING(ps_hw_skyboxtime);
{
// do we really need to save player (is it not the same)?
player_t *saved_player = stplyr;
stplyr = player;
ST_doPaletteStuff();
stplyr = saved_player;
#ifdef ALAM_LIGHTING
HWR_SetLights(viewnumber);
#endif
}
HWR_SetupView(player, viewnumber, fpov, false);
// note: sets viewangle, viewx, viewy, viewz
R_SetupFrame(player);
framecount++; // timedemo
// copy view cam position for local use
dup_viewx = viewx;
dup_viewy = viewy;
dup_viewz = viewz;
dup_viewangle = viewangle;
// set window position
gl_centery = gl_basecentery;
gl_viewwindowy = gl_baseviewwindowy;
gl_windowcentery = gl_basewindowcentery;
if (splitscreen && viewnumber == 1)
{
gl_viewwindowy += (vid.height/2);
gl_windowcentery += (vid.height/2);
}
// check for new console commands.
NetUpdate();
gl_viewx = FIXED_TO_FLOAT(dup_viewx);
gl_viewy = FIXED_TO_FLOAT(dup_viewy);
gl_viewz = FIXED_TO_FLOAT(dup_viewz);
gl_viewsin = FIXED_TO_FLOAT(viewsin);
gl_viewcos = FIXED_TO_FLOAT(viewcos);
//04/01/2000: Hurdler: added for T&L
// It should replace all other gl_viewxxx when finished
memset(&atransform, 0x00, sizeof(FTransform));
HWR_SetTransformAiming(&atransform, player, false);
atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
gl_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT));
gl_viewludcos = FIXED_TO_FLOAT(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT));
if (*type == postimg_flip)
atransform.flip = true;
else
atransform.flip = false;
atransform.x = gl_viewx; // FIXED_TO_FLOAT(viewx)
atransform.y = gl_viewy; // FIXED_TO_FLOAT(viewy)
atransform.z = gl_viewz; // FIXED_TO_FLOAT(viewz)
atransform.scalex = 1;
atransform.scaley = (float)vid.width/vid.height;
atransform.scalez = 1;
atransform.fovxangle = fpov; // Tails
atransform.fovyangle = fpov; // Tails
if (player->viewrollangle != 0)
{
fixed_t rol = AngleFixed(player->viewrollangle);
atransform.rollangle = FIXED_TO_FLOAT(rol);
atransform.roll = true;
atransform.rollx = 1.0f;
atransform.rollz = 0.0f;
}
atransform.splitscreen = splitscreen;
gl_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
//------------------------------------------------------------------------
HWR_ClearView(); // Clears the depth buffer and resets the view I believe
......@@ -6364,19 +5504,15 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
drawcount = 0;
#ifdef NEWCLIP
if (rendermode == render_opengl)
{
angle_t a1 = gld_FrustumAngle(gl_aimingangle);
angle_t a1 = gld_FrustumAngle(fpov, gl_aimingangle);
gld_clipper_Clear();
gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1);
#ifdef HAVE_SPHEREFRUSTRUM
gld_FrustrumSetup();
#endif
}
#else
HWR_ClearClipSegs();
#endif
//04/01/2000: Hurdler: added for T&L
// Actually it only works on Walls and Planes
......@@ -6451,6 +5587,56 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE);
}
// Returns whether palette rendering is "actually enabled."
// Can't have palette rendering if shaders are disabled.
boolean HWR_ShouldUsePaletteRendering(void)
{
return (pMasterPalette != NULL && cv_glpaletterendering.value && HWR_UseShader());
}
// enable or disable palette rendering state depending on settings and availability
// called when relevant settings change
// shader recompilation is done in the cvar callback
static void HWR_TogglePaletteRendering(void)
{
// which state should we go to?
if (HWR_ShouldUsePaletteRendering())
{
// are we not in that state already?
if (!gl_palette_rendering_state)
{
gl_palette_rendering_state = true;
// The textures will still be converted to RGBA by r_opengl.
// This however makes hw_cache use paletted blending for composite textures!
// (patchformat is not touched)
textureformat = GL_TEXFMT_AP_88;
HWR_SetMapPalette();
HWR_SetPalette(pLocalPalette);
// If the r_opengl "texture palette" stays the same during this switch, these textures
// will not be cleared out. However they are still out of date since the
// composite texture blending method has changed. Therefore they need to be cleared.
HWR_LoadMapTextures(numtextures);
}
}
else
{
// are we not in that state already?
if (gl_palette_rendering_state)
{
gl_palette_rendering_state = false;
textureformat = GL_TEXFMT_RGBA;
HWR_SetPalette(pLocalPalette);
// If the r_opengl "texture palette" stays the same during this switch, these textures
// will not be cleared out. However they are still out of date since the
// composite texture blending method has changed. Therefore they need to be cleared.
HWR_LoadMapTextures(numtextures);
}
}
}
void HWR_LoadLevel(void)
{
#ifdef ALAM_LIGHTING
......@@ -6464,6 +5650,9 @@ void HWR_LoadLevel(void)
HWR_ClearSkyDome();
HWR_BuildSkyDome();
if (HWR_ShouldUsePaletteRendering())
HWR_SetMapPalette();
gl_maploaded = true;
}
......@@ -6471,13 +5660,16 @@ void HWR_LoadLevel(void)
// 3D ENGINE COMMANDS
// ==========================================================================
static CV_PossibleValue_t glshaders_cons_t[] = {{HWD_SHADEROPTION_OFF, "Off"}, {HWD_SHADEROPTION_ON, "On"}, {HWD_SHADEROPTION_NOCUSTOM, "Ignore custom shaders"}, {0, NULL}};
static CV_PossibleValue_t glmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
static CV_PossibleValue_t glshaders_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Ignore custom shaders"}, {0, NULL}};
static CV_PossibleValue_t glfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}};
static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}};
static void CV_glfiltermode_OnChange(void);
static void CV_glanisotropic_OnChange(void);
static void CV_glmodellighting_OnChange(void);
static void CV_glpaletterendering_OnChange(void);
static void CV_glpalettedepth_OnChange(void);
static void CV_glshaders_OnChange(void);
static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"},
{HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"},
......@@ -6487,8 +5679,7 @@ static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA
{0, NULL}};
CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}};
consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, glshaders_cons_t, NULL);
consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowclientshaders", "On", CV_NETVAR, CV_OnOff, NULL);
consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE|CV_CALL, glshaders_cons_t, CV_glshaders_OnChange);
#ifdef ALAM_LIGHTING
consvar_t cv_gldynamiclighting = CVAR_INIT ("gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL);
......@@ -6498,8 +5689,8 @@ consvar_t cv_glcoronasize = CVAR_INIT ("gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0
#endif
consvar_t cv_glmodels = CVAR_INIT ("gr_models", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, glmodelinterpolation_cons_t, NULL);
consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_glmodellighting_OnChange);
consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, glshearing_cons_t, NULL);
consvar_t cv_glspritebillboarding = CVAR_INIT ("gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL);
......@@ -6514,18 +5705,61 @@ consvar_t cv_glsolvetjoin = CVAR_INIT ("gr_solvetjoin", "On", 0, CV_OnOff, NULL)
consvar_t cv_glbatching = CVAR_INIT ("gr_batching", "On", 0, CV_OnOff, NULL);
static CV_PossibleValue_t glpalettedepth_cons_t[] = {{16, "16 bits"}, {24, "24 bits"}, {0, NULL}};
consvar_t cv_glpaletterendering = CVAR_INIT ("gr_paletterendering", "On", CV_SAVE|CV_CALL, CV_OnOff, CV_glpaletterendering_OnChange);
consvar_t cv_glpalettedepth = CVAR_INIT ("gr_palettedepth", "16 bits", CV_SAVE|CV_CALL, glpalettedepth_cons_t, CV_glpalettedepth_OnChange);
#define ONLY_IF_GL_LOADED if (vid.glstate != VID_GL_LIBRARY_LOADED) return;
consvar_t cv_glwireframe = CVAR_INIT ("gr_wireframe", "Off", 0, CV_OnOff, NULL);
static void CV_glfiltermode_OnChange(void)
{
if (rendermode == render_opengl)
HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_glfiltermode.value);
ONLY_IF_GL_LOADED
HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_glfiltermode.value);
}
static void CV_glanisotropic_OnChange(void)
{
if (rendermode == render_opengl)
HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value);
ONLY_IF_GL_LOADED
HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value);
}
static void CV_glmodellighting_OnChange(void)
{
ONLY_IF_GL_LOADED
// if shaders have been compiled, then they now need to be recompiled.
if (gl_shadersavailable)
HWR_CompileShaders();
}
static void CV_glpaletterendering_OnChange(void)
{
ONLY_IF_GL_LOADED
if (gl_shadersavailable)
{
HWR_CompileShaders();
HWR_TogglePaletteRendering();
}
}
static void CV_glpalettedepth_OnChange(void)
{
ONLY_IF_GL_LOADED
// refresh the screen palette
if (HWR_ShouldUsePaletteRendering())
HWR_SetPalette(pLocalPalette);
}
static void CV_glshaders_OnChange(void)
{
ONLY_IF_GL_LOADED
HWR_SetShaderState();
if (cv_glpaletterendering.value)
{
// can't do palette rendering without shaders, so update the state if needed
HWR_TogglePaletteRendering();
}
}
//added by Hurdler: console varibale that are saved
......@@ -6545,9 +5779,9 @@ void HWR_AddCommands(void)
CV_RegisterVar(&cv_glskydome);
CV_RegisterVar(&cv_glspritebillboarding);
CV_RegisterVar(&cv_glfakecontrast);
CV_RegisterVar(&cv_glslopecontrast);
CV_RegisterVar(&cv_glshearing);
CV_RegisterVar(&cv_glshaders);
CV_RegisterVar(&cv_glallowshaders);
CV_RegisterVar(&cv_glfiltermode);
CV_RegisterVar(&cv_glanisotropicmode);
......@@ -6555,11 +5789,9 @@ void HWR_AddCommands(void)
CV_RegisterVar(&cv_glbatching);
CV_RegisterVar(&cv_glpaletterendering);
CV_RegisterVar(&cv_glpalettedepth);
CV_RegisterVar(&cv_glwireframe);
#ifndef NEWCLIP
CV_RegisterVar(&cv_glclipwalls);
#endif
}
// --------------------------------------------------------------------------
......@@ -6571,6 +5803,8 @@ void HWR_Startup(void)
{
CONS_Printf("HWR_Startup()...\n");
textureformat = patchformat = GL_TEXFMT_RGBA;
HWR_InitPolyPool();
HWR_InitMapTextures();
HWR_InitModels();
......@@ -6578,14 +5812,12 @@ void HWR_Startup(void)
HWR_InitLight();
#endif
gl_shadersavailable = HWR_InitShaders();
HWR_SetShaderState();
HWR_LoadAllCustomShaders();
if (!HWR_CompileShaders())
gl_shadersavailable = false;
HWR_TogglePaletteRendering();
}
if (rendermode == render_opengl)
textureformat = patchformat = GL_TEXFMT_RGBA;
gl_init = true;
}
......@@ -6649,6 +5881,9 @@ void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 te
{
static size_t allocedwalls = 0;
if (!r_renderwalls)
return;
// Force realloc if buffer has been freed
if (!wallinfo)
allocedwalls = 0;
......@@ -6675,7 +5910,10 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend,
FBITFIELD blendmode = blend;
UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha
INT32 shader = SHADER_DEFAULT;
INT32 shader = SHADER_NONE;
if (!r_renderwalls)
return;
// Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting
HWR_Lighting(pSurf, lightlevel, wallcolormap);
......@@ -6720,7 +5958,7 @@ void HWR_DoPostProcessor(player_t *player)
// Armageddon Blast Flash!
// Could this even be considered postprocessor?
if (player->flashcount)
if (player->flashcount && !HWR_ShouldUsePaletteRendering())
{
FOutVector v[4];
FSurfaceInfo Surf;
......@@ -6745,7 +5983,7 @@ void HWR_DoPostProcessor(player_t *player)
// Capture the screen for intermission and screen waving
if(gamestate != GS_INTERMISSION)
HWD.pfnMakeScreenTexture();
HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1);
if (splitscreen) // Not supported in splitscreen - someone want to add support?
return;
......@@ -6766,7 +6004,7 @@ void HWR_DoPostProcessor(player_t *player)
if (*type == postimg_water)
{
WAVELENGTH = 5;
AMPLITUDE = 20;
AMPLITUDE = 40;
FREQUENCY = 8;
}
else
......@@ -6789,7 +6027,7 @@ void HWR_DoPostProcessor(player_t *player)
// Capture the screen again for screen waving on the intermission
if(gamestate != GS_INTERMISSION)
HWD.pfnMakeScreenTexture();
HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1);
}
// Flipping of the screen isn't done here anymore
}
......@@ -6797,18 +6035,18 @@ void HWR_DoPostProcessor(player_t *player)
void HWR_StartScreenWipe(void)
{
//CONS_Debug(DBG_RENDER, "In HWR_StartScreenWipe()\n");
HWD.pfnStartScreenWipe();
HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_WIPE_START);
}
void HWR_EndScreenWipe(void)
{
//CONS_Debug(DBG_RENDER, "In HWR_EndScreenWipe()\n");
HWD.pfnEndScreenWipe();
HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_WIPE_END);
}
void HWR_DrawIntermissionBG(void)
{
HWD.pfnDrawIntermissionBG();
HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC1, NULL, 0);
}
//
......@@ -6853,201 +6091,40 @@ void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum)
return;
HWR_GetFadeMask(wipelumpnum);
HWD.pfnDoScreenWipe();
}
if (wipestyle == WIPESTYLE_COLORMAP && HWR_UseShader())
{
FSurfaceInfo surf = {0};
FBITFIELD polyflags = PF_Modulated|PF_NoDepthTest;
void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum)
{
// It does the same thing
HWR_DoWipe(wipenum, scrnnum);
polyflags |= (wipestyleflags & WSF_TOWHITE) ? PF_Additive : PF_ReverseSubtract;
surf.PolyColor.s.red = FADEREDFACTOR;
surf.PolyColor.s.green = FADEGREENFACTOR;
surf.PolyColor.s.blue = FADEBLUEFACTOR;
// polycolor alpha communicates fadein / fadeout to the shader and the backend
surf.PolyColor.s.alpha = (wipestyleflags & WSF_FADEIN) ? 255 : 0;
HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_UI_TINTED_WIPE));
HWD.pfnDoScreenWipe(HWD_SCREENTEXTURE_WIPE_START, HWD_SCREENTEXTURE_WIPE_END,
&surf, polyflags);
HWD.pfnUnSetShader();
}
else
{
HWD.pfnDoScreenWipe(HWD_SCREENTEXTURE_WIPE_START, HWD_SCREENTEXTURE_WIPE_END,
NULL, 0);
}
}
void HWR_MakeScreenFinalTexture(void)
{
HWD.pfnMakeScreenFinalTexture();
int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2;
HWD.pfnMakeScreenTexture(tex);
}
void HWR_DrawScreenFinalTexture(int width, int height)
{
HWD.pfnDrawScreenFinalTexture(width, height);
}
static inline UINT16 HWR_FindShaderDefs(UINT16 wadnum)
{
UINT16 i;
lumpinfo_t *lump_p;
lump_p = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lump_p++)
if (memcmp(lump_p->name, "SHADERS", 7) == 0)
return i;
return INT16_MAX;
}
boolean HWR_CompileShaders(void)
{
return HWD.pfnCompileShaders();
}
customshaderxlat_t shaderxlat[] =
{
{"Flat", SHADER_FLOOR},
{"WallTexture", SHADER_WALL},
{"Sprite", SHADER_SPRITE},
{"Model", SHADER_MODEL},
{"ModelLighting", SHADER_MODEL_LIGHTING},
{"WaterRipple", SHADER_WATER},
{"Fog", SHADER_FOG},
{"Sky", SHADER_SKY},
{NULL, 0},
};
void HWR_LoadAllCustomShaders(void)
{
INT32 i;
// read every custom shader
for (i = 0; i < numwadfiles; i++)
HWR_LoadCustomShadersFromFile(i, W_FileHasFolders(wadfiles[i]));
}
void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3)
{
UINT16 lump;
char *shaderdef, *line;
char *stoken;
char *value;
size_t size;
int linenum = 1;
int shadertype = 0;
int i;
lump = HWR_FindShaderDefs(wadnum);
if (lump == INT16_MAX)
return;
shaderdef = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE);
size = W_LumpLengthPwad(wadnum, lump);
line = Z_Malloc(size+1, PU_STATIC, NULL);
M_Memcpy(line, shaderdef, size);
line[size] = '\0';
stoken = strtok(line, "\r\n ");
while (stoken)
{
if ((stoken[0] == '/' && stoken[1] == '/')
|| (stoken[0] == '#'))// skip comments
{
stoken = strtok(NULL, "\r\n");
goto skip_field;
}
if (!stricmp(stoken, "GLSL"))
{
value = strtok(NULL, "\r\n ");
if (!value)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
stoken = strtok(NULL, "\r\n"); // skip end of line
goto skip_lump;
}
if (!stricmp(value, "VERTEX"))
shadertype = 1;
else if (!stricmp(value, "FRAGMENT"))
shadertype = 2;
skip_lump:
stoken = strtok(NULL, "\r\n ");
linenum++;
}
else
{
value = strtok(NULL, "\r\n= ");
if (!value)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
stoken = strtok(NULL, "\r\n"); // skip end of line
goto skip_field;
}
if (!shadertype)
{
CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
Z_Free(line);
return;
}
for (i = 0; shaderxlat[i].type; i++)
{
if (!stricmp(shaderxlat[i].type, stoken))
{
size_t shader_size;
char *shader_source;
char *shader_lumpname;
UINT16 shader_lumpnum;
if (PK3)
{
shader_lumpname = Z_Malloc(strlen(value) + 12, PU_STATIC, NULL);
strcpy(shader_lumpname, "Shaders/sh_");
strcat(shader_lumpname, value);
shader_lumpnum = W_CheckNumForFullNamePK3(shader_lumpname, wadnum, 0);
}
else
{
shader_lumpname = Z_Malloc(strlen(value) + 4, PU_STATIC, NULL);
strcpy(shader_lumpname, "SH_");
strcat(shader_lumpname, value);
shader_lumpnum = W_CheckNumForNamePwad(shader_lumpname, wadnum, 0);
}
if (shader_lumpnum == INT16_MAX)
{
CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum);
Z_Free(shader_lumpname);
continue;
}
shader_size = W_LumpLengthPwad(wadnum, shader_lumpnum);
shader_source = Z_Malloc(shader_size, PU_STATIC, NULL);
W_ReadLumpPwad(wadnum, shader_lumpnum, shader_source);
HWD.pfnLoadCustomShader(shaderxlat[i].id, shader_source, shader_size, (shadertype == 2));
Z_Free(shader_source);
Z_Free(shader_lumpname);
}
}
skip_field:
stoken = strtok(NULL, "\r\n= ");
linenum++;
}
}
Z_Free(line);
return;
}
const char *HWR_GetShaderName(INT32 shader)
{
INT32 i;
if (shader)
{
for (i = 0; shaderxlat[i].type; i++)
{
if (shaderxlat[i].id == shader)
return shaderxlat[i].type;
}
return "Unknown";
}
return "Default";
int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2;
HWD.pfnDrawScreenFinalTexture(tex, width, height);
}
#endif // HWRENDER
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -35,11 +35,8 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player);
void HWR_RenderPlayerView(INT32 viewnumber, player_t *player);
void HWR_ClearSkyDome(void);
void HWR_BuildSkyDome(void);
void HWR_DrawViewBorder(INT32 clearlines);
void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum);
void HWR_InitTextureMapping(void);
void HWR_SetViewSize(void);
void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option);
void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap);
void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h);
void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap);
......@@ -48,7 +45,6 @@ void HWR_CreateStaticLightmaps(INT32 bspnum);
void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color);
void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 actualcolor, UINT8 strength);
void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32 actualcolor); // Lat: separate flags from color since color needs to be an uint to work right.
void HWR_DrawPic(INT32 x,INT32 y,lumpnum_t lumpnum);
UINT8 *HWR_GetScreenshot(void);
boolean HWR_Screenshot(const char *pathname);
......@@ -61,11 +57,11 @@ void HWR_StartScreenWipe(void);
void HWR_EndScreenWipe(void);
void HWR_DrawIntermissionBG(void);
void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum);
void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum);
void HWR_MakeScreenFinalTexture(void);
void HWR_DrawScreenFinalTexture(int width, int height);
// This stuff is put here so models can use them
boolean HWR_UseShader(void);
void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap);
UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap); // Let's see if this can work
......@@ -74,13 +70,7 @@ FBITFIELD HWR_GetBlendModeFlag(INT32 style);
FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf);
FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf);
boolean HWR_CompileShaders(void);
void HWR_LoadAllCustomShaders(void);
void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3);
const char *HWR_GetShaderName(INT32 shader);
extern customshaderxlat_t shaderxlat[];
boolean HWR_ShouldUsePaletteRendering(void);
extern CV_PossibleValue_t glanisotropicmode_cons_t[];
......@@ -103,21 +93,17 @@ extern consvar_t cv_glspritebillboarding;
extern consvar_t cv_glskydome;
extern consvar_t cv_glfakecontrast;
extern consvar_t cv_glslopecontrast;
extern consvar_t cv_glbatching;
extern consvar_t cv_glpaletterendering;
extern consvar_t cv_glpalettedepth;
extern consvar_t cv_glwireframe;
extern float gl_viewwidth, gl_viewheight, gl_baseviewwindowy;
extern float gl_viewwindowx, gl_basewindowcentery;
// BP: big hack for a test in lighting ref : 1249753487AB
extern fixed_t *hwbbox;
extern FTransform atransform;
extern float gl_viewsin, gl_viewcos;
// Render stats
extern ps_metric_t ps_hw_skyboxtime;
extern ps_metric_t ps_hw_nodesorttime;
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -390,8 +390,6 @@ static void md2_loadTexture(md2_t *model)
if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data)
{
int w = 0, h = 0;
UINT32 size;
RGBA_t *image;
#ifdef HAVE_PNG
grPatch->mipmap->format = PNG_Load(filename, &w, &h, grPatch);
......@@ -412,13 +410,19 @@ static void md2_loadTexture(md2_t *model)
grPatch->mipmap->width = (UINT16)w;
grPatch->mipmap->height = (UINT16)h;
// Lactozilla: Apply colour cube
image = grPatch->mipmap->data;
size = w*h;
while (size--)
// for palette rendering, color cube is applied in post-processing instead of here
if (!HWR_ShouldUsePaletteRendering())
{
V_CubeApply(&image->s.red, &image->s.green, &image->s.blue);
image++;
UINT32 size;
RGBA_t *image;
// Lactozilla: Apply colour cube
image = grPatch->mipmap->data;
size = w*h;
while (size--)
{
V_CubeApply(&image->s.red, &image->s.green, &image->s.blue);
image++;
}
}
}
HWD.pfnSetTexture(grPatch->mipmap);
......@@ -567,19 +571,15 @@ void HWR_LoadModels(void)
}
// Add sprite models.
// Must be 4 characters long exactly. Otherwise, it's not a sprite name.
if (len == 4)
for (i = 0; i < numsprites; i++)
{
for (i = 0; i < numsprites; i++)
if (stricmp(name, sprnames[i]) == 0)
{
if (stricmp(name, sprnames[i]) == 0)
{
md2_models[i].scale = scale;
md2_models[i].offset = offset;
md2_models[i].found = true;
strcpy(md2_models[i].filename, filename);
goto modelfound;
}
md2_models[i].scale = scale;
md2_models[i].offset = offset;
md2_models[i].found = true;
strcpy(md2_models[i].filename, filename);
goto modelfound;
}
}
......@@ -1062,42 +1062,55 @@ static boolean HWR_AllowModel(mobj_t *mobj)
static boolean HWR_CanInterpolateModel(mobj_t *mobj, model_t *model)
{
if (cv_glmodelinterpolation.value == 2) // Always interpolate
return true;
return model->interpolate[(mobj->frame & FF_FRAMEMASK)];
}
static boolean HWR_CanInterpolateSprite2(modelspr2frames_t *spr2frame)
{
if (cv_glmodelinterpolation.value == 2) // Always interpolate
return true;
return spr2frame->interpolate;
}
//
// HWR_GetModelSprite2 (see P_GetSkinSprite2)
// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
//
static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *player)
static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2)
{
UINT8 super = 0, i = 0;
if (!md2 || !md2->model)
return NULL;
if (!md2 || !md2->model || !md2->model->spr2frames || !skin)
return 0;
boolean is_super = spr2 & SPR2F_SUPER;
spr2 &= SPR2F_MASK;
if (spr2 >= free_spr2)
return NULL;
if (is_super)
{
modelspr2frames_t *frames = md2->model->superspr2frames;
if (frames && md2->model->superspr2frames[spr2].numframes)
return &md2->model->superspr2frames[spr2];
}
if (md2->model->spr2frames[spr2].numframes)
return &md2->model->spr2frames[spr2];
return NULL;
}
if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2)
static UINT16 HWR_GetModelSprite2Num(md2_t *md2, skin_t *skin, UINT16 spr2, player_t *player)
{
UINT16 super = 0;
UINT8 i = 0;
if (!md2 || !md2->model || !skin)
return 0;
while (!md2->model->spr2frames[spr2].numframes
while (!HWR_GetModelSprite2Frames(md2, spr2)
&& spr2 != SPR2_STND
&& ++i != 32) // recursion limiter
&& ++i < 32) // recursion limiter
{
if (spr2 & FF_SPR2SUPER)
if (spr2 & SPR2F_SUPER)
{
super = FF_SPR2SUPER;
spr2 &= ~FF_SPR2SUPER;
super = SPR2F_SUPER;
spr2 &= ~SPR2F_SUPER;
continue;
}
......@@ -1126,7 +1139,7 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t
}
if (i >= 32) // probably an infinite loop...
return 0;
spr2 = 0;
return spr2;
}
......@@ -1137,6 +1150,9 @@ static void adjustTextureCoords(model_t *model, patch_t *patch)
int i;
GLPatch_t *gpatch = ((GLPatch_t *)patch->hardware);
if (!gpatch)
return;
for (i = 0; i < model->numMeshes; i++)
{
int j;
......@@ -1173,6 +1189,90 @@ static void adjustTextureCoords(model_t *model, patch_t *patch)
model->max_t = gpatch->max_t;
}
static INT32 GetAnimDuration(mobj_t *mobj) //part of p_mobj's setplayermobjstate logic, used to make sure that anim durations are actually correct when the speed gets adjusted on players
{
player_t *player = mobj->player;
INT32 tics = mobj->state->tics;
if (!(mobj->frame & FF_ANIMATE) && mobj->anim_duration) //set manually by something through lua
return mobj->anim_duration;
if (!player && mobj->type == MT_TAILSOVERLAY && mobj->tracer) //so tails overlays interpolate properly
player = mobj->tracer->player;
if (player)
{
if (player->panim == PA_EDGE && (player->charflags & SF_FASTEDGE))
tics = 2;
else if (player->powers[pw_tailsfly] && (!(player->mo->eflags & MFE_UNDERWATER) || (mobj->type == MT_PLAYER))) //tailsoverlay does not get adjusted from these rules when underwater
{
if (player->fly1 > 0)
tics = 1;
else if (!(player->mo->eflags & MFE_UNDERWATER))
tics = 2;
else
tics = 4;
}
else if (!(disableSpeedAdjust || player->charflags & SF_NOSPEEDADJUST))
{
fixed_t speed;// = FixedDiv(player->speed, FixedMul(mobj->scale, player->mo->movefactor));
if (player->panim == PA_FALL)
{
speed = FixedDiv(abs(mobj->momz), mobj->scale);
if (speed < 10<<FRACBITS)
tics = 4;
else if (speed < 20<<FRACBITS)
tics = 3;
else if (speed < 30<<FRACBITS)
tics = 2;
else
tics = 1;
}
else if (player->panim == PA_ABILITY2 && player->charability2 == CA2_SPINDASH)
{
fixed_t step = (player->maxdash - player->mindash)/4;
speed = (player->dashspeed - player->mindash);
if (speed > 3*step)
tics = 1;
else if (speed > step)
tics = 2;
else
tics = 3;
}
else
{
speed = FixedDiv(player->speed, FixedMul(mobj->scale, player->mo->movefactor));
if (player->panim == PA_ROLL || player->panim == PA_JUMP)
{
if (speed > 16<<FRACBITS)
tics = 1;
else
tics = 2;
}
else if (P_IsObjectOnGround(mobj) || ((player->charability == CA_FLOAT || player->charability == CA_SLOWFALL) && player->secondjump == 1) || player->powers[pw_super]) // Only if on the ground or superflying.
{
if (player->panim == PA_WALK)
{
if (speed > 12<<FRACBITS)
tics = 2;
else if (speed > 6<<FRACBITS)
tics = 3;
else
tics = 4;
}
else if ((player->panim == PA_RUN) || (player->panim == PA_DASH))
{
if (speed > 52<<FRACBITS)
tics = 1;
else
tics = 2;
}
}
}
}
}
return tics;
}
//
// HWR_DrawModel
//
......@@ -1184,7 +1284,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
char filename[64];
INT32 frame = 0;
INT32 nextFrame = -1;
UINT8 spr2 = 0;
modelspr2frames_t *spr2frames = NULL;
FTransform p;
FSurfaceInfo Surf;
......@@ -1246,12 +1346,13 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
{
patch_t *gpatch, *blendgpatch;
GLPatch_t *hwrPatch = NULL, *hwrBlendPatch = NULL;
float durs = (float)spr->mobj->state->tics;
float durs = GetAnimDuration(spr->mobj);
float tics = (float)spr->mobj->tics;
const boolean papersprite = (R_ThingIsPaperSprite(spr->mobj) && !R_ThingIsFloorSprite(spr->mobj));
const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(spr->mobj));
const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj));
spritedef_t *sprdef;
UINT16 spr2 = 0;
spriteframe_t *sprframe;
INT32 mod;
interpmobjstate_t interp;
......@@ -1266,8 +1367,13 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
}
// Apparently people don't like jump frames like that, so back it goes
//if (tics > durs)
//durs = tics;
if (tics > durs)
durs = tics;
// Make linkdraw objects use their tracer's alpha value
fixed_t newalpha = spr->mobj->alpha;
if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
newalpha = spr->mobj->tracer->alpha;
INT32 blendmode;
if (spr->mobj->frame & FF_BLENDMASK)
......@@ -1283,6 +1389,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
Surf.PolyFlags = HWR_GetBlendModeFlag(blendmode);
}
Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
// don't forget to enable the depth test because we can't do this
// like before: model polygons are not sorted
......@@ -1414,18 +1522,28 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
tics = (float)spr->mobj->anim_duration;
}
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
sprdef = P_GetSkinSpritedef(spr->mobj->skin, spr->mobj->sprite2);
else
sprdef = &sprites[spr->mobj->sprite];
frame = (spr->mobj->frame & FF_FRAMEMASK);
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && md2->model->spr2frames)
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
{
spr2 = HWR_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player);
mod = md2->model->spr2frames[spr2].numframes;
spr2 = HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player);
spr2frames = HWR_GetModelSprite2Frames(md2, spr2);
}
if (spr2frames)
{
spritedef_t *defaultdef = P_GetSkinSpritedef(spr->mobj->skin, spr2);
mod = spr2frames->numframes;
#ifndef DONTHIDEDIFFANIMLENGTH // by default, different anim length is masked by the mod
if (mod > (INT32)((skin_t *)spr->mobj->skin)->sprites[spr2].numframes)
mod = ((skin_t *)spr->mobj->skin)->sprites[spr2].numframes;
if (mod > (INT32)defaultdef->numframes)
mod = defaultdef->numframes;
#endif
if (!mod)
mod = 1;
frame = md2->model->spr2frames[spr2].frames[frame%mod];
frame = spr2frames->frames[frame % mod];
}
else
{
......@@ -1445,13 +1563,18 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
if (durs > INTERPOLERATION_LIMIT)
durs = INTERPOLERATION_LIMIT;
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && md2->model->spr2frames)
if (spr2frames)
{
if (HWR_CanInterpolateSprite2(&md2->model->spr2frames[spr2])
UINT16 next_spr2 = P_GetStateSprite2(&states[spr->mobj->state->nextstate]);
// Add or remove SPR2F_SUPER based on certain conditions
next_spr2 = P_ApplySuperFlagToSprite2(next_spr2, spr->mobj);
if (HWR_CanInterpolateSprite2(spr2frames)
&& (spr->mobj->frame & FF_ANIMATE
|| (spr->mobj->state->nextstate != S_NULL
&& states[spr->mobj->state->nextstate].sprite == SPR_PLAY
&& ((P_GetSkinSprite2(spr->mobj->skin, (((spr->mobj->player && spr->mobj->player->powers[pw_super]) ? FF_SPR2SUPER : 0)|states[spr->mobj->state->nextstate].frame) & FF_FRAMEMASK, spr->mobj->player) == spr->mobj->sprite2)))))
&& ((P_GetSkinSprite2(spr->mobj->skin, next_spr2, spr->mobj->player) == spr->mobj->sprite2)))))
{
nextFrame = (spr->mobj->frame & FF_FRAMEMASK) + 1;
if (nextFrame >= mod)
......@@ -1462,7 +1585,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
nextFrame = 0;
}
if (frame || !(spr->mobj->state->frame & FF_SPR2ENDSTATE))
nextFrame = md2->model->spr2frames[spr2].frames[nextFrame];
nextFrame = spr2frames->frames[nextFrame];
else
nextFrame = -1;
}
......@@ -1498,11 +1621,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
else
p.z = FIXED_TO_FLOAT(interp.z);
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
sprdef = &((skin_t *)spr->mobj->skin)->sprites[spr->mobj->sprite2];
else
sprdef = &sprites[spr->mobj->sprite];
sprframe = &sprdef->spriteframes[spr->mobj->frame & FF_FRAMEMASK];
if (sprframe->rotate || papersprite)
......@@ -1550,7 +1668,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
p.flip = atransform.flip;
p.mirror = atransform.mirror;
HWD.pfnSetShader(SHADER_MODEL); // model shader
if (HWR_UseShader())
HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_MODEL));
{
float this_scale = FIXED_TO_FLOAT(interp.scale);
......@@ -1568,7 +1687,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, md2->scale * xs, md2->scale * ys, flip, hflip, &Surf);
}
}
return true;
}
......
......@@ -292,6 +292,7 @@ void LoadModelSprite2(model_t *model)
{
INT32 i;
modelspr2frames_t *spr2frames = NULL;
modelspr2frames_t *superspr2frames = NULL;
INT32 numframes = model->meshes[0].numFrames;
char *framename = model->frameNames;
......@@ -335,25 +336,33 @@ void LoadModelSprite2(model_t *model)
spr2idx = 0;
while (spr2idx < free_spr2)
{
modelspr2frames_t *frames = NULL;
if (!memcmp(spr2names[spr2idx], name, 4))
{
if (!spr2frames)
spr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES*2, PU_STATIC, NULL);
spr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES, PU_STATIC, NULL);
frames = spr2frames;
if (super)
spr2idx |= FF_SPR2SUPER;
{
if (!superspr2frames)
superspr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES, PU_STATIC, NULL);
frames = superspr2frames;
}
if (framechars[0])
{
frame = atoi(framechars);
if (spr2frames[spr2idx].numframes < frame+1)
spr2frames[spr2idx].numframes = frame+1;
if (frames[spr2idx].numframes < frame+1)
frames[spr2idx].numframes = frame+1;
}
else
{
frame = spr2frames[spr2idx].numframes;
spr2frames[spr2idx].numframes++;
frame = frames[spr2idx].numframes;
frames[spr2idx].numframes++;
}
spr2frames[spr2idx].frames[frame] = i;
spr2frames[spr2idx].interpolate = interpolate;
frames[spr2idx].frames[frame] = i;
frames[spr2idx].interpolate = interpolate;
break;
}
spr2idx++;
......@@ -366,7 +375,10 @@ void LoadModelSprite2(model_t *model)
if (model->spr2frames)
Z_Free(model->spr2frames);
if (model->superspr2frames)
Z_Free(model->superspr2frames);
model->spr2frames = spr2frames;
model->superspr2frames = superspr2frames;
}
//
......
......@@ -101,6 +101,7 @@ typedef struct model_s
char *frameNames;
boolean interpolate[256];
modelspr2frames_t *spr2frames;
modelspr2frames_t *superspr2frames;
// the max_s and max_t values that the uvs are currently adjusted to
// (if a sprite is used as a texture)
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2021-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file hw_shaders.c
/// \brief Handles the shaders used by the game.
#ifdef HWRENDER
#include "hw_glob.h"
#include "hw_drv.h"
#include "hw_shaders.h"
#include "../z_zone.h"
// ================
// Shader sources
// ================
static struct {
const char *vertex;
const char *fragment;
} const gl_shadersources[] = {
// Floor shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_FLOOR_FRAGMENT_SHADER},
// Wall shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_WALL_FRAGMENT_SHADER},
// Sprite shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_WALL_FRAGMENT_SHADER},
// Model shader
{GLSL_MODEL_VERTEX_SHADER, GLSL_MODEL_FRAGMENT_SHADER},
// Water shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_WATER_FRAGMENT_SHADER},
// Fog shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_FOG_FRAGMENT_SHADER},
// Sky shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER},
// Palette postprocess shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_PALETTE_POSTPROCESS_FRAGMENT_SHADER},
// UI colormap fade shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_COLORMAP_FADE_FRAGMENT_SHADER},
// UI tinted wipe shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_TINTED_WIPE_FRAGMENT_SHADER},
{NULL, NULL},
};
typedef struct
{
int base_shader; // index of base shader_t
int custom_shader; // index of custom shader_t
} shadertarget_t;
typedef struct
{
char *vertex;
char *fragment;
boolean compiled;
} shader_t; // these are in an array and accessed by indices
// the array has NUMSHADERTARGETS entries for base shaders and for custom shaders
// the array could be expanded in the future to fit "dynamic" custom shaders that
// aren't fixed to shader targets
static shader_t gl_shaders[NUMSHADERTARGETS*2];
static shadertarget_t gl_shadertargets[NUMSHADERTARGETS];
#define WHITESPACE_CHARS " \t"
#define MODEL_LIGHTING_DEFINE "#define SRB2_MODEL_LIGHTING"
#define PALETTE_RENDERING_DEFINE "#define SRB2_PALETTE_RENDERING"
// Initialize shader variables and the backend's shader system. Load the base shaders.
// Returns false if shaders cannot be used.
boolean HWR_InitShaders(void)
{
int i;
if (!HWD.pfnInitShaders())
return false;
for (i = 0; i < NUMSHADERTARGETS; i++)
{
// set up string pointers for base shaders
gl_shaders[i].vertex = Z_StrDup(gl_shadersources[i].vertex);
gl_shaders[i].fragment = Z_StrDup(gl_shadersources[i].fragment);
// set shader target indices to correct values
gl_shadertargets[i].base_shader = i;
gl_shadertargets[i].custom_shader = -1;
}
HWR_CompileShaders();
return true;
}
// helper function: strstr but returns an int with the substring position
// returns INT32_MAX if not found
static INT32 strstr_int(const char *str1, const char *str2)
{
char *location = strstr(str1, str2);
if (location)
return location - str1;
else
return INT32_MAX;
}
// Creates a preprocessed copy of the shader according to the current graphics settings
// Returns a pointer to the results on success and NULL on failure.
// Remember memory management of the returned string.
static char *HWR_PreprocessShader(char *original)
{
const char *line_ending = "\n";
int line_ending_len;
char *read_pos = original;
int original_len = strlen(original);
int distance_to_end = original_len;
int new_len;
char *new_shader;
char *write_pos;
char shader_glsl_version[3];
int version_pos = -1;
int version_len = 0;
if (strstr(original, "\r\n"))
{
line_ending = "\r\n";
// check if all line endings are same
while ((read_pos = strchr(read_pos, '\n')))
{
read_pos--;
if (*read_pos != '\r')
{
// this file contains mixed CRLF and LF line endings.
// treating it as a LF file during parsing should keep
// the results sane enough as long as the gpu driver is fine
// with these kinds of weirdly formatted shader sources.
line_ending = "\n";
break;
}
read_pos += 2;
}
read_pos = original;
}
line_ending_len = strlen(line_ending);
// Find the #version directive, if it exists. Also don't get fooled if it's
// inside a comment. Copy the version digits so they can be used in the preamble.
// Time for some string parsing :D
#define STARTSWITH(str, with_what) !strncmp(str, with_what, sizeof(with_what)-1)
#define ADVANCE(amount) read_pos += (amount); distance_to_end -= (amount);
while (true)
{
// we're at the start of a line or at the end of a block comment.
// first get any possible whitespace out of the way
int whitespace_len = strspn(read_pos, WHITESPACE_CHARS);
if (whitespace_len == distance_to_end)
break; // we got to the end
ADVANCE(whitespace_len)
if (STARTSWITH(read_pos, "#version"))
{
// found a version directive (and it's not inside a comment)
// now locate, verify and read the version number
int version_number_len;
version_pos = read_pos - original;
ADVANCE(sizeof("#version") - 1)
whitespace_len = strspn(read_pos, WHITESPACE_CHARS);
if (!whitespace_len)
{
CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected space after #version, but got other text.\n");
return NULL;
}
else if (whitespace_len == distance_to_end)
{
CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected version number, but got end of file.\n");
return NULL;
}
ADVANCE(whitespace_len)
version_number_len = strspn(read_pos, "0123456789");
if (!version_number_len)
{
CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected version number, but got other text.\n");
return NULL;
}
else if (version_number_len != 3)
{
CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected version with 3 digits, but got %d digits.\n", version_number_len);
return NULL;
}
M_Memcpy(shader_glsl_version, read_pos, 3);
ADVANCE(version_number_len)
version_len = (read_pos - original) - version_pos;
whitespace_len = strspn(read_pos, WHITESPACE_CHARS);
ADVANCE(whitespace_len)
if (STARTSWITH(read_pos, "es"))
{
CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Support for ES shaders is not implemented.\n");
return NULL;
}
break;
}
else
{
// go to next newline or end of next block comment if it starts before the newline
// and is not inside a line comment
INT32 newline_pos = strstr_int(read_pos, line_ending);
INT32 line_comment_pos;
INT32 block_comment_pos;
// optimization: temporarily put a null at the line ending, so strstr does not needlessly
// look past it since we're only interested in the current line
if (newline_pos != INT32_MAX)
read_pos[newline_pos] = '\0';
line_comment_pos = strstr_int(read_pos, "//");
block_comment_pos = strstr_int(read_pos, "/*");
// restore the line ending, remove the null we just put there
if (newline_pos != INT32_MAX)
read_pos[newline_pos] = line_ending[0];
if (line_comment_pos < block_comment_pos)
{
// line comment found, skip rest of the line
if (newline_pos != INT32_MAX)
{
ADVANCE(newline_pos + line_ending_len)
}
else
{
// we got to the end
break;
}
}
else if (block_comment_pos < line_comment_pos)
{
// block comment found, skip past it
INT32 block_comment_end;
ADVANCE(block_comment_pos + 2)
block_comment_end = strstr_int(read_pos, "*/");
if (block_comment_end == INT32_MAX)
{
// could also leave insertion_pos at 0 and let the GLSL compiler
// output an error message for this broken comment
CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Encountered unclosed block comment in shader.\n");
return NULL;
}
ADVANCE(block_comment_end + 2)
}
else if (newline_pos == INT32_MAX)
{
// we got to the end
break;
}
else
{
// nothing special on this line, move to the next one
ADVANCE(newline_pos + line_ending_len)
}
}
}
#undef STARTSWITH
#undef ADVANCE
#define ADD_TO_LEN(def) new_len += sizeof(def) - 1 + line_ending_len;
// Calculate length of modified shader.
new_len = original_len;
if (cv_glmodellighting.value)
ADD_TO_LEN(MODEL_LIGHTING_DEFINE)
if (cv_glpaletterendering.value)
ADD_TO_LEN(PALETTE_RENDERING_DEFINE)
#undef ADD_TO_LEN
#define VERSION_PART "#version "
if (new_len != original_len)
{
if (version_pos != -1)
new_len += sizeof(VERSION_PART) - 1 + 3 + line_ending_len;
new_len += sizeof("#line 0") - 1 + line_ending_len;
}
// Allocate memory for modified shader.
new_shader = Z_Malloc(new_len + 1, PU_STATIC, NULL);
read_pos = original;
write_pos = new_shader;
if (new_len != original_len && version_pos != -1)
{
strcpy(write_pos, VERSION_PART);
write_pos += sizeof(VERSION_PART) - 1;
M_Memcpy(write_pos, shader_glsl_version, 3);
write_pos += 3;
strcpy(write_pos, line_ending);
write_pos += line_ending_len;
}
#undef VERSION_PART
#define WRITE_DEFINE(define) \
{ \
strcpy(write_pos, define); \
write_pos += sizeof(define) - 1; \
strcpy(write_pos, line_ending); \
write_pos += line_ending_len; \
}
// Write the defines.
if (cv_glmodellighting.value)
WRITE_DEFINE(MODEL_LIGHTING_DEFINE)
if (cv_glpaletterendering.value)
WRITE_DEFINE(PALETTE_RENDERING_DEFINE)
#undef WRITE_DEFINE
// Write a #line directive, so compiler errors will report line numbers from the
// original shader without our preamble lines.
if (new_len != original_len)
{
// line numbering in the #line directive is different for versions 110-150
if (version_pos == -1 || shader_glsl_version[0] == '1')
strcpy(write_pos, "#line 0");
else
strcpy(write_pos, "#line 1");
write_pos += sizeof("#line 0") - 1;
strcpy(write_pos, line_ending);
write_pos += line_ending_len;
}
// Copy the original shader.
M_Memcpy(write_pos, read_pos, original_len);
// Erase the original #version directive, if it exists and was copied.
if (new_len != original_len && version_pos != -1)
memset(write_pos + version_pos, ' ', version_len);
// Terminate the new string.
new_shader[new_len] = '\0';
return new_shader;
}
// preprocess and compile shader at gl_shaders[index]
static void HWR_CompileShader(int index)
{
char *vertex_source = gl_shaders[index].vertex;
char *fragment_source = gl_shaders[index].fragment;
if (vertex_source)
{
char *preprocessed = HWR_PreprocessShader(vertex_source);
if (!preprocessed) return;
HWD.pfnLoadShader(index, preprocessed, HWD_SHADERSTAGE_VERTEX);
}
if (fragment_source)
{
char *preprocessed = HWR_PreprocessShader(fragment_source);
if (!preprocessed) return;
HWD.pfnLoadShader(index, preprocessed, HWD_SHADERSTAGE_FRAGMENT);
}
gl_shaders[index].compiled = HWD.pfnCompileShader(index);
}
// compile or recompile shaders
void HWR_CompileShaders(void)
{
int i;
for (i = 0; i < NUMSHADERTARGETS; i++)
{
int custom_index = gl_shadertargets[i].custom_shader;
HWR_CompileShader(i);
if (!gl_shaders[i].compiled)
CONS_Alert(CONS_ERROR, "HWR_CompileShaders: Compilation failed for base %s shader!\n", shaderxlat[i].type);
if (custom_index != -1)
{
HWR_CompileShader(custom_index);
if (!gl_shaders[custom_index].compiled)
CONS_Alert(CONS_ERROR, "HWR_CompileShaders: Recompilation failed for the custom %s shader! See the console messages above for more information.\n", shaderxlat[i].type);
}
}
}
int HWR_GetShaderFromTarget(int shader_target)
{
int custom_shader = gl_shadertargets[shader_target].custom_shader;
// use custom shader if following are true
// - custom shader exists
// - custom shader has been compiled successfully
// - custom shaders are enabled
// - custom shaders are allowed by the server
if (custom_shader != -1 && gl_shaders[custom_shader].compiled &&
cv_glshaders.value == 1 && cv_glallowshaders.value)
return custom_shader;
else
return gl_shadertargets[shader_target].base_shader;
}
static inline UINT16 HWR_FindShaderDefs(UINT16 wadnum)
{
UINT16 i;
lumpinfo_t *lump_p;
lump_p = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lump_p++)
if (memcmp(lump_p->name, "SHADERS", 7) == 0)
return i;
return INT16_MAX;
}
customshaderxlat_t shaderxlat[] =
{
{"Flat", SHADER_FLOOR},
{"WallTexture", SHADER_WALL},
{"Sprite", SHADER_SPRITE},
{"Model", SHADER_MODEL},
{"WaterRipple", SHADER_WATER},
{"Fog", SHADER_FOG},
{"Sky", SHADER_SKY},
{"PalettePostprocess", SHADER_PALETTE_POSTPROCESS},
{"UIColormapFade", SHADER_UI_COLORMAP_FADE},
{"UITintedWipe", SHADER_UI_TINTED_WIPE},
{NULL, 0},
};
void HWR_LoadAllCustomShaders(void)
{
INT32 i;
// read every custom shader
for (i = 0; i < numwadfiles; i++)
HWR_LoadCustomShadersFromFile(i, W_FileHasFolders(wadfiles[i]));
}
static const char version_directives[][14] = {
"#version 330\n",
"#version 150\n",
"#version 140\n",
"#version 130\n",
"#version 120\n",
"#version 110\n",
};
static boolean HWR_VersionDirectiveExists(const char* source)
{
return strncmp(source, "#version", 8) == 0;
}
static char* HWR_PrependVersionDirective(const char* source, UINT32 version_index)
{
const UINT32 version_len = sizeof(version_directives[version_index]) - 1;
const UINT32 source_len = strlen(source);
char* result = Z_Malloc(source_len + version_len + 1, PU_STATIC, NULL);
strcpy(result, version_directives[version_index]);
strcpy(result + version_len, source);
return result;
}
static void HWR_ReplaceVersionInplace(char* shader, UINT32 version_index)
{
shader[9] = version_directives[version_index][9];
shader[10] = version_directives[version_index][10];
shader[11] = version_directives[version_index][11];
}
static boolean HWR_CheckVersionDirectives(const char* vert, const char* frag)
{
return HWR_VersionDirectiveExists(vert) && HWR_VersionDirectiveExists(frag);
}
static void HWR_TryToCompileShaderWithImplicitVersion(INT32 shader_index, INT32 shaderxlat_id)
{
char* vert_shader = gl_shaders[shader_index].vertex;
char* frag_shader = gl_shaders[shader_index].fragment;
boolean vert_shader_version_exists = HWR_VersionDirectiveExists(vert_shader);
boolean frag_shader_version_exists = HWR_VersionDirectiveExists(frag_shader);
if(!vert_shader_version_exists) {
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: vertex shader '%s' is missing a #version directive\n", HWR_GetShaderName(shaderxlat_id));
}
if(!frag_shader_version_exists) {
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: fragment shader '%s' is missing a #version directive\n", HWR_GetShaderName(shaderxlat_id));
}
// try to compile as is
HWR_CompileShader(shader_index);
if (gl_shaders[shader_index].compiled)
return;
// try each version directive
for(UINT32 i = 0; i < sizeof(version_directives) / sizeof(version_directives[0]); ++i) {
CONS_Alert(CONS_NOTICE, "HWR_TryToCompileShaderWithImplicitVersion: Trying %s\n", version_directives[i]);
if(!vert_shader_version_exists) {
// first time reallocation would have to be made
if(i == 0) {
void* old = (void*)gl_shaders[shader_index].vertex;
vert_shader = gl_shaders[shader_index].vertex = HWR_PrependVersionDirective(vert_shader, i);
Z_Free(old);
} else {
HWR_ReplaceVersionInplace(vert_shader, i);
}
}
if(!frag_shader_version_exists) {
if(i == 0) {
void* old = (void*)gl_shaders[shader_index].fragment;
frag_shader = gl_shaders[shader_index].fragment = HWR_PrependVersionDirective(frag_shader, i);
Z_Free(old);
} else {
HWR_ReplaceVersionInplace(frag_shader, i);
}
}
HWR_CompileShader(shader_index);
if (gl_shaders[shader_index].compiled) {
CONS_Alert(CONS_NOTICE, "HWR_TryToCompileShaderWithImplicitVersion: Compiled with %s\n",
version_directives[i]);
CONS_Alert(CONS_WARNING, "Implicit GLSL version is used. Correct behavior is not guaranteed\n");
return;
}
}
}
void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3)
{
UINT16 lump;
char *shaderdef, *line;
char *stoken;
char *value;
size_t size;
int linenum = 1;
int shadertype = 0;
int i;
boolean modified_shaders[NUMSHADERTARGETS] = {0};
if (!gl_shadersavailable)
return;
lump = HWR_FindShaderDefs(wadnum);
if (lump == INT16_MAX)
return;
shaderdef = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE);
size = W_LumpLengthPwad(wadnum, lump);
line = Z_Malloc(size+1, PU_STATIC, NULL);
M_Memcpy(line, shaderdef, size);
line[size] = '\0';
stoken = strtok(line, "\r\n ");
while (stoken)
{
if ((stoken[0] == '/' && stoken[1] == '/')
|| (stoken[0] == '#'))// skip comments
{
stoken = strtok(NULL, "\r\n");
goto skip_field;
}
if (!stricmp(stoken, "GLSL"))
{
value = strtok(NULL, "\r\n ");
if (!value)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
stoken = strtok(NULL, "\r\n"); // skip end of line
goto skip_lump;
}
if (!stricmp(value, "VERTEX"))
shadertype = 1;
else if (!stricmp(value, "FRAGMENT"))
shadertype = 2;
skip_lump:
stoken = strtok(NULL, "\r\n ");
linenum++;
}
else
{
value = strtok(NULL, "\r\n= ");
if (!value)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
stoken = strtok(NULL, "\r\n"); // skip end of line
goto skip_field;
}
if (!shadertype)
{
CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
Z_Free(line);
return;
}
for (i = 0; shaderxlat[i].type; i++)
{
if (!stricmp(shaderxlat[i].type, stoken))
{
size_t shader_string_length;
char *shader_source;
char *shader_lumpname;
UINT16 shader_lumpnum;
int shader_index; // index in gl_shaders
if (PK3)
{
shader_lumpname = Z_Malloc(strlen(value) + 12, PU_STATIC, NULL);
strcpy(shader_lumpname, "Shaders/sh_");
strcat(shader_lumpname, value);
shader_lumpnum = W_CheckNumForFullNamePK3(shader_lumpname, wadnum, 0);
}
else
{
shader_lumpname = Z_Malloc(strlen(value) + 4, PU_STATIC, NULL);
strcpy(shader_lumpname, "SH_");
strcat(shader_lumpname, value);
shader_lumpnum = W_CheckNumForNamePwad(shader_lumpname, wadnum, 0);
}
if (shader_lumpnum == INT16_MAX)
{
CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum);
Z_Free(shader_lumpname);
continue;
}
shader_string_length = W_LumpLengthPwad(wadnum, shader_lumpnum) + 1;
shader_source = Z_Malloc(shader_string_length, PU_STATIC, NULL);
W_ReadLumpPwad(wadnum, shader_lumpnum, shader_source);
shader_source[shader_string_length-1] = '\0';
shader_index = shaderxlat[i].id + NUMSHADERTARGETS;
if (!modified_shaders[shaderxlat[i].id])
{
// this will clear any old custom shaders from previously loaded files
// Z_Free checks if the pointer is NULL!
Z_Free(gl_shaders[shader_index].vertex);
gl_shaders[shader_index].vertex = NULL;
Z_Free(gl_shaders[shader_index].fragment);
gl_shaders[shader_index].fragment = NULL;
}
modified_shaders[shaderxlat[i].id] = true;
if (shadertype == 1)
{
if (gl_shaders[shader_index].vertex)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: %s is overwriting another %s vertex shader from the same addon! (file %s, line %d)\n", shader_lumpname, shaderxlat[i].type, wadfiles[wadnum]->filename, linenum);
Z_Free(gl_shaders[shader_index].vertex);
}
gl_shaders[shader_index].vertex = shader_source;
}
else
{
if (gl_shaders[shader_index].fragment)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: %s is overwriting another %s fragment shader from the same addon! (file %s, line %d)\n", shader_lumpname, shaderxlat[i].type, wadfiles[wadnum]->filename, linenum);
Z_Free(gl_shaders[shader_index].fragment);
}
gl_shaders[shader_index].fragment = shader_source;
}
Z_Free(shader_lumpname);
}
}
skip_field:
stoken = strtok(NULL, "\r\n= ");
linenum++;
}
}
for (i = 0; i < NUMSHADERTARGETS; i++)
{
if (modified_shaders[i])
{
int shader_index = i + NUMSHADERTARGETS; // index to gl_shaders
gl_shadertargets[i].custom_shader = shader_index;
// if only one stage (vertex/fragment) is defined, the other one
// is copied from the base shaders.
if (!gl_shaders[shader_index].fragment)
gl_shaders[shader_index].fragment = Z_StrDup(gl_shadersources[i].fragment);
if (!gl_shaders[shader_index].vertex)
gl_shaders[shader_index].vertex = Z_StrDup(gl_shadersources[i].vertex);
if(!HWR_CheckVersionDirectives(gl_shaders[shader_index].vertex, gl_shaders[shader_index].fragment)) {
HWR_TryToCompileShaderWithImplicitVersion(shader_index, i);
} else {
HWR_CompileShader(shader_index);
}
if (!gl_shaders[shader_index].compiled)
CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: A compilation error occured for the %s shader in file %s. See the console messages above for more information.\n", shaderxlat[i].type, wadfiles[wadnum]->filename);
}
}
Z_Free(line);
return;
}
const char *HWR_GetShaderName(INT32 shader)
{
INT32 i;
for (i = 0; shaderxlat[i].type; i++)
{
if (shaderxlat[i].id == shader)
return shaderxlat[i].type;
}
return "Unknown";
}
#endif // HWRENDER
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2021-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file hw_shaders.h
/// \brief Handles the shaders used by the game.
#ifndef _HW_SHADERS_H_
#define _HW_SHADERS_H_
#include "../doomtype.h"
// ================
// Vertex shaders
// ================
//
// Generic vertex shader
//
#define GLSL_DEFAULT_VERTEX_SHADER \
"void main()\n" \
"{\n" \
"gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
"gl_FrontColor = gl_Color;\n" \
"gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \
"gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
"}\0"
// replicates the way fixed function lighting is used by the model lighting option,
// stores the lighting result to gl_Color
// (ambient lighting of 0.75 and diffuse lighting from above)
#define GLSL_MODEL_VERTEX_SHADER \
"void main()\n" \
"{\n" \
"#ifdef SRB2_MODEL_LIGHTING\n" \
"float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \
"float light = min(0.75 + max(nDotVP, 0.0), 1.0);\n" \
"gl_FrontColor = vec4(light, light, light, 1.0);\n" \
"#else\n" \
"gl_FrontColor = gl_Color;\n" \
"#endif\n" \
"gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
"gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \
"gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
"}\0"
// ==================
// Fragment shaders
// ==================
//
// Generic fragment shader
//
#define GLSL_DEFAULT_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"void main(void) {\n" \
"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \
"}\0"
//
// Software fragment shader
//
// Include GLSL_FLOOR_FUDGES or GLSL_WALL_FUDGES or define the fudges in shaders that use this macro.
#define GLSL_DOOM_COLORMAP \
"float R_DoomColormap(float light, float z)\n" \
"{\n" \
"float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \
"float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \
"float startmap = (15.0 - lightnum) * 4.0;\n" \
"float scale = 160.0 / (lightz + 1.0);\n" \
"float cap = (155.0 - light) * 0.26;\n" \
"return max(startmap * STARTMAP_FUDGE - scale * 0.5 * SCALE_FUDGE, cap);\n" \
"}\n"
// lighting cap adjustment:
// first num (155.0), increase to make it start to go dark sooner
// second num (0.26), increase to make it go dark faster
#define GLSL_DOOM_LIGHT_EQUATION \
"float R_DoomLightingEquation(float light)\n" \
"{\n" \
"float z = gl_FragCoord.z / gl_FragCoord.w;\n" \
"float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \
"return clamp(colormap, 0.0, 31.0) / 32.0;\n" \
"}\n"
#define GLSL_SOFTWARE_TINT_EQUATION \
"if (tint_color.a > 0.0) {\n" \
"float color_bright = sqrt((base_color.r * base_color.r) + (base_color.g * base_color.g) + (base_color.b * base_color.b));\n" \
"float strength = sqrt(tint_color.a);\n" \
"final_color.r = clamp((color_bright * (tint_color.r * strength)) + (base_color.r * (1.0 - strength)), 0.0, 1.0);\n" \
"final_color.g = clamp((color_bright * (tint_color.g * strength)) + (base_color.g * (1.0 - strength)), 0.0, 1.0);\n" \
"final_color.b = clamp((color_bright * (tint_color.b * strength)) + (base_color.b * (1.0 - strength)), 0.0, 1.0);\n" \
"}\n"
#define GLSL_SOFTWARE_FADE_EQUATION \
"float darkness = R_DoomLightingEquation(lighting);\n" \
"if (fade_start != 0.0 || fade_end != 31.0) {\n" \
"float fs = fade_start / 31.0;\n" \
"float fe = fade_end / 31.0;\n" \
"float fd = fe - fs;\n" \
"darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \
"}\n" \
"final_color = mix(final_color, fade_color, darkness);\n"
#define GLSL_PALETTE_RENDERING \
"float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \
"float z = gl_FragCoord.z / gl_FragCoord.w;\n" \
"float light_y = clamp(floor(R_DoomColormap(lighting, z)), 0.0, 31.0);\n" \
"vec2 lighttable_coord = vec2((tex_pal_idx + 0.5) / 256.0, (light_y + 0.5) / 32.0);\n" \
"vec4 final_color = texture2D(lighttable_tex, lighttable_coord);\n" \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
#define GLSL_SOFTWARE_FRAGMENT_SHADER \
"#ifdef SRB2_PALETTE_RENDERING\n" \
"uniform sampler2D tex;\n" \
"uniform sampler3D palette_lookup_tex;\n" \
"uniform sampler2D lighttable_tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform float lighting;\n" \
GLSL_DOOM_COLORMAP \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
GLSL_PALETTE_RENDERING \
"}\n" \
"#else\n" \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\n" \
"#endif\0"
// hand tuned adjustments for light level calculation
#define GLSL_FLOOR_FUDGES \
"#define STARTMAP_FUDGE 1.06\n" \
"#define SCALE_FUDGE 1.15\n"
#define GLSL_WALL_FUDGES \
"#define STARTMAP_FUDGE 1.05\n" \
"#define SCALE_FUDGE 2.2\n"
#define GLSL_FLOOR_FRAGMENT_SHADER \
GLSL_FLOOR_FUDGES \
GLSL_SOFTWARE_FRAGMENT_SHADER
#define GLSL_WALL_FRAGMENT_SHADER \
GLSL_WALL_FUDGES \
GLSL_SOFTWARE_FRAGMENT_SHADER
// same as above but multiplies results with the lighting value from the
// accompanying vertex shader (stored in gl_Color) if model lighting is enabled
#define GLSL_MODEL_FRAGMENT_SHADER \
GLSL_WALL_FUDGES \
"#ifdef SRB2_PALETTE_RENDERING\n" \
"uniform sampler2D tex;\n" \
"uniform sampler3D palette_lookup_tex;\n" \
"uniform sampler2D lighttable_tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform float lighting;\n" \
GLSL_DOOM_COLORMAP \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"#ifdef SRB2_MODEL_LIGHTING\n" \
"texel *= gl_Color;\n" \
"#endif\n" \
GLSL_PALETTE_RENDERING \
"}\n" \
"#else\n" \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"#ifdef SRB2_MODEL_LIGHTING\n" \
"final_color *= gl_Color;\n" \
"#endif\n" \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\n" \
"#endif\0"
//
// Water surface shader
//
// Mostly guesstimated, rather than the rest being built off Software science.
// Still needs to distort things underneath/around the water...
//
#define GLSL_WATER_TEXEL \
"float water_z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \
"float a = -pi * (water_z * freq) + (leveltime * speed);\n" \
"float sdistort = sin(a) * amp;\n" \
"float cdistort = cos(a) * amp;\n" \
"vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n"
#define GLSL_WATER_FRAGMENT_SHADER \
GLSL_FLOOR_FUDGES \
"const float freq = 0.025;\n" \
"const float amp = 0.025;\n" \
"const float speed = 2.0;\n" \
"const float pi = 3.14159;\n" \
"#ifdef SRB2_PALETTE_RENDERING\n" \
"uniform sampler2D tex;\n" \
"uniform sampler3D palette_lookup_tex;\n" \
"uniform sampler2D lighttable_tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform float lighting;\n" \
"uniform float leveltime;\n" \
GLSL_DOOM_COLORMAP \
"void main(void) {\n" \
GLSL_WATER_TEXEL \
GLSL_PALETTE_RENDERING \
"}\n" \
"#else\n" \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
"uniform float leveltime;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
GLSL_WATER_TEXEL \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\n" \
"#endif\0"
//
// Fog block shader
//
// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha
//
// The floor fudges are used, but should the wall fudges be used instead? or something inbetween?
// or separate values for floors and walls? (need to change more than this shader for that)
#define GLSL_FOG_FRAGMENT_SHADER \
GLSL_FLOOR_FUDGES \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 base_color = gl_Color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Sky fragment shader
// Modulates poly_color with gl_Color
//
#define GLSL_SKY_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"void main(void) {\n" \
"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \
"}\0"
// Shader for the palette rendering postprocess step
#define GLSL_PALETTE_POSTPROCESS_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform sampler3D palette_lookup_tex;\n" \
"uniform sampler1D palette_tex;\n" \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \
"float palette_coord = (tex_pal_idx + 0.5) / 256.0;\n" \
"vec4 final_color = texture1D(palette_tex, palette_coord);\n" \
"gl_FragColor = final_color;\n" \
"}\0"
// Applies a palettized colormap fade to tex
#define GLSL_UI_COLORMAP_FADE_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform float lighting;\n" \
"uniform sampler3D palette_lookup_tex;\n" \
"uniform sampler2D lighttable_tex;\n" \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \
"vec2 lighttable_coord = vec2((tex_pal_idx + 0.5) / 256.0, (lighting + 0.5) / 32.0);\n" \
"gl_FragColor = texture2D(lighttable_tex, lighttable_coord);\n" \
"}\0"
// For wipes that use additive and subtractive blending.
// alpha_factor = 31 * 8 / 10 = 24.8
// Calculated based on the use of the "fade" variable from the GETCOLOR macro
// in r_data.c:R_CreateFadeColormaps.
// However this value created some ugliness in fades to white (special stage entry)
// while palette rendering is enabled, so I raised the value just a bit.
#define GLSL_UI_TINTED_WIPE_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"const float alpha_factor = 24.875;\n" \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"vec4 final_color = poly_color;\n" \
"float alpha = texel.a;\n" \
"if (final_color.a >= 0.5)\n" \
"alpha = 1.0 - alpha;\n" \
"alpha *= alpha_factor;\n" \
"final_color *= alpha;\n" \
"final_color.a = 1.0;\n" \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Generic vertex shader
//
#define GLSL_FALLBACK_VERTEX_SHADER \
"void main()\n" \
"{\n" \
"gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
"gl_FrontColor = gl_Color;\n" \
"gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \
"gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
"}\0"
//
// Generic fragment shader
//
#define GLSL_FALLBACK_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"void main(void) {\n" \
"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \
"}\0"
//
// Software fragment shader
//
#define GLSL_SOFTWARE_FADE_EQUATION \
"float darkness = R_DoomLightingEquation(lighting);\n" \
"if (fade_start != 0.0 || fade_end != 31.0) {\n" \
"float fs = fade_start / 31.0;\n" \
"float fe = fade_end / 31.0;\n" \
"float fd = fe - fs;\n" \
"darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \
"}\n" \
"final_color = mix(final_color, fade_color, darkness);\n"
// same as above but multiplies results with the lighting value from the
// accompanying vertex shader (stored in gl_Color)
#define GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"final_color *= gl_Color;\n" \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Sky fragment shader
// Modulates poly_color with gl_Color
//
#define GLSL_SKY_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"void main(void) {\n" \
"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \
"}\0"
#endif
......@@ -117,7 +117,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, // handle to DLL module
#define pwglDeleteContext wglDeleteContext;
#define pwglMakeCurrent wglMakeCurrent;
#else
static HMODULE OGL32, GLU32;
static HMODULE OGL32;
typedef void *(WINAPI *PFNwglGetProcAddress) (const char *);
static PFNwglGetProcAddress pwglGetProcAddress;
typedef HGLRC (WINAPI *PFNwglCreateContext) (HDC hdc);
......@@ -132,13 +132,6 @@ static PFNwglMakeCurrent pwglMakeCurrent;
void *GetGLFunc(const char *proc)
{
void *func = NULL;
if (strncmp(proc, "glu", 3) == 0)
{
if (GLU32)
func = GetProcAddress(GLU32, proc);
else
return NULL;
}
if (pwglGetProcAddress)
func = pwglGetProcAddress(proc);
if (!func)
......@@ -155,8 +148,6 @@ boolean LoadGL(void)
if (!OGL32)
return 0;
GLU32 = LoadLibrary("GLU32.DLL");
pwglGetProcAddress = GetGLFunc("wglGetProcAddress");
pwglCreateContext = GetGLFunc("wglCreateContext");
pwglDeleteContext = GetGLFunc("wglDeleteContext");
......@@ -528,7 +519,6 @@ EXPORT void HWRAPI(Shutdown) (void)
ReleaseDC(hWnd, hDC);
hDC = NULL;
}
FreeLibrary(GLU32);
FreeLibrary(OGL32);
GL_DBG_Printf ("HWRAPI Shutdown(DONE)\n");
}
......
......@@ -24,6 +24,7 @@
#include "../../r_local.h" // For rendertimefrac, used for the leveltime shader uniform
#include "r_opengl.h"
#include "r_vbo.h"
#include "../hw_shaders.h"
#if defined (HWRENDER) && !defined (NOROPENGL)
......@@ -35,12 +36,21 @@ struct GLRGBAFloat
GLfloat alpha;
};
typedef struct GLRGBAFloat GLRGBAFloat;
static const GLubyte white[4] = { 255, 255, 255, 255 };
// lighttable list item
struct LTListItem
{
UINT32 id;
struct LTListItem *next;
};
typedef struct LTListItem LTListItem;
// ==========================================================================
// CONSTANTS
// ==========================================================================
static const GLubyte white[4] = { 255, 255, 255, 255 };
// With OpenGL 1.1+, the first texture should be 1
static GLuint NOTEXTURE_NUM = 0;
......@@ -56,6 +66,7 @@ static float NEAR_CLIPPING_PLANE = NZCLIP_PLANE;
static GLuint tex_downloaded = 0;
static GLuint lt_downloaded = 0; // currently bound lighttable texture
static GLfloat fov = 90.0f;
static FBITFIELD CurrentPolyFlags;
......@@ -66,7 +77,15 @@ static FTextureInfo *TexCacheHead = NULL;
static RGBA_t *textureBuffer = NULL;
static size_t textureBufferSize = 0;
RGBA_t myPaletteData[256];
// Linked list of all lighttables.
static LTListItem *LightTablesTail = NULL;
static LTListItem *LightTablesHead = NULL;
static RGBA_t screenPalette[256] = {0}; // the palette for the postprocessing step in palette rendering
static GLuint screenPaletteTex = 0; // 1D texture containing the screen palette
static GLuint paletteLookupTex = 0; // 3D texture containing RGB -> palette index lookup table
RGBA_t myPaletteData[256]; // the palette for converting textures to RGBA
GLint screen_width = 0; // used by Draw2DLine()
GLint screen_height = 0;
GLbyte screen_depth = 0;
......@@ -77,6 +96,7 @@ static GLint min_filter = GL_LINEAR;
static GLint mag_filter = GL_LINEAR;
static GLint anisotropic_filter = 0;
static boolean model_lighting = false;
boolean supportMipMap = false;
const GLubyte *gl_version = NULL;
const GLubyte *gl_renderer = NULL;
......@@ -91,10 +111,7 @@ static GLint viewport[4];
// flush all of the stored textures, leaving them unavailable at times such as between levels
// These need to start at 0 and be set to their number, and be reset to 0 when deleted so that intel GPUs
// can know when the textures aren't there, as textures are always considered resident in their virtual memory
static GLuint screentexture = 0;
static GLuint startScreenWipe = 0;
static GLuint endScreenWipe = 0;
static GLuint finalScreenTexture = 0;
static GLuint screenTextures[NUMSCREENTEXTURES] = {0};
// shortcut for ((float)1/i)
static const GLfloat byte2float[256] = {
......@@ -164,7 +181,7 @@ FUNCPRINTF void GL_DBG_Printf(const char *format, ...)
// GL_MSG_Warning : Raises a warning.
// -----------------+
static void GL_MSG_Warning(const char *format, ...)
FUNCPRINTF static void GL_MSG_Warning(const char *format, ...)
{
char str[4096] = "";
va_list arglist;
......@@ -187,7 +204,7 @@ static void GL_MSG_Warning(const char *format, ...)
// GL_MSG_Error : Raises an error.
// -----------------+
static void GL_MSG_Error(const char *format, ...)
FUNCPRINTF static void GL_MSG_Error(const char *format, ...)
{
char str[4096] = "";
va_list arglist;
......@@ -378,10 +395,14 @@ typedef void (APIENTRY * PFNglTexEnvi) (GLenum target, GLenum pname, GLint param
static PFNglTexEnvi pglTexEnvi;
typedef void (APIENTRY * PFNglTexParameteri) (GLenum target, GLenum pname, GLint param);
static PFNglTexParameteri pglTexParameteri;
typedef void (APIENTRY * PFNglTexImage1D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
static PFNglTexImage1D pglTexImage1D;
typedef void (APIENTRY * PFNglTexImage2D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
static PFNglTexImage2D pglTexImage2D;
typedef void (APIENTRY * PFNglTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
static PFNglTexSubImage2D pglTexSubImage2D;
typedef void (APIENTRY * PFNglGetTexImage) (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
static PFNglGetTexImage pglGetTexImage;
/* 1.1 functions */
/* texture objects */ //GL_EXT_texture_object
......@@ -397,9 +418,10 @@ static PFNglCopyTexImage2D pglCopyTexImage2D;
typedef void (APIENTRY * PFNglCopyTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
static PFNglCopyTexSubImage2D pglCopyTexSubImage2D;
#endif
/* GLU functions */
typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
static PFNgluBuild2DMipmaps pgluBuild2DMipmaps;
/* 1.2 functions for 3D textures */
typedef void (APIENTRY * PFNglTexImage3D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
static PFNglTexImage3D pglTexImage3D;
/* 1.3 functions for multitexturing */
typedef void (APIENTRY *PFNglActiveTexture) (GLenum);
......@@ -445,6 +467,9 @@ static PFNglBlendEquation pglBlendEquation;
#ifndef GL_TEXTURE1
#define GL_TEXTURE1 0x84C1
#endif
#ifndef GL_TEXTURE2
#define GL_TEXTURE2 0x84C2
#endif
/* 1.5 Parms */
#ifndef GL_ARRAY_BUFFER
......@@ -517,8 +542,10 @@ boolean SetupGLfunc(void)
GETOPENGLFUNC(pglTexEnvi, glTexEnvi)
GETOPENGLFUNC(pglTexParameteri, glTexParameteri)
GETOPENGLFUNC(pglTexImage1D, glTexImage1D)
GETOPENGLFUNC(pglTexImage2D, glTexImage2D)
GETOPENGLFUNC(pglTexSubImage2D, glTexSubImage2D)
GETOPENGLFUNC(pglGetTexImage, glGetTexImage)
GETOPENGLFUNC(pglGenTextures, glGenTextures)
GETOPENGLFUNC(pglDeleteTextures, glDeleteTextures)
......@@ -534,7 +561,7 @@ boolean SetupGLfunc(void)
}
static boolean gl_shadersenabled = false;
static hwdshaderoption_t gl_allowshaders = HWD_SHADEROPTION_OFF;
static INT32 gl_allowshaders = 0;
#ifdef GL_SHADERS
typedef GLuint (APIENTRY *PFNglCreateShader) (GLenum);
......@@ -592,7 +619,12 @@ typedef enum
gluniform_fade_start,
gluniform_fade_end,
// misc. (custom shaders)
// palette rendering
gluniform_palette_tex, // 1d texture containing a palette
gluniform_palette_lookup_tex, // 3d texture containing the rgb->index lookup table
gluniform_lighttable_tex, // 2d texture containing a light table
// misc.
gluniform_leveltime,
gluniform_max,
......@@ -600,14 +632,15 @@ typedef enum
typedef struct gl_shader_s
{
char *vertex_shader;
char *fragment_shader;
GLuint program;
GLint uniforms[gluniform_max+1];
boolean custom;
} gl_shader_t;
static gl_shader_t gl_shaders[HWR_MAXSHADERS];
static gl_shader_t gl_usershaders[HWR_MAXSHADERS];
static shadersource_t gl_customshaders[HWR_MAXSHADERS];
static gl_shader_t gl_fallback_shader;
// 09102020
typedef struct gl_shaderstate_s
......@@ -623,253 +656,19 @@ static gl_shaderstate_t gl_shaderstate;
static float shader_leveltime = 0;
// Lactozilla: Shader functions
static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader);
static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i);
static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum);
static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade);
static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f};
// ================
// Vertex shaders
// ================
//
// Generic vertex shader
//
#define GLSL_DEFAULT_VERTEX_SHADER \
"void main()\n" \
"{\n" \
"gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
"gl_FrontColor = gl_Color;\n" \
"gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \
"gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
"}\0"
// replicates the way fixed function lighting is used by the model lighting option,
// stores the lighting result to gl_Color
// (ambient lighting of 0.75 and diffuse lighting from above)
#define GLSL_MODEL_LIGHTING_VERTEX_SHADER \
"void main()\n" \
"{\n" \
"float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \
"float light = 0.75 + max(nDotVP, 0.0);\n" \
"gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
"gl_FrontColor = vec4(light, light, light, 1.0);\n" \
"gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \
"gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
"}\0"
// ==================
// Fragment shaders
// ==================
//
// Generic fragment shader
//
#define GLSL_DEFAULT_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"void main(void) {\n" \
"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \
"}\0"
//
// Software fragment shader
//
#define GLSL_DOOM_COLORMAP \
"float R_DoomColormap(float light, float z)\n" \
"{\n" \
"float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \
"float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \
"float startmap = (15.0 - lightnum) * 4.0;\n" \
"float scale = 160.0 / (lightz + 1.0);\n" \
"return startmap - scale * 0.5;\n" \
"}\n"
#define GLSL_DOOM_LIGHT_EQUATION \
"float R_DoomLightingEquation(float light)\n" \
"{\n" \
"float z = gl_FragCoord.z / gl_FragCoord.w;\n" \
"float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \
"return clamp(colormap, 0.0, 31.0) / 32.0;\n" \
"}\n"
#define GLSL_SOFTWARE_TINT_EQUATION \
"if (tint_color.a > 0.0) {\n" \
"float color_bright = sqrt((base_color.r * base_color.r) + (base_color.g * base_color.g) + (base_color.b * base_color.b));\n" \
"float strength = sqrt(tint_color.a);\n" \
"final_color.r = clamp((color_bright * (tint_color.r * strength)) + (base_color.r * (1.0 - strength)), 0.0, 1.0);\n" \
"final_color.g = clamp((color_bright * (tint_color.g * strength)) + (base_color.g * (1.0 - strength)), 0.0, 1.0);\n" \
"final_color.b = clamp((color_bright * (tint_color.b * strength)) + (base_color.b * (1.0 - strength)), 0.0, 1.0);\n" \
"}\n"
#define GLSL_SOFTWARE_FADE_EQUATION \
"float darkness = R_DoomLightingEquation(lighting);\n" \
"if (fade_start != 0.0 || fade_end != 31.0) {\n" \
"float fs = fade_start / 31.0;\n" \
"float fe = fade_end / 31.0;\n" \
"float fd = fe - fs;\n" \
"darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \
"}\n" \
"final_color = mix(final_color, fade_color, darkness);\n"
#define GLSL_SOFTWARE_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\0"
// same as above but multiplies results with the lighting value from the
// accompanying vertex shader (stored in gl_Color)
#define GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"final_color *= gl_Color;\n" \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Water surface shader
//
// Mostly guesstimated, rather than the rest being built off Software science.
// Still needs to distort things underneath/around the water...
//
#define GLSL_WATER_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
"uniform float leveltime;\n" \
"const float freq = 0.025;\n" \
"const float amp = 0.025;\n" \
"const float speed = 2.0;\n" \
"const float pi = 3.14159;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"float z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \
"float a = -pi * (z * freq) + (leveltime * speed);\n" \
"float sdistort = sin(a) * amp;\n" \
"float cdistort = cos(a) * amp;\n" \
"vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Fog block shader
//
// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha
//
#define GLSL_FOG_FRAGMENT_SHADER \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 base_color = gl_Color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Sky fragment shader
// Modulates poly_color with gl_Color
//
#define GLSL_SKY_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"void main(void) {\n" \
"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \
"}\0"
// ================
// Shader sources
// ================
static struct {
const char *vertex;
const char *fragment;
} const gl_shadersources[] = {
// Default shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_DEFAULT_FRAGMENT_SHADER},
// Floor shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
// Wall shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
// Sprite shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
// Model shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
// Model shader + diffuse lighting from above
{GLSL_MODEL_LIGHTING_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER},
// Water shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_WATER_FRAGMENT_SHADER},
// Fog shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_FOG_FRAGMENT_SHADER},
// Sky shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER},
{NULL, NULL},
};
#endif // GL_SHADERS
void SetupGLFunc4(void)
{
/* 1.2 funcs */
pglTexImage3D = GetGLFunc("glTexImage3D");
/* 1.3 funcs */
pglActiveTexture = GetGLFunc("glActiveTexture");
pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f");
pglClientActiveTexture = GetGLFunc("glClientActiveTexture");
......@@ -907,64 +706,77 @@ void SetupGLFunc4(void)
pglUniform3fv = GetGLFunc("glUniform3fv");
pglGetUniformLocation = GetGLFunc("glGetUniformLocation");
#endif
// GLU
pgluBuild2DMipmaps = GetGLFunc("gluBuild2DMipmaps");
}
EXPORT boolean HWRAPI(CompileShaders) (void)
EXPORT boolean HWRAPI(InitShaders) (void)
{
#ifdef GL_SHADERS
GLint i;
if (!pglUseProgram)
return false;
gl_customshaders[SHADER_DEFAULT].vertex = NULL;
gl_customshaders[SHADER_DEFAULT].fragment = NULL;
gl_fallback_shader.vertex_shader = Z_StrDup(GLSL_FALLBACK_VERTEX_SHADER);
gl_fallback_shader.fragment_shader = Z_StrDup(GLSL_FALLBACK_FRAGMENT_SHADER);
for (i = 0; gl_shadersources[i].vertex && gl_shadersources[i].fragment; i++)
if (!Shader_CompileProgram(&gl_fallback_shader, -1))
{
gl_shader_t *shader, *usershader;
const GLchar *vert_shader = gl_shadersources[i].vertex;
const GLchar *frag_shader = gl_shadersources[i].fragment;
GL_MSG_Error("Failed to compile the fallback shader program!\n");
return false;
}
if (i >= HWR_MAXSHADERS)
break;
return true;
#else
return false;
#endif
}
shader = &gl_shaders[i];
usershader = &gl_usershaders[i];
EXPORT void HWRAPI(LoadShader) (int slot, char *code, hwdshaderstage_t stage)
{
#ifdef GL_SHADERS
gl_shader_t *shader;
if (shader->program)
pglDeleteProgram(shader->program);
if (usershader->program)
pglDeleteProgram(usershader->program);
if (slot < 0 || slot >= HWR_MAXSHADERS)
I_Error("LoadShader: Invalid slot %d", slot);
shader->program = 0;
usershader->program = 0;
shader = &gl_shaders[slot];
if (!Shader_CompileProgram(shader, i, vert_shader, frag_shader))
shader->program = 0;
#define LOADSHADER(source) { \
if (shader->source) \
Z_Free(shader->source); \
shader->source = code; \
}
// Compile custom shader
if ((i == SHADER_DEFAULT) || !(gl_customshaders[i].vertex || gl_customshaders[i].fragment))
continue;
if (stage == HWD_SHADERSTAGE_VERTEX)
LOADSHADER(vertex_shader)
else if (stage == HWD_SHADERSTAGE_FRAGMENT)
LOADSHADER(fragment_shader)
else
I_Error("LoadShader: invalid shader stage");
// 18032019
if (gl_customshaders[i].vertex)
vert_shader = gl_customshaders[i].vertex;
if (gl_customshaders[i].fragment)
frag_shader = gl_customshaders[i].fragment;
#undef LOADSHADER
#else
(void)slot;
(void)code;
(void)stage;
#endif
}
if (!Shader_CompileProgram(usershader, i, vert_shader, frag_shader))
{
GL_MSG_Warning("CompileShaders: Could not compile custom shader program for %s\n", HWR_GetShaderName(i));
usershader->program = 0;
}
}
EXPORT boolean HWRAPI(CompileShader) (int slot)
{
#ifdef GL_SHADERS
if (slot < 0 || slot >= HWR_MAXSHADERS)
I_Error("CompileShader: Invalid slot %d", slot);
return true;
if (Shader_CompileProgram(&gl_shaders[slot], slot))
{
return true;
}
else
{
gl_shaders[slot].program = 0;
return false;
}
#else
(void)slot;
return false;
#endif
}
......@@ -991,90 +803,36 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value)
#endif
}
//
// Custom shader loading
//
EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boolean isfragment)
{
#ifdef GL_SHADERS
shadersource_t *shader;
if (!pglUseProgram)
return;
if (number < 1 || number > HWR_MAXSHADERS)
I_Error("LoadCustomShader: cannot load shader %d (min 1, max %d)", number, HWR_MAXSHADERS);
else if (code == NULL)
I_Error("LoadCustomShader: empty shader");
shader = &gl_customshaders[number];
#define COPYSHADER(source) { \
if (shader->source) \
free(shader->source); \
shader->source = malloc(size+1); \
strncpy(shader->source, code, size); \
shader->source[size] = 0; \
}
if (isfragment)
COPYSHADER(fragment)
else
COPYSHADER(vertex)
#else
(void)number;
(void)shader;
(void)size;
(void)fragment;
#endif
}
EXPORT void HWRAPI(SetShader) (int type)
EXPORT void HWRAPI(SetShader) (int slot)
{
#ifdef GL_SHADERS
if (type == SHADER_NONE)
if (slot == SHADER_NONE)
{
UnSetShader();
return;
}
if (gl_allowshaders != HWD_SHADEROPTION_OFF)
if (gl_allowshaders)
{
gl_shader_t *shader = gl_shaderstate.current;
gl_shader_t *next_shader = &gl_shaders[slot]; // the gl_shader_t we are going to switch to
// If using model lighting, set the appropriate shader.
// However don't override a custom shader.
if (type == SHADER_MODEL && model_lighting
&& !(gl_shaders[SHADER_MODEL].custom && !gl_shaders[SHADER_MODEL_LIGHTING].custom))
type = SHADER_MODEL_LIGHTING;
if (!next_shader->program)
next_shader = &gl_fallback_shader; // unusable shader, use fallback instead
if ((shader == NULL) || (GLuint)type != gl_shaderstate.type)
// update gl_shaderstate if an actual shader switch is needed
if (gl_shaderstate.current != next_shader)
{
gl_shader_t *baseshader = &gl_shaders[type];
gl_shader_t *usershader = &gl_usershaders[type];
if (usershader->program)
shader = (gl_allowshaders == HWD_SHADEROPTION_NOCUSTOM) ? baseshader : usershader;
else
shader = baseshader;
gl_shaderstate.current = shader;
gl_shaderstate.type = type;
gl_shaderstate.current = next_shader;
gl_shaderstate.program = next_shader->program;
gl_shaderstate.type = slot;
gl_shaderstate.changed = true;
}
if (gl_shaderstate.program != shader->program)
{
gl_shaderstate.program = shader->program;
gl_shaderstate.changed = true;
}
gl_shadersenabled = true;
gl_shadersenabled = (shader->program != 0);
return;
}
#else
(void)type;
(void)slot;
#endif
gl_shadersenabled = false;
}
......@@ -1082,36 +840,20 @@ EXPORT void HWRAPI(SetShader) (int type)
EXPORT void HWRAPI(UnSetShader) (void)
{
#ifdef GL_SHADERS
gl_shaderstate.current = NULL;
gl_shaderstate.type = 0;
gl_shaderstate.program = 0;
if (gl_shadersenabled) // don't repeatedly call glUseProgram if not needed
{
gl_shaderstate.current = NULL;
gl_shaderstate.type = 0;
gl_shaderstate.program = 0;
if (pglUseProgram)
pglUseProgram(0);
if (pglUseProgram)
pglUseProgram(0);
}
#endif
gl_shadersenabled = false;
}
EXPORT void HWRAPI(CleanShaders) (void)
{
INT32 i;
for (i = 1; i < HWR_MAXSHADERS; i++)
{
shadersource_t *shader = &gl_customshaders[i];
if (shader->vertex)
free(shader->vertex);
if (shader->fragment)
free(shader->fragment);
shader->vertex = NULL;
shader->fragment = NULL;
}
}
// -----------------+
// SetNoTexture : Disable texture
// -----------------+
......@@ -1407,55 +1149,38 @@ EXPORT void HWRAPI(ClearMipMapCache) (void)
}
// -----------------+
// ReadRect : Read a rectangle region of the truecolor framebuffer
// : store pixels as 16bit 565 RGB
// Returns : 16bit 565 RGB pixel array stored in dst_data
// -----------------+
EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
INT32 dst_stride, UINT16 * dst_data)
// Writes screen texture tex into dst_data.
// Pixel format is 24-bit RGB. Row order is top to bottom.
// Dimensions are screen_width * screen_height.
EXPORT void HWRAPI(ReadScreenTexture) (int tex, UINT8 *dst_data)
{
INT32 i;
// GL_DBG_Printf ("ReadRect()\n");
if (dst_stride == width*3)
{
GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1);
GLubyte *row = malloc(dst_stride);
if (!row) return;
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data);
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for(i = 0; i < height/2; i++)
{
memcpy(row, top, dst_stride);
memcpy(top, bottom, dst_stride);
memcpy(bottom, row, dst_stride);
top += dst_stride;
bottom -= dst_stride;
}
free(row);
}
else
{
INT32 j;
GLubyte *image = malloc(width*height*3*sizeof (*image));
if (!image) return;
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (i = height-1; i >= 0; i--)
{
for (j = 0; j < width; j++)
{
dst_data[(height-1-i)*width+j] =
(UINT16)(
((image[(i*width+j)*3]>>3)<<11) |
((image[(i*width+j)*3+1]>>2)<<5) |
((image[(i*width+j)*3+2]>>3)));
}
}
free(image);
}
int dst_stride = screen_width * 3; // stride between rows of image data
GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (screen_height - 1);
GLubyte *row;
row = malloc(dst_stride);
if (!row) return;
// at the time this function is called, generic2 can be found drawn on the framebuffer
// if some other screen texture is needed, draw it to the framebuffer
// and draw generic2 back after reading the framebuffer.
// this hack is for some reason **much** faster than the simple solution of using glGetTexImage.
if (tex != HWD_SCREENTEXTURE_GENERIC2)
DrawScreenTexture(tex, NULL, 0);
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(0, 0, screen_width, screen_height, GL_RGB, GL_UNSIGNED_BYTE, dst_data);
if (tex != HWD_SCREENTEXTURE_GENERIC2)
DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2, NULL, 0);
// Flip image upside down.
// In other words, convert OpenGL's "bottom->top" row order into "top->bottom".
for(i = 0; i < screen_height/2; i++)
{
memcpy(row, top, dst_stride);
memcpy(top, bottom, dst_stride);
memcpy(bottom, row, dst_stride);
top += dst_stride;
bottom -= dst_stride;
}
free(row);
}
......@@ -1887,7 +1612,8 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
//pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
if (MipMap)
{
pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
pglTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
pglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
if (pTexInfo->flags & TF_TRANSPARENT)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff
......@@ -1908,7 +1634,8 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
//pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
if (MipMap)
{
pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
pglTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
if (pTexInfo->flags & TF_TRANSPARENT)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff
......@@ -1928,7 +1655,8 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
{
if (MipMap)
{
pgluBuild2DMipmaps(GL_TEXTURE_2D, textureformatGL, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
pglTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
pglTexImage2D(GL_TEXTURE_2D, 0, textureformatGL, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
// Control the mipmap level of detail
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); // the lower the number, the higer the detail
if (pTexInfo->flags & TF_TRANSPARENT)
......@@ -2071,69 +1799,91 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF
#endif
}
static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader)
static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i)
{
GLuint gl_vertShader, gl_fragShader;
GLuint gl_vertShader = 0;
GLuint gl_fragShader = 0;
GLint result;
const GLchar *vert_shader = shader->vertex_shader;
const GLchar *frag_shader = shader->fragment_shader;
//
// Load and compile vertex shader
//
gl_vertShader = pglCreateShader(GL_VERTEX_SHADER);
if (!gl_vertShader)
if (shader->program)
pglDeleteProgram(shader->program);
if (!vert_shader && !frag_shader)
{
GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i));
GL_MSG_Error("Shader_CompileProgram: Missing shaders for shader program %s\n", HWR_GetShaderName(i));
return false;
}
pglShaderSource(gl_vertShader, 1, &vert_shader, NULL);
pglCompileShader(gl_vertShader);
// check for compile errors
pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
if (vert_shader)
{
Shader_CompileError("Error compiling vertex shader", gl_vertShader, i);
pglDeleteShader(gl_vertShader);
return false;
//
// Load and compile vertex shader
//
gl_vertShader = pglCreateShader(GL_VERTEX_SHADER);
if (!gl_vertShader)
{
GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i));
return false;
}
pglShaderSource(gl_vertShader, 1, &vert_shader, NULL);
pglCompileShader(gl_vertShader);
// check for compile errors
pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
Shader_CompileError("Error compiling vertex shader", gl_vertShader, i);
pglDeleteShader(gl_vertShader);
return false;
}
}
//
// Load and compile fragment shader
//
gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER);
if (!gl_fragShader)
if (frag_shader)
{
GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i));
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
return false;
}
//
// Load and compile fragment shader
//
gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER);
if (!gl_fragShader)
{
GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i));
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
return false;
}
pglShaderSource(gl_fragShader, 1, &frag_shader, NULL);
pglCompileShader(gl_fragShader);
pglShaderSource(gl_fragShader, 1, &frag_shader, NULL);
pglCompileShader(gl_fragShader);
// check for compile errors
pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
Shader_CompileError("Error compiling fragment shader", gl_fragShader, i);
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
return false;
// check for compile errors
pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
Shader_CompileError("Error compiling fragment shader", gl_fragShader, i);
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
return false;
}
}
shader->program = pglCreateProgram();
pglAttachShader(shader->program, gl_vertShader);
pglAttachShader(shader->program, gl_fragShader);
if (vert_shader)
pglAttachShader(shader->program, gl_vertShader);
if (frag_shader)
pglAttachShader(shader->program, gl_fragShader);
pglLinkProgram(shader->program);
// check link status
pglGetProgramiv(shader->program, GL_LINK_STATUS, &result);
// delete the shader objects
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
if (vert_shader)
pglDeleteShader(gl_vertShader);
if (frag_shader)
pglDeleteShader(gl_fragShader);
// couldn't link?
if (result != GL_TRUE)
......@@ -2154,11 +1904,31 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar
shader->uniforms[gluniform_fade_start] = GETUNI("fade_start");
shader->uniforms[gluniform_fade_end] = GETUNI("fade_end");
// misc. (custom shaders)
shader->uniforms[gluniform_leveltime] = GETUNI("leveltime");
// palette rendering
shader->uniforms[gluniform_palette_tex] = GETUNI("palette_tex");
shader->uniforms[gluniform_palette_lookup_tex] = GETUNI("palette_lookup_tex");
shader->uniforms[gluniform_lighttable_tex] = GETUNI("lighttable_tex");
// misc.
shader->uniforms[gluniform_leveltime] = GETUNI("leveltime");
#undef GETUNI
// set permanent uniform values
#define UNIFORM_1(uniform, a, function) \
if (uniform != -1) \
function (uniform, a);
pglUseProgram(shader->program);
// texture unit numbers for the samplers used for palette rendering
UNIFORM_1(shader->uniforms[gluniform_palette_tex], 2, pglUniform1i);
UNIFORM_1(shader->uniforms[gluniform_palette_lookup_tex], 1, pglUniform1i);
UNIFORM_1(shader->uniforms[gluniform_lighttable_tex], 2, pglUniform1i);
// restore gl shader state
pglUseProgram(gl_shaderstate.program);
#undef UNIFORM_1
return true;
}
......@@ -2182,6 +1952,7 @@ static void Shader_CompileError(const char *message, GLuint program, INT32 shade
}
// code that is common between DrawPolygon and DrawIndexedTriangles
// DrawScreenTexture also can use this function for fancier screen texture drawing
// the corona thing is there too, i have no idea if that stuff works with DrawIndexedTriangles and batching
static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD PolyFlags)
{
......@@ -2221,6 +1992,14 @@ static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD
fade.green = byte2float[pSurf->FadeColor.s.green];
fade.blue = byte2float[pSurf->FadeColor.s.blue];
fade.alpha = byte2float[pSurf->FadeColor.s.alpha];
if (pSurf->LightTableId && pSurf->LightTableId != lt_downloaded)
{
pglActiveTexture(GL_TEXTURE2);
pglBindTexture(GL_TEXTURE_2D, pSurf->LightTableId);
pglActiveTexture(GL_TEXTURE0);
lt_downloaded = pSurf->LightTableId;
}
}
}
......@@ -2413,9 +2192,6 @@ EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky)
pglDisableClientState(GL_COLOR_ARRAY);
}
// ==========================================================================
//
// ==========================================================================
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
{
switch (IdState)
......@@ -2425,7 +2201,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
break;
case HWD_SET_SHADERS:
gl_allowshaders = (hwdshaderoption_t)Value;
gl_allowshaders = Value;
break;
case HWD_SET_TEXTUREFILTERMODE:
......@@ -2463,7 +2239,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
mag_filter = GL_LINEAR;
min_filter = GL_NEAREST;
}
if (!pgluBuild2DMipmaps)
if (!supportMipMap)
{
MipMap = GL_FALSE;
min_filter = GL_LINEAR;
......@@ -2784,6 +2560,14 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float
else if (Surface->PolyColor.s.alpha == 0xFF)
flags |= (PF_Occlude | PF_Masked);
if (Surface->LightTableId && Surface->LightTableId != lt_downloaded)
{
pglActiveTexture(GL_TEXTURE2);
pglBindTexture(GL_TEXTURE_2D, Surface->LightTableId);
pglActiveTexture(GL_TEXTURE0);
lt_downloaded = Surface->LightTableId;
}
SetBlend(flags);
Shader_SetUniforms(Surface, &poly, &tint, &fade);
......@@ -3071,7 +2855,7 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2])
INT32 x, y;
float float_x, float_y, float_nextx, float_nexty;
float xfix, yfix;
INT32 texsize = 2048;
INT32 texsize = 512;
const float blackBack[16] =
{
......@@ -3081,11 +2865,9 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2])
16.0f, -16.0f, 6.0f
};
// Use a power of two texture, dammit
if(screen_width <= 1024)
texsize = 1024;
if(screen_width <= 512)
texsize = 512;
// look for power of two that is large enough for the screen
while (texsize < screen_width || texsize < screen_height)
texsize <<= 1;
// X/Y stretch fix for all resolutions(!)
xfix = (float)(texsize)/((float)((screen_width)/(float)(SCREENVERTS-1)));
......@@ -3159,84 +2941,16 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2])
// a new size
EXPORT void HWRAPI(FlushScreenTextures) (void)
{
pglDeleteTextures(1, &screentexture);
pglDeleteTextures(1, &startScreenWipe);
pglDeleteTextures(1, &endScreenWipe);
pglDeleteTextures(1, &finalScreenTexture);
screentexture = 0;
startScreenWipe = 0;
endScreenWipe = 0;
finalScreenTexture = 0;
}
// Create Screen to fade from
EXPORT void HWRAPI(StartScreenWipe) (void)
{
INT32 texsize = 2048;
boolean firstTime = (startScreenWipe == 0);
// Use a power of two texture, dammit
if(screen_width <= 512)
texsize = 512;
else if(screen_width <= 1024)
texsize = 1024;
// Create screen texture
if (firstTime)
pglGenTextures(1, &startScreenWipe);
pglBindTexture(GL_TEXTURE_2D, startScreenWipe);
if (firstTime)
{
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Clamp2D(GL_TEXTURE_WRAP_S);
Clamp2D(GL_TEXTURE_WRAP_T);
pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
}
else
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
tex_downloaded = startScreenWipe;
}
// Create Screen to fade to
EXPORT void HWRAPI(EndScreenWipe)(void)
{
INT32 texsize = 2048;
boolean firstTime = (endScreenWipe == 0);
// Use a power of two texture, dammit
if(screen_width <= 512)
texsize = 512;
else if(screen_width <= 1024)
texsize = 1024;
// Create screen texture
if (firstTime)
pglGenTextures(1, &endScreenWipe);
pglBindTexture(GL_TEXTURE_2D, endScreenWipe);
if (firstTime)
{
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Clamp2D(GL_TEXTURE_WRAP_S);
Clamp2D(GL_TEXTURE_WRAP_T);
pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
}
else
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
tex_downloaded = endScreenWipe;
int i;
pglDeleteTextures(NUMSCREENTEXTURES, screenTextures);
for (i = 0; i < NUMSCREENTEXTURES; i++)
screenTextures[i] = 0;
}
// Draw the last scene under the intermission
EXPORT void HWRAPI(DrawIntermissionBG)(void)
EXPORT void HWRAPI(DrawScreenTexture)(int tex, FSurfaceInfo *surf, FBITFIELD polyflags)
{
float xfix, yfix;
INT32 texsize = 2048;
INT32 texsize = 512;
const float screenVerts[12] =
{
......@@ -3248,10 +2962,9 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void)
float fix[8];
if(screen_width <= 1024)
texsize = 1024;
if(screen_width <= 512)
texsize = 512;
// look for power of two that is large enough for the screen
while (texsize < screen_width || texsize < screen_height)
texsize <<= 1;
xfix = 1/((float)(texsize)/((float)((screen_width))));
yfix = 1/((float)(texsize)/((float)((screen_height))));
......@@ -3270,20 +2983,23 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void)
pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
pglBindTexture(GL_TEXTURE_2D, screentexture);
pglColor4ubv(white);
pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]);
PreparePolygon(surf, NULL, surf ? polyflags : (PF_NoDepthTest));
if (!surf)
pglColor4ubv(white);
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
tex_downloaded = screentexture;
tex_downloaded = screenTextures[tex];
}
// Do screen fades!
EXPORT void HWRAPI(DoScreenWipe)(void)
EXPORT void HWRAPI(DoScreenWipe)(int wipeStart, int wipeEnd, FSurfaceInfo *surf,
FBITFIELD polyFlags)
{
INT32 texsize = 2048;
INT32 texsize = 512;
float xfix, yfix;
INT32 fademaskdownloaded = tex_downloaded; // the fade mask that has been set
......@@ -3306,11 +3022,15 @@ EXPORT void HWRAPI(DoScreenWipe)(void)
1.0f, 1.0f
};
// Use a power of two texture, dammit
if(screen_width <= 1024)
texsize = 1024;
if(screen_width <= 512)
texsize = 512;
int firstScreen;
if (surf && surf->PolyColor.s.alpha == 255)
firstScreen = wipeEnd; // it's a tinted fade-in, we need wipeEnd
else
firstScreen = wipeStart;
// look for power of two that is large enough for the screen
while (texsize < screen_width || texsize < screen_height)
texsize <<= 1;
xfix = 1/((float)(texsize)/((float)((screen_width))));
yfix = 1/((float)(texsize)/((float)((screen_height))));
......@@ -3332,91 +3052,71 @@ EXPORT void HWRAPI(DoScreenWipe)(void)
SetBlend(PF_Modulated|PF_NoDepthTest);
pglEnable(GL_TEXTURE_2D);
// Draw the original screen
pglBindTexture(GL_TEXTURE_2D, startScreenWipe);
pglBindTexture(GL_TEXTURE_2D, screenTextures[firstScreen]);
pglColor4ubv(white);
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest);
// Draw the end screen that fades in
pglActiveTexture(GL_TEXTURE0);
pglEnable(GL_TEXTURE_2D);
pglBindTexture(GL_TEXTURE_2D, endScreenWipe);
pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
pglActiveTexture(GL_TEXTURE1);
pglEnable(GL_TEXTURE_2D);
pglBindTexture(GL_TEXTURE_2D, fademaskdownloaded);
pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// const float defaultST[8]
if (surf)
{
// Draw fade mask to screen using surf and polyFlags
// Used for colormap/tinted wipes.
pglBindTexture(GL_TEXTURE_2D, fademaskdownloaded);
pglTexCoordPointer(2, GL_FLOAT, 0, defaultST);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
PreparePolygon(surf, NULL, polyFlags);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
else // Blend wipeEnd into screen with the fade mask
{
SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest);
pglClientActiveTexture(GL_TEXTURE0);
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglClientActiveTexture(GL_TEXTURE1);
pglEnableClientState(GL_TEXTURE_COORD_ARRAY);
pglTexCoordPointer(2, GL_FLOAT, 0, defaultST);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
// Draw the end screen that fades in
pglActiveTexture(GL_TEXTURE0);
pglEnable(GL_TEXTURE_2D);
pglBindTexture(GL_TEXTURE_2D, screenTextures[wipeEnd]);
pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
pglDisable(GL_TEXTURE_2D); // disable the texture in the 2nd texture unit
pglDisableClientState(GL_TEXTURE_COORD_ARRAY);
pglActiveTexture(GL_TEXTURE1);
pglEnable(GL_TEXTURE_2D);
pglBindTexture(GL_TEXTURE_2D, fademaskdownloaded);
pglActiveTexture(GL_TEXTURE0);
pglClientActiveTexture(GL_TEXTURE0);
tex_downloaded = endScreenWipe;
}
pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// Create a texture from the screen.
EXPORT void HWRAPI(MakeScreenTexture) (void)
{
INT32 texsize = 2048;
boolean firstTime = (screentexture == 0);
// const float defaultST[8]
// Use a power of two texture, dammit
if(screen_width <= 512)
texsize = 512;
else if(screen_width <= 1024)
texsize = 1024;
pglClientActiveTexture(GL_TEXTURE0);
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglClientActiveTexture(GL_TEXTURE1);
pglEnableClientState(GL_TEXTURE_COORD_ARRAY);
pglTexCoordPointer(2, GL_FLOAT, 0, defaultST);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
// Create screen texture
if (firstTime)
pglGenTextures(1, &screentexture);
pglBindTexture(GL_TEXTURE_2D, screentexture);
pglDisable(GL_TEXTURE_2D); // disable the texture in the 2nd texture unit
pglDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (firstTime)
{
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Clamp2D(GL_TEXTURE_WRAP_S);
Clamp2D(GL_TEXTURE_WRAP_T);
pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
pglActiveTexture(GL_TEXTURE0);
pglClientActiveTexture(GL_TEXTURE0);
tex_downloaded = screenTextures[wipeEnd];
}
else
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
tex_downloaded = screentexture;
}
EXPORT void HWRAPI(MakeScreenFinalTexture) (void)
// Create a texture from the screen.
EXPORT void HWRAPI(MakeScreenTexture) (int tex)
{
INT32 texsize = 2048;
boolean firstTime = (finalScreenTexture == 0);
INT32 texsize = 512;
boolean firstTime = (screenTextures[tex] == 0);
// Use a power of two texture, dammit
if(screen_width <= 512)
texsize = 512;
else if(screen_width <= 1024)
texsize = 1024;
// look for power of two that is large enough for the screen
while (texsize < screen_width || texsize < screen_height)
texsize <<= 1;
// Create screen texture
if (firstTime)
pglGenTextures(1, &finalScreenTexture);
pglBindTexture(GL_TEXTURE_2D, finalScreenTexture);
pglGenTextures(1, &screenTextures[tex]);
pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]);
if (firstTime)
{
......@@ -3429,24 +3129,23 @@ EXPORT void HWRAPI(MakeScreenFinalTexture) (void)
else
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
tex_downloaded = finalScreenTexture;
tex_downloaded = screenTextures[tex];
}
EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)
EXPORT void HWRAPI(DrawScreenFinalTexture)(int tex, int width, int height)
{
float xfix, yfix;
float origaspect, newaspect;
float xoff = 1, yoff = 1; // xoffset and yoffset for the polygon to have black bars around the screen
FRGBAFloat clearColour;
INT32 texsize = 2048;
INT32 texsize = 512;
float off[12];
float fix[8];
if(screen_width <= 1024)
texsize = 1024;
if(screen_width <= 512)
texsize = 512;
// look for power of two that is large enough for the screen
while (texsize < screen_width || texsize < screen_height)
texsize <<= 1;
xfix = 1/((float)(texsize)/((float)((screen_width))));
yfix = 1/((float)(texsize)/((float)((screen_height))));
......@@ -3493,7 +3192,8 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)
clearColour.red = clearColour.green = clearColour.blue = 0;
clearColour.alpha = 1;
ClearBuffer(true, false, &clearColour);
pglBindTexture(GL_TEXTURE_2D, finalScreenTexture);
SetBlend(PF_NoDepthTest);
pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]);
pglColor4ubv(white);
......@@ -3501,7 +3201,110 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)
pglVertexPointer(3, GL_FLOAT, 0, off);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
tex_downloaded = finalScreenTexture;
tex_downloaded = screenTextures[tex];
}
EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut)
{
GLenum internalFormat;
if (gl_version[0] == '1' || gl_version[0] == '2')
{
// if the OpenGL version is below 3.0, then the GL_R8 format may not be available.
// so use GL_LUMINANCE8 instead to get a single component 8-bit format
// (it is possible to have access to shaders even in some OpenGL 1.x systems,
// so palette rendering can still possibly be achieved there)
internalFormat = GL_LUMINANCE8;
}
else
{
internalFormat = GL_R8;
}
if (!paletteLookupTex)
pglGenTextures(1, &paletteLookupTex);
pglActiveTexture(GL_TEXTURE1);
pglBindTexture(GL_TEXTURE_3D, paletteLookupTex);
pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexImage3D(GL_TEXTURE_3D, 0, internalFormat, HWR_PALETTE_LUT_SIZE, HWR_PALETTE_LUT_SIZE, HWR_PALETTE_LUT_SIZE,
0, GL_RED, GL_UNSIGNED_BYTE, lut);
pglActiveTexture(GL_TEXTURE0);
}
EXPORT UINT32 HWRAPI(CreateLightTable)(RGBA_t *hw_lighttable)
{
LTListItem *item = malloc(sizeof(LTListItem));
if (!LightTablesTail)
{
LightTablesHead = LightTablesTail = item;
}
else
{
LightTablesTail->next = item;
LightTablesTail = item;
}
item->next = NULL;
pglGenTextures(1, &item->id);
pglBindTexture(GL_TEXTURE_2D, item->id);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, hw_lighttable);
// restore previously bound texture
pglBindTexture(GL_TEXTURE_2D, tex_downloaded);
return item->id;
}
EXPORT void HWRAPI(UpdateLightTable)(UINT32 id, RGBA_t *hw_lighttable)
{
LTListItem *item = LightTablesHead;
while (item && item->id != id)
item = item->next;
if (item)
{
pglBindTexture(GL_TEXTURE_2D, item->id);
// Just update it
pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 32, GL_RGBA, GL_UNSIGNED_BYTE, hw_lighttable);
// restore previously bound texture
pglBindTexture(GL_TEXTURE_2D, tex_downloaded);
}
}
// Delete light table textures, ids given before become invalid and must not be used.
EXPORT void HWRAPI(ClearLightTables)(void)
{
while (LightTablesHead)
{
LTListItem *item = LightTablesHead;
pglDeleteTextures(1, (GLuint *)&item->id);
LightTablesHead = item->next;
free(item);
}
LightTablesTail = NULL;
// we no longer have a bound light table (if we had one), we just deleted it!
lt_downloaded = 0;
}
// This palette is used for the palette rendering postprocessing step.
EXPORT void HWRAPI(SetScreenPalette)(RGBA_t *palette)
{
if (memcmp(screenPalette, palette, sizeof(screenPalette)))
{
memcpy(screenPalette, palette, sizeof(screenPalette));
if (!screenPaletteTex)
pglGenTextures(1, &screenPaletteTex);
pglActiveTexture(GL_TEXTURE2);
pglBindTexture(GL_TEXTURE_1D, screenPaletteTex);
pglTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, palette);
pglActiveTexture(GL_TEXTURE0);
}
}
#endif //HWRENDER
......@@ -35,7 +35,6 @@
#else
#include <GL/gl.h>
#include <GL/glu.h>
#ifdef STATIC_OPENGL // Because of the 1.3 functions, you'll need GLext to compile it if static
#define GL_GLEXT_PROTOTYPES
......@@ -46,6 +45,7 @@
#define _CREATE_DLL_ // necessary for Unix AND Windows
#include "../../doomdef.h"
#include "../hw_drv.h"
#include "../../z_zone.h"
// ==========================================================================
// DEFINITIONS
......@@ -126,6 +126,7 @@ extern GLint screen_width;
extern GLint screen_height;
extern GLbyte screen_depth;
extern GLint maximumAnisotropy;
extern boolean supportMipMap;
/** \brief OpenGL flags for video driver
*/
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -29,7 +29,7 @@
#include "i_video.h"
#include "i_system.h"
#include "st_stuff.h" // ST_HEIGHT
#include "st_stuff.h"
#include "r_local.h"
#include "keys.h"
......@@ -52,6 +52,7 @@
#include "lua_hud.h"
#include "lua_hudlib_drawlist.h"
#include "lua_hook.h"
#include "lua_libs.h"
// coords are scaled
#define HU_INPUTX 0
......@@ -61,21 +62,22 @@
#define HU_CSAY 2 // Server CECHOes to everyone.
//-------------------------------------------
// heads up font
// Fonts & stuff
//-------------------------------------------
patch_t *hu_font[HU_FONTSIZE];
patch_t *tny_font[HU_FONTSIZE];
// Font definitions
fontdef_t hu_font;
fontdef_t tny_font;
fontdef_t cred_font;
fontdef_t lt_font;
fontdef_t ntb_font;
fontdef_t nto_font;
// Numbers
patch_t *tallnum[10]; // 0-9
patch_t *nightsnum[10]; // 0-9
// Level title and credits fonts
patch_t *lt_font[LT_FONTSIZE];
patch_t *cred_font[CRED_FONTSIZE];
patch_t *ttlnum[10]; // act numbers (0-9)
// Name tag fonts
patch_t *ntb_font[NT_FONTSIZE];
patch_t *nto_font[NT_FONTSIZE];
patch_t *tallminus;
patch_t *tallinfin;
static player_t *plr;
boolean chat_on; // entering a chat message?
......@@ -91,8 +93,6 @@ patch_t *bflagico;
patch_t *rmatcico;
patch_t *bmatcico;
patch_t *tagico;
patch_t *tallminus;
patch_t *tallinfin;
//-------------------------------------------
// coop hud
......@@ -188,53 +188,26 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum);
void HU_LoadGraphics(void)
{
char buffer[9];
INT32 i, j;
INT32 i;
if (dedicated)
return;
j = HU_FONTSTART;
for (i = 0; i < HU_FONTSIZE; i++, j++)
{
// cache the heads-up font for entire game execution
sprintf(buffer, "STCFN%.3d", j);
if (W_CheckNumForName(buffer) == LUMPERROR)
hu_font[i] = NULL;
else
hu_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
// tiny version of the heads-up font
sprintf(buffer, "TNYFN%.3d", j);
if (W_CheckNumForName(buffer) == LUMPERROR)
tny_font[i] = NULL;
else
tny_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
j = LT_FONTSTART;
for (i = 0; i < LT_FONTSIZE; i++)
{
sprintf(buffer, "LTFNT%.3d", j);
j++;
if (W_CheckNumForName(buffer) == LUMPERROR)
lt_font[i] = NULL;
else
lt_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
// cache the credits font for entire game execution (why not?)
j = CRED_FONTSTART;
for (i = 0; i < CRED_FONTSIZE; i++)
{
sprintf(buffer, "CRFNT%.3d", j);
j++;
if (W_CheckNumForName(buffer) == LUMPERROR)
cred_font[i] = NULL;
else
cred_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
// Cache fonts
HU_LoadFontCharacters(&hu_font, "STCFN");
HU_LoadFontCharacters(&tny_font, "TNYFN");
HU_LoadFontCharacters(&cred_font, "CRFNT");
HU_LoadFontCharacters(&lt_font, "LTFNT");
HU_LoadFontCharacters(&ntb_font, "NTFNT");
HU_LoadFontCharacters(&nto_font, "NTFNO");
// For each font, set kerning, space width, character width and line spacing
HU_SetFontProperties(&hu_font, 0, 4, 8, 12);
HU_SetFontProperties(&tny_font, 0, 2, 4, 12);
HU_SetFontProperties(&cred_font, 0, 16, 16, 16);
HU_SetFontProperties(&lt_font, 0, 16, 20, 16);
HU_SetFontProperties(&ntb_font, 2, 4, 20, 21);
HU_SetFontProperties(&nto_font, 0, 4, 20, 21);
//cache numbers too!
for (i = 0; i < 10; i++)
......@@ -243,45 +216,14 @@ void HU_LoadGraphics(void)
tallnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
sprintf(buffer, "NGTNUM%d", i);
nightsnum[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
sprintf(buffer, "TTL%.2d", i);
ttlnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
// minus for negative tallnums
tallminus = (patch_t *)W_CachePatchName("STTMINUS", PU_HUDGFX);
tallinfin = (patch_t *)W_CachePatchName("STTINFIN", PU_HUDGFX);
// cache act numbers for level titles
for (i = 0; i < 10; i++)
{
sprintf(buffer, "TTL%.2d", i);
ttlnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
// cache the base name tag font for entire game execution
j = NT_FONTSTART;
for (i = 0; i < NT_FONTSIZE; i++)
{
sprintf(buffer, "NTFNT%.3d", j);
j++;
if (W_CheckNumForName(buffer) == LUMPERROR)
ntb_font[i] = NULL;
else
ntb_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
// cache the outline name tag font for entire game execution
j = NT_FONTSTART;
for (i = 0; i < NT_FONTSIZE; i++)
{
sprintf(buffer, "NTFNO%.3d", j);
j++;
if (W_CheckNumForName(buffer) == LUMPERROR)
nto_font[i] = NULL;
else
nto_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
// cache the crosshairs, don't bother to know which one is being used,
// just cache all 3, they're so small anyway.
for (i = 0; i < HU_CROSSHAIRS; i++)
......@@ -323,6 +265,29 @@ void HU_LoadGraphics(void)
//emeraldpics[2][7] = W_CachePatchName("EMBOX8", PU_HUDGFX); -- unused
}
void HU_LoadFontCharacters(fontdef_t *font, const char *prefix)
{
char buffer[9];
INT32 i, j = FONTSTART;
for (i = 0; i < FONTSIZE; i++, j++)
{
sprintf(buffer, "%.5s%.3d", prefix, j);
if (W_CheckNumForPatchName(buffer) == LUMPERROR)
font->chars[i] = NULL;
else
font->chars[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
}
void HU_SetFontProperties(fontdef_t *font, INT32 kerning, UINT32 spacewidth, UINT32 charwidth, UINT32 linespacing)
{
font->kerning = kerning;
font->spacewidth = spacewidth;
font->charwidth = charwidth;
font->linespacing = linespacing;
}
// Initialise Heads up
// once at game startup.
//
......@@ -431,8 +396,11 @@ void HU_AddChatText(const char *text, boolean playsound)
if (OLDCHAT) // if we're using oldchat, print directly in console
CONS_Printf("%s\n", text);
else // if we aren't, still save the message to log.txt
CON_LogMessage(va("%s\n", text));
else // if we aren't, still save the message to log.txt
{
CON_LogMessage(text);
CON_LogMessage("\n"); // Add newline. Don't use va for that, since `text` might be refering to va's buffer itself
}
}
/** Runs a say command, sending an ::XD_SAY message.
......@@ -465,9 +433,12 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags)
numwords = COM_Argc() - usedargs;
I_Assert(numwords > 0);
if (CHAT_MUTE) // TODO: Per Player mute.
if (CHAT_MUTE)
{
HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false);
if (cv_mute.value)
HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false);
else
HU_AddChatText(va("%s>ERROR: You have been muted. You can't say anything.", "\x85"), false);
return;
}
......@@ -496,10 +467,10 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags)
// what we're gonna do now is check if the player exists
// with that logic, characters 4 and 5 are our numbers:
const char *newmsg;
char playernum[3];
char playernum[3+1];
INT32 spc = 1; // used if playernum[1] is a space.
strncpy(playernum, msg+3, 3);
strncpy(playernum, msg+3, sizeof(playernum)-1);
// check for undesirable characters in our "number"
if (((playernum[0] < '0') || (playernum[0] > '9')) || ((playernum[1] < '0') || (playernum[1] > '9')))
{
......@@ -620,8 +591,47 @@ static void Command_CSay_f(void)
DoSayCommand(0, 1, HU_CSAY);
}
static tic_t spam_tokens[MAXPLAYERS];
static tic_t spam_tics[MAXPLAYERS];
UINT8 spam_tokens[MAXPLAYERS] = { 1 }; // fill the buffer with 1 so the motd can be sent.
tic_t spam_tics[MAXPLAYERS];
static const char *GetChatColorFromSkinColor(INT32 skincolor)
{
const char *textcolor = NULL;
UINT16 chatcolor = skincolors[skincolor].chatcolor;
if (!chatcolor || chatcolor%0x1000 || chatcolor>V_INVERTMAP)
textcolor = "\x80";
else if (chatcolor == V_MAGENTAMAP)
textcolor = "\x81";
else if (chatcolor == V_YELLOWMAP)
textcolor = "\x82";
else if (chatcolor == V_GREENMAP)
textcolor = "\x83";
else if (chatcolor == V_BLUEMAP)
textcolor = "\x84";
else if (chatcolor == V_REDMAP)
textcolor = "\x85";
else if (chatcolor == V_GRAYMAP)
textcolor = "\x86";
else if (chatcolor == V_ORANGEMAP)
textcolor = "\x87";
else if (chatcolor == V_SKYMAP)
textcolor = "\x88";
else if (chatcolor == V_PURPLEMAP)
textcolor = "\x89";
else if (chatcolor == V_AQUAMAP)
textcolor = "\x8a";
else if (chatcolor == V_PERIDOTMAP)
textcolor = "\x8b";
else if (chatcolor == V_AZUREMAP)
textcolor = "\x8c";
else if (chatcolor == V_BROWNMAP)
textcolor = "\x8d";
else if (chatcolor == V_ROSYMAP)
textcolor = "\x8e";
else if (chatcolor == V_INVERTMAP)
textcolor = "\x8f";
return textcolor;
}
/** Receives a message, processing an ::XD_SAY command.
* \sa DoSayCommand
......@@ -632,6 +642,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
SINT8 target;
UINT8 flags;
const char *dispname;
char buf[HU_MAXMSGLEN + 1];
char *msg;
boolean action = false;
char *ptr;
......@@ -641,12 +652,12 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
target = READSINT8(*p);
flags = READUINT8(*p);
msg = (char *)*p;
SKIPSTRINGL(*p, HU_MAXMSGLEN + 1);
msg = buf;
READSTRINGL(*p, msg, HU_MAXMSGLEN + 1);
if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum)))
if ((cv_mute.value || players[playernum].muted || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum)))
{
CONS_Alert(CONS_WARNING, cv_mute.value ?
CONS_Alert(CONS_WARNING, (cv_mute.value || players[playernum].muted) ?
M_GetText("Illegal say command received from %s while muted\n") : M_GetText("Illegal csay command received from non-admin %s\n"),
player_names[playernum]);
if (server)
......@@ -682,14 +693,12 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
else
spam_tokens[playernum] -= 1;
// run the lua hook even if we were supposed to eat the msg, netgame consistency goes first.
if (spam_eatmsg)
return; // don't proceed if we were supposed to eat the message.
if (LUA_HookPlayerMsg(playernum, target, flags, msg))
return;
if (spam_eatmsg)
return; // don't proceed if we were supposed to eat the message.
// If it's a CSAY, just CECHO and be done with it.
if (flags & HU_CSAY)
{
......@@ -744,51 +753,27 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
{
if (players[playernum].ctfteam == 1) // red
{
cstart = "\x85";
textcolor = "\x85";
cstart = textcolor = GetChatColorFromSkinColor(skincolor_redteam);
}
else // blue
{
cstart = "\x84";
textcolor = "\x84";
cstart = textcolor = GetChatColorFromSkinColor(skincolor_blueteam);
}
}
else
{
UINT16 chatcolor = skincolors[players[playernum].skincolor].chatcolor;
if (!chatcolor || chatcolor%0x1000 || chatcolor>V_INVERTMAP)
cstart = "\x80";
else if (chatcolor == V_MAGENTAMAP)
cstart = "\x81";
else if (chatcolor == V_YELLOWMAP)
cstart = "\x82";
else if (chatcolor == V_GREENMAP)
cstart = "\x83";
else if (chatcolor == V_BLUEMAP)
cstart = "\x84";
else if (chatcolor == V_REDMAP)
cstart = "\x85";
else if (chatcolor == V_GRAYMAP)
cstart = "\x86";
else if (chatcolor == V_ORANGEMAP)
cstart = "\x87";
else if (chatcolor == V_SKYMAP)
cstart = "\x88";
else if (chatcolor == V_PURPLEMAP)
cstart = "\x89";
else if (chatcolor == V_AQUAMAP)
cstart = "\x8a";
else if (chatcolor == V_PERIDOTMAP)
cstart = "\x8b";
else if (chatcolor == V_AZUREMAP)
cstart = "\x8c";
else if (chatcolor == V_BROWNMAP)
cstart = "\x8d";
else if (chatcolor == V_ROSYMAP)
cstart = "\x8e";
else if (chatcolor == V_INVERTMAP)
cstart = "\x8f";
cstart = GetChatColorFromSkinColor(players[playernum].skincolor);
if (G_GametypeHasTeams())
{
if (players[playernum].ctfteam == 1) // red
{
cstart = GetChatColorFromSkinColor(skincolor_redteam);
}
else // blue
{
cstart = GetChatColorFromSkinColor(skincolor_blueteam);
}
}
}
prefix = cstart;
......@@ -962,14 +947,17 @@ static void HU_sendChatMessage(void)
// last minute mute check
if (CHAT_MUTE)
{
HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false);
if (cv_mute.value)
HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false);
else
HU_AddChatText(va("%s>ERROR: You have been muted. You can't say anything.", "\x85"), false);
return;
}
if (strlen(msg) > 4 && strnicmp(msg, "/pm", 3) == 0) // used /pm
{
INT32 spc = 1; // used if playernum[1] is a space.
char playernum[3];
char playernum[3+1];
const char *newmsg;
// what we're gonna do now is check if the player exists
......@@ -982,7 +970,7 @@ static void HU_sendChatMessage(void)
return;
}
strncpy(playernum, msg+3, 3);
strncpy(playernum, msg+3, sizeof(playernum)-1);
// check for undesirable characters in our "number"
if (!(isdigit(playernum[0]) && isdigit(playernum[1])))
{
......@@ -1029,6 +1017,7 @@ static void HU_sendChatMessage(void)
void HU_clearChatChars(void)
{
memset(w_chat, '\0', sizeof(w_chat));
I_SetTextInputMode(textinputmodeenabledbylua);
chat_on = false;
c_input = 0;
......@@ -1078,6 +1067,7 @@ boolean HU_Responder(event_t *ev)
if ((ev->key == gamecontrol[GC_TALKKEY][0] || ev->key == gamecontrol[GC_TALKKEY][1])
&& netgame && !OLD_MUTE) // check for old chat mute, still let the players open the chat incase they want to scroll otherwise.
{
I_SetTextInputMode(true);
chat_on = true;
chat_on_first_event = false;
w_chat[0] = 0;
......@@ -1089,6 +1079,7 @@ boolean HU_Responder(event_t *ev)
if ((ev->key == gamecontrol[GC_TEAMKEY][0] || ev->key == gamecontrol[GC_TEAMKEY][1])
&& netgame && !OLD_MUTE)
{
I_SetTextInputMode(true);
chat_on = true;
chat_on_first_event = false;
w_chat[0] = 0;
......@@ -1111,7 +1102,7 @@ boolean HU_Responder(event_t *ev)
if (ev->type == ev_text)
{
if ((c < HU_FONTSTART || c > HU_FONTEND || !hu_font[c-HU_FONTSTART])
if ((c < FONTSTART || c > FONTEND || !hu_font.chars[c-FONTSTART])
&& c != ' ') // Allow spaces, of course
{
return false;
......@@ -1163,6 +1154,7 @@ boolean HU_Responder(event_t *ev)
if (!CHAT_MUTE)
HU_sendChatMessage();
I_SetTextInputMode(textinputmodeenabledbylua);
chat_on = false;
c_input = 0; // reset input cursor
chat_scrollmedown = true; // you hit enter, so you might wanna autoscroll to see what you just sent. :)
......@@ -1173,6 +1165,7 @@ boolean HU_Responder(event_t *ev)
|| c == gamecontrol[GC_TEAMKEY][0] || c == gamecontrol[GC_TEAMKEY][1])
&& c >= KEY_MOUSE1)) // If it's not a keyboard key, then the chat button is used as a toggle.
{
I_SetTextInputMode(textinputmodeenabledbylua);
chat_on = false;
c_input = 0; // reset input cursor
I_UpdateMouseGrab();
......@@ -1230,199 +1223,98 @@ boolean HU_Responder(event_t *ev)
// HEADS UP DRAWING
//======================================================================
// Precompile a wordwrapped string to any given width.
// This is a muuuch better method than V_WORDWRAP.
// again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day.
// this one is simplified for the chat drawer.
static char *CHAT_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
{
INT32 c;
size_t chw, i, lastusablespace = 0;
size_t slen;
char *newstring = Z_StrDup(string);
INT32 spacewidth = (vid.width < 640) ? 8 : 4, charwidth = (vid.width < 640) ? 8 : 4;
slen = strlen(string);
x = 0;
for (i = 0; i < slen; ++i)
{
c = newstring[i];
if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09
continue;
if (c == '\n')
{
x = 0;
lastusablespace = 0;
continue;
}
if (!(option & V_ALLOWLOWERCASE))
c = toupper(c);
c -= HU_FONTSTART;
if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
{
chw = spacewidth;
lastusablespace = i;
}
else
chw = charwidth;
x += chw;
if (lastusablespace != 0 && x > w)
{
//CONS_Printf("Wrap at index %d\n", i);
newstring[lastusablespace] = '\n';
i = lastusablespace+1;
lastusablespace = 0;
x = 0;
}
}
return newstring;
}
// 30/7/18: chaty is now the distance at which the lowest point of the chat will be drawn if that makes any sense.
INT16 chatx = 13, chaty = 169; // let's use this as our coordinates
// chat stuff by VincyTM LOL XD!
// HU_DrawMiniChat
static void HU_drawMiniChat(void)
{
INT32 x = chatx+2;
INT32 x = chatx+2, y;
INT32 chatheight = 0;
INT32 charwidth = 4, charheight = 6;
INT32 boxw = cv_chatwidth.value;
INT32 dx = 0, dy = 0;
size_t i = chat_nummsg_min;
boolean prev_linereturn = false; // a hack to prevent double \n while I have no idea why they happen in the first place.
INT32 msglines = 0;
// process all messages once without rendering anything or doing anything fancy so that we know how many lines each message has...
INT32 y;
boolean prev_linereturn = false;
if (!chat_nummsg_min)
return; // needless to say it's useless to do anything if we don't have anything to draw.
/*if (splitscreen > 1)
boxw = max(64, boxw/2);*/
for (; i>0; i--)
for (size_t i = chat_nummsg_min; i > 0; i--)
{
char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]);
size_t j = 0;
INT32 linescount = 0;
while(msg[j]) // iterate through msg
char *msg = V_ChatWordWrap(0, boxw-charwidth-2, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE|V_MONOSPACE, chat_mini[i-1]);
for(size_t j = 0; msg[j]; j++) // iterate through msg
{
if (msg[j] < HU_FONTSTART) // don't draw
if (msg[j] == '\n') // get back down.
{
if (msg[j] == '\n') // get back down.
{
++j;
if (!prev_linereturn)
{
linescount += 1;
dx = 0;
}
prev_linereturn = true;
continue;
}
else if (msg[j] & 0x80) // stolen from video.c, nice.
if (!prev_linereturn)
{
++j;
continue;
chatheight += charheight;
dx = 0;
}
++j;
prev_linereturn = true;
}
else
else if (msg[j] >= FONTSTART)
{
j++;
}
prev_linereturn = false;
dx += charwidth;
if (dx >= boxw)
{
dx = 0;
linescount += 1;
prev_linereturn = false;
dx += charwidth;
if (dx >= boxw-charwidth-2)
{
dx = 0;
chatheight += charheight;
prev_linereturn = true;
}
}
}
dy = 0;
dx = 0;
msglines += linescount+1;
chatheight += charheight;
if (msg)
Z_Free(msg);
}
y = chaty - charheight*(msglines+1);
/*if (splitscreen)
{
y -= BASEVIDHEIGHT/2;
if (splitscreen > 1)
y += 16;
}*/
dx = 0;
dy = 0;
i = 0;
y = chaty - (chatheight + charheight);
prev_linereturn = false;
for (; i<=(chat_nummsg_min-1); i++) // iterate through our hot messages
for (size_t i = 0; i < chat_nummsg_min; i++) // iterate through our hot messages
{
INT32 clrflag = 0;
INT32 timer = ((cv_chattime.value*TICRATE)-chat_timers[i]) - cv_chattime.value*TICRATE+9; // see below...
INT32 transflag = (timer >= 0 && timer <= 9) ? (timer*V_10TRANS) : 0; // you can make bad jokes out of this one.
size_t j = 0;
char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it.
char *msg = V_ChatWordWrap(0, boxw-charwidth-2, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE|V_MONOSPACE, chat_mini[i]); // get the current message, and word wrap it.
UINT8 *colormap = NULL;
while(msg[j]) // iterate through msg
for(size_t j = 0; msg[j]; j++) // iterate through msg
{
if (msg[j] < HU_FONTSTART) // don't draw
if (msg[j] == '\n') // get back down.
{
if (msg[j] == '\n') // get back down.
{
++j;
if (!prev_linereturn)
{
dy += charheight;
dx = 0;
}
prev_linereturn = true;
continue;
}
else if (msg[j] & 0x80) // stolen from video.c, nice.
if (!prev_linereturn)
{
clrflag = ((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
colormap = V_GetStringColormap(clrflag);
++j;
continue;
dy += charheight;
dx = 0;
}
++j;
prev_linereturn = true;
}
else
else if (msg[j] & 0x80) // get colormap
colormap = V_GetStringColormap(((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK);
else if (msg[j] >= FONTSTART)
{
prev_linereturn = false;
if (cv_chatbacktint.value) // on request of wolfy
V_DrawFillConsoleMap(x + dx + 2, y+dy, charwidth, charheight, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT);
V_DrawChatCharacter(x + dx + 2, y+dy, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|transflag, true, colormap);
}
V_DrawChatCharacter(x + dx + 2, y+dy, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_MONOSPACE|transflag, true, colormap);
dx += charwidth;
dx += charwidth;
prev_linereturn = false;
if (dx >= boxw)
{
dx = 0;
dy += charheight;
if (dx >= boxw-charwidth-2)
{
dx = 0;
dy += charheight;
prev_linereturn = true;
}
}
}
dy += charheight;
......@@ -1434,7 +1326,6 @@ static void HU_drawMiniChat(void)
// decrement addy and make that shit smooth:
addy /= 2;
}
// HU_DrawChatLog
......@@ -1447,6 +1338,7 @@ static void HU_drawChatLog(INT32 offset)
UINT32 i = 0;
INT32 chat_topy, chat_bottomy;
boolean atbottom = false;
boolean prev_linereturn = false;
// make sure that our scroll position isn't "illegal";
if (chat_scroll > chat_maxscroll)
......@@ -1479,44 +1371,39 @@ static void HU_drawChatLog(INT32 offset)
for (i=0; i<chat_nummsg_log; i++) // iterate through our chatlog
{
INT32 clrflag = 0;
INT32 j = 0;
char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_log[i]); // get the current message, and word wrap it.
char *msg = V_ChatWordWrap(0, boxw-charwidth-2, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE|V_MONOSPACE, chat_log[i]); // get the current message, and word wrap it.
UINT8 *colormap = NULL;
while(msg[j]) // iterate through msg
for(size_t j = 0; msg[j]; j++) // iterate through msg
{
if (msg[j] < HU_FONTSTART) // don't draw
if (msg[j] == '\n') // get back down.
{
if (msg[j] == '\n') // get back down.
if (!prev_linereturn)
{
++j;
dy += charheight;
dx = 0;
continue;
}
else if (msg[j] & 0x80) // stolen from video.c, nice.
{
clrflag = ((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
colormap = V_GetStringColormap(clrflag);
++j;
continue;
}
++j;
prev_linereturn = true;
}
else if (msg[j] & 0x80) // get colormap
colormap = V_GetStringColormap(((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK);
else
{
if ((y+dy+2 >= chat_topy) && (y+dy < (chat_bottomy)))
V_DrawChatCharacter(x + dx + 2, y+dy+2, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT, true, colormap);
else
j++; // don't forget to increment this or we'll get stuck in the limbo.
}
prev_linereturn = false;
dx += charwidth;
if (dx >= boxw-charwidth-2 && i<chat_nummsg_log && msg[j] >= HU_FONTSTART) // end of message shouldn't count, nor should invisible characters!!!!
{
dx = 0;
dy += charheight;
if (msg[j] >= FONTSTART)
{
if ((y+dy+2 >= chat_topy) && (y+dy < (chat_bottomy)))
V_DrawChatCharacter(x + dx + 2, y+dy+2, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_MONOSPACE, true, colormap);
dx += charwidth;
}
if (dx >= boxw-charwidth-2 && i < chat_nummsg_log) // end of message shouldn't count, nor should invisible characters!!!!
{
dx = 0;
dy += charheight;
prev_linereturn = true;
}
}
}
dy += charheight;
......@@ -1526,30 +1413,25 @@ static void HU_drawChatLog(INT32 offset)
Z_Free(msg);
}
if (((chat_scroll >= chat_maxscroll) || (chat_scrollmedown)) && !(justscrolleddown || justscrolledup || chat_scrolltime)) // was already at the bottom of the page before new maxscroll calculation and was NOT scrolling.
{
atbottom = true; // we should scroll
}
chat_scrollmedown = false;
// getmaxscroll through a lazy hack. We do all these loops,
// so let's not do more loops that are gonna lag the game more. :P
// getmaxscroll through a lazy hack. We do all these loops, so let's not do more loops that are gonna lag the game more. :P
chat_maxscroll = max(dy / charheight - cv_chatheight.value, 0);
// if we're not bound by the time, autoscroll for next frame:
if (atbottom)
chat_scroll = chat_maxscroll;
// draw arrows to indicate that we can (or not) scroll.
// account for Y = -1 offset in tinyfont
// draw arrows to indicate that we can (or not) scroll, accounting for Y = -1 offset in tinyfont
if (chat_scroll > 0)
V_DrawThinString(chatx-8, ((justscrolledup) ? (chat_topy-1) : (chat_topy)) - 1, V_SNAPTOBOTTOM | V_SNAPTOLEFT | V_YELLOWMAP, "\x1A"); // up arrow
if (chat_scroll < chat_maxscroll)
V_DrawThinString(chatx-8, chat_bottomy-((justscrolleddown) ? 5 : 6) - 1, V_SNAPTOBOTTOM | V_SNAPTOLEFT | V_YELLOWMAP, "\x1B"); // down arrow
justscrolleddown = false;
justscrolledup = false;
justscrolleddown = justscrolledup = false;
}
//
......@@ -1567,7 +1449,6 @@ static void HU_DrawChat(void)
INT32 cflag = 0;
const char *ntalk = "Say: ", *ttalk = "Team: ";
const char *talk = ntalk;
const char *mute = "Chat has been muted.";
#ifdef NETSPLITSCREEN
if (splitscreen)
......@@ -1582,35 +1463,24 @@ static void HU_DrawChat(void)
#endif
if (teamtalk)
{
talk = ttalk;
#if 0
if (players[consoleplayer].ctfteam == 1)
t = 0x500; // Red
else if (players[consoleplayer].ctfteam == 2)
t = 0x400; // Blue
#endif
}
if (CHAT_MUTE)
{
talk = mute;
if (cv_mute.value)
talk = "Chat has been muted.";
else
talk = "You have been muted.";
typelines = 1;
cflag = V_GRAYMAP; // set text in gray if chat is muted.
}
V_DrawFillConsoleMap(chatx, y-1, boxw, (typelines*charheight), 239 | V_SNAPTOBOTTOM | V_SNAPTOLEFT);
while (talk[i])
for (i = 0; talk[i]; i++)
{
if (talk[i] < HU_FONTSTART)
++i;
else
{
if (talk[i] >= FONTSTART)
V_DrawChatCharacter(chatx + c + 2, y, talk[i] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|cflag, true, V_GetStringColormap(talk[i]|cflag));
i++;
}
c += charwidth;
}
......@@ -1621,13 +1491,12 @@ static void HU_DrawChat(void)
return;
}
i = 0;
typelines = 1;
if ((strlen(w_chat) == 0 || c_input == 0) && hu_tick < 4)
V_DrawChatCharacter(chatx + 2 + c, y+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, true, NULL);
while (w_chat[i])
for (i = 0; w_chat[i]; i++)
{
boolean skippedline = false;
if (c_input == (i+1))
......@@ -1644,14 +1513,11 @@ static void HU_DrawChat(void)
}
}
//Hurdler: isn't it better like that?
if (w_chat[i] < HU_FONTSTART)
++i;
else
V_DrawChatCharacter(chatx + c + 2, y, w_chat[i++] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, true, NULL);
if (w_chat[i] >= FONTSTART)
V_DrawChatCharacter(chatx + c + 2, y, w_chat[i] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, true, NULL);
c += charwidth;
if (c > boxw-(charwidth*2) && !skippedline)
if (c > boxw-charwidth && !skippedline)
{
c = 0;
y += charheight;
......@@ -1673,47 +1539,31 @@ static void HU_DrawChat(void)
}
#endif
i = 0;
for(i=0; (i<MAXPLAYERS); i++)
for(i=0; i<MAXPLAYERS; i++)
{
// filter: (code needs optimization pls help I'm bad with C)
if (w_chat[3])
{
char playernum[3];
char playernum[3+1];
UINT32 n;
// right, that's half important: (w_chat[4] may be a space since /pm0 msg is perfectly acceptable!)
if ( ( ((w_chat[3] != 0) && ((w_chat[3] < '0') || (w_chat[3] > '9'))) || ((w_chat[4] != 0) && (((w_chat[4] < '0') || (w_chat[4] > '9'))))) && (w_chat[4] != ' '))
break;
strncpy(playernum, w_chat+3, 3);
strncpy(playernum, w_chat+3, sizeof(playernum)-1);
playernum[3] = 0;
n = atoi(playernum); // turn that into a number
// special cases:
if ((n == 0) && !(w_chat[4] == '0'))
{
if (!(i<10))
continue;
}
else if ((n == 1) && !(w_chat[3] == '0'))
{
if (!((i == 1) || ((i >= 10) && (i <= 19))))
continue;
}
else if ((n == 2) && !(w_chat[3] == '0'))
{
if (!((i == 2) || ((i >= 20) && (i <= 29))))
continue;
}
else if ((n == 3) && !(w_chat[3] == '0'))
{
if (!((i == 3) || ((i >= 30) && (i <= 31))))
continue;
}
if ((n == 0) && !(w_chat[4] == '0') && (!(i<10)))
continue;
else if ((n == 1) && !(w_chat[3] == '0') && (!((i == 1) || ((i >= 10) && (i <= 19)))))
continue;
else if ((n == 2) && !(w_chat[3] == '0') && (!((i == 2) || ((i >= 20) && (i <= 29)))))
continue;
else if ((n == 3) && !(w_chat[3] == '0') && (!((i == 3) || ((i >= 30) && (i <= 31)))))
continue;
else // general case.
{
if (i != n)
continue;
}
if (i != n) continue;
}
if (playeringame[i])
......@@ -1744,41 +1594,22 @@ static void HU_DrawChat_Old(void)
size_t i = 0;
const char *ntalk = "Say: ", *ttalk = "Say-Team: ";
const char *talk = ntalk;
INT32 charwidth = 8 * con_scalefactor; //(hu_font['A'-HU_FONTSTART]->width) * con_scalefactor;
INT32 charheight = 8 * con_scalefactor; //(hu_font['A'-HU_FONTSTART]->height) * con_scalefactor;
INT32 charwidth = 8 * con_scalefactor, charheight = 8 * con_scalefactor;
if (teamtalk)
{
talk = ttalk;
#if 0
if (players[consoleplayer].ctfteam == 1)
t = 0x500; // Red
else if (players[consoleplayer].ctfteam == 2)
t = 0x400; // Blue
#endif
}
while (talk[i])
for (i = 0; talk[i]; i++)
{
if (talk[i] < HU_FONTSTART)
{
++i;
//charwidth = 4 * con_scalefactor;
}
else
{
//charwidth = (hu_font[talk[i]-HU_FONTSTART]->width) * con_scalefactor;
V_DrawCharacter(HU_INPUTX + c, y, talk[i++] | cv_constextsize.value | V_NOSCALESTART, true);
}
if (talk[i] >= FONTSTART)
V_DrawCharacter(HU_INPUTX + c, y, talk[i] | cv_constextsize.value | V_NOSCALESTART, true);
c += charwidth;
}
if ((strlen(w_chat) == 0 || c_input == 0) && hu_tick < 4)
V_DrawCharacter(HU_INPUTX+c, y+2*con_scalefactor, '_' |cv_constextsize.value | V_NOSCALESTART|t, true);
i = 0;
while (w_chat[i])
for (i = 0; w_chat[i]; i++)
{
if (c_input == (i+1) && hu_tick < 4)
{
INT32 cursorx = (HU_INPUTX+c+charwidth < vid.width) ? (HU_INPUTX + c + charwidth) : (HU_INPUTX); // we may have to go down.
......@@ -1786,17 +1617,8 @@ static void HU_DrawChat_Old(void)
V_DrawCharacter(cursorx, cursory+2*con_scalefactor, '_' |cv_constextsize.value | V_NOSCALESTART|t, true);
}
//Hurdler: isn't it better like that?
if (w_chat[i] < HU_FONTSTART)
{
++i;
//charwidth = 4 * con_scalefactor;
}
else
{
//charwidth = (hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor;
V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | cv_constextsize.value | V_NOSCALESTART | t, true);
}
if (w_chat[i] >= FONTSTART)
V_DrawCharacter(HU_INPUTX + c, y, w_chat[i] | cv_constextsize.value | V_NOSCALESTART | t, true);
c += charwidth;
if (c >= vid.width)
......@@ -1805,9 +1627,6 @@ static void HU_DrawChat_Old(void)
y += charheight;
}
}
if (hu_tick < 4)
V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true);
}
// Draw crosshairs at the exact center of the view.
......@@ -1893,21 +1712,6 @@ static void HU_DrawCEcho(void)
}
}
static void HU_drawGametype(void)
{
const char *strvalue = NULL;
if (gametype < 0 || gametype >= gametypecount)
return; // not a valid gametype???
strvalue = Gametype_Names[gametype];
if (splitscreen)
V_DrawString(4, 184, 0, strvalue);
else
V_DrawString(4, 192, 0, strvalue);
}
//
// demo info stuff
//
......@@ -1948,24 +1752,28 @@ static void HU_DrawDemoInfo(void)
//
void HU_Drawer(void)
{
// draw chat string plus cursor
if (chat_on)
if (LUA_HudEnabled(hud_chat))
{
if (!OLDCHAT)
HU_DrawChat();
// draw chat string plus cursor
if (chat_on)
{
if (!OLDCHAT)
HU_DrawChat();
else
HU_DrawChat_Old();
}
else
HU_DrawChat_Old();
}
else
{
typelines = 1;
chat_scrolltime = 0;
{
typelines = 1;
chat_scrolltime = 0;
if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden)
HU_drawMiniChat(); // draw messages in a cool fashion.
if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden)
HU_drawMiniChat(); // draw messages in a cool fashion.
}
}
if (cechotimer)
if (cechotimer && LUA_HudEnabled(hud_cecho))
HU_DrawCEcho();
if (demoplayback && hu_showscores)
......@@ -2044,76 +1852,6 @@ void HU_Drawer(void)
}
}
//======================================================================
// HUD MESSAGES CLEARING FROM SCREEN
//======================================================================
// Clear old messages from the borders around the view window
// (only for reduced view, refresh the borders when needed)
//
// startline: y coord to start clear,
// clearlines: how many lines to clear.
//
static INT32 oldclearlines;
void HU_Erase(void)
{
INT32 topline, bottomline;
INT32 y, yoffset;
#ifdef HWRENDER
// clear hud msgs on double buffer (OpenGL mode)
boolean secondframe;
static INT32 secondframelines;
#endif
if (con_clearlines == oldclearlines && !con_hudupdate && !chat_on)
return;
#ifdef HWRENDER
// clear the other frame in double-buffer modes
secondframe = (con_clearlines != oldclearlines);
if (secondframe)
secondframelines = oldclearlines;
#endif
// clear the message lines that go away, so use _oldclearlines_
bottomline = oldclearlines;
oldclearlines = con_clearlines;
if (chat_on && OLDCHAT)
if (bottomline < 8)
bottomline = 8; // only do it for consolechat. consolechat is gay.
if (automapactive || viewwindowx == 0) // hud msgs don't need to be cleared
return;
// software mode copies view border pattern & beveled edges from the backbuffer
if (rendermode == render_soft)
{
topline = 0;
for (y = topline, yoffset = y*vid.width; y < bottomline; y++, yoffset += vid.width)
{
if (y < viewwindowy || y >= viewwindowy + viewheight)
R_VideoErase(yoffset, vid.width); // erase entire line
else
{
R_VideoErase(yoffset, viewwindowx); // erase left border
// erase right border
R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx);
}
}
con_hudupdate = false; // if it was set..
}
#ifdef HWRENDER
else if (rendermode != render_none)
{
// refresh just what is needed from the view borders
HWR_DrawViewBorder(secondframelines);
con_hudupdate = secondframe;
}
#endif
}
//======================================================================
// IN-LEVEL MULTIPLAYER RANKINGS
//======================================================================
......@@ -2328,13 +2066,13 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer)
greycheck = greycheckdef;
supercheck = supercheckdef;
if (tab[i].color == skincolor_redteam) //red
if (players[tab[i].num].ctfteam == 1) //red
{
redplayers++;
x = 14 + (BASEVIDWIDTH/2);
y = (redplayers * 9) + 20;
}
else if (tab[i].color == skincolor_blueteam) //blue
else if (players[tab[i].num].ctfteam == 2) //blue
{
blueplayers++;
x = 14;
......@@ -2416,7 +2154,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
if (players[tab[i].num].spectator)
continue; //ignore them.
if (tab[i].color == skincolor_redteam) //red
if (players[tab[i].num].ctfteam == 1) //red
{
if (redplayers++ > 8)
{
......@@ -2424,7 +2162,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
break; // don't make more loops than we need to.
}
}
else if (tab[i].color == skincolor_blueteam) //blue
else if (players[tab[i].num].ctfteam == 2) //blue
{
if (blueplayers++ > 8)
{
......@@ -2455,14 +2193,14 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
if (players[tab[i].num].spectator)
continue; //ignore them.
if (tab[i].color == skincolor_redteam) //red
if (players[tab[i].num].ctfteam == 1) //red
{
if (redplayers++ > 8)
continue;
x = 32 + (BASEVIDWIDTH/2);
y = (redplayers * 16) + 16;
}
else if (tab[i].color == skincolor_blueteam) //blue
else if (players[tab[i].num].ctfteam == 2) //blue
{
if (blueplayers++ > 8)
continue;
......@@ -2776,53 +2514,20 @@ static inline void HU_DrawSpectatorTicker(void)
{
int i;
int length = 0, height = 174;
int totallength = 0, templength = 0;
int totallength = 0;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].spectator)
totallength += (signed)strlen(player_names[i]) * 8 + 16;
length -= (leveltime % (totallength + BASEVIDWIDTH));
length += BASEVIDWIDTH;
length -= (leveltime % (totallength + (vid.width / vid.dup)));
length += (vid.width / vid.dup);
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].spectator)
{
char *pos;
char initial[MAXPLAYERNAME+1];
char current[MAXPLAYERNAME+1];
strcpy(initial, player_names[i]);
pos = initial;
if (length >= -((signed)strlen(player_names[i]) * 8 + 16) && length <= BASEVIDWIDTH)
{
if (length < 0)
{
UINT8 eatenchars = (UINT8)(abs(length) / 8 + 1);
if (eatenchars <= strlen(initial))
{
// Eat one letter off the left side,
// then compensate the drawing position.
pos += eatenchars;
strcpy(current, pos);
templength = length % 8 + 8;
}
else
{
strcpy(current, " ");
templength = length;
}
}
else
{
strcpy(current, initial);
templength = length;
}
V_DrawString(templength, height + 8, V_TRANSLUCENT|V_ALLOWLOWERCASE, current);
}
if (length >= -((signed)strlen(player_names[i]) * 8 + 16) && length <= (vid.width / vid.dup))
V_DrawString(length, height + 8, V_TRANSLUCENT|V_ALLOWLOWERCASE|V_SNAPTOLEFT, player_names[i]);
length += (signed)strlen(player_names[i]) * 8 + 16;
}
......@@ -2839,7 +2544,8 @@ static void HU_DrawRankings(void)
UINT32 whiteplayer;
// draw the current gametype in the lower right
HU_drawGametype();
if (gametype >= 0 && gametype < gametypecount)
V_DrawString(4, splitscreen ? 184 : 192, 0, Gametype_Names[gametype]);
if (gametyperules & (GTR_TIMELIMIT|GTR_POINTLIMIT))
{
......@@ -3052,7 +2758,7 @@ void HU_DoCEcho(const char *msg)
{
I_OutputMsg("%s\n", msg); // print to log
strncpy(cechotext, msg, sizeof(cechotext));
strncpy(cechotext, msg, sizeof(cechotext)-1);
strncat(cechotext, "\\", sizeof(cechotext) - strlen(cechotext) - 1);
cechotext[sizeof(cechotext) - 1] = '\0';
cechotimer = cechoduration;
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -19,33 +19,34 @@
#include "r_defs.h"
//------------------------------------
// heads up font
// Fonts & stuff
//------------------------------------
#define HU_FONTSTART '\x16' // the first font character
#define HU_FONTEND '~'
#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
// Level title font
#define LT_FONTSTART '!' // the first font characters
#define LT_FONTEND 'z' // the last font characters
#define LT_FONTSIZE (LT_FONTEND - LT_FONTSTART + 1)
#define CRED_FONTSTART '!' // the first font character
#define CRED_FONTEND 'Z' // the last font character
#define CRED_FONTSIZE (CRED_FONTEND - CRED_FONTSTART + 1)
// Name tag font
// Used by base and outline font set
#define NT_FONTSTART '!' // the first font character
#define NT_FONTEND 'Z' // the last font character
#define NT_FONTSIZE (NT_FONTEND - NT_FONTSTART + 1)
#define FONTSTART '\x16' // the first font character
#define FONTEND '~'
#define FONTSIZE (FONTEND - FONTSTART + 1)
#define HU_CROSSHAIRS 3 // maximum of 9 - see HU_Init();
extern char *shiftxform; // english translation shift table
extern char english_shiftxform[];
typedef struct
{
patch_t *chars[FONTSIZE];
INT32 kerning;
UINT32 spacewidth;
UINT32 charwidth;
UINT32 linespacing;
} fontdef_t;
extern fontdef_t hu_font, tny_font, cred_font, lt_font;
extern fontdef_t ntb_font, nto_font;
extern patch_t *tallnum[10];
extern patch_t *nightsnum[10];
extern patch_t *ttlnum[10];
extern patch_t *tallminus;
extern patch_t *tallinfin;
//------------------------------------
// sorted player lines
//------------------------------------
......@@ -69,8 +70,8 @@ typedef struct
#else
#define OLDCHAT (cv_consolechat.value == 1 || dedicated || vid.width < 640 || splitscreen)
#endif
#define CHAT_MUTE (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer))) // this still allows to open the chat but not to type. That's used for scrolling and whatnot.
#define OLD_MUTE (OLDCHAT && cv_mute.value && !(server || IsPlayerAdmin(consoleplayer))) // this is used to prevent oldchat from opening when muted.
#define CHAT_MUTE ((cv_mute.value || players[consoleplayer].muted) && !(server || IsPlayerAdmin(consoleplayer))) // this still allows to open the chat but not to type. That's used for scrolling and whatnot.
#define OLD_MUTE (OLDCHAT && (cv_mute.value || players[consoleplayer].muted) && !(server || IsPlayerAdmin(consoleplayer))) // this is used to prevent oldchat from opening when muted.
// some functions
void HU_AddChatText(const char *text, boolean playsound);
......@@ -78,22 +79,15 @@ void HU_AddChatText(const char *text, boolean playsound);
// set true when entering a chat message
extern boolean chat_on;
extern patch_t *hu_font[HU_FONTSIZE], *tny_font[HU_FONTSIZE];
extern patch_t *tallnum[10];
extern patch_t *nightsnum[10];
extern patch_t *lt_font[LT_FONTSIZE];
extern patch_t *cred_font[CRED_FONTSIZE];
extern patch_t *ntb_font[NT_FONTSIZE];
extern patch_t *nto_font[NT_FONTSIZE];
extern patch_t *ttlnum[10];
extern UINT8 spam_tokens[MAXPLAYERS];
extern tic_t spam_tics[MAXPLAYERS];
extern patch_t *emeraldpics[3][8];
extern patch_t *rflagico;
extern patch_t *bflagico;
extern patch_t *rmatcico;
extern patch_t *bmatcico;
extern patch_t *tagico;
extern patch_t *tallminus;
extern patch_t *tallinfin;
extern patch_t *tokenicon;
// set true whenever the tab rankings are being shown for any reason
......@@ -103,6 +97,8 @@ extern boolean hu_showscores;
void HU_Init(void);
void HU_LoadGraphics(void);
void HU_LoadFontCharacters(fontdef_t *font, const char *prefix);
void HU_SetFontProperties(fontdef_t *font, INT32 kerning, UINT32 spacewidth, UINT32 charwidth, UINT32 linespacing);
// reset heads up when consoleplayer respawns.
void HU_Start(void);
......@@ -111,7 +107,6 @@ boolean HU_Responder(event_t *ev);
void HU_Ticker(void);
void HU_Drawer(void);
char HU_dequeueChatChar(void);
void HU_Erase(void);
void HU_clearChatChars(void);
void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags); // Lat': Ping drawer for scoreboard.
void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer);
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -335,4 +335,16 @@ void I_GetCursorPosition(INT32 *x, INT32 *y);
*/
void I_SetMouseGrab(boolean grab);
/** \brief Returns the system name.
*/
const char *I_GetSysName(void);
/** \brief Sets text input mode. When enabled, keyboard inputs will respect dead keys.
*/
void I_SetTextInputMode(boolean active);
/** \brief Retrieves current text input mode.
*/
boolean I_GetTextInputMode(void);
#endif
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -40,10 +40,6 @@ extern rendermode_t rendermode;
*/
extern rendermode_t chosenrendermode;
/** \brief use highcolor modes if true
*/
extern boolean highcolor;
/** \brief setup video mode
*/
void I_StartupGraphics(void);
......@@ -108,8 +104,8 @@ void VID_CheckGLLoaded(rendermode_t oldrender);
\return name of video mode
*/
const char *VID_GetModeName(INT32 modenum);
void VID_PrepareModeList(void); /// note hack for SDL
void VID_PrepareModeList(void);
/** \brief can video system do fullscreen
*/
......
Source diff could not be displayed: it is too large. Options to address this: view the blob.