- sync 3D floor branch with trunk.

SVN r3094 (3dfloors2)
This commit is contained in:
Christoph Oelckers 2011-01-09 12:07:19 +00:00
parent 652558577c
commit f511e29278
65 changed files with 3577 additions and 924 deletions

View file

@ -658,6 +658,7 @@ add_executable( zdoom WIN32
m_misc.cpp m_misc.cpp
m_png.cpp m_png.cpp
m_random.cpp m_random.cpp
memarena.cpp
md5.cpp md5.cpp
name.cpp name.cpp
nodebuild.cpp nodebuild.cpp

View file

@ -28,6 +28,9 @@
%define setupmvlineasm _setupmvlineasm %define setupmvlineasm _setupmvlineasm
%define mvlineasm1 _mvlineasm1 %define mvlineasm1 _mvlineasm1
%define mvlineasm4 _mvlineasm4 %define mvlineasm4 _mvlineasm4
%define R_SetupDrawSlab _R_SetupDrawSlab
%define R_DrawSlab _R_DrawSlab
%endif %endif
EXTERN ylookup ; near EXTERN ylookup ; near
@ -44,9 +47,6 @@ EXTERN dc_dest
EXTERN dc_source EXTERN dc_source
EXTERN dc_texturefrac EXTERN dc_texturefrac
mvlineasm4_counter:
dd 0
SECTION .text SECTION .text
ALIGN 16 ALIGN 16
@ -59,8 +59,45 @@ setvlinebpl_:
mov [fixchain2ma+2], eax mov [fixchain2ma+2], eax
mov [fixchain2mb+2], eax mov [fixchain2mb+2], eax
selfmod fixchain1a, fixchain2mb+6 selfmod fixchain1a, fixchain2mb+6
setdrawslabbpl:
mov dword [voxbpl1+2], eax
mov dword [voxbpl2+2], eax
mov dword [voxbpl3+2], eax
mov dword [voxbpl4+2], eax
mov dword [voxbpl5+2], eax
mov dword [voxbpl6+2], eax
mov dword [voxbpl7+2], eax
mov dword [voxbpl8+2], eax
selfmod voxbpl1, voxpl8+6
ret ret
SECTION .data
lastslabcolormap:
dd 4
SECTION .text
GLOBAL R_SetupDrawSlab
GLOBAL @R_SetupDrawSlab@4
R_SetupDrawSlab:
mov ecx, [esp+4]
@R_SetupDrawSlab@4:
cmp [lastslabcolormap], ecx
je .done
mov [lastslabcolormap], ecx
mov dword [voxpal1+2], ecx
mov dword [voxpal2+2], ecx
mov dword [voxpal3+2], ecx
mov dword [voxpal4+2], ecx
mov dword [voxpal5+2], ecx
mov dword [voxpal6+2], ecx
mov dword [voxpal7+2], ecx
mov dword [voxpal8+2], ecx
.done ret
; pass it log2(texheight) ; pass it log2(texheight)
ALIGN 16 ALIGN 16
@ -549,6 +586,226 @@ mvcase0: jmp beginmvlineasm4
align 16 align 16
;*************************************************************************
;***************************** Voxel Slabs *******************************
;*************************************************************************
GLOBAL R_DrawSlab
R_DrawSlab:
push ebx
push ebp
push esi
push edi
mov eax, [esp+5*4+0]
mov ebx, [esp+5*4+4]
mov ecx, [esp+5*4+8]
mov edx, [esp+5*4+12]
mov esi, [esp+5*4+16]
mov edi, [esp+5*4+20]
cmp eax, 2
je voxbegdraw2
ja voxskip2
xor eax, eax
voxbegdraw1:
mov ebp, ebx
shr ebp, 16
add ebx, edx
dec ecx
mov al, byte [esi+ebp]
voxpal1: mov al, byte [eax+88888888h]
mov byte [edi], al
voxbpl1: lea edi, [edi+88888888h]
jnz voxbegdraw1
jmp voxskipslab5
voxbegdraw2:
mov ebp, ebx
shr ebp, 16
add ebx, edx
xor eax, eax
dec ecx
mov al, byte [esi+ebp]
voxpal2: mov al, byte [eax+88888888h]
mov ah, al
mov word [edi], ax
voxbpl2: lea edi, [edi+88888888h]
jnz voxbegdraw2
jmp voxskipslab5
voxskip2:
cmp eax, 4
jne voxskip4
xor eax, eax
voxbegdraw4:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal3: mov al, byte [eax+88888888h]
mov ah, al
shl eax, 8
mov al, ah
shl eax, 8
mov al, ah
mov dword [edi], eax
voxbpl3: add edi, 88888888h
dec ecx
jnz voxbegdraw4
jmp voxskipslab5
voxskip4:
add eax, edi
test edi, 1
jz voxskipslab1
cmp edi, eax
je voxskipslab1
push eax
push ebx
push ecx
push edi
voxbegslab1:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal4: mov al, byte [eax+88888888h]
mov byte [edi], al
voxbpl4: add edi, 88888888h
dec ecx
jnz voxbegslab1
pop edi
pop ecx
pop ebx
pop eax
inc edi
voxskipslab1:
push eax
test edi, 2
jz voxskipslab2
dec eax
cmp edi, eax
jge voxskipslab2
push ebx
push ecx
push edi
voxbegslab2:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal5: mov al, byte [eax+88888888h]
mov ah, al
mov word [edi], ax
voxbpl5: add edi, 88888888h
dec ecx
jnz voxbegslab2
pop edi
pop ecx
pop ebx
add edi, 2
voxskipslab2:
mov eax, [esp]
sub eax, 3
cmp edi, eax
jge voxskipslab3
voxprebegslab3:
push ebx
push ecx
push edi
voxbegslab3:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal6: mov al, byte [eax+88888888h]
mov ah, al
shl eax, 8
mov al, ah
shl eax, 8
mov al, ah
mov dword [edi], eax
voxbpl6: add edi, 88888888h
dec ecx
jnz voxbegslab3
pop edi
pop ecx
pop ebx
add edi, 4
mov eax, [esp]
sub eax, 3
cmp edi, eax
jl voxprebegslab3
voxskipslab3:
mov eax, [esp]
dec eax
cmp edi, eax
jge voxskipslab4
push ebx
push ecx
push edi
voxbegslab4:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal7: mov al, byte [eax+88888888h]
mov ah, al
mov word [edi], ax
voxbpl7: add edi, 88888888h
dec ecx
jnz voxbegslab4
pop edi
pop ecx
pop ebx
add edi, 2
voxskipslab4:
pop eax
cmp edi, eax
je voxskipslab5
voxbegslab5:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal8: mov al, byte [eax+88888888h]
mov byte [edi], al
voxbpl8: add edi, 88888888h
dec ecx
jnz voxbegslab5
voxskipslab5:
pop edi
pop esi
pop ebp
pop ebx
ret
align 16
%ifdef M_TARGET_MACHO %ifdef M_TARGET_MACHO
GLOBAL _rtext_a_end GLOBAL _rtext_a_end
_rtext_a_end: _rtext_a_end:

View file

@ -342,13 +342,13 @@ dsy3: shr ebp,26
mov edx,[ds_ystep] mov edx,[ds_ystep]
mov ecx,[ds_xfrac] mov ecx,[ds_xfrac]
dsy4: shr ecx,26 dsy4: shr ecx,26
dsm8: and edx,0xffffffc0 dsm8: and edx,strict dword 0xffffffc0
or ebp,edx or ebp,edx
mov [esp+4],ebp mov [esp+4],ebp
mov ebp,[ds_yfrac] mov ebp,[ds_yfrac]
mov edx,[ds_xfrac] mov edx,[ds_xfrac]
dsy2: shl edx,6 dsy2: shl edx,6
dsm9: and ebp,0xffffffc0 dsm9: and ebp,strict dword 0xffffffc0
or ecx,ebp or ecx,ebp
shr esi,1 shr esi,1
jnc dseven1 jnc dseven1
@ -485,13 +485,13 @@ dmsy3: shr ebp,26
mov edx,[ds_ystep] mov edx,[ds_ystep]
mov ecx,[ds_xfrac] mov ecx,[ds_xfrac]
dmsy4: shr ecx,26 dmsy4: shr ecx,26
dmsm8: and edx,0xffffffc0 dmsm8: and edx,strict dword 0xffffffc0
or ebp,edx or ebp,edx
mov [esp+4],ebp mov [esp+4],ebp
mov ebp,[ds_yfrac] mov ebp,[ds_yfrac]
mov edx,[ds_xfrac] mov edx,[ds_xfrac]
dmsy2: shl edx,6 dmsy2: shl edx,6
dmsm9: and ebp,0xffffffc0 dmsm9: and ebp,strict dword 0xffffffc0
or ecx,ebp or ecx,ebp
shr esi,1 shr esi,1
jnc dmseven1 jnc dmseven1
@ -850,8 +850,8 @@ GLOBAL R_DrawColumnHorizP_ASM
align 16 align 16
@R_DrawColumnHorizP_ASM@0: @R_DrawColumnHorizP_ASM@0:
R_DrawColumnHorizP_ASM:
_R_DrawColumnHorizP_ASM: _R_DrawColumnHorizP_ASM:
R_DrawColumnHorizP_ASM:
; count = dc_yh - dc_yl; ; count = dc_yh - dc_yl;
@ -870,8 +870,10 @@ _R_DrawColumnHorizP_ASM:
inc eax ; make 0 count mean 0 pixels inc eax ; make 0 count mean 0 pixels
and edx,3 and edx,3
push eax push eax
mov esi,[dc_ctspan+edx*4] mov eax,[dc_temp]
lea eax,[dc_temp+ecx*4+edx] ; eax = top of column in buffer mov esi,[dc_ctspan+edx*4]
add eax,edx
lea eax,[eax+ecx*4] ; eax = top of column in buffer
mov ebp,[dc_yh] mov ebp,[dc_yh]
mov [esi],ecx mov [esi],ecx
mov [esi+4],ebp mov [esi+4],ebp
@ -1102,8 +1104,9 @@ _rt_copy1col_asm:
lea esi,[eax*4] lea esi,[eax*4]
inc ebx ; ebx = count inc ebx ; ebx = count
mov eax,edx mov eax,edx
lea ecx,[dc_temp+ecx+esi] ; ecx = source add ecx,esi
mov edi,[ylookup+esi] mov edi,[ylookup+esi]
add ecx,[dc_temp] ; ecx = source
mov esi,[dc_pitch] ; esi = pitch mov esi,[dc_pitch] ; esi = pitch
add eax,edi ; eax = dest add eax,edi ; eax = dest
add eax,[dc_destorg] add eax,[dc_destorg]
@ -1169,10 +1172,11 @@ _rt_copy4cols_asm:
inc ebx ; ebx = count inc ebx ; ebx = count
mov eax,ecx mov eax,ecx
mov esi,[ylookup+edx*4] mov esi,[ylookup+edx*4]
lea ecx,[dc_temp+edx*4] ; ecx = source mov ecx,[dc_temp]
mov edx,[dc_pitch] ; edx = pitch
add eax,esi ; eax = dest add eax,esi ; eax = dest
add eax,[dc_destorg] add eax,[dc_destorg]
lea ecx,[ecx+edx*4] ; ecx = source
mov edx,[dc_pitch] ; edx = pitch
shr ebx,1 shr ebx,1
jnc .even jnc .even
@ -1241,7 +1245,8 @@ _rt_map1col_asm:
mov esi,[dc_colormap] ; esi = colormap mov esi,[dc_colormap] ; esi = colormap
inc ebx ; ebx = count inc ebx ; ebx = count
mov eax,edx mov eax,edx
lea ebp,[dc_temp+ecx+edi] ; ebp = source lea ebp,[ecx+edi] ; ebp = source
add ebp,[dc_temp]
mov ecx,[ylookup+edi] mov ecx,[ylookup+edi]
mov edi,[dc_pitch] ; edi = pitch mov edi,[dc_pitch] ; edi = pitch
add eax,ecx ; eax = dest add eax,ecx ; eax = dest
@ -1320,7 +1325,8 @@ _rt_map4cols_asm1:
mov eax,ecx mov eax,ecx
inc ebx ; ebx = count inc ebx ; ebx = count
mov edi,[ylookup+edx] mov edi,[ylookup+edx]
lea ebp,[dc_temp+edx] ; ebp = source mov ebp,[dc_temp]
add ebp,edx ; ebp = source
add eax,edi ; eax = dest add eax,edi ; eax = dest
mov edi,[dc_pitch] ; edi = pitch mov edi,[dc_pitch] ; edi = pitch
add eax,[dc_destorg] add eax,[dc_destorg]
@ -1414,7 +1420,8 @@ _rt_map4cols_asm2:
mov eax,ecx mov eax,ecx
inc ebx ; ebx = count inc ebx ; ebx = count
mov edi,[ylookup+edx] mov edi,[ylookup+edx]
lea ebp,[dc_temp+edx] ; ebp = source mov ebp,[dc_temp]
add ebp,edx ; ebp = source
add eax,edi ; eax = dest add eax,edi ; eax = dest
mov edi,[dc_pitch] ; edi = pitch mov edi,[dc_pitch] ; edi = pitch
add eax,[dc_destorg] add eax,[dc_destorg]
@ -1493,10 +1500,11 @@ _rt_shaded4cols_asm:
add eax,[dc_destorg] ; eax = destination add eax,[dc_destorg] ; eax = destination
push ebx push ebx
push esi push esi
mov esi,[dc_temp]
inc ebp ; ebp = count inc ebp ; ebp = count
add eax,[esp+16] add eax,[esp+16]
push edi push edi
lea esi,[dc_temp+ecx*4] ; esi = source lea esi,[esi+ecx*4] ; esi = source
align 16 align 16
@ -1580,10 +1588,11 @@ _rt_add4cols_asm:
add eax,[dc_destorg] add eax,[dc_destorg]
push ebx push ebx
push esi push esi
mov esi,[dc_temp]
push ebp push ebp
inc edi inc edi
add eax,[esp+20] add eax,[esp+20]
lea esi,[dc_temp+ecx*4] lea esi,[esi+ecx*4]
align 16 align 16
a4loop: a4loop:
@ -1659,10 +1668,11 @@ _rt_addclamp4cols_asm:
add eax,[dc_destorg] add eax,[dc_destorg]
push ebx push ebx
push esi push esi
mov esi,[dc_temp]
push ebp push ebp
inc edi inc edi
add eax,[esp+20] add eax,[esp+20]
lea esi,[dc_temp+ecx*4] lea esi,[esi+ecx*4]
push edi push edi
align 16 align 16

View file

@ -453,7 +453,7 @@ CCMD (puke)
if (argc < 2 || argc > 5) if (argc < 2 || argc > 5)
{ {
Printf (" puke <script> [arg1] [arg2] [arg3]\n"); Printf ("Usage: puke <script> [arg1] [arg2] [arg3]\n");
} }
else else
{ {
@ -489,6 +489,52 @@ CCMD (puke)
} }
} }
CCMD (special)
{
int argc = argv.argc();
if (argc < 2 || argc > 7)
{
Printf("Usage: special <special-name> [arg1] [arg2] [arg3] [arg4] [arg5]\n");
}
else
{
int specnum;
if (argv[1][0] >= '0' && argv[1][0] <= '9')
{
specnum = atoi(argv[1]);
if (specnum < 0 || specnum > 255)
{
Printf("Bad special number\n");
return;
}
}
else
{
int min_args;
specnum = P_FindLineSpecial(argv[1], &min_args);
if (specnum == 0 || min_args < 0)
{
Printf("Unknown special\n");
return;
}
if (argc < 2 + min_args)
{
Printf("%s needs at least %d argument%s\n", argv[1], min_args, min_args == 1 ? "" : "s");
return;
}
}
Net_WriteByte(DEM_RUNSPECIAL);
Net_WriteByte(specnum);
Net_WriteByte(argc - 2);
for (int i = 2; i < argc; ++i)
{
Net_WriteLong(atoi(argv[i]));
}
}
}
CCMD (error) CCMD (error)
{ {
if (argv.argc() > 1) if (argv.argc() > 1)

View file

@ -221,7 +221,16 @@ int FBaseCVar::ToInt (UCVarValue value, ECVarType type)
#else #else
case CVAR_Float: res = (int)value.Float; break; case CVAR_Float: res = (int)value.Float; break;
#endif #endif
case CVAR_String: res = strtol (value.String, NULL, 0); break; case CVAR_String:
{
if (stricmp (value.String, "true") == 0)
res = 1;
else if (stricmp (value.String, "false") == 0)
res = 0;
else
res = strtol (value.String, NULL, 0);
break;
}
case CVAR_GUID: res = 0; break; case CVAR_GUID: res = 0; break;
default: res = 0; break; default: res = 0; break;
} }
@ -444,7 +453,12 @@ UCVarValue FBaseCVar::FromString (const char *value, ECVarType type)
break; break;
case CVAR_Int: case CVAR_Int:
ret.Int = strtol (value, NULL, 0); if (stricmp (value, "true") == 0)
ret.Int = 1;
else if (stricmp (value, "false") == 0)
ret.Int = 0;
else
ret.Int = strtol (value, NULL, 0);
break; break;
case CVAR_Float: case CVAR_Float:

View file

@ -166,5 +166,6 @@ void ResetButtonStates (); // Same as above, but also clear bDown
extern unsigned int MakeKey (const char *s); extern unsigned int MakeKey (const char *s);
extern unsigned int MakeKey (const char *s, size_t len); extern unsigned int MakeKey (const char *s, size_t len);
extern unsigned int SuperFastHash (const char *data, size_t len);
#endif //__C_DISPATCH_H__ #endif //__C_DISPATCH_H__

View file

@ -90,7 +90,6 @@ static FCompatOption Options[] =
{ "resetplayerspeed", 0, BCOMPATF_RESETPLAYERSPEED }, { "resetplayerspeed", 0, BCOMPATF_RESETPLAYERSPEED },
{ "vileghosts", 0, BCOMPATF_VILEGHOSTS }, { "vileghosts", 0, BCOMPATF_VILEGHOSTS },
{ "ignoreteleporttags", 0, BCOMPATF_BADTELEPORTERS }, { "ignoreteleporttags", 0, BCOMPATF_BADTELEPORTERS },
{ "oldportals", 0, BCOMPATF_BADPORTALS },
// list copied from g_mapinfo.cpp // list copied from g_mapinfo.cpp
{ "shorttex", COMPATF_SHORTTEX, 0 }, { "shorttex", COMPATF_SHORTTEX, 0 },
@ -284,12 +283,6 @@ void CheckCompatibility(MapData *map)
ib_compatflags = 0; ib_compatflags = 0;
ii_compatparams = -1; ii_compatparams = -1;
} }
else if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATPORTAL))
{
ii_compatflags = 0;
ib_compatflags = BCOMPATF_BADPORTALS;
ii_compatparams = -1;
}
else else
{ {
map->GetChecksum(md5.Bytes); map->GetChecksum(md5.Bytes);

View file

@ -174,7 +174,6 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
else if(sc.Compare("Extended")) iwad->flags |= GI_MENUHACK_EXTENDED; else if(sc.Compare("Extended")) iwad->flags |= GI_MENUHACK_EXTENDED;
else if(sc.Compare("Shorttex")) iwad->flags |= GI_COMPATSHORTTEX; else if(sc.Compare("Shorttex")) iwad->flags |= GI_COMPATSHORTTEX;
else if(sc.Compare("Stairs")) iwad->flags |= GI_COMPATSTAIRS; else if(sc.Compare("Stairs")) iwad->flags |= GI_COMPATSTAIRS;
else if(sc.Compare("Portals")) iwad->flags |= GI_COMPATPORTAL;
else sc.ScriptError(NULL); else sc.ScriptError(NULL);
} }
while (sc.CheckString(",")); while (sc.CheckString(","));

