Merge remote-tracking branch 'origin/next' into remove-glide-2

This commit is contained in:
James R 2020-07-12 16:05:15 -07:00
commit b9a24001d8
49 changed files with 740 additions and 1261 deletions

View file

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
# DO NOT CHANGE THIS SRB2 STRING! Some variable names depend on this string. # DO NOT CHANGE THIS SRB2 STRING! Some variable names depend on this string.
# Version change is fine. # Version change is fine.
project(SRB2 project(SRB2
VERSION 2.2.4 VERSION 2.2.6
LANGUAGES C) LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

View file

@ -1,4 +1,4 @@
version: 2.2.4.{branch}-{build} version: 2.2.6.{branch}-{build}
os: MinGW os: MinGW
environment: environment:
@ -110,8 +110,8 @@ after_build:
- set BUILDSARCHIVE=%REPO%-%CONFIGURATION%.7z - set BUILDSARCHIVE=%REPO%-%CONFIGURATION%.7z
- cmd: 7z a %BUILD_ARCHIVE% %BUILD_PATH% -xr!.gitignore - cmd: 7z a %BUILD_ARCHIVE% %BUILD_PATH% -xr!.gitignore
- appveyor PushArtifact %BUILD_ARCHIVE% - appveyor PushArtifact %BUILD_ARCHIVE%
- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE% #- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE%
- appveyor PushArtifact %BUILDSARCHIVE% #- appveyor PushArtifact %BUILDSARCHIVE%
############################## ##############################
# DEPLOYER SCRIPT # DEPLOYER SCRIPT
############################## ##############################

View file

@ -429,7 +429,6 @@ if(${SRB2_CONFIG_HWRENDER})
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md3load.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md3load.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_model.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_model.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_trick.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/u_list.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/u_list.c
) )

View file

@ -224,7 +224,7 @@ ifdef NOHW
else else
OPTS+=-DHWRENDER OPTS+=-DHWRENDER
OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \ OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \
$(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o $(OBJDIR)/hw_trick.o \ $(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o \
$(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o $(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o
endif endif

View file

@ -1,3 +1,4 @@
# vim: ft=make
# #
# Makefile.cfg for SRB2 # Makefile.cfg for SRB2
# #
@ -7,6 +8,66 @@
# and other things # and other things
# #
# See the following variable don't start with 'GCC'. This is
# to avoid a false positive with the version detection...
SUPPORTED_GCC_VERSIONS:=\
91\
81 82 83\
71 72\
61 62 63 64\
51 52 53 54\
40 41 42 43 44 45 46 47 48 49
LATEST_GCC_VERSION=9.1
# gcc or g++
ifdef PREFIX
CC=$(PREFIX)-gcc
CXX=$(PREFIX)-g++
OBJCOPY=$(PREFIX)-objcopy
OBJDUMP=$(PREFIX)-objdump
STRIP=$(PREFIX)-strip
WINDRES=$(PREFIX)-windres
else
OBJCOPY=objcopy
OBJDUMP=objdump
STRIP=strip
WINDRES=windres
endif
# because Apple screws with us on this
# need to get bintools from homebrew
ifdef MACOSX
CC=clang
CXX=clang
OBJCOPY=gobjcopy
OBJDUMP=gobjdump
endif
# Automatically set version flag, but not if one was manually set
ifeq (,$(filter GCC%,$(.VARIABLES)))
ifneq (,$(findstring GCC,$(shell $(CC) --version))) # if it's GCC
version:=$(shell $(CC) -dumpversion)
# Turn version into words of major, minor
v:=$(subst ., ,$(version))
# concat. major minor
v:=$(word 1,$(v))$(word 2,$(v))
# If this version is not in the list, default to the latest supported
ifeq (,$(filter $(v),$(SUPPORTED_GCC_VERSIONS)))
$(info\
Your compiler version, GCC $(version), is not supported by the Makefile.\
The Makefile will assume GCC $(LATEST_GCC_VERSION).)
GCC$(subst .,,$(LATEST_GCC_VERSION))=1
else
$(info Detected GCC $(version) (GCC$(v)))
GCC$(v)=1
endif
endif
endif
ifdef GCC91 ifdef GCC91
GCC83=1 GCC83=1
endif endif
@ -358,30 +419,6 @@ ifdef ARCHNAME
BIN:=$(BIN)/$(ARCHNAME) BIN:=$(BIN)/$(ARCHNAME)
endif endif
# gcc or g++
ifdef PREFIX
CC=$(PREFIX)-gcc
CXX=$(PREFIX)-g++
OBJCOPY=$(PREFIX)-objcopy
OBJDUMP=$(PREFIX)-objdump
STRIP=$(PREFIX)-strip
WINDRES=$(PREFIX)-windres
else
OBJCOPY=objcopy
OBJDUMP=objdump
STRIP=strip
WINDRES=windres
endif
# because Apple screws with us on this
# need to get bintools from homebrew
ifdef MACOSX
CC=clang
CXX=clang
OBJCOPY=gobjcopy
OBJDUMP=gobjdump
endif
OBJDUMP_OPTS?=--wide --source --line-numbers OBJDUMP_OPTS?=--wide --source --line-numbers
LD=$(CC) LD=$(CC)

View file

@ -150,15 +150,15 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr)
#undef DEALIGNED #undef DEALIGNED
#define WRITESTRINGN(p,s,n) { size_t tmp_i = 0; for (; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); if (tmp_i < n) WRITECHAR(p, '\0');} #define WRITESTRINGN(p,s,n) do { size_t tmp_i = 0; for (; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); if (tmp_i < n) WRITECHAR(p, '\0');} while (0)
#define WRITESTRING(p,s) { size_t tmp_i = 0; for (; s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); WRITECHAR(p, '\0');} #define WRITESTRING(p,s) do { size_t tmp_i = 0; for (; s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); WRITECHAR(p, '\0');} while (0)
#define WRITEMEM(p,s,n) { memcpy(p, s, n); p += n; } #define WRITEMEM(p,s,n) do { memcpy(p, s, n); p += n; } while (0)
#define SKIPSTRING(p) while (READCHAR(p) != '\0') #define SKIPSTRING(p) while (READCHAR(p) != '\0')
#define READSTRINGN(p,s,n) { size_t tmp_i = 0; for (; tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';} #define READSTRINGN(p,s,n) ({ size_t tmp_i = 0; for (; tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';})
#define READSTRING(p,s) { size_t tmp_i = 0; for (; (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';} #define READSTRING(p,s) ({ size_t tmp_i = 0; for (; (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';})
#define READMEM(p,s,n) { memcpy(s, p, n); p += n; } #define READMEM(p,s,n) ({ memcpy(s, p, n); p += n; })
#if 0 // old names #if 0 // old names
#define WRITEBYTE(p,b) WRITEUINT8(p,b) #define WRITEBYTE(p,b) WRITEUINT8(p,b)

View file

@ -56,7 +56,13 @@ static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr);
static boolean CV_Command(void); static boolean CV_Command(void);
consvar_t *CV_FindVar(const char *name); consvar_t *CV_FindVar(const char *name);
static const char *CV_StringValue(const char *var_name); static const char *CV_StringValue(const char *var_name);
static consvar_t *consvar_vars; // list of registered console variables static consvar_t *consvar_vars; // list of registered console variables
static UINT16 consvar_number_of_netids = 0;
#ifdef OLD22DEMOCOMPAT
static old_demo_var_t *consvar_old_demo_vars;
#endif
static char com_token[1024]; static char com_token[1024];
static char *COM_Parse(char *data); static char *COM_Parse(char *data);
@ -1121,14 +1127,16 @@ consvar_t *CV_FindVar(const char *name)
return NULL; return NULL;
} }
/** Builds a unique Net Variable identifier number, which is used #ifdef OLD22DEMOCOMPAT
* in network packets instead of the full name. /** Builds a unique Net Variable identifier number, which was used
* in network packets and demos instead of the full name.
*
* This function only still exists to keep compatibility with old demos.
* *
* \param s Name of the variable. * \param s Name of the variable.
* \return A new unique identifier. * \return A new unique identifier.
* \sa CV_FindNetVar
*/ */
static inline UINT16 CV_ComputeNetid(const char *s) static inline UINT16 CV_ComputeOldDemoID(const char *s)
{ {
UINT16 ret = 0, i = 0; UINT16 ret = 0, i = 0;
static UINT16 premiers[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53}; static UINT16 premiers[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
@ -1142,16 +1150,47 @@ static inline UINT16 CV_ComputeNetid(const char *s)
return ret; return ret;
} }
/** Finds a net variable based on its old style hash. If a hash collides, a
* warning is printed and this function returns NULL.
*
* \param chk The variable's old style hash.
* \return A pointer to the variable itself if found, or NULL.
*/
static old_demo_var_t *CV_FindOldDemoVar(UINT16 chk)
{
old_demo_var_t *demovar;
for (demovar = consvar_old_demo_vars; demovar; demovar = demovar->next)
{
if (demovar->checksum == chk)
{
if (demovar->collides)
{
CONS_Alert(CONS_WARNING,
"Old demo netvar id %hu is a collision\n", chk);
return NULL;
}
return demovar;
}
}
return NULL;
}
#endif/*OLD22DEMOCOMPAT*/
/** Finds a net variable based on its identifier number. /** Finds a net variable based on its identifier number.
* *
* \param netid The variable's identifier number. * \param netid The variable's identifier number.
* \return A pointer to the variable itself if found, or NULL. * \return A pointer to the variable itself if found, or NULL.
* \sa CV_ComputeNetid
*/ */
static consvar_t *CV_FindNetVar(UINT16 netid) static consvar_t *CV_FindNetVar(UINT16 netid)
{ {
consvar_t *cvar; consvar_t *cvar;
if (netid >= consvar_number_of_netids)
return NULL;
for (cvar = consvar_vars; cvar; cvar = cvar->next) for (cvar = consvar_vars; cvar; cvar = cvar->next)
if (cvar->netid == netid) if (cvar->netid == netid)
return cvar; return cvar;
@ -1161,6 +1200,32 @@ static consvar_t *CV_FindNetVar(UINT16 netid)
static void Setvalue(consvar_t *var, const char *valstr, boolean stealth); static void Setvalue(consvar_t *var, const char *valstr, boolean stealth);
#ifdef OLD22DEMOCOMPAT
/* Sets up a netvar for compatibility with old demos. */
static void CV_RegisterOldDemoVar(consvar_t *variable)
{
old_demo_var_t *demovar;
UINT16 old_demo_id;
old_demo_id = CV_ComputeOldDemoID(variable->name);
demovar = CV_FindOldDemoVar(old_demo_id);
if (demovar)
demovar->collides = true;
else
{
demovar = ZZ_Calloc(sizeof *demovar);
demovar->checksum = old_demo_id;
demovar->cvar = variable;
demovar->next = consvar_old_demo_vars;
consvar_old_demo_vars = demovar;
}
}
#endif
/** Registers a variable for later use from the console. /** Registers a variable for later use from the console.
* *
* \param variable The variable to register. * \param variable The variable to register.
@ -1184,11 +1249,15 @@ void CV_RegisterVar(consvar_t *variable)
// check net variables // check net variables
if (variable->flags & CV_NETVAR) if (variable->flags & CV_NETVAR)
{ {
const consvar_t *netvar; variable->netid = consvar_number_of_netids++;
variable->netid = CV_ComputeNetid(variable->name);
netvar = CV_FindNetVar(variable->netid); /* in case of overflow... */
if (netvar) if (variable->netid > consvar_number_of_netids)
I_Error("Variables %s and %s have same netid\n", variable->name, netvar->name); I_Error("Way too many netvars");
#ifdef OLD22DEMOCOMPAT
CV_RegisterOldDemoVar(variable);
#endif
} }
// link the variable in // link the variable in
@ -1448,12 +1517,100 @@ badinput:
static boolean serverloading = false; static boolean serverloading = false;
static consvar_t *
ReadNetVar (UINT8 **p, char **return_value, boolean *return_stealth)
{
UINT16 netid;
char *val;
boolean stealth;
consvar_t *cvar;
netid = READUINT16 (*p);
val = (char *)*p;
SKIPSTRING (*p);
stealth = READUINT8 (*p);
cvar = CV_FindNetVar(netid);
if (cvar)
{
(*return_value) = val;
(*return_stealth) = stealth;
DEBFILE(va("Netvar received: %s [netid=%d] value %s\n", cvar->name, netid, val));
}
else
CONS_Alert(CONS_WARNING, "Netvar not found with netid %hu\n", netid);
return cvar;
}
#ifdef OLD22DEMOCOMPAT
static consvar_t *
ReadOldDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
{
UINT16 id;
char *val;
boolean stealth;
old_demo_var_t *demovar;
id = READUINT16 (*p);
val = (char *)*p;
SKIPSTRING (*p);
stealth = READUINT8 (*p);
demovar = CV_FindOldDemoVar(id);
if (demovar)
{
(*return_value) = val;
(*return_stealth) = stealth;
return demovar->cvar;
}
else
{
CONS_Alert(CONS_WARNING, "Netvar not found with old demo id %hu\n", id);
return NULL;
}
}
#endif/*OLD22DEMOCOMPAT*/
static consvar_t *
ReadDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
{
char *name;
char *val;
boolean stealth;
consvar_t *cvar;
name = (char *)*p;
SKIPSTRING (*p);
val = (char *)*p;
SKIPSTRING (*p);
stealth = READUINT8 (*p);
cvar = CV_FindVar(name);
if (cvar)
{
(*return_value) = val;
(*return_stealth) = stealth;
}
else
CONS_Alert(CONS_WARNING, "Netvar not found with name %s\n", name);
return cvar;
}
static void Got_NetVar(UINT8 **p, INT32 playernum) static void Got_NetVar(UINT8 **p, INT32 playernum)
{ {
consvar_t *cvar; consvar_t *cvar;
UINT16 netid;
char *svalue; char *svalue;
UINT8 stealth = false; boolean stealth;
if (playernum != serverplayer && !IsPlayerAdmin(playernum) && !serverloading) if (playernum != serverplayer && !IsPlayerAdmin(playernum) && !serverloading)
{ {
@ -1463,23 +1620,14 @@ static void Got_NetVar(UINT8 **p, INT32 playernum)
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return; return;
} }
netid = READUINT16(*p);
cvar = CV_FindNetVar(netid);
svalue = (char *)*p;
SKIPSTRING(*p);
stealth = READUINT8(*p);
if (!cvar) cvar = ReadNetVar(p, &svalue, &stealth);
{
CONS_Alert(CONS_WARNING, "Netvar not found with netid %hu\n", netid);
return;
}
DEBFILE(va("Netvar received: %s [netid=%d] value %s\n", cvar->name, netid, svalue));
Setvalue(cvar, svalue, stealth); if (cvar)
Setvalue(cvar, svalue, stealth);
} }
void CV_SaveNetVars(UINT8 **p) void CV_SaveVars(UINT8 **p, boolean in_demo)
{ {
consvar_t *cvar; consvar_t *cvar;
UINT8 *count_p = *p; UINT8 *count_p = *p;
@ -1491,7 +1639,10 @@ void CV_SaveNetVars(UINT8 **p)
for (cvar = consvar_vars; cvar; cvar = cvar->next) for (cvar = consvar_vars; cvar; cvar = cvar->next)
if ((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) if ((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar))
{ {
WRITEUINT16(*p, cvar->netid); if (in_demo)
WRITESTRING(*p, cvar->name);
else
WRITEUINT16(*p, cvar->netid);
WRITESTRING(*p, cvar->string); WRITESTRING(*p, cvar->string);
WRITEUINT8(*p, false); WRITEUINT8(*p, false);
++count; ++count;
@ -1499,11 +1650,15 @@ void CV_SaveNetVars(UINT8 **p)
WRITEUINT16(count_p, count); WRITEUINT16(count_p, count);
} }
void CV_LoadNetVars(UINT8 **p) static void CV_LoadVars(UINT8 **p,
consvar_t *(*got)(UINT8 **p, char **ret_value, boolean *ret_stealth))
{ {
consvar_t *cvar; consvar_t *cvar;
UINT16 count; UINT16 count;
char *val;
boolean stealth;
// prevent "invalid command received" // prevent "invalid command received"
serverloading = true; serverloading = true;
@ -1513,11 +1668,33 @@ void CV_LoadNetVars(UINT8 **p)
count = READUINT16(*p); count = READUINT16(*p);
while (count--) while (count--)
Got_NetVar(p, 0); {
cvar = (*got)(p, &val, &stealth);
if (cvar)
Setvalue(cvar, val, stealth);
}
serverloading = false; serverloading = false;
} }
void CV_LoadNetVars(UINT8 **p)
{
CV_LoadVars(p, ReadNetVar);
}
#ifdef OLD22DEMOCOMPAT
void CV_LoadOldDemoVars(UINT8 **p)
{
CV_LoadVars(p, ReadOldDemoVar);
}
#endif
void CV_LoadDemoVars(UINT8 **p)
{
CV_LoadVars(p, ReadDemoVar);
}
static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth); static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth);
void CV_ResetCheatNetVars(void) void CV_ResetCheatNetVars(void)
@ -1574,7 +1751,7 @@ static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth)
// send the value of the variable // send the value of the variable
UINT8 buf[128]; UINT8 buf[128];
UINT8 *p = buf; UINT8 *p = buf;
if (!(server || (IsPlayerAdmin(consoleplayer)))) if (!(server || (addedtogame && IsPlayerAdmin(consoleplayer))))
{ {
CONS_Printf(M_GetText("Only the server or admin can change: %s %s\n"), var->name, var->string); CONS_Printf(M_GetText("Only the server or admin can change: %s %s\n"), var->name, var->string);
return; return;

View file

@ -144,6 +144,19 @@ typedef struct consvar_s //NULL, NULL, 0, NULL, NULL |, 0, NULL, NULL, 0, 0, NUL
struct consvar_s *next; struct consvar_s *next;
} consvar_t; } consvar_t;
#ifdef OLD22DEMOCOMPAT
typedef struct old_demo_var old_demo_var_t;
struct old_demo_var
{
UINT16 checksum;
boolean collides;/* this var is a collision of multiple hashes */
consvar_t *cvar;
old_demo_var_t *next;
};
#endif/*OLD22DEMOCOMPAT*/
extern CV_PossibleValue_t CV_OnOff[]; extern CV_PossibleValue_t CV_OnOff[];
extern CV_PossibleValue_t CV_YesNo[]; extern CV_PossibleValue_t CV_YesNo[];
extern CV_PossibleValue_t CV_Unsigned[]; extern CV_PossibleValue_t CV_Unsigned[];
@ -184,9 +197,18 @@ void CV_AddValue(consvar_t *var, INT32 increment);
void CV_SaveVariables(FILE *f); void CV_SaveVariables(FILE *f);
// load/save gamesate (load and save option and for network join in game) // load/save gamesate (load and save option and for network join in game)
void CV_SaveNetVars(UINT8 **p); void CV_SaveVars(UINT8 **p, boolean in_demo);
#define CV_SaveNetVars(p) CV_SaveVars(p, false)
void CV_LoadNetVars(UINT8 **p); void CV_LoadNetVars(UINT8 **p);
#define CV_SaveDemoVars(p) CV_SaveVars(p, true)
void CV_LoadDemoVars(UINT8 **p);
#ifdef OLD22DEMOCOMPAT
void CV_LoadOldDemoVars(UINT8 **p);
#endif
// reset cheat netvars after cheats is deactivated // reset cheat netvars after cheats is deactivated
void CV_ResetCheatNetVars(void); void CV_ResetCheatNetVars(void);

View file

@ -30,12 +30,14 @@
* Last updated 2020 / 02 / 22 - v2.2.2 - patch.pk3 * Last updated 2020 / 02 / 22 - v2.2.2 - patch.pk3
* Last updated 2020 / 05 / 10 - v2.2.3 - player.dta & patch.pk3 * Last updated 2020 / 05 / 10 - v2.2.3 - player.dta & patch.pk3
* Last updated 2020 / 05 / 11 - v2.2.4 - patch.pk3 * Last updated 2020 / 05 / 11 - v2.2.4 - patch.pk3
* Last updated 2020 / 07 / 07 - v2.2.5 - player.dta & patch.pk3
* Last updated 2020 / 07 / 10 - v2.2.6 - player.dta & patch.pk3
*/ */
#define ASSET_HASH_SRB2_PK3 "0277c9416756627004e83cbb5b2e3e28" #define ASSET_HASH_SRB2_PK3 "0277c9416756627004e83cbb5b2e3e28"
#define ASSET_HASH_ZONES_PK3 "f7e88afb6af7996a834c7d663144bead" #define ASSET_HASH_ZONES_PK3 "f7e88afb6af7996a834c7d663144bead"
#define ASSET_HASH_PLAYER_DTA "8a4507ddf9bc0682c09174400f26ad65" #define ASSET_HASH_PLAYER_DTA "49dad7b24634c89728cc3e0b689e12bb"
#ifdef USE_PATCH_DTA #ifdef USE_PATCH_DTA
#define ASSET_HASH_PATCH_PK3 "bbbf6af3b20349612ee06e0b55979a76" #define ASSET_HASH_PATCH_PK3 "ecf00060f03c76b3e49c6ae3925b627f"
#endif #endif
#endif #endif

View file

@ -5159,7 +5159,7 @@ static void SV_SendTics(void)
{ {
// assert supposedtics[n]>=nettics[n] // assert supposedtics[n]>=nettics[n]
realfirsttic = supposedtics[n]; realfirsttic = supposedtics[n];
lasttictosend = min(maketic, realfirsttic + CLIENTBACKUPTICS); lasttictosend = min(maketic, nettics[n] + CLIENTBACKUPTICS);
if (realfirsttic >= lasttictosend) if (realfirsttic >= lasttictosend)
{ {
@ -5496,7 +5496,7 @@ void NetUpdate(void)
// update node latency values so we can take an average later. // update node latency values so we can take an average later.
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && playernode[i] != UINT8_MAX) if (playeringame[i] && playernode[i] != UINT8_MAX)
realpingtable[i] += GetLag(playernode[i]) * (1000.00f / TICRATE); realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i]));
pingmeasurecount++; pingmeasurecount++;
} }

