Merge remote-tracking branch 'gzdoom/master' into ssao

This commit is contained in:
Magnus Norddahl 2016-11-27 09:59:57 +01:00
commit 057060022a
104 changed files with 2800 additions and 1999 deletions

View file

@ -94,6 +94,15 @@ function( add_pk3 PK3_NAME PK3_DIR )
SOURCES ${PK3_SRCS})
# Phase 3: Assign source files to a nice folder structure in the IDE
assort_pk3_source_folder("Source Files" ${PK3_DIR})
# Phase 4: Add the resulting PK3 to the install target.
if( WIN32 )
set( INSTALL_PK3_PATH . CACHE STRING "Directory where zdoom.pk3 will be placed during install." )
else()
set( INSTALL_PK3_PATH share/games/doom CACHE STRING "Directory where zdoom.pk3 will be placed during install." )
endif()
install(FILES "${PROJECT_BINARY_DIR}/${PK3_NAME}"
DESTINATION ${INSTALL_PK3_PATH}
COMPONENT "Game resources")
endfunction()
# Macro for building libraries without debugging information
@ -252,6 +261,7 @@ if( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB )
message( STATUS "Using system zlib, includes found at ${ZLIB_INCLUDE_DIR}" )
else()
message( STATUS "Using internal zlib" )
set( SKIP_INSTALL_ALL TRUE ) # Avoid installing zlib alongside zdoom
add_subdirectory( zlib )
set( ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/zlib )
set( ZLIB_LIBRARIES z )
@ -295,6 +305,16 @@ if( NOT CMAKE_CROSSCOMPILING )
endif()
endif()
# Install the entire docs directory in the distributed zip package
if( WIN32 )
set( INSTALL_DOCS_PATH docs CACHE STRING "Directory where the documentation will be placed during install." )
else()
set( INSTALL_DOCS_PATH share/doc/${ZDOOM_EXE_NAME} CACHE STRING "Directory where the zdoom documentation will be placed during install." )
endif()
install(DIRECTORY docs/
DESTINATION ${INSTALL_DOCS_PATH}
COMPONENT "Documentation")
add_subdirectory( lzma )
add_subdirectory( tools )
add_subdirectory( dumb )

View file

@ -87,16 +87,14 @@ conversation // Starts a dialog.
page // Starts a new page. Pages are automatically numbered starting at 1.
{
name = <string>; // Name that goes in the upper left hand corner
panel = <string>; // Name of lump to render as the background.
voice = <string>; // Narration sound lump.
dialog = <string>; // Dialog of the page.
goodbye = <string>; // Custom goodbye message. If omitted then the
// generic goodbyes will be displayed instead.
drop = <integer>; // mobj for the object to drop if the actor is
// killed.
link = <integer>; // Page to jump to if all ifitem conditions are
// satisified.
name = <string>; // Name that goes in the upper left hand corner
panel = <string>; // Name of lump to render as the background.
voice = <string>; // Narration sound lump.
dialog = <string>; // Dialog of the page.
drop = <integer>; // mobj for the object to drop if the actor is
// killed.
link = <integer>; // Page to jump to if all ifitem conditions are
// satisified.
// jumps to the specified page if the player has the specified amount
// or more of item in their inventory. This can be repeated as many

View file

@ -76,8 +76,8 @@ namespace = "ZDoom";
III.A : Conversations
---------------------
This block only lists the newly added fields. Currently ZDoom only adds one
field to the specification:
This block only lists the newly added fields. Currently ZDoom only adds a few
fields to the specification:
conversation // Starts a dialog.
{
@ -86,6 +86,35 @@ conversation // Starts a dialog.
// the standard conversation ID ('actor' property) is used instead
// for this purpose but since 'ZDoom' namespace requires the actor
// to be a class name it needs a separate field for this.
page
{
goodbye = <string>; // Custom goodbye message. If omitted then the
// generic goodbyes will be displayed instead.
choice
{
// The amount of an item needed for this option to become available.
// You can have as many as needed. All require blocks must be satisfied
// to show this option.
require
{
item = <string>; // Item that is required to show this option.
amount = <integer>; // Minimum amount of the item needed.
}
// The undesired amount of an item. This option will become available
// if you have less than the specified amount. You can have as many
// as needed. All exclude blocks must be satisfied to show this option.
// Note: if both require and exclude are defined then all require
// and all exclude blocks must be satisfied to show this option.
exclude
{
item = <string>; // Item that is unwanted to show this option.
amount = <integer>; // Unwanted minimum amount of the item.
}
}
}
}
===============================================================================

View file

@ -179,8 +179,12 @@ if( WIN32 )
comdlg32
ws2_32
setupapi
oleaut32
DelayImp )
oleaut32 )
if( NOT ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set( ZDOOM_LIBS ${ZDOOM_LIBS} DelayImp )
endif()
if( DX_dxguid_LIBRARY )
list( APPEND ZDOOM_LIBS "${DX_dxguid_LIBRARY}" )
endif()
@ -190,6 +194,7 @@ else()
set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES inc )
set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib )
set( NO_GTK ON )
set( DYN_GTK OFF )
# Prevent inclusion of fp.h and FixMath.h from Carbon framework
# Declarations from these files are not used but cause the following conflicts:
@ -198,6 +203,7 @@ else()
add_definitions( -D__FP__ -D__FIXMATH__ )
else()
option( NO_GTK "Disable GTK+ dialogs (Not applicable to Windows)" )
option( DYN_GTK "Load GTK+ at runtime instead of compile time" ON )
option( VALGRIND "Add special Valgrind sequences to self-modifying code" )
set( FMOD_SEARCH_PATHS
@ -213,22 +219,37 @@ else()
# Use GTK+ for the IWAD picker, if available.
if( NOT NO_GTK )
pkg_check_modules( GTK2 gtk+-2.0 )
if( GTK2_FOUND )
set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK2_LIBRARIES} )
include_directories( ${GTK2_INCLUDE_DIRS} )
link_directories( ${GTK2_LIBRARY_DIRS} )
pkg_check_modules( GTK3 gtk+-3.0 )
if( GTK3_FOUND )
if( NOT DYN_GTK )
set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK3_LIBRARIES} )
endif()
include_directories( ${GTK3_INCLUDE_DIRS} )
link_directories( ${GTK3_LIBRARY_DIRS} )
else()
set( NO_GTK ON )
pkg_check_modules( GTK2 gtk+-2.0 )
if( GTK2_FOUND )
if( NOT DYN_GTK )
set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK2_LIBRARIES} )
endif()
include_directories( ${GTK2_INCLUDE_DIRS} )
link_directories( ${GTK2_LIBRARY_DIRS} )
else()
set( NO_GTK ON )
endif()
endif()
endif()
endif()
set( NASM_NAMES nasm )
if( NO_GTK )
add_definitions( -DNO_GTK=1 )
add_definitions( -DNO_GTK )
elseif( DYN_GTK )
add_definitions( -DDYN_GTK=1 )
else()
add_definitions( -DDYN_GTK=0 )
endif()
# Non-Windows version also needs SDL except native OS X backend
if( NOT APPLE OR NOT OSX_COCOA_BACKEND )
find_package( SDL2 REQUIRED )
@ -291,6 +312,19 @@ if( NOT NO_FMOD )
if( EXISTS "${FMOD_INCLUDE_DIR}/fmod_common.h" )
set( FMOD_STUDIO YES )
set( FMOD_VERSION_FILE "fmod_common.h" )
else()
set( FMOD_STUDIO NO )
set( FMOD_VERSION_FILE "fmod.h" )
endif()
file( STRINGS "${FMOD_INCLUDE_DIR}/${FMOD_VERSION_FILE}" FMOD_VERSION_LINE REGEX "^#define[ \t]+FMOD_VERSION[ \t]+0x[0-9]+$" )
string( REGEX REPLACE "^#define[ \t]+FMOD_VERSION[ \t]+0x([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])$" "\\1.\\2.\\3" FMOD_VERSION "${FMOD_VERSION_LINE}" )
message( STATUS "FMOD version: ${FMOD_VERSION}" )
# FMOD Ex didn't hide xiph symbols in the past (not applicable to Win32 since symbols are hidden by default there).
if( NOT WIN32 AND NOT FMOD_STUDIO AND NOT NO_OPENAL AND "${FMOD_VERSION}" VERSION_LESS "4.36.00")
message( SEND_ERROR "Use of FMOD Ex ${FMOD_VERSION} with OpenAL will result in crashes. Either update FMOD to 4.36 or later or set NO_OPENAL." )
endif()
else()
message( STATUS "Could not find FMOD include files" )
@ -702,7 +736,8 @@ set( PLAT_SDL_SOURCES
posix/sdl/sdlglvideo.cpp
posix/sdl/st_start.cpp )
set( PLAT_UNIX_SOURCES
posix/unix/i_specialpaths.cpp )
posix/unix/i_specialpaths.cpp
posix/unix/iwadpicker_gtk.cpp )
set( PLAT_OSX_SOURCES
posix/osx/iwadpicker_cocoa.mm
posix/osx/i_specialpaths.mm
@ -724,15 +759,7 @@ if( WIN32 )
set( SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} )
set( OTHER_SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} ${PLAT_UNIX_SOURCES} )
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
# CMake is not set up to compile and link rc files with GCC. :(
add_custom_command( OUTPUT zdoom-rc.o
COMMAND windres -o zdoom-rc.o -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zdoom.rc
DEPENDS win32/zdoom.rc )
set( SYSTEM_SOURCES ${SYSTEM_SOURCES} zdoom-rc.o )
else()
set( SYSTEM_SOURCES ${SYSTEM_SOURCES} win32/zdoom.rc )
endif()
set( SYSTEM_SOURCES ${SYSTEM_SOURCES} win32/zdoom.rc )
elseif( APPLE )
if( OSX_COCOA_BACKEND )
set( SYSTEM_SOURCES_DIR posix posix/cocoa )
@ -1210,6 +1237,7 @@ set (PCH_SOURCES
gi.cpp
gitinfo.cpp
hu_scores.cpp
i_module.cpp
i_net.cpp
info.cpp
keysections.cpp
@ -1565,6 +1593,15 @@ if( APPLE )
endif()
endif()
if( WIN32 )
set( INSTALL_PATH . CACHE STRING "Directory where the zdoom executable will be placed during install." )
else()
set( INSTALL_PATH bin CACHE STRING "Directory where the zdoom executable will be placed during install." )
endif()
install(TARGETS zdoom
DESTINATION ${INSTALL_PATH}
COMPONENT "Game executable")
source_group("Assembly Files\\ia32" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/asm_ia32/.+")
source_group("Assembly Files\\x86_64" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/asm_x86_64/.+")
source_group("Audio Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/.+")

View file

@ -2046,7 +2046,8 @@ void AM_drawSubsectors()
scale / scaley,
rotation,
colormap,
floorlight
floorlight,
f_y + f_h
);
}
}

View file

@ -198,7 +198,10 @@ SetTiltedSpanSize:
mov [y8+2],cl
mov [y9+2],cl
mov [y10+2],cl
cmp eax,0 ; if x bits is 0, mask must be 0 too.
jz .notted
not eax
.notted:
pop ecx
mov [m1+2],eax

View file

@ -358,7 +358,7 @@ void DBot::WhatToGet (AActor *item)
}
else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere)
return;
else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && player->mo->health >= deh.MaxHealth /*MAXHEALTH*/)
else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && player->mo->health >= player->mo->GetMaxHealth() + player->mo->stamina)
return;
if ((dest == NULL ||

File diff suppressed because it is too large Load diff

View file

@ -168,6 +168,9 @@ public:
// [CW] Fades for when you are being damaged.
PalEntry DamageFade;
// [SP] ViewBob Multiplier
double ViewBob;
bool UpdateWaterLevel (bool splash);
bool ResetAirSupply (bool playgasp = true);

View file

@ -71,6 +71,9 @@ extern bool netgame;
// Bot game? Like netgame, but doesn't involve network communication.
extern bool multiplayer;
// [SP] Map dm/coop implementation - invokes fake multiplayer without bots
extern bool multiplayernext;
// Flag: true only if started as net deathmatch.
EXTERN_CVAR (Int, deathmatch)

View file

@ -164,6 +164,7 @@ bool viewactive;
bool netgame; // only true if packets are broadcast
bool multiplayer;
bool multiplayernext = false; // [SP] Map coop/dm implementation
player_t players[MAXPLAYERS];
bool playeringame[MAXPLAYERS];
@ -1171,7 +1172,7 @@ void G_Ticker ()
}
// check for turbo cheats
if (cmd->ucmd.forwardmove > TURBOTHRESHOLD &&
if (turbo > 100.f && cmd->ucmd.forwardmove > TURBOTHRESHOLD &&
!(gametic&31) && ((gametic>>5)&(MAXPLAYERS-1)) == i )
{
Printf ("%s is turbo!\n", players[i].userinfo.GetName());
@ -1655,9 +1656,10 @@ static void G_QueueBody (AActor *body)
//
// G_DoReborn
//
EXTERN_CVAR(Bool, sv_singleplayerrespawn)
void G_DoReborn (int playernum, bool freshbot)
{
if (!multiplayer && !(level.flags2 & LEVEL2_ALLOWRESPAWN))
if (!multiplayer && !(level.flags2 & LEVEL2_ALLOWRESPAWN) && !sv_singleplayerrespawn)
{
if (BackupSaveName.Len() > 0 && FileExists (BackupSaveName.GetChars()))
{ // Load game from the last point it was saved

View file

@ -90,6 +90,8 @@
#include "g_hub.h"
#include <string.h>
void STAT_StartNewGame(const char *lev);
void STAT_ChangeLevel(const char *newl);
@ -181,6 +183,16 @@ CCMD (map)
}
else
{
if (argv.argc() > 2 && stricmp(argv[2], "coop") == 0)
{
deathmatch = false;
multiplayernext = true;
}
else if (argv.argc() > 2 && stricmp(argv[2], "dm") == 0)
{
deathmatch = true;
multiplayernext = true;
}
G_DeferedInitNew (argv[1]);
}
}
@ -192,7 +204,7 @@ CCMD (map)
}
else
{
Printf ("Usage: map <map name>\n");
Printf ("Usage: map <map name> [coop|dm]\n");
}
}
@ -218,6 +230,16 @@ CCMD(recordmap)
}
else
{
if (argv.argc() > 3 && stricmp(argv[3], "coop") == 0)
{
deathmatch = false;
multiplayernext = true;
}
else if (argv.argc() > 3 && stricmp(argv[3], "dm") == 0)
{
deathmatch = true;
multiplayernext = true;
}
G_DeferedInitNew(argv[2]);
gameaction = ga_recordgame;
newdemoname = argv[1];
@ -232,7 +254,7 @@ CCMD(recordmap)
}
else
{
Printf("Usage: recordmap <filename> <map name>\n");
Printf("Usage: recordmap <filename> <map name> [coop|dm]\n");
}
}
@ -258,13 +280,23 @@ CCMD (open)
}
else
{
if (argv.argc() > 2 && stricmp(argv[2], "coop") == 0)
{
deathmatch = false;
multiplayernext = true;
}
else if (argv.argc() > 2 && stricmp(argv[2], "dm") == 0)
{
deathmatch = true;
multiplayernext = true;
}
gameaction = ga_newgame2;
d_skill = -1;
}
}
else
{
Printf ("Usage: open <map file>\n");
Printf ("Usage: open <map file> [coop|dm]\n");
}
}
@ -293,7 +325,8 @@ void G_NewInit ()
G_ClearSnapshots ();
ST_SetNeedRefresh();
netgame = false;
multiplayer = false;
multiplayer = multiplayernext;
multiplayernext = false;
if (demoplayback)
{
C_RestoreCVars ();
@ -526,6 +559,8 @@ static bool unloading;
//
//==========================================================================
EXTERN_CVAR(Bool, sv_singleplayerrespawn)
void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill)
{
level_info_t *nextinfo = NULL;
@ -634,7 +669,7 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
// If this is co-op, respawn any dead players now so they can
// keep their inventory on the next map.
if ((multiplayer || level.flags2 & LEVEL2_ALLOWRESPAWN) && !deathmatch && player->playerstate == PST_DEAD)
if ((multiplayer || level.flags2 & LEVEL2_ALLOWRESPAWN || sv_singleplayerrespawn) && !deathmatch && player->playerstate == PST_DEAD)
{
// Copied from the end of P_DeathThink [[
player->cls = NULL; // Force a new class if the player is using a random class

View file

@ -1508,10 +1508,18 @@ level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo)
if (sc.CheckNumber())
{ // MAPNAME is a number; assume a Hexen wad
char maptemp[8];
mysnprintf (maptemp, countof(maptemp), "MAP%02d", sc.Number);
mapname = maptemp;
HexenHack = true;
if (format_type == FMT_New)
{
mapname = sc.String;
}
else
{
char maptemp[8];
mysnprintf(maptemp, countof(maptemp), "MAP%02d", sc.Number);
mapname = maptemp;
HexenHack = true;
format_type = FMT_Old;
}
}
else
{

View file

@ -640,6 +640,7 @@ void AWeapon::PostMorphWeapon ()
pspr = Owner->player->GetPSprite(PSP_WEAPON);
pspr->y = WEAPONBOTTOM;
pspr->ResetInterpolation();
pspr->SetState(GetUpState());
}

View file

@ -241,7 +241,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
applyscale = false;
}
if(type == PLAYERICON)
texture = TexMan[statusBar->CPlayer->mo->ScoreIcon];
texture = TexMan(statusBar->CPlayer->mo->ScoreIcon);
else if(type == AMMO1)
{
AAmmo *ammo = statusBar->ammo1;
@ -270,7 +270,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
{
AInventory *item = statusBar->CPlayer->mo->FindInventory<ASigil>();
if (item != NULL)
texture = TexMan[item->Icon];
texture = TexMan(item->Icon);
}
else if(type == HEXENARMOR_ARMOR || type == HEXENARMOR_SHIELD || type == HEXENARMOR_HELM || type == HEXENARMOR_AMULET)
{
@ -290,7 +290,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
}
}
else if(type == INVENTORYICON)
texture = TexMan[sprite];
texture = TexMan(sprite);
else if(type == SELECTEDINVENTORYICON && statusBar->CPlayer->mo->InvSel != NULL)
texture = TexMan(statusBar->CPlayer->mo->InvSel->Icon);
else if(image >= 0)
@ -312,7 +312,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
spawnScaleY = item->Scale.Y;
}
texture = TexMan[icon];
texture = TexMan(icon);
}
enum ImageType
@ -2436,22 +2436,22 @@ class CommandDrawKeyBar : public SBarInfoCommand
{
if(!vertical)
{
statusBar->DrawGraphic(TexMan[item->Icon], x+slotOffset, y+rowOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets());
rowWidth = rowIconSize == -1 ? TexMan[item->Icon]->GetScaledHeight()+2 : rowIconSize;
statusBar->DrawGraphic(TexMan(item->Icon), x+slotOffset, y+rowOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets());
rowWidth = rowIconSize == -1 ? TexMan(item->Icon)->GetScaledHeight()+2 : rowIconSize;
}
else
{
statusBar->DrawGraphic(TexMan[item->Icon], x+rowOffset, y+slotOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets());
rowWidth = rowIconSize == -1 ? TexMan[item->Icon]->GetScaledWidth()+2 : rowIconSize;
statusBar->DrawGraphic(TexMan(item->Icon), x+rowOffset, y+slotOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets());
rowWidth = rowIconSize == -1 ? TexMan(item->Icon)->GetScaledWidth()+2 : rowIconSize;
}
// If cmd.special is -1 then the slot size is auto detected
if(iconSize == -1)
{
if(!vertical)
slotOffset += (reverse ? -1 : 1) * (TexMan[item->Icon]->GetScaledWidth() + 2);
slotOffset += (reverse ? -1 : 1) * (TexMan(item->Icon)->GetScaledWidth() + 2);
else
slotOffset += (reverse ? -1 : 1) * (TexMan[item->Icon]->GetScaledHeight() + 2);
slotOffset += (reverse ? -1 : 1) * (TexMan(item->Icon)->GetScaledHeight() + 2);
}
else
slotOffset += (reverse ? -iconSize : iconSize);

View file

@ -119,6 +119,7 @@ CUSTOM_CVAR(Int, am_showmaplabel, 2, CVAR_ARCHIVE)
}
CVAR (Bool, idmypos, false, 0);
CVAR(Float, underwater_fade_scalar, 1.0f, CVAR_ARCHIVE) // [Nash] user-settable underwater blend intensity
//---------------------------------------------------------------------------
//
@ -1544,7 +1545,10 @@ void DBaseStatusBar::DrawPowerups ()
void DBaseStatusBar::BlendView (float blend[4])
{
V_AddBlend (BaseBlendR / 255.f, BaseBlendG / 255.f, BaseBlendB / 255.f, BaseBlendA, blend);
// [Nash] Allow user to set blend intensity
float cnt = (BaseBlendA * underwater_fade_scalar);
V_AddBlend (BaseBlendR / 255.f, BaseBlendG / 255.f, BaseBlendB / 255.f, cnt, blend);
V_AddPlayerBlend(CPlayer, blend, 1.0f, 228);
if (screen->Accel2D || (CPlayer->camera != NULL && menuactive == MENU_Off && ConsoleState == c_up))

View file

@ -1082,6 +1082,7 @@ void gl_AttachLight(AActor *actor, unsigned int count, const FLightDefaults *lig
light->target = actor;
light->owned = true;
light->ObjectFlags |= OF_Transient;
light->flags4 |= MF4_ATTENUATE;
actor->dynamiclights.Push(light);
}
light->flags2&=~MF2_DORMANT;

View file

@ -50,6 +50,7 @@ enum
#define MF4_SUBTRACTIVE MF4_MISSILEEVENMORE
#define MF4_ADDITIVE MF4_MISSILEMORE
#define MF4_DONTLIGHTSELF MF4_SEESDAGGERS
#define MF4_ATTENUATE MF4_INCOMBAT
enum ELightType
{

View file

@ -116,7 +116,7 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FD
data[4] = r;
data[5] = g;
data[6] = b;
data[7] = 0;
data[7] = !!(light->flags4 & MF4_ATTENUATE);
return true;
}

View file

@ -216,7 +216,7 @@ public:
void FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, FDynamicColormap *colormap, int lightlevel);
DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip);
int PTM_BestColor (const uint32 *pal_in, int r, int g, int b, int first, int num);

View file

@ -140,12 +140,15 @@ static void AddLine (seg_t *seg, bool portalclip)
{
if (currentsector->sectornum == seg->backsector->sectornum)
{
FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::mid));
if (!tex || tex->UseType==FTexture::TEX_Null)
if (!seg->linedef->isVisualPortal())
{
// nothing to do here!
seg->linedef->validcount=validcount;
return;
FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::mid));
if (!tex || tex->UseType==FTexture::TEX_Null)
{
// nothing to do here!
seg->linedef->validcount=validcount;
return;
}
}
backsector=currentsector;
}

View file

@ -536,7 +536,7 @@ void GLDrawList::SortSpriteIntoWall(SortNode * head,SortNode * sort)
const bool drawBillboardFacingCamera = gl_billboard_faces_camera;
// [Nash] has +ROLLSPRITE
const bool rotated = (ss->actor != nullptr && ss->actor->renderflags & RF_ROLLSPRITE | RF_WALLSPRITE | RF_FLATSPRITE);
const bool rotated = (ss->actor != nullptr && ss->actor->renderflags & (RF_ROLLSPRITE | RF_WALLSPRITE | RF_FLATSPRITE));
// cannot sort them at the moment. This requires more complex splitting.
if (drawWithXYBillboard || drawBillboardFacingCamera || rotated)

View file

@ -82,6 +82,7 @@ CVAR(Bool, gl_sort_textures, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
EXTERN_CVAR (Bool, cl_capfps)
EXTERN_CVAR (Bool, r_deathcamera)
EXTERN_CVAR (Float, underwater_fade_scalar)
extern int viewpitch;
@ -633,7 +634,11 @@ void FGLRenderer::DrawBlend(sector_t * viewsector)
}
else if (blendv.a)
{
V_AddBlend(blendv.r / 255.f, blendv.g / 255.f, blendv.b / 255.f, blendv.a / 255.0f, blend);
// [Nash] allow user to set blend intensity
int cnt = blendv.a;
cnt = (int)(cnt * underwater_fade_scalar);
V_AddBlend(blendv.r / 255.f, blendv.g / 255.f, blendv.b / 255.f, cnt / 255.0f, blend);
}
}

View file

@ -66,7 +66,7 @@ struct GLSeg
// we do not use the vector math inlines here because they are not optimized for speed but accuracy in the playsim
float x = y2 - y1;
float y = x1 - x2;
float length = sqrt(x*x + y*y);
float length = sqrtf(x*x + y*y);
return FVector3(x / length, 0, y / length);
}
};

View file

@ -464,7 +464,7 @@ void OpenGLFrameBuffer::Clear(int left, int top, int right, int bottom, int palc
void OpenGLFrameBuffer::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, FDynamicColormap *colormap, int lightlevel)
DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip)
{
if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr && npoints >= 3)
{

View file

@ -71,7 +71,7 @@ public:
void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, FDynamicColormap *colormap, int lightlevel);
DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip);
FNativePalette *CreatePalette(FRemapTable *remap);

101
src/i_module.cpp Normal file
View file