View file

@ -57,6 +57,7 @@
#include "g_level.h" #include "g_level.h"
#include "d_event.h" #include "d_event.h"
#include "m_argv.h" #include "m_argv.h"
#include "p_lnspec.h"
int P_StartScript (AActor *who, line_t *where, int script, char *map, bool backSide, int P_StartScript (AActor *who, line_t *where, int script, char *map, bool backSide,
int arg0, int arg1, int arg2, int always, bool wantResultCode, bool net); int arg0, int arg1, int arg2, int always, bool wantResultCode, bool net);
@ -2316,13 +2317,38 @@ void Net_DoCommand (int type, BYTE **stream, int player)
for (i = 0; i < argn; ++i) for (i = 0; i < argn; ++i)
{ {
arg[i] = ReadLong (stream); int argval = ReadLong(stream);
if (i < countof(arg))
{
arg[i] = argval;
}
} }
P_StartScript (players[player].mo, NULL, snum, level.mapname, false, P_StartScript (players[player].mo, NULL, snum, level.mapname, false,
arg[0], arg[1], arg[2], type == DEM_RUNSCRIPT2, false, true); arg[0], arg[1], arg[2], type == DEM_RUNSCRIPT2, false, true);
} }
break; break;
case DEM_RUNSPECIAL:
{
int snum = ReadByte(stream);
int argn = ReadByte(stream);
int arg[5] = { 0, 0, 0, 0, 0 };
for (i = 0; i < argn; ++i)
{
int argval = ReadLong(stream);
if (i < countof(arg))
{
arg[i] = argval;
}
}
if (!CheckCheatmode(player == consoleplayer))
{
LineSpecials[snum](NULL, players[player].mo, false, arg[0], arg[1], arg[2], arg[3], arg[4]);
}
}
break;
case DEM_CROUCH: case DEM_CROUCH:
if (gamestate == GS_LEVEL && players[player].mo != NULL && if (gamestate == GS_LEVEL && players[player].mo != NULL &&
players[player].health > 0 && !(players[player].oldbuttons & BT_JUMP)) players[player].health > 0 && !(players[player].oldbuttons & BT_JUMP))
@ -2521,6 +2547,10 @@ void Net_SkipCommand (int type, BYTE **stream)
skip = 3 + *(*stream + 2) * 4; skip = 3 + *(*stream + 2) * 4;
break; break;
case DEM_RUNSPECIAL:
skip = 2 + *(*stream + 1) * 4;
break;
case DEM_CONVREPLY: case DEM_CONVREPLY:
skip = 3; skip = 3;
break; break;

View file

@ -137,6 +137,7 @@ public:
int SpawnMask; int SpawnMask;
FNameNoInit MorphWeapon; FNameNoInit MorphWeapon;
fixed_t AttackZOffset; // attack height, relative to player center fixed_t AttackZOffset; // attack height, relative to player center
const PClass *FlechetteType;
// [CW] Fades for when you are being damaged. // [CW] Fades for when you are being damaged.
PalEntry DamageFade; PalEntry DamageFade;

View file

@ -158,6 +158,7 @@ enum EDemoCommand
DEM_CONVREPLY, // 59 Word: Dialogue node, Byte: Reply number DEM_CONVREPLY, // 59 Word: Dialogue node, Byte: Reply number
DEM_CONVCLOSE, // 60 DEM_CONVCLOSE, // 60
DEM_CONVNULL, // 61 DEM_CONVNULL, // 61
DEM_RUNSPECIAL, // 62 Byte: Special number, Byte: Arg count, Ints: Args
}; };
// The following are implemented by cht_DoCheat in m_cheat.cpp // The following are implemented by cht_DoCheat in m_cheat.cpp

View file