View file

@ -3475,7 +3475,7 @@ static void Command_Version_f(void)
#ifdef DEVELOP #ifdef DEVELOP
CONS_Printf("Sonic Robo Blast 2 %s-%s (%s %s) ", compbranch, comprevision, compdate, comptime); CONS_Printf("Sonic Robo Blast 2 %s-%s (%s %s) ", compbranch, comprevision, compdate, comptime);
#else #else
CONS_Printf("Sonic Robo Blast 2 %s (%s %s %s) ", VERSIONSTRING, compdate, comptime, comprevision); CONS_Printf("Sonic Robo Blast 2 %s (%s %s %s %s) ", VERSIONSTRING, compdate, comptime, comprevision, compbranch);
#endif #endif
// Base library // Base library

View file

@ -3082,6 +3082,7 @@ static actionpointer_t actionpointers[] =
{{A_NapalmScatter}, "A_NAPALMSCATTER"}, {{A_NapalmScatter}, "A_NAPALMSCATTER"},
{{A_SpawnFreshCopy}, "A_SPAWNFRESHCOPY"}, {{A_SpawnFreshCopy}, "A_SPAWNFRESHCOPY"},
{{A_FlickySpawn}, "A_FLICKYSPAWN"}, {{A_FlickySpawn}, "A_FLICKYSPAWN"},
{{A_FlickyCenter}, "A_FLICKYCENTER"},
{{A_FlickyAim}, "A_FLICKYAIM"}, {{A_FlickyAim}, "A_FLICKYAIM"},
{{A_FlickyFly}, "A_FLICKYFLY"}, {{A_FlickyFly}, "A_FLICKYFLY"},
{{A_FlickySoar}, "A_FLICKYSOAR"}, {{A_FlickySoar}, "A_FLICKYSOAR"},

View file

@ -143,9 +143,9 @@ extern char logfilename[1024];
// we use comprevision and compbranch instead. // we use comprevision and compbranch instead.
#else #else
#define VERSION 202 // Game version #define VERSION 202 // Game version
#define SUBVERSION 4 // more precise version number #define SUBVERSION 6 // more precise version number
#define VERSIONSTRING "v2.2.4" #define VERSIONSTRING "v2.2.6"
#define VERSIONSTRINGW L"v2.2.4" #define VERSIONSTRINGW L"v2.2.6"
// Hey! If you change this, add 1 to the MODVERSION below! // Hey! If you change this, add 1 to the MODVERSION below!
// Otherwise we can't force updates! // Otherwise we can't force updates!
#endif #endif
@ -204,7 +204,7 @@ extern char logfilename[1024];
// Will always resemble the versionstring, 205 = 2.0.5, 210 = 2.1, etc. // Will always resemble the versionstring, 205 = 2.0.5, 210 = 2.1, etc.
#define CODEBASE 220 #define CODEBASE 220
// The Modification ID; must be obtained from Rob ( https://mb.srb2.org/private.php?do=newpm&u=546 ). // The Modification ID; must be obtained from a Master Server Admin ( https://mb.srb2.org/showgroups.php ).
// DO NOT try to set this otherwise, or your modification will be unplayable through the Master Server. // DO NOT try to set this otherwise, or your modification will be unplayable through the Master Server.
// "18" is the default mod ID for version 2.2 // "18" is the default mod ID for version 2.2
#define MODID 18 #define MODID 18
@ -213,7 +213,7 @@ extern char logfilename[1024];
// it's only for detection of the version the player is using so the MS can alert them of an update. // it's only for detection of the version the player is using so the MS can alert them of an update.
// Only set it higher, not lower, obviously. // Only set it higher, not lower, obviously.
// Note that we use this to help keep internal testing in check; this is why v2.2.0 is not version "1". // Note that we use this to help keep internal testing in check; this is why v2.2.0 is not version "1".
#define MODVERSION 44 #define MODVERSION 47
// To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically. // To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically.
// Increment MINOREXECVERSION whenever a config change is needed that does not correspond // Increment MINOREXECVERSION whenever a config change is needed that does not correspond
@ -657,4 +657,7 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// Render flats on walls /// Render flats on walls
#define WALLFLATS #define WALLFLATS
/// Maintain compatibility with older 2.2 demos
#define OLD22DEMOCOMPAT
#endif // __DOOMDEF__ #endif // __DOOMDEF__

View file

@ -1674,6 +1674,18 @@ void F_GameEvaluationDrawer(void)
V_DrawString(8, 96, V_YELLOWMAP, "Modified games\ncan't unlock\nextras!"); V_DrawString(8, 96, V_YELLOWMAP, "Modified games\ncan't unlock\nextras!");
} }
#endif #endif
if (marathonmode)
{
const char *rtatext, *cuttext;
rtatext = (marathonmode & MA_INGAME) ? "In-game timer" : "RTA timer";
cuttext = (marathonmode & MA_NOCUTSCENES) ? "" : " w/ cutscenes";
if (botskin)
endingtext = va("%s & %s, %s%s", skins[players[consoleplayer].skin].realname, skins[botskin-1].realname, rtatext, cuttext);
else
endingtext = va("%s, %s%s", skins[players[consoleplayer].skin].realname, rtatext, cuttext);
V_DrawCenteredString(BASEVIDWIDTH/2, 182, V_SNAPTOBOTTOM|(ultimatemode ? V_REDMAP : V_YELLOWMAP), endingtext);
}
} }
void F_GameEvaluationTicker(void) void F_GameEvaluationTicker(void)

View file

@ -1525,7 +1525,7 @@ void G_BeginRecording(void)
} }
// Save netvar data // Save netvar data
CV_SaveNetVars(&demo_p); CV_SaveDemoVars(&demo_p);
memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldcmd,0,sizeof(oldcmd));
memset(&oldghost,0,sizeof(oldghost)); memset(&oldghost,0,sizeof(oldghost));
@ -1756,6 +1756,9 @@ void G_DoPlayDemo(char *defdemoname)
UINT32 randseed, followitem; UINT32 randseed, followitem;
fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight; fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight;
char msg[1024]; char msg[1024];
#ifdef OLD22DEMOCOMPAT
boolean use_old_demo_vars = false;
#endif
skin[16] = '\0'; skin[16] = '\0';
color[MAXCOLORNAME] = '\0'; color[MAXCOLORNAME] = '\0';
@ -1818,10 +1821,13 @@ void G_DoPlayDemo(char *defdemoname)
case DEMOVERSION: // latest always supported case DEMOVERSION: // latest always supported
cnamelen = MAXCOLORNAME; cnamelen = MAXCOLORNAME;
break; break;
#ifdef OLD22DEMOCOMPAT
// all that changed between then and now was longer color name // all that changed between then and now was longer color name
case 0x000c: case 0x000c:
cnamelen = 16; cnamelen = 16;
use_old_demo_vars = true;
break; break;
#endif
// too old, cannot support. // too old, cannot support.
default: default:
snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname); snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname);
@ -1923,7 +1929,13 @@ void G_DoPlayDemo(char *defdemoname)
} }
// net var data // net var data
CV_LoadNetVars(&demo_p); #ifdef OLD22DEMOCOMPAT
if (use_old_demo_vars)
CV_LoadOldDemoVars(&demo_p);
else
#else
CV_LoadDemoVars(&demo_p);
#endif
// Sigh ... it's an empty demo. // Sigh ... it's an empty demo.
if (*demo_p == DEMOMARKER) if (*demo_p == DEMOMARKER)