@ -0,0 +1,101 @@
/*
** i_module.cpp
**
**---------------------------------------------------------------------------
** Copyright 2016 Braden Obrzut
** 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 "i_module.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define USE_WINDOWS_DWORD
#else
#include <dlfcn.h>
#endif
#ifndef _WIN32
#define LoadLibrary(x) dlopen((x), RTLD_LAZY)
#define GetProcAddress(a,b) dlsym((a),(b))
#define FreeLibrary(x) dlclose((x))
using HMODULE = void*;
#endif
bool FModule::Load(std::initializer_list<const char*> libnames)
{
for(auto lib : libnames)
{
if(!Open(lib))
continue;
StaticProc *proc;
for(proc = reqSymbols;proc;proc = proc->Next)
{
if(!(proc->Call = GetSym(proc->Name)) && !proc->Optional)
{
Unload();
break;
}
}
if(IsLoaded())
return true;
}
return false;
}
void FModule::Unload()
{
if(handle)
{
FreeLibrary((HMODULE)handle);
handle = nullptr;
}
}
bool FModule::Open(const char* lib)
{
#ifdef _WIN32
if((handle = GetModuleHandle(lib)) != nullptr)
return true;
#else
// Loading an empty string in Linux doesn't do what we expect it to.
if(*lib == '\0')
return false;
#endif
handle = LoadLibrary(lib);
return handle != nullptr;
}
void *FModule::GetSym(const char* name)
{
return (void *)GetProcAddress((HMODULE)handle, name);
}

229
src/i_module.h Normal file
View file

@ -0,0 +1,229 @@
/*
** i_module.h
**
**---------------------------------------------------------------------------
** Copyright 2016 Braden Obrzut
** 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.
**---------------------------------------------------------------------------
**
*/
#pragma once
#include <assert.h>
#include <initializer_list>
/* FModule Run Time Library Loader
*
* This provides an interface for loading optional dependencies or detecting
* version specific symbols at run time. These classes largely provide an
* interface for statically declaring the symbols that are going to be used
* ahead of time, thus should not be used on the stack or as part of a
* dynamically allocated object. The procedure templates take the FModule
* as a template argument largely to make such use of FModule awkward.
*
* Declared procedures register themselves with FModule and the module will not
* be considered loaded unless all required procedures can be resolved. In
* order to remove the need for boilerplate code, optional procedures do not
* enforce the requirement that the value is null checked before use. As a
* debugging aid debug builds will check that operator bool was called at some
* point, but this is just a first order sanity check.
*/
class FModule;
class FStaticModule;
template<FModule &Module, typename Proto>
class TOptProc;
template<FModule &Module, typename Proto>
class TReqProc;
template<FStaticModule &Module, typename Proto, Proto Sym>
class TStaticProc;
class FModule
{
template<FModule &Module, typename Proto>
friend class TOptProc;
template<FModule &Module, typename Proto>
friend class TReqProc;
struct StaticProc
{
void *Call;
const char* Name;
StaticProc *Next;
bool Optional;
};
void RegisterStatic(StaticProc &proc)
{
proc.Next = reqSymbols;
reqSymbols = &proc;
}
void *handle = nullptr;
// Debugging aid
const char *name;
// Since FModule is supposed to be statically allocated it is assumed that
// reqSymbols will be initialized to nullptr avoiding initialization order
// problems with declaring procedures.
StaticProc *reqSymbols;
bool Open(const char* lib);
void *GetSym(const char* name);
public:
template<FModule &Module, typename Proto, Proto Sym>
using Opt = TOptProc<Module, Proto>;
template<FModule &Module, typename Proto, Proto Sym>
using Req = TReqProc<Module, Proto>;
FModule(const char* name) : name(name) {};
~FModule() { Unload(); }
// Load a shared library using the first library name which satisfies all
// of the required symbols.
bool Load(std::initializer_list<const char*> libnames);
void Unload();
bool IsLoaded() const { return handle != nullptr; }
};
// Null version of FModule which satisfies the API so the same code can be used
// for run time and compile time linking.
class FStaticModule
{
template<FStaticModule &Module, typename Proto, Proto Sym>
friend class TStaticProc;
const char *name;
public:
template<FStaticModule &Module, typename Proto, Proto Sym>
using Opt = TStaticProc<Module, Proto, Sym>;
template<FStaticModule &Module, typename Proto, Proto Sym>
using Req = TStaticProc<Module, Proto, Sym>;
FStaticModule(const char* name) : name(name) {};
bool Load(std::initializer_list<const char*> libnames) { return true; }
void Unload() {}
bool IsLoaded() const { return true; }
};
// Allow FModuleMaybe<DYN_XYZ> to switch based on preprocessor flag.
// Use FModuleMaybe<DYN_XYZ>::Opt and FModuleMaybe<DYN_XYZ>::Req for procs.
template<bool Dynamic>
struct TModuleType { using Type = FModule; };
template<>
struct TModuleType<false> { using Type = FStaticModule; };
template<bool Dynamic>
using FModuleMaybe = typename TModuleType<Dynamic>::Type;
// ------------------------------------------------------------------------
template<FModule &Module, typename Proto>
class TOptProc
{
FModule::StaticProc proc;
#ifndef NDEBUG
mutable bool checked = false;
#endif
// I am not a pointer
bool operator==(void*) const;
bool operator!=(void*) const;
public:
TOptProc(const char* function)
{
proc.Name = function;
proc.Optional = true;
Module.RegisterStatic(proc);
}
operator Proto() const
{
#ifndef NDEBUG
assert(checked);
#endif
return (Proto)proc.Call;
}
explicit operator bool() const
{
#ifndef NDEBUG
assert(Module.IsLoaded());
checked = true;
#endif
return proc.Call != nullptr;
}
};
template<FModule &Module, typename Proto>
class TReqProc
{
FModule::StaticProc proc;
// I am not a pointer
bool operator==(void*) const;
bool operator!=(void*) const;
public:
TReqProc(const char* function)
{
proc.Name = function;
proc.Optional = false;
Module.RegisterStatic(proc);
}
operator Proto() const
{
#ifndef NDEBUG
assert(Module.IsLoaded());
#endif
return (Proto)proc.Call;
}
explicit operator bool() const { return true; }
};
template<FStaticModule &Module, typename Proto, Proto Sym>
class TStaticProc
{
// I am not a pointer
bool operator==(void*) const;
bool operator!=(void*) const;
public:
TStaticProc(const char* function) {}
operator Proto() const { return Sym; }
explicit operator bool() const { return Sym != nullptr; }
};

View file

@ -671,6 +671,7 @@ public:
{
return FOptionMenuItem::MenuEvent(mkey, fromcontroller);
}
if (fabs(value) < FLT_EPSILON) value = 0;
SetSliderValue(clamp(value, mMin, mMax));
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
return true;

View file

@ -585,6 +585,8 @@ xx(Ifitem)
xx(Choice)
xx(Link)
xx(Goodbye)
xx(Require)
xx(Exclude)
// Special menus
xx(Mainmenu)

View file

@ -375,6 +375,7 @@ void ACSStringPool::Clear()
int ACSStringPool::AddString(const char *str)
{
if (str == nullptr) str = "";
size_t len = strlen(str);
unsigned int h = SuperFastHash(str, len);
unsigned int bucketnum = h % NUM_BUCKETS;
@ -791,6 +792,10 @@ void ACSStringPool::WriteStrings(FSerializer &file, const char *key) const
{
if (file.BeginObject(nullptr))
{
if (i == 430)
{
int a = 0;
}
file("index", i)
("string", entry->Str)
("lockcount", entry->LockCount)
@ -2907,7 +2912,8 @@ FSerializer &Serialize(FSerializer &arc, const char *key, SavingRunningscript &r
void DACSThinker::Serialize(FSerializer &arc)
{
Super::Serialize(arc);
arc("scripts", Scripts);
arc("scripts", Scripts)
("lastscript", LastScript);
if (arc.isWriting())
{
@ -5344,7 +5350,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
case ACSF_PlaySound:
case ACSF_PlayActorSound:
// PlaySound(tid, "SoundName", channel, volume, looping, attenuation)
// PlaySound(tid, "SoundName", channel, volume, looping, attenuation, local)
{
FSoundID sid;
@ -5365,6 +5371,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
float vol = argCount > 3 ? ACSToFloat(args[3]) : 1.f;
INTBOOL looping = argCount > 4 ? args[4] : false;
float atten = argCount > 5 ? ACSToFloat(args[5]) : ATTN_NORM;
INTBOOL local = argCount > 6 ? args[6] : false;
if (args[0] == 0)
{
@ -5381,11 +5388,11 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
{
if (!looping)
{
S_Sound(spot, chan, sid, vol, atten);
S_PlaySound(spot, chan, sid, vol, atten, local);
}
else if (!S_IsActorPlayingSomething(spot, chan & 7, sid))
{
S_Sound(spot, chan | CHAN_LOOP, sid, vol, atten);
S_PlaySound(spot, chan | CHAN_LOOP, sid, vol, atten, local);
}
}
}

View file

@ -1032,16 +1032,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySound)
PARAM_FLOAT_OPT (volume) { volume = 1; }
PARAM_BOOL_OPT (looping) { looping = false; }
PARAM_FLOAT_OPT (attenuation) { attenuation = ATTN_NORM; }
PARAM_BOOL_OPT (local) { local = false; }
if (!looping)
{
S_Sound (self, channel, soundid, (float)volume, (float)attenuation);
S_PlaySound(self, channel, soundid, (float)volume, (float)attenuation, local);
}
else
{
if (!S_IsActorPlayingSomething (self, channel&7, soundid))
{
S_Sound (self, channel | CHAN_LOOP, soundid, (float)volume, (float)attenuation);
S_PlaySound(self, channel | CHAN_LOOP, soundid, (float)volume, (float)attenuation, local);
}
}
return 0;

View file

@ -252,7 +252,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc
if ((type == 1 && !isbinary) || (type == 2 && isbinary))
{
DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum));
DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum));
return false;
}
@ -272,7 +272,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc
// is exactly 1516 bytes long.
if (numnodes % 1516 != 0)
{
DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum));
DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum));
return false;
}
numnodes /= 1516;
@ -282,7 +282,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc
// And the teaser version has 1488-byte entries.
if (numnodes % 1488 != 0)
{
DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum));
DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum));
return false;
}
numnodes /= 1488;
@ -516,6 +516,8 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses)
reply->ItemCheck[k].Item = dyn_cast<PClassInventory>(GetStrifeType(rsp->Item[k]));
reply->ItemCheck[k].Amount = rsp->Count[k];
}
reply->ItemCheckRequire.Clear();
reply->ItemCheckExclude.Clear();
// If the first item check has a positive amount required, then
// add that to the reply string. Otherwise, use the reply as-is.
@ -656,6 +658,38 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
else if (self > 1.f) self = 1.f;
}
//============================================================================
//
// ShouldSkipReply
//
// Determines whether this reply should be skipped or not.
//
//============================================================================
static bool ShouldSkipReply(FStrifeDialogueReply *reply, player_t *player)
{
if (reply->Reply == nullptr)
return true;
int i;
for (i = 0; i < (int)reply->ItemCheckRequire.Size(); ++i)
{
if (!CheckStrifeItem(player, reply->ItemCheckRequire[i].Item, reply->ItemCheckRequire[i].Amount))
{
return true;
}
}
for (i = 0; i < (int)reply->ItemCheckExclude.Size(); ++i)
{
if (CheckStrifeItem(player, reply->ItemCheckExclude[i].Item, reply->ItemCheckExclude[i].Amount))
{
return true;
}
}
return false;
}
//============================================================================
//
// The conversation menu
@ -673,6 +707,7 @@ class DConversationMenu : public DMenu
bool mShowGold;
FStrifeDialogueNode *mCurNode;
int mYpos;
player_t *mPlayer;
public:
static int mSelection;
@ -683,9 +718,10 @@ public:
//
//=============================================================================
DConversationMenu(FStrifeDialogueNode *CurNode)
DConversationMenu(FStrifeDialogueNode *CurNode, player_t *player)
{
mCurNode = CurNode;
mPlayer = player;
mDialogueLines = NULL;
mShowGold = false;
@ -720,7 +756,7 @@ public:
int i,j;
for (reply = CurNode->Children, i = 1; reply != NULL; reply = reply->Next)
{
if (reply->Reply == NULL)
if (ShouldSkipReply(reply, mPlayer))
{
continue;
}
@ -778,6 +814,13 @@ public:
}
ConversationMenuY = mYpos;
//ConversationMenu.indent = 50;
// Because replies can be selectively hidden mResponses.Size() won't be consistent.
// So make sure mSelection doesn't exceed mResponses.Size(). [FishyClockwork]
if (mSelection >= (int)mResponses.Size())
{
mSelection = mResponses.Size() - 1;
}
}
//=============================================================================
@ -839,12 +882,24 @@ public:
}
else
{
// Send dialogue and reply numbers across the wire.
assert((unsigned)mCurNode->ThisNodeNum < StrifeDialogues.Size());
assert(StrifeDialogues[mCurNode->ThisNodeNum] == mCurNode);
// This is needed because mSelection represents the replies currently being displayed which will
// not match up with what's supposed to be selected if there are any hidden/skipped replies. [FishyClockwork]
FStrifeDialogueReply *reply = mCurNode->Children;
int replynum = mSelection;
for (int i = 0; i <= mSelection && reply != nullptr; reply = reply->Next)
{
if (ShouldSkipReply(reply, mPlayer))
replynum++;
else
i++;
}
// Send dialogue and reply numbers across the wire.
Net_WriteByte(DEM_CONVREPLY);
Net_WriteWord(mCurNode->ThisNodeNum);
Net_WriteByte(mSelection);
Net_WriteByte(replynum);
}
Close();
return true;
@ -1169,7 +1224,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
S_Sound (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM);
}
DConversationMenu *cmenu = new DConversationMenu(CurNode);
DConversationMenu *cmenu = new DConversationMenu(CurNode, pc->player);
if (CurNode != PrevNode)

View file

@ -45,6 +45,8 @@ struct FStrifeDialogueReply
int ActionSpecial;
int Args[5];
TArray<FStrifeDialogueItemCheck> ItemCheck;
TArray<FStrifeDialogueItemCheck> ItemCheckRequire;
TArray<FStrifeDialogueItemCheck> ItemCheckExclude;
char *Reply;
char *QuickYes;
int NextNode; // index into StrifeDialogues

View file

@ -839,9 +839,11 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
// If the floor planes on both sides match we should recalculate open.bottom at the actual position we are checking
// This is to avoid bumpy movement when crossing a linedef with the same slope on both sides.
// This should never narrow down the opening, though, only widen it.
if (open.frontfloorplane == open.backfloorplane && open.bottom > LINEOPEN_MIN)
{
open.bottom = open.frontfloorplane.ZatPoint(cres.Position);
auto newopen = open.frontfloorplane.ZatPoint(cres.Position);
if (newopen < open.bottom) open.bottom = newopen;
}
if (rail &&

View file

@ -1,4 +1,4 @@
// Emacs style mode select -*- C++ -*-
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
@ -3373,11 +3373,14 @@ void AActor::Tick ()
}
}
UnlinkFromWorld ();
flags |= MF_NOBLOCKMAP;
SetXYZ(Vec3Offset(Vel));
CheckPortalTransition(false);
LinkToWorld ();
if (!Vel.isZero() || !(flags & MF_NOBLOCKMAP))
{
UnlinkFromWorld();
flags |= MF_NOBLOCKMAP;
SetXYZ(Vec3Offset(Vel));
CheckPortalTransition(false);
LinkToWorld();
}
}
else
{
@ -4495,6 +4498,7 @@ void AActor::AdjustFloorClip ()
// Most of the player structure stays unchanged between levels.
//
EXTERN_CVAR (Bool, chasedemo)
EXTERN_CVAR(Bool, sv_singleplayerrespawn)
extern bool demonew;
@ -4682,7 +4686,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
{ // Give all cards in death match mode.
p->mo->GiveDeathmatchInventory ();
}
else if ((multiplayer || (level.flags2 & LEVEL2_ALLOWRESPAWN)) && state == PST_REBORN && oldactor != NULL)
else if ((multiplayer || (level.flags2 & LEVEL2_ALLOWRESPAWN) || sv_singleplayerrespawn) && state == PST_REBORN && oldactor != NULL)
{ // Special inventory handling for respawning in coop
p->mo->FilterCoopRespawnInventory (oldactor);
}
@ -5059,7 +5063,11 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
if (mthing->FloatbobPhase >= 0 && mthing->FloatbobPhase < 64) mobj->FloatBobPhase = mthing->FloatbobPhase;
if (mthing->Gravity < 0) mobj->Gravity = -mthing->Gravity;
else if (mthing->Gravity > 0) mobj->Gravity *= mthing->Gravity;
else mobj->flags &= ~MF_NOGRAVITY;
else
{
mobj->flags |= MF_NOGRAVITY;
mobj->Gravity = 0;
}
// For Hexen floatbob 'compatibility' we do not really want to alter the floorz.
if (mobj->specialf1 == 0 || !(mobj->flags2 & MF2_FLOATBOB) || !(ib_compatflags & BCOMPATF_FLOATBOB))

View file

@ -262,8 +262,7 @@ void DPSprite::NewTick()
while (pspr)
{
pspr->processPending = true;
pspr->oldx = pspr->x;
pspr->oldy = pspr->y;
pspr->ResetInterpolation();
pspr = pspr->Next;
}
@ -582,8 +581,9 @@ void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac)
if (curbob != 0)
{
float bobx = float(player->bob * Rangex);
float boby = float(player->bob * Rangey);
//[SP] Added in decorate player.viewbob checks
float bobx = float(player->bob * Rangex * (float)player->mo->ViewBob);
float boby = float(player->bob * Rangey * (float)player->mo->ViewBob);
switch (bobstyle)
{
case AWeapon::BobNormal:

View file

@ -29,11 +29,8 @@
#define WEAPONBOTTOM 128.
// [RH] +0x6000 helps it meet the screen bottom
// at higher resolutions while still being in
// the right spot at 320x200.
#define WEAPONTOP (32+6./16)
#define WEAPONTOP 32.
#define WEAPON_FUDGE_Y 0.375
class AInventory;
//
@ -78,6 +75,7 @@ public:
DPSprite* GetNext() { return Next; }
AActor* GetCaller() { return Caller; }
void SetCaller(AActor *newcaller) { Caller = newcaller; }
void ResetInterpolation() { oldx = x; oldy = y; }
double x, y;
double oldx, oldy;

View file

@ -640,6 +640,12 @@ static void ReadOnePlayer(FSerializer &arc, bool skipload)
playerTemp.Serialize(arc);
if (!skipload)
{
// This temp player has undefined pitch limits, so set them to something
// that should leave the pitch stored in the savegame intact when
// rendering. The real pitch limits will be set by P_SerializePlayers()
// via a net command, but that won't be processed in time for a screen
// wipe, so we need something here.
playerTemp.MaxPitch = playerTemp.MinPitch = playerTemp.mo->Angles.Pitch;
CopyPlayer(&players[i], &playerTemp, name);
}
else

View file

@ -76,11 +76,11 @@ class USDFParser : public UDMFParserBase
//===========================================================================
//
// Parse a cost block
// Parse a cost/require/exclude block
//
//===========================================================================
bool ParseCost(FStrifeDialogueReply *response)
bool ParseCostRequireExclude(FStrifeDialogueReply *response, FName type)
{
FStrifeDialogueItemCheck check;
check.Item = NULL;
@ -101,7 +101,12 @@ class USDFParser : public UDMFParserBase
}
}
response->ItemCheck.Push(check);
switch (type)
{
case NAME_Cost: response->ItemCheck.Push(check); break;
case NAME_Require: response->ItemCheckRequire.Push(check); break;
case NAME_Exclude: response->ItemCheckExclude.Push(check); break;
}
return true;
}
@ -206,8 +211,15 @@ class USDFParser : public UDMFParserBase
switch(key)
{
case NAME_Cost:
ParseCost(reply);
break;
case NAME_Require:
case NAME_Exclude:
// Require and Exclude are exclusive to namespace ZDoom. [FishyClockwork]
if (key == NAME_Cost || namespace_bits == Zd)
{
ParseCostRequireExclude(reply, key);
break;
}
// Intentional fall-through
default:
sc.UnGet();
@ -333,7 +345,11 @@ class USDFParser : public UDMFParserBase
break;
case NAME_Goodbye:
Goodbye = CheckString(key);
// Custom goodbyes are exclusive to namespace ZDoom. [FishyClockwork]
if (namespace_bits == Zd)
{
Goodbye = CheckString(key);
}
break;
}
}

View file