@ -455,6 +455,8 @@ CCMD (drop)
} }
} }
const PClass *GetFlechetteType(AActor *other);
CCMD (useflechette) CCMD (useflechette)
{ // Select from one of arti_poisonbag1-3, whichever the player has { // Select from one of arti_poisonbag1-3, whichever the player has
static const ENamedName bagnames[3] = static const ENamedName bagnames[3] =
@ -463,22 +465,26 @@ CCMD (useflechette)
NAME_ArtiPoisonBag2, NAME_ArtiPoisonBag2,
NAME_ArtiPoisonBag3 NAME_ArtiPoisonBag3
}; };
int i, j;
if (who == NULL) if (who == NULL)
return; return;
if (who->IsKindOf (PClass::FindClass (NAME_ClericPlayer))) const PClass *type = GetFlechetteType(who);
i = 0; if (type != NULL)
else if (who->IsKindOf (PClass::FindClass (NAME_MagePlayer)))
i = 1;
else
i = 2;
for (j = 0; j < 3; ++j)
{ {
AInventory *item; AInventory *item;
if ( (item = who->FindInventory (bagnames[(i+j)%3])) ) if ( (item = who->FindInventory (type) ))
{
SendItemUse = item;
return;
}
}
// The default flechette could not be found. Try all 3 types then.
for (int j = 0; j < 3; ++j)
{
AInventory *item;
if ( (item = who->FindInventory (bagnames[j])) )
{ {
SendItemUse = item; SendItemUse = item;
break; break;

View file

@ -141,6 +141,27 @@ bool AArtiPoisonBag3::Use (bool pickup)
return false; return false;
} }
//============================================================================
//
// GetFlechetteType
//
//============================================================================
const PClass *GetFlechetteType(AActor *other)
{
const PClass *spawntype = NULL;
if (other->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
{
spawntype = static_cast<APlayerPawn*>(other)->FlechetteType;
}
if (spawntype == NULL)
{
// default fallback if nothing valid defined.
spawntype = RUNTIME_CLASS(AArtiPoisonBag3);
}
return spawntype;
}
//============================================================================ //============================================================================
// //
// AArtiPoisonBag :: HandlePickup // AArtiPoisonBag :: HandlePickup
@ -155,21 +176,7 @@ bool AArtiPoisonBag::HandlePickup (AInventory *item)
return Super::HandlePickup (item); return Super::HandlePickup (item);
} }
bool matched; if (GetClass() == GetFlechetteType(Owner))
if (Owner->IsKindOf (PClass::FindClass(NAME_ClericPlayer)))
{
matched = (GetClass() == RUNTIME_CLASS(AArtiPoisonBag1));
}
else if (Owner->IsKindOf (PClass::FindClass(NAME_MagePlayer)))
{
matched = (GetClass() == RUNTIME_CLASS(AArtiPoisonBag2));
}
else
{
matched = (GetClass() == RUNTIME_CLASS(AArtiPoisonBag3));
}
if (matched)
{ {
if (Amount < MaxAmount) if (Amount < MaxAmount)
{ {
@ -204,20 +211,8 @@ AInventory *AArtiPoisonBag::CreateCopy (AActor *other)
} }
AInventory *copy; AInventory *copy;
const PClass *spawntype;
if (other->IsKindOf (PClass::FindClass(NAME_ClericPlayer))) const PClass *spawntype = GetFlechetteType(other);
{
spawntype = RUNTIME_CLASS(AArtiPoisonBag1);
}
else if (other->IsKindOf (PClass::FindClass(NAME_MagePlayer)))
{
spawntype = RUNTIME_CLASS(AArtiPoisonBag2);
}
else
{
spawntype = RUNTIME_CLASS(AArtiPoisonBag3);
}
copy = static_cast<AInventory *>(Spawn (spawntype, 0, 0, 0, NO_REPLACE)); copy = static_cast<AInventory *>(Spawn (spawntype, 0, 0, 0, NO_REPLACE));
copy->Amount = Amount; copy->Amount = Amount;
copy->MaxAmount = MaxAmount; copy->MaxAmount = MaxAmount;

View file

@ -36,8 +36,6 @@ static FRandom pr_torch ("Torch");
#define TIMEFREEZE_TICS ( 12 * TICRATE ) #define TIMEFREEZE_TICS ( 12 * TICRATE )
*/ */
EXTERN_CVAR (Bool, r_drawfuzz);
IMPLEMENT_CLASS (APowerup) IMPLEMENT_CLASS (APowerup)
// Powerup-Giver ------------------------------------------------------------- // Powerup-Giver -------------------------------------------------------------

View file

@ -1190,7 +1190,7 @@ public:
} }
if(clearDontDraw) if(clearDontDraw)
screen->Clear(static_cast<int>(MAX<double>(dx, dcx)), static_cast<int>(MAX<double>(dy, dcy)), static_cast<int>(dcr), static_cast<int>(dcb), GPalette.BlackIndex, 0); screen->Clear(static_cast<int>(MAX<double>(dx, dcx)), static_cast<int>(MAX<double>(dy, dcy)), static_cast<int>(MIN<double>(dcr,w+MAX<double>(dx, dcx))), static_cast<int>(MIN<double>(dcb,MAX<double>(dy, dcy)+h)), GPalette.BlackIndex, 0);
else else
{ {
if(alphaMap) if(alphaMap)

View file

@ -2660,6 +2660,58 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
class CommandPlayerType : public SBarInfoCommandFlowControl
{
public:
CommandPlayerType(SBarInfo *script) : SBarInfoCommandFlowControl(script)
{
}
void Parse(FScanner &sc, bool fullScreenOffsets)
{
sc.MustGetToken(TK_Identifier);
do
{
bool foundClass = false;
const PClass *cls = PClass::FindClass(sc.String);
if (cls != NULL)
{
foundClass = true;
classes.Push(cls);
}
/*
if(!foundClass)
sc.ScriptError("Unkown PlayerClass '%s'.", sc.String);
*/
if(!sc.CheckToken(','))
break;
}
while(sc.CheckToken(TK_Identifier));
SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets);
}
void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged)
{
SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged);
if(statusBar->CPlayer->cls == NULL)
return; //No class so we can not continue
for(unsigned int i = 0;i < classes.Size();i++)
{
if (statusBar->CPlayer->cls->IsDescendantOf(classes[i]))
{
SetTruth(true, block, statusBar);
return;
}
}
SetTruth(false, block, statusBar);
}
protected:
TArray<const PClass *> classes;
};
////////////////////////////////////////////////////////////////////////////////
class CommandHasWeaponPiece : public SBarInfoCommandFlowControl class CommandHasWeaponPiece : public SBarInfoCommandFlowControl
{ {
public: public:
@ -3082,7 +3134,7 @@ static const char *SBarInfoCommandNames[] =
"drawmugshot", "drawselectedinventory", "drawmugshot", "drawselectedinventory",
"drawinventorybar", "drawbar", "drawgem", "drawinventorybar", "drawbar", "drawgem",
"drawshader", "drawstring", "drawkeybar", "drawshader", "drawstring", "drawkeybar",
"gamemode", "playerclass", "aspectratio", "gamemode", "playerclass", "playertype", "aspectratio",
"isselected", "usesammo", "usessecondaryammo", "isselected", "usesammo", "usessecondaryammo",
"hasweaponpiece", "inventorybarnotvisible", "hasweaponpiece", "inventorybarnotvisible",
"weaponammo", "ininventory", "alpha", "weaponammo", "ininventory", "alpha",
@ -3095,7 +3147,7 @@ enum SBarInfoCommands
SBARINFO_DRAWMUGSHOT, SBARINFO_DRAWSELECTEDINVENTORY, SBARINFO_DRAWMUGSHOT, SBARINFO_DRAWSELECTEDINVENTORY,
SBARINFO_DRAWINVENTORYBAR, SBARINFO_DRAWBAR, SBARINFO_DRAWGEM, SBARINFO_DRAWINVENTORYBAR, SBARINFO_DRAWBAR, SBARINFO_DRAWGEM,
SBARINFO_DRAWSHADER, SBARINFO_DRAWSTRING, SBARINFO_DRAWKEYBAR, SBARINFO_DRAWSHADER, SBARINFO_DRAWSTRING, SBARINFO_DRAWKEYBAR,
SBARINFO_GAMEMODE, SBARINFO_PLAYERCLASS, SBARINFO_ASPECTRATIO, SBARINFO_GAMEMODE, SBARINFO_PLAYERCLASS, SBARINFO_PLAYERTYPE, SBARINFO_ASPECTRATIO,
SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO, SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO,
SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE, SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE,
SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA, SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA,
@ -3126,6 +3178,7 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
case SBARINFO_ASPECTRATIO: return new CommandAspectRatio(script); case SBARINFO_ASPECTRATIO: return new CommandAspectRatio(script);
case SBARINFO_ISSELECTED: return new CommandIsSelected(script); case SBARINFO_ISSELECTED: return new CommandIsSelected(script);
case SBARINFO_PLAYERCLASS: return new CommandPlayerClass(script); case SBARINFO_PLAYERCLASS: return new CommandPlayerClass(script);
case SBARINFO_PLAYERTYPE: return new CommandPlayerType(script);
case SBARINFO_HASWEAPONPIECE: return new CommandHasWeaponPiece(script); case SBARINFO_HASWEAPONPIECE: return new CommandHasWeaponPiece(script);
case SBARINFO_WEAPONAMMO: return new CommandWeaponAmmo(script); case SBARINFO_WEAPONAMMO: return new CommandWeaponAmmo(script);
case SBARINFO_ININVENTORY: return new CommandInInventory(script); case SBARINFO_ININVENTORY: return new CommandInInventory(script);

View file

@ -47,7 +47,6 @@
#define GI_COMPATPOLY1 0x00000040 // Hexen's MAP36 needs old polyobject drawing #define GI_COMPATPOLY1 0x00000040 // Hexen's MAP36 needs old polyobject drawing
#define GI_COMPATPOLY2 0x00000080 // so does HEXDD's MAP47 #define GI_COMPATPOLY2 0x00000080 // so does HEXDD's MAP47
#define GI_NOTEXTCOLOR 0x00000100 // Chex Quest 3 would have everything green #define GI_NOTEXTCOLOR 0x00000100 // Chex Quest 3 would have everything green
#define GI_COMPATPORTAL 0x00000200 // Urban Brawl relies on the old portal code
#include "gametype.h" #include "gametype.h"

View file

@ -810,7 +810,8 @@ void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int
const char *text, INTBOOL textInLump, INTBOOL finalePic, INTBOOL lookupText, const char *text, INTBOOL textInLump, INTBOOL finalePic, INTBOOL lookupText,
bool ending, FName endsequence) bool ending, FName endsequence)
{ {
if (text != NULL && *text != 0) // Hexen's chess ending doesn't have a text screen, even if the cluster has a message defined.
if (text != NULL && *text != 0 && endsequence != NAME_Inter_Chess)
{ {
FIntermissionActionTextscreen *textscreen = new FIntermissionActionTextscreen; FIntermissionActionTextscreen *textscreen = new FIntermissionActionTextscreen;
if (textInLump) if (textInLump)

View file

@ -141,4 +141,36 @@ inline SDWORD ModDiv (SDWORD num, SDWORD den, SDWORD *dmval)
#define FIXED2FLOAT(f) ((f) / float(65536)) #define FIXED2FLOAT(f) ((f) / float(65536))
#define FIXED2DBL(f) ((f) / double(65536)) #define FIXED2DBL(f) ((f) / double(65536))
class Fixed
{
int v;
public:
Fixed() {}
Fixed(int val) { v = val; }
Fixed(double val) { v = xs_Fix<16>::ToFix(val); }
Fixed &operator = (int val) { v = val; return *this; }
Fixed &operator = (double val) { v = xs_Fix<16>::ToFix(val); return *this; }
Fixed &operator += (Fixed val) { v += val.v; return *this; }
Fixed &operator -= (Fixed val) { v -= val.v; return *this; }
Fixed &operator *= (Fixed val) { v = FixedMul(v, val.v); return *this; }
Fixed &operator /= (Fixed val) { v = FixedDiv(v, val.v); return *this; }
Fixed &operator += (double val) { v += xs_Fix<16>::ToFix(val); return *this; }
Fixed &operator -= (double val) { v -= xs_Fix<16>::ToFix(val); return *this; }
Fixed &operator *= (Fixed val) { v = FixedMul(v, xs_Fix<16>::ToFix(val)); return *this; }
Fixed &operator /= (Fixed val) { v = FixedDiv(v, xs_Fix<16>::ToFix(val)); return *this; }
Fixed operator + (Fixed val) { return v + val.v; }
Fixed operator - (Fixed val) { return v - val.v; }
Fixed operator * (Fixed val) { return FixedMul(v, val.v); }
Fixed operator / (Fixed val) { return FixedDiv(v, val.v); }
Fixed operator + (double val) { return v + xs_Fix<16>::ToFix(val); }
Fixed operator - (double val) { return v - xs_Fix<16>::ToFix(val); }
Fixed operator * (Fixed val) { return FixedMul(v, xs_Fix<16>::ToFix(val)); }
Fixed operator / (Fixed val) { return FixedDiv(v, xs_Fix<16>::ToFix(val)); }
};
#endif #endif

376
src/memarena.cpp Normal file
View file

@ -0,0 +1,376 @@
/*
** memarena.cpp
** Implements memory arenas.
**
**---------------------------------------------------------------------------
** Copyright 2010 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
** A memory arena is used for efficient allocation of many small objects that
** will all be freed at once. Note that since individual destructors are not
** called, you must not use an arena to allocate any objects that use a
** destructor, either explicitly or implicitly (because they have members
** with destructors).
*/
#include "doomtype.h"
#include "m_alloc.h"
#include "memarena.h"
#include "c_dispatch.h"
#include "zstring.h"
#define BLOCK_SIZE (10*1024)
struct FMemArena::Block
{
Block *NextBlock;
void *Limit; // End of this block
void *Avail; // Start of free space in this block
void Reset();
void *Alloc(size_t size);
};
//==========================================================================
//
// RoundPointer
//
// Rounds a pointer up to a pointer-sized boundary.
//
//==========================================================================
static inline void *RoundPointer(void *ptr)
{
return (void *)(((size_t)ptr + sizeof(void*) - 1) & ~(sizeof(void*) - 1));
}
//==========================================================================
//
// FMemArena Constructor
//
//==========================================================================
FMemArena::FMemArena()
{
TopBlock = NULL;
FreeBlocks = NULL;
}
//==========================================================================
//
// FMemArena Destructor
//
//==========================================================================
FMemArena::~FMemArena()
{
FreeAllBlocks();
}
//==========================================================================
//
// FMemArena :: Alloc
//
//==========================================================================
void *FMemArena::Alloc(size_t size)
{
Block *block;
for (block = TopBlock; block != NULL; block = block->NextBlock)
{
void *res = block->Alloc(size);
if (res != NULL)
{
return res;
}
}
block = AddBlock(size);
return block->Alloc(size);
}
//==========================================================================
//
// FMemArena :: FreeAll
//
// Moves all blocks to the free list. No system-level deallocation occurs.
//
//==========================================================================
void FMemArena::FreeAll()
{
for (Block *next, *block = TopBlock; block != NULL; block = next)
{
next = block->NextBlock;
block->Reset();
block->NextBlock = FreeBlocks;
FreeBlocks = block;
}
TopBlock = NULL;
}
//==========================================================================
//
// FMemArena :: FreeAllBlocks
//
// Frees all blocks used by this arena.
//
//==========================================================================
void FMemArena::FreeAllBlocks()
{
FreeBlockChain(TopBlock);
FreeBlockChain(FreeBlocks);
}
//==========================================================================
//
// FMemArena :: FreeBlockChain
//
// Frees a chain of blocks.
//
//==========================================================================
void FMemArena::FreeBlockChain(Block *&top)
{
for (Block *next, *block = top; block != NULL; block = next)
{
next = block->NextBlock;
M_Free(block);
}
top = NULL;
}
//==========================================================================
//
// FMemArena :: AddBlock
//
// Allocates a block large enough to hold at least <size> bytes and adds it
// to the TopBlock chain.
//
//==========================================================================
FMemArena::Block *FMemArena::AddBlock(size_t size)
{
Block *mem, **last;
size += sizeof(Block); // Account for header size
// Search for a free block to use
for (last = &FreeBlocks, mem = FreeBlocks; mem != NULL; last = &mem->NextBlock, mem = mem->NextBlock)
{
if ((BYTE *)mem->Limit - (BYTE *)mem >= (ptrdiff_t)size)
{
*last = mem->NextBlock;
break;
}
}
if (mem == NULL)
{
// Allocate a new block
if (size < BLOCK_SIZE)
{
size = BLOCK_SIZE;
}
else
{ // Stick some free space at the end so we can use this block for
// other things.
size += BLOCK_SIZE/2;
}
mem = (Block *)M_Malloc(size);
mem->Limit = (BYTE *)mem + size;
}
mem->Reset();
mem->NextBlock = TopBlock;
TopBlock = mem;
return mem;
}
//==========================================================================
//
// FMemArena :: Block :: Reset
//
// Resets this block's Avail pointer.
//
//==========================================================================
void FMemArena::Block::Reset()
{
Avail = RoundPointer(this + sizeof(*this));
}
//==========================================================================
//
// FMemArena :: Block :: Alloc
//
// Allocates memory from the block if it has space. Returns NULL if not.
//
//==========================================================================
void *FMemArena::Block::Alloc(size_t size)
{
if ((char *)Avail + size > Limit)
{
return NULL;
}
void *res = Avail;
Avail = RoundPointer((char *)Avail + size);
return res;
}
//==========================================================================
//
// FSharedStringArena Constructor
//
//==========================================================================
FSharedStringArena::FSharedStringArena()
{
memset(Buckets, 0, sizeof(Buckets));
}
//==========================================================================
//
// FSharedStringArena Destructor
//
//==========================================================================
FSharedStringArena::~FSharedStringArena()
{
FreeAll();
// FMemArena destructor will free the blocks.
}
//==========================================================================
//
// FSharedStringArena :: Alloc
//
// Allocates a new string and initializes it with the passed string. This
// version takes an FString as a parameter, so it won't need to allocate any
// memory for the string text if it already exists in the arena.
//
//==========================================================================
FString *FSharedStringArena::Alloc(const FString &source)
{
unsigned int hash;
Node *strnode;
strnode = FindString(source, source.Len(), hash);
if (strnode == NULL)
{
strnode = (Node *)FMemArena::Alloc(sizeof(Node));
::new(&strnode->String) FString(source);
strnode->Hash = hash;
hash %= countof(Buckets);
strnode->Next = Buckets[hash];
Buckets[hash] = strnode;
}
return &strnode->String;
}
//==========================================================================
//
// FSharedStringArena :: Alloc
//
//==========================================================================
FString *FSharedStringArena::Alloc(const char *source)
{
return Alloc(source, strlen(source));
}
//==========================================================================
//
// FSharedStringArena :: Alloc
//
//==========================================================================
FString *FSharedStringArena::Alloc(const char *source, size_t strlen)
{
unsigned int hash;
Node *strnode;
strnode = FindString(source, strlen, hash);
if (strnode == NULL)
{
strnode = (Node *)FMemArena::Alloc(sizeof(Node));
::new(&strnode->String) FString(source, strlen);
strnode->Hash = hash;
hash %= countof(Buckets);
strnode->Next = Buckets[hash];
Buckets[hash] = strnode;
}
return &strnode->String;
}
//==========================================================================
//
// FSharedStringArena :: FindString
//
// Finds the string if it's already in the arena. Returns NULL if not.
//
//==========================================================================
FSharedStringArena::Node *FSharedStringArena::FindString(const char *str, size_t strlen, unsigned int &hash)
{
hash = SuperFastHash(str, strlen);
for (Node *node = Buckets[hash % countof(Buckets)]; node != NULL; node = node->Next)
{
if (node->Hash == hash && node->String.Len() == strlen && memcmp(&node->String[0], str, strlen) == 0)
{
return node;
}
}
return NULL;
}
//==========================================================================
//
// FSharedStringArena :: FreeAll
//
// In addition to moving all used blocks onto the free list, all FStrings
// they contain will have their destructors called.
//
//==========================================================================
void FSharedStringArena::FreeAll()
{
for (Block *next, *block = TopBlock; block != NULL; block = next)
{
next = block->NextBlock;
void *limit = block->Avail;
block->Reset();
for (Node *string = (Node *)block->Avail; string < limit; ++string)
{
string->~Node();
}
block->NextBlock = FreeBlocks;
FreeBlocks = block;
}
memset(Buckets, 0, sizeof(Buckets));
}

83
src/memarena.h Normal file
View file

@ -0,0 +1,83 @@
/*
** memarena.h
**
**---------------------------------------------------------------------------
** Copyright 2010 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "zstring.h"
// A general purpose arena.
class FMemArena
{
public:
FMemArena();
~FMemArena();
void *Alloc(size_t size);
void FreeAll();
void FreeAllBlocks();
protected:
struct Block;
Block *AddBlock(size_t size);
void FreeBlockChain(Block *&top);
Block *TopBlock;
Block *FreeBlocks;
};
// An arena specializing in storage of FStrings. It knows how to free them,
// but this means it also should never be used for allocating anything else.
// Identical strings all return the same pointer.
class FSharedStringArena : public FMemArena
{
public:
FSharedStringArena();
~FSharedStringArena();
void FreeAll();
class FString *Alloc(const FString &source);
class FString *Alloc(const char *source);
class FString *Alloc(const char *source, size_t strlen);
protected:
struct Node
{
Node *Next;
FString String;
unsigned int Hash;
};
Node *Buckets[256];
Node *FindString(const char *str, size_t strlen, unsigned int &hash);
private:
void *Alloc(size_t size) { return NULL; } // No access to FMemArena::Alloc for outsiders.
};

View file

@ -912,7 +912,7 @@ void DPlayerMenu::ClassChanged (FListMenuItem *li)
players[consoleplayer].userinfo.PlayerClass = sel-1; players[consoleplayer].userinfo.PlayerClass = sel-1;
PickPlayerClass(); PickPlayerClass();
cvar_set ("playerclass", sel == 0 ? "Random" : PlayerClass->Type->TypeName); cvar_set ("playerclass", sel == 0 ? "Random" : PlayerClass->Type->Meta.GetMetaString (APMETA_DisplayName));
UpdateSkins(); UpdateSkins();
UpdateColorsets(); UpdateColorsets();

View file

@ -529,6 +529,7 @@ xx(res_9)
xx(AlwaysRun) xx(AlwaysRun)
// end sequences // end sequences
xx(Inter_Chess)
xx(Inter_Strife) xx(Inter_Strife)
xx(Inter_Strife_Good) xx(Inter_Strife_Good)
xx(Inter_Strife_Sad) xx(Inter_Strife_Sad)

View file

@ -2829,6 +2829,9 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value)
case APROP_MasterTID: case APROP_MasterTID:
case APROP_TargetTID: case APROP_TargetTID:
case APROP_TracerTID: case APROP_TracerTID:
case APROP_WaterLevel:
case APROP_ScaleX:
case APROP_ScaleY:
return (GetActorProperty(tid, property) == value); return (GetActorProperty(tid, property) == value);
// Boolean values need to compare to a binary version of value // Boolean values need to compare to a binary version of value

View file

@ -30,9 +30,11 @@
#include "r_state.h" #include "r_state.h"
#include "gi.h" #include "gi.h"
//============================================================================
// //
// CEILINGS // CEILINGS
// //
//============================================================================
IMPLEMENT_CLASS (DCeiling) IMPLEMENT_CLASS (DCeiling)
@ -40,6 +42,12 @@ DCeiling::DCeiling ()
{ {
} }
//============================================================================
//
//
//
//============================================================================
void DCeiling::Serialize (FArchive &arc) void DCeiling::Serialize (FArchive &arc)
{ {
Super::Serialize (arc); Super::Serialize (arc);
@ -59,6 +67,12 @@ void DCeiling::Serialize (FArchive &arc)
<< m_Hexencrush; << m_Hexencrush;
} }
//============================================================================
//
//
//
//============================================================================
void DCeiling::PlayCeilingSound () void DCeiling::PlayCeilingSound ()
{ {
if (m_Sector->seqType >= 0) if (m_Sector->seqType >= 0)
@ -80,9 +94,12 @@ void DCeiling::PlayCeilingSound ()
} }
} }
//============================================================================
// //
// T_MoveCeiling // DCeiling :: Tick
// //
//============================================================================
void DCeiling::Tick () void DCeiling::Tick ()
{ {
EResult res; EResult res;
@ -176,6 +193,12 @@ void DCeiling::Tick ()
} }
} }
//============================================================================
//
//
//
//============================================================================
DCeiling::DCeiling (sector_t *sec) DCeiling::DCeiling (sector_t *sec)
: DMovingCeiling (sec) : DMovingCeiling (sec)
{ {
@ -191,11 +214,258 @@ DCeiling::DCeiling (sector_t *sec, fixed_t speed1, fixed_t speed2, int silent)
m_Silent = silent; m_Silent = silent;
} }
//============================================================================
//
//
//
//============================================================================
DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag,
fixed_t speed, fixed_t speed2, fixed_t height,
int crush, int silent, int change, bool hexencrush)
{
fixed_t targheight = 0; // Silence, GCC
// if ceiling already moving, don't start a second function on it
if (sec->PlaneMoving(sector_t::ceiling))
{
return NULL;
}
// new door thinker
DCeiling *ceiling = new DCeiling (sec, speed, speed2, silent);
vertex_t *spot = sec->lines[0]->v1;
switch (type)
{
case ceilCrushAndRaise:
case ceilCrushRaiseAndStay:
ceiling->m_TopHeight = sec->ceilingplane.d;
case ceilLowerAndCrush:
case ceilLowerAndCrushDist:
targheight = sec->FindHighestFloorPoint (&spot);
if (type == ceilLowerAndCrush)
{
targheight += 8*FRACUNIT;
}
else if (type == ceilLowerAndCrushDist)
{
targheight += height;
}
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case ceilRaiseToHighest:
targheight = sec->FindHighestCeilingSurrounding (&spot);
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case ceilLowerByValue:
targheight = sec->ceilingplane.ZatPoint (spot) - height;
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case ceilRaiseByValue:
targheight = sec->ceilingplane.ZatPoint (spot) + height;
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case ceilMoveToValue:
{
int diff = height - sec->ceilingplane.ZatPoint (spot);
targheight = height;
if (diff < 0)
{
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, height);
ceiling->m_Direction = -1;
}
else
{
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, height);
ceiling->m_Direction = 1;
}
}
break;
case ceilLowerToHighestFloor:
targheight = sec->FindHighestFloorSurrounding (&spot);
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case ceilRaiseToHighestFloor:
targheight = sec->FindHighestFloorSurrounding (&spot);
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case ceilLowerInstant:
targheight = sec->ceilingplane.ZatPoint (spot) - height;
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
ceiling->m_Speed = height;
break;
case ceilRaiseInstant:
targheight = sec->ceilingplane.ZatPoint (spot) + height;
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
ceiling->m_Speed = height;
break;
case ceilLowerToNearest:
targheight = sec->FindNextLowestCeiling (&spot);
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case ceilRaiseToNearest:
targheight = sec->FindNextHighestCeiling (&spot);
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case ceilLowerToLowest:
targheight = sec->FindLowestCeilingSurrounding (&spot);
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case ceilRaiseToLowest:
targheight = sec->FindLowestCeilingSurrounding (&spot);
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case ceilLowerToFloor:
targheight = sec->FindHighestFloorPoint (&spot);
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case ceilRaiseToFloor: // [RH] What's this for?
targheight = sec->FindHighestFloorPoint (&spot);
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case ceilLowerToHighest:
targheight = sec->FindHighestCeilingSurrounding (&spot);
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case ceilLowerByTexture:
targheight = sec->ceilingplane.ZatPoint (spot) - sec->FindShortestUpperAround ();
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case ceilRaiseByTexture:
targheight = sec->ceilingplane.ZatPoint (spot) + sec->FindShortestUpperAround ();
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
default:
break; // Silence GCC
}
ceiling->m_Tag = tag;
ceiling->m_Type = type;
ceiling->m_Crush = crush;
ceiling->m_Hexencrush = hexencrush;
// Do not interpolate instant movement ceilings.
// Note for ZDoomGL: Check to make sure that you update the sector
// after the ceiling moves, because it hasn't actually moved yet.
fixed_t movedist;
if (ceiling->m_Direction < 0)
{
movedist = sec->ceilingplane.d - ceiling->m_BottomHeight;
}
else
{
movedist = ceiling->m_TopHeight - sec->ceilingplane.d;
}
if (ceiling->m_Speed >= movedist)
{
ceiling->StopInterpolation();
}
// set texture/type change properties
if (change & 3) // if a texture change is indicated
{
if (change & 4) // if a numeric model change
{
sector_t *modelsec;
//jff 5/23/98 find model with floor at target height if target
//is a floor type
modelsec = (/*type == ceilRaiseToHighest ||*/
type == ceilRaiseToFloor ||
/*type == ceilLowerToHighest ||*/
type == ceilLowerToFloor) ?
sec->FindModelFloorSector (targheight) :
sec->FindModelCeilingSector (targheight);
if (modelsec != NULL)
{
ceiling->m_Texture = modelsec->GetTexture(sector_t::ceiling);
switch (change & 3)
{
case 1: // type is zeroed
ceiling->m_NewSpecial = 0;
ceiling->m_Type = genCeilingChg0;
break;
case 2: // type is copied
ceiling->m_NewSpecial = sec->special;
ceiling->m_Type = genCeilingChgT;
break;
case 3: // type is left alone
ceiling->m_Type = genCeilingChg;
break;
}
}
}
else if (line) // else if a trigger model change
{
ceiling->m_Texture = line->frontsector->GetTexture(sector_t::ceiling);
switch (change & 3)
{
case 1: // type is zeroed
ceiling->m_NewSpecial = 0;
ceiling->m_Type = genCeilingChg0;
break;
case 2: // type is copied
ceiling->m_NewSpecial = line->frontsector->special;
ceiling->m_Type = genCeilingChgT;
break;
case 3: // type is left alone
ceiling->m_Type = genCeilingChg;
break;
}
}
}
ceiling->PlayCeilingSound ();
return ceiling;
}
//============================================================================
// //
// EV_DoCeiling // EV_DoCeiling
// Move a ceiling up/down and all around! // Move a ceiling up/down and all around!
// //
// [RH] Added tag, speed, speed2, height, crush, silent, change params // [RH] Added tag, speed, speed2, height, crush, silent, change params
//
//============================================================================
bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line, bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line,
int tag, fixed_t speed, fixed_t speed2, fixed_t height, int tag, fixed_t speed, fixed_t speed2, fixed_t height,
int crush, int silent, int change, bool hexencrush) int crush, int silent, int change, bool hexencrush)
@ -203,10 +473,6 @@ bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line,
int secnum; int secnum;
bool rtn; bool rtn;
sector_t* sec; sector_t* sec;
DCeiling* ceiling;
bool manual = false;
fixed_t targheight = 0; // Silence, GCC
vertex_t* spot;
rtn = false; rtn = false;
@ -216,11 +482,10 @@ bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line,
if (!line || !(sec = line->backsector)) if (!line || !(sec = line->backsector))
return rtn; return rtn;
secnum = (int)(sec-sectors); secnum = (int)(sec-sectors);
manual = true;
// [RH] Hack to let manual crushers be retriggerable, too // [RH] Hack to let manual crushers be retriggerable, too
tag ^= secnum | 0x1000000; tag ^= secnum | 0x1000000;
P_ActivateInStasisCeiling (tag); P_ActivateInStasisCeiling (tag);
goto manual_ceiling; return !!DCeiling::Create(sec, type, line, tag, speed, speed2, height, crush, silent, change, hexencrush);
} }
// Reactivate in-stasis ceilings...for certain types. // Reactivate in-stasis ceilings...for certain types.
@ -234,252 +499,19 @@ bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line,
// affects all sectors with the same tag as the linedef // affects all sectors with the same tag as the linedef
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
{ {
sec = &sectors[secnum]; rtn |= !!DCeiling::Create(&sectors[secnum], type, line, tag, speed, speed2, height, crush, silent, change, hexencrush);
manual_ceiling:
// if ceiling already moving, don't start a second function on it
if (sec->PlaneMoving(sector_t::ceiling))
{
if (!manual)
continue;
else
return false;
}
// new door thinker
rtn = 1;
ceiling = new DCeiling (sec, speed, speed2, silent);
spot = sec->lines[0]->v1;
switch (type)
{
case DCeiling::ceilCrushAndRaise:
case DCeiling::ceilCrushRaiseAndStay:
ceiling->m_TopHeight = sec->ceilingplane.d;
case DCeiling::ceilLowerAndCrush:
case DCeiling::ceilLowerAndCrushDist:
targheight = sec->FindHighestFloorPoint (&spot);
if (type == DCeiling::ceilLowerAndCrush)
{
targheight += 8*FRACUNIT;
}
else if (type == DCeiling::ceilLowerAndCrushDist)
{
targheight += height;
}
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case DCeiling::ceilRaiseToHighest:
targheight = sec->FindHighestCeilingSurrounding (&spot);
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case DCeiling::ceilLowerByValue:
targheight = sec->ceilingplane.ZatPoint (spot) - height;
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case DCeiling::ceilRaiseByValue:
targheight = sec->ceilingplane.ZatPoint (spot) + height;
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case DCeiling::ceilMoveToValue:
{
int diff = height - sec->ceilingplane.ZatPoint (spot);
targheight = height;
if (diff < 0)
{
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, height);
ceiling->m_Direction = -1;
}
else
{
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, height);
ceiling->m_Direction = 1;
}
}
break;
case DCeiling::ceilLowerToHighestFloor:
targheight = sec->FindHighestFloorSurrounding (&spot);
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case DCeiling::ceilRaiseToHighestFloor:
targheight = sec->FindHighestFloorSurrounding (&spot);
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case DCeiling::ceilLowerInstant:
targheight = sec->ceilingplane.ZatPoint (spot) - height;
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
ceiling->m_Speed = height;
break;
case DCeiling::ceilRaiseInstant:
targheight = sec->ceilingplane.ZatPoint (spot) + height;
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
ceiling->m_Speed = height;
break;
case DCeiling::ceilLowerToNearest:
targheight = sec->FindNextLowestCeiling (&spot);
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case DCeiling::ceilRaiseToNearest:
targheight = sec->FindNextHighestCeiling (&spot);
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case DCeiling::ceilLowerToLowest:
targheight = sec->FindLowestCeilingSurrounding (&spot);
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case DCeiling::ceilRaiseToLowest:
targheight = sec->FindLowestCeilingSurrounding (&spot);
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case DCeiling::ceilLowerToFloor:
targheight = sec->FindHighestFloorPoint (&spot);
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case DCeiling::ceilRaiseToFloor: // [RH] What's this for?
targheight = sec->FindHighestFloorPoint (&spot);
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
case DCeiling::ceilLowerToHighest:
targheight = sec->FindHighestCeilingSurrounding (&spot);
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case DCeiling::ceilLowerByTexture:
targheight = sec->ceilingplane.ZatPoint (spot) - sec->FindShortestUpperAround ();
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case DCeiling::ceilRaiseByTexture:
targheight = sec->ceilingplane.ZatPoint (spot) + sec->FindShortestUpperAround ();
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
default:
break; // Silence GCC
}
ceiling->m_Tag = tag;
ceiling->m_Type = type;
ceiling->m_Crush = crush;
ceiling->m_Hexencrush = hexencrush;
// Do not interpolate instant movement ceilings.
// Note for ZDoomGL: Check to make sure that you update the sector
// after the ceiling moves, because it hasn't actually moved yet.
fixed_t movedist;
if (ceiling->m_Direction < 0)
{
movedist = sec->ceilingplane.d - ceiling->m_BottomHeight;
}
else
{
movedist = ceiling->m_TopHeight - sec->ceilingplane.d;
}
if (ceiling->m_Speed >= movedist)
{
ceiling->StopInterpolation();
}
// set texture/type change properties
if (change & 3) // if a texture change is indicated
{
if (change & 4) // if a numeric model change
{
sector_t *modelsec;
//jff 5/23/98 find model with floor at target height if target
//is a floor type
modelsec = (/*type == DCeiling::ceilRaiseToHighest ||*/
type == DCeiling::ceilRaiseToFloor ||
/*type == DCeiling::ceilLowerToHighest ||*/
type == DCeiling::ceilLowerToFloor) ?
sec->FindModelFloorSector (targheight) :
sec->FindModelCeilingSector (targheight);
if (modelsec != NULL)
{
ceiling->m_Texture = modelsec->GetTexture(sector_t::ceiling);
switch (change & 3)
{
case 1: // type is zeroed
ceiling->m_NewSpecial = 0;
ceiling->m_Type = DCeiling::genCeilingChg0;
break;
case 2: // type is copied
ceiling->m_NewSpecial = sec->special;
ceiling->m_Type = DCeiling::genCeilingChgT;
break;
case 3: // type is left alone
ceiling->m_Type = DCeiling::genCeilingChg;
break;
}
}
}
else if (line) // else if a trigger model change
{
ceiling->m_Texture = line->frontsector->GetTexture(sector_t::ceiling);
switch (change & 3)
{
case 1: // type is zeroed
ceiling->m_NewSpecial = 0;
ceiling->m_Type = DCeiling::genCeilingChg0;
break;
case 2: // type is copied
ceiling->m_NewSpecial = line->frontsector->special;
ceiling->m_Type = DCeiling::genCeilingChgT;
break;
case 3: // type is left alone
ceiling->m_Type = DCeiling::genCeilingChg;
break;
}
}
}
ceiling->PlayCeilingSound ();
if (manual)
return rtn;
} }
return rtn; return rtn;
} }
//============================================================================
// //
// Restart a ceiling that's in-stasis // Restart a ceiling that's in-stasis
// [RH] Passed a tag instead of a line and rewritten to use a list // [RH] Passed a tag instead of a line and rewritten to use a list
// //
//============================================================================
void P_ActivateInStasisCeiling (int tag) void P_ActivateInStasisCeiling (int tag)
{ {
DCeiling *scan; DCeiling *scan;
@ -495,11 +527,14 @@ void P_ActivateInStasisCeiling (int tag)
} }
} }
//============================================================================
// //
// EV_CeilingCrushStop // EV_CeilingCrushStop
// Stop a ceiling from crushing! // Stop a ceiling from crushing!
// [RH] Passed a tag instead of a line and rewritten to use a list // [RH] Passed a tag instead of a line and rewritten to use a list
// //
//============================================================================
bool EV_CeilingCrushStop (int tag) bool EV_CeilingCrushStop (int tag)
{ {
bool rtn = false; bool rtn = false;

View file

@ -36,6 +36,12 @@
#include "sc_man.h" #include "sc_man.h"
#include "cmdlib.h" #include "cmdlib.h"
//============================================================================
//
// VERTICAL DOORS
//
//============================================================================
IMPLEMENT_CLASS (DDoor) IMPLEMENT_CLASS (DDoor)
DDoor::DDoor () DDoor::DDoor ()
@ -55,14 +61,12 @@ void DDoor::Serialize (FArchive &arc)
<< m_LightTag; << m_LightTag;
} }
//============================================================================
//
// VERTICAL DOORS
//
// //
// T_VerticalDoor // T_VerticalDoor
// //
//============================================================================
void DDoor::Tick () void DDoor::Tick ()
{ {
EResult res; EResult res;
@ -215,7 +219,12 @@ void DDoor::Tick ()
} }
} }
//============================================================================
//
// [RH] DoorSound: Plays door sound depending on direction and speed // [RH] DoorSound: Plays door sound depending on direction and speed
//
//============================================================================
void DDoor::DoorSound (bool raise) const void DDoor::DoorSound (bool raise) const
{ {
int choice; int choice;
@ -309,10 +318,12 @@ DDoor::DDoor (sector_t *sector)
{ {
} }
// [RH] Merged EV_VerticalDoor and EV_DoLockedDoor into EV_DoDoor //============================================================================
// and made them more general to support the new specials. //
// [RH] SpawnDoor: Helper function for EV_DoDoor // [RH] SpawnDoor: Helper function for EV_DoDoor
//
//============================================================================
DDoor::DDoor (sector_t *sec, EVlDoor type, fixed_t speed, int delay, int lightTag) DDoor::DDoor (sector_t *sec, EVlDoor type, fixed_t speed, int delay, int lightTag)
: DMovingCeiling (sec), : DMovingCeiling (sec),
m_Type (type), m_Speed (speed), m_TopWait (delay), m_LightTag (lightTag) m_Type (type), m_Speed (speed), m_TopWait (delay), m_LightTag (lightTag)
@ -371,6 +382,13 @@ DDoor::DDoor (sector_t *sec, EVlDoor type, fixed_t speed, int delay, int lightTa
m_OldFloorDist = sec->floorplane.d; m_OldFloorDist = sec->floorplane.d;
} }
//============================================================================
//
// [RH] Merged EV_VerticalDoor and EV_DoLockedDoor into EV_DoDoor
// and made them more general to support the new specials.
//
//============================================================================
bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing, bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing,
int tag, int speed, int delay, int lock, int lightTag) int tag, int speed, int delay, int lock, int lightTag)
{ {
@ -464,10 +482,12 @@ bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing,
return rtn; return rtn;
} }
//============================================================================
// //
// Spawn a door that closes after 30 seconds // Spawn a door that closes after 30 seconds
// //
//============================================================================
void P_SpawnDoorCloseIn30 (sector_t *sec) void P_SpawnDoorCloseIn30 (sector_t *sec)
{ {
fixed_t height; fixed_t height;
@ -487,18 +507,56 @@ void P_SpawnDoorCloseIn30 (sector_t *sec)
door->m_LightTag = 0; door->m_LightTag = 0;
} }
//============================================================================
// //
// Spawn a door that opens after 5 minutes // Spawn a door that opens after 5 minutes
// //
//============================================================================
void P_SpawnDoorRaiseIn5Mins (sector_t *sec) void P_SpawnDoorRaiseIn5Mins (sector_t *sec)
{ {
sec->special = 0; sec->special = 0;
new DDoor (sec, DDoor::doorRaiseIn5Mins, 2*FRACUNIT, TICRATE*30/7, 0); new DDoor (sec, DDoor::doorRaiseIn5Mins, 2*FRACUNIT, TICRATE*30/7, 0);
} }
// EV_SlidingDoor : slide a door horizontally
// (animate midtexture, then set noblocking line) //============================================================================
// //
// animated doors
//
//============================================================================
IMPLEMENT_CLASS (DAnimatedDoor)
DAnimatedDoor::DAnimatedDoor ()
{
}
DAnimatedDoor::DAnimatedDoor (sector_t *sec)
: DMovingCeiling (sec)
{
}
void DAnimatedDoor::Serialize (FArchive &arc)
{
Super::Serialize (arc);
arc << m_Line1 << m_Line2
<< m_Frame
<< m_Timer
<< m_BotDist
<< m_Status
<< m_Speed
<< m_Delay
<< m_DoorAnim
<< m_SetBlocking1 << m_SetBlocking2;
}
//============================================================================
//
// Starts a closing action on an animated door
//
//============================================================================
bool DAnimatedDoor::StartClosing () bool DAnimatedDoor::StartClosing ()
{ {
@ -528,6 +586,12 @@ bool DAnimatedDoor::StartClosing ()
return true; return true;
} }
//============================================================================
//
//
//
//============================================================================
void DAnimatedDoor::Tick () void DAnimatedDoor::Tick ()
{ {
if (m_DoorAnim == NULL) if (m_DoorAnim == NULL)
@ -624,31 +688,11 @@ void DAnimatedDoor::Tick ()
} }
} }
IMPLEMENT_CLASS (DAnimatedDoor) //============================================================================
//
DAnimatedDoor::DAnimatedDoor () //
{ //
} //============================================================================
DAnimatedDoor::DAnimatedDoor (sector_t *sec)
: DMovingCeiling (sec)
{
}
void DAnimatedDoor::Serialize (FArchive &arc)
{
Super::Serialize (arc);
arc << m_Line1 << m_Line2
<< m_Frame
<< m_Timer
<< m_BotDist
<< m_Status
<< m_Speed
<< m_Delay
<< m_DoorAnim
<< m_SetBlocking1 << m_SetBlocking2;
}
DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim) DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim)
: DMovingCeiling (sec) : DMovingCeiling (sec)
@ -706,7 +750,8 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay,
//============================================================================ //============================================================================
// //
// EV_SlidingDoor // EV_SlidingDoor : slide a door horizontally
// (animate midtexture, then set noblocking line)
// //
//============================================================================ //============================================================================