View file

@ -3729,6 +3729,32 @@ static boolean CanSaveLevel(INT32 mapnum)
return (mapheaderinfo[mapnum-1] && (mapheaderinfo[mapnum-1]->levelflags & LF_SAVEGAME)); return (mapheaderinfo[mapnum-1] && (mapheaderinfo[mapnum-1]->levelflags & LF_SAVEGAME));
} }
static void G_HandleSaveLevel(void)
{
// do this before running the intermission or custom cutscene, mostly for the sake of marathon mode but it also massively reduces redundant file save events in f_finale.c
if (nextmap >= 1100-1)
{
if (!gamecomplete)
gamecomplete = 2; // special temporary mode to prevent using SP level select in pause menu until the intermission is over without restricting it in every intermission
if (cursaveslot > 0)
{
if (marathonmode)
{
// don't keep a backup around when the run is done!
if (FIL_FileExists(liveeventbackup))
remove(liveeventbackup);
cursaveslot = 0;
}
else if ((!modifiedgame || savemoddata) && !(netgame || multiplayer || ultimatemode || demorecording || metalrecording || modeattacking))
G_SaveGame((UINT32)cursaveslot, spstage_start);
}
}
// and doing THIS here means you don't lose your progress if you close the game mid-intermission
else if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking)
&& (!modifiedgame || savemoddata) && cursaveslot > 0 && CanSaveLevel(lastmap+1))
G_SaveGame((UINT32)cursaveslot, lastmap+1); // not nextmap+1 to route around special stages
}
// //
// G_DoCompleted // G_DoCompleted
// //
@ -3875,6 +3901,7 @@ static void G_DoCompleted(void)
if ((skipstats && !modeattacking) || (spec && modeattacking && stagefailed) || (intertype == int_none)) if ((skipstats && !modeattacking) || (spec && modeattacking && stagefailed) || (intertype == int_none))
{ {
G_UpdateVisited(); G_UpdateVisited();
G_HandleSaveLevel();
G_AfterIntermission(); G_AfterIntermission();
} }
else else
@ -3882,30 +3909,8 @@ static void G_DoCompleted(void)
G_SetGamestate(GS_INTERMISSION); G_SetGamestate(GS_INTERMISSION);
Y_StartIntermission(); Y_StartIntermission();
G_UpdateVisited(); G_UpdateVisited();
G_HandleSaveLevel();
} }
// do this before running the intermission or custom cutscene, mostly for the sake of marathon mode but it also massively reduces redundant file save events in f_finale.c
if (nextmap >= 1100-1)
{
if (!gamecomplete)
gamecomplete = 2; // special temporary mode to prevent using SP level select in pause menu until the intermission is over without restricting it in every intermission
if (cursaveslot > 0)
{
if (marathonmode)
{
// don't keep a backup around when the run is done!
if (FIL_FileExists(liveeventbackup))
remove(liveeventbackup);
cursaveslot = 0;
}
else if ((!modifiedgame || savemoddata) && !(netgame || multiplayer || ultimatemode || demorecording || metalrecording || modeattacking))
G_SaveGame((UINT32)cursaveslot, spstage_start);
}
}
// and doing THIS here means you don't lose your progress if you close the game mid-intermission
else if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking)
&& (!modifiedgame || savemoddata) && cursaveslot > 0 && CanSaveLevel(lastmap+1))
G_SaveGame((UINT32)cursaveslot, lastmap+1); // not nextmap+1 to route around special stages
} }
// See also F_EndCutscene, the only other place which handles intra-map/ending transitions // See also F_EndCutscene, the only other place which handles intra-map/ending transitions
@ -4498,7 +4503,10 @@ void G_SaveGame(UINT32 slot, INT16 mapnum)
P_SaveGame(mapnum); P_SaveGame(mapnum);
if (marathonmode) if (marathonmode)
{ {
WRITEUINT32(save_p, marathontime); UINT32 writetime = marathontime;
if (!(marathonmode & MA_INGAME))
writetime += TICRATE*5; // live event backup penalty because we don't know how long it takes to get to the next map
WRITEUINT32(save_p, writetime);
WRITEUINT8(save_p, (marathonmode & ~MA_INIT)); WRITEUINT8(save_p, (marathonmode & ~MA_INIT));
} }

View file