@ -65,6 +65,9 @@ static FRandom pr_skullpop ("SkullPop");
// [RH] # of ticks to complete a turn180
#define TURN180_TICKS ((TICRATE / 4) + 1)
// [SP] Allows respawn in single player
CVAR(Bool, sv_singleplayerrespawn, false, CVAR_SERVERINFO | CVAR_LATCH)
// Variables for prediction
CVAR (Bool, cl_noprediction, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Bool, cl_predict_specials, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
@ -651,7 +654,8 @@ void APlayerPawn::Serialize(FSerializer &arc)
("fallingscreammaxn", FallingScreamMaxSpeed, def->FallingScreamMaxSpeed)
("userange", UseRange, def->UseRange)
("aircapacity", AirCapacity, def->AirCapacity)
("viewheight", ViewHeight, def->ViewHeight);
("viewheight", ViewHeight, def->ViewHeight)
("viewbob", ViewBob, def->ViewBob);
}
//===========================================================================
@ -1891,7 +1895,7 @@ void P_CalcHeight (player_t *player)
{
bob = 0;
}
player->viewz = player->mo->Z() + player->viewheight + bob;
player->viewz = player->mo->Z() + player->viewheight + (bob * player->mo->ViewBob); // [SP] Allow DECORATE changes to view bobbing speed.
if (player->mo->Floorclip && player->playerstate != PST_DEAD
&& player->mo->Z() <= player->mo->floorz)
{
@ -2210,7 +2214,9 @@ void P_DeathThink (player_t *player)
if (level.time >= player->respawn_time || ((player->cmd.ucmd.buttons & BT_USE) && player->Bot == NULL))
{
player->cls = NULL; // Force a new class if the player is using a random class
player->playerstate = (multiplayer || (level.flags2 & LEVEL2_ALLOWRESPAWN)) ? PST_REBORN : PST_ENTER;
player->playerstate =
(multiplayer || (level.flags2 & LEVEL2_ALLOWRESPAWN) || sv_singleplayerrespawn)
? PST_REBORN : PST_ENTER;
if (player->mo->special1 > 2)
{
player->mo->special1 = 0;
@ -2671,10 +2677,11 @@ void P_PlayerThink (player_t *player)
// Apply degeneration.
if (dmflags2 & DF2_YES_DEGENERATION)
{
if ((level.time % TICRATE) == 0 && player->health > deh.MaxHealth)
int maxhealth = player->mo->GetMaxHealth() + player->mo->stamina;
if ((level.time % TICRATE) == 0 && player->health > maxhealth)
{
if (player->health - 5 < deh.MaxHealth)
player->health = deh.MaxHealth;
if (player->health - 5 < maxhealth)
player->health = maxhealth;
else
player->health--;

View file

@ -1024,7 +1024,8 @@ void P_CreateLinkedPortals()
{
if (sectors[i].GetPortalType(j) == PORTS_LINKEDPORTAL && sectors[i].PortalGroup == 0)
{
CollectSectors(sectors[i].GetOppositePortalGroup(j), &sectors[i]);
auto p = sectors[i].GetPortal(j);
CollectSectors(p->mOrigin->PortalGroup, &sectors[i]);
}
}
}

View file

@ -526,7 +526,7 @@ void ProcessMouseMoveInGame(NSEvent* theEvent)
lastX = x;
lastY = y;
if (0 != event.x | 0 != event.y)
if (0 != event.x || 0 != event.y)
{
event.type = EV_Mouse;

View file

@ -1018,7 +1018,7 @@ IOKitJoystickManager::~IOKitJoystickManager()
if (0 != notification)
{
IOObjectRelease(notification);
notification = NULL;
notification = 0;
}
}
}

View file

@ -156,7 +156,7 @@ static void I_DetectOS()
case 12: name = "macOS Sierra"; break;
}
char release[16] = {};
char release[16] = "unknown";
size_t size = sizeof release - 1;
sysctlbyname("kern.osversion", release, &size, nullptr, 0);

View file

@ -37,8 +37,6 @@
#include <pthread.h>
#include <libkern/OSAtomic.h>
#include "basictypes.h"
#include "basicinlines.h"
#include "doomdef.h"
#include "i_system.h"
#include "templates.h"

View file

@ -40,9 +40,6 @@
#include <signal.h>
#include <new>
#include <sys/param.h>
#ifndef NO_GTK
#include <gtk/gtk.h>
#endif
#include <locale.h>
#if defined(__MACH__) && !defined(NOASM)
#include <sys/types.h>
@ -87,10 +84,6 @@ void Mac_I_FatalError(const char* errortext);
// PUBLIC DATA DEFINITIONS -------------------------------------------------
#ifndef NO_GTK
bool GtkAvailable;
#endif
// The command line arguments.
DArgs *Args;
@ -259,10 +252,6 @@ int main (int argc, char **argv)
// Note that the LANG environment variable is overridden by LC_*
setenv ("LC_NUMERIC", "C", 1);
#ifndef NO_GTK
GtkAvailable = gtk_init_check (&argc, &argv);
#endif
setlocale (LC_ALL, "C");
if (SDL_Init (0) < 0)

View file

@ -34,10 +34,8 @@
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#ifndef NO_GTK
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#endif
#include <SDL.h>
#include "doomerrors.h"
#include <math.h>
@ -71,10 +69,6 @@
#include "m_fixed.h"
#include "g_level.h"
#ifdef __APPLE__
#include <ApplicationServices/ApplicationServices.h>
#endif // __APPLE__
EXTERN_CVAR (String, language)
extern "C"
@ -84,7 +78,8 @@ extern "C"
}
#ifndef NO_GTK
extern bool GtkAvailable;
bool I_GtkAvailable ();
int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad);
#elif defined(__APPLE__)
int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad);
#endif
@ -262,183 +257,6 @@ void I_PrintStr (const char *cp)
fflush (stdout);
}
#ifndef NO_GTK
// GtkTreeViews eats return keys. I want this to be like a Windows listbox
// where pressing Return can still activate the default button.
gint AllowDefault(GtkWidget *widget, GdkEventKey *event, gpointer func_data)
{
if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Return)
{
gtk_window_activate_default (GTK_WINDOW(func_data));
}
return FALSE;
}
// Double-clicking an entry in the list is the same as pressing OK.
gint DoubleClickChecker(GtkWidget *widget, GdkEventButton *event, gpointer func_data)
{
if (event->type == GDK_2BUTTON_PRESS)
{
*(int *)func_data = 1;
gtk_main_quit();
}
return FALSE;
}
// When the user presses escape, that should be the same as canceling the dialog.
gint CheckEscape (GtkWidget *widget, GdkEventKey *event, gpointer func_data)
{
if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Escape)
{
gtk_main_quit();
}
return FALSE;
}
void ClickedOK(GtkButton *button, gpointer func_data)
{
*(int *)func_data = 1;
gtk_main_quit();
}
EXTERN_CVAR (Bool, queryiwad);
int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *bbox;
GtkWidget *widget;
GtkWidget *tree;
GtkWidget *check;
GtkListStore *store;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeSelection *selection;
GtkTreeIter iter, defiter;
int close_style = 0;
int i;
char caption[100];
// Create the dialog window.
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
mysnprintf(caption, countof(caption), GAMESIG " %s: Select an IWAD to use", GetVersionString());
gtk_window_set_title (GTK_WINDOW(window), caption);
gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_container_set_border_width (GTK_CONTAINER(window), 10);
g_signal_connect (window, "delete_event", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect (window, "key_press_event", G_CALLBACK(CheckEscape), NULL);
// Create the vbox container.
vbox = gtk_vbox_new (FALSE, 10);
gtk_container_add (GTK_CONTAINER(window), vbox);
// Create the top label.
widget = gtk_label_new (GAMENAME " found more than one IWAD\nSelect from the list below to determine which one to use:");
gtk_box_pack_start (GTK_BOX(vbox), widget, false, false, 0);
gtk_misc_set_alignment (GTK_MISC(widget), 0, 0);
// Create a list store with all the found IWADs.
store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
for (i = 0; i < numwads; ++i)
{
const char *filepart = strrchr (wads[i].Path, '/');
if (filepart == NULL)
filepart = wads[i].Path;
else
filepart++;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
0, filepart,
1, wads[i].Name.GetChars(),
2, i,
-1);
if (i == defaultiwad)
{
defiter = iter;
}
}
// Create the tree view control to show the list.
tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL(store));
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("IWAD", renderer, "text", 0, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Game", renderer, "text", 1, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column);
gtk_box_pack_start (GTK_BOX(vbox), GTK_WIDGET(tree), true, true, 0);
g_signal_connect(G_OBJECT(tree), "button_press_event", G_CALLBACK(DoubleClickChecker), &close_style);
g_signal_connect(G_OBJECT(tree), "key_press_event", G_CALLBACK(AllowDefault), window);
// Select the default IWAD.
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree));
gtk_tree_selection_select_iter (selection, &defiter);
// Create the hbox for the bottom row.
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_end (GTK_BOX(vbox), hbox, false, false, 0);
// Create the "Don't ask" checkbox.
check = gtk_check_button_new_with_label ("Don't ask me this again");
gtk_box_pack_start (GTK_BOX(hbox), check, false, false, 0);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(check), !showwin);
// Create the OK/Cancel button box.
bbox = gtk_hbutton_box_new ();
gtk_button_box_set_layout (GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
gtk_box_set_spacing (GTK_BOX(bbox), 10);
gtk_box_pack_end (GTK_BOX(hbox), bbox, false, false, 0);
// Create the OK button.
widget = gtk_button_new_from_stock (GTK_STOCK_OK);
gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0);
GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT);
gtk_widget_grab_default (widget);
g_signal_connect (widget, "clicked", G_CALLBACK(ClickedOK), &close_style);
g_signal_connect (widget, "activate", G_CALLBACK(ClickedOK), &close_style);
// Create the cancel button.
widget = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0);
g_signal_connect (widget, "clicked", G_CALLBACK(gtk_main_quit), &window);
// Finally we can show everything.
gtk_widget_show_all (window);
gtk_main ();
if (close_style == 1)
{
GtkTreeModel *model;
GValue value = { 0, { {0} } };
// Find out which IWAD was selected.
gtk_tree_selection_get_selected (selection, &model, &iter);
gtk_tree_model_get_value (GTK_TREE_MODEL(model), &iter, 2, &value);
i = g_value_get_int (&value);
g_value_unset (&value);
// Set state of queryiwad based on the checkbox.
queryiwad = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check));
}
else
{
i = -1;
}
if (GTK_IS_WINDOW(window))
{
gtk_widget_destroy (window);
// If we don't do this, then the X window might not actually disappear.
while (g_main_context_iteration (NULL, FALSE)) {}
}
return i;
}
#endif
int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
{
int i;
@ -448,7 +266,7 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
return defaultiwad;
}
#if !defined(__APPLE__)
#ifndef __APPLE__
const char *str;
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
{
@ -500,12 +318,15 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
}
}
#endif
#ifndef NO_GTK
if (GtkAvailable)
if (I_GtkAvailable())
{
return I_PickIWad_Gtk (wads, numwads, showwin, defaultiwad);
}
#elif defined(__APPLE__)
#endif
#ifdef __APPLE__
return I_PickIWad_Cocoa (wads, numwads, showwin, defaultiwad);
#endif
@ -605,139 +426,19 @@ int I_FindAttr (findstate_t *fileinfo)
return 0;
}
#ifdef __APPLE__
static PasteboardRef s_clipboard;
static CFDataRef GetPasteboardData(const PasteboardItemID itemID, const CFStringRef flavorType)
{
CFDataRef data = NULL;
const OSStatus result = PasteboardCopyItemFlavorData(s_clipboard, itemID, flavorType, &data);
return noErr == result ? data : NULL;
}
#endif // __APPLE__
// Clipboard support requires GTK+
// TODO: GTK+ uses UTF-8. We don't, so some conversions would be appropriate.
void I_PutInClipboard (const char *str)
{
#ifndef NO_GTK
if (GtkAvailable)
{
GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
if (clipboard != NULL)
{
gtk_clipboard_set_text(clipboard, str, -1);
}
/* Should I? I don't know. It's not actually a selection.
clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
if (clipboard != NULL)
{
gtk_clipboard_set_text(clipboard, str, -1);
}
*/
}
#elif defined __APPLE__
if (NULL == s_clipboard)
{
PasteboardCreate(kPasteboardClipboard, &s_clipboard);
}
PasteboardClear(s_clipboard);
PasteboardSynchronize(s_clipboard);
const CFDataRef textData = CFDataCreate(kCFAllocatorDefault,
reinterpret_cast<const UInt8*>(str), strlen(str));
if (NULL != textData)
{
PasteboardPutItemFlavor(s_clipboard, PasteboardItemID(1),
CFSTR("public.utf8-plain-text"), textData, 0);
}
#endif
SDL_SetClipboardText(str);
}
FString I_GetFromClipboard (bool use_primary_selection)
{
#ifndef NO_GTK
if (GtkAvailable)
if(char *ret = SDL_GetClipboardText())
{
GtkClipboard *clipboard = gtk_clipboard_get(use_primary_selection ?
GDK_SELECTION_PRIMARY : GDK_SELECTION_CLIPBOARD);
if (clipboard != NULL)
{
gchar *text = gtk_clipboard_wait_for_text(clipboard);
if (text != NULL)
{
FString copy(text);
g_free(text);
return copy;
}
}
FString text(ret);
SDL_free(ret);
return text;
}
#elif defined __APPLE__
FString result;
if (NULL == s_clipboard)
{
PasteboardCreate(kPasteboardClipboard, &s_clipboard);
}
PasteboardSynchronize(s_clipboard);
ItemCount itemCount = 0;
PasteboardGetItemCount(s_clipboard, &itemCount);
if (0 == itemCount)
{
return FString();
}
PasteboardItemID itemID;
if (0 != PasteboardGetItemIdentifier(s_clipboard, 1, &itemID))
{
return FString();
}
if (CFDataRef data = GetPasteboardData(itemID, kUTTypeUTF8PlainText))
{
const CFIndex bufferLength = CFDataGetLength(data);
char* const buffer = result.LockNewBuffer(bufferLength);
memcpy(buffer, CFDataGetBytePtr(data), bufferLength);
result.UnlockBuffer();
}
else if (CFDataRef data = GetPasteboardData(itemID, kUTTypeUTF16PlainText))
{
#ifdef __LITTLE_ENDIAN__
static const CFStringEncoding ENCODING = kCFStringEncodingUTF16LE;
#else // __BIG_ENDIAN__
static const CFStringEncoding ENCODING = kCFStringEncodingUTF16BE;
#endif // __LITTLE_ENDIAN__
if (const CFStringRef utf16 = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, data, ENCODING))
{
const CFRange range = { 0, CFStringGetLength(utf16) };
CFIndex bufferLength = 0;
if (CFStringGetBytes(utf16, range, kCFStringEncodingUTF8, '?', false, NULL, 0, &bufferLength) > 0)
{
UInt8* const buffer = reinterpret_cast<UInt8*>(result.LockNewBuffer(bufferLength));
CFStringGetBytes(utf16, range, kCFStringEncodingUTF8, '?', false, buffer, bufferLength, NULL);
result.UnlockBuffer();
}
CFRelease(utf16);
}
}
return result;
#endif
return "";
}

View file

@ -7,8 +7,7 @@
#include <SDL.h>
#include "basictypes.h"
#include "basicinlines.h"
#include "m_fixed.h"
#include "hardware.h"
#include "i_system.h"
#include "templates.h"

View file

@ -442,6 +442,16 @@ void SDLGLFB::SetVSync( bool vsync )
#if defined (__APPLE__)
const GLint value = vsync ? 1 : 0;
CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, &value );
#else
if (vsync)
{
if (SDL_GL_SetSwapInterval(-1) == -1)
SDL_GL_SetSwapInterval(1);
}
else
{
SDL_GL_SetSwapInterval(0);
}
#endif
}

View file

@ -0,0 +1,339 @@
#ifndef NO_GTK
#if !DYN_GTK
// Function addresses will never be NULL, but that's because we're using the
// same code for both dynamic and static.
#pragma GCC diagnostic ignored "-Waddress"
#endif
#include <gtk/gtk.h>
#if GTK_MAJOR_VERSION >= 3
#include <gdk/gdk.h>
#else
#include <gdk/gdkkeysyms.h>
typedef enum
{
GTK_ALIGN_FULL,
GTK_ALIGN_START,
GTK_ALIGN_END,
GTK_ALIGN_CENTER,
GTK_ALIGN_BASELINE
} GtkAlign;
#endif
#include "c_cvars.h"
#include "d_main.h"
#include "i_module.h"
#include "i_system.h"
#include "version.h"
EXTERN_CVAR (Bool, queryiwad);
namespace Gtk {
FModuleMaybe<DYN_GTK> GtkModule{"GTK"};
static int GtkAvailable = -1;
#define DYN_GTK_SYM(x) const FModuleMaybe<DYN_GTK>::Req<GtkModule, decltype(::x)*, &x> x{#x};
#define DYN_GTK_REQ_SYM(x, proto) const FModuleMaybe<DYN_GTK>::Req<GtkModule, proto, &x> x{#x};
#if GTK_MAJOR_VERSION >= 3
#define DYN_GTK_OPT2_SYM(x, proto) const FModuleMaybe<DYN_GTK>::Opt<GtkModule, proto, nullptr> x{#x};
#define DYN_GTK_OPT3_SYM(x, proto) const FModuleMaybe<DYN_GTK>::Opt<GtkModule, proto, &x> x{#x};
#else
#define DYN_GTK_OPT2_SYM(x, proto) const FModuleMaybe<DYN_GTK>::Opt<GtkModule, proto, &x> x{#x};
#define DYN_GTK_OPT3_SYM(x, proto) const FModuleMaybe<DYN_GTK>::Opt<GtkModule, proto, nullptr> x{#x};
#endif
DYN_GTK_SYM(g_main_context_iteration);
DYN_GTK_SYM(g_signal_connect_data);
DYN_GTK_SYM(g_type_check_instance_cast);
DYN_GTK_SYM(g_type_check_instance_is_a);
DYN_GTK_SYM(g_value_get_int);
DYN_GTK_SYM(g_value_unset);
DYN_GTK_SYM(gtk_box_get_type);
DYN_GTK_SYM(gtk_box_pack_end);
DYN_GTK_SYM(gtk_box_pack_start);
DYN_GTK_SYM(gtk_box_set_spacing);
DYN_GTK_SYM(gtk_button_box_get_type);
DYN_GTK_SYM(gtk_button_box_set_layout);
DYN_GTK_SYM(gtk_button_new_with_label);
DYN_GTK_SYM(gtk_cell_renderer_text_new);
DYN_GTK_SYM(gtk_check_button_new_with_label);
DYN_GTK_SYM(gtk_container_add);
DYN_GTK_SYM(gtk_container_get_type);
DYN_GTK_SYM(gtk_container_set_border_width);
DYN_GTK_SYM(gtk_init_check);
DYN_GTK_SYM(gtk_label_new);
DYN_GTK_SYM(gtk_list_store_append);
DYN_GTK_SYM(gtk_list_store_new);
DYN_GTK_SYM(gtk_list_store_set);
DYN_GTK_SYM(gtk_toggle_button_get_type);
DYN_GTK_SYM(gtk_toggle_button_set_active);
DYN_GTK_SYM(gtk_tree_model_get_type);
DYN_GTK_SYM(gtk_tree_model_get_value);
DYN_GTK_SYM(gtk_tree_selection_get_selected);
DYN_GTK_SYM(gtk_tree_selection_select_iter);
DYN_GTK_SYM(gtk_tree_view_append_column);
// Explicitly give the type so that attributes don't cause a warning.
DYN_GTK_REQ_SYM(gtk_tree_view_column_new_with_attributes, GtkTreeViewColumn *(*)(const gchar *, GtkCellRenderer *, ...));
DYN_GTK_SYM(gtk_toggle_button_get_active);
DYN_GTK_SYM(gtk_tree_view_get_selection);
DYN_GTK_SYM(gtk_tree_view_get_type);
DYN_GTK_SYM(gtk_tree_view_new_with_model);
DYN_GTK_SYM(gtk_main);
DYN_GTK_SYM(gtk_main_quit);
DYN_GTK_SYM(gtk_widget_destroy);
DYN_GTK_SYM(gtk_widget_grab_default);
DYN_GTK_SYM(gtk_widget_get_type);
DYN_GTK_SYM(gtk_widget_set_can_default);
DYN_GTK_SYM(gtk_widget_show_all);
DYN_GTK_SYM(gtk_window_activate_default);
DYN_GTK_SYM(gtk_window_get_type);
DYN_GTK_SYM(gtk_window_new);
DYN_GTK_SYM(gtk_window_set_gravity);
DYN_GTK_SYM(gtk_window_set_position);
DYN_GTK_SYM(gtk_window_set_title);
// Gtk3 Only
DYN_GTK_OPT3_SYM(gtk_box_new, GtkWidget *(*)(GtkOrientation, gint));
DYN_GTK_OPT3_SYM(gtk_button_box_new, GtkWidget *(*)(GtkOrientation));
DYN_GTK_OPT3_SYM(gtk_widget_set_halign, void(*)(GtkWidget *, GtkAlign));
DYN_GTK_OPT3_SYM(gtk_widget_set_valign, void(*)(GtkWidget *, GtkAlign));
// Gtk2 Only
DYN_GTK_OPT2_SYM(gtk_misc_get_type, GType(*)());
DYN_GTK_OPT2_SYM(gtk_hbox_new, GtkWidget *(*)(gboolean, gint));
DYN_GTK_OPT2_SYM(gtk_hbutton_box_new, GtkWidget *(*)());
DYN_GTK_OPT2_SYM(gtk_misc_set_alignment, void(*)(GtkMisc *, gfloat, gfloat));
DYN_GTK_OPT2_SYM(gtk_vbox_new, GtkWidget *(*)(gboolean, gint));
#undef DYN_GTK_SYM
#undef DYN_GTK_REQ_SYM
#undef DYN_GTK_OPT2_SYM
#undef DYN_GTK_OPT3_SYM
// GtkTreeViews eats return keys. I want this to be like a Windows listbox
// where pressing Return can still activate the default button.
static gint AllowDefault(GtkWidget *widget, GdkEventKey *event, gpointer func_data)
{
if (event->type == GDK_KEY_PRESS && event->keyval == GDK_KEY_Return)
{
gtk_window_activate_default (GTK_WINDOW(func_data));
}
return FALSE;
}
// Double-clicking an entry in the list is the same as pressing OK.
static gint DoubleClickChecker(GtkWidget *widget, GdkEventButton *event, gpointer func_data)
{
if (event->type == GDK_2BUTTON_PRESS)
{
*(int *)func_data = 1;
gtk_main_quit();
}
return FALSE;
}
// When the user presses escape, that should be the same as canceling the dialog.
static gint CheckEscape (GtkWidget *widget, GdkEventKey *event, gpointer func_data)
{
if (event->type == GDK_KEY_PRESS && event->keyval == GDK_KEY_Escape)
{
gtk_main_quit();
}
return FALSE;
}
static void ClickedOK(GtkButton *button, gpointer func_data)
{
*(int *)func_data = 1;
gtk_main_quit();
}
static int PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
{
GtkWidget *window;
GtkWidget *vbox = nullptr;
GtkWidget *hbox = nullptr;
GtkWidget *bbox = nullptr;
GtkWidget *widget;
GtkWidget *tree;
GtkWidget *check;
GtkListStore *store;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeSelection *selection;
GtkTreeIter iter, defiter;
int close_style = 0;
int i;
char caption[100];
// Create the dialog window.
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
mysnprintf(caption, countof(caption), GAMESIG " %s: Select an IWAD to use", GetVersionString());
gtk_window_set_title (GTK_WINDOW(window), caption);
gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_gravity (GTK_WINDOW(window), GDK_GRAVITY_CENTER);
gtk_container_set_border_width (GTK_CONTAINER(window), 10);
g_signal_connect (window, "delete_event", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect (window, "key_press_event", G_CALLBACK(CheckEscape), NULL);
// Create the vbox container.
if (gtk_box_new) // Gtk3
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
else if (gtk_vbox_new) // Gtk2
vbox = gtk_vbox_new (FALSE, 10);
gtk_container_add (GTK_CONTAINER(window), vbox);
// Create the top label.
widget = gtk_label_new (GAMENAME " found more than one IWAD\nSelect from the list below to determine which one to use:");
gtk_box_pack_start (GTK_BOX(vbox), widget, false, false, 0);
if (gtk_widget_set_halign && gtk_widget_set_valign) // Gtk3
{
gtk_widget_set_halign (widget, GTK_ALIGN_START);
gtk_widget_set_valign (widget, GTK_ALIGN_START);
}
else if (gtk_misc_set_alignment && gtk_misc_get_type) // Gtk2
gtk_misc_set_alignment (GTK_MISC(widget), 0, 0);
// Create a list store with all the found IWADs.
store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
for (i = 0; i < numwads; ++i)
{
const char *filepart = strrchr (wads[i].Path, '/');
if (filepart == NULL)
filepart = wads[i].Path;
else
filepart++;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
0, filepart,
1, wads[i].Name.GetChars(),
2, i,
-1);
if (i == defaultiwad)
{
defiter = iter;
}
}
// Create the tree view control to show the list.
tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL(store));
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("IWAD", renderer, "text", 0, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Game", renderer, "text", 1, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column);
gtk_box_pack_start (GTK_BOX(vbox), GTK_WIDGET(tree), true, true, 0);
g_signal_connect(G_OBJECT(tree), "button_press_event", G_CALLBACK(DoubleClickChecker), &close_style);
g_signal_connect(G_OBJECT(tree), "key_press_event", G_CALLBACK(AllowDefault), window);
// Select the default IWAD.
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree));
gtk_tree_selection_select_iter (selection, &defiter);
// Create the hbox for the bottom row.
if (gtk_box_new) // Gtk3
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
else if (gtk_hbox_new) // Gtk2
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_end (GTK_BOX(vbox), hbox, false, false, 0);
// Create the "Don't ask" checkbox.
check = gtk_check_button_new_with_label ("Don't ask me this again");
gtk_box_pack_start (GTK_BOX(hbox), check, false, false, 0);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(check), !showwin);
// Create the OK/Cancel button box.
if (gtk_button_box_new) // Gtk3
bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
else if (gtk_hbutton_box_new) // Gtk2
bbox = gtk_hbutton_box_new ();
gtk_button_box_set_layout (GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
gtk_box_set_spacing (GTK_BOX(bbox), 10);
gtk_box_pack_end (GTK_BOX(hbox), bbox, false, false, 0);
// Create the OK button.
widget = gtk_button_new_with_label ("OK");
gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0);
gtk_widget_set_can_default (widget, true);
gtk_widget_grab_default (widget);
g_signal_connect (widget, "clicked", G_CALLBACK(ClickedOK), &close_style);
g_signal_connect (widget, "activate", G_CALLBACK(ClickedOK), &close_style);
// Create the cancel button.
widget = gtk_button_new_with_label ("Cancel");
gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0);
g_signal_connect (widget, "clicked", G_CALLBACK(gtk_main_quit), &window);
// Finally we can show everything.
gtk_widget_show_all (window);
gtk_main ();
if (close_style == 1)
{
GtkTreeModel *model;
GValue value = { 0, { {0} } };
// Find out which IWAD was selected.
gtk_tree_selection_get_selected (selection, &model, &iter);
gtk_tree_model_get_value (GTK_TREE_MODEL(model), &iter, 2, &value);
i = g_value_get_int (&value);
g_value_unset (&value);
// Set state of queryiwad based on the checkbox.
queryiwad = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(check));
}
else
{
i = -1;
}
if (GTK_IS_WINDOW(window))
{
gtk_widget_destroy (window);
// If we don't do this, then the X window might not actually disappear.
while (g_main_context_iteration (NULL, FALSE)) {}
}
return i;
}
} // namespace Gtk
int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
{
return Gtk::PickIWad (wads, numwads, showwin, defaultiwad);
}
bool I_GtkAvailable()
{
using namespace Gtk;
if(GtkAvailable < 0)
{
if (!GtkModule.Load({"libgtk-3.so.0", "libgtk-x11-2.0.so.0"}))
{
GtkAvailable = 0;
return false;
}
int argc = 0;
char **argv = nullptr;
GtkAvailable = Gtk::gtk_init_check (&argc, &argv);
}
return GtkAvailable != 0;
}
#endif

83
src/posix/zdoom.xpm Normal file
View file

@ -0,0 +1,83 @@
/* XPM */
static char * zdoom_xpm[] = {
"48 48 32 1",
" c None",
". c #ADA990",
"+ c #999966",
"@ c #666666",
"# c #393939",
"$ c #555555",
"% c #996666",
"& c #777777",
"* c #5F5F5F",
"= c #333333",
"- c #4D4D4D",
"; c #868686",
"> c #969696",
", c #1C1C1C",
"' c #339933",
") c #336633",
"! c #66CC66",
"~ c #66FF66",
"{ c #66CC33",
"] c #222222",
"^ c #333300",
"/ c #292929",
"( c #040404",
"_ c #0C0C0C",
": c #663333",
"< c #996633",
"[ c #CC9966",
"} c #CC6633",
"| c #CC9999",
"1 c #FFCC99",
"2 c #FF9966",
"3 c #FFCCCC",
" ... ",
" ++@##$+ ",
" +...+%&+ ",
" %*=-*&;$=&* ",
" %**=$@;>@=&*% ",
" &**@$*@@$-.+& ",
" %$%@*..$@.. ",
" ,#@+++@@#& ",
" $,#$$@@$#=$'' ",
" )!!!~!{=],,,,]^)'!{') =/, ",
" )){'~!!'')=],=))'{)'')) /=],( ",
" )'!!'!)~'{'),)''''''')) @@/==](( ",
" ^)''')'{{''')'''''),))) $$@$/,( ",
" ,^))),))''''))'')^,__/$$$-#-(( ",
" :<[}<,_)))))))),___,]#@@-/]] ",
" :<|12<:_,,,,,_,#$$-#/,^^=^}}< ",
" :<[1}::,^,,__,#$-==/,,::^:<<< ",
" ::&+@#^,,__/)#-=/,,,,-::^<::= ",
" :*+12[:==_,$-=/,,,,/,#::::=^ ",
" #*}331}-$]-==/,,,,// ##:=^ ",
" /]<13[---],,,,,,,]_] ",
" ,:--/,___]]]]:^___/ ",
" _______,^^,^,__/# ",
" ______:::::/$,,/# ",
" ____^:::=,^^^^,^^ ",
" __,,:=^,,)))^,,= ",
" _,,),,,,,^)^^^,, ",
" ,^,,),__,^))),,^ ",
" ,,,^^,,,,,)))),, ",
" ,,,,,,,)^))))^ ",
" ,,^,,,^^)))))^ ",
" ,^^,,,,)))))), ",
" ,^,,,,))^))), ",
" ],,,,,$&&&*$# ",
" ],,,]#****$# ",
" ]]]]]^####, ",
" ]]]]*,,,,#* ",
" ,_,#@&&@*/ ",
" __$####=# ",
" ,_/$$$$$# ",
" ,,,$*$$$ ",
" ],,,$**$# ",
" ],,,@&&@# ",
" ],,,$**#= ",
" ,,=+++%$ ",
" *%%%*$ ",
" /$*$#/ ",
" ],,]] "};