View file

@ -1223,6 +1223,7 @@ static void CreateCachedNodes(MapData *map)
FILE *f = fopen(path, "wb"); FILE *f = fopen(path, "wb");
fwrite(compressed, 1, outlen+offset, f); fwrite(compressed, 1, outlen+offset, f);
fclose(f); fclose(f);
delete [] compressed;
} }

View file

@ -81,7 +81,6 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj);
extern cycle_t BotSupportCycles; extern cycle_t BotSupportCycles;
extern int BotWTG; extern int BotWTG;
EXTERN_CVAR (Bool, r_drawfuzz);
EXTERN_CVAR (Int, cl_rockettrails) EXTERN_CVAR (Int, cl_rockettrails)
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------

View file

@ -2519,10 +2519,10 @@ void P_LoadSideDefs2 (MapData * map)
// as possible from its ZDBSP incarnation. // as possible from its ZDBSP incarnation.
// //
static unsigned int BlockHash (TArray<WORD> *block) static unsigned int BlockHash (TArray<int> *block)
{ {
int hash = 0; int hash = 0;
WORD *ar = &(*block)[0]; int *ar = &(*block)[0];
for (size_t i = 0; i < block->Size(); ++i) for (size_t i = 0; i < block->Size(); ++i)
{ {
hash = hash * 12235 + ar[i]; hash = hash * 12235 + ar[i];
@ -2530,7 +2530,7 @@ static unsigned int BlockHash (TArray<WORD> *block)
return hash & 0x7fffffff; return hash & 0x7fffffff;
} }
static bool BlockCompare (TArray<WORD> *block1, TArray<WORD> *block2) static bool BlockCompare (TArray<int> *block1, TArray<int> *block2)
{ {
size_t size = block1->Size(); size_t size = block1->Size();
@ -2542,8 +2542,8 @@ static bool BlockCompare (TArray<WORD> *block1, TArray<WORD> *block2)
{ {
return true; return true;
} }
WORD *ar1 = &(*block1)[0]; int *ar1 = &(*block1)[0];
WORD *ar2 = &(*block2)[0]; int *ar2 = &(*block2)[0];
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i)
{ {
if (ar1[i] != ar2[i]) if (ar1[i] != ar2[i])
@ -2554,20 +2554,20 @@ static bool BlockCompare (TArray<WORD> *block1, TArray<WORD> *block2)
return true; return true;
} }
static void CreatePackedBlockmap (TArray<int> &BlockMap, TArray<WORD> *blocks, int bmapwidth, int bmapheight) static void CreatePackedBlockmap (TArray<int> &BlockMap, TArray<int> *blocks, int bmapwidth, int bmapheight)
{ {
int buckets[4096]; int buckets[4096];
int *hashes, hashblock; int *hashes, hashblock;
TArray<WORD> *block; TArray<int> *block;
int zero = 0; int zero = 0;
int terminator = -1; int terminator = -1;
WORD *array; int *array;
int i, hash; int i, hash;
int hashed = 0, nothashed = 0; int hashed = 0, nothashed = 0;
hashes = new int[bmapwidth * bmapheight]; hashes = new int[bmapwidth * bmapheight];
memset (hashes, 0xff, sizeof(WORD)*bmapwidth*bmapheight); memset (hashes, 0xff, sizeof(int)*bmapwidth*bmapheight);
memset (buckets, 0xff, sizeof(buckets)); memset (buckets, 0xff, sizeof(buckets));
for (i = 0; i < bmapwidth * bmapheight; ++i) for (i = 0; i < bmapwidth * bmapheight; ++i)
@ -2614,12 +2614,12 @@ static void CreatePackedBlockmap (TArray<int> &BlockMap, TArray<WORD> *blocks, i
static void P_CreateBlockMap () static void P_CreateBlockMap ()
{ {
TArray<WORD> *BlockLists, *block, *endblock; TArray<int> *BlockLists, *block, *endblock;
WORD adder; int adder;
int bmapwidth, bmapheight; int bmapwidth, bmapheight;
int minx, maxx, miny, maxy; int minx, maxx, miny, maxy;
int i; int i;
WORD line; int line;
if (numvertexes <= 0) if (numvertexes <= 0)
return; return;
@ -2651,7 +2651,7 @@ static void P_CreateBlockMap ()
adder = bmapwidth; BlockMap.Push (adder); adder = bmapwidth; BlockMap.Push (adder);
adder = bmapheight; BlockMap.Push (adder); adder = bmapheight; BlockMap.Push (adder);
BlockLists = new TArray<WORD>[bmapwidth * bmapheight]; BlockLists = new TArray<int>[bmapwidth * bmapheight];
for (line = 0; line < numlines; ++line) for (line = 0; line < numlines; ++line)
{ {

View file

@ -921,39 +921,6 @@ static bool SpreadCeilingPortal(AStackPoint *pt, fixed_t alpha, sector_t *sector
return fail; return fail;
} }
static bool SpreadFloorPortal(AStackPoint *pt, fixed_t alpha, sector_t *sector)
{
bool fail = false;
sector->validcount = validcount;
for(int i=0; i<sector->linecount; i++)
{
line_t *line = sector->lines[i];
sector_t *backsector = sector == line->frontsector? line->backsector : line->frontsector;
if (line->backsector == line->frontsector) continue;
if (backsector == NULL) { fail = true; continue; }
if (backsector->validcount == validcount) continue;
if (backsector->FloorSkyBox == pt) continue;
// Check if the backside would map to the same visplane
if (backsector->FloorSkyBox != NULL) { fail = true; continue; }
if (backsector->floorplane != sector->ceilingplane) { fail = true; continue; }
if (backsector->lightlevel != sector->lightlevel) { fail = true; continue; }
if (backsector->GetTexture(sector_t::floor) != sector->GetTexture(sector_t::floor)) { fail = true; continue; }
if (backsector->GetXOffset(sector_t::floor) != sector->GetXOffset(sector_t::floor)) { fail = true; continue; }
if (backsector->GetYOffset(sector_t::floor) != sector->GetYOffset(sector_t::floor)) { fail = true; continue; }
if (backsector->GetXScale(sector_t::floor) != sector->GetXScale(sector_t::floor)) { fail = true; continue; }
if (backsector->GetYScale(sector_t::floor) != sector->GetYScale(sector_t::floor)) { fail = true; continue; }
if (backsector->GetAngle(sector_t::floor) != sector->GetAngle(sector_t::floor)) { fail = true; continue; }
if (SpreadFloorPortal(pt, alpha, backsector)) { fail = true; continue; }
}
if (!fail)
{
sector->FloorSkyBox = pt;
sector->SetAlpha(sector_t::floor, alpha);
}
return fail;
}
void P_SetupPortals() void P_SetupPortals()
{ {
TThinkerIterator<AStackPoint> it; TThinkerIterator<AStackPoint> it;
@ -974,51 +941,6 @@ void P_SetupPortals()
pt->special1 = 0; pt->special1 = 0;
points.Push(pt); points.Push(pt);
} }
// Maps using undefined portal hacks may not benefit from portal optimizations.
if (ib_compatflags & BCOMPATF_BADPORTALS) return;
for(unsigned i=0;i<points.Size(); i++)
{
if (points[i]->special1 == 0 && points[i]->Mate != NULL)
{
for(unsigned j=1;j<points.Size(); j++)
{
if (points[j]->special1 == 0 && points[j]->Mate != NULL && points[i]->GetClass() == points[j]->GetClass())
{
fixed_t deltax1 = points[i]->Mate->x - points[i]->x;
fixed_t deltay1 = points[i]->Mate->y - points[i]->y;
fixed_t deltax2 = points[j]->Mate->x - points[j]->x;
fixed_t deltay2 = points[j]->Mate->y - points[j]->y;
if (deltax1 == deltax2 && deltay1 == deltay2)
{
if (points[j]->Sector->FloorSkyBox == points[j]->Mate)
points[j]->Sector->FloorSkyBox = points[i]->Mate;
if (points[j]->Sector->CeilingSkyBox == points[j]->Mate)
points[j]->Sector->CeilingSkyBox = points[i]->Mate;
points[j]->special1 = 1;
}
}
}
}
}
validcount++;
// Some fudging to preserve an unintended 'portal bleeding' effect caused by incomplete checks in the rendering code.
// Due to the addition of linedef-based portals this effect no longer works.
for(int i=0;i<numsectors; i++)
{
if (sectors[i].CeilingSkyBox != NULL && sectors[i].CeilingSkyBox->bAlways && sectors[i].validcount != validcount)
{
SpreadCeilingPortal(barrier_cast<AStackPoint*>(sectors[i].CeilingSkyBox), sectors[i].GetAlpha(sector_t::ceiling), &sectors[i]);
}
if (sectors[i].FloorSkyBox != NULL && sectors[i].FloorSkyBox->bAlways && sectors[i].validcount != validcount)
{
SpreadFloorPortal(barrier_cast<AStackPoint*>(sectors[i].FloorSkyBox), sectors[i].GetAlpha(sector_t::floor), &sectors[i]);
}
}
} }
inline void SetPortal(sector_t *sector, int plane, AStackPoint *portal, fixed_t alpha) inline void SetPortal(sector_t *sector, int plane, AStackPoint *portal, fixed_t alpha)

View file

@ -677,6 +677,10 @@ public:
void Serialize (FArchive &arc); void Serialize (FArchive &arc);
void Tick (); void Tick ();
static DCeiling *Create(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag,
fixed_t speed, fixed_t speed2, fixed_t height,
int crush, int silent, int change, bool hexencrush);
protected: protected:
ECeiling m_Type; ECeiling m_Type;
fixed_t m_BottomHeight; fixed_t m_BottomHeight;
@ -702,9 +706,6 @@ protected:
private: private:
DCeiling (); DCeiling ();
friend bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line,
int tag, fixed_t speed, fixed_t speed2, fixed_t height,
int crush, int silent, int change, bool hexencrush);
friend bool EV_CeilingCrushStop (int tag); friend bool EV_CeilingCrushStop (int tag);
friend void P_ActivateInStasisCeiling (int tag); friend void P_ActivateInStasisCeiling (int tag);
}; };

View file

@ -432,7 +432,8 @@ void APlayerPawn::Serialize (FArchive &arc)
<< InvSel << InvSel
<< MorphWeapon << MorphWeapon
<< DamageFade << DamageFade
<< PlayerFlags; << PlayerFlags
<< FlechetteType;
} }
//=========================================================================== //===========================================================================

View file

@ -48,6 +48,7 @@ enum ERenderStyle
STYLE_Add, // Draw additive STYLE_Add, // Draw additive
STYLE_Shaded, // Treat patch data as alpha values for alphacolor STYLE_Shaded, // Treat patch data as alpha values for alphacolor
STYLE_TranslucentStencil, STYLE_TranslucentStencil,
STYLE_Shadow,
STYLE_Count STYLE_Count
}; };
@ -63,6 +64,9 @@ enum ERenderOp
STYLEOP_FuzzOrAdd, // Draw fuzzy or add, based on user preference STYLEOP_FuzzOrAdd, // Draw fuzzy or add, based on user preference
STYLEOP_FuzzOrSub, // Draw fuzzy or subtract, based on user preference STYLEOP_FuzzOrSub, // Draw fuzzy or subtract, based on user preference
STYLEOP_FuzzOrRevSub, // Draw fuzzy or reverse subtract, based on user preference STYLEOP_FuzzOrRevSub, // Draw fuzzy or reverse subtract, based on user preference
// special styles
STYLEOP_Shadow,
}; };
enum ERenderAlpha enum ERenderAlpha