@ -117,7 +117,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
{ {
case 2 : // uhhhhhhhh.......... case 2 : // uhhhhhhhh..........
if ((originPatch != NULL) && (originPatch->style != AST_COPY)) if ((originPatch != NULL) && (originPatch->style != AST_COPY))
texel = ASTBlendPixel_8bpp(*(dest+1), texel, originPatch->style, originPatch->alpha); texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha);
texelu16 = (UINT16)((alpha<<8) | texel); texelu16 = (UINT16)((alpha<<8) | texel);
memcpy(dest, &texelu16, sizeof(UINT16)); memcpy(dest, &texelu16, sizeof(UINT16));
break; break;
@ -126,7 +126,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
{ {
RGBA_t rgbatexel; RGBA_t rgbatexel;
rgbatexel.rgba = *(UINT32 *)dest; rgbatexel.rgba = *(UINT32 *)dest;
colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
} }
memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
break; break;
@ -136,14 +136,14 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
{ {
RGBA_t rgbatexel; RGBA_t rgbatexel;
rgbatexel.rgba = *(UINT32 *)dest; rgbatexel.rgba = *(UINT32 *)dest;
colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
} }
memcpy(dest, &colortemp, sizeof(RGBA_t)); memcpy(dest, &colortemp, sizeof(RGBA_t));
break; break;
// default is 1 // default is 1
default: default:
if ((originPatch != NULL) && (originPatch->style != AST_COPY)) if ((originPatch != NULL) && (originPatch->style != AST_COPY))
*dest = ASTBlendPixel_8bpp(*dest, texel, originPatch->style, originPatch->alpha); *dest = ASTBlendPaletteIndexes(*dest, texel, originPatch->style, originPatch->alpha);
else else
*dest = texel; *dest = texel;
break; break;
@ -229,7 +229,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
{ {
case 2 : // uhhhhhhhh.......... case 2 : // uhhhhhhhh..........
if ((originPatch != NULL) && (originPatch->style != AST_COPY)) if ((originPatch != NULL) && (originPatch->style != AST_COPY))
texel = ASTBlendPixel_8bpp(*(dest+1), texel, originPatch->style, originPatch->alpha); texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha);
texelu16 = (UINT16)((alpha<<8) | texel); texelu16 = (UINT16)((alpha<<8) | texel);
memcpy(dest, &texelu16, sizeof(UINT16)); memcpy(dest, &texelu16, sizeof(UINT16));
break; break;
@ -238,7 +238,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
{ {
RGBA_t rgbatexel; RGBA_t rgbatexel;
rgbatexel.rgba = *(UINT32 *)dest; rgbatexel.rgba = *(UINT32 *)dest;
colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
} }
memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
break; break;
@ -248,14 +248,14 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
{ {
RGBA_t rgbatexel; RGBA_t rgbatexel;
rgbatexel.rgba = *(UINT32 *)dest; rgbatexel.rgba = *(UINT32 *)dest;
colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
} }
memcpy(dest, &colortemp, sizeof(RGBA_t)); memcpy(dest, &colortemp, sizeof(RGBA_t));
break; break;
// default is 1 // default is 1
default: default:
if ((originPatch != NULL) && (originPatch->style != AST_COPY)) if ((originPatch != NULL) && (originPatch->style != AST_COPY))
*dest = ASTBlendPixel_8bpp(*dest, texel, originPatch->style, originPatch->alpha); *dest = ASTBlendPaletteIndexes(*dest, texel, originPatch->style, originPatch->alpha);
else else
*dest = texel; *dest = texel;
break; break;

View file

@ -63,11 +63,12 @@ typedef struct gl_vissprite_s
{ {
float x1, x2; float x1, x2;
float tz, ty; float tz, ty;
float tracertz; // for MF2_LINKDRAW sprites, this contains tracer's tz for use in sorting
//lumpnum_t patchlumpnum; //lumpnum_t patchlumpnum;
GLPatch_t *gpatch; GLPatch_t *gpatch;
boolean flip; boolean flip;
UINT8 translucency; //alpha level 0-255 UINT8 translucency; //alpha level 0-255
mobj_t *mobj; mobj_t *mobj; // NOTE: This is a precipmobj_t if precip is true !!! Watch out.
boolean precip; // Tails 08-25-2002 boolean precip; // Tails 08-25-2002
boolean vflip; boolean vflip;
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode

View file

@ -2990,34 +2990,11 @@ static void HWR_Subsector(size_t num)
//gl_cursectorlight.blue = light; //gl_cursectorlight.blue = light;
//gl_cursectorlight.alpha = light; //gl_cursectorlight.alpha = light;
// ----- for special tricks with HW renderer -----
if (gl_frontsector->pseudoSector)
{
cullFloorHeight = locFloorHeight = gl_frontsector->virtualFloorheight;
cullCeilingHeight = locCeilingHeight = gl_frontsector->virtualCeilingheight;
}
else if (gl_frontsector->virtualFloor)
{
///@TODO Is this whole virtualFloor mess even useful? I don't think it even triggers ever.
cullFloorHeight = locFloorHeight = gl_frontsector->virtualFloorheight;
if (gl_frontsector->virtualCeiling)
cullCeilingHeight = locCeilingHeight = gl_frontsector->virtualCeilingheight;
else
cullCeilingHeight = locCeilingHeight = gl_frontsector->ceilingheight;
}
else if (gl_frontsector->virtualCeiling)
{
cullCeilingHeight = locCeilingHeight = gl_frontsector->virtualCeilingheight;
cullFloorHeight = locFloorHeight = gl_frontsector->floorheight;
}
else
{
cullFloorHeight = P_GetSectorFloorZAt (gl_frontsector, viewx, viewy);
cullCeilingHeight = P_GetSectorCeilingZAt(gl_frontsector, viewx, viewy);
locFloorHeight = P_GetSectorFloorZAt (gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y);
locCeilingHeight = P_GetSectorCeilingZAt(gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y);
}
// ----- end special tricks ----- // ----- end special tricks -----
cullFloorHeight = P_GetSectorFloorZAt (gl_frontsector, viewx, viewy);
cullCeilingHeight = P_GetSectorCeilingZAt(gl_frontsector, viewx, viewy);
locFloorHeight = P_GetSectorFloorZAt (gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y);
locCeilingHeight = P_GetSectorCeilingZAt(gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y);
if (gl_frontsector->ffloors) if (gl_frontsector->ffloors)
{ {
@ -3501,6 +3478,54 @@ static gl_vissprite_t *HWR_NewVisSprite(void)
return HWR_GetVisSprite(gl_visspritecount++); return HWR_GetVisSprite(gl_visspritecount++);
} }
// A hack solution for transparent surfaces appearing on top of linkdraw sprites.
// Keep a list of linkdraw sprites and draw their shapes to the z-buffer after all other
// sprite drawing is done. (effectively the z-buffer drawing of linkdraw sprites is delayed)
// NOTE: This will no longer be necessary once full translucent sorting is implemented, where
// translucent sprites and surfaces are sorted together.
typedef struct
{
FOutVector verts[4];
gr_vissprite_t *spr;
} zbuffersprite_t;
// this list is used to store data about linkdraw sprites
zbuffersprite_t linkdrawlist[MAXVISSPRITES];
UINT32 linkdrawcount = 0;
// add the necessary data to the list for delayed z-buffer drawing
static void HWR_LinkDrawHackAdd(FOutVector *verts, gr_vissprite_t *spr)
{
if (linkdrawcount < MAXVISSPRITES)
{
memcpy(linkdrawlist[linkdrawcount].verts, verts, sizeof(FOutVector) * 4);
linkdrawlist[linkdrawcount].spr = spr;
linkdrawcount++;
}
}
// process and clear the list of sprites for delayed z-buffer drawing
static void HWR_LinkDrawHackFinish(void)
{
UINT32 i;
FSurfaceInfo surf;
surf.PolyColor.rgba = 0xFFFFFFFF;
surf.TintColor.rgba = 0xFFFFFFFF;
surf.FadeColor.rgba = 0xFFFFFFFF;
surf.LightInfo.light_level = 0;
surf.LightInfo.fade_start = 0;
surf.LightInfo.fade_end = 31;
for (i = 0; i < linkdrawcount; i++)
{
// draw sprite shape, only to z-buffer
HWR_GetPatch(linkdrawlist[i].spr->gpatch);
HWR_ProcessPolygon(&surf, linkdrawlist[i].verts, 4, PF_Translucent|PF_Occlude|PF_Invisible|PF_Clip, 0, false);
}
// reset list
linkdrawcount = 0;
}
// //
// HWR_DoCulling // HWR_DoCulling
// Hardware version of R_DoCulling // Hardware version of R_DoCulling
@ -3687,6 +3712,8 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
extracolormap_t *colormap; extracolormap_t *colormap;
FUINT lightlevel; FUINT lightlevel;
FBITFIELD blend = 0; FBITFIELD blend = 0;
FBITFIELD occlusion;
boolean use_linkdraw_hack = false;
UINT8 alpha; UINT8 alpha;
INT32 i; INT32 i;
@ -3780,10 +3807,18 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
// co-ordinates // co-ordinates
memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts)); memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts));
// 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;
else
occlusion = PF_Occlude;
if (!cv_translucency.value) // translucency disabled if (!cv_translucency.value) // translucency disabled
{ {
Surf.PolyColor.s.alpha = 0xFF; Surf.PolyColor.s.alpha = 0xFF;
blend = PF_Translucent|PF_Occlude; blend = PF_Translucent|occlusion;
if (!occlusion) use_linkdraw_hack = true;
} }
else if (spr->mobj->flags2 & MF2_SHADOW) else if (spr->mobj->flags2 & MF2_SHADOW)
{ {
@ -3799,7 +3834,8 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
// Hurdler: PF_Environement would be cool, but we need to fix // Hurdler: PF_Environement would be cool, but we need to fix
// the issue with the fog before // the issue with the fog before
Surf.PolyColor.s.alpha = 0xFF; Surf.PolyColor.s.alpha = 0xFF;
blend = PF_Translucent|PF_Occlude; blend = PF_Translucent|occlusion;
if (!occlusion) use_linkdraw_hack = true;
} }
alpha = Surf.PolyColor.s.alpha; alpha = Surf.PolyColor.s.alpha;
@ -3904,6 +3940,9 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader
if (use_linkdraw_hack)
HWR_LinkDrawHackAdd(wallVerts, spr);
top = bot; top = bot;
endtop = endbot; endtop = endbot;
} }
@ -3929,6 +3968,9 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
Surf.PolyColor.s.alpha = alpha; Surf.PolyColor.s.alpha = alpha;
HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader
if (use_linkdraw_hack)
HWR_LinkDrawHackAdd(wallVerts, spr);
} }
// -----------------+ // -----------------+
@ -4051,10 +4093,21 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
{ {
FBITFIELD blend = 0; FBITFIELD blend = 0;
FBITFIELD occlusion;
boolean use_linkdraw_hack = false;
// 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;
else
occlusion = PF_Occlude;
if (!cv_translucency.value) // translucency disabled if (!cv_translucency.value) // translucency disabled
{ {
Surf.PolyColor.s.alpha = 0xFF; Surf.PolyColor.s.alpha = 0xFF;
blend = PF_Translucent|PF_Occlude; blend = PF_Translucent|occlusion;
if (!occlusion) use_linkdraw_hack = true;
} }
else if (spr->mobj->flags2 & MF2_SHADOW) else if (spr->mobj->flags2 & MF2_SHADOW)
{ {
@ -4070,10 +4123,14 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
// Hurdler: PF_Environement would be cool, but we need to fix // Hurdler: PF_Environement would be cool, but we need to fix
// the issue with the fog before // the issue with the fog before
Surf.PolyColor.s.alpha = 0xFF; Surf.PolyColor.s.alpha = 0xFF;
blend = PF_Translucent|PF_Occlude; blend = PF_Translucent|occlusion;
if (!occlusion) use_linkdraw_hack = true;
} }
HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader
if (use_linkdraw_hack)
HWR_LinkDrawHackAdd(wallVerts, spr);
} }
} }
@ -4189,6 +4246,7 @@ static int CompareVisSprites(const void *p1, const void *p2)
gl_vissprite_t* spr2 = *(gl_vissprite_t*const*)p2; gl_vissprite_t* spr2 = *(gl_vissprite_t*const*)p2;
int idiff; int idiff;
float fdiff; float fdiff;
float tz1, tz2;
// Make transparent sprites last. Comment from the previous sort implementation: // Make transparent sprites last. Comment from the previous sort implementation:
// Sryder: Oh boy, while it's nice having ALL the sprites sorted properly, it fails when we bring MD2's into the // Sryder: Oh boy, while it's nice having ALL the sprites sorted properly, it fails when we bring MD2's into the
@ -4196,12 +4254,53 @@ static int CompareVisSprites(const void *p1, const void *p2)
// everything else, but still ordered of course, the depth buffer can handle the opaque ones plenty fine. // everything else, but still ordered of course, the depth buffer can handle the opaque ones plenty fine.
// We just need to move all translucent ones to the end in order // We just need to move all translucent ones to the end in order
// TODO: Fully sort all sprites and MD2s with walls and floors, this part will be unnecessary after that // TODO: Fully sort all sprites and MD2s with walls and floors, this part will be unnecessary after that
int transparency1 = (spr1->mobj->flags2 & MF2_SHADOW) || (spr1->mobj->frame & FF_TRANSMASK); int transparency1;
int transparency2 = (spr2->mobj->flags2 & MF2_SHADOW) || (spr2->mobj->frame & FF_TRANSMASK); int transparency2;
// check for precip first, because then sprX->mobj is actually a precipmobj_t and does not have flags2 or tracer
int linkdraw1 = !spr1->precip && (spr1->mobj->flags2 & MF2_LINKDRAW) && spr1->mobj->tracer;
int linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer;
// ^ is the XOR operation
// if comparing a linkdraw and non-linkdraw sprite or 2 linkdraw sprites with different tracers, then use
// the tracer's properties instead of the main sprite's.
if ((linkdraw1 && linkdraw2 && spr1->mobj->tracer != spr2->mobj->tracer) || (linkdraw1 ^ linkdraw2))
{
if (linkdraw1)
{
tz1 = spr1->tracertz;
transparency1 = (spr1->mobj->tracer->flags2 & MF2_SHADOW) || (spr1->mobj->tracer->frame & FF_TRANSMASK);
}
else
{
tz1 = spr1->tz;
transparency1 = (!spr1->precip && (spr1->mobj->flags2 & MF2_SHADOW)) || (spr1->mobj->frame & FF_TRANSMASK);
}
if (linkdraw2)
{
tz2 = spr2->tracertz;
transparency2 = (spr2->mobj->tracer->flags2 & MF2_SHADOW) || (spr2->mobj->tracer->frame & FF_TRANSMASK);
}
else
{
tz2 = spr2->tz;
transparency2 = (!spr2->precip && (spr2->mobj->flags2 & MF2_SHADOW)) || (spr2->mobj->frame & FF_TRANSMASK);
}
}
else
{
tz1 = spr1->tz;
transparency1 = (!spr1->precip && (spr1->mobj->flags2 & MF2_SHADOW)) || (spr1->mobj->frame & FF_TRANSMASK);
tz2 = spr2->tz;
transparency2 = (!spr2->precip && (spr2->mobj->flags2 & MF2_SHADOW)) || (spr2->mobj->frame & FF_TRANSMASK);
}
// first compare transparency flags, then compare tz, then compare dispoffset
idiff = transparency1 - transparency2; idiff = transparency1 - transparency2;
if (idiff != 0) return idiff; if (idiff != 0) return idiff;
fdiff = spr2->tz - spr1->tz; // this order seems correct when checking with apitrace. Back to front. fdiff = tz2 - tz1; // this order seems correct when checking with apitrace. Back to front.
if (fabsf(fdiff) < 1.0E-36f) if (fabsf(fdiff) < 1.0E-36f)
return spr1->dispoffset - spr2->dispoffset; // smallest dispoffset first if sprites are at (almost) same location. return spr1->dispoffset - spr2->dispoffset; // smallest dispoffset first if sprites are at (almost) same location.
else if (fdiff > 0) else if (fdiff > 0)
@ -4525,6 +4624,7 @@ static void HWR_CreateDrawNodes(void)
static void HWR_DrawSprites(void) static void HWR_DrawSprites(void)
{ {
UINT32 i; UINT32 i;
boolean skipshadow = false; // skip shadow if it was drawn already for a linkdraw sprite encountered earlier in the list
HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, cv_glmodellighting.value); HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, cv_glmodellighting.value);
for (i = 0; i < gl_visspritecount; i++) for (i = 0; i < gl_visspritecount; i++)
{ {
@ -4535,11 +4635,32 @@ static void HWR_DrawSprites(void)
else else
#endif #endif
{ {
if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value) if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value && !skipshadow)
{ {
HWR_DrawDropShadow(spr->mobj, spr->mobj->shadowscale); HWR_DrawDropShadow(spr->mobj, spr->mobj->shadowscale);
} }
if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
{
// If this linkdraw sprite is behind a sprite that has a shadow,
// then that shadow has to be drawn first, otherwise the shadow ends up on top of
// the linkdraw sprite because the linkdraw sprite does not modify the z-buffer.
// The !skipshadow check is there in case there are multiple linkdraw sprites connected
// to the same tracer, so the tracer's shadow only gets drawn once.
if (cv_shadow.value && !skipshadow && spr->dispoffset < 0 && spr->mobj->tracer->shadowscale)
{
HWR_DrawDropShadow(spr->mobj->tracer, spr->mobj->tracer->shadowscale);
skipshadow = true;
// The next sprite in this loop should be either another linkdraw sprite or the tracer.
// When the tracer is inevitably encountered, skipshadow will cause it's shadow
// to get skipped and skipshadow will get set to false by the 'else' clause below.
}
}
else
{
skipshadow = false;
}
if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
{ {
if (!cv_glmodels.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) if (!cv_glmodels.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f)
@ -4563,6 +4684,16 @@ static void HWR_DrawSprites(void)
} }
} }
HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, 0); HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, 0);
// At the end of sprite drawing, draw shapes of linkdraw sprites to z-buffer, so they
// don't get drawn over by transparent surfaces.
HWR_LinkDrawHackFinish();
// Work around a r_opengl.c bug with PF_Invisible by making this SetBlend call
// where PF_Invisible is off and PF_Masked is on.
// (Other states probably don't matter. Here I left them same as in LinkDrawHackFinish)
// Without this workaround the rest of the draw calls in this frame (including UI, screen texture)
// can get drawn using an incorrect glBlendFunc, resulting in a occasional black screen.
HWD.pfnSetBlend(PF_Translucent|PF_Occlude|PF_Clip|PF_Masked);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -4624,6 +4755,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
gl_vissprite_t *vis; gl_vissprite_t *vis;
float tr_x, tr_y; float tr_x, tr_y;
float tz; float tz;
float tracertz = 0.0f;
float x1, x2; float x1, x2;
float rightsin, rightcos; float rightsin, rightcos;
float this_scale; float this_scale;
@ -4638,6 +4770,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP));
boolean mirrored = thing->mirrored; boolean mirrored = thing->mirrored;
boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored); boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored);
INT32 dispoffset;
angle_t ang; angle_t ang;
INT32 heightsec, phs; INT32 heightsec, phs;
@ -4655,6 +4788,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (!thing) if (!thing)
return; return;
dispoffset = thing->info->dispoffset;
this_scale = FIXED_TO_FLOAT(thing->scale); this_scale = FIXED_TO_FLOAT(thing->scale);
// transform the origin point // transform the origin point
@ -4867,9 +5002,28 @@ static void HWR_ProjectSprite(mobj_t *thing)
if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer)
{ {
// bodge support - not nearly as comprehensive as r_things.c, but better than nothing
if (! R_ThingVisible(thing->tracer)) if (! R_ThingVisible(thing->tracer))
return; return;
// calculate tz for tracer, same way it is calculated for this sprite
// transform the origin point
tr_x = FIXED_TO_FLOAT(thing->tracer->x) - gr_viewx;
tr_y = FIXED_TO_FLOAT(thing->tracer->y) - gr_viewy;
// rotation around vertical axis
tracertz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin);
// Software does not render the linkdraw sprite if the tracer is behind the view plane,
// so do the same check here.
// NOTE: This check has the same flaw as the view plane check at the beginning of HWR_ProjectSprite:
// the view aiming angle is not taken into account, leading to sprites disappearing too early when they
// can still be seen when looking down/up at steep angles.
if (tracertz < ZCLIP_PLANE)
return;
// if the sprite is behind the tracer, invert dispoffset, putting the sprite behind the tracer
if (tz > tracertz)
dispoffset *= -1;
} }
// store information in a vissprite // store information in a vissprite
@ -4877,7 +5031,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
vis->x1 = x1; vis->x1 = x1;
vis->x2 = x2; vis->x2 = x2;
vis->tz = tz; // Keep tz for the simple sprite sorting that happens vis->tz = tz; // Keep tz for the simple sprite sorting that happens
vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST vis->tracertz = tracertz;
vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
//vis->patchlumpnum = sprframe->lumppat[rot]; //vis->patchlumpnum = sprframe->lumppat[rot];
#ifdef ROTSPRITE #ifdef ROTSPRITE
if (rotsprite) if (rotsprite)
@ -5688,7 +5843,7 @@ static CV_PossibleValue_t grshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Thi
static void CV_glfiltermode_OnChange(void); static void CV_glfiltermode_OnChange(void);
static void CV_glanisotropic_OnChange(void); static void CV_glanisotropic_OnChange(void);
static CV_PossibleValue_t grfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"}, static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"},
{HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"}, {HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"},
{HWD_SET_TEXTUREFILTER_MIXED1, "Linear_Nearest"}, {HWD_SET_TEXTUREFILTER_MIXED1, "Linear_Nearest"},
{HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"}, {HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"},
@ -5716,12 +5871,11 @@ consvar_t cv_glskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL,
consvar_t cv_glfakecontrast = {"gr_fakecontrast", "Smooth", CV_SAVE, grfakecontrast_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glfakecontrast = {"gr_fakecontrast", "Smooth", CV_SAVE, grfakecontrast_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_glslopecontrast = {"gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glslopecontrast = {"gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_glfiltermode = {"gr_filtermode", "Nearest", CV_SAVE|CV_CALL, grfiltermode_cons_t, consvar_t cv_glfiltermode = {"gr_filtermode", "Nearest", CV_SAVE|CV_CALL, glfiltermode_cons_t,
CV_glfiltermode_OnChange, 0, NULL, NULL, 0, 0, NULL}; CV_glfiltermode_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_glanisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t, consvar_t cv_glanisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t,
CV_glanisotropic_OnChange, 0, NULL, NULL, 0, 0, NULL}; CV_glanisotropic_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_glcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_glsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_glbatching = {"gr_batching", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glbatching = {"gr_batching", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -5761,7 +5915,6 @@ void HWR_AddCommands(void)
CV_RegisterVar(&cv_glshaders); CV_RegisterVar(&cv_glshaders);
CV_RegisterVar(&cv_glfiltermode); CV_RegisterVar(&cv_glfiltermode);
CV_RegisterVar(&cv_glcorrecttricks);
CV_RegisterVar(&cv_glsolvetjoin); CV_RegisterVar(&cv_glsolvetjoin);
CV_RegisterVar(&cv_renderstats); CV_RegisterVar(&cv_renderstats);

View file

@ -52,7 +52,6 @@ boolean HWR_Screenshot(const char *pathname);
void HWR_AddCommands(void); void HWR_AddCommands(void);
void HWR_AddSessionCommands(void); void HWR_AddSessionCommands(void);
void HWR_CorrectSWTricks(void);
void transform(float *cx, float *cy, float *cz); void transform(float *cx, float *cy, float *cz);
FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf);
INT32 HWR_GetTextureUsed(void); INT32 HWR_GetTextureUsed(void);
@ -87,7 +86,6 @@ extern consvar_t cv_glmodelinterpolation;
extern consvar_t cv_glmodellighting; extern consvar_t cv_glmodellighting;
extern consvar_t cv_glfiltermode; extern consvar_t cv_glfiltermode;
extern consvar_t cv_glanisotropicmode; extern consvar_t cv_glanisotropicmode;
extern consvar_t cv_glcorrecttricks;
extern consvar_t cv_fovchange; extern consvar_t cv_fovchange;
extern consvar_t cv_glsolvetjoin; extern consvar_t cv_glsolvetjoin;
extern consvar_t cv_glshearing; extern consvar_t cv_glshearing;

View file

@ -1177,6 +1177,34 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t
return spr2; return spr2;
} }
static void adjustTextureCoords(model_t *model, GLPatch_t *gpatch)
{
int i;
for (i = 0; i < model->numMeshes; i++)
{
int j;
mesh_t *mesh = &model->meshes[i];
int numVertices;
float *uvPtr = mesh->uvs;
// i dont know if this is actually possible, just logical conclusion of structure in CreateModelVBOs
if (!mesh->frames && !mesh->tinyframes) return;
if (mesh->frames) // again CreateModelVBO and CreateModelVBOTiny iterate like this so I'm gonna do that too
numVertices = mesh->numTriangles * 3;
else
numVertices = mesh->numVertices;
// fix uvs (texture coordinates) to take into account that the actual texture
// has empty space added until the next power of two
for (j = 0; j < numVertices; j++)
{
*uvPtr++ *= gpatch->max_s;
*uvPtr++ *= gpatch->max_t;
}
}
}
// //
// HWR_DrawModel // HWR_DrawModel
// //
@ -1278,6 +1306,19 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
sprinfo = &spriteinfo[spr->mobj->sprite]; sprinfo = &spriteinfo[spr->mobj->sprite];
} }
// texture loading before model init, so it knows if sprite graphics are used, which
// means that texture coordinates have to be adjusted
gpatch = md2->grpatch;
if (!gpatch || ((!gpatch->mipmap->grInfo.format || !gpatch->mipmap->downloaded) && !md2->notexturefile))
md2_loadTexture(md2);
gpatch = md2->grpatch; // Load it again, because it isn't being loaded into gpatch after md2_loadtexture...
if ((gpatch && gpatch->mipmap->grInfo.format) // don't load the blend texture if the base texture isn't available
&& (!md2->blendgrpatch
|| ((!((GLPatch_t *)md2->blendgrpatch)->mipmap->grInfo.format || !((GLPatch_t *)md2->blendgrpatch)->mipmap->downloaded)
&& !md2->noblendfile)))
md2_loadBlendTexture(md2);
if (md2->error) if (md2->error)
return false; // we already failed loading this before :( return false; // we already failed loading this before :(
if (!md2->model) if (!md2->model)
@ -1289,6 +1330,10 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
if (md2->model) if (md2->model)
{ {
md2_printModelInfo(md2->model); md2_printModelInfo(md2->model);
// if model uses sprite patch as texture, then
// adjust texture coordinates to take power of two textures into account
if (!gpatch || !gpatch->mipmap->grInfo.format)
adjustTextureCoords(md2->model, spr->gpatch);
HWD.pfnCreateModelVBOs(md2->model); HWD.pfnCreateModelVBOs(md2->model);
} }
else else
@ -1306,16 +1351,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
//HWD.pfnSetBlend(blend); // This seems to actually break translucency? //HWD.pfnSetBlend(blend); // This seems to actually break translucency?
finalscale = md2->scale; finalscale = md2->scale;
//Hurdler: arf, I don't like that implementation at all... too much crappy //Hurdler: arf, I don't like that implementation at all... too much crappy
gpatch = md2->grpatch;
if (!gpatch || ((!gpatch->mipmap->format || !gpatch->mipmap->downloaded) && !md2->notexturefile))
md2_loadTexture(md2);
gpatch = md2->grpatch; // Load it again, because it isn't being loaded into gpatch after md2_loadtexture...
if ((gpatch && gpatch->mipmap->format) // don't load the blend texture if the base texture isn't available
&& (!md2->blendgrpatch
|| ((!((GLPatch_t *)md2->blendgrpatch)->mipmap->format || !((GLPatch_t *)md2->blendgrpatch)->mipmap->downloaded)
&& !md2->noblendfile)))
md2_loadBlendTexture(md2);
if (gpatch && gpatch->mipmap->format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture if (gpatch && gpatch->mipmap->format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture
{ {

View file

@ -1,914 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright (C) 1998-2001 by DooM Legacy Team.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//-----------------------------------------------------------------------------
/// \file
/// \brief special trick routines to make some SW tricks look OK with
/// HW rendering. This includes:
/// - deepwatereffect (e.g. tnt/map02)
/// - invisible staircase (e.g. eternal/map02)
/// - floating ceilings (e.g. eternal/map03)
///
/// It is not guaranteed that it looks identical to the SW mode,
/// but it looks in most of the cases far better than having
/// holes in the architecture, HOM, etc.
///
/// It fixes as well missing textures, which are replaced by either
/// a default texture or the midtexture.
///
/// words of notice:
/// pseudosectors, as mentioned in this file, are sectors where both
/// sidedefs point to the same sector. This expression is also used
/// for sectors which are enclosed by another sector but have no
/// correct sidedefs at all
///
/// if a vertex is inside a poly is determined by the angles between
/// this vertex and all angles on the linedefs (imagine walking along
/// a circle always facing a certain point inside/outside the circle;
/// if inside, angle have taken all values [0..pi), otherwise the
/// range was < pi/2
#include <math.h>
#include "../doomdef.h"
#include "../doomstat.h"
#ifdef HWRENDER
#include "hw_glob.h"
#include "hw_dll.h"
#include "../r_local.h"
#include "../i_system.h"
//
// add a line to a sectors list of lines
//
static void addLineToChain(sector_t *sector, line_t *line)
{
linechain_t *thisElem = NULL, *nextElem;
if (!sector)
return;
nextElem = sector->sectorLines;
while (nextElem) // walk through chain
{
thisElem = nextElem;
nextElem = thisElem->next;
}
// add a new element into the chain
if (thisElem)
{
thisElem->next = malloc(sizeof (linechain_t));
if (thisElem->next)
{
thisElem->next->line = line;
thisElem->next->next = NULL;
}
else
{
I_Error("Out of memory in addLineToChain(.)\n");
}
}
else // first element in chain
{
sector->sectorLines = malloc(sizeof (linechain_t));
if (sector->sectorLines)
{
sector->sectorLines->line = line;
sector->sectorLines->next = NULL;
}
else
{
I_Error("Out of memory in addLineToChain(.)\n");
}
}
}
//
// We dont want a memory hole, do we?;-)
//
static void releaseLineChains(void)
{
linechain_t *thisElem, *nextElem;
sector_t *sector;
size_t i;
for (i = 0; i < numsectors; i++)
{
sector = &sectors[i];
nextElem = sector->sectorLines;
while (nextElem)
{
thisElem = nextElem;
nextElem = thisElem->next;
free(thisElem);
}
sector->sectorLines = NULL;
}
}
//
// check if a pseudo sector is valid by checking all its linedefs
//
static boolean isPSectorValid(sector_t *sector)
{
linechain_t *thisElem, *nextElem;
if (!sector->pseudoSector) // check only pseudosectors, others dont care
{
#ifdef PARANOIA
CONS_Debug(DBG_RENDER, "Alert! non-pseudosector fed to isPSectorClosed()\n");
#endif
return false;
}
nextElem = sector->sectorLines;
while (nextElem)
{
thisElem = nextElem;
nextElem = thisElem->next;
if (thisElem->line->frontsector != thisElem->line->backsector)
return false;
}
return true;
}
//
// angles are always phiMax-phiMin [0...2\pi)
//
FUNCMATH static double phiDiff(double phiMin, double phiMax)
{
double result;
result = phiMax-phiMin;
if (result < 0.0l)
result += 2.0l*M_PIl;
return result;
}
//
// sort phi's so that enclosed angle < \pi
//
static void sortPhi(double phi1, double phi2, double *phiMin, double *phiMax)
{
if (phiDiff(phi1, phi2) < M_PIl)
{
*phiMin = phi1;
*phiMax = phi2;
}
else
{
*phiMin = phi2;
*phiMax = phi1;
}
}
//
// return if angle(phi1, phi2) is bigger than \pi
// if so, the vertex lies inside the poly
//
FUNCMATH static boolean biggerThanPi(double phi1, double phi2)
{
if (phiDiff(phi1, phi2) > M_PIl)
return true;
return false;
}
#define DELTAPHI (M_PIl/100.0l) // some small phi << \pi
//
// calculate bounds for minimum angle
//
static void phiBounds(double phi1, double phi2, double *phiMin, double *phiMax)
{
double phi1Tmp, phi2Tmp;
double psi1, psi2, psi3, psi4, psi5, psi6, psi7; // for optimization
sortPhi(phi1, phi2, &phi1Tmp, &phi2Tmp);
phi1 = phi1Tmp;
phi2 = phi2Tmp;
// check start condition
if (*phiMin > M_PIl || *phiMax > M_PIl)
{
*phiMin = phi1;
*phiMax = phi2;
return;
}
// 6 cases:
// new angles inbetween phiMin, phiMax -> forget it
// new angles enclose phiMin -> set phiMin
// new angles enclose phiMax -> set phiMax
// new angles completely outside phiMin, phiMax -> leave largest area free
// new angles close the range completely!
// new angles enlarges range on both sides
psi1 = phiDiff(*phiMin, phi1);
psi2 = phiDiff(*phiMin, phi2);
psi3 = phiDiff(*phiMax, phi1);
psi4 = phiDiff(*phiMax, phi2);
psi5 = phiDiff(*phiMin, *phiMax);
psi6 = (double)(2.0l*M_PIl - psi5); // phiDiff(*phiMax, *phiMin);
psi7 = (double)(2.0l*M_PIl - psi2); // phiDiff(phi2, *phiMin);
// case 1 & 5!
if ((psi1 <= psi5) && (psi2 <= psi5))
{
if (psi1 <= psi2) // case 1
{
return;
}
else // case 5
{
// create some artificial interval here not to get into numerical trouble
// in fact we know now the sector is completely enclosed -> base for computational optimization
*phiMax = 0.0l;
*phiMin = DELTAPHI;
return;
}
}
// case 2
if ((psi1 >= psi5) && (psi2 <= psi5))
{
*phiMin = phi1;
return;
}
// case 3
if ((psi3 >= psi6) && (psi4 <= psi6))
{
*phiMax = phi2;
return;
}
// case 4 & 6
#ifdef PARANOIA
if ((psi3 <= psi6) && (psi4 <= psi6)) // FIXME: isn't this case implicitly true anyway??
#endif
{
if (psi3 <= psi4) //case 4
{
if (psi3 >= psi7)
{
*phiMin = phi1;
return;
}
else
{
*phiMax = phi2;
return;
}
}
else // case 6
{
*phiMin = phi1;
*phiMax = phi2;
return;
}
}
#ifdef PARANOIA
CONS_Debug(DBG_RENDER, "phiMin = %f, phiMax = %f, phi1 = %f, phi2 = %f\n", *phiMin, *phiMax, phi1, phi2);
I_Error("phiBounds() out of range!\n");
#endif
}
//
// Check if a vertex lies inside a sector
// This works for "well-behaved" convex polygons
// If we need it mathematically correct, we need to sort the
// linedefs first so we have them in a row, then walk along the linedefs,
// but this is a bit overdone
//
static inline boolean isVertexInside(vertex_t *vertex, sector_t *sector)
{
double xa, ya, xe, ye;
linechain_t *chain;
double phiMin, phiMax;
double phi1, phi2;
chain = sector->sectorLines;
phiMin = phiMax = 10.0l*M_PIl; // some value > \pi
while (chain)
{
// start and end vertex
xa = (double)chain->line->v1->x - (double)vertex->x;
ya = (double)chain->line->v1->y - (double)vertex->y;
xe = (double)chain->line->v2->x - (double)vertex->x;
ye = (double)chain->line->v2->y - (double)vertex->y;
// angle phi of connection between the vertices and the x-axis
phi1 = atan2(ya, xa);
phi2 = atan2(ye, xe);
// if we have just started, we can have to create start bounds for phi
phiBounds(phi1, phi2, &phiMin, &phiMax);
chain = chain->next;
}
return biggerThanPi(phiMin, phiMax);
}
#define MAXSTACK 256 // Not more than 256 polys in each other?
//
// generate a list of sectors which enclose the given sector
//
static void generateStacklist(sector_t *thisSector)
{
size_t i, stackCnt = 0;
sector_t *locStacklist[MAXSTACK];
sector_t *checkSector;
for (i = 0; i < numsectors; i++)
{
checkSector = &sectors[i];
if (checkSector == thisSector) // dont check self
continue;
// buggy sector?
if (!thisSector->sectorLines)
continue;
// check if an arbitrary vertex of thisSector lies inside the checkSector
if (isVertexInside(thisSector->sectorLines->line->v1, checkSector))
{
// if so, the thisSector lies inside the checkSector
locStacklist[stackCnt] = checkSector;
stackCnt++;
if (MAXSTACK-1 == stackCnt) // beware of the SIGSEGV! and consider terminating NULL!
break;
}
}
thisSector->stackList = malloc(sizeof (sector_t *) * (stackCnt+1));
if (NULL == thisSector->stackList)
{
I_Error("Out of memory error in generateStacklist()");
}
locStacklist[stackCnt] = NULL; // terminating NULL
memcpy(thisSector->stackList, locStacklist, sizeof (sector_t *) * (stackCnt+1));
}
//
// Bubble sort the stacklist with rising lineoutlengths
//
static void sortStacklist(sector_t *sector)
{
sector_t **list;
sector_t *sec1, *sec2;
boolean finished;
size_t i;
list = sector->stackList;
finished = false;
if (!*list)
return; // nothing to sort
while (!finished)
{
i = 0;
finished = true;
while (*(list+i+1))
{
sec1 = *(list+i);
sec2 = *(list+i+1);
if (sec1->lineoutLength > sec2->lineoutLength)
{
*(list+i) = sec2;
*(list+i+1) = sec1;
finished = false;
}
i++;
}
}
}
//
// length of a line in euclidian sense
//
static double lineLength(line_t *line)
{
double dx, dy, length;
dx = (double) line->v1->x - (double) line->v2->x;
dy = (double) line->v1->y - (double) line->v2->y;
length = hypot(dx, dy);
return length;
}
//
// length of the sector lineout
//
static double calcLineoutLength(sector_t *sector)
{
linechain_t *chain;
double length = 0.0L;
chain = sector->sectorLines;
while (chain) // sum up lengths of all lines
{
length += lineLength(chain->line);
chain = chain->next;
}
return length;
}
//
// Calculate length of the sectors lineout
//
static void calcLineouts(sector_t *sector)
{
size_t secCount = 0;
sector_t *encSector = *(sector->stackList);
while (encSector)
{
if (encSector->lineoutLength < 0.0L) // if length has not yet been calculated
{
encSector->lineoutLength = calcLineoutLength(encSector);
}
secCount++;
encSector = *((sector->stackList) + secCount);
}
}
//
// Free Stacklists of all sectors
//
static void freeStacklists(void)
{
size_t i;
for (i = 0; i < numsectors; i++)
{
if (sectors[i].stackList)
{
free(sectors[i].stackList);
sectors[i].stackList = NULL;
}
}
}
//
// if more than half of the toptextures are missing
//
static boolean areToptexturesMissing(sector_t *thisSector)
{
linechain_t *thisElem, *nextElem = thisSector->sectorLines;
sector_t *frontSector, *backSector;
size_t nomiss = 0;
side_t *sidel, *sider;
while (nextElem) // walk through chain
{
thisElem = nextElem;
nextElem = thisElem->next;
frontSector = thisElem->line->frontsector;
backSector = thisElem->line->backsector;
if (frontSector == backSector) // skip damn renderer tricks here
continue;
if (!frontSector || !backSector)
continue;
sider = &sides[thisElem->line->sidenum[0]];
sidel = &sides[thisElem->line->sidenum[1]];
if (backSector->ceilingheight < frontSector->ceilingheight)
{
if (sider->toptexture != 0)
{
nomiss++;
break; // we can stop here if decision criterium is ==0
}
}
else if (backSector->ceilingheight > frontSector->ceilingheight)
{
if (sidel->toptexture != 0)
{
nomiss++;
break; // we can stop here if decision criterium is ==0
}
}
}
return nomiss == 0;
}
//
// are more textures missing than present?
//
static boolean areBottomtexturesMissing(sector_t *thisSector)
{
linechain_t *thisElem, *nextElem = thisSector->sectorLines;
sector_t *frontSector, *backSector;
size_t nomiss = 0;
side_t *sidel, *sider;
while (nextElem) // walk through chain
{
thisElem = nextElem;
nextElem = thisElem->next;
frontSector = thisElem->line->frontsector;
backSector = thisElem->line->backsector;
if (frontSector == backSector) // skip damn renderer tricks here
continue;
if (!frontSector || !backSector)
continue;
sider = &sides[thisElem->line->sidenum[0]];
sidel = &sides[thisElem->line->sidenum[1]];
if (backSector->floorheight > frontSector->floorheight)
{
if (sider->bottomtexture != 0)
{
nomiss++;
break; // we can stop here if decision criterium is ==0
}
}
else if (backSector->floorheight < frontSector->floorheight)
{
if (sidel->bottomtexture != 0)
{
nomiss++;
break; // we can stop here if decision criterium is ==0
}
}
}
// return missing >= nomiss;
return nomiss == 0;
}
//
// check if no adjacent sector has same ceiling height
//
static boolean isCeilingFloating(sector_t *thisSector)
{
sector_t *adjSector, *refSector = NULL, *frontSector, *backSector;
linechain_t *thisElem, *nextElem;
if (!thisSector)
return false;
nextElem = thisSector->sectorLines;
while (nextElem) // walk through chain
{
thisElem = nextElem;
nextElem = thisElem->next;
frontSector = thisElem->line->frontsector;
backSector = thisElem->line->backsector;
if (frontSector == thisSector)
adjSector = backSector;
else
adjSector = frontSector;
if (!adjSector) // assume floating sectors have surrounding sectors
return false;
if (adjSector->c_slope) // Don't bother with slopes
return false;
if (!refSector)
{
refSector = adjSector;
continue;
}
// if adjacent sector has same height or more than one adjacent sector exists -> stop
if (thisSector->ceilingheight == adjSector->ceilingheight || refSector != adjSector)
return false;
}
// now check for walltextures
if (!areToptexturesMissing(thisSector))
return false;
return true;
}
//
// check if no adjacent sector has same ceiling height
// FIXME: throw that together with isCeilingFloating??
//
static boolean isFloorFloating(sector_t *thisSector)
{
sector_t *adjSector, *refSector = NULL, *frontSector, *backSector;
linechain_t *thisElem, *nextElem;
if (!thisSector)
return false;
nextElem = thisSector->sectorLines;
while (nextElem) // walk through chain
{
thisElem = nextElem;
nextElem = thisElem->next;
frontSector = thisElem->line->frontsector;
backSector = thisElem->line->backsector;
if (frontSector == thisSector)
adjSector = backSector;
else
adjSector = frontSector;
if (!adjSector) // assume floating sectors have surrounding sectors
return false;
if (adjSector->f_slope) // Don't bother with slopes
return false;
if (!refSector)
{
refSector = adjSector;
continue;
}
// if adjacent sector has same height or more than one adjacent sector exists -> stop
if (thisSector->floorheight == adjSector->floorheight || refSector != adjSector)
return false;
}
// now check for walltextures
if (!areBottomtexturesMissing(thisSector))
return false;
return true;
}
//
// estimate ceilingheight according to height of adjacent sector
//
static fixed_t estimateCeilHeight(sector_t *thisSector)
{
sector_t *adjSector;
if (!thisSector || !thisSector->sectorLines || !thisSector->sectorLines->line)
return 0;
adjSector = thisSector->sectorLines->line->frontsector;
if (adjSector == thisSector)
adjSector = thisSector->sectorLines->line->backsector;
if (!adjSector)
return 0;
return adjSector->ceilingheight;
}
//
// estimate ceilingheight according to height of adjacent sector
//
static fixed_t estimateFloorHeight(sector_t *thisSector)
{
sector_t *adjSector;
if (!thisSector || !thisSector->sectorLines || !thisSector->sectorLines->line)
return 0;
adjSector = thisSector->sectorLines->line->frontsector;
if (adjSector == thisSector)
adjSector = thisSector->sectorLines->line->backsector;
if (!adjSector)
return 0;
return adjSector->floorheight;
}
#define CORRECT_FLOAT_EXPERIMENTAL
// --------------------------------------------------------------------------
// Some levels have missing sidedefs, which produces HOM, so lets try to compensate for that
// and some levels have deep water trick, invisible staircases etc.
// --------------------------------------------------------------------------
// FIXME: put some nice default texture in legacy.dat and use it
void HWR_CorrectSWTricks(void)
{
size_t i;
size_t k;
line_t *ld;
side_t *sidel = NULL, *sider;
sector_t *secl, *secr;
sector_t **sectorList;
sector_t *outSector;
if ((0 == cv_glcorrecttricks.value))
return;
// determine lines for sectors
for (i = 0; i < numlines; i++)
{
ld = &lines[i];
secr = ld->frontsector;
secl = ld->backsector;
if (secr == secl)
{
secr->pseudoSector = true; // special renderer trick?
addLineToChain(secr, ld);
}
else
{
addLineToChain(secr, ld);
addLineToChain(secl, ld);
}
}
// preprocessing
for (i = 0; i < numsectors; i++)
{
sector_t *checkSector;
checkSector = &sectors[i];
// identify real pseudosectors first
if (checkSector->pseudoSector)
{
if (!isPSectorValid(checkSector)) // drop invalid pseudo sectors
{
checkSector->pseudoSector = false;
}
}
// determine enclosing sectors for pseudosectors ... used later
if (checkSector->pseudoSector)
{
generateStacklist(checkSector);
calcLineouts(checkSector);
sortStacklist(checkSector);
}
}
// set virtual floor heights for pseudo sectors
// required for deep water effect e.g.
for (i = 0; i < numsectors; i++)
{
if (sectors[i].pseudoSector)
{
sectorList = sectors[i].stackList;
k = 0;
while (*(sectorList+k))
{
outSector = *(sectorList+k);
if (!outSector->pseudoSector)
{
sectors[i].virtualFloorheight = outSector->floorheight;
sectors[i].virtualCeilingheight = outSector->ceilingheight;
break;
}
k++;
}
if (*(sectorList+k) == NULL) // sorry, did not work :(
{
sectors[i].virtualFloorheight = sectors[i].floorheight;
sectors[i].virtualCeilingheight = sectors[i].ceilingheight;
}
}
}
#ifdef CORRECT_FLOAT_EXPERIMENTAL
// correct ceiling/floor heights of totally floating sectors
for (i = 0; i < numsectors; i++)
{
sector_t *floatSector;
floatSector = &sectors[i];
// correct height of floating sectors
if (isCeilingFloating(floatSector))
{
floatSector->virtualCeilingheight = estimateCeilHeight(floatSector);
floatSector->virtualCeiling = true;
}
if (isFloorFloating(floatSector))
{
floatSector->virtualFloorheight = estimateFloorHeight(floatSector);
floatSector->virtualFloor = true;
}
}
#endif
// now for the missing textures
for (i = 0; i < numlines; i++)
{
ld = &lines[i];
sider = &sides[ld->sidenum[0]];
if (ld->sidenum[1] != 0xffff)
sidel = &sides[ld->sidenum[1]];
secr = ld->frontsector;
secl = ld->backsector;
if (secr == secl) // special renderer trick
continue; // we cant correct missing textures here
if (secl) // only if there is a backsector
{
if (secr->pseudoSector || secl->pseudoSector)
continue;
if (!secr->virtualFloor && !secl->virtualFloor)
{
if (secl->floorheight > secr->floorheight)
{
// now check if r-sidedef is correct
if (sider->bottomtexture == 0)
{
if (sider->midtexture == 0)
sider->bottomtexture = 0; // Tails // More redwall sky shenanigans
else
sider->bottomtexture = sider->midtexture;
}
}
else if (secl->floorheight < secr->floorheight)
{
// now check if l-sidedef is correct
if (sidel->bottomtexture == 0)
{
if (sidel->midtexture == 0)
sidel->bottomtexture = 0; // Tails // More redwall sky shenanigans
else
sidel->bottomtexture = sidel->midtexture;
}
}
}
if (!secr->virtualCeiling && !secl->virtualCeiling)
{
if (secl->ceilingheight < secr->ceilingheight)
{
// now check if r-sidedef is correct
if (sider->toptexture == 0)
{
if (sider->midtexture == 0)
sider->toptexture = 0; // Tails // When this was REDWALL it was causing issues in the sky sometimes
else
sider->toptexture = sider->midtexture;
}
}
else if (secl->ceilingheight > secr->ceilingheight)
{
// now check if l-sidedef is correct
if (sidel->toptexture == 0)
{
if (sidel->midtexture == 0)
sidel->toptexture = 0; // Tails // When this was REDWALL it was causing issues in the sky sometimes
else
sidel->toptexture = sidel->midtexture;
}
}
}
} // if (NULL != secl)
} // for (i = 0; i < numlines; i++)
// release all linechains
releaseLineChains();
freeStacklists();
}
#endif // HWRENDER

View file

@ -2939,6 +2939,8 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform)
if (shearing) if (shearing)
{ {
float fdy = stransform->viewaiming * 2; float fdy = stransform->viewaiming * 2;
if (stransform->flip)
fdy *= -1.0f;
pglTranslatef(0.0f, -fdy/BASEVIDHEIGHT, 0.0f); pglTranslatef(0.0f, -fdy/BASEVIDHEIGHT, 0.0f);
} }

View file

@ -21803,11 +21803,11 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
{"Super Orange 4", {0x00, 0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46}, SKINCOLOR_SAPPHIRE, 4, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE4 {"Super Orange 4", {0x00, 0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46}, SKINCOLOR_SAPPHIRE, 4, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE4
{"Super Orange 5", {0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46, 0x47}, SKINCOLOR_SAPPHIRE, 3, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE5 {"Super Orange 5", {0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46, 0x47}, SKINCOLOR_SAPPHIRE, 3, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE5
{"Super Gold 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x52, 0x53, 0x48}, SKINCOLOR_CORNFLOWER, 15, 0, false}, // SKINCOLOR_SUPERGOLD1 {"Super Gold 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x52, 0x53, 0x48, 0x48, 0x48}, SKINCOLOR_CORNFLOWER, 15, 0, false}, // SKINCOLOR_SUPERGOLD1
{"Super Gold 2", {0x00, 0x50, 0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41}, SKINCOLOR_CORNFLOWER, 9, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD2 {"Super Gold 2", {0x00, 0x50, 0x51, 0x52, 0x53, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x41, 0x41}, SKINCOLOR_CORNFLOWER, 9, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD2
{"Super Gold 3", {0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD3 {"Super Gold 3", {0x51, 0x52, 0x53, 0x53, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x43, 0x43}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD3
{"Super Gold 4", {0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD4 {"Super Gold 4", {0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x46, 0x46}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD4
{"Super Gold 5", {0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD5 {"Super Gold 5", {0x48, 0x48, 0x49, 0x49, 0x49, 0x40, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x47, 0x47}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD5
{"Super Peridot 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc}, SKINCOLOR_COBALT, 15, 0, false}, // SKINCOLOR_SUPERPERIDOT1 {"Super Peridot 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc}, SKINCOLOR_COBALT, 15, 0, false}, // SKINCOLOR_SUPERPERIDOT1
{"Super Peridot 2", {0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe}, SKINCOLOR_COBALT, 4, V_PERIDOTMAP, false}, // SKINCOLOR_SUPERPERIDOT2 {"Super Peridot 2", {0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe}, SKINCOLOR_COBALT, 4, V_PERIDOTMAP, false}, // SKINCOLOR_SUPERPERIDOT2

View file

@ -902,6 +902,17 @@ static int lib_pMaceRotate(lua_State *L)
return 0; return 0;
} }
static int lib_pRailThinker(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_RailThinker(mobj));
return 1;
}
// P_USER // P_USER
//////////// ////////////
@ -3259,6 +3270,7 @@ static luaL_Reg lib[] = {
{"P_CheckSolidLava",lib_pCheckSolidLava}, {"P_CheckSolidLava",lib_pCheckSolidLava},
{"P_CanRunOnWater",lib_pCanRunOnWater}, {"P_CanRunOnWater",lib_pCanRunOnWater},
{"P_MaceRotate",lib_pMaceRotate}, {"P_MaceRotate",lib_pMaceRotate},
{"P_RailThinker",lib_pRailThinker},
// p_user // p_user
{"P_GetPlayerHeight",lib_pGetPlayerHeight}, {"P_GetPlayerHeight",lib_pGetPlayerHeight},

View file

@ -487,7 +487,7 @@ CV_PossibleValue_t loadless_cons_t[] = {{0, "Realtime"}, {1, "In-game"}, {0, NUL
consvar_t cv_dummymarathon = {"dummymarathon", "Standard", CV_HIDEN, marathon_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_dummymarathon = {"dummymarathon", "Standard", CV_HIDEN, marathon_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_dummycutscenes = {"dummycutscenes", "Off", CV_HIDEN, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_dummycutscenes = {"dummycutscenes", "Off", CV_HIDEN, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_dummyloadless = {"dummyloadless", "Realtime", CV_HIDEN, loadless_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_dummyloadless = {"dummyloadless", "In-game", CV_HIDEN, loadless_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
// ========================================================================== // ==========================================================================
// ORGANIZATION START. // ORGANIZATION START.
@ -1942,7 +1942,7 @@ static menu_t SP_NightsGhostDef =
static menu_t SP_MarathonDef = static menu_t SP_MarathonDef =
{ {
MTREE2(MN_SP_MAIN, MN_SP_MARATHON), MTREE2(MN_SP_MAIN, MN_SP_MARATHON),
"M_ATTACK", // temporary "M_RATHON",
sizeof(SP_MarathonMenu)/sizeof(menuitem_t), sizeof(SP_MarathonMenu)/sizeof(menuitem_t),
&MainDef, // Doesn't matter. &MainDef, // Doesn't matter.
SP_MarathonMenu, SP_MarathonMenu,
@ -10563,8 +10563,7 @@ static void M_StartMarathon(INT32 choice)
(void)choice; (void)choice;
marathontime = 0; marathontime = 0;
marathonmode = MA_RUNNING|MA_INIT; marathonmode = MA_RUNNING|MA_INIT;
if (cv_dummymarathon.value == 1) cursaveslot = (cv_dummymarathon.value == 1) ? MARATHONSLOT : 0;
cursaveslot = MARATHONSLOT;
if (!cv_dummycutscenes.value) if (!cv_dummycutscenes.value)
marathonmode |= MA_NOCUTSCENES; marathonmode |= MA_NOCUTSCENES;
if (cv_dummyloadless.value) if (cv_dummyloadless.value)
@ -10709,7 +10708,7 @@ void M_DrawMarathon(void)
recatkdrawtimer -= (10*TICRATE); recatkdrawtimer -= (10*TICRATE);
} }
//M_DrawMenuTitle(); M_DrawMenuTitle();
// draw menu (everything else goes on top of it) // draw menu (everything else goes on top of it)
// Sadly we can't just use generic mode menus because we need some extra hacks // Sadly we can't just use generic mode menus because we need some extra hacks

View file

@ -162,7 +162,7 @@ consvar_t cv_zlib_memorya = {"apng_memory_level", "(Max Memory) 9", CV_SAVE, zli
consvar_t cv_zlib_levela = {"apng_compress_level", "4", CV_SAVE, zlib_level_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_zlib_levela = {"apng_compress_level", "4", CV_SAVE, zlib_level_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_zlib_strategya = {"apng_strategy", "RLE", CV_SAVE, zlib_strategy_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_zlib_strategya = {"apng_strategy", "RLE", CV_SAVE, zlib_strategy_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_zlib_window_bitsa = {"apng_window_size", "32k", CV_SAVE, zlib_window_bits_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_zlib_window_bitsa = {"apng_window_size", "32k", CV_SAVE, zlib_window_bits_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_apng_delay = {"apng_speed", "1/2x", CV_SAVE, apng_delay_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_apng_delay = {"apng_speed", "1x", CV_SAVE, apng_delay_t, NULL, 0, NULL, NULL, 0, 0, NULL};
boolean takescreenshot = false; // Take a screenshot this tic boolean takescreenshot = false; // Take a screenshot this tic

View file

@ -5214,7 +5214,7 @@ void A_SignPlayer(mobj_t *actor)
actor->tracer->color = signcolor; actor->tracer->color = signcolor;
if (signcolor && signcolor < numskincolors) if (signcolor && signcolor < numskincolors)
signframe += (15 - skincolors[facecolor].invshade); signframe += (15 - skincolors[skincolors[signcolor].invcolor].invshade);
actor->tracer->frame = signframe; actor->tracer->frame = signframe;
} }

View file

@ -467,10 +467,22 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1)) if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1))
{ {
if (elementalpierce == 2) if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
P_DoBubbleBounce(player); {
else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) fixed_t setmomz = -toucher->momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce
toucher->momz = -toucher->momz;
if (elementalpierce == 2) // Reset bubblewrap, part 1
P_DoBubbleBounce(player);
toucher->momz = setmomz;
if (elementalpierce == 2) // Reset bubblewrap, part 2
{
boolean underwater = toucher->eflags & MFE_UNDERWATER;
if (underwater)
toucher->momz /= 2;
toucher->momz -= (toucher->momz/(underwater ? 8 : 4)); // Cap the height!
}
}
} }
if (player->pflags & PF_BOUNCING) if (player->pflags & PF_BOUNCING)
P_DoAbilityBounce(player, false); P_DoAbilityBounce(player, false);

View file

@ -1678,13 +1678,23 @@ static boolean PIT_CheckThing(mobj_t *thing)
&& (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up && (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up
&& (elementalpierce != 1)) // you're not piercing through the monitor... && (elementalpierce != 1)) // you're not piercing through the monitor...
{ {
if (elementalpierce == 2) if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
P_DoBubbleBounce(player);
else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
{ {
*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically. fixed_t setmomz = -*momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce
if (elementalpierce == 2) // Reset bubblewrap, part 1
P_DoBubbleBounce(player);
*momz = setmomz; // Therefore, you should be thrust in the opposite direction, vertically.
if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)
P_TwinSpinRejuvenate(player, player->thokitem); P_TwinSpinRejuvenate(player, player->thokitem);
if (elementalpierce == 2) // Reset bubblewrap, part 2
{
boolean underwater = tmthing->eflags & MFE_UNDERWATER;
if (underwater)
*momz /= 2;
*momz -= (*momz/(underwater ? 8 : 4)); // Cap the height!
}
} }
} }
if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough. if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough.

View file

@ -442,7 +442,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
mobj->sprite2 = spr2; mobj->sprite2 = spr2;
mobj->frame = frame|(st->frame&~FF_FRAMEMASK); mobj->frame = frame|(st->frame&~FF_FRAMEMASK);
if (mobj->color >= FIRSTSUPERCOLOR && mobj->color < numskincolors) // Super colours? Super bright! if (player->powers[pw_super] || (player->powers[pw_carry] == CR_NIGHTSMODE && (player->charflags & (SF_SUPER|SF_NONIGHTSSUPER)) == SF_SUPER)) // Super colours? Super bright!
mobj->frame |= FF_FULLBRIGHT; mobj->frame |= FF_FULLBRIGHT;
} }
// Regular sprites // Regular sprites

View file

@ -995,17 +995,6 @@ static void P_InitializeSector(sector_t *ss)
ss->extra_colormap = NULL; ss->extra_colormap = NULL;
#ifdef HWRENDER // ----- for special tricks with HW renderer -----
ss->pseudoSector = false;
ss->virtualFloor = false;
ss->virtualFloorheight = 0;
ss->virtualCeiling = false;
ss->virtualCeilingheight = 0;
ss->sectorLines = NULL;
ss->stackList = NULL;
ss->lineoutLength = -1.0l;
#endif // ----- end special tricks -----
ss->gravity = NULL; ss->gravity = NULL;
ss->verticalflip = false; ss->verticalflip = false;
ss->flags = SF_FLIPSPECIAL_FLOOR; ss->flags = SF_FLIPSPECIAL_FLOOR;
@ -3767,7 +3756,7 @@ boolean P_LoadLevel(boolean fromnetsave)
if (!lastmaploaded) // Start a new game? if (!lastmaploaded) // Start a new game?
{ {
// I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020 // I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020
if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking || marathonmode)
&& (!modifiedgame || savemoddata) && cursaveslot > 0) && (!modifiedgame || savemoddata) && cursaveslot > 0)
G_SaveGame((UINT32)cursaveslot, gamemap); G_SaveGame((UINT32)cursaveslot, gamemap);
// If you're looking for saving sp file progression (distinct from G_SaveGameOver), check G_DoCompleted. // If you're looking for saving sp file progression (distinct from G_SaveGameOver), check G_DoCompleted.
@ -3825,8 +3814,6 @@ void HWR_SetupLevel(void)
HWR_ResetLights(); HWR_ResetLights();
#endif #endif
// Correct missing sidedefs & deep water trick
HWR_CorrectSWTricks();
HWR_CreatePlanePolygons((INT32)numnodes - 1); HWR_CreatePlanePolygons((INT32)numnodes - 1);
} }
#endif #endif

View file

@ -4863,7 +4863,7 @@ void P_DoBubbleBounce(player_t *player)
player->pflags |= PF_THOKKED; player->pflags |= PF_THOKKED;
player->pflags &= ~PF_STARTJUMP; player->pflags &= ~PF_STARTJUMP;
player->secondjump = UINT8_MAX; player->secondjump = UINT8_MAX;
player->mo->momz = FixedMul(player->mo->momz, 5*FRACUNIT/4); player->mo->momz = FixedMul(player->mo->momz, 11*FRACUNIT/8);
} }
// //
@ -5112,15 +5112,19 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL); boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL);
player->pflags |= PF_THOKKED|PF_SHIELDABILITY; player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
if (elem) if (elem)
{
player->mo->momx = player->mo->momy = 0;
S_StartSound(player->mo, sfx_s3k43); S_StartSound(player->mo, sfx_s3k43);
}
else else
{ {
player->mo->momx -= (player->mo->momx/3);
player->mo->momy -= (player->mo->momy/3);
player->pflags &= ~PF_NOJUMPDAMAGE; player->pflags &= ~PF_NOJUMPDAMAGE;
P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
S_StartSound(player->mo, sfx_s3k44); S_StartSound(player->mo, sfx_s3k44);
} }
player->secondjump = 0; player->secondjump = 0;
player->mo->momx = player->mo->momy = 0;
P_SetObjectMomZ(player->mo, -24*FRACUNIT, false); P_SetObjectMomZ(player->mo, -24*FRACUNIT, false);
break; break;
} }

View file

@ -227,6 +227,8 @@ static inline void R_DrawFlippedColumnInCache(column_t *patch, UINT8 *cache, tex
} }
} }
// Blends two pixels together, using the equation
// that matches the specified alpha style.
UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha) UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha)
{ {
RGBA_t output; RGBA_t output;
@ -245,7 +247,13 @@ UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alph
// if the background pixel is empty, // if the background pixel is empty,
// match software and don't blend anything // match software and don't blend anything
if (!background.s.alpha) if (!background.s.alpha)
output.s.alpha = 0; {
// ...unless the foreground pixel ISN'T actually translucent.
if (alpha == 0xFF)
output.rgba = foreground.rgba;
else
output.rgba = 0;
}
else else
{ {
UINT8 beta = (0xFF - alpha); UINT8 beta = (0xFF - alpha);
@ -302,18 +310,46 @@ UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alph
return 0; return 0;
} }
UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 alpha) INT32 ASTTextureBlendingThreshold[2] = {255/11, (10*255/11)};
// Blends a pixel for a texture patch.
UINT32 ASTBlendTexturePixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha)
{ {
// Alpha style set to translucent? // Alpha style set to translucent?
if (style == AST_TRANSLUCENT) if (style == AST_TRANSLUCENT)
{ {
// Is the alpha small enough for translucency? // Is the alpha small enough for translucency?
if (alpha <= (10*255/11)) if (alpha <= ASTTextureBlendingThreshold[1])
{
// Is the patch way too translucent? Don't blend then.
if (alpha < ASTTextureBlendingThreshold[0])
return background.rgba;
return ASTBlendPixel(background, foreground, style, alpha);
}
else // just copy the pixel
return foreground.rgba;
}
else
return ASTBlendPixel(background, foreground, style, alpha);
}
// Blends two palette indexes for a texture patch, then
// finds the nearest palette index from the blended output.
UINT8 ASTBlendPaletteIndexes(UINT8 background, UINT8 foreground, int style, UINT8 alpha)
{
// Alpha style set to translucent?
if (style == AST_TRANSLUCENT)
{
// Is the alpha small enough for translucency?
if (alpha <= ASTTextureBlendingThreshold[1])
{ {
UINT8 *mytransmap; UINT8 *mytransmap;
// Is the patch way too translucent? Don't blend then. // Is the patch way too translucent? Don't blend then.
if (alpha < 255/11) if (alpha < ASTTextureBlendingThreshold[0])
return background; return background;
// The equation's not exact but it works as intended. I'll call it a day for now. // The equation's not exact but it works as intended. I'll call it a day for now.
mytransmap = transtables + ((8*(alpha) + 255/8)/(255 - 255/11) << FF_TRANSSHIFT); mytransmap = transtables + ((8*(alpha) + 255/8)/(255 - 255/11) << FF_TRANSSHIFT);
if (background != 0xFF) if (background != 0xFF)
@ -378,7 +414,7 @@ static inline void R_DrawBlendColumnInCache(column_t *patch, UINT8 *cache, texpa
{ {
for (; dest < cache + position + count; source++, dest++) for (; dest < cache + position + count; source++, dest++)
if (*source != 0xFF) if (*source != 0xFF)
*dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); *dest = ASTBlendPaletteIndexes(*dest, *source, originPatch->style, originPatch->alpha);
} }
patch = (column_t *)((UINT8 *)patch + patch->length + 4); patch = (column_t *)((UINT8 *)patch + patch->length + 4);
@ -422,7 +458,7 @@ static inline void R_DrawBlendFlippedColumnInCache(column_t *patch, UINT8 *cache
{ {
for (; dest < cache + position + count; --source, dest++) for (; dest < cache + position + count; --source, dest++)
if (*source != 0xFF) if (*source != 0xFF)
*dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); *dest = ASTBlendPaletteIndexes(*dest, *source, originPatch->style, originPatch->alpha);
} }
patch = (column_t *)((UINT8 *)patch + patch->length + 4); patch = (column_t *)((UINT8 *)patch + patch->length + 4);

View file

@ -26,7 +26,10 @@
enum patchalphastyle {AST_COPY, AST_TRANSLUCENT, AST_ADD, AST_SUBTRACT, AST_REVERSESUBTRACT, AST_MODULATE, AST_OVERLAY}; enum patchalphastyle {AST_COPY, AST_TRANSLUCENT, AST_ADD, AST_SUBTRACT, AST_REVERSESUBTRACT, AST_MODULATE, AST_OVERLAY};
UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha); UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha);
UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 alpha); UINT32 ASTBlendTexturePixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha);
UINT8 ASTBlendPaletteIndexes(UINT8 background, UINT8 foreground, int style, UINT8 alpha);
extern INT32 ASTTextureBlendingThreshold[2];
UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b);

View file

@ -221,20 +221,6 @@ typedef struct r_lightlist_s
INT32 lightnum; INT32 lightnum;
} r_lightlist_t; } r_lightlist_t;
// ----- for special tricks with HW renderer -----
//
// For creating a chain with the lines around a sector
//
typedef struct linechain_s
{
struct line_s *line;
struct linechain_s *next;
} linechain_t;
// ----- end special tricks -----
// Slopes // Slopes
typedef enum { typedef enum {
SL_NOPHYSICS = 1, /// This plane will have no physics applied besides the positioning. SL_NOPHYSICS = 1, /// This plane will have no physics applied besides the positioning.
@ -348,17 +334,6 @@ typedef struct sector_s
// per-sector colormaps! // per-sector colormaps!
extracolormap_t *extra_colormap; extracolormap_t *extra_colormap;
#ifdef HWRENDER // ----- for special tricks with HW renderer -----
boolean pseudoSector;
boolean virtualFloor;
fixed_t virtualFloorheight;
boolean virtualCeiling;
fixed_t virtualCeilingheight;
linechain_t *sectorLines;
struct sector_s **stackList;
double lineoutLength;
#endif // ----- end special tricks -----
// This points to the master's floorheight, so it can be changed in realtime! // This points to the master's floorheight, so it can be changed in realtime!
fixed_t *gravity; // per-sector gravity fixed_t *gravity; // per-sector gravity
boolean verticalflip; // If gravity < 0, then allow flipped physics boolean verticalflip; // If gravity < 0, then allow flipped physics

View file

@ -381,7 +381,6 @@
<ClCompile Include="..\hardware\hw_md2load.c" /> <ClCompile Include="..\hardware\hw_md2load.c" />
<ClCompile Include="..\hardware\hw_md3load.c" /> <ClCompile Include="..\hardware\hw_md3load.c" />
<ClCompile Include="..\hardware\hw_model.c" /> <ClCompile Include="..\hardware\hw_model.c" />
<ClCompile Include="..\hardware\hw_trick.c" />
<ClCompile Include="..\hardware\r_opengl\r_opengl.c" /> <ClCompile Include="..\hardware\r_opengl\r_opengl.c" />
<ClCompile Include="..\hardware\u_list.c" /> <ClCompile Include="..\hardware\u_list.c" />
<ClCompile Include="..\hu_stuff.c" /> <ClCompile Include="..\hu_stuff.c" />

View file

@ -669,9 +669,6 @@
<ClCompile Include="..\hardware\hw_model.c"> <ClCompile Include="..\hardware\hw_model.c">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\hardware\hw_trick.c">
<Filter>Hw_Hardware</Filter>
</ClCompile>
<ClCompile Include="..\hardware\u_list.c"> <ClCompile Include="..\hardware\u_list.c">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClCompile> </ClCompile>

View file

@ -2546,46 +2546,6 @@
RelativePath="..\hardware\hw_md2.h" RelativePath="..\hardware\hw_md2.h"
> >
</File> </File>
<File
RelativePath="..\hardware\hw_trick.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File <File
RelativePath="..\hardware\hws_data.h" RelativePath="..\hardware\hws_data.h"
> >

View file

@ -604,10 +604,6 @@ SOURCE=..\hardware\hw_md2.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\hardware\hw_trick.c
# End Source File
# Begin Source File
SOURCE=..\hardware\hws_data.h SOURCE=..\hardware\hws_data.h
# End Source File # End Source File
# End Group # End Group

View file

@ -108,7 +108,7 @@ int TimeFunction(int requested_frequency);
#endif #endif
#endif #endif
#if (defined (__unix__) && !defined (_MSDOS)) || defined (UNIXCOMMON) #if (defined (__unix__) && !defined (_MSDOS)) || (defined (UNIXCOMMON) && !defined(__APPLE__))
#include <errno.h> #include <errno.h>
#include <sys/wait.h> #include <sys/wait.h>
#define NEWSIGNALHANDLER #define NEWSIGNALHANDLER

View file

@ -1113,13 +1113,6 @@
path = ../../hardware/hw_md2.h; path = ../../hardware/hw_md2.h;
refType = 2; refType = 2;
}; };
84177743085A106C000C01D8 = {
fileEncoding = 30;
isa = PBXFileReference;
name = hw_trick.c;
path = ../../hardware/hw_trick.c;
refType = 2;
};
84177744085A106C000C01D8 = { 84177744085A106C000C01D8 = {
fileEncoding = 30; fileEncoding = 30;
isa = PBXFileReference; isa = PBXFileReference;

View file

@ -19,7 +19,6 @@
1E44AE800B67CC2B00BAD059 /* hw_draw.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE6C0B67CC2B00BAD059 /* hw_draw.c */; }; 1E44AE800B67CC2B00BAD059 /* hw_draw.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE6C0B67CC2B00BAD059 /* hw_draw.c */; };
1E44AE820B67CC2B00BAD059 /* hw_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE6E0B67CC2B00BAD059 /* hw_main.c */; }; 1E44AE820B67CC2B00BAD059 /* hw_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE6E0B67CC2B00BAD059 /* hw_main.c */; };
1E44AE840B67CC2B00BAD059 /* hw_md2.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE700B67CC2B00BAD059 /* hw_md2.c */; }; 1E44AE840B67CC2B00BAD059 /* hw_md2.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE700B67CC2B00BAD059 /* hw_md2.c */; };
1E44AE860B67CC2B00BAD059 /* hw_trick.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE720B67CC2B00BAD059 /* hw_trick.c */; };
1E44AEA40B67CC8500BAD059 /* d_clisrv.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE8D0B67CC8400BAD059 /* d_clisrv.c */; }; 1E44AEA40B67CC8500BAD059 /* d_clisrv.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE8D0B67CC8400BAD059 /* d_clisrv.c */; };
1E44AEA70B67CC8500BAD059 /* d_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE900B67CC8400BAD059 /* d_main.c */; }; 1E44AEA70B67CC8500BAD059 /* d_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE900B67CC8400BAD059 /* d_main.c */; };
1E44AEA80B67CC8500BAD059 /* d_net.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE910B67CC8500BAD059 /* d_net.c */; }; 1E44AEA80B67CC8500BAD059 /* d_net.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE910B67CC8500BAD059 /* d_net.c */; };
@ -191,7 +190,6 @@
1E44AE6F0B67CC2B00BAD059 /* hw_main.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = hw_main.h; path = ../../hardware/hw_main.h; sourceTree = SOURCE_ROOT; }; 1E44AE6F0B67CC2B00BAD059 /* hw_main.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = hw_main.h; path = ../../hardware/hw_main.h; sourceTree = SOURCE_ROOT; };
1E44AE700B67CC2B00BAD059 /* hw_md2.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = hw_md2.c; path = ../../hardware/hw_md2.c; sourceTree = SOURCE_ROOT; }; 1E44AE700B67CC2B00BAD059 /* hw_md2.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = hw_md2.c; path = ../../hardware/hw_md2.c; sourceTree = SOURCE_ROOT; };
1E44AE710B67CC2B00BAD059 /* hw_md2.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = hw_md2.h; path = ../../hardware/hw_md2.h; sourceTree = SOURCE_ROOT; }; 1E44AE710B67CC2B00BAD059 /* hw_md2.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = hw_md2.h; path = ../../hardware/hw_md2.h; sourceTree = SOURCE_ROOT; };
1E44AE720B67CC2B00BAD059 /* hw_trick.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = hw_trick.c; path = ../../hardware/hw_trick.c; sourceTree = SOURCE_ROOT; };
1E44AE730B67CC2B00BAD059 /* hws_data.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = hws_data.h; path = ../../hardware/hws_data.h; sourceTree = SOURCE_ROOT; }; 1E44AE730B67CC2B00BAD059 /* hws_data.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = hws_data.h; path = ../../hardware/hws_data.h; sourceTree = SOURCE_ROOT; };
1E44AE8A0B67CC6000BAD059 /* asm_defs.inc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.pascal; name = asm_defs.inc; path = ../../asm_defs.inc; sourceTree = SOURCE_ROOT; }; 1E44AE8A0B67CC6000BAD059 /* asm_defs.inc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.pascal; name = asm_defs.inc; path = ../../asm_defs.inc; sourceTree = SOURCE_ROOT; };
1E44AE8D0B67CC8400BAD059 /* d_clisrv.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = d_clisrv.c; path = ../../d_clisrv.c; sourceTree = SOURCE_ROOT; }; 1E44AE8D0B67CC8400BAD059 /* d_clisrv.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = d_clisrv.c; path = ../../d_clisrv.c; sourceTree = SOURCE_ROOT; };
@ -544,7 +542,6 @@
1E44AE6F0B67CC2B00BAD059 /* hw_main.h */, 1E44AE6F0B67CC2B00BAD059 /* hw_main.h */,
1E44AE700B67CC2B00BAD059 /* hw_md2.c */, 1E44AE700B67CC2B00BAD059 /* hw_md2.c */,
1E44AE710B67CC2B00BAD059 /* hw_md2.h */, 1E44AE710B67CC2B00BAD059 /* hw_md2.h */,
1E44AE720B67CC2B00BAD059 /* hw_trick.c */,
1E44AE730B67CC2B00BAD059 /* hws_data.h */, 1E44AE730B67CC2B00BAD059 /* hws_data.h */,
); );
name = Hw_Hardware; name = Hw_Hardware;
@ -1078,7 +1075,6 @@
1E44AE800B67CC2B00BAD059 /* hw_draw.c in Sources */, 1E44AE800B67CC2B00BAD059 /* hw_draw.c in Sources */,
1E44AE820B67CC2B00BAD059 /* hw_main.c in Sources */, 1E44AE820B67CC2B00BAD059 /* hw_main.c in Sources */,
1E44AE840B67CC2B00BAD059 /* hw_md2.c in Sources */, 1E44AE840B67CC2B00BAD059 /* hw_md2.c in Sources */,
1E44AE860B67CC2B00BAD059 /* hw_trick.c in Sources */,
1E44AEA40B67CC8500BAD059 /* d_clisrv.c in Sources */, 1E44AEA40B67CC8500BAD059 /* d_clisrv.c in Sources */,
1E44AEA70B67CC8500BAD059 /* d_main.c in Sources */, 1E44AEA70B67CC8500BAD059 /* d_main.c in Sources */,
1E44AEA80B67CC8500BAD059 /* d_net.c in Sources */, 1E44AEA80B67CC8500BAD059 /* d_net.c in Sources */,
@ -1217,7 +1213,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.2.4; CURRENT_PROJECT_VERSION = 2.2.6;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1229,7 +1225,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.2.4; CURRENT_PROJECT_VERSION = 2.2.6;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View file