View file

@ -105,6 +105,7 @@ TArray<PortalDrawseg> WallPortals(1000); // note: this array needs to go away as
subsector_t *InSubsector;
CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs?
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
void R_StoreWallRange (int start, int stop);
@ -1108,7 +1109,7 @@ void R_Subsector (subsector_t *sub)
}
else
{
basecolormap = frontsector->ColorMap;
basecolormap = (r_fullbrightignoresectorcolor && fixedlightlev >= 0) ? &FullNormalLight : frontsector->ColorMap;
}
portal = frontsector->ValidatePortal(sector_t::ceiling);
@ -1142,7 +1143,7 @@ void R_Subsector (subsector_t *sub)
}
else
{
basecolormap = frontsector->ColorMap;
basecolormap = (r_fullbrightignoresectorcolor && fixedlightlev >= 0) ? &FullNormalLight : frontsector->ColorMap;
}
// killough 3/7/98: Add (x,y) offsets to flats, add deep water check

View file

@ -59,6 +59,7 @@ static bool R_CheckForFixedLights(const BYTE *colormaps);
extern "C" {
FDynamicColormap NormalLight;
FDynamicColormap FullNormalLight; //[SP] Emulate GZDoom brightness
}
bool NormalLightHasFixedLights;
@ -72,6 +73,7 @@ struct FakeCmap
TArray<FakeCmap> fakecmaps;
BYTE *realcolormaps;
BYTE *realfbcolormaps; //[SP] For fullbright use
size_t numfakecmaps;
@ -459,6 +461,11 @@ void R_DeinitColormaps ()
delete[] realcolormaps;
realcolormaps = NULL;
}
if (realfbcolormaps != NULL)
{
delete[] realfbcolormaps;
realfbcolormaps = NULL;
}
FreeSpecialLights();
}
@ -548,9 +555,20 @@ void R_InitColormaps ()
}
}
}
// [SP] Create a copy of the colormap
if (!realfbcolormaps)
{
realfbcolormaps = new BYTE[256*NUMCOLORMAPS*fakecmaps.Size()];
memcpy(realfbcolormaps, realcolormaps, 256*NUMCOLORMAPS*fakecmaps.Size());
}
NormalLight.Color = PalEntry (255, 255, 255);
NormalLight.Fade = 0;
NormalLight.Maps = realcolormaps;
FullNormalLight.Color = PalEntry (255, 255, 255);
FullNormalLight.Fade = 0;
FullNormalLight.Maps = realfbcolormaps;
NormalLightHasFixedLights = R_CheckForFixedLights(realcolormaps);
numfakecmaps = fakecmaps.Size();

View file

@ -80,6 +80,7 @@ extern BYTE DesaturateColormap[31][256];
extern "C"
{
extern FDynamicColormap NormalLight;
extern FDynamicColormap FullNormalLight;
}
extern bool NormalLightHasFixedLights;

View file

@ -116,7 +116,6 @@ extern void (*R_DrawSpanMaskedAddClamp)(void);
// [RH] Span blit into an interleaved intermediate buffer
extern void (*R_DrawColumnHoriz)(void);
void R_DrawMaskedColumnHoriz (const BYTE *column, const FTexture::Span *spans);
// [RH] Initialize the above pointers
void R_InitColumnDrawers ();
@ -183,6 +182,7 @@ extern void (*rt_map4cols)(int sx, int yl, int yh);
#define rt_addclamp4cols rt_addclamp4cols_c
#endif
void rt_flip_posts();
void rt_draw4cols (int sx);
// [RH] Preps the temporary horizontal buffer.

View file

@ -838,6 +838,21 @@ void rt_tlaterevsubclamp4cols (int sx, int yl, int yh)
rt_revsubclamp4cols(sx, yl, yh);
}
// Reorder the posts so that they get drawn top-to-bottom instead of bottom-to-top.
void rt_flip_posts()
{
unsigned int *front = horizspan[dc_x & 3];
unsigned int *back = dc_ctspan[dc_x & 3] - 2;
while (front < back)
{
swapvalues(front[0], back[0]);
swapvalues(front[1], back[1]);
front += 2;
back -= 2;
}
}
// Copies all spans in all four columns to the screen starting at sx.
// sx should be dword-aligned.
void rt_draw4cols (int sx)
@ -1103,101 +1118,3 @@ void R_FillColumnHorizP (void)
dest += 8;
} while (--count);
}
// Same as R_DrawMaskedColumn() except that it always uses R_DrawColumnHoriz().
void R_DrawMaskedColumnHoriz (const BYTE *column, const FTexture::Span *span)
{
const fixed_t texturemid = FLOAT2FIXED(dc_texturemid);
while (span->Length != 0)
{
const int length = span->Length;
const int top = span->TopOffset;
// calculate unclipped screen coordinates for post
dc_yl = xs_RoundToInt(sprtopscreen + spryscale * top);
dc_yh = xs_RoundToInt(sprtopscreen + spryscale * (top + length) - 1);
if (sprflipvert)
{
swapvalues (dc_yl, dc_yh);
}
if (dc_yh >= mfloorclip[dc_x])
{
dc_yh = mfloorclip[dc_x] - 1;
}
if (dc_yl < mceilingclip[dc_x])
{
dc_yl = mceilingclip[dc_x];
}
if (dc_yl <= dc_yh)
{
if (sprflipvert)
{
dc_texturefrac = (dc_yl*dc_iscale) - (top << FRACBITS)
- fixed_t(CenterY * dc_iscale) - texturemid;
const fixed_t maxfrac = length << FRACBITS;
while (dc_texturefrac >= maxfrac)
{
if (++dc_yl > dc_yh)
goto nextpost;
dc_texturefrac += dc_iscale;
}
fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale;
while (endfrac < 0)
{
if (--dc_yh < dc_yl)
goto nextpost;
endfrac -= dc_iscale;
}
}
else
{
dc_texturefrac = texturemid - (top << FRACBITS)
+ (dc_yl*dc_iscale) - fixed_t((CenterY-1) * dc_iscale);
while (dc_texturefrac < 0)
{
if (++dc_yl > dc_yh)
goto nextpost;
dc_texturefrac += dc_iscale;
}
fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale;
const fixed_t maxfrac = length << FRACBITS;
if (dc_yh < mfloorclip[dc_x]-1 && endfrac < maxfrac - dc_iscale)
{
dc_yh++;
}
else while (endfrac >= maxfrac)
{
if (--dc_yh < dc_yl)
goto nextpost;
endfrac -= dc_iscale;
}
}
dc_source = column + top;
dc_dest = ylookup[dc_yl] + dc_x + dc_destorg;
dc_count = dc_yh - dc_yl + 1;
hcolfunc_pre ();
}
nextpost:
span++;
}
if (sprflipvert)
{
unsigned int *front = horizspan[dc_x&3];
unsigned int *back = dc_ctspan[dc_x&3] - 2;
// Reorder the posts so that they get drawn top-to-bottom
// instead of bottom-to-top.
while (front < back)
{
swapvalues (front[0], back[0]);
swapvalues (front[1], back[1]);
front += 2;
back -= 2;
}
}
}

View file

@ -355,7 +355,7 @@ void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight,
MaxVisForWall = (InvZtoScale * (SCREENWIDTH*r_Yaspect) /
(viewwidth*SCREENHEIGHT * FocalTangent));
MaxVisForWall = 32767.0 / MaxVisForWall;
MaxVisForFloor = 32767.0 / (viewheight * FocalLengthY / 160);
MaxVisForFloor = 32767.0 / (viewheight >> 2) * FocalLengthY / 160;
// Reset r_*Visibility vars
R_SetVisibility(R_GetVisibility());
@ -455,6 +455,8 @@ void R_CopyStackedViewParameters()
//
//==========================================================================
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
void R_SetupColormap(player_t *player)
{
realfixedcolormap = NULL;
@ -481,6 +483,11 @@ void R_SetupColormap(player_t *player)
else if (player->fixedlightlevel >= 0 && player->fixedlightlevel < NUMCOLORMAPS)
{
fixedlightlev = player->fixedlightlevel * 256;
// [SP] Emulate GZDoom's light-amp goggles.
if (r_fullbrightignoresectorcolor && fixedlightlev >= 0)
{
fixedcolormap = FullNormalLight.Maps;
}
}
}
// [RH] Inverse light for shooting the Sigil

View file