View file

@ -355,6 +355,304 @@ const BYTE *R_GetColumn (FTexture *tex, int col)
return tex->GetColumn (col, NULL); return tex->GetColumn (col, NULL);
} }
//==========================================================================
//
// GetVoxelRemap
//
// Calculates a remap table for the voxel's palette. Results are cached so
// passing the same palette repeatedly will not require repeated
// recalculations.
//
//==========================================================================
static BYTE *GetVoxelRemap(const BYTE *pal)
{
static BYTE remap[256];
static BYTE oldpal[768];
static bool firsttime = true;
if (firsttime || memcmp(oldpal, pal, 768) != 0)
{ // Not the same palette as last time, so recalculate.
firsttime = false;
memcpy(oldpal, pal, 768);
for (int i = 0; i < 256; ++i)
{
// The voxel palette uses VGA colors, so we have to expand it
// from 6 to 8 bits per component.
remap[i] = BestColor((uint32 *)GPalette.BaseColors,
(oldpal[i*3 + 0] << 2) | (oldpal[i*3 + 0] >> 4),
(oldpal[i*3 + 1] << 2) | (oldpal[i*3 + 1] >> 4),
(oldpal[i*3 + 2] << 2) | (oldpal[i*3 + 2] >> 4));
}
}
return remap;
}
//==========================================================================
//
// CopyVoxelSlabs
//
// Copy all the slabs in a block of slabs.
//
//==========================================================================
static bool CopyVoxelSlabs(kvxslab_t *dest, const kvxslab_t *src, int size)
{
while (size >= 3)
{
int slabzleng = src->zleng;
if (3 + slabzleng > size)
{ // slab is too tall
return false;
}
dest->ztop = src->ztop;
dest->zleng = src->zleng;
dest->backfacecull = src->backfacecull;
for (int j = 0; j < slabzleng; ++j)
{
dest->col[j] = src->col[j];
}
slabzleng += 3;
src = (kvxslab_t *)((BYTE *)src + slabzleng);
dest = (kvxslab_t *)((BYTE *)dest + slabzleng);
size -= slabzleng;
}
return true;
}
//==========================================================================
//
// RemapVoxelSlabs
//
// Remaps all the slabs in a block of slabs.
//
//==========================================================================
static void RemapVoxelSlabs(kvxslab_t *dest, int size, const BYTE *remap)
{
while (size >= 3)
{
int slabzleng = dest->zleng;
for (int j = 0; j < slabzleng; ++j)
{
dest->col[j] = remap[dest->col[j]];
}
slabzleng += 3;
dest = (kvxslab_t *)((BYTE *)dest + slabzleng);
size -= slabzleng;
}
}
//==========================================================================
//
// R_LoadKVX
//
//==========================================================================
FVoxel *R_LoadKVX(int lumpnum)
{
const kvxslab_t *slabs[MAXVOXMIPS];
FVoxel *voxel = new FVoxel;
const BYTE *rawmip;
int mip, maxmipsize;
int i, j, n;
FMemLump lump = Wads.ReadLump(lumpnum); // FMemLump adds an extra 0 byte to the end.
BYTE *rawvoxel = (BYTE *)lump.GetMem();
int voxelsize = (int)(lump.GetSize()-1);
// Oh, KVX, why couldn't you have a proper header? We'll just go through
// and collect each MIP level, doing lots of range checking, and if the
// last one doesn't end exactly 768 bytes before the end of the file,
// we'll reject it.
for (mip = 0, rawmip = rawvoxel, maxmipsize = voxelsize - 768 - 4;
mip < MAXVOXMIPS;
mip++)
{
int numbytes = GetInt(rawmip);
if (numbytes > maxmipsize || numbytes < 24)
{
break;
}
rawmip += 4;
FVoxelMipLevel *mipl = &voxel->Mips[mip];
// Load header data.
mipl->SizeX = GetInt(rawmip + 0);
mipl->SizeY = GetInt(rawmip + 4);
mipl->SizeZ = GetInt(rawmip + 8);
mipl->PivotX = GetInt(rawmip + 12);
mipl->PivotY = GetInt(rawmip + 16);
mipl->PivotZ = GetInt(rawmip + 20);
// How much space do we have for voxdata?
int offsetsize = (mipl->SizeX + 1) * 4 + mipl->SizeX * (mipl->SizeY + 1) * 2;
int voxdatasize = numbytes - 24 - offsetsize;
if (voxdatasize < 0)
{ // Clearly, not enough.
break;
}
if (voxdatasize == 0)
{ // This mip level is empty.
goto nextmip;
}
// Allocate slab data space.
mipl->OffsetX = new int[(numbytes - 24 + 3) / 4];
mipl->OffsetXY = (short *)(mipl->OffsetX + mipl->SizeX + 1);
mipl->SlabData = (BYTE *)(mipl->OffsetXY + mipl->SizeX * (mipl->SizeY + 1));
// Load x offsets.
for (i = 0, n = mipl->SizeX; i <= n; ++i)
{
// The X offsets stored in the KVX file are relative to the start of the
// X offsets array. Make them relative to voxdata instead.
mipl->OffsetX[i] = GetInt(rawmip + 24 + i * 4) - offsetsize;
}
// The first X offset must be 0 (since we subtracted offsetsize), according to the spec:
// NOTE: xoffset[0] = (xsiz+1)*4 + xsiz*(ysiz+1)*2 (ALWAYS)
if (mipl->OffsetX[0] != 0)
{
break;
}
// And the final X offset must point just past the end of the voxdata.
if (mipl->OffsetX[mipl->SizeX] != voxdatasize)
{
break;
}
// Load xy offsets.
i = 24 + i * 4;
for (j = 0, n *= mipl->SizeY + 1; j < n; ++j)
{
mipl->OffsetXY[j] = GetShort(rawmip + i + j * 2);
}
// Ensure all offsets are within bounds.
for (i = 0; i < mipl->SizeX; ++i)
{
int xoff = mipl->OffsetX[i];
for (j = 0; j < mipl->SizeY; ++j)
{
int yoff = mipl->OffsetXY[(mipl->SizeY + 1) * i + j];
if (unsigned(xoff + yoff) > unsigned(voxdatasize))
{
goto bad;
}
}
}
// Record slab location for the end.
slabs[mip] = (kvxslab_t *)(rawmip + 24 + offsetsize);
// Time for the next mip Level.
nextmip:
rawmip += numbytes;
maxmipsize -= numbytes + 4;
}
// Did we get any mip levels, and if so, does the last one leave just
// enough room for the palette after it?
if (mip == 0 || rawmip != rawvoxel + voxelsize - 768)
{
bad: delete voxel;
return NULL;
}
// Do not count empty mips at the end.
for (; mip > 0; --mip)
{
if (voxel->Mips[mip - 1].SlabData != NULL)
break;
}
voxel->NumMips = mip;
for (i = 0; i < mip; ++i)
{
if (!CopyVoxelSlabs((kvxslab_t *)voxel->Mips[i].SlabData, slabs[i], voxel->Mips[i].OffsetX[voxel->Mips[i].SizeX]))
{ // Invalid slabs encountered. Reject this voxel.
delete voxel;
return NULL;
}
}
voxel->LumpNum = lumpnum;
voxel->Palette = new BYTE[768];
memcpy(voxel->Palette, rawvoxel + voxelsize - 768, 768);
return voxel;
}
//==========================================================================
//
// FVoxelMipLevel Constructor
//
//==========================================================================
FVoxelMipLevel::FVoxelMipLevel()
{
SizeZ = SizeY = SizeX = 0;
PivotZ = PivotY = PivotX = 0;
OffsetX = NULL;
OffsetXY = NULL;
SlabData = NULL;
}
//==========================================================================
//
// FVoxelMipLevel Destructor
//
//==========================================================================
FVoxelMipLevel::~FVoxelMipLevel()
{
if (OffsetX != NULL)
{
delete[] OffsetX;
}
}
//==========================================================================
//
// FVoxel Constructor
//
//==========================================================================
FVoxel::FVoxel()
{
Palette = NULL;
}
FVoxel::~FVoxel()
{
if (Palette != NULL) delete [] Palette;
}
//==========================================================================
//
// Remap the voxel to the game palette
//
//==========================================================================
void FVoxel::Remap()
{
if (Palette != NULL)
{
BYTE *remap = GetVoxelRemap(Palette);
for (int i = 0; i < NumMips; ++i)
{
RemapVoxelSlabs((kvxslab_t *)Mips[i].SlabData, Mips[i].OffsetX[Mips[i].SizeX], remap);
}
delete [] Palette;
Palette = NULL;
}
}
//========================================================================== //==========================================================================
// //
@ -389,10 +687,4 @@ CCMD (printspans)
Printf ("\n"); Printf ("\n");
} }
} }
CCMD (picnum)
{
//int picnum = TexMan.GetTexture (argv[1], FTexture::TEX_Any);
//Printf ("%d: %s - %s\n", picnum, TexMan[picnum]->Name, TexMan(picnum)->Name);
}
#endif #endif

View file

@ -144,4 +144,6 @@ extern size_t numfakecmaps;
int R_FindSkin (const char *name, int pclass); // [RH] Find a skin int R_FindSkin (const char *name, int pclass); // [RH] Find a skin
FVoxel *R_LoadKVX(int lumpnum);
#endif #endif

View file

@ -25,6 +25,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "templates.h" #include "templates.h"
#include "memarena.h"
// Some more or less basic data types // Some more or less basic data types
// we depend on. // we depend on.
@ -1038,7 +1039,6 @@ struct column_t
typedef BYTE lighttable_t; // This could be wider for >8 bit display. typedef BYTE lighttable_t; // This could be wider for >8 bit display.
// A vissprite_t is a thing // A vissprite_t is a thing
// that will be drawn during a refresh. // that will be drawn during a refresh.
// I.e. a sprite object that is partly visible. // I.e. a sprite object that is partly visible.
@ -1046,8 +1046,9 @@ struct vissprite_t
{ {
short x1, x2; short x1, x2;
fixed_t cx; // for line side calculation fixed_t cx; // for line side calculation
fixed_t gx, gy; // for drawseg and fake floor clipping fixed_t gx, gy, gz; // origin in world coordinates
fixed_t gz, gzt; // global bottom / top for silhouette clipping angle_t angle;
fixed_t gzb, gzt; // global bottom / top for silhouette clipping
fixed_t startfrac; // horizontal position of x1 fixed_t startfrac; // horizontal position of x1
fixed_t xscale, yscale; fixed_t xscale, yscale;
fixed_t xiscale; // negative if flipped fixed_t xiscale; // negative if flipped
@ -1060,12 +1061,17 @@ struct vissprite_t
sector_t *sector; // [RH] sector this sprite is in sector_t *sector; // [RH] sector this sprite is in
fixed_t alpha; fixed_t alpha;
fixed_t floorclip; fixed_t floorclip;
FTexture *pic; union
{
FTexture *pic;
struct FVoxel *voxel;
};
BYTE bIsVoxel:1; // [RH] Use voxel instead of pic
BYTE bSplitSprite:1; // [RH] Sprite was split by a drawseg
BYTE FakeFlatStat; // [RH] which side of fake/floor ceiling sprite is on
short renderflags; short renderflags;
DWORD Translation; // [RH] for color translation DWORD Translation; // [RH] for color translation
FRenderStyle RenderStyle; FRenderStyle RenderStyle;
BYTE FakeFlatStat; // [RH] which side of fake/floor ceiling sprite is on
BYTE bSplitSprite; // [RH] Sprite was split by a drawseg
}; };
enum enum
@ -1087,14 +1093,16 @@ enum
// //
struct spriteframe_t struct spriteframe_t
{ {
struct FVoxelDef *Voxel;// voxel to use for this frame
FTextureID Texture[16]; // texture to use for view angles 0-15 FTextureID Texture[16]; // texture to use for view angles 0-15
WORD Flip; // flip (1 = flip) to use for view angles 0-15. WORD Flip; // flip (1 = flip) to use for view angles 0-15.
}; };
// //
// A sprite definition: // A sprite definition:
// a number of animation frames. // a number of animation frames.
// //
struct spritedef_t struct spritedef_t
{ {
union union
@ -1127,4 +1135,77 @@ public:
int namespc; // namespace for this skin int namespc; // namespace for this skin
}; };
// [RH] Voxels from Build
#define MAXVOXMIPS 5
struct kvxslab_t
{
BYTE ztop; // starting z coordinate of top of slab
BYTE zleng; // # of bytes in the color array - slab height
BYTE backfacecull; // low 6 bits tell which of 6 faces are exposed
BYTE col[1/*zleng*/];// color data from top to bottom
};
struct FVoxelMipLevel
{
FVoxelMipLevel();
~FVoxelMipLevel();
int SizeX;
int SizeY;
int SizeZ;
fixed_t PivotX; // 24.8 fixed point
fixed_t PivotY; // ""
fixed_t PivotZ; // ""
int *OffsetX;
short *OffsetXY;
BYTE *SlabData;
};
struct FVoxel
{
int LumpNum;
int NumMips;
BYTE *Palette;
FVoxelMipLevel Mips[MAXVOXMIPS];
FVoxel();
~FVoxel();
void Remap();
};
struct FVoxelDef
{
FVoxel *Voxel;
int PlacedSpin; // degrees/sec to spin actors without MF_DROPPED set
int DroppedSpin; // degrees/sec to spin actors with MF_DROPPED set
fixed_t Scale;
angle_t AngleOffset; // added to actor's angle to compensate for wrong-facing voxels
};
// [RH] A c-buffer. Used for keeping track of offscreen voxel spans.
struct FCoverageBuffer
{
struct Span
{
Span *NextSpan;
short Start, Stop;
};
FCoverageBuffer(int size);
~FCoverageBuffer();
void Clear();
void InsertSpan(int listnum, int start, int stop);
Span *AllocSpan();
FMemArena SpanArena;
Span **Spans; // [0..NumLists-1] span lists
Span *FreeSpans;
unsigned int NumLists;
};
#endif #endif

View file