@ -240,8 +240,8 @@ void ST_LoadGraphics(void)
int i; int i;
// SRB2 border patch // SRB2 border patch
st_borderpatchnum = W_GetNumForName("GFZFLR01"); // st_borderpatchnum = W_GetNumForName("GFZFLR01");
scr_borderpatch = W_CacheLumpNum(st_borderpatchnum, PU_HUDGFX); // scr_borderpatch = W_CacheLumpNum(st_borderpatchnum, PU_HUDGFX);
// the original Doom uses 'STF' as base name for all face graphics // the original Doom uses 'STF' as base name for all face graphics
// Graue 04-08-2004: face/name graphics are now indexed by skins // Graue 04-08-2004: face/name graphics are now indexed by skins

View file

@ -234,7 +234,6 @@
<ClCompile Include="..\hardware\hw_md2load.c" /> <ClCompile Include="..\hardware\hw_md2load.c" />
<ClCompile Include="..\hardware\hw_md3load.c" /> <ClCompile Include="..\hardware\hw_md3load.c" />
<ClCompile Include="..\hardware\hw_model.c" /> <ClCompile Include="..\hardware\hw_model.c" />
<ClCompile Include="..\hardware\hw_trick.c" />
<ClCompile Include="..\hardware\u_list.c" /> <ClCompile Include="..\hardware\u_list.c" />
<ClCompile Include="..\hu_stuff.c" /> <ClCompile Include="..\hu_stuff.c" />
<ClCompile Include="..\info.c" /> <ClCompile Include="..\info.c" />