@ -221,10 +221,26 @@ void R_MapPlane (int y, int x1)
distance = planeheight * yslope[y];
ds_xstep = xs_ToFixed(32-ds_xbits, distance * xstepscale);
ds_ystep = xs_ToFixed(32-ds_ybits, distance * ystepscale);
ds_xfrac = xs_ToFixed(32-ds_xbits, distance * basexfrac) + pviewx;
ds_yfrac = xs_ToFixed(32-ds_ybits, distance * baseyfrac) + pviewy;
if (ds_xbits != 0)
{
ds_xstep = xs_ToFixed(32 - ds_xbits, distance * xstepscale);
ds_xfrac = xs_ToFixed(32 - ds_xbits, distance * basexfrac) + pviewx;
}
else
{
ds_xstep = 0;
ds_xfrac = 0;
}
if (ds_ybits != 0)
{
ds_ystep = xs_ToFixed(32 - ds_ybits, distance * ystepscale);
ds_yfrac = xs_ToFixed(32 - ds_ybits, distance * baseyfrac) + pviewy;
}
else
{
ds_ystep = 0;
ds_yfrac = 0;
}
if (plane_shade)
{
@ -357,7 +373,7 @@ void R_CalcTiltedLighting (double lval, double lend, int width)
//
//==========================================================================
void R_MapTiltedPlane (int y, int x1)
void R_MapTiltedPlane(int y, int x1)
{
int x2 = spanend[y];
int width = x2 - x1;
@ -366,18 +382,18 @@ void R_MapTiltedPlane (int y, int x1)
DWORD u, v;
int i;
iz = plane_sz[2] + plane_sz[1]*(centery-y) + plane_sz[0]*(x1-centerx);
iz = plane_sz[2] + plane_sz[1] * (centery - y) + plane_sz[0] * (x1 - centerx);
// Lighting is simple. It's just linear interpolation from start to end
if (plane_shade)
{
uz = (iz + plane_sz[0]*width) * planelightfloat;
uz = (iz + plane_sz[0] * width) * planelightfloat;
vz = iz * planelightfloat;
R_CalcTiltedLighting (vz, uz, width);
R_CalcTiltedLighting(vz, uz, width);
}
uz = plane_su[2] + plane_su[1]*(centery-y) + plane_su[0]*(x1-centerx);
vz = plane_sv[2] + plane_sv[1]*(centery-y) + plane_sv[0]*(x1-centerx);
uz = plane_su[2] + plane_su[1] * (centery - y) + plane_su[0] * (x1 - centerx);
vz = plane_sv[2] + plane_sv[1] * (centery - y) + plane_sv[0] * (x1 - centerx);
fb = ylookup[y] + x1 + dc_destorg;
@ -595,9 +611,10 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
fixed_t alpha = FLOAT2FIXED(Alpha);
//angle_t angle = (xform.Angle + xform.baseAngle).BAMs();
FTransform nulltransform;
if (picnum == skyflatnum) // killough 10/98
{ // most skies map together
FTransform nulltransform;
lightlevel = 0;
xform = &nulltransform;
nulltransform.xOffs = nulltransform.yOffs = nulltransform.baseyOffs = 0;
@ -1887,6 +1904,15 @@ void R_DrawTiltedPlane (visplane_t *pl, double _xscale, double _yscale, fixed_t
}
}
// Hack in support for 1 x Z and Z x 1 texture sizes
if (ds_ybits == 0)
{
plane_sv[2] = plane_sv[1] = plane_sv[0] = 0;
}
if (ds_xbits == 0)
{
plane_su[2] = plane_su[1] = plane_su[0] = 0;
}
#if defined(X86_ASM)
if (ds_source != ds_curtiltedsource)
R_SetTiltedSpanSource_ASM (ds_source);

View file

@ -57,6 +57,7 @@
CVAR(Bool, r_np2, true, 0)
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
//CVAR (Int, ty, 8, 0)
//CVAR (Int, tx, 8, 0)
@ -172,7 +173,7 @@ CVAR(Bool, r_drawmirrors, true, 0)
float *MaskedSWall;
float MaskedScaleY;
static void BlastMaskedColumn (void (*blastfunc)(const BYTE *pixels, const FTexture::Span *spans), FTexture *tex)
static void BlastMaskedColumn (FTexture *tex, bool useRt)
{
// calculate lighting
if (fixedcolormap == NULL && fixedlightlev < 0)
@ -197,7 +198,7 @@ static void BlastMaskedColumn (void (*blastfunc)(const BYTE *pixels, const FText
// draw the texture
const FTexture::Span *spans;
const BYTE *pixels = tex->GetColumn (maskedtexturecol[dc_x] >> FRACBITS, &spans);
blastfunc (pixels, spans);
R_DrawMaskedColumn(pixels, spans, useRt);
rw_light += rw_lightstep;
spryscale += rw_scalestep;
}
@ -313,7 +314,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
rw_scalestep = ds->iscalestep;
if (fixedlightlev >= 0)
dc_colormap = basecolormap->Maps + fixedlightlev;
dc_colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev);
else if (fixedcolormap != NULL)
dc_colormap = fixedcolormap;
@ -440,7 +441,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
{
for (dc_x = x1; dc_x < x2; ++dc_x)
{
BlastMaskedColumn (R_DrawMaskedColumn, tex);
BlastMaskedColumn (tex, false);
}
}
else
@ -455,24 +456,24 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
while ((dc_x < stop) && (dc_x & 3))
{
BlastMaskedColumn (R_DrawMaskedColumn, tex);
BlastMaskedColumn (tex, false);
dc_x++;
}
while (dc_x < stop)
{
rt_initcols();
BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++;
BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++;
BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++;
BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex);
BlastMaskedColumn (tex, true); dc_x++;
BlastMaskedColumn (tex, true); dc_x++;
BlastMaskedColumn (tex, true); dc_x++;
BlastMaskedColumn (tex, true);
rt_draw4cols (dc_x - 3);
dc_x++;
}
while (dc_x < x2)
{
BlastMaskedColumn (R_DrawMaskedColumn, tex);
BlastMaskedColumn (tex, false);
dc_x++;
}
}
@ -630,7 +631,7 @@ void R_RenderFakeWall(drawseg_t *ds, int x1, int x2, F3DFloor *rover)
}
if (fixedlightlev >= 0)
dc_colormap = basecolormap->Maps + fixedlightlev;
dc_colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev);
else if (fixedcolormap != NULL)
dc_colormap = fixedcolormap;
@ -1065,50 +1066,188 @@ void R_RenderFakeWallRange (drawseg_t *ds, int x1, int x2)
return;
}
// prevlineasm1 is like vlineasm1 but skips the loop if only drawing one pixel
inline fixed_t prevline1 (fixed_t vince, BYTE *colormap, int count, fixed_t vplce, const BYTE *bufplce, BYTE *dest)
struct WallscanSampler
{
dc_iscale = vince;
dc_colormap = colormap;
dc_count = count;
dc_texturefrac = vplce;
dc_source = bufplce;
dc_dest = dest;
return doprevline1 ();
}
WallscanSampler() { }
WallscanSampler(int y1, float swal, double yrepeat, fixed_t xoffset, FTexture *texture, const BYTE*(*getcol)(FTexture *texture, int x));
void wallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal,
double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x))
uint32_t uv_pos;
uint32_t uv_step;
uint32_t uv_max;
const BYTE *source;
uint32_t height;
};
WallscanSampler::WallscanSampler(int y1, float swal, double yrepeat, fixed_t xoffset, FTexture *texture, const BYTE*(*getcol)(FTexture *texture, int x))
{
int x, fracbits;
int y1ve[4], y2ve[4], u4, d4, z;
char bad;
float light = rw_light - rw_lightstep;
SDWORD xoffset;
BYTE *basecolormapdata;
double iscale;
height = texture->GetHeight();
// This function also gets used to draw skies. Unlike BUILD, skies are
// drawn by visplane instead of by bunch, so these checks are invalid.
//if ((uwal[x1] > viewheight) && (uwal[x2] > viewheight)) return;
//if ((dwal[x1] < 0) && (dwal[x2] < 0)) return;
if (rw_pic->UseType == FTexture::TEX_Null)
int uv_fracbits = 32 - texture->HeightBits;
if (uv_fracbits != 32)
{
return;
uv_max = height << uv_fracbits;
// Find start uv in [0-base_height[ range.
// Not using xs_ToFixed because it rounds the result and we need something that always rounds down to stay within the range.
double uv_stepd = swal * yrepeat;
double v = (dc_texturemid + uv_stepd * (y1 - CenterY + 0.5)) / height;
v = v - floor(v);
v *= height;
v *= (1 << uv_fracbits);
uv_pos = (uint32_t)v;
uv_step = xs_ToFixed(uv_fracbits, uv_stepd);
if (uv_step == 0) // To prevent divide by zero elsewhere
uv_step = 1;
}
else
{ // Hack for one pixel tall textures
uv_pos = 0;
uv_step = 0;
uv_max = 1;
}
//extern cycle_t WallScanCycles;
//clock (WallScanCycles);
source = getcol(texture, xoffset >> FRACBITS);
}
rw_pic->GetHeight(); // Make sure texture size is loaded
fracbits = 32 - rw_pic->HeightBits;
setupvline(fracbits);
xoffset = rw_offset;
basecolormapdata = basecolormap->Maps;
// Draw a column with support for non-power-of-two ranges
void wallscan_drawcol1(int x, int y1, int y2, WallscanSampler &sampler, DWORD(*draw1column)())
{
if (sampler.uv_max == 0 || sampler.uv_step == 0) // power of two
{
int count = y2 - y1;
x = x1;
//while ((umost[x] > dmost[x]) && (x < x2)) x++;
dc_source = sampler.source;
dc_dest = (ylookup[y1] + x) + dc_destorg;
dc_count = count;
dc_iscale = sampler.uv_step;
dc_texturefrac = sampler.uv_pos;
draw1column();
uint64_t step64 = sampler.uv_step;
uint64_t pos64 = sampler.uv_pos;
sampler.uv_pos = (uint32_t)(pos64 + step64 * count);
}
else
{
uint32_t uv_pos = sampler.uv_pos;
uint32_t left = y2 - y1;
while (left > 0)
{
uint32_t available = sampler.uv_max - uv_pos;
uint32_t next_uv_wrap = available / sampler.uv_step;
if (available % sampler.uv_step != 0)
next_uv_wrap++;
uint32_t count = MIN(left, next_uv_wrap);
dc_source = sampler.source;
dc_dest = (ylookup[y1] + x) + dc_destorg;
dc_count = count;
dc_iscale = sampler.uv_step;
dc_texturefrac = uv_pos;
draw1column();
left -= count;
uv_pos += sampler.uv_step * count;
if (uv_pos >= sampler.uv_max)
uv_pos -= sampler.uv_max;
}
sampler.uv_pos = uv_pos;
}
}
// Draw four columns with support for non-power-of-two ranges
void wallscan_drawcol4(int x, int y1, int y2, WallscanSampler *sampler, void(*draw4columns)())
{
if (sampler[0].uv_max == 0 || sampler[0].uv_step == 0) // power of two, no wrap handling needed
{
int count = y2 - y1;
for (int i = 0; i < 4; i++)
{
bufplce[i] = sampler[i].source;
vplce[i] = sampler[i].uv_pos;
vince[i] = sampler[i].uv_step;
uint64_t step64 = sampler[i].uv_step;
uint64_t pos64 = sampler[i].uv_pos;
sampler[i].uv_pos = (uint32_t)(pos64 + step64 * count);
}
dc_dest = (ylookup[y1] + x) + dc_destorg;
dc_count = count;
draw4columns();
}
else
{
dc_dest = (ylookup[y1] + x) + dc_destorg;
for (int i = 0; i < 4; i++)
{
bufplce[i] = sampler[i].source;
}
uint32_t left = y2 - y1;
while (left > 0)
{
// Find which column wraps first
uint32_t count = left;
for (int i = 0; i < 4; i++)
{
uint32_t available = sampler[i].uv_max - sampler[i].uv_pos;
uint32_t next_uv_wrap = available / sampler[i].uv_step;
if (available % sampler[i].uv_step != 0)
next_uv_wrap++;
count = MIN(next_uv_wrap, count);
}
// Draw until that column wraps
for (int i = 0; i < 4; i++)
{
vplce[i] = sampler[i].uv_pos;
vince[i] = sampler[i].uv_step;
}
dc_count = count;
draw4columns();
// Wrap the uv position
for (int i = 0; i < 4; i++)
{
sampler[i].uv_pos += sampler[i].uv_step * count;
if (sampler[i].uv_pos >= sampler[i].uv_max)
sampler[i].uv_pos -= sampler[i].uv_max;
}
left -= count;
}
}
}
typedef DWORD(*Draw1ColumnFuncPtr)();
typedef void(*Draw4ColumnsFuncPtr)();
void wallscan_any(
int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat,
const BYTE *(*getcol)(FTexture *tex, int x),
void(setupwallscan(int bits, Draw1ColumnFuncPtr &draw1, Draw4ColumnsFuncPtr &draw2)))
{
if (rw_pic->UseType == FTexture::TEX_Null)
return;
fixed_t xoffset = rw_offset;
rw_pic->GetHeight(); // To ensure that rw_pic->HeightBits has been set
int fracbits = 32 - rw_pic->HeightBits;
if (fracbits == 32)
{ // Hack for one pixel tall textures
fracbits = 0;
yrepeat = 0;
dc_texturemid = 0;
}
DWORD(*draw1column)();
void(*draw4columns)();
setupwallscan(fracbits, draw1column, draw4columns);
bool fixed = (fixedcolormap != NULL || fixedlightlev >= 0);
if (fixed)
@ -1119,128 +1258,175 @@ void wallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *l
palookupoffse[3] = dc_colormap;
}
for(; (x < x2) && (x & 3); ++x)
if (fixedcolormap)
dc_colormap = fixedcolormap;
else
dc_colormap = basecolormap->Maps;
float light = rw_light;
// Calculate where 4 column alignment begins and ends:
int aligned_x1 = clamp((x1 + 3) / 4 * 4, x1, x2);
int aligned_x2 = clamp(x2 / 4 * 4, x1, x2);
// First unaligned columns:
for (int x = x1; x < aligned_x1; x++, light += rw_lightstep)
{
light += rw_lightstep;
y1ve[0] = uwal[x];//max(uwal[x],umost[x]);
y2ve[0] = dwal[x];//min(dwal[x],dmost[x]);
if (y2ve[0] <= y1ve[0]) continue;
assert (y1ve[0] < viewheight);
assert (y2ve[0] <= viewheight);
int y1 = uwal[x];
int y2 = dwal[x];
if (y2 <= y1)
continue;
if (!fixed)
{ // calculate lighting
dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
dc_colormap = basecolormap->Maps + (GETPALOOKUP(light, wallshade) << COLORMAPSHIFT);
dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
dc_dest = ylookup[y1ve[0]] + x + dc_destorg;
dc_count = y2ve[0] - y1ve[0];
iscale = swal[x] * yrepeat;
dc_iscale = xs_ToFixed(fracbits, iscale);
dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5));
dovline1();
WallscanSampler sampler(y1, swal[x], yrepeat, lwal[x] + xoffset, rw_pic, getcol);
wallscan_drawcol1(x, y1, y2, sampler, draw1column);
}
for(; x < x2-3; x += 4)
// The aligned columns
for (int x = aligned_x1; x < aligned_x2; x += 4)
{
bad = 0;
for (z = 3; z>= 0; --z)
{
y1ve[z] = uwal[x+z];//max(uwal[x+z],umost[x+z]);
y2ve[z] = dwal[x+z];//min(dwal[x+z],dmost[x+z])-1;
if (y2ve[z] <= y1ve[z]) { bad += 1<<z; continue; }
assert (y1ve[z] < viewheight);
assert (y2ve[z] <= viewheight);
// Find y1, y2, light and uv values for four columns:
int y1[4] = { uwal[x], uwal[x + 1], uwal[x + 2], uwal[x + 3] };
int y2[4] = { dwal[x], dwal[x + 1], dwal[x + 2], dwal[x + 3] };
bufplce[z] = getcol (rw_pic, (lwal[x+z] + xoffset) >> FRACBITS);
iscale = swal[x + z] * yrepeat;
vince[z] = xs_ToFixed(fracbits, iscale);
vplce[z] = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[z] - CenterY + 0.5));
}
if (bad == 15)
float lights[4];
for (int i = 0; i < 4; i++)
{
light += rw_lightstep * 4;
continue;
lights[i] = light;
light += rw_lightstep;
}
if (!fixed)
WallscanSampler sampler[4];
for (int i = 0; i < 4; i++)
sampler[i] = WallscanSampler(y1[i], swal[x + i], yrepeat, lwal[x + i] + xoffset, rw_pic, getcol);
// Figure out where we vertically can start and stop drawing 4 columns in one go
int middle_y1 = y1[0];
int middle_y2 = y2[0];
for (int i = 1; i < 4; i++)
{
for (z = 0; z < 4; ++z)
middle_y1 = MAX(y1[i], middle_y1);
middle_y2 = MIN(y2[i], middle_y2);
}
// If we got an empty column in our set we cannot draw 4 columns in one go:
bool empty_column_in_set = false;
for (int i = 0; i < 4; i++)
{
if (y2[i] <= y1[i])
empty_column_in_set = true;
}
if (empty_column_in_set || middle_y2 <= middle_y1)
{
for (int i = 0; i < 4; i++)
{
light += rw_lightstep;
palookupoffse[z] = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
}
if (y2[i] <= y1[i])
continue;
u4 = MAX(MAX(y1ve[0],y1ve[1]),MAX(y1ve[2],y1ve[3]));
d4 = MIN(MIN(y2ve[0],y2ve[1]),MIN(y2ve[2],y2ve[3]));
if ((bad != 0) || (u4 >= d4))
{
for (z = 0; z < 4; ++z)
{
if (!(bad & 1))
{
prevline1(vince[z],palookupoffse[z],y2ve[z]-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+x+z+dc_destorg);
}
bad >>= 1;
if (!fixed)
dc_colormap = basecolormap->Maps + (GETPALOOKUP(lights[i], wallshade) << COLORMAPSHIFT);
wallscan_drawcol1(x + i, y1[i], y2[i], sampler[i], draw1column);
}
continue;
}
for (z = 0; z < 4; ++z)
// Draw the first rows where not all 4 columns are active
for (int i = 0; i < 4; i++)
{
if (u4 > y1ve[z])
{
vplce[z] = prevline1(vince[z],palookupoffse[z],u4-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+x+z+dc_destorg);
}
if (!fixed)
dc_colormap = basecolormap->Maps + (GETPALOOKUP(lights[i], wallshade) << COLORMAPSHIFT);
if (y1[i] < middle_y1)
wallscan_drawcol1(x + i, y1[i], middle_y1, sampler[i], draw1column);
}
if (d4 > u4)
// Draw the area where all 4 columns are active
if (!fixed)
{
dc_count = d4-u4;
dc_dest = ylookup[u4]+x+dc_destorg;
dovline4();
}
BYTE *i = x+ylookup[d4]+dc_destorg;
for (z = 0; z < 4; ++z)
{
if (y2ve[z] > d4)
for (int i = 0; i < 4; i++)
{
prevline1(vince[z],palookupoffse[0],y2ve[z]-d4,vplce[z],bufplce[z],i+z);
palookupoffse[i] = basecolormap->Maps + (GETPALOOKUP(lights[i], wallshade) << COLORMAPSHIFT);
}
}
wallscan_drawcol4(x, middle_y1, middle_y2, sampler, draw4columns);
// Draw the last rows where not all 4 columns are active
for (int i = 0; i < 4; i++)
{
if (!fixed)
dc_colormap = basecolormap->Maps + (GETPALOOKUP(lights[i], wallshade) << COLORMAPSHIFT);
if (middle_y2 < y2[i])
wallscan_drawcol1(x + i, middle_y2, y2[i], sampler[i], draw1column);
}
}
for(;x<x2;x++)
// The last unaligned columns:
for (int x = aligned_x2; x < x2; x++, light += rw_lightstep)
{
light += rw_lightstep;
y1ve[0] = uwal[x];//max(uwal[x],umost[x]);
y2ve[0] = dwal[x];//min(dwal[x],dmost[x]);
if (y2ve[0] <= y1ve[0]) continue;
assert (y1ve[0] < viewheight);
assert (y2ve[0] <= viewheight);
int y1 = uwal[x];
int y2 = dwal[x];
if (y2 <= y1)
continue;
if (!fixed)
{ // calculate lighting
dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
dc_colormap = basecolormap->Maps + (GETPALOOKUP(light, wallshade) << COLORMAPSHIFT);
dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
dc_dest = ylookup[y1ve[0]] + x + dc_destorg;
dc_count = y2ve[0] - y1ve[0];
iscale = swal[x] * yrepeat;
dc_iscale = xs_ToFixed(fracbits, iscale);
dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5));
dovline1();
WallscanSampler sampler(y1, swal[x], yrepeat, lwal[x] + xoffset, rw_pic, getcol);
wallscan_drawcol1(x, y1, y2, sampler, draw1column);
}
//unclock (WallScanCycles);
NetUpdate();
}
NetUpdate ();
void wallscan(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x))
{
wallscan_any(x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol, [](int bits, Draw1ColumnFuncPtr &line1, Draw4ColumnsFuncPtr &line4)
{
setupvline(bits);
line1 = dovline1;
line4 = dovline4;
});
}
void maskwallscan(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x))
{
if (!rw_pic->bMasked) // Textures that aren't masked can use the faster wallscan.
{
wallscan(x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol);
}
else
{
wallscan_any(x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol, [](int bits, Draw1ColumnFuncPtr &line1, Draw4ColumnsFuncPtr &line4)
{
setupmvline(bits);
line1 = domvline1;
line4 = domvline4;
});
}
}
void transmaskwallscan(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x))
{
static fixed_t(*tmvline1)();
static void(*tmvline4)();
if (!R_GetTransMaskDrawers(&tmvline1, &tmvline4))
{
// The current translucency is unsupported, so draw with regular maskwallscan instead.
maskwallscan(x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol);
}
else
{
wallscan_any(x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol, [](int bits, Draw1ColumnFuncPtr &line1, Draw4ColumnsFuncPtr &line4)
{
setuptmvline(bits);
line1 = reinterpret_cast<DWORD(*)()>(tmvline1);
line4 = tmvline4;
});
}
}
void wallscan_striped (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat)
@ -1416,358 +1602,6 @@ static void wallscan_np2_ds(drawseg_t *ds, int x1, int x2, short *uwal, short *d
}
}
inline fixed_t mvline1 (fixed_t vince, BYTE *colormap, int count, fixed_t vplce, const BYTE *bufplce, BYTE *dest)
{
dc_iscale = vince;
dc_colormap = colormap;
dc_count = count;
dc_texturefrac = vplce;
dc_source = bufplce;
dc_dest = dest;
return domvline1 ();
}
void maskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal,
double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x))
{
int x, fracbits;
BYTE *p;
int y1ve[4], y2ve[4], u4, d4, startx, dax, z;
char bad;
float light = rw_light - rw_lightstep;
SDWORD xoffset;
BYTE *basecolormapdata;
double iscale;
if (rw_pic->UseType == FTexture::TEX_Null)
{
return;
}
if (!rw_pic->bMasked)
{ // Textures that aren't masked can use the faster wallscan.
wallscan (x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol);
return;
}
//extern cycle_t WallScanCycles;
//clock (WallScanCycles);
rw_pic->GetHeight(); // Make sure texture size is loaded
fracbits = 32- rw_pic->HeightBits;
setupmvline(fracbits);
xoffset = rw_offset;
basecolormapdata = basecolormap->Maps;
x = startx = x1;
p = x + dc_destorg;
bool fixed = (fixedcolormap != NULL || fixedlightlev >= 0);
if (fixed)
{
palookupoffse[0] = dc_colormap;
palookupoffse[1] = dc_colormap;
palookupoffse[2] = dc_colormap;
palookupoffse[3] = dc_colormap;
}
for(; (x < x2) && ((size_t)p & 3); ++x, ++p)
{
light += rw_lightstep;
y1ve[0] = uwal[x];//max(uwal[x],umost[x]);
y2ve[0] = dwal[x];//min(dwal[x],dmost[x]);
if (y2ve[0] <= y1ve[0]) continue;
if (!fixed)
{ // calculate lighting
dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
dc_dest = ylookup[y1ve[0]] + p;
dc_count = y2ve[0] - y1ve[0];
iscale = swal[x] * yrepeat;
dc_iscale = xs_ToFixed(fracbits, iscale);
dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5));
domvline1();
}
for(; x < x2-3; x += 4, p+= 4)
{
bad = 0;
for (z = 3, dax = x+3; z >= 0; --z, --dax)
{
y1ve[z] = uwal[dax];
y2ve[z] = dwal[dax];
if (y2ve[z] <= y1ve[z]) { bad += 1<<z; continue; }
bufplce[z] = getcol (rw_pic, (lwal[dax] + xoffset) >> FRACBITS);
iscale = swal[dax] * yrepeat;
vince[z] = xs_ToFixed(fracbits, iscale);
vplce[z] = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[z] - CenterY + 0.5));
}
if (bad == 15)
{
light += rw_lightstep * 4;
continue;
}
if (!fixed)
{
for (z = 0; z < 4; ++z)
{
light += rw_lightstep;
palookupoffse[z] = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
}
u4 = MAX(MAX(y1ve[0],y1ve[1]),MAX(y1ve[2],y1ve[3]));
d4 = MIN(MIN(y2ve[0],y2ve[1]),MIN(y2ve[2],y2ve[3]));
if ((bad != 0) || (u4 >= d4))
{
for (z = 0; z < 4; ++z)
{
if (!(bad & 1))
{
mvline1(vince[z],palookupoffse[z],y2ve[z]-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z);
}
bad >>= 1;
}
continue;
}
for (z = 0; z < 4; ++z)
{
if (u4 > y1ve[z])
{
vplce[z] = mvline1(vince[z],palookupoffse[z],u4-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z);
}
}
if (d4 > u4)
{
dc_count = d4-u4;
dc_dest = ylookup[u4]+p;
domvline4();
}
BYTE *i = p+ylookup[d4];
for (z = 0; z < 4; ++z)
{
if (y2ve[z] > d4)
{
mvline1(vince[z],palookupoffse[0],y2ve[z]-d4,vplce[z],bufplce[z],i+z);
}
}
}
for(; x < x2; ++x, ++p)
{
light += rw_lightstep;
y1ve[0] = uwal[x];
y2ve[0] = dwal[x];
if (y2ve[0] <= y1ve[0]) continue;
if (!fixed)
{ // calculate lighting
dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
dc_dest = ylookup[y1ve[0]] + p;
dc_count = y2ve[0] - y1ve[0];
iscale = swal[x] * yrepeat;
dc_iscale = xs_ToFixed(fracbits, iscale);
dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5));
domvline1();
}
//unclock(WallScanCycles);
NetUpdate ();
}
inline void preptmvline1 (fixed_t vince, BYTE *colormap, int count, fixed_t vplce, const BYTE *bufplce, BYTE *dest)
{
dc_iscale = vince;
dc_colormap = colormap;
dc_count = count;
dc_texturefrac = vplce;
dc_source = bufplce;
dc_dest = dest;
}
void transmaskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal,
double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x))
{
fixed_t (*tmvline1)();
void (*tmvline4)();
int x, fracbits;
BYTE *p;
int y1ve[4], y2ve[4], u4, d4, startx, dax, z;
char bad;
float light = rw_light - rw_lightstep;
SDWORD xoffset;
BYTE *basecolormapdata;
double iscale;
if (rw_pic->UseType == FTexture::TEX_Null)
{
return;
}
if (!R_GetTransMaskDrawers (&tmvline1, &tmvline4))
{
// The current translucency is unsupported, so draw with regular maskwallscan instead.
maskwallscan (x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol);
return;
}
//extern cycle_t WallScanCycles;
//clock (WallScanCycles);
rw_pic->GetHeight(); // Make sure texture size is loaded
fracbits = 32 - rw_pic->HeightBits;
setuptmvline(fracbits);
xoffset = rw_offset;
basecolormapdata = basecolormap->Maps;
fixed_t centeryfrac = FLOAT2FIXED(CenterY);
x = startx = x1;
p = x + dc_destorg;
bool fixed = (fixedcolormap != NULL || fixedlightlev >= 0);
if (fixed)
{
palookupoffse[0] = dc_colormap;
palookupoffse[1] = dc_colormap;
palookupoffse[2] = dc_colormap;
palookupoffse[3] = dc_colormap;
}
for(; (x < x2) && ((size_t)p & 3); ++x, ++p)
{
light += rw_lightstep;
y1ve[0] = uwal[x];//max(uwal[x],umost[x]);
y2ve[0] = dwal[x];//min(dwal[x],dmost[x]);
if (y2ve[0] <= y1ve[0]) continue;
if (!fixed)
{ // calculate lighting
dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
dc_dest = ylookup[y1ve[0]] + p;
dc_count = y2ve[0] - y1ve[0];
iscale = swal[x] * yrepeat;
dc_iscale = xs_ToFixed(fracbits, iscale);
dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5));
tmvline1();
}
for(; x < x2-3; x += 4, p+= 4)
{
bad = 0;
for (z = 3, dax = x+3; z >= 0; --z, --dax)
{
y1ve[z] = uwal[dax];
y2ve[z] = dwal[dax];
if (y2ve[z] <= y1ve[z]) { bad += 1<<z; continue; }
bufplce[z] = getcol (rw_pic, (lwal[dax] + xoffset) >> FRACBITS);
iscale = swal[dax] * yrepeat;
vince[z] = xs_ToFixed(fracbits, iscale);
vplce[z] = xs_ToFixed(fracbits, dc_texturemid + vince[z] * (y1ve[z] - CenterY + 0.5));
}
if (bad == 15)
{
light += rw_lightstep * 4;
continue;
}
if (!fixed)
{
for (z = 0; z < 4; ++z)
{
light += rw_lightstep;
palookupoffse[z] = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
}
u4 = MAX(MAX(y1ve[0],y1ve[1]),MAX(y1ve[2],y1ve[3]));
d4 = MIN(MIN(y2ve[0],y2ve[1]),MIN(y2ve[2],y2ve[3]));
if ((bad != 0) || (u4 >= d4))
{
for (z = 0; z < 4; ++z)
{
if (!(bad & 1))
{
preptmvline1(vince[z],palookupoffse[z],y2ve[z]-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z);
tmvline1();
}
bad >>= 1;
}
continue;
}
for (z = 0; z < 4; ++z)
{
if (u4 > y1ve[z])
{
preptmvline1(vince[z],palookupoffse[z],u4-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z);
vplce[z] = tmvline1();
}
}
if (d4 > u4)
{
dc_count = d4-u4;
dc_dest = ylookup[u4]+p;
tmvline4();
}
BYTE *i = p+ylookup[d4];
for (z = 0; z < 4; ++z)
{
if (y2ve[z] > d4)
{
preptmvline1(vince[z],palookupoffse[0],y2ve[z]-d4,vplce[z],bufplce[z],i+z);
tmvline1();
}
}
}
for(; x < x2; ++x, ++p)
{
light += rw_lightstep;
y1ve[0] = uwal[x];
y2ve[0] = dwal[x];
if (y2ve[0] <= y1ve[0]) continue;
if (!fixed)
{ // calculate lighting
dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
}
dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
dc_dest = ylookup[y1ve[0]] + p;
dc_count = y2ve[0] - y1ve[0];
iscale = swal[x] * yrepeat;
dc_iscale = xs_ToFixed(fracbits, iscale);
dc_texturefrac = xs_ToFixed(fracbits, dc_texturemid + iscale * (y1ve[0] - CenterY + 0.5));
tmvline1();
}
//unclock(WallScanCycles);
NetUpdate ();
}
//
// R_RenderSegLoop
// Draws zero, one, or two textures for walls.
@ -1788,7 +1622,7 @@ void R_RenderSegLoop ()
fixed_t xoffset = rw_offset;
if (fixedlightlev >= 0)
dc_colormap = basecolormap->Maps + fixedlightlev;
dc_colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (basecolormap->Maps + fixedlightlev);
else if (fixedcolormap != NULL)
dc_colormap = fixedcolormap;
@ -2520,7 +2354,7 @@ void R_StoreWallRange (int start, int stop)
lwal = (fixed_t *)(openings + ds_p->maskedtexturecol);
swal = (float *)(openings + ds_p->swall);
FTexture *pic = TexMan(sidedef->GetTexture(side_t::mid), true);
double yscale = pic->Scale.X * sidedef->GetTextureYScale(side_t::mid);
double yscale = pic->Scale.Y * sidedef->GetTextureYScale(side_t::mid);
fixed_t xoffset = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::mid));
if (pic->bWorldPanning)
@ -3185,13 +3019,13 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper,
rereadcolormap = false;
}
rw_light = rw_lightleft + (x1 - WallC.sx1) * rw_lightstep;
rw_light = rw_lightleft + (x1 - savecoord.sx1) * rw_lightstep;
if (fixedlightlev >= 0)
dc_colormap = usecolormap->Maps + fixedlightlev;
dc_colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (usecolormap->Maps + fixedlightlev);
else if (fixedcolormap != NULL)
dc_colormap = fixedcolormap;
else if (!foggy && (decal->RenderFlags & RF_FULLBRIGHT))
dc_colormap = usecolormap->Maps;
dc_colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : usecolormap->Maps;
else
calclighting = true;
@ -3244,7 +3078,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper,
{ // calculate lighting
dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
}
R_WallSpriteColumn (R_DrawMaskedColumn);
R_WallSpriteColumn (false);
dc_x++;
}
@ -3257,7 +3091,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper,
rt_initcols();
for (int zz = 4; zz; --zz)
{
R_WallSpriteColumn (R_DrawMaskedColumnHoriz);
R_WallSpriteColumn (true);
dc_x++;
}
rt_draw4cols (dc_x - 4);
@ -3269,7 +3103,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper,
{ // calculate lighting
dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
}
R_WallSpriteColumn (R_DrawMaskedColumn);
R_WallSpriteColumn (false);
dc_x++;
}
}

View file

@ -76,10 +76,20 @@ void R_InitSkyMap ()
int skyheight;
FTexture *skytex1, *skytex2;
// Do not allow the null texture which has no bitmap and will crash.
if (sky1texture.isNull())
{
sky1texture = TexMan.CheckForTexture("-noflat-", FTexture::TEX_Any);
}
if (sky2texture.isNull())
{
sky2texture = TexMan.CheckForTexture("-noflat-", FTexture::TEX_Any);
}
skytex1 = TexMan(sky1texture, true);
skytex2 = TexMan(sky2texture, true);
if (skytex1 == NULL)
if (skytex1 == nullptr)
return;
if ((level.flags & LEVEL_DOUBLESKY) && skytex1->GetHeight() != skytex2->GetHeight())

View file

@ -99,6 +99,7 @@ EXTERN_CVAR (Bool, st_scale)
EXTERN_CVAR(Bool, r_shadercolormaps)
EXTERN_CVAR(Int, r_drawfuzz)
EXTERN_CVAR(Bool, r_deathcamera);
CVAR(Bool, r_fullbrightignoresectorcolor, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
//
// Sprite rotation 0 is facing the viewer,
@ -249,18 +250,16 @@ double sprtopscreen;
bool sprflipvert;
void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span)
void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span, bool useRt)
{
const fixed_t centeryfrac = FLOAT2FIXED(CenterY);
const fixed_t texturemid = FLOAT2FIXED(dc_texturemid);
while (span->Length != 0)
{
const int length = span->Length;
const int top = span->TopOffset;
// calculate unclipped screen coordinates for post
dc_yl = xs_RoundToInt(sprtopscreen + spryscale * top);
dc_yh = xs_RoundToInt(sprtopscreen + spryscale * (top + length)) - 1;
dc_yl = (int)(sprtopscreen + spryscale * top + 0.5);
dc_yh = (int)(sprtopscreen + spryscale * (top + length) + 0.5) - 1;
if (sprflipvert)
{
@ -278,56 +277,29 @@ void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span)
if (dc_yl <= dc_yh)
{
if (sprflipvert)
{
dc_texturefrac = (dc_yl*dc_iscale) - (top << FRACBITS)
- FixedMul (centeryfrac, dc_iscale) - texturemid;
const fixed_t maxfrac = length << FRACBITS;
while (dc_texturefrac >= maxfrac)
{
if (++dc_yl > dc_yh)
goto nextpost;
dc_texturefrac += dc_iscale;
}
fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale;
while (endfrac < 0)
{
if (--dc_yh < dc_yl)
goto nextpost;
endfrac -= dc_iscale;
}
}
else
{
dc_texturefrac = texturemid - (top << FRACBITS)
+ (dc_yl*dc_iscale) - FixedMul (centeryfrac-FRACUNIT, dc_iscale);
while (dc_texturefrac < 0)
{
if (++dc_yl > dc_yh)
goto nextpost;
dc_texturefrac += dc_iscale;
}
fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale;
const fixed_t maxfrac = length << FRACBITS;
if (dc_yh < mfloorclip[dc_x]-1 && endfrac < maxfrac - dc_iscale)
{
dc_yh++;
}
else while (endfrac >= maxfrac)
{
if (--dc_yh < dc_yl)
goto nextpost;
endfrac -= dc_iscale;
}
}
dc_source = column + top;
dc_dest = ylookup[dc_yl] + dc_x + dc_destorg;
dc_texturefrac = FLOAT2FIXED((dc_yl + 0.5 - sprtopscreen) / spryscale);
dc_source = column;
dc_dest = (ylookup[dc_yl] + dc_x) + dc_destorg;
dc_count = dc_yh - dc_yl + 1;
colfunc ();
fixed_t maxfrac = ((top + length) << FRACBITS) - 1;
dc_texturefrac = MAX(dc_texturefrac, 0);
dc_texturefrac = MIN(dc_texturefrac, maxfrac);
if (dc_iscale > 0)
dc_count = MIN(dc_count, (maxfrac - dc_texturefrac + dc_iscale - 1) / dc_iscale);
else if (dc_iscale < 0)
dc_count = MIN(dc_count, (dc_texturefrac - dc_iscale) / (-dc_iscale));
if (useRt)
hcolfunc_pre();
else
colfunc ();
}
nextpost:
span++;
}
if (sprflipvert && useRt)
rt_flip_posts();
}
// [ZZ]
@ -469,7 +441,7 @@ void R_DrawVisSprite (vissprite_t *vis)
{
pixels = tex->GetColumn (frac >> FRACBITS, &spans);
if (ispsprite || !R_ClipSpriteColumnWithPortals(vis))
R_DrawMaskedColumn (pixels, spans);
R_DrawMaskedColumn (pixels, spans, false);
dc_x++;
frac += xiscale;
}
@ -481,7 +453,7 @@ void R_DrawVisSprite (vissprite_t *vis)
{
pixels = tex->GetColumn (frac >> FRACBITS, &spans);
if (ispsprite || !R_ClipSpriteColumnWithPortals(vis))
R_DrawMaskedColumnHoriz (pixels, spans);
R_DrawMaskedColumn (pixels, spans, true);
dc_x++;
frac += xiscale;
}
@ -492,7 +464,7 @@ void R_DrawVisSprite (vissprite_t *vis)
{
pixels = tex->GetColumn (frac >> FRACBITS, &spans);
if (ispsprite || !R_ClipSpriteColumnWithPortals(vis))
R_DrawMaskedColumn (pixels, spans);
R_DrawMaskedColumn (pixels, spans, false);
dc_x++;
frac += xiscale;
}
@ -548,7 +520,7 @@ void R_DrawWallSprite(vissprite_t *spr)
else if (fixedcolormap != NULL)
dc_colormap = fixedcolormap;
else if (!foggy && (spr->renderflags & RF_FULLBRIGHT))
dc_colormap = usecolormap->Maps;
dc_colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : usecolormap->Maps;
else
calclighting = true;
@ -602,7 +574,7 @@ void R_DrawWallSprite(vissprite_t *spr)
dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT);
}
if (!R_ClipSpriteColumnWithPortals(spr))
R_WallSpriteColumn(R_DrawMaskedColumn);
R_WallSpriteColumn(false);
dc_x++;
}
@ -616,7 +588,7 @@ void R_DrawWallSprite(vissprite_t *spr)
for (int zz = 4; zz; --zz)
{
if (!R_ClipSpriteColumnWithPortals(spr))
R_WallSpriteColumn(R_DrawMaskedColumnHoriz);
R_WallSpriteColumn(true);
dc_x++;
}
rt_draw4cols(dc_x - 4);
@ -629,14 +601,14 @@ void R_DrawWallSprite(vissprite_t *spr)
dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT);
}
if (!R_ClipSpriteColumnWithPortals(spr))
R_WallSpriteColumn(R_DrawMaskedColumn);
R_WallSpriteColumn(false);
dc_x++;
}
}
R_FinishSetPatchStyle();
}
void R_WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Span *spans))
void R_WallSpriteColumn (bool useRt)
{
float iscale = swall[dc_x] * MaskedScaleY;
dc_iscale = FLOAT2FIXED(iscale);
@ -650,7 +622,7 @@ void R_WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Sp
const FTexture::Span *spans;
column = WallSpriteTile->GetColumn (lwall[dc_x] >> FRACBITS, &spans);
dc_texturefrac = 0;
drawfunc (column, spans);
R_DrawMaskedColumn(column, spans, useRt);
rw_light += rw_lightstep;
}
@ -983,7 +955,8 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
const double thingxscalemul = spriteScale.X / tex->Scale.X;
tx -= ((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->LeftOffset - 1) : tex->LeftOffset) * thingxscalemul;
x1 = centerx + xs_RoundToInt(tx * xscale);
double dtx1 = tx * xscale;
x1 = centerx + xs_RoundToInt(dtx1);
// off the right side?
if (x1 >= WindowRight)
@ -997,7 +970,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
return;
xscale = spriteScale.X * xscale / tex->Scale.X;
iscale = (tex->GetWidth() << FRACBITS) / (x2 - x1);
iscale = (fixed_t)(FRACUNIT / xscale); // Round towards zero to avoid wrapping in edge cases
double yscale = spriteScale.Y / tex->Scale.Y;
@ -1025,8 +998,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
vis->xiscale = iscale;
}
if (vis->x1 > x1)
vis->startfrac += vis->xiscale * (vis->x1 - x1);
vis->startfrac += (fixed_t)(vis->xiscale * (vis->x1 - centerx + 0.5 - dtx1));
}
else
{
@ -1066,7 +1038,8 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
vis->deltax = float(pos.X - ViewPos.X);
vis->deltay = float(pos.Y - ViewPos.Y);
vis->renderflags = renderflags;
if(thing->flags5 & MF5_BRIGHT) vis->renderflags |= RF_FULLBRIGHT; // kg3D
if(thing->flags5 & MF5_BRIGHT)
vis->renderflags |= RF_FULLBRIGHT; // kg3D
vis->Style.RenderStyle = thing->RenderStyle;
vis->FillColor = thing->fillcolor;
vis->Translation = thing->Translation; // [RH] thing translation table
@ -1140,7 +1113,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
}
else if (!foggy && ((renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)))
{ // full bright
vis->Style.colormap = mybasecolormap->Maps;
vis->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps;
}
else
{ // diminished light
@ -1337,7 +1310,7 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double
}
sx = pspr->oldx + (pspr->x - pspr->oldx) * ticfrac;
sy = pspr->oldy + (pspr->y - pspr->oldy) * ticfrac;
sy = pspr->oldy + (pspr->y - pspr->oldy) * ticfrac + WEAPON_FUDGE_Y;
if (pspr->Flags & PSPF_ADDBOB)
{
@ -1462,11 +1435,11 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double
}
if (fixedlightlev >= 0)
{
vis->Style.colormap = mybasecolormap->Maps + fixedlightlev;
vis->Style.colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (mybasecolormap->Maps + fixedlightlev);
}
else if (!foggy && pspr->GetState()->GetFullbright())
{ // full bright
vis->Style.colormap = mybasecolormap->Maps; // [RH] use basecolormap
vis->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps; // [RH] use basecolormap
}
else
{ // local light
@ -1516,6 +1489,11 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double
{
noaccel = true;
}
// [SP] If emulating GZDoom fullbright, disable acceleration
if (r_fullbrightignoresectorcolor && fixedlightlev >= 0)
mybasecolormap = &FullNormalLight;
if (r_fullbrightignoresectorcolor && !foggy && pspr->GetState()->GetFullbright())
mybasecolormap = &FullNormalLight;
colormap_to_use = mybasecolormap;
}
else
@ -1640,7 +1618,7 @@ void R_DrawPlayerSprites ()
else
{
wx = weapon->oldx + (weapon->x - weapon->oldx) * r_TicFracF;
wy = weapon->oldy + (weapon->y - weapon->oldy) * r_TicFracF;
wy = weapon->oldy + (weapon->y - weapon->oldy) * r_TicFracF + WEAPON_FUDGE_Y;
}
}
else
@ -2057,7 +2035,7 @@ void R_DrawSprite (vissprite_t *spr)
}
else if (!foggy && (spr->renderflags & RF_FULLBRIGHT))
{ // full bright
spr->Style.colormap = mybasecolormap->Maps;
spr->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps;
}
else
{ // diminished light
@ -2615,7 +2593,7 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade,
}
else if (particle->bright)
{
vis->Style.colormap = map;
vis->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : map;
}
else
{

View file

@ -124,8 +124,8 @@ extern double pspriteyscale;
extern FTexture *WallSpriteTile;
void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *spans);
void R_WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Span *spans));
void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *spans, bool useRt);
void R_WallSpriteColumn (bool useRt);
void R_CacheSprite (spritedef_t *sprite);
void R_SortVisSprites (int (*compare)(const void *, const void *), size_t first);