@ -141,6 +141,7 @@ FRenderStyle LegacyRenderStyles[STYLE_Count] =
/* STYLE_Add */ {{ STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_One, 0 }}, /* STYLE_Add */ {{ STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_One, 0 }},
/* STYLE_Shaded */ {{ STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_RedIsAlpha | STYLEF_ColorIsFixed }}, /* STYLE_Shaded */ {{ STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_RedIsAlpha | STYLEF_ColorIsFixed }},
/* STYLE_TranslucentStencil */{{ STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_ColorIsFixed }}, /* STYLE_TranslucentStencil */{{ STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_ColorIsFixed }},
/* STYLE_Shadow */{{ STYLEOP_Shadow, 0, 0, 0 }},
}; };
#else #else
FRenderStyle LegacyRenderStyles[STYLE_Count]; FRenderStyle LegacyRenderStyles[STYLE_Count];
@ -157,6 +158,7 @@ static const BYTE Styles[STYLE_Count * 4] =
STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_One, 0, STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_One, 0,
STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_RedIsAlpha | STYLEF_ColorIsFixed, STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_RedIsAlpha | STYLEF_ColorIsFixed,
STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_ColorIsFixed, STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_ColorIsFixed,
STYLEOP_Shadow, 0, 0, 0
}; };
static struct LegacyInit static struct LegacyInit
@ -1350,6 +1352,97 @@ void R_FillSpan (void)
memset (ylookup[ds_y] + ds_x1 + dc_destorg, ds_color, ds_x2 - ds_x1 + 1); memset (ylookup[ds_y] + ds_x1 + dc_destorg, ds_color, ds_x2 - ds_x1 + 1);
} }
// Draw a voxel slab
//
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
// Ken Silverman's official web site: "http://www.advsys.net/ken"
// See the included license file "BUILDLIC.TXT" for license info.
// Actually, this is just R_DrawColumn with an extra width parameter.
#ifndef X86_ASM
static const BYTE *slabcolormap;
extern "C" void R_SetupDrawSlab(const BYTE *colormap)
{
slabcolormap = colormap;
}
extern "C" void STACK_ARGS R_DrawSlab(int dx, fixed_t v, int dy, fixed_t vi, const BYTE *vptr, BYTE *p)
{
int x;
const BYTE *colormap = slabcolormap;
int pitch = dc_pitch;
assert(dx > 0);
if (dx == 1)
{
while (dy > 0)
{
*p = colormap[vptr[v >> FRACBITS]];
p += pitch;
v += vi;
dy--;
}
}
else if (dx == 2)
{
while (dy > 0)
{
BYTE color = colormap[vptr[v >> FRACBITS]];
p[0] = color;
p[1] = color;
p += pitch;
v += vi;
dy--;
}
}
else if (dx == 3)
{
while (dy > 0)
{
BYTE color = colormap[vptr[v >> FRACBITS]];
p[0] = color;
p[1] = color;
p[2] = color;
p += pitch;
v += vi;
dy--;
}
}
else if (dx == 4)
{
while (dy > 0)
{
BYTE color = colormap[vptr[v >> FRACBITS]];
p[0] = color;
p[1] = color;
p[2] = color;
p[3] = color;
p += pitch;
v += vi;
dy--;
}
}
else while (dy > 0)
{
BYTE color = colormap[vptr[v >> FRACBITS]];
// The optimizer will probably turn this into a memset call.
// Since dx is not likely to be large, I'm not sure that's a good thing,
// hence the alternatives above.
for (x = 0; x < dx; x++)
{
p[x] = color;
}
p += pitch;
v += vi;
dy--;
}
}
#endif
/****************************************************/ /****************************************************/
/****************************************************/ /****************************************************/
@ -2068,7 +2161,7 @@ void R_InitColumnDrawers ()
} }
// [RH] Choose column drawers in a single place // [RH] Choose column drawers in a single place
EXTERN_CVAR (Bool, r_drawfuzz) EXTERN_CVAR (Int, r_drawfuzz)
EXTERN_CVAR (Float, transsouls) EXTERN_CVAR (Float, transsouls)
CVAR (Bool, r_drawtrans, true, 0) CVAR (Bool, r_drawtrans, true, 0)
@ -2235,6 +2328,13 @@ ESPSResult R_SetPatchStyle (FRenderStyle style, fixed_t alpha, int translation,
style.CheckFuzz(); style.CheckFuzz();
if (style.BlendOp == STYLEOP_Shadow)
{
style = LegacyRenderStyles[STYLE_TranslucentStencil];
alpha = FRACUNIT*3/10;
color = 0;
}
if (style.Flags & STYLEF_TransSoulsAlpha) if (style.Flags & STYLEF_TransSoulsAlpha)
{ {
alpha = fixed_t(transsouls * FRACUNIT); alpha = fixed_t(transsouls * FRACUNIT);
@ -2390,16 +2490,42 @@ bool FRenderStyle::IsVisible(fixed_t alpha) const throw()
void FRenderStyle::CheckFuzz() void FRenderStyle::CheckFuzz()
{ {
if (BlendOp == STYLEOP_FuzzOrAdd) switch (BlendOp)
{ {
BlendOp = (r_drawfuzz || !r_drawtrans) ? STYLEOP_Fuzz : STYLEOP_Add; default:
return;
case STYLEOP_FuzzOrAdd:
if (r_drawtrans && r_drawfuzz == 0)
{
BlendOp = STYLEOP_Add;
return;
}
break;
case STYLEOP_FuzzOrSub:
if (r_drawtrans && r_drawfuzz == 0)
{
BlendOp = STYLEOP_Sub;
return;
}
break;
case STYLEOP_FuzzOrRevSub:
if (r_drawtrans && r_drawfuzz == 0)
{
BlendOp = STYLEOP_RevSub;
return;
}
break;
} }
else if (BlendOp == STYLEOP_FuzzOrSub)
if (r_drawfuzz == 2)
{ {
BlendOp = (r_drawfuzz || !r_drawtrans) ? STYLEOP_Fuzz : STYLEOP_Sub; BlendOp = STYLEOP_Shadow;
} }
else if (BlendOp == STYLEOP_FuzzOrRevSub) else
{ {
BlendOp = (r_drawfuzz || !r_drawtrans) ? STYLEOP_Fuzz : STYLEOP_RevSub; BlendOp = STYLEOP_Fuzz;
} }
} }

View file

@ -53,7 +53,7 @@ extern "C" BYTE* palookupoffse[4];
extern "C" const BYTE* bufplce[4]; extern "C" const BYTE* bufplce[4];
// [RH] Temporary buffer for column drawing // [RH] Temporary buffer for column drawing
extern "C" BYTE dc_temp[MAXHEIGHT*4]; extern "C" BYTE *dc_temp;
extern "C" unsigned int dc_tspans[4][MAXHEIGHT]; extern "C" unsigned int dc_tspans[4][MAXHEIGHT];
extern "C" unsigned int *dc_ctspan[4]; extern "C" unsigned int *dc_ctspan[4];
extern "C" unsigned int horizspans[4]; extern "C" unsigned int horizspans[4];
@ -178,7 +178,7 @@ extern void (STACK_ARGS *rt_map4cols)(int sx, int yl, int yh);
void rt_draw4cols (int sx); void rt_draw4cols (int sx);
// [RH] Preps the temporary horizontal buffer. // [RH] Preps the temporary horizontal buffer.
void rt_initcols (void); void rt_initcols (BYTE *buffer=NULL);
void R_DrawFogBoundary (int x1, int x2, short *uclip, short *dclip); void R_DrawFogBoundary (int x1, int x2, short *uclip, short *dclip);
@ -216,6 +216,9 @@ void R_FillColumnP (void);
void R_FillColumnHorizP (void); void R_FillColumnHorizP (void);
void R_FillSpan (void); void R_FillSpan (void);
extern "C" void R_SetupDrawSlab(const BYTE *colormap);
extern "C" void STACK_ARGS R_DrawSlab(int dx, fixed_t v, int dy, fixed_t vi, const BYTE *vptr, BYTE *p);
extern "C" int ds_y; extern "C" int ds_y;
extern "C" int ds_x1; extern "C" int ds_x1;
extern "C" int ds_x2; extern "C" int ds_x2;

View file

@ -52,9 +52,13 @@
// dc_temp is the buffer R_DrawColumnHoriz writes into. // dc_temp is the buffer R_DrawColumnHoriz writes into.
// dc_tspans points into it. // dc_tspans points into it.
// dc_ctspan points into dc_tspans. // dc_ctspan points into dc_tspans.
// But what is horizspan, and what is its relation with dc_ctspan? // horizspan also points into dc_tspans.
BYTE dc_temp[MAXHEIGHT*4]; // dc_ctspan is advanced while drawing into dc_temp.
// horizspan is advanced up to dc_ctspan when drawing from dc_temp to the screen.
BYTE dc_tempbuff[MAXHEIGHT*4];
BYTE *dc_temp;
unsigned int dc_tspans[4][MAXHEIGHT]; unsigned int dc_tspans[4][MAXHEIGHT];
unsigned int *dc_ctspan[4]; unsigned int *dc_ctspan[4];
unsigned int *horizspan[4]; unsigned int *horizspan[4];
@ -998,10 +1002,11 @@ void rt_draw4cols (int sx)
// Before each pass through a rendering loop that uses these routines, // Before each pass through a rendering loop that uses these routines,
// call this function to set up the span pointers. // call this function to set up the span pointers.
void rt_initcols (void) void rt_initcols (BYTE *buff)
{ {
int y; int y;
dc_temp = buff == NULL ? dc_tempbuff : buff;
for (y = 3; y >= 0; y--) for (y = 3; y >= 0; y--)
horizspan[y] = dc_ctspan[y] = &dc_tspans[y][0]; horizspan[y] = dc_ctspan[y] = &dc_tspans[y][0];
} }
@ -1035,26 +1040,18 @@ void R_DrawColumnHorizP_C (void)
const BYTE *source = dc_source; const BYTE *source = dc_source;
if (count & 1) { if (count & 1) {
*dest = source[frac>>FRACBITS]; *dest = source[frac>>FRACBITS]; dest += 4; frac += fracstep;
dest += 4;
frac += fracstep;
} }
if (count & 2) { if (count & 2) {
dest[0] = source[frac>>FRACBITS]; dest[0] = source[frac>>FRACBITS]; frac += fracstep;
frac += fracstep; dest[4] = source[frac>>FRACBITS]; frac += fracstep;
dest[4] = source[frac>>FRACBITS];
frac += fracstep;
dest += 8; dest += 8;
} }
if (count & 4) { if (count & 4) {
dest[0] = source[frac>>FRACBITS]; dest[0] = source[frac>>FRACBITS]; frac += fracstep;
frac += fracstep; dest[4] = source[frac>>FRACBITS]; frac += fracstep;
dest[4] = source[frac>>FRACBITS]; dest[8] = source[frac>>FRACBITS]; frac += fracstep;
frac += fracstep; dest[12]= source[frac>>FRACBITS]; frac += fracstep;
dest[8] = source[frac>>FRACBITS];
frac += fracstep;
dest[12] = source[frac>>FRACBITS];
frac += fracstep;
dest += 16; dest += 16;
} }
count >>= 3; count >>= 3;
@ -1062,22 +1059,14 @@ void R_DrawColumnHorizP_C (void)
do do
{ {
dest[0] = source[frac>>FRACBITS]; dest[0] = source[frac>>FRACBITS]; frac += fracstep;
frac += fracstep; dest[4] = source[frac>>FRACBITS]; frac += fracstep;
dest[4] = source[frac>>FRACBITS]; dest[8] = source[frac>>FRACBITS]; frac += fracstep;
frac += fracstep; dest[12]= source[frac>>FRACBITS]; frac += fracstep;
dest[8] = source[frac>>FRACBITS]; dest[16]= source[frac>>FRACBITS]; frac += fracstep;
frac += fracstep; dest[20]= source[frac>>FRACBITS]; frac += fracstep;
dest[12] = source[frac>>FRACBITS]; dest[24]= source[frac>>FRACBITS]; frac += fracstep;
frac += fracstep; dest[28]= source[frac>>FRACBITS]; frac += fracstep;
dest[16] = source[frac>>FRACBITS];
frac += fracstep;
dest[20] = source[frac>>FRACBITS];
frac += fracstep;
dest[24] = source[frac>>FRACBITS];
frac += fracstep;
dest[28] = source[frac>>FRACBITS];
frac += fracstep;
dest += 32; dest += 32;
} while (--count); } while (--count);
} }
@ -1110,8 +1099,7 @@ void R_FillColumnHorizP (void)
if (!(count >>= 1)) if (!(count >>= 1))
return; return;
do { do {
dest[0] = color; dest[0] = color; dest[4] = color;
dest[4] = color;
dest += 8; dest += 8;
} while (--count); } while (--count);
} }

View file

@ -103,7 +103,6 @@ static fixed_t MaxVisForFloor;
static FRandom pr_torchflicker ("TorchFlicker"); static FRandom pr_torchflicker ("TorchFlicker");
static FRandom pr_hom; static FRandom pr_hom;
static TArray<InterpolationViewer> PastViewers; static TArray<InterpolationViewer> PastViewers;
static int centerxwide;
static bool polyclipped; static bool polyclipped;
static bool r_showviewer; static bool r_showviewer;
bool r_dontmaplines; bool r_dontmaplines;
@ -135,6 +134,7 @@ float LastFOV;
int WidescreenRatio; int WidescreenRatio;
fixed_t GlobVis; fixed_t GlobVis;
fixed_t viewingrangerecip;
fixed_t FocalTangent; fixed_t FocalTangent;
fixed_t FocalLengthX; fixed_t FocalLengthX;
fixed_t FocalLengthY; fixed_t FocalLengthY;
@ -151,6 +151,8 @@ float WallTMapScale2;
extern "C" { extern "C" {
int centerx; int centerx;
int centery; int centery;
int centerxwide;
} }
DCanvas *RenderTarget; // [RH] canvas to render to DCanvas *RenderTarget; // [RH] canvas to render to
@ -159,6 +161,7 @@ fixed_t globaluclip, globaldclip;
fixed_t centerxfrac; fixed_t centerxfrac;
fixed_t centeryfrac; fixed_t centeryfrac;
fixed_t yaspectmul; fixed_t yaspectmul;
fixed_t baseyaspectmul; // yaspectmul without a forced aspect ratio
float iyaspectmulfloat; float iyaspectmulfloat;
fixed_t InvZtoScale; fixed_t InvZtoScale;
@ -458,6 +461,9 @@ void R_InitTextureMapping ()
FocalLengthY = Scale (centerxfrac, yaspectmul, hitan); FocalLengthY = Scale (centerxfrac, yaspectmul, hitan);
FocalLengthXfloat = (float)FocalLengthX / 65536.f; FocalLengthXfloat = (float)FocalLengthX / 65536.f;
// This is 1/FocalTangent before the widescreen extension of FOV.
viewingrangerecip = DivScale32(1, finetangent[FINEANGLES/4+(FieldOfView/2)]);
// Now generate xtoviewangle for sky texture mapping. // Now generate xtoviewangle for sky texture mapping.
// [RH] Do not generate viewangletox, because texture mapping is no // [RH] Do not generate viewangletox, because texture mapping is no
// longer done with trig, so it's not needed. // longer done with trig, so it's not needed.
@ -600,7 +606,7 @@ void R_SetViewSize (int blocks)
void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight)
{ {
int virtheight, virtwidth; int virtheight, virtwidth, trueratio, virtwidth2, virtheight2;
if (windowSize >= 11) if (windowSize >= 11)
{ {
@ -621,7 +627,7 @@ void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight)
} }
// If the screen is approximately 16:9 or 16:10, consider it widescreen. // If the screen is approximately 16:9 or 16:10, consider it widescreen.
WidescreenRatio = CheckRatio (fullWidth, fullHeight); WidescreenRatio = CheckRatio (fullWidth, fullHeight, &trueratio);
DrawFSHUD = (windowSize == 11); DrawFSHUD = (windowSize == 11);
@ -644,8 +650,18 @@ void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight)
centerxfrac = centerx<<FRACBITS; centerxfrac = centerx<<FRACBITS;
centeryfrac = centery<<FRACBITS; centeryfrac = centery<<FRACBITS;
virtwidth = fullWidth; virtwidth = virtwidth2 = fullWidth;
virtheight = fullHeight; virtheight = virtheight2 = fullHeight;
if (trueratio & 4)
{
virtheight2 = virtheight2 * BaseRatioSizes[trueratio][3] / 48;
}
else
{
virtwidth2 = virtwidth2 * BaseRatioSizes[trueratio][3] / 48;
}
if (WidescreenRatio & 4) if (WidescreenRatio & 4)
{ {
virtheight = virtheight * BaseRatioSizes[WidescreenRatio][3] / 48; virtheight = virtheight * BaseRatioSizes[WidescreenRatio][3] / 48;
@ -657,6 +673,7 @@ void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight)
centerxwide = centerx * BaseRatioSizes[WidescreenRatio][3] / 48; centerxwide = centerx * BaseRatioSizes[WidescreenRatio][3] / 48;
} }
baseyaspectmul = Scale(320 << FRACBITS, virtheight2, r_Yaspect * virtwidth2);
yaspectmul = Scale ((320<<FRACBITS), virtheight, r_Yaspect * virtwidth); yaspectmul = Scale ((320<<FRACBITS), virtheight, r_Yaspect * virtwidth);
iyaspectmulfloat = (float)virtwidth * r_Yaspect / 320.f / (float)virtheight; iyaspectmulfloat = (float)virtwidth * r_Yaspect / 320.f / (float)virtheight;
InvZtoScale = yaspectmul * centerx; InvZtoScale = yaspectmul * centerx;

View file

@ -43,6 +43,7 @@ extern fixed_t viewsin;
extern fixed_t viewtancos; extern fixed_t viewtancos;
extern fixed_t viewtansin; extern fixed_t viewtansin;
extern fixed_t FocalTangent; extern fixed_t FocalTangent;
extern fixed_t viewingrangerecip;
extern fixed_t FocalLengthX, FocalLengthY; extern fixed_t FocalLengthX, FocalLengthY;
extern float FocalLengthXfloat; extern float FocalLengthXfloat;
extern fixed_t InvZtoScale; extern fixed_t InvZtoScale;
@ -62,7 +63,7 @@ extern int viewwindowy;
extern "C" int centerx; extern "C" int centerx, centerxwide;
extern "C" int centery; extern "C" int centery;
extern fixed_t centerxfrac; extern fixed_t centerxfrac;

View file