View file

@ -108,9 +108,6 @@
<ClCompile Include="..\hardware\hw_md2.c"> <ClCompile Include="..\hardware\hw_md2.c">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\hardware\hw_trick.c">
<Filter>Hw_Hardware</Filter>
</ClCompile>
<ClCompile Include="..\hardware\hw3sound.c"> <ClCompile Include="..\hardware\hw3sound.c">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClCompile> </ClCompile>

View file

@ -2287,46 +2287,6 @@
RelativePath="..\hardware\hw_md2.h" RelativePath="..\hardware\hw_md2.h"
> >
</File> </File>
<File
RelativePath="..\hardware\hw_trick.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File <File
RelativePath="..\hardware\hws_data.h" RelativePath="..\hardware\hws_data.h"
> >

View file

@ -563,10 +563,6 @@ SOURCE=..\hardware\hw_md2.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\hardware\hw_trick.c
# End Source File
# Begin Source File
SOURCE=..\hardware\hws_data.h SOURCE=..\hardware\hws_data.h
# End Source File # End Source File
# End Group # End Group

View file

@ -66,8 +66,8 @@ END
#include "../doomdef.h" // Needed for version string #include "../doomdef.h" // Needed for version string
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,2,0,0 FILEVERSION 2,2,6,0
PRODUCTVERSION 2,2,0,0 PRODUCTVERSION 2,2,6,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L