View file

@ -577,7 +577,7 @@ bool WriteZip(const char *filename, TArray<FString> &filenames, TArray<FCompress
dirend.DiskNumber = 0;
dirend.FirstDisk = 0;
dirend.NumEntriesOnAllDisks = dirend.NumEntries = LittleShort(filenames.Size());
dirend.DirectoryOffset = dirofs;
dirend.DirectoryOffset = LittleLong(dirofs);
dirend.DirectorySize = LittleLong(ftell(f) - dirofs);
dirend.ZipCommentLength = 0;
if (fwrite(&dirend, sizeof(dirend), 1, f) != 1)

View file

@ -95,7 +95,8 @@ void FResourceLump::LumpNameSetup(FString iname)
{
long slash = iname.LastIndexOf('/');
FString base = (slash >= 0) ? iname.Mid(slash + 1) : iname;
base.Truncate(base.LastIndexOf('.'));
auto dot = base.LastIndexOf('.');
if (dot >= 0) base.Truncate(dot);
uppercopy(Name, base);
Name[8] = 0;
FullName = iname;

View file

@ -1301,6 +1301,32 @@ void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, fl
S_StartSound (NULL, sec, NULL, NULL, channel, sfxid, volume, attenuation);
}
//==========================================================================
//
// S_PlaySound - Subfunction used by ACS and DECORATE
//
// Has a local parameter to make the sound audible only to the source
//
//==========================================================================
void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local)
{
if (a == nullptr)
return;
if (!local)
{
S_Sound(a, chan, sid, vol, atten);
}
else
{
if (a->CheckLocalView(consoleplayer))
{
S_Sound(chan, sid, vol, ATTN_NONE);
}
}
}
//==========================================================================
//
// S_LoadSound

View file

@ -241,6 +241,9 @@ void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, float volume, f
void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation);
void S_Sound(const DVector3 &pos, int channel, FSoundID sfxid, float volume, float attenuation);
// [Nash] Used by ACS and DECORATE
void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local);
// sound channels
// channel 0 never willingly overrides
// other channels (1-7) always override a playing sound on that channel

View file

@ -67,6 +67,143 @@
char nulspace[1024 * 1024 * 4];
bool save_full = false; // for testing. Should be removed afterward.
int utf8_encode(int32_t codepoint, char *buffer, int *size)
{
if (codepoint < 0)
return -1;
else if (codepoint < 0x80)
{
buffer[0] = (char)codepoint;
*size = 1;
}
else if (codepoint < 0x800)
{
buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6);
buffer[1] = 0x80 + ((codepoint & 0x03F));
*size = 2;
}
else if (codepoint < 0x10000)
{
buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12);
buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6);
buffer[2] = 0x80 + ((codepoint & 0x003F));
*size = 3;
}
else if (codepoint <= 0x10FFFF)
{
buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18);
buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12);
buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6);
buffer[3] = 0x80 + ((codepoint & 0x00003F));
*size = 4;
}
else
return -1;
return 0;
}
int utf8_decode(const char *src, int *size)
{
int c = src[0] & 255;
int r;
*size = 1;
if ((c & 0x80) == 0)
{
return c;
}
int c1 = src[1] & 255;
if ((c & 0xE0) == 0xC0)
{
r = ((c & 0x1F) << 6) | c1;
if (r >= 128)
{
*size = 2;
return r;
}
return -1;
}
int c2 = src[2] & 255;
if ((c & 0xF0) == 0xE0)
{
r = ((c & 0x0F) << 12) | (c1 << 6) | c2;
if (r >= 2048 && (r < 55296 || r > 57343))
{
*size = 3;
return r;
}
return -1;
}
int c3 = src[3] & 255;
if ((c & 0xF8) == 0xF0)
{
r = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3;
if (r >= 65536 && r <= 1114111)
{
*size = 4;
return r;
}
}
return -1;
}
static TArray<char> out;
static const char *StringToUnicode(const char *cc, int size = -1)
{
int ch;
const char *c = cc;
int count = 0;
int count1 = 0;
out.Clear();
while ((ch = (*c++) & 255))
{
count1++;
if (ch >= 128)
{
if (ch < 0x800) count += 2;
else count += 3;
// The source cannot contain 4-byte chars.
}
else count++;
if (count1 == size && size > 0) break;
}
if (count == count1) return cc; // string is pure ASCII.
// we need to convert
out.Resize(count + 1);
out.Last() = 0;
c = cc;
int i = 0;
while ((ch = (*c++) & 255))
{
utf8_encode(ch, &out[i], &count1);
i += count1;
}
return &out[0];
}
static const char *UnicodeToString(const char *cc)
{
out.Resize((unsigned)strlen(cc) + 1);
int ndx = 0;
while (*cc != 0)
{
int size;
int c = utf8_decode(cc, &size);
if (c < 0 || c > 255) c = '?';
out[ndx++] = c;
cc += size;
}
out[ndx] = 0;
return &out[0];
}
//==========================================================================
//
//
@ -99,8 +236,8 @@ struct FJSONObject
struct FWriter
{
typedef rapidjson::Writer<rapidjson::StringBuffer, rapidjson::ASCII<> > Writer;
typedef rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::ASCII<> > PrettyWriter;
typedef rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<> > Writer;
typedef rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<> > PrettyWriter;
Writer *mWriter1;
PrettyWriter *mWriter2;
@ -173,14 +310,16 @@ struct FWriter
void String(const char *k)
{
k = StringToUnicode(k);
if (mWriter1) mWriter1->String(k);
else if (mWriter2) mWriter2->String(k);
}
void String(const char *k, int size)
{
if (mWriter1) mWriter1->String(k, size);
else if (mWriter2) mWriter2->String(k, size);
k = StringToUnicode(k, size);
if (mWriter1) mWriter1->String(k);
else if (mWriter2) mWriter2->String(k);
}
void Bool(bool k)
@ -602,7 +741,7 @@ FSerializer &FSerializer::Args(const char *key, int *args, int *defargs, int spe
}
else if (i == 0 && aval.IsString())
{
args[i] = -FName(aval.GetString());
args[i] = -FName(UnicodeToString(aval.GetString()));
}
else
{
@ -654,7 +793,7 @@ FSerializer &FSerializer::ScriptNum(const char *key, int &num)
}
else if (val->IsString())
{
num = -FName(val->GetString());
num = -FName(UnicodeToString(val->GetString()));
}
else
{
@ -709,7 +848,7 @@ FSerializer &FSerializer::Sprite(const char *key, int32_t &spritenum, int32_t *d
{
if (val->IsString())
{
uint32_t name = *reinterpret_cast<const uint32_t*>(val->GetString());
uint32_t name = *reinterpret_cast<const uint32_t*>(UnicodeToString(val->GetString()));
for (auto hint = NumStdSprites; hint-- != 0; )
{
if (sprites[hint].dwName == name)
@ -747,7 +886,7 @@ FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr)
{
if (val->IsString())
{
charptr = val->GetString();
charptr = UnicodeToString(val->GetString());
}
else
{
@ -1403,7 +1542,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe
assert(nameval.IsString() && typeval.IsInt());
if (nameval.IsString() && typeval.IsInt())
{
value = TexMan.GetTexture(nameval.GetString(), typeval.GetInt());
value = TexMan.GetTexture(UnicodeToString(nameval.GetString()), typeval.GetInt());
}
else
{
@ -1553,7 +1692,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d
assert(val->IsString());
if (val->IsString())
{
value = val->GetString();
value = UnicodeToString(val->GetString());
}
else
{
@ -1638,7 +1777,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI
assert(val->IsString() || val->IsNull());
if (val->IsString())
{
sid = val->GetString();
sid = UnicodeToString(val->GetString());
}
else if (val->IsNull())
{
@ -1687,7 +1826,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor
assert(val->IsString() || val->IsNull());
if (val->IsString())
{
clst = PClass::FindActor(val->GetString());
clst = PClass::FindActor(UnicodeToString(val->GetString()));
}
else if (val->IsNull())
{
@ -1735,7 +1874,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&cl
{
if (val->IsString())
{
clst = PClass::FindClass(val->GetString());
clst = PClass::FindClass(UnicodeToString(val->GetString()));
}
else if (val->IsNull())
{
@ -1810,7 +1949,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState
assert(cls.IsString() && ndx.IsUint());
if (cls.IsString() && ndx.IsUint())
{
PClassActor *clas = PClass::FindActor(cls.GetString());
PClassActor *clas = PClass::FindActor(UnicodeToString(cls.GetString()));
if (clas && ndx.GetUint() < (unsigned)clas->NumOwnedStates)
{
state = clas->OwnedStates + ndx.GetUint();
@ -1932,7 +2071,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&p
}
else if (val->IsString())
{
pstr = AActor::mStringPropertyData.Alloc(val->GetString());
pstr = AActor::mStringPropertyData.Alloc(UnicodeToString(val->GetString()));
}
else
{
@ -1974,7 +2113,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FString &pstr, FString
}
else if (val->IsString())
{
pstr = val->GetString();
pstr = UnicodeToString(val->GetString());
}
else
{
@ -2023,7 +2162,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr
}
else if (val->IsString())
{
pstr = copystring(val->GetString());
pstr = copystring(UnicodeToString(val->GetString()));
}
else
{

View file

@ -238,8 +238,8 @@ static const FEnumList ResamplerNames[] =
{ "No Interpolation", FMOD_DSP_RESAMPLER_NOINTERP },
{ "NoInterp", FMOD_DSP_RESAMPLER_NOINTERP },
{ "Linear", FMOD_DSP_RESAMPLER_LINEAR },
// [BL] 64-bit version of FMOD Ex 4.26 crashes with these resamplers.
#if FMOD_STUDIO || !(defined(_M_X64) || defined(__amd64__)) || !(FMOD_VERSION >= 0x42600 && FMOD_VERSION <= 0x426FF)
// [BL] 64-bit versions of FMOD Ex between 4.24 and 4.26 crash with these resamplers.
#if FMOD_STUDIO || !(defined(_M_X64) || defined(__amd64__)) || !(FMOD_VERSION >= 0x42400 && FMOD_VERSION <= 0x426FF)
{ "Cubic", FMOD_DSP_RESAMPLER_CUBIC },
{ "Spline", FMOD_DSP_RESAMPLER_SPLINE },
#endif

View file

@ -359,6 +359,9 @@ protected:
#ifndef DYN_FLUIDSYNTH
#include <fluidsynth.h>
#else
#include "i_module.h"
extern FModule FluidSynthModule;
struct fluid_settings_t;
struct fluid_synth_t;
#endif
@ -386,40 +389,35 @@ protected:
#ifdef DYN_FLUIDSYNTH
enum { FLUID_FAILED = -1, FLUID_OK = 0 };
fluid_settings_t *(*new_fluid_settings)();
fluid_synth_t *(*new_fluid_synth)(fluid_settings_t *);
int (*delete_fluid_synth)(fluid_synth_t *);
void (*delete_fluid_settings)(fluid_settings_t *);
int (*fluid_settings_setnum)(fluid_settings_t *, const char *, double);
int (*fluid_settings_setstr)(fluid_settings_t *, const char *, const char *);
int (*fluid_settings_setint)(fluid_settings_t *, const char *, int);
int (*fluid_settings_getstr)(fluid_settings_t *, const char *, char **);
int (*fluid_settings_getint)(fluid_settings_t *, const char *, int *);
void (*fluid_synth_set_reverb_on)(fluid_synth_t *, int);
void (*fluid_synth_set_chorus_on)(fluid_synth_t *, int);
int (*fluid_synth_set_interp_method)(fluid_synth_t *, int, int);
int (*fluid_synth_set_polyphony)(fluid_synth_t *, int);
int (*fluid_synth_get_polyphony)(fluid_synth_t *);
int (*fluid_synth_get_active_voice_count)(fluid_synth_t *);
double (*fluid_synth_get_cpu_load)(fluid_synth_t *);
int (*fluid_synth_system_reset)(fluid_synth_t *);
int (*fluid_synth_noteon)(fluid_synth_t *, int, int, int);
int (*fluid_synth_noteoff)(fluid_synth_t *, int, int);
int (*fluid_synth_cc)(fluid_synth_t *, int, int, int);
int (*fluid_synth_program_change)(fluid_synth_t *, int, int);
int (*fluid_synth_channel_pressure)(fluid_synth_t *, int, int);
int (*fluid_synth_pitch_bend)(fluid_synth_t *, int, int);
int (*fluid_synth_write_float)(fluid_synth_t *, int, void *, int, int, void *, int, int);
int (*fluid_synth_sfload)(fluid_synth_t *, const char *, int);
void (*fluid_synth_set_reverb)(fluid_synth_t *, double, double, double, double);
void (*fluid_synth_set_chorus)(fluid_synth_t *, int, double, double, double, int);
int (*fluid_synth_sysex)(fluid_synth_t *, const char *, int, char *, int *, int *, int);
static TReqProc<FluidSynthModule, fluid_settings_t *(*)()> new_fluid_settings;
static TReqProc<FluidSynthModule, fluid_synth_t *(*)(fluid_settings_t *)> new_fluid_synth;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *)> delete_fluid_synth;
static TReqProc<FluidSynthModule, void (*)(fluid_settings_t *)> delete_fluid_settings;
static TReqProc<FluidSynthModule, int (*)(fluid_settings_t *, const char *, double)> fluid_settings_setnum;
static TReqProc<FluidSynthModule, int (*)(fluid_settings_t *, const char *, const char *)> fluid_settings_setstr;
static TReqProc<FluidSynthModule, int (*)(fluid_settings_t *, const char *, int)> fluid_settings_setint;
static TReqProc<FluidSynthModule, int (*)(fluid_settings_t *, const char *, char **)> fluid_settings_getstr;
static TReqProc<FluidSynthModule, int (*)(fluid_settings_t *, const char *, int *)> fluid_settings_getint;
static TReqProc<FluidSynthModule, void (*)(fluid_synth_t *, int)> fluid_synth_set_reverb_on;
static TReqProc<FluidSynthModule, void (*)(fluid_synth_t *, int)> fluid_synth_set_chorus_on;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int)> fluid_synth_set_interp_method;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int)> fluid_synth_set_polyphony;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *)> fluid_synth_get_polyphony;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *)> fluid_synth_get_active_voice_count;
static TReqProc<FluidSynthModule, double (*)(fluid_synth_t *)> fluid_synth_get_cpu_load;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *)> fluid_synth_system_reset;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int, int)> fluid_synth_noteon;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int)> fluid_synth_noteoff;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int, int)> fluid_synth_cc;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int)> fluid_synth_program_change;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int)> fluid_synth_channel_pressure;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int)> fluid_synth_pitch_bend;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, void *, int, int, void *, int, int)> fluid_synth_write_float;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, const char *, int)> fluid_synth_sfload;
static TReqProc<FluidSynthModule, void (*)(fluid_synth_t *, double, double, double, double)> fluid_synth_set_reverb;
static TReqProc<FluidSynthModule, void (*)(fluid_synth_t *, int, double, double, double, int)> fluid_synth_set_chorus;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, const char *, int, char *, int *, int *, int)> fluid_synth_sysex;
#ifdef _WIN32
HMODULE FluidSynthDLL;
#else
void *FluidSynthSO;
#endif
bool LoadFluidSynth();
void UnloadFluidSynth();
#endif

View file

@ -60,9 +60,9 @@
#include <dlfcn.h>
#ifdef __APPLE__
#define FLUIDSYNTHLIB "libfluidsynth.1.dylib"
#define FLUIDSYNTHLIB1 "libfluidsynth.1.dylib"
#else // !__APPLE__
#define FLUIDSYNTHLIB "libfluidsynth.so.1"
#define FLUIDSYNTHLIB1 "libfluidsynth.so.1"
#endif // __APPLE__
#endif
@ -644,12 +644,6 @@ FString FluidSynthMIDIDevice::GetStats()
#ifdef DYN_FLUIDSYNTH
struct LibFunc
{
void **FuncPointer;
const char *FuncName;
};
//==========================================================================
//
// FluidSynthMIDIDevice :: LoadFluidSynth
@ -658,124 +652,65 @@ struct LibFunc
//
//==========================================================================
FModuleMaybe<DYN_FLUIDSYNTH> FluidSynthModule{"FluidSynth"};
#define DYN_FLUID_SYM(x) decltype(FluidSynthMIDIDevice::x) FluidSynthMIDIDevice::x{#x}
DYN_FLUID_SYM(new_fluid_settings);
DYN_FLUID_SYM(new_fluid_synth);
DYN_FLUID_SYM(delete_fluid_synth);
DYN_FLUID_SYM(delete_fluid_settings);
DYN_FLUID_SYM(fluid_settings_setnum);
DYN_FLUID_SYM(fluid_settings_setstr);
DYN_FLUID_SYM(fluid_settings_setint);
DYN_FLUID_SYM(fluid_settings_getstr);
DYN_FLUID_SYM(fluid_settings_getint);
DYN_FLUID_SYM(fluid_synth_set_reverb_on);
DYN_FLUID_SYM(fluid_synth_set_chorus_on);
DYN_FLUID_SYM(fluid_synth_set_interp_method);
DYN_FLUID_SYM(fluid_synth_set_polyphony);
DYN_FLUID_SYM(fluid_synth_get_polyphony);
DYN_FLUID_SYM(fluid_synth_get_active_voice_count);
DYN_FLUID_SYM(fluid_synth_get_cpu_load);
DYN_FLUID_SYM(fluid_synth_system_reset);
DYN_FLUID_SYM(fluid_synth_noteon);
DYN_FLUID_SYM(fluid_synth_noteoff);
DYN_FLUID_SYM(fluid_synth_cc);
DYN_FLUID_SYM(fluid_synth_program_change);
DYN_FLUID_SYM(fluid_synth_channel_pressure);
DYN_FLUID_SYM(fluid_synth_pitch_bend);
DYN_FLUID_SYM(fluid_synth_write_float);
DYN_FLUID_SYM(fluid_synth_sfload);
DYN_FLUID_SYM(fluid_synth_set_reverb);
DYN_FLUID_SYM(fluid_synth_set_chorus);
DYN_FLUID_SYM(fluid_synth_sysex);
bool FluidSynthMIDIDevice::LoadFluidSynth()
{
LibFunc imports[] =
{
{ (void **)&new_fluid_settings, "new_fluid_settings" },
{ (void **)&new_fluid_synth, "new_fluid_synth" },
{ (void **)&delete_fluid_synth, "delete_fluid_synth" },
{ (void **)&delete_fluid_settings, "delete_fluid_settings" },
{ (void **)&fluid_settings_setnum, "fluid_settings_setnum" },
{ (void **)&fluid_settings_setstr, "fluid_settings_setstr" },
{ (void **)&fluid_settings_setint, "fluid_settings_setint" },
{ (void **)&fluid_settings_getstr, "fluid_settings_getstr" },
{ (void **)&fluid_settings_getint, "fluid_settings_getint" },
{ (void **)&fluid_synth_set_reverb_on, "fluid_synth_set_reverb_on" },
{ (void **)&fluid_synth_set_chorus_on, "fluid_synth_set_chorus_on" },
{ (void **)&fluid_synth_set_interp_method, "fluid_synth_set_interp_method" },
{ (void **)&fluid_synth_set_polyphony, "fluid_synth_set_polyphony" },
{ (void **)&fluid_synth_get_polyphony, "fluid_synth_get_polyphony" },
{ (void **)&fluid_synth_get_active_voice_count, "fluid_synth_get_active_voice_count" },
{ (void **)&fluid_synth_get_cpu_load, "fluid_synth_get_cpu_load" },
{ (void **)&fluid_synth_system_reset, "fluid_synth_system_reset" },
{ (void **)&fluid_synth_noteon, "fluid_synth_noteon" },
{ (void **)&fluid_synth_noteoff, "fluid_synth_noteoff" },
{ (void **)&fluid_synth_cc, "fluid_synth_cc" },
{ (void **)&fluid_synth_program_change, "fluid_synth_program_change" },
{ (void **)&fluid_synth_channel_pressure, "fluid_synth_channel_pressure" },
{ (void **)&fluid_synth_pitch_bend, "fluid_synth_pitch_bend" },
{ (void **)&fluid_synth_write_float, "fluid_synth_write_float" },
{ (void **)&fluid_synth_sfload, "fluid_synth_sfload" },
{ (void **)&fluid_synth_set_reverb, "fluid_synth_set_reverb" },
{ (void **)&fluid_synth_set_chorus, "fluid_synth_set_chorus" },
{ (void **)&fluid_synth_sysex, "fluid_synth_sysex" },
};
int fail = 0;
const char *libname;
#ifdef _WIN32
if (strlen(fluid_lib) > 0)
{
FluidSynthDLL = LoadLibrary(libname = fluid_lib);
if (nullptr == FluidSynthDLL)
if(!FluidSynthModule.Load({fluid_lib}))
{
const char* libname = fluid_lib;
Printf(TEXTCOLOR_RED "Could not load %s\n", libname);
}
}
else
{
FluidSynthDLL = nullptr;
}
if (nullptr == FluidSynthDLL)
{
FluidSynthDLL = LoadLibrary(libname = FLUIDSYNTHLIB1);
if (nullptr == FluidSynthDLL)
{
FluidSynthDLL = LoadLibrary(libname = FLUIDSYNTHLIB2);
if (nullptr == FluidSynthDLL)
{
Printf(TEXTCOLOR_RED "Could not load " FLUIDSYNTHLIB1 " or " FLUIDSYNTHLIB2 "\n");
return false;
}
}
}
#else
if (strlen(fluid_lib) > 0)
{
FluidSynthSO = dlopen(libname = fluid_lib, RTLD_LAZY);
if (nullptr == FluidSynthSO)
{
Printf(TEXTCOLOR_RED "Could not load %s: %s\n", libname, dlerror());
}
}
else
{
FluidSynthSO = nullptr;
else
return true;
}
if (nullptr == FluidSynthSO)
#ifdef FLUIDSYNTHLIB2
if(!FluidSynthModule.Load({FLUIDSYNTHLIB1, FLUIDSYNTHLIB2}))
{
FluidSynthSO = dlopen(libname = FLUIDSYNTHLIB, RTLD_LAZY);
if (nullptr == FluidSynthSO)
{
Printf(TEXTCOLOR_RED "Could not load " FLUIDSYNTHLIB ": %s\n", dlerror());
return false;
}
}
#endif
for (size_t i = 0; i < countof(imports); ++i)
{
#ifdef _WIN32
FARPROC proc = GetProcAddress(FluidSynthDLL, imports[i].FuncName);
#else
void *proc = dlsym(FluidSynthSO, imports[i].FuncName);
#endif
if (proc == NULL)
{
Printf(TEXTCOLOR_RED"Failed to find %s in %s\n", imports[i].FuncName, libname);
fail++;
}
*imports[i].FuncPointer = (void *)proc;
}
if (fail == 0)
{
return true;
}
else
{
#ifdef _WIN32
FreeLibrary(FluidSynthDLL);
FluidSynthDLL = NULL;
#else
dlclose(FluidSynthSO);
FluidSynthSO = NULL;
#endif
Printf(TEXTCOLOR_RED "Could not load " FLUIDSYNTHLIB1 " or " FLUIDSYNTHLIB2 "\n");
return false;
}
#else
if(!FluidSynthModule.Load({fluid_lib, FLUIDSYNTHLIB1}))
{
Printf(TEXTCOLOR_RED "Could not load " FLUIDSYNTHLIB1 ": %s\n", dlerror());
return false;
}
#endif
return true;
}
//==========================================================================
@ -786,19 +721,7 @@ bool FluidSynthMIDIDevice::LoadFluidSynth()
void FluidSynthMIDIDevice::UnloadFluidSynth()
{
#ifdef _WIN32
if (FluidSynthDLL != NULL)
{
FreeLibrary(FluidSynthDLL);
FluidSynthDLL = NULL;
}
#else
if (FluidSynthSO != NULL)
{
dlclose(FluidSynthSO);
FluidSynthSO = NULL;
}
#endif
FluidSynthModule.Unload();
}
#endif