@ -593,7 +593,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
check->viewz == stacked_viewz && check->viewz == stacked_viewz &&
( (
// headache inducing logic... :( // headache inducing logic... :(
(ib_compatflags & BCOMPATF_BADPORTALS) || (!(skybox->flags & MF_JUSTATTACKED)) ||
( (
check->alpha == alpha && check->alpha == alpha &&
(alpha == 0 || // if alpha is > 0 everything needs to be checked (alpha == 0 || // if alpha is > 0 everything needs to be checked

File diff suppressed because it is too large Load diff

View file

@ -104,6 +104,14 @@ void R_ClearSprites ();
void R_DrawMasked (); void R_DrawMasked ();
void R_DrawRemainingPlayerSprites (); void R_DrawRemainingPlayerSprites ();
void R_CheckOffscreenBuffer(int width, int height, bool spansonly);
enum { DVF_OFFSCREEN = 1, DVF_SPANSONLY = 2 };
void R_DrawVoxel(fixed_t dasprx, fixed_t daspry, fixed_t dasprz, angle_t dasprang,
fixed_t daxscale, fixed_t dayscale, FVoxel *voxobj,
lighttable_t *colormap, short *daumost, short *dadmost, int minslabz, int maxslabz, int flags);
void R_ClipVisSprite (vissprite_t *vis, int xl, int xh); void R_ClipVisSprite (vissprite_t *vis, int xl, int xh);

View file

@ -113,6 +113,7 @@ bool FWadFile::Open(bool quiet)
SetNamespace("TX_START", "TX_END", ns_newtextures); SetNamespace("TX_START", "TX_END", ns_newtextures);
SetNamespace("V_START", "V_END", ns_strifevoices); SetNamespace("V_START", "V_END", ns_strifevoices);
SetNamespace("HI_START", "HI_END", ns_hires); SetNamespace("HI_START", "HI_END", ns_hires);
SetNamespace("VX_START", "VX_END", ns_voxels);
SkinHack(); SkinHack();
} }
delete [] fileinfo; delete [] fileinfo;

View file

@ -116,6 +116,7 @@ void FResourceLump::LumpNameSetup(const char *iname)
!strncmp(iname, "textures/", 9) ? ns_newtextures : !strncmp(iname, "textures/", 9) ? ns_newtextures :
!strncmp(iname, "hires/", 6) ? ns_hires : !strncmp(iname, "hires/", 6) ? ns_hires :
!strncmp(iname, "sprites/", 8) ? ns_sprites : !strncmp(iname, "sprites/", 8) ? ns_sprites :
!strncmp(iname, "voxels/", 7) ? ns_voxels :
!strncmp(iname, "colormaps/", 10) ? ns_colormaps : !strncmp(iname, "colormaps/", 10) ? ns_colormaps :
!strncmp(iname, "acs/", 4) ? ns_acslibrary : !strncmp(iname, "acs/", 4) ? ns_acslibrary :
!strncmp(iname, "voices/", 7) ? ns_strifevoices : !strncmp(iname, "voices/", 7) ? ns_strifevoices :
@ -137,7 +138,7 @@ void FResourceLump::LumpNameSetup(const char *iname)
// Since '\' can't be used as a file name's part inside a ZIP // Since '\' can't be used as a file name's part inside a ZIP
// we have to work around this for sprites because it is a valid // we have to work around this for sprites because it is a valid
// frame character. // frame character.
else if (Namespace == ns_sprites) else if (Namespace == ns_sprites || Namespace == ns_voxels)
{ {
char *c; char *c;

View file

@ -4,21 +4,39 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/param.h>
#include <sys/ucontext.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <sys/ucontext.h>
// Solaris doesn't have SA_ONESHOT #ifdef __linux__
// According to the Linux header this is the same. #include <sys/prctl.h>
#ifndef SA_ONESHOT #ifndef PR_SET_PTRACER
#define SA_ONESHOT SA_RESETHAND #define PR_SET_PTRACER 0x59616d61
#endif
#endif #endif
static const char *cc_logfile = NULL;
static char respfile[256]; static const char crash_switch[] = "--cc-handle-crash";
static char buf[256];
static char user_info_buf[1024]; static const char fatal_err[] = "\n\n*** Fatal Error ***\n";
static const char pipe_err[] = "!!! Failed to create pipe\n";
static const char fork_err[] = "!!! Failed to fork debug process\n";
static const char exec_err[] = "!!! Failed to exec debug process\n";
static char argv0[PATH_MAX];
static char altstack[SIGSTKSZ];
static struct {
int signum;
pid_t pid;
int has_siginfo;
siginfo_t siginfo;
char buf[1024];
} crash_info;
static const struct { static const struct {
const char *name; const char *name;
@ -88,16 +106,19 @@ static const struct {
static int (*cc_user_info)(char*, char*); static int (*cc_user_info)(char*, char*);
static void gdb_info(pid_t pid) static void gdb_info(pid_t pid)
{ {
char respfile[64];
char cmd_buf[128];
FILE *f; FILE *f;
int fd; int fd;
/* Create a temp file to put gdb commands into */ /* Create a temp file to put gdb commands into */
strcpy(respfile, "gdb-respfile-XXXXXX"); strcpy(respfile, "gdb-respfile-XXXXXX");
if((fd = mkstemp(respfile)) >= 0 && (f = fdopen(fd, "w"))) if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL)
{ {
fprintf(f, "signal SIGCHLD\n" fprintf(f, "attach %d\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* Loaded Libraries\"\n" "shell echo \"* Loaded Libraries\"\n"
"info sharedlibrary\n" "info sharedlibrary\n"
@ -111,49 +132,18 @@ static void gdb_info(pid_t pid)
"shell echo \"* Registers\"\n" "shell echo \"* Registers\"\n"
"info registers\n" "info registers\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* Bytes near %%eip:\"\n"
"x/x $eip-3\nx/x $eip\n"
"shell echo \"\"\n"
"shell echo \"* Backtrace\"\n" "shell echo \"* Backtrace\"\n"
"backtrace full\n" "thread apply all backtrace full\n"
#if 0 /* This sorta works to print out the core, but is too slow and skips 0's.. */ "detach\n"
"shell echo \"\"\n" "quit\n", pid);
"shell echo \"* Stack\"\n"
"set var $_sp = $esp\n"
"while $_sp <= $ebp - 12\n"
" printf \"%%08x: \", $_sp\n"
" set var $_i = $_sp\n"
" while $_i < $_sp + 16\n"
" printf \"%%08x \", {int} $_i\n"
" set $_i += 4\n"
" end\n"
" set var $_i = $_sp\n"
" while $_i < $_sp + 16\n"
" printf \"%%c\", {int} $_i\n"
" set ++$_i\n"
" end\n"
" set var $_sp += 16\n"
" printf \"\\n\"\n"
"end\n"
"if $_sp <= $ebp\n"
" printf \"%%08x: \", $esp\n"
" while $_sp <= $ebp\n"
" printf \"%%08x \", {int} $_i\n"
" set $_sp += 4\n"
" end\n"
" printf \"\\n\"\n"
"end\n"
#endif
"kill\n"
"quit\n");
fclose(f); fclose(f);
/* Run gdb and print process info. */ /* Run gdb and print process info. */
snprintf(buf, sizeof(buf), "gdb --quiet --batch --command=%s --pid=%i", respfile, pid); snprintf(cmd_buf, sizeof(cmd_buf), "gdb --quiet --batch --command=%s", respfile);
printf("Executing: %s\n", buf); printf("Executing: %s\n", cmd_buf);
fflush(stdout); fflush(stdout);
system(buf);
system(cmd_buf);
/* Clean up */ /* Clean up */
remove(respfile); remove(respfile);
} }
@ -165,55 +155,137 @@ static void gdb_info(pid_t pid)
close(fd); close(fd);
remove(respfile); remove(respfile);
} }
printf("Could not create gdb command file\n"); printf("!!! Could not create gdb command file\n");
} }
fflush(stdout); fflush(stdout);
} }
/* Generic system info */
static void sys_info(void) static void sys_info(void)
{ {
#if (defined __unix__) #ifdef __unix__
system("echo \"System: `uname -a`\""); system("echo \"System: `uname -a`\"");
#endif
system("echo \"GCC version: `gcc -dumpversion`\"");
putchar('\n'); putchar('\n');
fflush(stdout); fflush(stdout);
#endif
}
static size_t safe_write(int fd, const void *buf, size_t len)
{
size_t ret = 0;
while(ret < len)
{
ssize_t rem;
if((rem=write(fd, (const char*)buf+ret, len-ret)) == -1)
{
if(errno == EINTR)
continue;
break;
}
ret += rem;
}
return ret;
} }
static void crash_catcher(int signum, siginfo_t *siginfo, void *context) static void crash_catcher(int signum, siginfo_t *siginfo, void *context)
{ {
ucontext_t *ucontext = (ucontext_t*)context; ucontext_t *ucontext = (ucontext_t*)context;
const char *sigdesc = NULL; pid_t dbg_pid;
pid_t pid, dbg_pid; int fd[2];
struct stat sbuf;
#ifndef __FreeBSD__ /* Make sure the effective uid is the real uid */
struct rlimit rl; if(getuid() != geteuid())
{
raise(signum);
return;
}
safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1);
if(pipe(fd) == -1)
{
safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1);
raise(signum);
return;
}
crash_info.signum = signum;
crash_info.pid = getpid();
crash_info.has_siginfo = !!siginfo;
if(siginfo)
crash_info.siginfo = *siginfo;
if(cc_user_info)
cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf));
/* Fork off to start a crash handler */
switch((dbg_pid=fork()))
{
/* Error */
case -1:
safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1);
raise(signum);
return;
case 0:
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execl(argv0, argv0, crash_switch, NULL);
safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1);
_exit(1);
default:
#ifdef __linux__
prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0);
#endif #endif
int status, i; safe_write(fd[1], &crash_info, sizeof(crash_info));
FILE *f; close(fd[0]);
close(fd[1]);
/* Wait; we'll be killed when gdb is done */
do {
int status;
if(waitpid(dbg_pid, &status, 0) == dbg_pid &&
(WIFEXITED(status) || WIFSIGNALED(status)))
{
/* The debug process died before it could kill us */
raise(signum);
break;
}
} while(1);
}
}
static void crash_handler(const char *logfile)
{
const char *sigdesc = "";
int i;
if(fread(&crash_info, sizeof(crash_info), 1, stdin) != 1)
{
fprintf(stderr, "!!! Failed to retrieve info from crashed process\n");
exit(1);
}
/* Get the signal description */ /* Get the signal description */
if(!siginfo) for(i = 0;signals[i].name;++i)
{ {
for(i = 0;signals[i].name;++i) if(signals[i].signum == crash_info.signum)
{ {
if(signals[i].signum == signum) sigdesc = signals[i].name;
{ break;
sigdesc = signals[i].name;
break;
}
} }
} }
else
if(crash_info.has_siginfo)
{ {
switch(signum) switch(crash_info.signum)
{ {
case SIGSEGV: case SIGSEGV:
for(i = 0;sigsegv_codes[i].name;++i) for(i = 0;sigsegv_codes[i].name;++i)
{ {
if(sigsegv_codes[i].code == siginfo->si_code) if(sigsegv_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigsegv_codes[i].name; sigdesc = sigsegv_codes[i].name;
break; break;
@ -224,7 +296,7 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context)
case SIGFPE: case SIGFPE:
for(i = 0;sigfpe_codes[i].name;++i) for(i = 0;sigfpe_codes[i].name;++i)
{ {
if(sigfpe_codes[i].code == siginfo->si_code) if(sigfpe_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigfpe_codes[i].name; sigdesc = sigfpe_codes[i].name;
break; break;
@ -235,7 +307,7 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context)
case SIGILL: case SIGILL:
for(i = 0;sigill_codes[i].name;++i) for(i = 0;sigill_codes[i].name;++i)
{ {
if(sigill_codes[i].code == siginfo->si_code) if(sigill_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigill_codes[i].name; sigdesc = sigill_codes[i].name;
break; break;
@ -246,7 +318,7 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context)
case SIGBUS: case SIGBUS:
for(i = 0;sigbus_codes[i].name;++i) for(i = 0;sigbus_codes[i].name;++i)
{ {
if(sigbus_codes[i].code == siginfo->si_code) if(sigbus_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigbus_codes[i].name; sigdesc = sigbus_codes[i].name;
break; break;
@ -255,149 +327,91 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context)
break; break;
} }
} }
fprintf(stderr, "%s (signal %i)\n", sigdesc, crash_info.signum);
if(crash_info.has_siginfo)
fprintf(stderr, "Address: %p\n", crash_info.siginfo.si_addr);
fputc('\n', stderr);
if(!sigdesc) if(logfile)
{ {
/* Unknown signal, let the default handler deal with it */ /* Create crash log file and redirect shell output to it */
raise(signum); if(freopen(logfile, "wa", stdout) != stdout)
return;
}
#if 0 /* Do we need this? */
/* Make sure the effective uid is the real uid */
if (getuid() != geteuid())
{
fprintf(stderr, "%s (signal %i)\ngetuid() does not match geteuid().\n", sigdesc, signum);
_exit(-1);
}
#endif
/* Create crash log file */
if(cc_logfile)
{
f = fopen(cc_logfile, "w");
if(!f)
{ {
fprintf(stderr, "Could not create %s following signal.\n", cc_logfile); fprintf(stderr, "!!! Could not create %s following signal\n", logfile);
raise(signum); exit(1);
return;
} }
} fprintf(stderr, "Generating %s and killing process %d, please wait... ", logfile, crash_info.pid);
else
f = stderr;
/* Get current process id and fork off */ printf("*** Fatal Error ***\n"
pid = getpid(); "%s (signal %i)\n", sigdesc, crash_info.signum);
switch ((dbg_pid = fork())) if(crash_info.has_siginfo)
printf("Address: %p\n", crash_info.siginfo.si_addr);
fputc('\n', stdout);
fflush(stdout);
}
sys_info();
crash_info.buf[sizeof(crash_info.buf)-1] = '\0';
printf("%s\n", crash_info.buf);
fflush(stdout);
if(crash_info.pid > 0)
{ {
/* Error */ gdb_info(crash_info.pid);
case -1: kill(crash_info.pid, SIGKILL);
break;
case 0:
fprintf(stderr, "\n\n*** Fatal Error ***\n"
"%s (signal %i)\n", sigdesc, signum);
/* Redirect shell output */
close(STDOUT_FILENO);
dup2(fileno(f), STDOUT_FILENO);
if(f != stderr)
{
fprintf(stderr, "\nGenerating %s and killing process %i, please wait... ", cc_logfile, pid);
fprintf(f, "*** Fatal Error ***\n"
"%s (signal %i)\n", sigdesc, signum);
}
if(siginfo)
fprintf(f, "Address: %p\n", siginfo->si_addr);
fputc('\n', f);
fflush(f);
/* Get info */
sys_info();
if(cc_user_info)
{
if(cc_user_info(user_info_buf, user_info_buf+sizeof(user_info_buf)) > 0)
{
fprintf(f, "%s\n", user_info_buf);
fflush(f);
}
}
gdb_info(pid);
#if 0 /* Why won't this work? */
if(ucontext)
{
unsigned char *ptr = ucontext->uc_stack.ss_sp;
size_t len;
fprintf(f, "\n* Stack\n");
for(len = ucontext->uc_stack.ss_size/4;len > 0; len -= 4)
{
fprintf(f, "0x%08x:", (int)ptr);
for(i = 0;i < ((len < 4) ? len : 4);++i)
{
fprintf(f, " %02x%02x%02x%02x", ptr[i*4 + 0], ptr[i*4 + 1],
ptr[i*4 + 2], ptr[i*4 + 3]);
}
fputc(' ', f);
fflush(f);
for(i = 0;i < ((len < 4) ? len : 4);++i)
{
fprintf(f, "%c", *(ptr++));
fprintf(f, "%c", *(ptr++));
fprintf(f, "%c", *(ptr++));
fprintf(f, "%c", *(ptr++));
}
fputc('\n', f);
fflush(f);
}
}
#endif
if(f != stderr)
{
fclose(f);
#if (defined __unix__)
if(cc_logfile)
{
char buf[256];
snprintf(buf, sizeof(buf),
"if (which gxmessage > /dev/null 2>&1);"
"then gxmessage -buttons \"Damn it:0\" -center -title \"Very Fatal Error\" -file %s;"
"elif (which xmessage > /dev/null 2>&1);"
"then xmessage -buttons \"Damn it:0\" -center -file %s -geometry 600x400;"
"fi", cc_logfile, cc_logfile);
system(buf);
}
#endif
}
_exit(0);
default:
/* Wait and let the child attach gdb */
waitpid(dbg_pid, NULL, 0);
} }
if(logfile)
{
const char *str;
char buf[512];
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
snprintf(buf, sizeof(buf), "kdialog --title \"Very Fatal Error\" --textbox \"%s\" 800 600", logfile);
else if((str=getenv("GNOME_DESKTOP_SESSION_ID")) && str[0] != '\0')
snprintf(buf, sizeof(buf), "gxmessage -buttons \"Okay:0\" -geometry 800x600 -title \"Very Fatal Error\" -center -file \"%s\"", logfile);
else
snprintf(buf, sizeof(buf), "xmessage -buttons \"Okay:0\" -center -file \"%s\"", logfile);
system(buf);
}
exit(0);
} }
int cc_install_handlers(int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*)) int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*))
{ {
int retval = 0;
struct sigaction sa; struct sigaction sa;
memset(&sa, 0, sizeof(sa)); stack_t altss;
int retval;
sa.sa_sigaction = crash_catcher; if(argc == 2 && strcmp(argv[1], crash_switch) == 0)
crash_handler(logfile);
#if !defined(__FreeBSD__) && !defined(__APPLE__)
sa.sa_flags = SA_ONESHOT | SA_NODEFER | SA_SIGINFO;
#else
sa.sa_flags = SA_NODEFER | SA_SIGINFO;
#endif
cc_logfile = logfile;
cc_user_info = user_info; cc_user_info = user_info;
if(argv[0][0] == '/')
snprintf(argv0, sizeof(argv0), "%s", argv[0]);
else
{
getcwd(argv0, sizeof(argv0));
retval = strlen(argv0);
snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]);
}
/* Set an alternate signal stack so SIGSEGVs caused by stack overflows
* still run */
altss.ss_sp = altstack;
altss.ss_flags = 0;
altss.ss_size = sizeof(altstack);
sigaltstack(&altss, NULL);
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = crash_catcher;
sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&sa.sa_mask);
retval = 0;
while(num_signals--) while(num_signals--)
{ {
if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE && if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE &&
@ -408,6 +422,5 @@ int cc_install_handlers(int num_signals, int *signals, const char *logfile, int
} }
++signals; ++signals;
} }
return retval; return retval;
} }

View file

@ -73,7 +73,7 @@
// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
extern "C" int cc_install_handlers(int, int*, const char*, int(*)(char*, char*)); extern "C" int cc_install_handlers(int, char**, int, int*, const char*, int(*)(char*, char*));
// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -156,13 +156,14 @@ static void STACK_ARGS NewFailure ()
static int DoomSpecificInfo (char *buffer, char *end) static int DoomSpecificInfo (char *buffer, char *end)
{ {
const char *arg; const char *arg;
int size = end-buffer; int size = end-buffer-2;
int i, p; int i, p;
SDL_Quit();
p = 0; p = 0;
p += snprintf (buffer+p, size-p, GAMENAME" version " DOTVERSIONSTR " (" __DATE__ ")\n"); p += snprintf (buffer+p, size-p, GAMENAME" version " DOTVERSIONSTR " (" __DATE__ ")\n");
#ifdef __VERSION__
p += snprintf (buffer+p, size-p, "Compiler version: %s\n", __VERSION__);
#endif
p += snprintf (buffer+p, size-p, "\nCommand line:"); p += snprintf (buffer+p, size-p, "\nCommand line:");
for (i = 0; i < Args->NumArgs(); ++i) for (i = 0; i < Args->NumArgs(); ++i)
{ {
@ -250,14 +251,14 @@ void I_ShutdownJoysticks();
int main (int argc, char **argv) int main (int argc, char **argv)
{ {
printf(GAMENAME" v%s - SVN revision %s - SDL version\nCompiled on %s\n\n",
DOTVERSIONSTR_NOREV,SVN_REVISION_STRING,__DATE__);
{ {
int s[4] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS }; int s[4] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS };
cc_install_handlers(4, s, "zdoom-crash.log", DoomSpecificInfo); cc_install_handlers(argc, argv, 4, s, "zdoom-crash.log", DoomSpecificInfo);
} }
printf(GAMENAME" v%s - SVN revision %s - SDL version\nCompiled on %s\n\n",
DOTVERSIONSTR_NOREV,SVN_REVISION_STRING,__DATE__);
seteuid (getuid ()); seteuid (getuid ());
std::set_new_handler (NewFailure); std::set_new_handler (NewFailure);

View file

@ -608,6 +608,57 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
return defaultiwad; return defaultiwad;
} }
#if !defined(__APPLE__)
const char *str;
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
{
FString cmd("kdialog --title \""GAMESIG" "DOTVERSIONSTR": Select an IWAD to use\""
" --menu \"ZDoom found more than one IWAD\n"
"Select from the list below to determine which one to use:\"");
for(i = 0; i < numwads; ++i)
{
const char *filepart = strrchr(wads[i].Path, '/');
if(filepart == NULL)
filepart = wads[i].Path;
else
filepart++;
// Menu entries are specified in "tag" "item" pairs, where when a
// particular item is selected (and the Okay button clicked), its
// corresponding tag is printed to stdout for identification.
cmd.AppendFormat(" \"%d\" \"%s (%s)\"", i, wads[i].Name.GetChars(), filepart);
}
if(defaultiwad >= 0 && defaultiwad < numwads)
{
const char *filepart = strrchr(wads[defaultiwad].Path, '/');
if(filepart == NULL)
filepart = wads[defaultiwad].Path;
else
filepart++;
cmd.AppendFormat(" --default \"%s (%s)\"", wads[defaultiwad].Name.GetChars(), filepart);
}
FILE *f = popen(cmd, "r");
if(f != NULL)
{
char gotstr[16];
if(fgets(gotstr, sizeof(gotstr), f) == NULL ||
sscanf(gotstr, "%d", &i) != 1)
i = -1;
// Exit status = 1 means the selection was canceled (either by
// Cancel/Esc or the X button), not that there was an error running
// the program. In that case, nothing was printed so fgets will
// have failed. Other values can indicate an error running the app,
// so fall back to whatever else can be used.
int status = pclose(f);
if(WIFEXITED(status) && (WEXITSTATUS(status) == 0 || WEXITSTATUS(status) == 1))
return i;
}
}
#endif
#ifndef NO_GTK #ifndef NO_GTK
if (GtkAvailable) if (GtkAvailable)
{ {

View file

@ -2555,7 +2555,7 @@ void FMODSoundRenderer::DrawWaveDebug(int mode)
// 16 pixels of padding between each window. // 16 pixels of padding between each window.
window_size = (screen->GetWidth() - 16) / numoutchans - 16; window_size = (screen->GetWidth() - 16) / numoutchans - 16;
float *wavearray = (float*)alloca(window_size*sizeof(float)); float *wavearray = (float*)alloca(MAX(SPECTRUM_SIZE,window_size)*sizeof(float));
y = 16; y = 16;
y = DrawChannelGroupOutput(SfxGroup, wavearray, window_size, window_height, y, mode); y = DrawChannelGroupOutput(SfxGroup, wavearray, window_size, window_height, y, mode);

View file

@ -60,7 +60,7 @@ extern fixed_t finesine[5*FINEANGLES/4];
// (encapsulated in a struct so that we can still use array accesses). // (encapsulated in a struct so that we can still use array accesses).
struct cosine_inline struct cosine_inline
{ {
fixed_t operator[] (unsigned int x) fixed_t operator[] (unsigned int x) const
{ {
return finesine[x+FINEANGLES/4]; return finesine[x+FINEANGLES/4];
} }

View file

@ -234,6 +234,7 @@ void FTextureManager::AddTiles (void *tiles)
rot.Texture[8] = rot.Texture[8] =
rot.Texture[9] = texnum.GetIndex() + 4; rot.Texture[9] = texnum.GetIndex() + 4;
rot.Flip = 0x00FC; rot.Flip = 0x00FC;
rot.Voxel = NULL;
tex->Rotations = SpriteFrames.Push (rot); tex->Rotations = SpriteFrames.Push (rot);
} }
else if (rotType == 2) else if (rotType == 2)
@ -247,6 +248,7 @@ void FTextureManager::AddTiles (void *tiles)
rot.Texture[17-j*2] = texnum.GetIndex() + j; rot.Texture[17-j*2] = texnum.GetIndex() + j;
} }
rot.Flip = 0; rot.Flip = 0;
rot.Voxel = NULL;
tex->Rotations = SpriteFrames.Push (rot); tex->Rotations = SpriteFrames.Push (rot);
} }
} }

