mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
1037 lines
34 KiB
C++
1037 lines
34 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
IceTech GPL Source Code
|
|
Copyright (C) 2026 Justin Marshall
|
|
|
|
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
|
|
|
|
IceTech Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
IceTech Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#ifndef __MATERIAL_H__
|
|
#define __MATERIAL_H__
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Material
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
class idImage;
|
|
class idCinematic;
|
|
class idUserInterface;
|
|
class idMegaTexture;
|
|
#ifdef QUAKE4
|
|
class rvNewShaderStage;
|
|
class rvGLSLShaderStage;
|
|
class rvDeclMatType;
|
|
class idVec2;
|
|
class idVec3;
|
|
#endif
|
|
|
|
#ifdef PREY
|
|
// HUMANHEAD tmj: type of subview that this surface represents
|
|
typedef enum {
|
|
SC_MIRROR,
|
|
SC_PORTAL,
|
|
SC_PORTAL_SKYBOX,
|
|
} subviewClass_t;
|
|
#endif
|
|
|
|
// moved from image.h for default parm
|
|
typedef enum {
|
|
TF_LINEAR,
|
|
TF_NEAREST,
|
|
TF_DEFAULT // use the user-specified r_textureFilter
|
|
} textureFilter_t;
|
|
|
|
typedef enum {
|
|
TR_REPEAT,
|
|
TR_CLAMP,
|
|
TR_CLAMP_TO_BORDER, // this should replace TR_CLAMP_TO_ZERO and TR_CLAMP_TO_ZERO_ALPHA,
|
|
// but I don't want to risk changing it right now
|
|
TR_CLAMP_TO_ZERO, // guarantee 0,0,0,255 edge for projected textures,
|
|
// set AFTER image format selection
|
|
TR_CLAMP_TO_ZERO_ALPHA // guarantee 0 alpha edge for projected textures,
|
|
// set AFTER image format selection
|
|
#ifdef QUAKE4
|
|
, TR_MIRRORED_REPEAT // RAVEN: mirrored texture repeat mode
|
|
#endif
|
|
} textureRepeat_t;
|
|
|
|
typedef struct {
|
|
int stayTime; // msec for no change
|
|
#ifdef QUAKE4
|
|
float maxAngle; // maximum dot product to reject projection angles
|
|
#else
|
|
int fadeTime; // msec to fade vertex colors over
|
|
float start[4]; // vertex color at spawn (possibly out of 0.0 - 1.0 range, will clamp after calc)
|
|
float end[4]; // vertex color at fade-out (possibly out of 0.0 - 1.0 range, will clamp after calc)
|
|
#endif
|
|
} decalInfo_t;
|
|
|
|
typedef enum {
|
|
DFRM_NONE,
|
|
DFRM_SPRITE,
|
|
DFRM_TUBE,
|
|
DFRM_FLARE,
|
|
DFRM_EXPAND,
|
|
DFRM_MOVE,
|
|
DFRM_EYEBALL,
|
|
#ifdef QUAKE4
|
|
DFRM_RECTSPRITE, // RAVEN: rectangular sprites
|
|
#else
|
|
DFRM_PARTICLE,
|
|
DFRM_PARTICLE2,
|
|
#endif
|
|
DFRM_TURB
|
|
} deform_t;
|
|
|
|
typedef enum {
|
|
DI_STATIC,
|
|
DI_SCRATCH, // video, screen wipe, etc
|
|
DI_CUBE_RENDER,
|
|
DI_MIRROR_RENDER,
|
|
#ifdef QUAKE4
|
|
DI_REFLECTION_RENDER, // RAVEN: water reflection
|
|
DI_REFRACTION_RENDER, // RAVEN: water refraction
|
|
#else
|
|
DI_XRAY_RENDER,
|
|
#endif
|
|
#ifdef PREY
|
|
DI_PORTAL_RENDER, // HUMANHEAD
|
|
DI_SKYBOX_RENDER, // HUMANHEAD tmj
|
|
#endif
|
|
DI_REMOTE_RENDER
|
|
} dynamicidImage_t;
|
|
|
|
// note: keep opNames[] in sync with changes
|
|
typedef enum {
|
|
OP_TYPE_ADD,
|
|
OP_TYPE_SUBTRACT,
|
|
OP_TYPE_MULTIPLY,
|
|
OP_TYPE_DIVIDE,
|
|
OP_TYPE_MOD,
|
|
OP_TYPE_TABLE,
|
|
OP_TYPE_GT,
|
|
OP_TYPE_GE,
|
|
OP_TYPE_LT,
|
|
OP_TYPE_LE,
|
|
OP_TYPE_EQ,
|
|
OP_TYPE_NE,
|
|
OP_TYPE_AND,
|
|
OP_TYPE_OR,
|
|
OP_TYPE_SOUND
|
|
#ifdef PREY
|
|
, OP_TYPE_FRAGMENTPROGRAMS // HUMANHEAD CJR: fragment program support toggle
|
|
#endif
|
|
#ifdef QUAKE4
|
|
, OP_TYPE_GLSL_ENABLED,
|
|
OP_TYPE_POT_X,
|
|
OP_TYPE_POT_Y
|
|
#endif
|
|
} expOpType_t;
|
|
|
|
typedef enum {
|
|
EXP_REG_TIME,
|
|
|
|
EXP_REG_PARM0,
|
|
EXP_REG_PARM1,
|
|
EXP_REG_PARM2,
|
|
EXP_REG_PARM3,
|
|
EXP_REG_PARM4,
|
|
EXP_REG_PARM5,
|
|
EXP_REG_PARM6,
|
|
EXP_REG_PARM7,
|
|
EXP_REG_PARM8,
|
|
EXP_REG_PARM9,
|
|
EXP_REG_PARM10,
|
|
EXP_REG_PARM11,
|
|
|
|
EXP_REG_GLOBAL0,
|
|
EXP_REG_GLOBAL1,
|
|
EXP_REG_GLOBAL2,
|
|
EXP_REG_GLOBAL3,
|
|
EXP_REG_GLOBAL4,
|
|
EXP_REG_GLOBAL5,
|
|
EXP_REG_GLOBAL6,
|
|
EXP_REG_GLOBAL7,
|
|
|
|
#ifdef QUAKE4
|
|
EXP_REG_VERTEX_RANDOMIZER, // RAVEN: per-vertex randomizer
|
|
#endif
|
|
#ifdef PREY
|
|
EXP_REG_DISTANCE, // HUMANHEAD: CJR
|
|
#endif
|
|
|
|
EXP_REG_NUM_PREDEFINED
|
|
} expRegister_t;
|
|
|
|
#ifdef QUAKE4
|
|
// RAVEN: decal expression aliases
|
|
#define EXP_REG_DECAL_LIFE EXP_REG_PARM4
|
|
#define REG_DECAL_LIFE 4
|
|
#define EXP_REG_DECAL_SPAWN EXP_REG_PARM5
|
|
#define REG_DECAL_SPAWN 5
|
|
#endif
|
|
|
|
typedef struct {
|
|
expOpType_t opType;
|
|
int a, b, c;
|
|
} expOp_t;
|
|
|
|
typedef struct {
|
|
int registers[4];
|
|
} colorStage_t;
|
|
|
|
typedef enum {
|
|
TG_EXPLICIT,
|
|
TG_DIFFUSE_CUBE,
|
|
TG_REFLECT_CUBE,
|
|
TG_SKYBOX_CUBE,
|
|
TG_WOBBLESKY_CUBE,
|
|
TG_SCREEN, // screen aligned, for mirrorRenders and screen space temporaries
|
|
TG_SCREEN2,
|
|
TG_GLASSWARP
|
|
#ifdef QUAKE4
|
|
, TG_POT_CORRECTION // RAVEN: non-power-of-two correction texgen
|
|
#endif
|
|
} texgen_t;
|
|
|
|
typedef struct {
|
|
idCinematic* cinematic;
|
|
idImage* image;
|
|
texgen_t texgen;
|
|
bool hasMatrix;
|
|
int matrix[2][3]; // we only allow a subset of the full projection matrix
|
|
|
|
// dynamic image variables
|
|
dynamicidImage_t dynamic;
|
|
int width, height;
|
|
int dynamicFrameCount;
|
|
} textureStage_t;
|
|
|
|
// the order BUMP / DIFFUSE / SPECULAR is necessary for interactions to draw correctly on low end cards
|
|
typedef enum {
|
|
SL_AMBIENT, // execute after lighting
|
|
SL_BUMP,
|
|
SL_DIFFUSE,
|
|
SL_SPECULAR,
|
|
SL_GLOWMAP
|
|
#ifdef PREY
|
|
, SL_SHADER
|
|
#endif
|
|
} stageLighting_t;
|
|
|
|
// cross-blended terrain textures need to modulate the color by
|
|
// the vertex color to smoothly blend between two textures
|
|
typedef enum {
|
|
SVC_IGNORE,
|
|
SVC_MODULATE,
|
|
SVC_INVERSE_MODULATE
|
|
} stageVertexColor_t;
|
|
|
|
static const int MAX_FRAGMENT_IMAGES = 8;
|
|
#ifdef QUAKE4
|
|
static const int MAX_VERTEX_PARMS = 16;
|
|
static const int MAX_FRAGMENT_PARMS = 8;
|
|
#elif defined( PREY )
|
|
static const int MAX_VERTEX_PARMS = 8;
|
|
static const int MAX_FRAGMENT_PARMS = 8;
|
|
#else
|
|
static const int MAX_VERTEX_PARMS = 4;
|
|
#endif
|
|
|
|
typedef struct {
|
|
int vertexProgram;
|
|
#ifdef QUAKE4
|
|
#if defined( _MD5R_SUPPORT ) || defined( Q4SDK_MD5R )
|
|
int md5rVertexProgram; // RAVEN: MD5R-specific vertex program
|
|
#endif
|
|
#endif
|
|
int numVertexParms;
|
|
int vertexParms[MAX_VERTEX_PARMS][4]; // evaluated register indexes
|
|
#if defined( PREY ) || defined( QUAKE4 )
|
|
int numFragmentParms;
|
|
int fragmentParms[MAX_FRAGMENT_PARMS][4]; // evaluated register indexes
|
|
#endif
|
|
|
|
int fragmentProgram;
|
|
int numFragmentProgramImages;
|
|
idImage* fragmentProgramImages[MAX_FRAGMENT_IMAGES];
|
|
#ifdef QUAKE4
|
|
bool vertexParmsBindings[MAX_VERTEX_PARMS];
|
|
bool fragmentParmsBindings[MAX_FRAGMENT_PARMS];
|
|
int fragmentProgramBindings[MAX_FRAGMENT_IMAGES];
|
|
#endif
|
|
|
|
idMegaTexture* megaTexture; // handles all the binding and parameter setting
|
|
} newShaderStage_t;
|
|
|
|
#ifdef PREY
|
|
// HUMANHEAD bjk: specular exponent/brightness parsed by specularExp.
|
|
typedef struct {
|
|
float exponent;
|
|
float brightness;
|
|
} specData_t;
|
|
#endif
|
|
|
|
typedef struct {
|
|
int conditionRegister; // if registers[conditionRegister] == 0, skip stage
|
|
stageLighting_t lighting; // determines which passes interact with lights
|
|
int drawStateBits;
|
|
colorStage_t color;
|
|
bool hasAlphaTest;
|
|
#ifdef QUAKE4
|
|
bool hasAlphaFunc;
|
|
int alphaTestMode;
|
|
#endif
|
|
int alphaTestRegister;
|
|
textureStage_t texture;
|
|
stageVertexColor_t vertexColor;
|
|
bool ignoreAlphaTest; // this stage should act as translucent, even
|
|
// if the surface is alpha tested
|
|
float privatePolygonOffset; // a per-stage polygon offset
|
|
#ifdef PREY
|
|
|
|
bool isGlow; // HUMANHEAD CJR: Glow overlay
|
|
bool isScopeView; // HUMANHEAD CJR: Scope view
|
|
bool isShuttleView; // HUMANHEAD pdm: shuttle view
|
|
bool isNotScopeView; // HUMANHEAD CJR
|
|
bool isSpiritWalk; // HUMANHEAD CJR
|
|
bool isNotSpiritWalk; // HUMANHEAD CJR
|
|
#endif
|
|
|
|
newShaderStage_t* newStage; // vertex / fragment program based stage
|
|
#ifdef QUAKE4
|
|
rvNewShaderStage* newShaderStage; // RAVEN: GLSL/new shader stage system
|
|
int mStageRegisterStart;
|
|
int mNumStageRegisters;
|
|
int mStageOpsStart;
|
|
int mNumStageOps;
|
|
#endif
|
|
#ifdef PREY
|
|
specData_t specular; // HUMANHEAD bjk
|
|
#endif
|
|
} shaderStage_t;
|
|
|
|
typedef enum {
|
|
MC_BAD,
|
|
MC_OPAQUE, // completely fills the triangle, will have black drawn on fillDepthBuffer
|
|
MC_PERFORATED, // may have alpha tested holes
|
|
MC_TRANSLUCENT // blended with background
|
|
} materialCoverage_t;
|
|
|
|
typedef enum {
|
|
#ifdef QUAKE4
|
|
SS_MIN = -10000,
|
|
SS_SUBVIEW = -4, // mirrors, viewscreens, etc
|
|
SS_PREGUI = -3, // RAVEN: pre-gui sort
|
|
#else
|
|
SS_SUBVIEW = -3, // mirrors, viewscreens, etc
|
|
#endif
|
|
SS_GUI = -2, // guis
|
|
SS_BAD = -1,
|
|
SS_OPAQUE, // opaque
|
|
|
|
SS_PORTAL_SKY,
|
|
|
|
SS_DECAL, // scorch marks, etc.
|
|
|
|
SS_FAR,
|
|
SS_MEDIUM, // normal translucent
|
|
SS_CLOSE,
|
|
|
|
SS_ALMOST_NEAREST, // gun smoke puffs
|
|
|
|
SS_NEAREST, // screen blood blobs
|
|
|
|
SS_POST_PROCESS = 100 // after a screen copy to texture
|
|
#ifdef QUAKE4
|
|
, SS_MAX = 10000
|
|
#endif
|
|
} materialSort_t;
|
|
|
|
typedef enum {
|
|
CT_FRONT_SIDED,
|
|
CT_BACK_SIDED,
|
|
CT_TWO_SIDED
|
|
} cullType_t;
|
|
|
|
// these don't effect per-material storage, so they can be very large
|
|
const int MAX_SHADER_STAGES = 256;
|
|
|
|
const int MAX_TEXGEN_REGISTERS = 4;
|
|
|
|
#ifdef PREY
|
|
const int MAX_ENTITY_SHADER_PARMS = 13; // HUMANHEAD pdm: increased from 12
|
|
#else
|
|
const int MAX_ENTITY_SHADER_PARMS = 12;
|
|
#endif
|
|
|
|
// material flags
|
|
typedef enum {
|
|
MF_DEFAULTED = BIT(0),
|
|
MF_POLYGONOFFSET = BIT(1),
|
|
MF_NOSHADOWS = BIT(2),
|
|
MF_FORCESHADOWS = BIT(3),
|
|
MF_NOSELFSHADOW = BIT(4),
|
|
MF_NOPORTALFOG = BIT(5), // this fog volume won't ever consider a portal fogged out
|
|
MF_EDITOR_VISIBLE = BIT(6), // in use (visible) per editor
|
|
#ifdef QUAKE4
|
|
MF_SKY = BIT(7), // RAVEN: portal/sky material marker
|
|
MF_NEED_CURRENT_RENDER = BIT(8), // RAVEN: preserve GUI sort while requesting current render
|
|
#elif defined( PREY )
|
|
MF_USESDISTANCE = BIT(7), // HUMANHEAD pdm: distance optimization
|
|
MF_LIGHT_WHOLE_MESH = BIT(8), // HUMANHEAD bjk: don't cull tris with light bounds
|
|
#endif
|
|
MF_SKIPCLIP = BIT(9)
|
|
} materialFlags_t;
|
|
|
|
// contents flags, NOTE: make sure to keep the defines in doom_defs.script up to date with these!
|
|
typedef enum {
|
|
CONTENTS_SOLID = BIT(0), // an eye is never valid in a solid
|
|
CONTENTS_OPAQUE = BIT(1), // blocks visibility (for ai)
|
|
CONTENTS_WATER = BIT(2), // used for water
|
|
CONTENTS_PLAYERCLIP = BIT(3), // solid to players
|
|
CONTENTS_MONSTERCLIP = BIT(4), // solid to monsters
|
|
CONTENTS_MOVEABLECLIP = BIT(5), // solid to moveable entities
|
|
CONTENTS_IKCLIP = BIT(6), // solid to IK
|
|
CONTENTS_BLOOD = BIT(7), // used to detect blood decals
|
|
CONTENTS_BODY = BIT(8), // used for actors
|
|
CONTENTS_PROJECTILE = BIT(9), // used for projectiles
|
|
CONTENTS_CORPSE = BIT(10), // used for dead bodies
|
|
CONTENTS_RENDERMODEL = BIT(11), // used for render models for collision detection
|
|
CONTENTS_TRIGGER = BIT(12), // used for triggers
|
|
CONTENTS_AAS_SOLID = BIT(13), // solid for AAS
|
|
CONTENTS_AAS_OBSTACLE = BIT(14), // used to compile an obstacle into AAS that can be enabled/disabled
|
|
CONTENTS_FLASHLIGHT_TRIGGER = BIT(15), // used for triggers that are activated by the flashlight
|
|
|
|
#ifdef QUAKE4
|
|
// RAVEN: additional Quake 4 content flags
|
|
CONTENTS_SIGHTCLIP = BIT(16), // blocks actor/camera sight
|
|
CONTENTS_LARGESHOTCLIP = BIT(17), // blocks large projectiles
|
|
CONTENTS_NOTACTICALFEATURES = BIT(18), // don't place tactical features here
|
|
CONTENTS_VEHICLECLIP = BIT(19), // solid to vehicles
|
|
|
|
// contents used by utils
|
|
CONTENTS_AREAPORTAL = BIT(20), // portal separating renderer areas
|
|
CONTENTS_NOCSG = BIT(21), // don't cut this brush with CSG operations in the editor
|
|
CONTENTS_FLYCLIP = BIT(22), // solid to flying/vehicle movement
|
|
CONTENTS_ITEMCLIP = BIT(23), // item collision
|
|
CONTENTS_PROJECTILECLIP = BIT(24), // projectile-only clip
|
|
#elif defined( PREY )
|
|
// HUMANHEAD CJR: Content flags. Note that for simplicity of merging, id's areaportal and nocsg flags were left as is
|
|
CONTENTS_FORCEFIELD = BIT(16), // forcefield matter, only passable in spirit mode
|
|
CONTENTS_SPIRITBRIDGE = BIT(17), // cjr - Collidable only by spiritwalking players
|
|
// END HUMANHEAD
|
|
|
|
// contents used by utils
|
|
CONTENTS_AREAPORTAL = BIT(18), // portal separating renderer areas
|
|
CONTENTS_NOCSG = BIT(19), // don't cut this brush with CSG operations in the editor
|
|
|
|
// HUMANHEAD CJR: Content flags. Note that for simplicity of merging, id's areaportal and nocsg flags were left as is
|
|
CONTENTS_BLOCK_RADIUSDAMAGE = BIT(20), // aob - used by objects like forcefields and chaff
|
|
CONTENTS_SHOOTABLE = BIT(21), // pdm - bullets collide with but not player or monsters
|
|
CONTENTS_DEATHVOLUME = BIT(22), // AOB: used by death zones so the player can do a simple contents check
|
|
CONTENTS_VEHICLECLIP = BIT(23), // PDM: used to clip off vehicle movement
|
|
CONTENTS_OWNER_TO_OWNER = BIT(24), // bjk: used to disable owner to owner rejection for collision
|
|
CONTENTS_GAME_PORTAL = BIT(25), // cjr: used for clipping against game portals (glow portals, etc)
|
|
CONTENTS_SHOOTABLEBYARROW = BIT(26), // pdm: solid to spirit arrows specifically as opposed to other projectiles
|
|
CONTENTS_HUNTERCLIP = BIT(27), // pdm: solid to hunters, but not hunters in vehicles
|
|
// HUMANHEAD END
|
|
#else
|
|
// contents used by utils
|
|
CONTENTS_AREAPORTAL = BIT(20), // portal separating renderer areas
|
|
CONTENTS_NOCSG = BIT(21), // don't cut this brush with CSG operations in the editor
|
|
#endif
|
|
CONTENTS_REMOVE_UTIL = ~(CONTENTS_AREAPORTAL | CONTENTS_NOCSG)
|
|
} contentsFlags_t;
|
|
|
|
// surface types
|
|
const int NUM_SURFACE_BITS = 4;
|
|
const int MAX_SURFACE_TYPES = 1 << NUM_SURFACE_BITS;
|
|
#ifdef PREY
|
|
typedef enum {
|
|
SURFTYPE_NONE, // default type
|
|
SURFTYPE_METAL,
|
|
SURFTYPE_STONE,
|
|
SURFTYPE_FLESH,
|
|
SURFTYPE_WOOD,
|
|
SURFTYPE_CARDBOARD,
|
|
SURFTYPE_LIQUID,
|
|
SURFTYPE_GLASS,
|
|
SURFTYPE_TILE,
|
|
SURFTYPE_WALLWALK,
|
|
SURFTYPE_ALTMETAL,
|
|
SURFTYPE_FORCEFIELD,
|
|
SURFTYPE_PIPE,
|
|
SURFTYPE_SPIRIT,
|
|
SURFTYPE_CHAFF,
|
|
NUM_SURFACE_TYPES
|
|
// NOTE: Bits all used, no more matter types
|
|
} surfTypes_t;
|
|
#else
|
|
typedef enum {
|
|
SURFTYPE_NONE, // default type
|
|
SURFTYPE_METAL,
|
|
SURFTYPE_STONE,
|
|
SURFTYPE_FLESH,
|
|
SURFTYPE_WOOD,
|
|
SURFTYPE_CARDBOARD,
|
|
SURFTYPE_LIQUID,
|
|
SURFTYPE_GLASS,
|
|
SURFTYPE_PLASTIC,
|
|
SURFTYPE_RICOCHET,
|
|
SURFTYPE_10,
|
|
SURFTYPE_11,
|
|
SURFTYPE_12,
|
|
SURFTYPE_13,
|
|
SURFTYPE_14,
|
|
SURFTYPE_15
|
|
} surfTypes_t;
|
|
#endif
|
|
|
|
// surface flags
|
|
typedef enum {
|
|
SURF_TYPE_BIT0 = BIT(0), // encodes the material type (metal, flesh, concrete, etc.)
|
|
SURF_TYPE_BIT1 = BIT(1), // "
|
|
SURF_TYPE_BIT2 = BIT(2), // "
|
|
SURF_TYPE_BIT3 = BIT(3), // "
|
|
SURF_TYPE_MASK = (1 << NUM_SURFACE_BITS) - 1,
|
|
|
|
SURF_NODAMAGE = BIT(4), // never give falling damage
|
|
SURF_SLICK = BIT(5), // effects game physics
|
|
SURF_COLLISION = BIT(6), // collision surface
|
|
SURF_LADDER = BIT(7), // player can climb up this surface
|
|
SURF_NOIMPACT = BIT(8), // don't make missile explosions
|
|
SURF_NOSTEPS = BIT(9), // no footstep sounds
|
|
SURF_DISCRETE = BIT(10), // not clipped or merged by utilities
|
|
SURF_NOFRAGMENT = BIT(11), // dmap won't cut surface at each bsp boundary
|
|
SURF_NULLNORMAL = BIT(12) // renderbump will draw this surface as 0x80 0x80 0x80, which
|
|
// won't collect light from any angle
|
|
#ifdef QUAKE4
|
|
, SURF_BOUNCE = BIT(13), // RAVEN: projectiles should bounce
|
|
SURF_NO_T_FIX = BIT(14) // RAVEN: skip T-junction fixing
|
|
#endif
|
|
} surfaceFlags_t;
|
|
|
|
#ifndef QUAKE4
|
|
#define CONTENTS_SLIME BIT(14) // used for slime
|
|
#define CONTENTS_FOG BIT(15) // used for fog
|
|
#define CONTENTS_LAVA BIT(16)
|
|
#endif
|
|
|
|
class idSoundEmitter;
|
|
|
|
class idMaterial : public idDecl {
|
|
#ifdef QUAKE4
|
|
friend class rvNewShaderStage;
|
|
friend class rvGLSLShaderStage;
|
|
#endif
|
|
public:
|
|
idMaterial();
|
|
virtual ~idMaterial();
|
|
|
|
virtual size_t Size(void) const;
|
|
virtual bool SetDefaultText(void);
|
|
virtual const char* DefaultDefinition(void) const;
|
|
virtual bool Parse(const char* text, const int textLength);
|
|
virtual void FreeData(void);
|
|
virtual void Print(void) const;
|
|
|
|
//BSM Nerve: Added for material editor
|
|
bool Save(const char* fileName = NULL);
|
|
|
|
bool CheckSurfaceParm(idToken* token);
|
|
|
|
// returns the internal image name for stage 0, which can be used
|
|
// for the renderer CaptureRenderToImage() call
|
|
// I'm not really sure why this needs to be virtual...
|
|
virtual const char* ImageName(void) const;
|
|
|
|
bool HasNeuralPOMData() const {
|
|
return neuralPOMHasData &&
|
|
neuralPOMWeightsBytes.Num() > 0 &&
|
|
neuralPOMLatentRGBA16FBytes.Num() > 0;
|
|
}
|
|
|
|
bool IsNeuralPOMUploadedToShim() const {
|
|
return neuralPOMUploadedToShim;
|
|
}
|
|
|
|
void SetNeuralPOMUploadedToShim(bool uploaded) const {
|
|
const_cast<idMaterial*>(this)->neuralPOMUploadedToShim = uploaded;
|
|
}
|
|
|
|
GLuint GetNeuralPOMGLHandle() const {
|
|
return neuralPOMGLHandle;
|
|
}
|
|
|
|
void SetNeuralPOMGLHandle(GLuint handle) const {
|
|
const_cast<idMaterial*>(this)->neuralPOMGLHandle = handle;
|
|
}
|
|
|
|
const idList<byte>& GetNeuralPOMWeightsBytes() const {
|
|
return neuralPOMWeightsBytes;
|
|
}
|
|
|
|
const idList<byte>& GetNeuralPOMLatentRGBA16FBytes() const {
|
|
return neuralPOMLatentRGBA16FBytes;
|
|
}
|
|
|
|
void ReloadImages(bool force) const;
|
|
|
|
// returns number of stages this material contains
|
|
const int GetNumStages(void) const { return numStages; }
|
|
|
|
// get a specific stage
|
|
const shaderStage_t* GetStage(const int index) const { assert(index >= 0 && index < numStages); return &stages[index]; }
|
|
|
|
// get the first bump map stage, or NULL if not present.
|
|
// used for bumpy-specular
|
|
const shaderStage_t* GetBumpStage(void) const;
|
|
|
|
#ifdef PREY
|
|
// HUMANHEAD tmj: returns how the subview should be rendered (mirror/portal/skybox)
|
|
subviewClass_t GetSubviewClass(void) const { return subviewClass; }
|
|
#endif
|
|
|
|
// returns true if the material will draw anything at all. Triggers, portals,
|
|
// etc, will not have anything to draw. A not drawn surface can still castShadow,
|
|
// which can be used to make a simplified shadow hull for a complex object set
|
|
// as noShadow
|
|
bool IsDrawn(void) const { return (numStages > 0 || entityGui != 0 || gui != NULL); }
|
|
|
|
// returns true if the material will draw any non light interaction stages
|
|
bool HasAmbient(void) const { return (numAmbientStages > 0); }
|
|
|
|
// returns true if material has a gui
|
|
bool HasGui(void) const { return (entityGui != 0 || gui != NULL); }
|
|
|
|
// returns true if the material will generate another view, either as
|
|
// a mirror or dynamic rendered image
|
|
bool HasSubview(void) const { return hasSubview; }
|
|
|
|
// returns true if the material will generate shadows, not making a
|
|
// distinction between global and no-self shadows
|
|
bool SurfaceCastsShadow(void) const { return TestMaterialFlag(MF_FORCESHADOWS) || !TestMaterialFlag(MF_NOSHADOWS); }
|
|
|
|
// returns true if the material will generate interactions with fog/blend lights
|
|
// All non-translucent surfaces receive fog unless they are explicitly noFog
|
|
bool ReceivesFog(void) const { return (IsDrawn() && !noFog && coverage != MC_TRANSLUCENT); }
|
|
// jmarshall
|
|
// Returns the diffuse/albedo image used by this material stage.
|
|
idImage* GetDiffuseImage(const float* regs) const;
|
|
|
|
// Returns the bump/normal map image used by this material stage.
|
|
idImage* GetBumpImage(void) const;
|
|
|
|
// Returns the specular map image used by this material stage.
|
|
idImage* GetSpecImage(void) const;
|
|
|
|
// Returns the glow/emissive map image used by this material stage.
|
|
idImage* GetGlowImage(const float* regs) const;
|
|
|
|
// Returns true if this material participates in dynamic lighting.
|
|
bool IsLitMaterial(void) const;
|
|
|
|
// Returns true if this material is rendered as a sky surface.
|
|
bool IsSky(void) const;
|
|
// jmarshall end
|
|
// returns true if the material will generate interactions with normal lights
|
|
// Many special effect surfaces don't have any bump/diffuse/specular
|
|
// stages, and don't interact with lights at all
|
|
bool ReceivesLighting(void) const { return numAmbientStages != numStages; }
|
|
|
|
// returns true if the material should generate interactions on sides facing away
|
|
// from light centers, as with noshadow and noselfshadow options
|
|
bool ReceivesLightingOnBackSides(void) const { return (materialFlags & (MF_NOSELFSHADOW | MF_NOSHADOWS)) != 0; }
|
|
|
|
// Standard two-sided triangle rendering won't work with bump map lighting, because
|
|
// the normal and tangent vectors won't be correct for the back sides. When two
|
|
// sided lighting is desired. typically for alpha tested surfaces, this is
|
|
// addressed by having CleanupModelSurfaces() create duplicates of all the triangles
|
|
// with apropriate order reversal.
|
|
bool ShouldCreateBackSides(void) const { return shouldCreateBackSides; }
|
|
|
|
// characters and models that are created by a complete renderbump can use a faster
|
|
// method of tangent and normal vector generation than surfaces which have a flat
|
|
// renderbump wrapped over them.
|
|
bool UseUnsmoothedTangents(void) const { return unsmoothedTangents; }
|
|
|
|
// by default, monsters can have blood overlays placed on them, but this can
|
|
// be overrided on a per-material basis with the "noOverlays" material command.
|
|
// This will always return false for translucent surfaces
|
|
bool AllowOverlays(void) const { return allowOverlays; }
|
|
|
|
// MC_OPAQUE, MC_PERFORATED, or MC_TRANSLUCENT, for interaction list linking and
|
|
// dmap flood filling
|
|
// The depth buffer will not be filled for MC_TRANSLUCENT surfaces
|
|
// FIXME: what do nodraw surfaces return?
|
|
materialCoverage_t Coverage(void) const { return coverage; }
|
|
|
|
// returns true if this material takes precedence over other in coplanar cases
|
|
bool HasHigherDmapPriority(const idMaterial& other) const {
|
|
return (IsDrawn() && !other.IsDrawn()) ||
|
|
(Coverage() < other.Coverage());
|
|
}
|
|
|
|
// returns a idUserInterface if it has a global gui, or NULL if no gui
|
|
idUserInterface* GlobalGui(void) const { return gui; }
|
|
|
|
// a discrete surface will never be merged with other surfaces by dmap, which is
|
|
// necessary to prevent mutliple gui surfaces, mirrors, autosprites, and some other
|
|
// special effects from being combined into a single surface
|
|
// guis, merging sprites or other effects, mirrors and remote views are always discrete
|
|
bool IsDiscrete(void) const {
|
|
return (entityGui || gui || deform != DFRM_NONE || sort == SS_SUBVIEW ||
|
|
(surfaceFlags & SURF_DISCRETE) != 0);
|
|
}
|
|
|
|
// Normally, dmap chops each surface by every BSP boundary, then reoptimizes.
|
|
// For gigantic polygons like sky boxes, this can cause a huge number of planar
|
|
// triangles that make the optimizer take forever to turn back into a single
|
|
// triangle. The "noFragment" option causes dmap to only break the polygons at
|
|
// area boundaries, instead of every BSP boundary. This has the negative effect
|
|
// of not automatically fixing up interpenetrations, so when this is used, you
|
|
// should manually make the edges of your sky box exactly meet, instead of poking
|
|
// into each other.
|
|
bool NoFragment(void) const { return (surfaceFlags & SURF_NOFRAGMENT) != 0; }
|
|
#ifdef QUAKE4
|
|
bool NoTFix(void) const { return (surfaceFlags & SURF_NO_T_FIX) != 0; }
|
|
|
|
const rvDeclMatType* GetMaterialType(void) const { return materialType; }
|
|
const rvDeclMatType* GetMaterialType(idVec2& tc) const;
|
|
byte* GetMaterialTypeArray(void) const { return materialTypeArray; }
|
|
const char* GetMaterialTypeArrayName(void) const { return materialTypeArrayName.c_str(); }
|
|
int GetTexelCount(void) const;
|
|
bool HasDefaultedImage(void) const;
|
|
idImage* GetDiffuseImage(void) const;
|
|
float GetPortalNear(void) const { return portalDistanceNear; }
|
|
float GetPortalFar(void) const { return portalDistanceFar; }
|
|
const idImage* GetPortalImage(void) const { return portalImage; }
|
|
virtual bool RebuildTextSource(void) { return false; }
|
|
virtual bool Validate(const char* psText, int iTextLength, idStr& strReportTo) const;
|
|
#endif
|
|
|
|
//------------------------------------------------------------------
|
|
// light shader specific functions, only called for light entities
|
|
|
|
// lightshader option to fill with fog from viewer instead of light from center
|
|
bool IsFogLight() const { return fogLight; }
|
|
|
|
// perform simple blending of the projection, instead of interacting with bumps and textures
|
|
bool IsBlendLight() const { return blendLight; }
|
|
|
|
// an ambient light has non-directional bump mapping and no specular
|
|
bool IsAmbientLight() const { return ambientLight; }
|
|
|
|
// implicitly no-shadows lights (ambients, fogs, etc) will never cast shadows
|
|
// but individual light entities can also override this value
|
|
bool LightCastsShadows() const {
|
|
return TestMaterialFlag(MF_FORCESHADOWS) ||
|
|
(!fogLight && !ambientLight && !blendLight && !TestMaterialFlag(MF_NOSHADOWS));
|
|
}
|
|
|
|
// fog lights, blend lights, ambient lights, etc will all have to have interaction
|
|
// triangles generated for sides facing away from the light as well as those
|
|
// facing towards the light. It is debatable if noshadow lights should effect back
|
|
// sides, making everything "noSelfShadow", but that would make noshadow lights
|
|
// potentially slower than normal lights, which detracts from their optimization
|
|
// ability, so they currently do not.
|
|
bool LightEffectsBackSides() const { return fogLight || ambientLight || blendLight; }
|
|
|
|
// NULL unless an image is explicitly specified in the shader with "lightFalloffShader <image>"
|
|
idImage* LightFalloffImage() const { return lightFalloffImage; }
|
|
idImage* LightIESImage() const { return lightIESImage; }
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
// returns the renderbump command line for this shader, or an empty string if not present
|
|
const char* GetRenderBump() const { return renderBump; };
|
|
|
|
// set specific material flag(s)
|
|
void SetMaterialFlag(const int flag) const { materialFlags |= flag; }
|
|
|
|
// clear specific material flag(s)
|
|
void ClearMaterialFlag(const int flag) const { materialFlags &= ~flag; }
|
|
|
|
// test for existance of specific material flag(s)
|
|
bool TestMaterialFlag(const int flag) const { return (materialFlags & flag) != 0; }
|
|
|
|
// get content flags
|
|
const int GetContentFlags(void) const { return contentFlags; }
|
|
|
|
// get surface flags
|
|
const int GetSurfaceFlags(void) const { return surfaceFlags; }
|
|
|
|
// gets name for surface type (stone, metal, flesh, etc.)
|
|
const surfTypes_t GetSurfaceType(void) const { return static_cast<surfTypes_t>(surfaceFlags & SURF_TYPE_MASK); }
|
|
|
|
// get material description
|
|
const char* GetDescription(void) const { return desc; }
|
|
|
|
// get sort order
|
|
const float GetSort(void) const { return sort; }
|
|
// this is only used by the gui system to force sorting order
|
|
// on images referenced from tga's instead of materials.
|
|
// this is done this way as there are 2000 tgas the guis use
|
|
void SetSort(float s) const { sort = s; };
|
|
|
|
// DFRM_NONE, DFRM_SPRITE, etc
|
|
deform_t Deform(void) const { return deform; }
|
|
|
|
// flare size, expansion size, etc
|
|
const int GetDeformRegister(int index) const { return deformRegisters[index]; }
|
|
|
|
// particle system to emit from surface and table for turbulent
|
|
const idDecl* GetDeformDecl(void) const { return deformDecl; }
|
|
|
|
// currently a surface can only have one unique texgen for all the stages
|
|
texgen_t Texgen() const;
|
|
|
|
// wobble sky parms
|
|
const int* GetTexGenRegisters(void) const { return texGenRegisters; }
|
|
|
|
// get cull type
|
|
const cullType_t GetCullType(void) const { return cullType; }
|
|
|
|
float GetEditorAlpha(void) const { return editorAlpha; }
|
|
|
|
int GetEntityGui(void) const { return entityGui; }
|
|
|
|
decalInfo_t GetDecalInfo(void) const { return decalInfo; }
|
|
|
|
// spectrums are used for "invisible writing" that can only be
|
|
// illuminated by a light of matching spectrum
|
|
int Spectrum(void) const { return spectrum; }
|
|
|
|
float GetPolygonOffset(void) const { return polygonOffset; }
|
|
|
|
float GetSurfaceArea(void) const { return surfaceArea; }
|
|
void AddToSurfaceArea(float area) { surfaceArea += area; }
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
// returns the length, in milliseconds, of the videoMap on this material,
|
|
// or zero if it doesn't have one
|
|
int CinematicLength(void) const;
|
|
|
|
void CloseCinematic(void) const;
|
|
|
|
void ResetCinematicTime(int time) const;
|
|
|
|
void UpdateCinematic(int time) const;
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
// gets an image for the editor to use
|
|
idImage* GetEditorImage(void) const;
|
|
int GetImageWidth(void) const;
|
|
int GetImageHeight(void) const;
|
|
|
|
void SetGui(const char* _gui) const;
|
|
|
|
// just for resource tracking
|
|
void SetImageClassifications(int tag) const;
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
// returns number of registers this material contains
|
|
const int GetNumRegisters() const { return numRegisters; }
|
|
|
|
// regs should point to a float array large enough to hold GetNumRegisters() floats
|
|
#ifdef QUAKE4
|
|
void EvaluateStageRegisters(int stageIndex, float* registers, const float shaderParms[MAX_ENTITY_SHADER_PARMS], float floatTime) const;
|
|
void ClearUseCount(void) { useCount = 0; }
|
|
void IncreaseUseCount(void) { useCount++; globalUseCount++; }
|
|
int GetUseCount(void) { return useCount; }
|
|
int GetGlobalUseCount(void) const { return globalUseCount; }
|
|
void ResolveUse(void);
|
|
#endif
|
|
void EvaluateRegisters(float* regs, const float entityParms[MAX_ENTITY_SHADER_PARMS],
|
|
const struct viewDef_s* view, idSoundEmitter* soundEmitter = NULL) const;
|
|
|
|
|
|
// if a material only uses constants (no entityParm or globalparm references), this
|
|
// will return a pointer to an internal table, and EvaluateRegisters will not need
|
|
// to be called. If NULL is returned, EvaluateRegisters must be used.
|
|
const float* ConstantRegisters() const;
|
|
|
|
bool SuppressInSubview() const { return suppressInSubview; };
|
|
bool IsPortalSky() const { return portalSky; };
|
|
void AddReference();
|
|
|
|
#ifdef PREY
|
|
int GetDirectPortalDistance() const { return directPortalDistance; } // HUMANHEAD CJR
|
|
#endif
|
|
|
|
private:
|
|
// parse the entire material
|
|
void CommonInit();
|
|
void ParseMaterial(idLexer& src);
|
|
bool MatchToken(idLexer& src, const char* match);
|
|
void ParseSort(idLexer& src);
|
|
void ParseBlend(idLexer& src, shaderStage_t* stage);
|
|
void ParseVertexParm(idLexer& src, newShaderStage_t* newStage);
|
|
#if defined( PREY ) || defined( QUAKE4 )
|
|
void ParseFragmentParm(idLexer& src, newShaderStage_t* newStage);
|
|
#endif
|
|
void ParseFragmentMap(idLexer& src, newShaderStage_t* newStage);
|
|
void ParseStage(idLexer& src, const textureRepeat_t trpDefault = TR_REPEAT);
|
|
void ParseDeform(idLexer& src);
|
|
void ParseDecalInfo(idLexer& src);
|
|
int GetExpressionConstant(float f);
|
|
int GetExpressionTemporary(void);
|
|
expOp_t* GetExpressionOp(void);
|
|
int EmitOp(int a, int b, expOpType_t opType);
|
|
int ParseEmitOp(idLexer& src, int a, expOpType_t opType, int priority);
|
|
int ParseTerm(idLexer& src);
|
|
int ParseExpressionPriority(idLexer& src, int priority);
|
|
int ParseExpression(idLexer& src);
|
|
void ClearStage(shaderStage_t* ss);
|
|
int NameToSrcBlendMode(const idStr& name);
|
|
int NameToDstBlendMode(const idStr& name);
|
|
void MultiplyTextureMatrix(textureStage_t* ts, int registers[2][3]); // FIXME: for some reason the const is bad for gcc and Mac
|
|
void SortInteractionStages();
|
|
void AddImplicitStages(const textureRepeat_t trpDefault = TR_REPEAT);
|
|
void CheckForConstantRegisters();
|
|
|
|
private:
|
|
void LoadNeuralBytesForMaterial(const char* path);
|
|
|
|
#ifdef PREY
|
|
subviewClass_t subviewClass; // HUMANHEAD tmj: Type of subview this surface points to
|
|
#endif
|
|
idStr desc; // description
|
|
idStr renderBump; // renderbump command options, without the "renderbump" at the start
|
|
|
|
idImage* lightFalloffImage;
|
|
idImage* lightIESImage;
|
|
|
|
int entityGui; // draw a gui with the idUserInterface from the renderEntity_t
|
|
// non zero will draw gui, gui2, or gui3 from renderEnitty_t
|
|
mutable idUserInterface* gui; // non-custom guis are shared by all users of a material
|
|
|
|
#ifdef QUAKE4
|
|
const rvDeclMatType* materialType;
|
|
byte* materialTypeArray; // material type indices generated from materialImage
|
|
idStr materialTypeArrayName;
|
|
int MTAWidth;
|
|
int MTAHeight;
|
|
int useCount;
|
|
int globalUseCount;
|
|
float portalDistanceNear;
|
|
float portalDistanceFar;
|
|
idImage* portalImage;
|
|
#endif
|
|
|
|
bool noFog; // surface does not create fog interactions
|
|
|
|
int spectrum; // for invisible writing, used for both lights and surfaces
|
|
|
|
#ifdef PREY
|
|
int directPortalDistance; // HUMANHEAD: Distance at which direct render portals are drawn
|
|
#endif
|
|
float polygonOffset;
|
|
|
|
int contentFlags; // content flags
|
|
int surfaceFlags; // surface flags
|
|
mutable int materialFlags; // material flags
|
|
|
|
decalInfo_t decalInfo;
|
|
|
|
|
|
mutable float sort; // lower numbered shaders draw before higher numbered
|
|
deform_t deform;
|
|
int deformRegisters[4]; // numeric parameter for deforms
|
|
const idDecl* deformDecl; // for surface emitted particle deforms and tables
|
|
|
|
int texGenRegisters[MAX_TEXGEN_REGISTERS]; // for wobbleSky
|
|
|
|
materialCoverage_t coverage;
|
|
cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED
|
|
bool shouldCreateBackSides;
|
|
|
|
bool fogLight;
|
|
bool blendLight;
|
|
bool ambientLight;
|
|
bool unsmoothedTangents;
|
|
bool hasSubview; // mirror, remote render, etc
|
|
bool allowOverlays;
|
|
|
|
int numOps;
|
|
expOp_t* ops; // evaluate to make expressionRegisters
|
|
|
|
int numRegisters; //
|
|
float* expressionRegisters;
|
|
|
|
float* constantRegisters; // NULL if ops ever reference globalParms or entityParms
|
|
|
|
int numStages;
|
|
int numAmbientStages;
|
|
|
|
shaderStage_t* stages;
|
|
|
|
struct mtrParsingData_s* pd; // only used during parsing
|
|
|
|
float surfaceArea; // only for listSurfaceAreas
|
|
|
|
// we defer loading of the editor image until it is asked for, so the game doesn't load up
|
|
// all the invisible and uncompressed images.
|
|
// If editorImage is NULL, it will atempt to load editorImageName, and set editorImage to that or defaultImage
|
|
idStr editorImageName;
|
|
mutable idImage* editorImage; // image used for non-shaded preview
|
|
float editorAlpha;
|
|
|
|
bool suppressInSubview;
|
|
bool portalSky;
|
|
int refCount;
|
|
|
|
bool neuralPOMBytesLoaded;
|
|
bool neuralPOMHasData;
|
|
bool neuralPOMUploadedToShim;
|
|
GLuint neuralPOMGLHandle;
|
|
|
|
idList<byte> neuralPOMWeightsBytes;
|
|
idList<byte> neuralPOMLatentRGBA16FBytes;
|
|
};
|
|
|
|
typedef idList<const idMaterial*> idMatList;
|
|
|
|
#ifdef QUAKE4
|
|
// RAVEN: material editor bridge used by Radiant/editor code.
|
|
class rvMaterialEdit {
|
|
public:
|
|
virtual ~rvMaterialEdit() {}
|
|
virtual void SetGui(idMaterial* edit, const char* name) = 0;
|
|
virtual int GetImageWidth(const idMaterial* edit) const = 0;
|
|
virtual int GetImageHeight(const idMaterial* edit) const = 0;
|
|
};
|
|
|
|
extern rvMaterialEdit* materialEdit;
|
|
#endif
|
|
|
|
#endif /* !__MATERIAL_H__ */
|