View file

@ -3,24 +3,9 @@
#if !defined NO_OPENAL && defined DYN_OPENAL
#ifndef _WIN32
typedef void* FARPROC;
#endif
#define DEFINE_ENTRY(type, name) static type p_##name;
#define DEFINE_ENTRY(type, name) static TReqProc<OpenALModule, type> p_##name{#name};
#include "oaldef.h"
#undef DEFINE_ENTRY
struct oalloadentry
{
const char *name;
FARPROC *funcaddr;
};
static oalloadentry oalfuncs[] = {
#define DEFINE_ENTRY(type, name) { #name, (FARPROC*)&p_##name },
#include "oaldef.h"
#undef DEFINE_ENTRY
{ NULL, 0 }
};
#ifndef IN_IDE_PARSER
#define alEnable p_alEnable

View file

@ -55,29 +55,25 @@
#include "actor.h"
#include "r_state.h"
#include "w_wad.h"
#include "i_module.h"
#include "i_music.h"
#include "i_musicinterns.h"
#include "tempfiles.h"
FModule OpenALModule{"OpenAL"};
#include "oalload.h"
CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
#ifdef _WIN32
static HMODULE hmodOpenAL;
#define OPENALLIB "openal32.dll"
#else
static void* hmodOpenAL;
#ifdef __APPLE__
#elif defined(__APPLE__)
#define OPENALLIB "OpenAL.framework/OpenAL"
#else
#define OPENALLIB "libopenal.so.1"
#endif
#define LoadLibrary(x) dlopen((x), RTLD_LAZY)
#define GetProcAddress(a,b) dlsym((a),(b))
#define FreeLibrary(x) dlclose((x))
#endif
bool IsOpenALPresent()
{
@ -92,29 +88,7 @@ bool IsOpenALPresent()
if (!done)
{
done = true;
if (hmodOpenAL == NULL)
{
hmodOpenAL = LoadLibrary(NicePath("$PROGDIR/" OPENALLIB));
if (hmodOpenAL == NULL)
{
hmodOpenAL = LoadLibrary(OPENALLIB);
if (hmodOpenAL == NULL)
{
return false;
}
}
for(int i = 0; oalfuncs[i].name != NULL; i++)
{
*oalfuncs[i].funcaddr = GetProcAddress(hmodOpenAL, oalfuncs[i].name);
if (*oalfuncs[i].funcaddr == NULL)
{
FreeLibrary(hmodOpenAL);
hmodOpenAL = NULL;
return false;
}
}
}
cached_result = true;
cached_result = OpenALModule.Load({NicePath("$PROGDIR/" OPENALLIB), OPENALLIB});
}
return cached_result;
#endif

View file

@ -1002,7 +1002,7 @@ void FTextureManager::UpdateAnimations (DWORD mstime)
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimation *&p, FDoorAnimation **def)
{
FTextureID tex = p->BaseTexture;
FTextureID tex = p? p->BaseTexture : FNullTextureID();
Serialize(arc, key, tex, def ? &(*def)->BaseTexture : nullptr);
if (arc.isReading())
{

View file

@ -48,6 +48,7 @@
#include "v_palette.h"
#include "v_video.h"
#include "v_text.h"
#include "cmdlib.h"
#include "m_fixed.h"
#include "textures/textures.h"
#include "r_data/colormaps.h"
@ -138,7 +139,6 @@ struct strifemaptexture_t
struct FPatchLookup
{
FString Name;
FTexture *Texture;
};
@ -166,6 +166,7 @@ public:
int GetSourceLump() { return DefinitionLump; }
FTexture *GetRedirect(bool wantwarped);
FTexture *GetRawTexture();
void ResolvePatches();
protected:
BYTE *Pixels;
@ -185,8 +186,19 @@ protected:
TexPart();
};
struct TexInit
{
FString TexName;
int UseType = TEX_Null;
bool Silent = false;
bool HasLine = false;
bool UseOffsets = false;
FScriptPosition sc;
};
int NumParts;
TexPart *Parts;
TexInit *Inits;
bool bRedirect:1;
bool bTranslucentPatches:1;
@ -194,7 +206,7 @@ protected:
private:
void CheckForHacks ();
void ParsePatch(FScanner &sc, TexPart & part, bool silent, int usetype);
void ParsePatch(FScanner &sc, TexPart & part, TexInit &init);
};
//==========================================================================
@ -204,7 +216,7 @@ private:
//==========================================================================
FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflumpnum)
: Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false)
: Pixels (0), Spans(0), Parts(nullptr), Inits(nullptr), bRedirect(false), bTranslucentPatches(false)
{
union
{
@ -240,7 +252,8 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl
}
UseType = FTexture::TEX_Wall;
Parts = NumParts > 0 ? new TexPart[NumParts] : NULL;
Parts = NumParts > 0 ? new TexPart[NumParts] : nullptr;
Inits = NumParts > 0 ? new TexInit[NumParts] : nullptr;
Width = SAFESHORT(mtexture.d->width);
Height = SAFESHORT(mtexture.d->height);
Name = (char *)mtexture.d->name;
@ -272,17 +285,9 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl
}
Parts[i].OriginX = LittleShort(mpatch.d->originx);
Parts[i].OriginY = LittleShort(mpatch.d->originy);
Parts[i].Texture = patchlookup[LittleShort(mpatch.d->patch)].Texture;
if (Parts[i].Texture == NULL)
{
Printf(TEXTCOLOR_RED "Unknown patch %s in texture %s\n", patchlookup[LittleShort(mpatch.d->patch)].Name.GetChars(), Name.GetChars());
NumParts--;
i--;
}
else
{
Parts[i].Texture->bKeepAround = true;
}
Parts[i].Texture = nullptr;
Inits[i].TexName = patchlookup[LittleShort(mpatch.d->patch)].Name;
Inits[i].UseType = TEX_WallPatch;
if (strife)
mpatch.s++;
else
@ -293,19 +298,6 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl
Printf ("Texture %s is left without any patches\n", Name.GetChars());
}
CheckForHacks ();
// If this texture is just a wrapper around a single patch, we can simply
// forward GetPixels() and GetColumn() calls to that patch.
if (NumParts == 1)
{
if (Parts->OriginX == 0 && Parts->OriginY == 0 &&
Parts->Texture->GetWidth() == Width &&
Parts->Texture->GetHeight() == Height)
{
bRedirect = true;
}
}
DefinitionLump = deflumpnum;
}
@ -327,6 +319,11 @@ FMultiPatchTexture::~FMultiPatchTexture ()
delete[] Parts;
Parts = NULL;
}
if (Inits != nullptr)
{
delete[] Inits;
Inits = nullptr;
}
if (Spans != NULL)
{
FreeSpans (Spans);
@ -864,19 +861,6 @@ void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int d
pnames.Read(pname, 8);
pname[8] = '\0';
patchlookup[i].Name = pname;
FTextureID j = CheckForTexture (patchlookup[i].Name, FTexture::TEX_WallPatch);
if (j.isValid())
{
patchlookup[i].Texture = Textures[j.GetIndex()].Texture;
}
else
{
// Shareware Doom has the same PNAMES lump as the registered
// Doom, so printing warnings for patches that don't really
// exist isn't such a good idea.
//Printf ("Patch %s not found.\n", patchlookup[i].Name);
patchlookup[i].Texture = NULL;
}
}
}
@ -997,35 +981,13 @@ void FTextureManager::AddTexturesLumps (int lump1, int lump2, int patcheslump)
//
//==========================================================================
void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, bool silent, int usetype)
void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, TexInit &init)
{
FString patchname;
int Mirror = 0;
sc.MustGetString();
FTextureID texno = TexMan.CheckForTexture(sc.String, usetype);
int Mirror = 0;
if (!texno.isValid())
{
if (strlen(sc.String) <= 8 && !strpbrk(sc.String, "./"))
{
int lumpnum = Wads.CheckNumForName(sc.String, usetype == TEX_MiscPatch? ns_graphics : ns_patches);
if (lumpnum >= 0)
{
part.Texture = FTexture::CreateTexture(lumpnum, usetype);
TexMan.AddTexture(part.Texture);
}
}
}
else
{
part.Texture = TexMan[texno];
bComplex |= part.Texture->bComplex;
}
if (part.Texture == NULL)
{
if (!silent) sc.ScriptMessage(TEXTCOLOR_RED "Unknown patch '%s' in texture '%s'\n", sc.String, Name.GetChars());
}
init.TexName = sc.String;
sc.MustGetStringName(",");
sc.MustGetNumber();
part.OriginX = sc.Number;
@ -1179,11 +1141,7 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, bool silent, i
}
else if (sc.Compare("useoffsets"))
{
if (part.Texture != NULL)
{
part.OriginX -= part.Texture->LeftOffset;
part.OriginY -= part.Texture->TopOffset;
}
init.UseOffsets = true;
}
}
}
@ -1208,6 +1166,7 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
: Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false)
{
TArray<TexPart> parts;
TArray<TexInit> inits;
bool bSilent = false;
bMultiPatch = true;
@ -1268,16 +1227,51 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
else if (sc.Compare("Patch"))
{
TexPart part;
ParsePatch(sc, part, bSilent, TEX_WallPatch);
if (part.Texture != NULL) parts.Push(part);
TexInit init;
ParsePatch(sc, part, init);
if (init.TexName.IsNotEmpty())
{
parts.Push(part);
init.UseType = TEX_WallPatch;
init.Silent = bSilent;
init.HasLine = true;
init.sc = sc;
inits.Push(init);
}
part.Texture = NULL;
part.Translation = NULL;
}
else if (sc.Compare("Sprite"))
{
TexPart part;
TexInit init;
ParsePatch(sc, part, init);
if (init.TexName.IsNotEmpty())
{
parts.Push(part);
init.UseType = TEX_Sprite;
init.Silent = bSilent;
init.HasLine = true;
init.sc = sc;
inits.Push(init);
}
part.Texture = NULL;
part.Translation = NULL;
}
else if (sc.Compare("Graphic"))
{
TexPart part;
ParsePatch(sc, part, bSilent, TEX_MiscPatch);
if (part.Texture != NULL) parts.Push(part);
TexInit init;
ParsePatch(sc, part, init);
if (init.TexName.IsNotEmpty())
{
parts.Push(part);
init.UseType = TEX_MiscPatch;
init.Silent = bSilent;
init.HasLine = true;
init.sc = sc;
inits.Push(init);
}
part.Texture = NULL;
part.Translation = NULL;
}
@ -1298,21 +1292,10 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
NumParts = parts.Size();
Parts = new TexPart[NumParts];
memcpy(Parts, &parts[0], NumParts * sizeof(*Parts));
//CalcBitSize ();
// If this texture is just a wrapper around a single patch, we can simply
// forward GetPixels() and GetColumn() calls to that patch.
if (NumParts == 1)
Inits = new TexInit[NumParts];
for (int i = 0; i < NumParts; i++)
{
if (Parts->OriginX == 0 && Parts->OriginY == 0 &&
Parts->Texture->GetWidth() == Width &&
Parts->Texture->GetHeight() == Height &&
Parts->Rotate == 0 &&
!bComplex)
{
bRedirect = true;
}
Inits[i] = inits[i];
}
}
@ -1329,6 +1312,89 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
}
void FMultiPatchTexture::ResolvePatches()
{
if (Inits != nullptr)
{
for (int i = 0; i < NumParts; i++)
{
FTextureID texno = TexMan.CheckForTexture(Inits[i].TexName, Inits[i].UseType);
if (texno == id) // we found ourselves. Try looking for another one with the same name which is not a multipatch texture itself.
{
TArray<FTextureID> list;
TexMan.ListTextures(Inits[i].TexName, list, true);
for (int i = list.Size() - 1; i >= 0; i--)
{
if (list[i] != id && !TexMan[list[i]]->bMultiPatch)
{
texno = list[i];
break;
}
}
if (texno == id)
{
if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars());
else Printf(TEXTCOLOR_YELLOW "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars());
continue;
}
else
{
// If it could be resolved, just print a developer warning.
DPrintf(DMSG_WARNING, "Resolved self-referencing texture by picking an older entry for %s\n", Inits[i].TexName.GetChars());
}
}
if (!texno.isValid())
{
if (!Inits[i].Silent)
{
if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Unknown patch '%s' in texture '%s'\n", Inits[i].TexName.GetChars(), Name.GetChars());
else Printf(TEXTCOLOR_YELLOW "Unknown patch '%s' in texture '%s'\n", Inits[i].TexName.GetChars(), Name.GetChars());
}
}
else
{
Parts[i].Texture = TexMan[texno];
bComplex |= Parts[i].Texture->bComplex;
Parts[i].Texture->bKeepAround = true;
if (Inits[i].UseOffsets)
{
Parts[i].OriginX -= Parts[i].Texture->LeftOffset;
Parts[i].OriginY -= Parts[i].Texture->TopOffset;
}
}
}
for (int i = 0; i < NumParts; i++)
{
if (Parts[i].Texture == nullptr)
{
memcpy(&Parts[i], &Parts[i + 1], NumParts - i - 1);
i--;
NumParts--;
}
}
}
delete[] Inits;
Inits = nullptr;
CheckForHacks();
// If this texture is just a wrapper around a single patch, we can simply
// forward GetPixels() and GetColumn() calls to that patch.
if (NumParts == 1)
{
if (Parts->OriginX == 0 && Parts->OriginY == 0 &&
Parts->Texture->GetWidth() == Width &&
Parts->Texture->GetHeight() == Height &&
Parts->Rotate == 0 &&
!bComplex)
{
bRedirect = true;
}
}
}
void FTextureManager::ParseXTexture(FScanner &sc, int usetype)
{

View file

@ -210,8 +210,9 @@ void FTexture::CalcBitSize ()
}
WidthMask = (1 << WidthBits) - 1;
// The minimum height is 2, because we cannot shift right 32 bits.
for (i = 1; (1 << i) < Height; ++i)
// <hr>The minimum height is 2, because we cannot shift right 32 bits.</hr>
// Scratch that. Somebody actually made a 1x1 texture, so now we have to handle it.
for (i = 0; (1 << i) < Height; ++i)
{ }
HeightBits = i;
@ -615,8 +616,6 @@ namespace
PalEntry FTexture::GetSkyCapColor(bool bottom)
{
PalEntry col;
int w;
int h;
if (!bSWSkyColorDone)
{

View file

@ -267,7 +267,7 @@ FTextureID FTextureManager::CheckForTexture (const char *name, int usetype, BITF
//
//==========================================================================
int FTextureManager::ListTextures (const char *name, TArray<FTextureID> &list)
int FTextureManager::ListTextures (const char *name, TArray<FTextureID> &list, bool listall)
{
int i;
@ -293,11 +293,14 @@ int FTextureManager::ListTextures (const char *name, TArray<FTextureID> &list)
// NULL textures must be ignored.
if (tex->UseType!=FTexture::TEX_Null)
{
unsigned int j;
for(j = 0; j < list.Size(); j++)
unsigned int j = list.Size();
if (!listall)
{
// Check for overriding definitions from newer WADs
if (Textures[list[j].GetIndex()].Texture->UseType == tex->UseType) break;
for (j = 0; j < list.Size(); j++)
{
// Check for overriding definitions from newer WADs
if (Textures[list[j].GetIndex()].Texture->UseType == tex->UseType) break;
}
}
if (j==list.Size()) list.Push(FTextureID(i));
}
@ -981,6 +984,10 @@ void FTextureManager::Init()
{
AddTexturesForWad(i);
}
for (unsigned i = 0; i < Textures.Size(); i++)
{
Textures[i].Texture->ResolvePatches();
}
// Add one marker so that the last WAD is easier to handle and treat
// Build tiles as a completely separate block.

View file

@ -232,6 +232,7 @@ public:
int GetScaledTopOffset () { int foo = int((TopOffset * 2) / Scale.Y); return (foo >> 1) + (foo & 1); }
double GetScaledLeftOffsetDouble() { return LeftOffset / Scale.X; }
double GetScaledTopOffsetDouble() { return TopOffset / Scale.Y; }
virtual void ResolvePatches() {}
virtual void SetFrontSkyLayer();
@ -411,7 +412,7 @@ public:
FTextureID CheckForTexture (const char *name, int usetype, BITFIELD flags=TEXMAN_TryAny);
FTextureID GetTexture (const char *name, int usetype, BITFIELD flags=0);
int ListTextures (const char *name, TArray<FTextureID> &list);
int ListTextures (const char *name, TArray<FTextureID> &list, bool listall = false);
void AddTexturesLump (const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup=0, bool texture1=false);
void AddTexturesLumps (int lump1, int lump2, int patcheslump);

View file

@ -2945,6 +2945,26 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss
}
}
//==========================================================================
//
// [SP] Player.Viewbob
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, viewbob, F, PlayerPawn)
{
PROP_DOUBLE_PARM(z, 0);
// [SP] Hard limits. This is to prevent terrywads from making players sick.
// Remember - this messes with a user option who probably has it set a
// certain way for a reason. I think a 1.5 limit is pretty generous, but
// it may be safe to increase it. I really need opinions from people who
// could be affected by this.
if (z < 0.0 || z > 1.5)
{
I_Error("ViewBob must be between 0.0 and 1.5.");
}
defaults->ViewBob = z;
}
//==========================================================================
//
//==========================================================================

View file

@ -299,7 +299,7 @@ void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms)
while ((dc_x < stop4) && (dc_x & 3))
{
pixels = img->GetColumn(frac >> FRACBITS, spanptr);
R_DrawMaskedColumn(pixels, spans);
R_DrawMaskedColumn(pixels, spans, false);
dc_x++;
frac += xiscale_i;
}
@ -310,7 +310,7 @@ void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms)
for (int zz = 4; zz; --zz)
{
pixels = img->GetColumn(frac >> FRACBITS, spanptr);
R_DrawMaskedColumnHoriz(pixels, spans);
R_DrawMaskedColumn(pixels, spans, true);
dc_x++;
frac += xiscale_i;
}
@ -320,7 +320,7 @@ void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms)
while (dc_x < x2_i)
{
pixels = img->GetColumn(frac >> FRACBITS, spanptr);
R_DrawMaskedColumn(pixels, spans);
R_DrawMaskedColumn(pixels, spans, false);
dc_x++;
frac += xiscale_i;
}
@ -1282,7 +1282,7 @@ void DCanvas::FinishSimplePolys()
void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley, DAngle rotation,
FDynamicColormap *colormap, int lightlevel)
FDynamicColormap *colormap, int lightlevel, int bottomclip)
{
#ifndef NO_SWRENDER
// Use an equation similar to player sprites to determine shade
@ -1300,6 +1300,11 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
return;
}
if (bottomclip <= 0)
{
bottomclip = Height;
}
// Find the extents of the polygon, in particular the highest and lowest points.
for (botpt = toppt = 0, boty = topy = points[0].Y, leftx = rightx = points[0].X, i = 1; i <= npoints; ++i)
{
@ -1322,7 +1327,7 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
rightx = points[i].X;
}
}
if (topy >= Height || // off the bottom of the screen
if (topy >= bottomclip || // off the bottom of the screen
boty <= 0 || // off the top of the screen
leftx >= Width || // off the right of the screen
rightx <= 0) // off the left of the screen
@ -1330,6 +1335,13 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
return;
}
BYTE *destorgsave = dc_destorg;
dc_destorg = screen->GetBuffer();
if (dc_destorg == NULL)
{
I_FatalError("Attempt to write to buffer of hardware canvas");
}
scalex /= tex->Scale.X;
scaley /= tex->Scale.Y;
@ -1341,10 +1353,26 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
R_SetupSpanBits(tex);
R_SetSpanColormap(colormap != NULL ? &colormap->Maps[clamp(shade >> FRACBITS, 0, NUMCOLORMAPS-1) * 256] : identitymap);
R_SetSpanSource(tex->GetPixels());
scalex = double(1u << (32 - ds_xbits)) / scalex;
scaley = double(1u << (32 - ds_ybits)) / scaley;
ds_xstep = xs_RoundToInt(cosrot * scalex);
ds_ystep = xs_RoundToInt(sinrot * scaley);
if (ds_xbits != 0)
{
scalex = double(1u << (32 - ds_xbits)) / scalex;
ds_xstep = xs_RoundToInt(cosrot * scalex);
}
else
{ // Texture is one pixel wide.
scalex = 0;
ds_xstep = 0;
}
if (ds_ybits != 0)
{
scaley = double(1u << (32 - ds_ybits)) / scaley;
ds_ystep = xs_RoundToInt(sinrot * scaley);
}
else
{ // Texture is one pixel tall.
scaley = 0;
ds_ystep = 0;
}
// Travel down the right edge and create an outline of that edge.
pt1 = toppt;
@ -1354,13 +1382,13 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
{
x = FLOAT2FIXED(points[pt1].X + 0.5f);
y2 = xs_RoundToInt(points[pt2].Y + 0.5f);
if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height))
if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= bottomclip && y2 >= bottomclip))
{
}
else
{
fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y));
int y3 = MIN(y2, Height);
int y3 = MIN(y2, bottomclip);
if (y1 < 0)
{
x += xinc * -y1;
@ -1385,13 +1413,13 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
{
x = FLOAT2FIXED(points[pt1].X + 0.5f);
y2 = xs_RoundToInt(points[pt2].Y + 0.5f);
if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height))
if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= bottomclip && y2 >= bottomclip))
{
}
else
{
fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y));
int y3 = MIN(y2, Height);
int y3 = MIN(y2, bottomclip);
if (y1 < 0)
{
x += xinc * -y1;
@ -1432,6 +1460,7 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
pt1 = pt2;
pt2--; if (pt2 < 0) pt2 = npoints;
} while (pt1 != botpt);
dc_destorg = destorgsave;
#endif
}

View file

@ -72,7 +72,7 @@ FRenderer *Renderer;
IMPLEMENT_ABSTRACT_CLASS (DCanvas)
IMPLEMENT_ABSTRACT_CLASS (DFrameBuffer)
#if defined(_DEBUG) && defined(_M_IX86)
#if defined(_DEBUG) && defined(_M_IX86) && !defined(__MINGW32__)
#define DBGBREAK { __asm int 3 }
#else
#define DBGBREAK
@ -877,8 +877,6 @@ void DFrameBuffer::DrawRateStuff ()
int rate_x;
int textScale = active_con_scale();
if (textScale == 0)
textScale = CleanXfac;
chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2u ms (%3u fps)", howlong, LastCount);
rate_x = Width / textScale - ConFont->StringWidth(&fpsbuff[0]);

View file

@ -224,7 +224,7 @@ public:
// Fill a simple polygon with a texture
virtual void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley, DAngle rotation,
struct FDynamicColormap *colormap, int lightlevel);
struct FDynamicColormap *colormap, int lightlevel, int bottomclip);
// Set an area to a specified color
virtual void Clear (int left, int top, int right, int bottom, int palcolor, uint32 color);

View file