View file

@ -2070,6 +2070,15 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, morphweapon, S, PlayerPawn)
defaults->MorphWeapon = FName(z); defaults->MorphWeapon = FName(z);
} }
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, flechettetype, S, PlayerPawn)
{
PROP_STRING_PARM(str, 0);
defaults->FlechetteType = FindClassTentative(str, "ArtiPoisonBag");
}
//========================================================================== //==========================================================================
// //
//========================================================================== //==========================================================================

View file

@ -1313,6 +1313,21 @@ void DFrameBuffer::RenderView(player_t *player)
FCanvasTextureInfo::UpdateAll (); FCanvasTextureInfo::UpdateAll ();
} }
//==========================================================================
//
//
//
//==========================================================================
extern TDeletingArray<FVoxel *> Voxels;
void DFrameBuffer::RemapVoxels()
{
for (unsigned i=0; i<Voxels.Size(); i++)
{
Voxels[i]->Remap();
}
}
//=========================================================================== //===========================================================================
// //
// Render the view to a savegame picture // Render the view to a savegame picture
@ -1689,6 +1704,7 @@ void V_Init2()
Printf ("Resolution: %d x %d\n", SCREENWIDTH, SCREENHEIGHT); Printf ("Resolution: %d x %d\n", SCREENWIDTH, SCREENHEIGHT);
screen->SetGamma (gamma); screen->SetGamma (gamma);
screen->RemapVoxels();
FBaseCVar::ResetColors (); FBaseCVar::ResetColors ();
C_NewModeAdjust(); C_NewModeAdjust();
M_InitVideoModesMenu(); M_InitVideoModesMenu();
@ -1733,43 +1749,61 @@ CUSTOM_CVAR (Int, vid_aspect, 0, CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
// 1: 16:9 // 1: 16:9
// 2: 16:10 // 2: 16:10
// 4: 5:4 // 4: 5:4
int CheckRatio (int width, int height) int CheckRatio (int width, int height, int *trueratio)
{ {
int fakeratio = -1;
int ratio;
if ((vid_aspect >=1) && (vid_aspect <=4)) if ((vid_aspect >=1) && (vid_aspect <=4))
{ {
// [SP] User wants to force aspect ratio; let them. // [SP] User wants to force aspect ratio; let them.
return vid_aspect == 3? 0: int(vid_aspect); fakeratio = vid_aspect == 3? 0: int(vid_aspect);
} }
if (vid_nowidescreen) if (vid_nowidescreen)
{ {
if (!vid_tft) if (!vid_tft)
{ {
return 0; fakeratio = 0;
}
else
{
fakeratio = (height * 5/4 == width) ? 4 : 0;
} }
return (height * 5/4 == width) ? 4 : 0;
} }
// If the size is approximately 16:9, consider it so. // If the size is approximately 16:9, consider it so.
if (abs (height * 16/9 - width) < 10) if (abs (height * 16/9 - width) < 10)
{ {
return 1; ratio = 1;
} }
// 16:10 has more variance in the pixel dimensions. Grr. // 16:10 has more variance in the pixel dimensions. Grr.
if (abs (height * 16/10 - width) < 60) else if (abs (height * 16/10 - width) < 60)
{ {
// 320x200 and 640x400 are always 4:3, not 16:10 // 320x200 and 640x400 are always 4:3, not 16:10
if ((width == 320 && height == 200) || (width == 640 && height == 400)) if ((width == 320 && height == 200) || (width == 640 && height == 400))
{ {
return 0; ratio = 0;
}
else
{
ratio = 2;
} }
return 2;
} }
// Unless vid_tft is set, 1280x1024 is 4:3, not 5:4. // Unless vid_tft is set, 1280x1024 is 4:3, not 5:4.
if (height * 5/4 == width && vid_tft) else if (height * 5/4 == width && vid_tft)
{ {
return 4; ratio = 4;
} }
// Assume anything else is 4:3. // Assume anything else is 4:3.
return 0; else
{
ratio = 0;
}
if (trueratio != NULL)
{
*trueratio = ratio;
}
return (fakeratio >= 0) ? fakeratio : ratio;
} }
// First column: Base width (unused) // First column: Base width (unused)

View file

@ -364,6 +364,9 @@ public:
// Set the rect defining the area affected by blending. // Set the rect defining the area affected by blending.
virtual void SetBlendingRect (int x1, int y1, int x2, int y2); virtual void SetBlendingRect (int x1, int y1, int x2, int y2);
// Remap voxel palette
virtual void RemapVoxels();
// render 3D view // render 3D view
virtual void RenderView(player_t *player); virtual void RenderView(player_t *player);
@ -500,7 +503,7 @@ void V_DrawFrame (int left, int top, int width, int height);
extern "C" void ASM_PatchPitch (void); extern "C" void ASM_PatchPitch (void);
#endif #endif
int CheckRatio (int width, int height); int CheckRatio (int width, int height, int *trueratio=NULL);
static inline int CheckRatio (double width, double height) { return CheckRatio(int(width), int(height)); } static inline int CheckRatio (double width, double height) { return CheckRatio(int(width), int(height)); }
extern const int BaseRatioSizes[5][4]; extern const int BaseRatioSizes[5][4];

View file

@ -64,7 +64,7 @@
// Protocol version used in demos. // Protocol version used in demos.
// Bump it if you change existing DEM_ commands or add new ones. // Bump it if you change existing DEM_ commands or add new ones.
// Otherwise, it should be safe to leave it alone. // Otherwise, it should be safe to leave it alone.
#define DEMOGAMEVERSION 0x213 #define DEMOGAMEVERSION 0x214
// Minimum demo version we can play. // Minimum demo version we can play.
// Bump it whenever you change or remove existing DEM_ commands. // Bump it whenever you change or remove existing DEM_ commands.
@ -75,7 +75,7 @@
// SAVESIG should match SAVEVER. // SAVESIG should match SAVEVER.
// MINSAVEVER is the minimum level snapshot version that can be loaded. // MINSAVEVER is the minimum level snapshot version that can be loaded.
#define MINSAVEVER 3030 #define MINSAVEVER 3085
#if SVN_REVISION_NUMBER < MINSAVEVER #if SVN_REVISION_NUMBER < MINSAVEVER
// If we don't know the current revision write something very high to ensure that // If we don't know the current revision write something very high to ensure that

View file

@ -62,6 +62,7 @@ typedef enum {
ns_bloodmisc, ns_bloodmisc,
ns_strifevoices, ns_strifevoices,
ns_hires, ns_hires,
ns_voxels,
// These namespaces are only used to mark lumps in special subdirectories // These namespaces are only used to mark lumps in special subdirectories
// so that their contents doesn't interfere with the global namespace. // so that their contents doesn't interfere with the global namespace.

View file

@ -3677,6 +3677,14 @@ bool D3DFB::SetStyle(D3DTex *tex, DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &
alpha = clamp<fixed_t> (parms.alpha, 0, FRACUNIT) / 65536.f; alpha = clamp<fixed_t> (parms.alpha, 0, FRACUNIT) / 65536.f;
} }
style.CheckFuzz();
if (style.BlendOp == STYLEOP_Shadow)
{
style = LegacyRenderStyles[STYLE_TranslucentStencil];
alpha = 0.3f;
parms.fillcolor = 0;
}
// FIXME: Fuzz effect is not written // FIXME: Fuzz effect is not written
if (style.BlendOp == STYLEOP_FuzzOrAdd || style.BlendOp == STYLEOP_Fuzz) if (style.BlendOp == STYLEOP_FuzzOrAdd || style.BlendOp == STYLEOP_Fuzz)
{ {

View file

@ -28,6 +28,7 @@ ACTOR ClericPlayer : PlayerPawn
Player.WeaponSlot 2, CWeapStaff Player.WeaponSlot 2, CWeapStaff
Player.WeaponSlot 3, CWeapFlame Player.WeaponSlot 3, CWeapFlame
Player.WeaponSlot 4, CWeapWraithverge Player.WeaponSlot 4, CWeapWraithverge
Player.FlechetteType "ArtiPoisonBag1"
Player.ColorRange 146, 163 Player.ColorRange 146, 163
Player.Colorset 0, "Blue", 146, 163, 161 Player.Colorset 0, "Blue", 146, 163, 161

View file

@ -30,6 +30,7 @@ ACTOR MagePlayer : PlayerPawn
Player.WeaponSlot 2, MWeapFrost Player.WeaponSlot 2, MWeapFrost
Player.WeaponSlot 3, MWeapLightning Player.WeaponSlot 3, MWeapLightning
Player.WeaponSlot 4, MWeapBloodscourge Player.WeaponSlot 4, MWeapBloodscourge
Player.FlechetteType "ArtiPoisonBag2"
Player.ColorRange 146, 163 Player.ColorRange 146, 163
Player.Colorset 0, "Blue", 146, 163, 161 Player.Colorset 0, "Blue", 146, 163, 161

View file

@ -28,6 +28,7 @@ Actor PlayerPawn : Actor native
Player.SoundClass "player" Player.SoundClass "player"
Player.DamageScreenColor "ff 00 00" Player.DamageScreenColor "ff 00 00"
Player.MugShotMaxHealth 0 Player.MugShotMaxHealth 0
Player.FlechetteType "ArtiPoisonBag3"
} }
Actor PlayerChunk : PlayerPawn native Actor PlayerChunk : PlayerPawn native

View file

@ -26,7 +26,6 @@ IWad
Game = "Doom" Game = "Doom"
Config = "UrbanBrawl" Config = "UrbanBrawl"
Mapinfo = "mapinfo/urbanbrawl.txt" Mapinfo = "mapinfo/urbanbrawl.txt"
Compatibility = "Portals"
MustContain = "MAP01", "AD2LIB" MustContain = "MAP01", "AD2LIB"
BannerColors = "a8 a8 00", "a8 00 00" BannerColors = "a8 a8 00", "a8 00 00"
} }

View file

@ -640,6 +640,13 @@ OptionValue Contrast
2.0, "Smooth" 2.0, "Smooth"
} }
OptionValue Fuzziness
{
0.0, "Translucent"
1.0, "Fuzz"
2.0, "Shadow"
}
OptionMenu "VideoOptions" OptionMenu "VideoOptions"
{ {
Title "DISPLAY OPTIONS" Title "DISPLAY OPTIONS"
@ -662,7 +669,7 @@ OptionMenu "VideoOptions"
} }
Option "Stretch short skies", "r_stretchsky", "OnOff" Option "Stretch short skies", "r_stretchsky", "OnOff"
Option "Use fuzz effect", "r_drawfuzz", "YesNo" Option "Use fuzz effect", "r_drawfuzz", "Fuzziness"
Slider "Lost Soul translucency", "transsouls", 0.25, 1.0, 0.05, 2 Slider "Lost Soul translucency", "transsouls", 0.25, 1.0, 0.05, 2
Option "Use fake contrast", "r_fakecontrast", "Contrast" Option "Use fake contrast", "r_fakecontrast", "Contrast"
Option "Rocket Trails", "cl_rockettrails", "RocketTrailTypes" Option "Rocket Trails", "cl_rockettrails", "RocketTrailTypes"

View file

@ -114,29 +114,26 @@ statusbar Normal
drawimage "ARMCLS", 255, 178; drawimage "ARMCLS", 255, 178;
drawnumber 2, HUDFONT_RAVEN, untranslated, armorclass, 275, 176, 1; drawnumber 2, HUDFONT_RAVEN, untranslated, armorclass, 275, 176, 1;
playerclass Cleric playertype ClericPlayer
{ {
drawimage "WPSLOT1", 190, 162; drawimage "WPSLOT1", 190, 162;
hasweaponpiece CWeapWraithverge, 1 ininventory CWeapWraithverge
{ {
drawimage "WPIECEC1", 190, 162; drawimage "WPFULL1", 190, 162;
} }
hasweaponpiece CWeapWraithverge, 2 else
{
drawimage "WPIECEC2", 212, 162;
}
hasweaponpiece CWeapWraithverge, 3
{
drawimage "WPIECEC3", 225, 162;
}
hasweaponpiece CWeapWraithverge, 1
{ {
hasweaponpiece CWeapWraithverge, 1
{
drawimage "WPIECEC1", 190, 162;
}
hasweaponpiece CWeapWraithverge, 2 hasweaponpiece CWeapWraithverge, 2
{ {
hasweaponpiece CWeapWraithverge, 3 drawimage "WPIECEC2", 212, 162;
{ }
drawimage "WPFULL1", 190, 162; hasweaponpiece CWeapWraithverge, 3
} {
drawimage "WPIECEC3", 225, 162;
} }
} }
@ -145,29 +142,26 @@ statusbar Normal
else else
drawgem translatable, interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193; drawgem translatable, interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193;
} }
else playerclass Mage else playertype MagePlayer
{ {
drawimage "WPSLOT2", 190, 162; drawimage "WPSLOT2", 190, 162;
hasweaponpiece MWeapBloodscourge, 1 ininventory MWeapBloodscourge
{ {
drawimage "WPIECEM1", 190, 162; drawimage "WPFULL2", 190, 162;
} }
hasweaponpiece MWeapBloodscourge, 2 else
{
drawimage "WPIECEM2", 205, 162;
}
hasweaponpiece MWeapBloodscourge, 3
{
drawimage "WPIECEM3", 224, 162;
}
hasweaponpiece MWeapBloodscourge, 1
{ {
hasweaponpiece MWeapBloodscourge, 1
{
drawimage "WPIECEM1", 190, 162;
}
hasweaponpiece MWeapBloodscourge, 2 hasweaponpiece MWeapBloodscourge, 2
{ {
hasweaponpiece MWeapBloodscourge, 3 drawimage "WPIECEM2", 205, 162;
{ }
drawimage "WPFULL2", 190, 162; hasweaponpiece MWeapBloodscourge, 3
} {
drawimage "WPIECEM3", 224, 162;
} }
} }
@ -179,26 +173,23 @@ statusbar Normal
else else
{ {
drawimage "WPSLOT0", 190, 162; drawimage "WPSLOT0", 190, 162;
hasweaponpiece FWeapQuietus, 1 ininventory FWeapQuietus
{ {
drawimage "WPIECEF1", 190, 162; drawimage "WPFULL0", 190, 162;
} }
hasweaponpiece FWeapQuietus, 2 else
{
drawimage "WPIECEF2", 225, 162;
}
hasweaponpiece FWeapQuietus, 3
{
drawimage "WPIECEF3", 234, 162;
}
hasweaponpiece FWeapQuietus, 1
{ {
hasweaponpiece FWeapQuietus, 1
{
drawimage "WPIECEF1", 190, 162;
}
hasweaponpiece FWeapQuietus, 2 hasweaponpiece FWeapQuietus, 2
{ {
hasweaponpiece FWeapQuietus, 3 drawimage "WPIECEF2", 225, 162;
{ }
drawimage "WPFULL0", 190, 162; hasweaponpiece FWeapQuietus, 3
} {
drawimage "WPIECEF3", 234, 162;
} }
} }
@ -222,21 +213,21 @@ statusbar Automap
drawimage hexenarmor amulet, "ARMSLOT4", 243, 164; drawimage hexenarmor amulet, "ARMSLOT4", 243, 164;
// Also draw the life gem here // Also draw the life gem here
playerclass Fighter playertype FighterPlayer
{ {
gamemode singleplayer gamemode singleplayer
drawgem interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; drawgem interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193;
else else
drawgem translatable, interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; drawgem translatable, interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193;
} }
else playerclass Cleric else playertype ClericPlayer
{ {
gamemode singleplayer gamemode singleplayer
drawgem interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193; drawgem interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193;
else else
drawgem translatable, interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193; drawgem translatable, interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193;
} }
else playerclass Mage else playertype MagePlayer
{ {
gamemode singleplayer gamemode singleplayer
drawgem interpolate(6), "CHAIN3", "LIFEGMM2", -23, 49, 15, 30, 193; drawgem interpolate(6), "CHAIN3", "LIFEGMM2", -23, 49, 15, 30, 193;

View file

@ -704,6 +704,10 @@
RelativePath=".\src\md5.cpp" RelativePath=".\src\md5.cpp"
> >
</File> </File>
<File
RelativePath=".\src\memarena.cpp"
>
</File>
<File <File
RelativePath=".\src\name.cpp" RelativePath=".\src\name.cpp"
> >
@ -1353,6 +1357,10 @@
RelativePath=".\src\md5.h" RelativePath=".\src\md5.h"
> >
</File> </File>
<File
RelativePath=".\src\memarena.h"
>
</File>
<File <File
RelativePath=".\src\mscinlines.h" RelativePath=".\src\mscinlines.h"
> >