@ -1092,6 +1092,7 @@ void D3DFB::Update ()
DrawRateStuff();
DrawPackedTextures(d3d_showpacks);
EndBatch(); // Make sure all batched primitives are drawn.
In2D = 0;
Flip();
}
In2D = 0;
@ -3083,11 +3084,16 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo
//
// Here, "simple" means that a simple triangle fan can draw it.
//
// Bottomclip is ignored by this implementation, since the hardware renderer
// will unconditionally draw the status bar border every frame on top of the
// polygons, so there's no need to waste time setting up a special scissor
// rectangle here and needlessly forcing separate batches.
//
//==========================================================================
void D3DFB::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, FDynamicColormap *colormap, int lightlevel)
DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip)
{
// Use an equation similar to player sprites to determine shade
double fadelevel = clamp((LIGHT2SHADE(lightlevel)/65536. - 12) / NUMCOLORMAPS, 0.0, 1.0);
@ -3108,7 +3114,7 @@ void D3DFB::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
}
if (In2D < 2)
{
Super::FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley, rotation, colormap, lightlevel);
Super::FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley, rotation, colormap, lightlevel, bottomclip);
return;
}
if (!InScene)

View file

@ -75,54 +75,6 @@
#include <time.h>
#include <zlib.h>
#if defined(_WIN64) && defined(__GNUC__)
struct KNONVOLATILE_CONTEXT_POINTERS {
union {
PDWORD64 IntegerContext[16];
struct {
PDWORD64 Rax;
PDWORD64 Rcx;
PDWORD64 Rdx;
PDWORD64 Rbx;
PDWORD64 Rsp;
PDWORD64 Rbp;
PDWORD64 Rsi;
PDWORD64 Rdi;
PDWORD64 R8;
PDWORD64 R9;
PDWORD64 R10;
PDWORD64 R11;
PDWORD64 R12;
PDWORD64 R13;
PDWORD64 R14;
PDWORD64 R15;
};
};
};
typedef
EXCEPTION_DISPOSITION
NTAPI
EXCEPTION_ROUTINE (
struct _EXCEPTION_RECORD *ExceptionRecord,
PVOID EstablisherFrame,
struct _CONTEXT *ContextRecord,
PVOID DispatcherContext
);
NTSYSAPI
EXCEPTION_ROUTINE *
NTAPI
RtlVirtualUnwind (
DWORD HandlerType,
DWORD64 ImageBase,
DWORD64 ControlPc,
PRUNTIME_FUNCTION FunctionEntry,
PCONTEXT ContextRecord,
PVOID *HandlerData,
PDWORD64 EstablisherFrame,
KNONVOLATILE_CONTEXT_POINTERS *ContextPointers
);
#endif
// MACROS ------------------------------------------------------------------
#define REMOTE_HOST "localhost"

View file

@ -21,6 +21,11 @@
#define DINPUT_BUFFERSIZE 32
// MinGW-w64 (TDM5.1 - 2016/11/21)
#ifndef DIK_PREVTRACK
#define DIK_PREVTRACK DIK_CIRCUMFLEX
#endif
// TYPES -------------------------------------------------------------------
class FDInputKeyboard : public FKeyboard

View file

@ -68,6 +68,7 @@
#include "doomtype.h"
#include "m_argv.h"
#include "d_main.h"
#include "i_module.h"
#include "i_system.h"
#include "c_console.h"
#include "version.h"
@ -84,6 +85,8 @@
#include "stats.h"
#include "st_start.h"
#include "optwin32.h"
#include <assert.h>
// MACROS ------------------------------------------------------------------
@ -143,6 +146,21 @@ LONG GameTitleFontHeight;
LONG DefaultGUIFontHeight;
LONG ErrorIconChar;
FModule Kernel32Module{"Kernel32"};
FModule Shell32Module{"Shell32"};
FModule User32Module{"User32"};
namespace OptWin32 {
#define DYN_WIN32_SYM(x) decltype(x) x{#x}
DYN_WIN32_SYM(SHGetFolderPathA);
DYN_WIN32_SYM(SHGetKnownFolderPath);
DYN_WIN32_SYM(GetLongPathNameA);
DYN_WIN32_SYM(GetMonitorInfoA);
#undef DYN_WIN32_SYM
} // namespace OptWin32
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static const char WinClassName[] = GAMENAME "MainWindow";
@ -818,6 +836,11 @@ void DoMain (HINSTANCE hInstance)
Args = new DArgs(__argc, __argv);
// Load Win32 modules
Kernel32Module.Load({"kernel32.dll"});
Shell32Module.Load({"shell32.dll"});
User32Module.Load({"user32.dll"});
// Under XP, get our session ID so we can know when the user changes/locks sessions.
// Since we need to remain binary compatible with older versions of Windows, we
// need to extract the ProcessIdToSessionId function from kernel32.dll manually.

View file

@ -389,7 +389,7 @@ bool FRawPS2Controller::ProcessInput(RAWHID *raw, int code)
{
// w32api has an incompatible definition of bRawData.
// (But the version that comes with MinGW64 is fine.)
#if defined(__GNUC__) && !defined(_WIN64)
#if defined(__GNUC__) && !defined(__MINGW64_VERSION_MAJOR)
BYTE *rawdata = &raw->bRawData;
#else
BYTE *rawdata = raw->bRawData;

View file

@ -33,6 +33,7 @@
**
*/
#define _WIN32_WINNT 0x0601
#include <windows.h>
#include <lmcons.h>
#include <shlobj.h>
@ -43,7 +44,16 @@
#include "version.h" // for GAMENAME
#include "i_system.h"
typedef HRESULT (WINAPI *GKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *);
#include "optwin32.h"
// Vanilla MinGW does not have folder ids
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
static const GUID FOLDERID_LocalAppData = { 0xf1b32785, 0x6fba, 0x4fcf, 0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91 };
static const GUID FOLDERID_RoamingAppData = { 0x3eb685db, 0x65f9, 0x4cf6, 0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d };
static const GUID FOLDERID_SavedGames = { 0x4c5c32ff, 0xbb9d, 0x43b0, 0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4 };
static const GUID FOLDERID_Documents = { 0xfdd39ad0, 0x238f, 0x46af, 0xad, 0xb4, 0x6c, 0x85, 0x48, 0x03, 0x69, 0xc7 };
static const GUID FOLDERID_Pictures = { 0x33e28130, 0x4e1e, 0x4676, 0x83, 0x5a, 0x98, 0x39, 0x5c, 0x3b, 0xc3, 0xbb };
#endif
//===========================================================================
//
@ -94,19 +104,17 @@ bool UseKnownFolders()
bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create, FString &path)
{
static TOptWin32Proc<GKFP> SHGetKnownFolderPath("shell32.dll", "SHGetKnownFolderPath");
using OptWin32::SHGetFolderPathA;
using OptWin32::SHGetKnownFolderPath;
char pathstr[MAX_PATH];
// SHGetKnownFolderPath knows about more folders than SHGetFolderPath, but is
// new to Vista, hence the reason we support both.
if (SHGetKnownFolderPath == NULL)
if (!SHGetKnownFolderPath)
{
static TOptWin32Proc<HRESULT(WINAPI*)(HWND, int, HANDLE, DWORD, LPTSTR)>
SHGetFolderPathA("shell32.dll", "SHGetFolderPathA");
// NT4 doesn't even have this function.
if (SHGetFolderPathA == NULL)
if (!SHGetFolderPathA)
return false;
if (shell_folder < 0)
@ -117,7 +125,7 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create
{
shell_folder |= CSIDL_FLAG_CREATE;
}
if (FAILED(SHGetFolderPathA.Call(NULL, shell_folder, NULL, 0, pathstr)))
if (FAILED(SHGetFolderPathA(NULL, shell_folder, NULL, 0, pathstr)))
{
return false;
}
@ -127,7 +135,7 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create
else
{
PWSTR wpath;
if (FAILED(SHGetKnownFolderPath.Call(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath)))
if (FAILED(SHGetKnownFolderPath(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath)))
{
return false;
}

View file

@ -86,6 +86,8 @@
#include "textures/bitmap.h"
#include "textures/textures.h"
#include "optwin32.h"
// MACROS ------------------------------------------------------------------
#ifdef _MSC_VER
@ -1312,7 +1314,7 @@ static HCURSOR CreateCompatibleCursor(FTexture *cursorpic)
HDC dc = GetDC(NULL);
if (dc == NULL)
{
return false;
return nullptr;
}
HDC and_mask_dc = CreateCompatibleDC(dc);
HDC xor_mask_dc = CreateCompatibleDC(dc);
@ -1716,20 +1718,19 @@ unsigned int I_MakeRNGSeed()
FString I_GetLongPathName(FString shortpath)
{
static TOptWin32Proc<DWORD (WINAPI*)(LPCTSTR, LPTSTR, DWORD)>
GetLongPathNameA("kernel32.dll", "GetLongPathNameA");
using OptWin32::GetLongPathNameA;
// Doesn't exist on NT4
if (GetLongPathName == NULL)
if (!GetLongPathNameA)
return shortpath;
DWORD buffsize = GetLongPathNameA.Call(shortpath.GetChars(), NULL, 0);
DWORD buffsize = GetLongPathNameA(shortpath.GetChars(), NULL, 0);
if (buffsize == 0)
{ // nothing to change (it doesn't exist, maybe?)
return shortpath;
}
TCHAR *buff = new TCHAR[buffsize];
DWORD buffsize2 = GetLongPathNameA.Call(shortpath.GetChars(), buff, buffsize);
DWORD buffsize2 = GetLongPathNameA(shortpath.GetChars(), buff, buffsize);
if (buffsize2 >= buffsize)
{ // Failure! Just return the short path
delete[] buff;

View file

@ -51,30 +51,6 @@ typedef enum {
extern os_t OSPlatform;
// Helper template so that we can access newer Win32 functions with a single static
// variable declaration. If this were C++11 it could be totally transparent.
template<typename Proto>
class TOptWin32Proc
{
static Proto GetOptionalWin32Proc(const char* module, const char* function)
{
HMODULE hmodule = GetModuleHandle(module);
if (hmodule == NULL)
return NULL;
return (Proto)GetProcAddress(hmodule, function);
}
public:
const Proto Call;
TOptWin32Proc(const char* module, const char* function)
: Call(GetOptionalWin32Proc(module, function)) {}
// Wrapper object can be tested against NULL, but not directly called.
operator const void*() const { return Call; }
};
// Called by DoomMain.
void I_Init (void);

View file

@ -33,6 +33,17 @@
#define XUSER_MAX_COUNT 4
#endif
// MinGW
#ifndef XINPUT_DLL
#define XINPUT_DLL_A "xinput1_3.dll"
#define XINPUT_DLL_W L"xinput1_3.dll"
#ifdef UNICODE
#define XINPUT_DLL XINPUT_DLL_W
#else
#define XINPUT_DLL XINPUT_DLL_A
#endif
#endif
// TYPES -------------------------------------------------------------------
typedef DWORD (WINAPI *XInputGetStateType)(DWORD index, XINPUT_STATE *state);

24
src/win32/optwin32.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
// Forward declarations for optional Win32 API procedures
// implemented in i_main.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shlobj.h>
#define USE_WINDOWS_DWORD
#include "i_module.h"
extern FModule Kernel32Module;
extern FModule Shell32Module;
extern FModule User32Module;
namespace OptWin32 {
extern TOptProc<Shell32Module, HRESULT(WINAPI*)(HWND, int, HANDLE, DWORD, LPTSTR)> SHGetFolderPathA;
extern TOptProc<Shell32Module, HRESULT(WINAPI*)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *)> SHGetKnownFolderPath;
extern TOptProc<Kernel32Module, DWORD (WINAPI*)(LPCTSTR, LPTSTR, DWORD)> GetLongPathNameA;
extern TOptProc<User32Module, BOOL(WINAPI*)(HMONITOR, LPMONITORINFO)> GetMonitorInfoA;
} // namespace OptWin32

View file

@ -265,7 +265,7 @@ public:
void DrawPixel(int x, int y, int palcolor, uint32 rgbcolor);
void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, FDynamicColormap *colormap, int lightlevel);
DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip) override;
bool WipeStartScreen(int type);
void WipeEndScreen();
bool WipeDo(int ticks);

View file

@ -74,6 +74,8 @@
#include "win32iface.h"
#include "optwin32.h"
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
@ -387,6 +389,8 @@ void Win32Video::BlankForGDI ()
void Win32Video::DumpAdapters()
{
using OptWin32::GetMonitorInfoA;
if (D3D == NULL)
{
Printf("Multi-monitor support requires Direct3D.\n");
@ -415,9 +419,8 @@ void Win32Video::DumpAdapters()
MONITORINFOEX mi;
mi.cbSize = sizeof(mi);
TOptWin32Proc<BOOL(WINAPI*)(HMONITOR, LPMONITORINFO)> GetMonitorInfo("user32.dll", "GetMonitorInfoW");
assert(GetMonitorInfo != NULL); // Missing in NT4, but so is D3D
if (GetMonitorInfo.Call(hm, &mi))
assert(GetMonitorInfo); // Missing in NT4, but so is D3D
if (GetMonitorInfo(hm, &mi))
{
mysnprintf(moreinfo, countof(moreinfo), " [%ldx%ld @ (%ld,%ld)]%s",
mi.rcMonitor.right - mi.rcMonitor.left,

View file

@ -11,21 +11,21 @@
#if COMPGOTO
#define OP(x) x
#define NEXTOP do { unsigned op = pc->op; a = pc->a; pc++; goto *ops[op]; } while(0)
#define NEXTOP do { pc++; unsigned op = pc->op; a = pc->a; goto *ops[op]; } while(0)
#else
#define OP(x) case OP_##x
#define NEXTOP break
#define NEXTOP pc++; break
#endif
#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b))
#define A (pc[-1].a)
#define B (pc[-1].b)
#define C (pc[-1].c)
#define Cs (pc[-1].cs)
#define BC (pc[-1].i16u)
#define BCs (pc[-1].i16)
#define ABCs (pc[-1].i24)
#define A (pc[0].a)
#define B (pc[0].b)
#define C (pc[0].c)
#define Cs (pc[0].cs)
#define BC (pc[0].i16u)
#define BCs (pc[0].i16)
#define ABCs (pc[0].i24)
#define JMPOFS(x) ((x)->i24)
#define KC (konstd[C])
@ -48,8 +48,8 @@
#define CMPJMP(test) \
if ((test) == (a & CMP_CHECK)) { \
assert(pc->op == OP_JMP); \
pc += 1 + JMPOFS(pc); \
assert(pc[1].op == OP_JMP); \
pc += 1 + JMPOFS(pc+1); \
} else { \
pc += 1; \
}

View file

@ -52,11 +52,17 @@ begin:
{
#if !COMPGOTO
VM_UBYTE op;
for(;;) switch(op = pc->op, a = pc->a, pc++, op)
for(;;) switch(op = pc->op, a = pc->a, op)
#else
pc--;
NEXTOP;
#endif
{
#if !COMPGOTO
default:
assert(0 && "Undefined opcode hit");
NEXTOP;
#endif
OP(LI):
ASSERTD(a);
reg.d[a] = BCs;
@ -367,13 +373,13 @@ begin:
}
NEXTOP;
OP(JMP):
pc += JMPOFS(pc - 1);
pc += JMPOFS(pc);
NEXTOP;
OP(IJMP):
ASSERTD(a);
pc += (BCs + reg.d[a]);
assert(pc->op == OP_JMP);
pc += 1 + JMPOFS(pc);
assert(pc[1].op == OP_JMP);
pc += 1 + JMPOFS(pc+1);
NEXTOP;
OP(PARAMI):
assert(f->NumParam < sfunc->MaxParam);
@ -490,7 +496,7 @@ begin:
VMReturn returns[MAX_RETURNS];
int numret;
FillReturns(reg, f, returns, pc, C);
FillReturns(reg, f, returns, pc+1, C);
if (call->Native)
{
numret = static_cast<VMNativeFunction *>(call)->NativeCall(stack, reg.param + f->NumParam - B, B, returns, C);
@ -603,8 +609,8 @@ begin:
{
THROW(X_TOO_MANY_TRIES);
}
assert((pc + JMPOFS(pc - 1))->op == OP_CATCH);
exception_frames[try_depth++] = pc + JMPOFS(pc - 1);
assert((pc + JMPOFS(pc) + 1)->op == OP_CATCH);
exception_frames[try_depth++] = pc + JMPOFS(pc) + 1;
NEXTOP;
OP(UNTRY):
assert(a <= try_depth);
@ -704,8 +710,8 @@ begin:
}
if (cmp == (a & CMP_CHECK))
{
assert(pc->op == OP_JMP);
pc += 1 + JMPOFS(pc);
assert(pc[1].op == OP_JMP);
pc += 1 + JMPOFS(pc+1);
}
else
{

View file

@ -343,28 +343,74 @@ FString &FString::operator += (char tail)
FString &FString::AppendCStrPart (const char *tail, size_t tailLen)
{
size_t len1 = Len();
ReallocBuffer (len1 + tailLen);
StrCopy (Chars + len1, tail, tailLen);
if (tailLen > 0)
{
size_t len1 = Len();
ReallocBuffer(len1 + tailLen);
StrCopy(Chars + len1, tail, tailLen);
}
return *this;
}
FString &FString::CopyCStrPart(const char *tail, size_t tailLen)
{
ReallocBuffer(tailLen);
StrCopy(Chars, tail, tailLen);
if (tailLen > 0)
{
ReallocBuffer(tailLen);
StrCopy(Chars, tail, tailLen);
}
else
{
Data()->Release();
NullString.RefCount++;
Chars = &NullString.Nothing[0];
}
return *this;
}
void FString::Truncate(long newlen)
{
if (newlen >= 0 && newlen < (long)Len())
if (newlen <= 0)
{
Data()->Release();
NullString.RefCount++;
Chars = &NullString.Nothing[0];
}
else if (newlen < (long)Len())
{
ReallocBuffer (newlen);
Chars[newlen] = '\0';
}
}
void FString::Remove(size_t index, size_t remlen)
{
if (index < Len())
{
if (index + remlen >= Len())
{
Truncate((long)index);
}
else
{
remlen = Len() - remlen < remlen ? Len() - remlen : remlen;
if (Data()->RefCount == 1)
{ // Can do this in place
memmove(Chars + index, Chars + index + remlen, Len() - index - remlen);
Data()->Len -= (unsigned)remlen;
}
else
{ // Must do it in a copy
FStringData *old = Data();
AllocBuffer(old->Len - remlen);
StrCopy(Chars, old->Chars(), index);
StrCopy(Chars + index, old->Chars() + index + remlen, old->Len - index - remlen);
old->Release();
}
}
}
}
FString FString::Left (size_t numChars) const
{
size_t len = Len();
@ -586,9 +632,13 @@ void FString::StripLeft ()
if (max == 0) return;
for (i = 0; i < max; ++i)
{
if (!isspace(Chars[i]))
if (!isspace((unsigned char)Chars[i]))
break;
}
if (i == 0)
{ // Nothing to strip.
return;
}
if (Data()->RefCount <= 1)
{
for (j = 0; i <= max; ++j, ++i)
@ -620,6 +670,10 @@ void FString::StripLeft (const char *charset)
if (!strchr (charset, Chars[i]))
break;
}
if (i == 0)
{ // Nothing to strip.
return;
}
if (Data()->RefCount <= 1)
{
for (j = 0; i <= max; ++j, ++i)
@ -640,11 +694,16 @@ void FString::StripLeft (const char *charset)
void FString::StripRight ()
{
size_t max = Len(), i;
for (i = max; i-- > 0; )
if (max == 0) return;
for (i = --max; i-- > 0; )
{
if (!isspace(Chars[i]))
if (!isspace((unsigned char)Chars[i]))
break;
}
if (i == max)
{ // Nothing to strip.
return;
}
if (Data()->RefCount <= 1)
{
Chars[i+1] = '\0';
@ -668,11 +727,15 @@ void FString::StripRight (const char *charset)
{
size_t max = Len(), i;
if (max == 0) return;
for (i = max; i-- > 0; )
for (i = --max; i-- > 0; )
{
if (!strchr (charset, Chars[i]))
break;
}
if (i == max)
{ // Nothing to strip.
return;
}
if (Data()->RefCount <= 1)
{
Chars[i+1] = '\0';
@ -693,14 +756,18 @@ void FString::StripLeftRight ()
if (max == 0) return;
for (i = 0; i < max; ++i)
{
if (!isspace(Chars[i]))
if (!isspace((unsigned char)Chars[i]))
break;
}
for (j = max - 1; j >= i; --j)
{
if (!isspace(Chars[j]))
if (!isspace((unsigned char)Chars[j]))
break;
}
if (i == 0 && j == max - 1)
{ // Nothing to strip.
return;
}
if (Data()->RefCount <= 1)
{
for (k = 0; i <= j; ++i, ++k)
@ -713,8 +780,8 @@ void FString::StripLeftRight ()
else
{
FStringData *old = Data();
AllocBuffer (j - i);
StrCopy (Chars, old->Chars(), j - i);
AllocBuffer(j - i + 1);
StrCopy(Chars, old->Chars(), j - i + 1);
old->Release();
}
}
@ -768,25 +835,28 @@ void FString::Insert (size_t index, const char *instr)
void FString::Insert (size_t index, const char *instr, size_t instrlen)
{
size_t mylen = Len();
if (index > mylen)
if (instrlen > 0)
{
index = mylen;
}
if (Data()->RefCount <= 1)
{
ReallocBuffer (mylen + instrlen);
memmove (Chars + index + instrlen, Chars + index, (mylen - index + 1)*sizeof(char));
memcpy (Chars + index, instr, instrlen*sizeof(char));
}
else
{
FStringData *old = Data();
AllocBuffer (mylen + instrlen);
StrCopy (Chars, old->Chars(), index);
StrCopy (Chars + index, instr, instrlen);
StrCopy (Chars + index + instrlen, old->Chars() + index, mylen - index);
old->Release();
size_t mylen = Len();
if (index >= mylen)
{
AppendCStrPart(instr, instrlen);
}
else if (Data()->RefCount <= 1)
{
ReallocBuffer(mylen + instrlen);
memmove(Chars + index + instrlen, Chars + index, (mylen - index + 1) * sizeof(char));
memcpy(Chars + index, instr, instrlen * sizeof(char));
}
else
{
FStringData *old = Data();
AllocBuffer(mylen + instrlen);
StrCopy(Chars, old->Chars(), index);
StrCopy(Chars + index, instr, instrlen);
StrCopy(Chars + index + instrlen, old->Chars() + index, mylen - index);
old->Release();
}
}
}
@ -970,7 +1040,7 @@ octdigits = [0-7];
yych = *YYCURSOR;
// Skip preceding whitespace
while (yych != '\0' && isspace(yych)) { yych = *++YYCURSOR; }
while (yych != '\0' && isspace((unsigned char)yych)) { yych = *++YYCURSOR; }
// Check for sign
if (yych == '+' || yych == '-') { yych = *++YYCURSOR; }
@ -1008,7 +1078,7 @@ octdigits = [0-7];
}
// The rest should all be whitespace
while (yych != '\0' && isspace(yych)) { yych = *++YYCURSOR; }
while (yych != '\0' && isspace((unsigned char)yych)) { yych = *++YYCURSOR; }
return yych == '\0';
}
@ -1028,7 +1098,7 @@ digits = [0-9];
yych = *YYCURSOR;
// Skip preceding whitespace
while (yych != '\0' && isspace(yych)) { yych = *++YYCURSOR; }
while (yych != '\0' && isspace((unsigned char)yych)) { yych = *++YYCURSOR; }
// Check for sign
if (yych == '+' || yych == '-') { yych = *++YYCURSOR; }
@ -1059,7 +1129,7 @@ digits = [0-9];
}
// The rest should all be whitespace
while (yych != '\0' && isspace(yych)) { yych = *++YYCURSOR; }
while (yych != '\0' && isspace((unsigned char)yych)) { yych = *++YYCURSOR; }
return yych == '\0';
}

View file

@ -268,6 +268,7 @@ public:
bool IsNotEmpty() const { return Len() != 0; }
void Truncate (long newlen);
void Remove(size_t index, size_t remlen);
int Compare (const FString &other) const { return strcmp (Chars, other.Chars); }
int Compare (const char *other) const { return strcmp (Chars, other); }

View file

@ -1,19 +1,12 @@
cmake_minimum_required( VERSION 2.8.7 )
if( WIN32 )
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE OR ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/trustinfo.o
COMMAND windres -o ${CMAKE_CURRENT_BINARY_DIR}/trustinfo.o -i ${CMAKE_CURRENT_SOURCE_DIR}/trustinfo.rc
DEPENDS trustinfo.rc )
set( TRUSTINFO trustinfo.o )
if( MSVC_VERSION GREATER 1399 )
# VC 8+ adds a manifest automatically to the executable. We need to
# merge ours with it.
set( MT_MERGE ON )
else()
if( MSVC_VERSION GREATER 1399 )
# VC 8+ adds a manifest automatically to the executable. We need to
# merge ours with it.
set( MT_MERGE ON )
else( MSVC_VERSION GREATER 1399 )
set( TRUSTINFO trustinfo.rc )
endif( MSVC_VERSION GREATER 1399 )
set( TRUSTINFO trustinfo.rc )
endif()
else( WIN32 )
set( TRUSTINFO "" )

View file

@ -191,7 +191,7 @@ ACTOR Actor native //: Thinker
action native A_ComboAttack();
action native A_BulletAttack();
action native A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", float snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, float runspeed = 160.0, class<Actor> pufftype = "BulletPuff");
action native A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, float volume = 1.0, bool looping = false, float attenuation = ATTN_NORM);
action native A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, float volume = 1.0, bool looping = false, float attenuation = ATTN_NORM, bool local = false);
native void A_PlayWeaponSound(sound whattoplay);
action native A_FLoopActiveSound();
action native A_LoopActiveSound();

Some files were not shown because too many files have changed in this diff Show more