This commit is contained in:
Rachael Alexanderson 2017-11-07 11:57:25 -05:00
commit a87b24b510
444 changed files with 3058 additions and 1065 deletions

View file

@ -20,10 +20,10 @@ environment:
CONFIGURATION: Release
TOOLSET: v141_xp
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2017"
# - GENERATOR: "Visual Studio 15 2017 Win64"
# CONFIGURATION: Release
# TOOLSET: v141_xp
# APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2017"
- GENERATOR: "Visual Studio 15 2017 Win64"
CONFIGURATION: Release
TOOLSET: v141_xp
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2017"
- GENERATOR: "Visual Studio 14 2015 Win64"
CONFIGURATION: Debug
TOOLSET: v140
@ -33,7 +33,7 @@ build_script:
- md build
- cd build
- cmake -G "%GENERATOR%" -T "%TOOLSET%" ..
- cmake --build . --config "%CONFIGURATION%"
- cmake --build . --config "%CONFIGURATION%" -- /verbosity:minimal
after_build:
- set OUTPUT_DIR=%APPVEYOR_BUILD_FOLDER%\build\%CONFIGURATION%\

2
.gitignore vendored
View file

@ -46,7 +46,9 @@
/build_vc2015
/build_vc2015-32
/build_vc2015-64
/build_vc2017-64
/build
/llvm
/src/r_drawersasm.obj
/src/r_drawersasm.o
.vs

View file

@ -11,15 +11,28 @@ git:
matrix:
include:
- os: osx
osx_image: xcode8.3
osx_image: xcode9.1
env:
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.7"
- os: linux
compiler: gcc
env:
- GCC_VERSION=4.9
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.9
- libsdl2-dev
- os: linux
compiler: gcc
env:
- GCC_VERSION=5
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release"
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized"
addons:
apt:
sources:
@ -32,7 +45,7 @@ matrix:
compiler: gcc
env:
- GCC_VERSION=6
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=RelWithDebInfo"
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized"
addons:
apt:
sources:
@ -45,6 +58,7 @@ matrix:
compiler: gcc
env:
- GCC_VERSION=7
- CMAKE_OPTIONS="-DCMAKE_CXX_FLAGS=-Wno-implicit-fallthrough"
addons:
apt:
sources:

View file

@ -83,6 +83,7 @@ FIND_PATH(SDL2_INCLUDE_DIR SDL.h
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
/boot/system/develop/headers/SDL2 #Hiaku OS
)
#MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}")
@ -96,6 +97,7 @@ FIND_LIBRARY(SDL2_LIBRARY_TEMP
/opt/local
/opt/csw
/opt
/system/lib #Hiaku OS
)
#MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}")

373
docs/licenses/mpl.txt Normal file
View file

@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

View file

@ -23,6 +23,10 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#undef PI
#define PI 3.1415926535897932384626433832795029
#if _MSC_VER >= 1911 && defined _M_X64
#pragma float_control(precise, on, push)
#endif // _MSC_VER >= 1911 && _M_X64
static void gen_sinc( double rolloff, int width, double offset, double spacing, double scale,
int count, short* out )
{
@ -52,6 +56,10 @@ static void gen_sinc( double rolloff, int width, double offset, double spacing,
}
}
#if _MSC_VER >= 1911 && defined _M_X64
#pragma float_control(pop)
#endif // _MSC_VER >= 1911 && _M_X64
Fir_Resampler_::Fir_Resampler_( int width, sample_t* impulses_ ) :
width_( width ),
write_offset( width * stereo - stereo ),

View file

@ -342,9 +342,9 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")
set (USE_ARMV8 0 CACHE BOOL "Use ARMv8 instructions - Raspberry Pi 3")
if (USE_ARMV8)
set( CMAKE_CXX_FLAGS "-mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mtune=cortex-a53 -mhard-float -DNO_SSE ${CMAKE_CXX_FLAGS}" )
set( CMAKE_CXX_FLAGS "-mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mtune=cortex-a53 -mhard-float -DNO_SSE ${CMAKE_CXX_FLAGS}" )
else ()
set( CMAKE_CXX_FLAGS "-mfpu=neon -DNO_SSE ${CMAKE_CXX_FLAGS}" )
set( CMAKE_CXX_FLAGS "-mcpu=cortex-a7 -mfpu=neon-vfpv4 -mtune=cortex-a7 -mhard-float -DNO_SSE ${CMAKE_CXX_FLAGS}" )
endif ()
endif ()
@ -958,7 +958,6 @@ set (PCH_SOURCES
stats.cpp
stringtable.cpp
teaminfo.cpp
tempfiles.cpp
v_blend.cpp
v_collection.cpp
v_draw.cpp
@ -1179,6 +1178,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
${PCH_SOURCES}
x86.cpp
strnatcmp.c
tmpfileplus.c
zstring.cpp
math/asin.c
math/atan.c
@ -1301,7 +1301,7 @@ endif()
if( APPLE )
set_target_properties(zdoom PROPERTIES
LINK_FLAGS "-framework Carbon -framework Cocoa -framework IOKit -framework OpenGL"
LINK_FLAGS "-framework Cocoa -framework IOKit -framework OpenGL"
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/zdoom-info.plist" )
endif()

View file

@ -957,8 +957,13 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha
{
counter++;
if (!countOnly)
Printf("%s at (%f,%f,%f)\n",
{
Printf("%s at (%f,%f,%f)",
mo->GetClass()->TypeName.GetChars(), mo->X(), mo->Y(), mo->Z());
if (mo->tid)
Printf(" (TID:%d)", mo->tid);
Printf("\n");
}
}
}
}

View file

@ -465,7 +465,7 @@ void CheckCompatibility(MapData *map)
// When playing Doom IWAD levels force COMPAT_SHORTTEX and COMPATF_LIGHT.
// I'm not sure if the IWAD maps actually need COMPATF_LIGHT but it certainly does not hurt.
// TNT's MAP31 also needs COMPATF_STAIRINDEX but that only gets activated for TNT.WAD.
if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATSHORTTEX) && level.maptype == MAPTYPE_DOOM)
if (Wads.GetLumpFile(map->lumpnum) == Wads.GetIwadNum() && (gameinfo.flags & GI_COMPATSHORTTEX) && level.maptype == MAPTYPE_DOOM)
{
ii_compatflags = COMPATF_SHORTTEX|COMPATF_LIGHT;
if (gameinfo.flags & GI_COMPATSTAIRS) ii_compatflags |= COMPATF_STAIRINDEX;

View file

@ -182,6 +182,21 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize,
sc.MustGetString();
iwad->Required = sc.String;
}
else if (sc.Compare("StartupType"))
{
sc.MustGetStringName("=");
sc.MustGetString();
FString sttype = sc.String;
if (!sttype.CompareNoCase("DOOM"))
iwad->StartupType = FStartupInfo::DoomStartup;
else if (!sttype.CompareNoCase("HERETIC"))
iwad->StartupType = FStartupInfo::HereticStartup;
else if (!sttype.CompareNoCase("HEXEN"))
iwad->StartupType = FStartupInfo::HexenStartup;
else if (!sttype.CompareNoCase("STRIFE"))
iwad->StartupType = FStartupInfo::StrifeStartup;
else iwad->StartupType = FStartupInfo::DefaultStartup;
}
else
{
sc.ScriptError("Unknown keyword '%s'", sc.String);
@ -390,7 +405,7 @@ void FIWadManager::CollectSearchPaths()
for (auto &str : mSearchPaths)
{
FixPathSeperator(str);
if (str[str.Len() - 1] == '/') str.Truncate(str.Len() - 1);
if (str.Back() == '/') str.Truncate(str.Len() - 1);
}
}
@ -739,6 +754,7 @@ const FIWADInfo *FIWadManager::FindIWAD(TArray<FString> &wadfiles, const char *i
DoomStartupInfo.BkColor = iwad_info->BkColor;
DoomStartupInfo.FgColor = iwad_info->FgColor;
}
if (DoomStartupInfo.Type == 0) DoomStartupInfo.Type = iwad_info->StartupType;
I_SetIWADInfo();
return iwad_info;
}

View file

@ -328,12 +328,12 @@ void D_PostEvent (const event_t *ev)
int look = int(ev->y * m_pitch * mouse_sensitivity * 16.0);
if (invertmouse)
look = -look;
G_AddViewPitch (look);
G_AddViewPitch (look, true);
events[eventhead].y = 0;
}
if (!Button_Strafe.bDown && !lookstrafe)
{
G_AddViewAngle (int(ev->x * m_yaw * mouse_sensitivity * 8.0));
G_AddViewAngle (int(ev->x * m_yaw * mouse_sensitivity * 8.0), true);
events[eventhead].x = 0;
}
if ((events[eventhead].x | events[eventhead].y) == 0)
@ -1720,7 +1720,7 @@ const char *BaseFileSearch (const char *file, const char *ext, bool lookfirstinp
}
if (lookfirstinprogdir)
{
mysnprintf (wad, countof(wad), "%s%s%s", progdir.GetChars(), progdir[progdir.Len() - 1] != '/' ? "/" : "", file);
mysnprintf (wad, countof(wad), "%s%s%s", progdir.GetChars(), progdir.Back() == '/' ? "" : "/", file);
if (DirEntryExists (wad))
{
return wad;
@ -1747,7 +1747,7 @@ const char *BaseFileSearch (const char *file, const char *ext, bool lookfirstinp
dir = NicePath(value);
if (dir.IsNotEmpty())
{
mysnprintf (wad, countof(wad), "%s%s%s", dir.GetChars(), dir[dir.Len() - 1] != '/' ? "/" : "", file);
mysnprintf (wad, countof(wad), "%s%s%s", dir.GetChars(), dir.Back() == '/' ? "" : "/", file);
if (DirEntryExists (wad))
{
return wad;

View file

@ -74,6 +74,23 @@ struct WadStuff
FString Name;
};
struct FStartupInfo
{
FString Name;
uint32_t FgColor; // Foreground color for title banner
uint32_t BkColor; // Background color for title banner
FString Song;
int Type;
enum
{
DefaultStartup,
DoomStartup,
HereticStartup,
HexenStartup,
StrifeStartup,
};
};
struct FIWADInfo
{
FString Name; // Title banner text for this IWAD
@ -85,6 +102,7 @@ struct FIWADInfo
uint32_t FgColor = 0; // Foreground color for title banner
uint32_t BkColor = 0xc0c0c0; // Background color for title banner
EGameType gametype = GAME_Doom; // which game are we playing?
int StartupType = FStartupInfo::DefaultStartup; // alternate startup type
FString MapInfo; // Base mapinfo to load
TArray<FString> Load; // Wads to be loaded with this one.
TArray<FString> Lumps; // Lump names for identification
@ -104,24 +122,6 @@ struct FFoundWadInfo
}
};
struct FStartupInfo
{
FString Name;
uint32_t FgColor; // Foreground color for title banner
uint32_t BkColor; // Background color for title banner
FString Song;
int Type;
enum
{
DefaultStartup,
DoomStartup,
HereticStartup,
HexenStartup,
StrifeStartup,
};
};
extern FStartupInfo DoomStartupInfo;
//==========================================================================

View file

@ -73,6 +73,7 @@ CVAR (Float, movebob, 0.25f, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (Float, stillbob, 0.f, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (Float, wbobspeed, 1.f, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (String, playerclass, "Fighter", CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (Bool, classicflight, false, CVAR_USERINFO | CVAR_ARCHIVE);
enum
{
@ -88,6 +89,7 @@ enum
INFO_WBobSpeed,
INFO_PlayerClass,
INFO_ColorSet,
INFO_ClassicFlight,
};
const char *GenderNames[3] = { "male", "female", "other" };

View file

@ -330,6 +330,10 @@ struct userinfo_t : TMap<FName,FBaseCVar *>
{
return *static_cast<FIntCVar *>(*CheckKey(NAME_PlayerClass));
}
bool GetClassicFlight() const
{
return *static_cast<FBoolCVar *>(*CheckKey(NAME_ClassicFlight));
}
PClassActor *GetPlayerClassType() const
{
return PlayerClasses[GetPlayerClassNum()].Type;

View file

@ -608,24 +608,20 @@ void G_BuildTiccmd (ticcmd_t *cmd)
if (Button_Right.bDown)
{
G_AddViewAngle (angleturn[tspeed]);
LocalKeyboardTurner = true;
}
if (Button_Left.bDown)
{
G_AddViewAngle (-angleturn[tspeed]);
LocalKeyboardTurner = true;
}
}
if (Button_LookUp.bDown)
{
G_AddViewPitch (lookspeed[speed]);
LocalKeyboardTurner = true;
}
if (Button_LookDown.bDown)
{
G_AddViewPitch (-lookspeed[speed]);
LocalKeyboardTurner = true;
}
if (Button_MoveUp.bDown)
@ -701,12 +697,10 @@ void G_BuildTiccmd (ticcmd_t *cmd)
if (joyaxes[JOYAXIS_Pitch] != 0)
{
G_AddViewPitch(joyint(joyaxes[JOYAXIS_Pitch] * 2048));
LocalKeyboardTurner = true;
}
if (joyaxes[JOYAXIS_Yaw] != 0)
{
G_AddViewAngle(joyint(-1280 * joyaxes[JOYAXIS_Yaw]));
LocalKeyboardTurner = true;
}
side -= joyint(sidemove[speed] * joyaxes[JOYAXIS_Side]);
@ -794,7 +788,7 @@ void G_BuildTiccmd (ticcmd_t *cmd)
//[Graf Zahl] This really helps if the mouse update rate can't be increased!
CVAR (Bool, smooth_mouse, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
void G_AddViewPitch (int look)
void G_AddViewPitch (int look, bool mouse)
{
if (gamestate == GS_TITLELEVEL)
{
@ -837,11 +831,11 @@ void G_AddViewPitch (int look)
}
if (look != 0)
{
LocalKeyboardTurner = smooth_mouse;
LocalKeyboardTurner = (!mouse || smooth_mouse);
}
}
void G_AddViewAngle (int yaw)
void G_AddViewAngle (int yaw, bool mouse)
{
if (gamestate == GS_TITLELEVEL)
{
@ -857,7 +851,7 @@ void G_AddViewAngle (int yaw)
LocalViewAngle -= yaw;
if (yaw != 0)
{
LocalKeyboardTurner = smooth_mouse;
LocalKeyboardTurner = (!mouse || smooth_mouse);
}
}
@ -2199,7 +2193,7 @@ static void PutSaveWads (FSerializer &arc)
arc.AddString("Game WAD", name);
// Name of wad the map resides in
if (Wads.GetLumpFile (level.lumpnum) > 1)
if (Wads.GetLumpFile (level.lumpnum) > Wads.GetIwadNum())
{
name = Wads.GetWadName (Wads.GetLumpFile (level.lumpnum));
arc.AddString("Map WAD", name);

View file

@ -89,10 +89,10 @@ void G_DoReborn (int playernum, bool freshbot);
void G_DoPlayerPop(int playernum);
// Adds pitch to consoleplayer's viewpitch and clamps it
void G_AddViewPitch (int look);
void G_AddViewPitch (int look, bool mouse = false);
// Adds to consoleplayer's viewangle if allowed
void G_AddViewAngle (int yaw);
void G_AddViewAngle (int yaw, bool mouse = false);
#define BODYQUESIZE 32
class AActor;

View file

@ -149,7 +149,10 @@ FGameConfigFile::FGameConfigFile ()
SetValueForKey ("Path", "$PROGDIR", true);
#else
SetValueForKey ("Path", "~/" GAME_DIR, true);
SetValueForKey ("Path", SHARE_DIR, true);
SetValueForKey ("Path", "/usr/local/share/doom", true);
SetValueForKey ("Path", "/usr/local/share/games/doom", true);
SetValueForKey ("Path", "/usr/share/doom", true);
SetValueForKey ("Path", "/usr/share/games/doom", true);
#endif
SetValueForKey ("Path", "$DOOMWADDIR", true);
}

View file

@ -63,6 +63,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, intermissioncounter)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, statusscreen_single)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, statusscreen_coop)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, statusscreen_dm)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mSliderColor)
const char *GameNames[17] =
@ -382,9 +383,9 @@ void FMapInfoParser::ParseGameInfo()
GAMEINFOKEY_COLOR(dimcolor, "dimcolor")
GAMEINFOKEY_FLOAT(dimamount, "dimamount")
GAMEINFOKEY_FLOAT(bluramount, "bluramount")
GAMEINFOKEY_STRING(mSliderColor, "menuslidercolor")
GAMEINFOKEY_INT(definventorymaxamount, "definventorymaxamount")
GAMEINFOKEY_INT(defaultrespawntime, "defaultrespawntime")
GAMEINFOKEY_INT(defaultrespawntime, "defaultrespawntime")
GAMEINFOKEY_INT(defaultdropstyle, "defaultdropstyle")
GAMEINFOKEY_STRING(Endoom, "endoom")
GAMEINFOKEY_STRINGARRAY(quitmessages, "addquitmessages", 0, false)

View file

@ -173,6 +173,7 @@ struct gameinfo_t
FName mFontColorHeader;
FName mFontColorHighlight;
FName mFontColorSelection;
FName mSliderColor;
FString mBackButton;
double gibfactor;
int TextScreenX;

View file

@ -87,7 +87,7 @@ void AdjustSpriteOffsets()
for (int i = 0; i < numtex; i++)
{
if (Wads.GetLumpFile(i) > 1) break; // we are past the IWAD
if (Wads.GetLumpFile(i) > Wads.GetIwadNum()) break; // we are past the IWAD
if (Wads.GetLumpNamespace(i) == ns_sprites && Wads.GetLumpFile(i) == Wads.GetIwadNum())
{
char str[9];

View file

@ -484,3 +484,213 @@ VSMatrix::multMatrix(FLOATTYPE *resMat, const FLOATTYPE *aMatrix)
}
memcpy(resMat, res, 16 * sizeof(FLOATTYPE));
}
static double mat3Determinant(const FLOATTYPE *mMat3x3)
{
return mMat3x3[0] * (mMat3x3[4] * mMat3x3[8] - mMat3x3[5] * mMat3x3[7]) +
mMat3x3[1] * (mMat3x3[5] * mMat3x3[6] - mMat3x3[8] * mMat3x3[3]) +
mMat3x3[2] * (mMat3x3[3] * mMat3x3[7] - mMat3x3[4] * mMat3x3[6]);
}
static double mat4Determinant(const FLOATTYPE *matrix)
{
FLOATTYPE mMat3x3_a[9] =
{
matrix[1 * 4 + 1], matrix[2 * 4 + 1], matrix[3 * 4 + 1],
matrix[1 * 4 + 2], matrix[2 * 4 + 2], matrix[3 * 4 + 2],
matrix[1 * 4 + 3], matrix[2 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_b[9] =
{
matrix[1 * 4 + 0], matrix[2 * 4 + 0], matrix[3 * 4 + 0],
matrix[1 * 4 + 2], matrix[2 * 4 + 2], matrix[3 * 4 + 2],
matrix[1 * 4 + 3], matrix[2 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_c[9] =
{
matrix[1 * 4 + 0], matrix[2 * 4 + 0], matrix[3 * 4 + 0],
matrix[1 * 4 + 1], matrix[2 * 4 + 1], matrix[3 * 4 + 1],
matrix[1 * 4 + 3], matrix[2 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_d[9] =
{
matrix[1 * 4 + 0], matrix[2 * 4 + 0], matrix[3 * 4 + 0],
matrix[1 * 4 + 1], matrix[2 * 4 + 1], matrix[3 * 4 + 1],
matrix[1 * 4 + 2], matrix[2 * 4 + 2], matrix[3 * 4 + 2]
};
FLOATTYPE a, b, c, d;
FLOATTYPE value;
a = mat3Determinant(mMat3x3_a);
b = mat3Determinant(mMat3x3_b);
c = mat3Determinant(mMat3x3_c);
d = mat3Determinant(mMat3x3_d);
value = matrix[0 * 4 + 0] * a;
value -= matrix[0 * 4 + 1] * b;
value += matrix[0 * 4 + 2] * c;
value -= matrix[0 * 4 + 3] * d;
return value;
}
static void mat4Adjoint(const FLOATTYPE *matrix, FLOATTYPE *result)
{
FLOATTYPE mMat3x3_a[9] =
{
matrix[1 * 4 + 1], matrix[2 * 4 + 1], matrix[3 * 4 + 1],
matrix[1 * 4 + 2], matrix[2 * 4 + 2], matrix[3 * 4 + 2],
matrix[1 * 4 + 3], matrix[2 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_b[9] =
{
matrix[1 * 4 + 0], matrix[2 * 4 + 0], matrix[3 * 4 + 0],
matrix[1 * 4 + 2], matrix[2 * 4 + 2], matrix[3 * 4 + 2],
matrix[1 * 4 + 3], matrix[2 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_c[9] =
{
matrix[1 * 4 + 0], matrix[2 * 4 + 0], matrix[3 * 4 + 0],
matrix[1 * 4 + 1], matrix[2 * 4 + 1], matrix[3 * 4 + 1],
matrix[1 * 4 + 3], matrix[2 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_d[9] =
{
matrix[1 * 4 + 0], matrix[2 * 4 + 0], matrix[3 * 4 + 0],
matrix[1 * 4 + 1], matrix[2 * 4 + 1], matrix[3 * 4 + 1],
matrix[1 * 4 + 2], matrix[2 * 4 + 2], matrix[3 * 4 + 2]
};
FLOATTYPE mMat3x3_e[9] =
{
matrix[0 * 4 + 1], matrix[2 * 4 + 1], matrix[3 * 4 + 1],
matrix[0 * 4 + 2], matrix[2 * 4 + 2], matrix[3 * 4 + 2],
matrix[0 * 4 + 3], matrix[2 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_f[9] =
{
matrix[0 * 4 + 0], matrix[2 * 4 + 0], matrix[3 * 4 + 0],
matrix[0 * 4 + 2], matrix[2 * 4 + 2], matrix[3 * 4 + 2],
matrix[0 * 4 + 3], matrix[2 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_g[9] =
{
matrix[0 * 4 + 0], matrix[2 * 4 + 0], matrix[3 * 4 + 0],
matrix[0 * 4 + 1], matrix[2 * 4 + 1], matrix[3 * 4 + 1],
matrix[0 * 4 + 3], matrix[2 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_h[9] =
{
matrix[0 * 4 + 0], matrix[2 * 4 + 0], matrix[3 * 4 + 0],
matrix[0 * 4 + 1], matrix[2 * 4 + 1], matrix[3 * 4 + 1],
matrix[0 * 4 + 2], matrix[2 * 4 + 2], matrix[3 * 4 + 2]
};
FLOATTYPE mMat3x3_i[9] =
{
matrix[0 * 4 + 1], matrix[1 * 4 + 1], matrix[3 * 4 + 1],
matrix[0 * 4 + 2], matrix[1 * 4 + 2], matrix[3 * 4 + 2],
matrix[0 * 4 + 3], matrix[1 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_j[9] =
{
matrix[0 * 4 + 0], matrix[1 * 4 + 0], matrix[3 * 4 + 0],
matrix[0 * 4 + 2], matrix[1 * 4 + 2], matrix[3 * 4 + 2],
matrix[0 * 4 + 3], matrix[1 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_k[9] =
{
matrix[0 * 4 + 0], matrix[1 * 4 + 0], matrix[3 * 4 + 0],
matrix[0 * 4 + 1], matrix[1 * 4 + 1], matrix[3 * 4 + 1],
matrix[0 * 4 + 3], matrix[1 * 4 + 3], matrix[3 * 4 + 3]
};
FLOATTYPE mMat3x3_l[9] =
{
matrix[0 * 4 + 0], matrix[1 * 4 + 0], matrix[3 * 4 + 0],
matrix[0 * 4 + 1], matrix[1 * 4 + 1], matrix[3 * 4 + 1],
matrix[0 * 4 + 2], matrix[1 * 4 + 2], matrix[3 * 4 + 2]
};
FLOATTYPE mMat3x3_m[9] =
{
matrix[0 * 4 + 1], matrix[1 * 4 + 1], matrix[2 * 4 + 1],
matrix[0 * 4 + 2], matrix[1 * 4 + 2], matrix[2 * 4 + 2],
matrix[0 * 4 + 3], matrix[1 * 4 + 3], matrix[2 * 4 + 3]
};
FLOATTYPE mMat3x3_n[9] =
{
matrix[0 * 4 + 0], matrix[1 * 4 + 0], matrix[2 * 4 + 0],
matrix[0 * 4 + 2], matrix[1 * 4 + 2], matrix[2 * 4 + 2],
matrix[0 * 4 + 3], matrix[1 * 4 + 3], matrix[2 * 4 + 3]
};
FLOATTYPE mMat3x3_o[9] =
{
matrix[0 * 4 + 0], matrix[1 * 4 + 0], matrix[2 * 4 + 0],
matrix[0 * 4 + 1], matrix[1 * 4 + 1], matrix[2 * 4 + 1],
matrix[0 * 4 + 3], matrix[1 * 4 + 3], matrix[2 * 4 + 3]
};
FLOATTYPE mMat3x3_p[9] =
{
matrix[0 * 4 + 0], matrix[1 * 4 + 0], matrix[2 * 4 + 0],
matrix[0 * 4 + 1], matrix[1 * 4 + 1], matrix[2 * 4 + 1],
matrix[0 * 4 + 2], matrix[1 * 4 + 2], matrix[2 * 4 + 2]
};
result[0 * 4 + 0] = mat3Determinant(mMat3x3_a);
result[1 * 4 + 0] = -mat3Determinant(mMat3x3_b);
result[2 * 4 + 0] = mat3Determinant(mMat3x3_c);
result[3 * 4 + 0] = -mat3Determinant(mMat3x3_d);
result[0 * 4 + 1] = -mat3Determinant(mMat3x3_e);
result[1 * 4 + 1] = mat3Determinant(mMat3x3_f);
result[2 * 4 + 1] = -mat3Determinant(mMat3x3_g);
result[3 * 4 + 1] = mat3Determinant(mMat3x3_h);
result[0 * 4 + 2] = mat3Determinant(mMat3x3_i);
result[1 * 4 + 2] = -mat3Determinant(mMat3x3_j);
result[2 * 4 + 2] = mat3Determinant(mMat3x3_k);
result[3 * 4 + 2] = -mat3Determinant(mMat3x3_l);
result[0 * 4 + 3] = -mat3Determinant(mMat3x3_m);
result[1 * 4 + 3] = mat3Determinant(mMat3x3_n);
result[2 * 4 + 3] = -mat3Determinant(mMat3x3_o);
result[3 * 4 + 3] = mat3Determinant(mMat3x3_p);
}
bool VSMatrix::inverseMatrix(VSMatrix &result)
{
// Calculate mat4 determinant
FLOATTYPE det = mat4Determinant(mMatrix);
// Inverse unknown when determinant is close to zero
if (fabs(det) < 1e-15)
{
for (int i = 0; i < 16; i++)
result.mMatrix[i] = FLOATTYPE(0.0);
return false;
}
else
{
mat4Adjoint(mMatrix, result.mMatrix);
FLOATTYPE invDet = FLOATTYPE(1.0) / det;
for (int i = 0; i < 16; i++)
{
result.mMatrix[i] = result.mMatrix[i] * invDet;
}
}
return true;
}

View file

@ -59,7 +59,7 @@ struct FDynLightData
bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FDynLightData &data);
void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata, bool hudmodel);
void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata);
void gl_UploadLights(FDynLightData &data);

View file

@ -77,7 +77,7 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FD
return false;
}
gl_AddLightToList(group, light, ldata, false);
gl_AddLightToList(group, light, ldata);
return true;
}
@ -86,38 +86,13 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FD
// Add one dynamic light to the light data list
//
//==========================================================================
void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata, bool hudmodel)
void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata)
{
int i = 0;
DVector3 pos = light->PosRelative(group);
float radius = light->GetRadius();
if (hudmodel)
{
// HUD model is already translated and rotated. We must rotate the lights into that view space.
DVector3 rotation;
DVector3 localpos = pos - r_viewpoint.Pos;
rotation.X = localpos.X * r_viewpoint.Angles.Yaw.Sin() - localpos.Y * r_viewpoint.Angles.Yaw.Cos();
rotation.Y = localpos.X * r_viewpoint.Angles.Yaw.Cos() + localpos.Y * r_viewpoint.Angles.Yaw.Sin();
rotation.Z = localpos.Z;
localpos = rotation;
rotation.X = localpos.X;
rotation.Y = localpos.Y * r_viewpoint.Angles.Pitch.Sin() - localpos.Z * r_viewpoint.Angles.Pitch.Cos();
rotation.Z = localpos.Y * r_viewpoint.Angles.Pitch.Cos() + localpos.Z * r_viewpoint.Angles.Pitch.Sin();
localpos = rotation;
rotation.Y = localpos.Y;
rotation.Z = localpos.Z * r_viewpoint.Angles.Roll.Sin() - localpos.X * r_viewpoint.Angles.Roll.Cos();
rotation.X = localpos.Z * r_viewpoint.Angles.Roll.Cos() + localpos.X * r_viewpoint.Angles.Roll.Sin();
localpos = rotation;
pos = localpos;
}
float cs;
if (light->IsAdditive())
{

View file

@ -1095,33 +1095,33 @@ void gl_RenderHUDModel(DPSprite *psp, float ofsX, float ofsY)
glFrontFace(GL_CCW);
}
// [BB] The model has to be drawn independently from the position of the player,
// so we have to reset the view matrix.
gl_RenderState.mViewMatrix.loadIdentity();
// Need to reset the normal matrix too
gl_RenderState.mNormalViewMatrix.loadIdentity();
// The model position and orientation has to be drawn independently from the position of the player,
// but we need to position it correctly in the world for light to work properly.
VSMatrix objectToWorldMatrix;
gl_RenderState.mViewMatrix.inverseMatrix(objectToWorldMatrix);
// Scaling model (y scale for a sprite means height, i.e. z in the world!).
gl_RenderState.mViewMatrix.scale(smf->xscale, smf->zscale, smf->yscale);
objectToWorldMatrix.scale(smf->xscale, smf->zscale, smf->yscale);
// Aplying model offsets (model offsets do not depend on model scalings).
gl_RenderState.mViewMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale);
objectToWorldMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale);
// [BB] Weapon bob, very similar to the normal Doom weapon bob.
gl_RenderState.mViewMatrix.rotate(ofsX/4, 0, 1, 0);
gl_RenderState.mViewMatrix.rotate((ofsY-WEAPONTOP)/-4., 1, 0, 0);
objectToWorldMatrix.rotate(ofsX/4, 0, 1, 0);
objectToWorldMatrix.rotate((ofsY-WEAPONTOP)/-4., 1, 0, 0);
// [BB] For some reason the jDoom models need to be rotated.
gl_RenderState.mViewMatrix.rotate(90.f, 0, 1, 0);
objectToWorldMatrix.rotate(90.f, 0, 1, 0);
// Applying angleoffset, pitchoffset, rolloffset.
gl_RenderState.mViewMatrix.rotate(-smf->angleoffset, 0, 1, 0);
gl_RenderState.mViewMatrix.rotate(smf->pitchoffset, 0, 0, 1);
gl_RenderState.mViewMatrix.rotate(-smf->rolloffset, 1, 0, 0);
gl_RenderState.ApplyMatrices();
objectToWorldMatrix.rotate(-smf->angleoffset, 0, 1, 0);
objectToWorldMatrix.rotate(smf->pitchoffset, 0, 0, 1);
objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0);
gl_RenderState.mModelMatrix = objectToWorldMatrix;
gl_RenderState.EnableModelMatrix(true);
gl_RenderFrameModels( smf, psp->GetState(), psp->GetTics(), playermo->player->ReadyWeapon->GetClass(), nullptr, 0 );
gl_RenderState.EnableModelMatrix(false);
glDepthFunc(GL_LESS);
if (!( playermo->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))

View file

@ -335,7 +335,7 @@ void GLSprite::Draw(int pass)
if (gl_lights && GLRenderer->mLightCount && mDrawer->FixedColormap == CM_DEFAULT && !fullbright)
{
if (modelframe && !particle)
gl_SetDynModelLight(gl_light_sprites ? actor : NULL, false);
gl_SetDynModelLight(gl_light_sprites ? actor : NULL);
else
gl_SetDynSpriteLight(gl_light_sprites ? actor : NULL, gl_light_particles ? particle : NULL);
}

View file

@ -178,7 +178,7 @@ void BSPWalkCircle(float x, float y, float radiusSquared, const Callback &callba
BSPNodeWalkCircle(level.HeadNode(), x, y, radiusSquared, callback);
}
void gl_SetDynModelLight(AActor *self, bool hudmodel)
void gl_SetDynModelLight(AActor *self)
{
// Legacy and deferred render paths gets the old flat model light
if (gl.lightmethod != LM_DIRECT)
@ -210,16 +210,16 @@ void gl_SetDynModelLight(AActor *self, bool hudmodel)
{
int group = subsector->sector->PortalGroup;
DVector3 pos = light->PosRelative(group);
float radius = light->GetRadius();
float radius = light->GetRadius() + self->renderradius;
double dx = pos.X - x;
double dy = pos.Y - y;
double dz = pos.Z - z;
double distSquared = dx * dx + dy * dy + dz * dz;
if (distSquared < radiusSquared + radius * radius) // Light and actor touches
if (distSquared < radius * radius) // Light and actor touches
{
if (std::find(addedLights.begin(), addedLights.end(), light) == addedLights.end()) // Check if we already added this light from a different subsector
{
gl_AddLightToList(group, light, modellightdata, hudmodel);
gl_AddLightToList(group, light, modellightdata);
addedLights.push_back(light);
}
}

View file

@ -422,6 +422,6 @@ inline float Dist2(float x1,float y1,float x2,float y2)
void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t *subsec);
void gl_SetDynSpriteLight(AActor *actor, particle_t *particle);
void gl_SetDynModelLight(AActor *self, bool hudmodel);
void gl_SetDynModelLight(AActor *self);
#endif

View file

@ -422,7 +422,7 @@ void GLSceneDrawer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
{
FSpriteModelFrame *smf = playermo->player->ReadyWeapon ? gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetState()->sprite, psp->GetState()->GetFrame(), false) : nullptr;
if (smf)
gl_SetDynModelLight(playermo, true);
gl_SetDynModelLight(playermo);
else
gl_SetDynSpriteLight(playermo, NULL);
}

View file

@ -239,7 +239,7 @@ void PostProcessShaderInstance::BindTextures()
GLuint handle = 0;
glGenTextures(1, &handle);
glBindTexture(GL_TEXTURE_2D, handle);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex->GetWidth(), tex->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap.GetPixels());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex->GetWidth(), tex->GetHeight(), 0, GL_BGRA, GL_UNSIGNED_BYTE, bitmap.GetPixels());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
mTextureHandles[tex] = handle;

View file

@ -182,8 +182,10 @@ void OpenGLFrameBuffer::Update()
Unlock();
CheckBench();
int clientWidth = ViewportScaledWidth(IsFullscreen() ? VideoWidth : GetClientWidth());
int clientHeight = ViewportScaledHeight(IsFullscreen() ? VideoHeight : GetClientHeight());
int initialWidth = IsFullscreen() ? VideoWidth : GetClientWidth();
int initialHeight = IsFullscreen() ? VideoHeight : GetClientHeight();
int clientWidth = ViewportScaledWidth(initialWidth, initialHeight);
int clientHeight = ViewportScaledHeight(initialWidth, initialHeight);
if (clientWidth > 0 && clientHeight > 0 && (Width != clientWidth || Height != clientHeight))
{
// Do not call Resize here because it's only for software canvases

View file

@ -1304,8 +1304,8 @@ void OpenGLSWFrameBuffer::Flip()
if (!IsFullscreen())
{
int clientWidth = ViewportScaledWidth(GetClientWidth());
int clientHeight = ViewportScaledHeight(GetClientHeight());
int clientWidth = ViewportScaledWidth(GetClientWidth(), GetClientHeight());
int clientHeight = ViewportScaledHeight(GetClientWidth(), GetClientHeight());
if (clientWidth > 0 && clientHeight > 0 && (Width != clientWidth || Height != clientHeight))
{
Resize(clientWidth, clientHeight);

View file

@ -93,8 +93,8 @@ void FHardwareTexture::Resize(int width, int height, unsigned char *src_data, un
// down we will need to gather a grid of pixels of the size of the scale
// factor in each direction and then do an averaging of the pixels.
TArray<BoxPrecalc> vPrecalcs(height);
TArray<BoxPrecalc> hPrecalcs(width);
TArray<BoxPrecalc> vPrecalcs(height, true);
TArray<BoxPrecalc> hPrecalcs(width, true);
ResampleBoxPrecalc(vPrecalcs, texheight);
ResampleBoxPrecalc(hPrecalcs, texwidth);

View file

@ -322,18 +322,16 @@ bool PClassActor::SetReplacement(FName replaceName)
void AActor::Finalize(FStateDefinitions &statedef)
{
AActor *defaults = this;
try
{
statedef.FinishStates(GetClass(), defaults);
statedef.FinishStates(GetClass());
}
catch (CRecoverableError &)
{
statedef.MakeStateDefines(nullptr);
throw;
}
statedef.InstallStates(GetClass(), defaults);
statedef.InstallStates(GetClass(), this);
statedef.MakeStateDefines(nullptr);
}
@ -355,8 +353,16 @@ void PClassActor::RegisterIDs()
return;
}
FActorInfo *actorInfo = ActorInfo();
if (nullptr == actorInfo)
{
// Undefined class, exiting
return;
}
// Conversation IDs have never been filtered by game so we cannot start doing that.
auto ConversationID = ActorInfo()->ConversationID;
auto ConversationID = actorInfo->ConversationID;
if (ConversationID > 0)
{
StrifeTypes[ConversationID] = cls;
@ -365,9 +371,9 @@ void PClassActor::RegisterIDs()
Printf(TEXTCOLOR_RED"Conversation ID %d refers to hidden class type '%s'\n", ConversationID, cls->TypeName.GetChars());
}
}
if (ActorInfo()->GameFilter == GAME_Any || (ActorInfo()->GameFilter & gameinfo.gametype))
if (actorInfo->GameFilter == GAME_Any || (ActorInfo()->GameFilter & gameinfo.gametype))
{
auto SpawnID = ActorInfo()->SpawnID;
auto SpawnID = actorInfo->SpawnID;
if (SpawnID > 0)
{
SpawnableThings[SpawnID] = cls;
@ -376,7 +382,7 @@ void PClassActor::RegisterIDs()
Printf(TEXTCOLOR_RED"Spawn ID %d refers to hidden class type '%s'\n", SpawnID, cls->TypeName.GetChars());
}
}
auto DoomEdNum = ActorInfo()->DoomEdNum;
auto DoomEdNum = actorInfo->DoomEdNum;
if (DoomEdNum != -1)
{
FDoomEdEntry *oldent = DoomEdMap.CheckKey(DoomEdNum);

View file

@ -299,7 +299,7 @@ bool FIntermissionActionTextscreen::ParseKey(FScanner &sc)
else
{
// only print an error if coming from a PWAD
if (Wads.GetLumpFile(sc.LumpNum) > 1)
if (Wads.GetLumpFile(sc.LumpNum) > Wads.GetIwadNum())
sc.ScriptMessage("Unknown text lump '%s'", sc.String);
mText.Format("Unknown text lump '%s'", sc.String);
}

View file

@ -54,14 +54,14 @@
#endif
#if defined(__APPLE__)
#define _msize(p) malloc_size(p)
#elif __solaris__ || defined(__OpenBSD__)
#elif defined(__solaris__) || defined(__OpenBSD__)
#define _msize(p) (*((size_t*)(p)-1))
#elif !defined(_WIN32)
#define _msize(p) malloc_usable_size(p) // from glibc/FreeBSD
#endif
#ifndef _DEBUG
#if !__solaris__ && !defined(__OpenBSD__)
#if !defined(__solaris__) && !defined(__OpenBSD__)
void *M_Malloc(size_t size)
{
void *block = malloc(size);
@ -131,7 +131,7 @@ void *M_Realloc(void *memblock, size_t size)
#include <crtdbg.h>
#endif
#if !__solaris__ && !defined(__OpenBSD__)
#if !defined(__solaris__) && !defined(__OpenBSD__)
void *M_Malloc_Dbg(size_t size, const char *file, int lineno)
{
void *block = _malloc_dbg(size, _NORMAL_BLOCK, file, lineno);
@ -199,7 +199,7 @@ void *M_Realloc_Dbg(void *memblock, size_t size, const char *file, int lineno)
#endif
#endif
#if !__solaris__ && !defined(__OpenBSD__)
#if !defined(__solaris__) && !defined(__OpenBSD__)
void M_Free (void *block)
{
if (block != NULL)

View file

@ -74,7 +74,6 @@ EXTERN_CVAR (Int, vid_defwidth)
EXTERN_CVAR (Int, vid_defheight)
EXTERN_CVAR (Int, vid_defbits)
EXTERN_CVAR (Bool, fullscreen)
EXTERN_CVAR (Bool, vid_tft) // Defined below
int testingmode; // Holds time to revert to old mode
int OldWidth, OldHeight, OldBits;
@ -87,43 +86,12 @@ CUSTOM_CVAR (Int, menu_screenratios, -1, CVAR_ARCHIVE)
{
self = -1;
}
else if (self == 4 && !vid_tft)
{
self = 0;
}
else
{
BuildModesList (screen->VideoWidth, screen->VideoHeight, DisplayBits);
}
}
CUSTOM_CVAR (Bool, vid_tft, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
const int OptionMenuItemOptionBase_OP_VALUES = 0x11001;
DOptionMenuDescriptor *opt = GetVideoModeMenu();
if (opt != NULL)
{
DMenuItemBase *it = opt->GetItem("menu_screenratios");
if (it != NULL)
{
if (self)
{
it->SetString(OptionMenuItemOptionBase_OP_VALUES, "RatiosTFT");
}
else
{
it->SetString(OptionMenuItemOptionBase_OP_VALUES, "Ratios");
}
}
}
setsizeneeded = true;
if (StatusBar != NULL)
{
StatusBar->CallScreenSizeChanged();
}
}
//=============================================================================
//
@ -278,7 +246,6 @@ void M_InitVideoModesMenu ()
size_t currval = 0;
M_RefreshModesList();
vid_tft.Callback();
for (unsigned int i = 1; i <= 32 && currval < countof(BitTranslate); i++)
{

View file

@ -768,6 +768,7 @@ xx(ColorSet)
xx(NeverSwitchOnPickup)
xx(MoveBob)
xx(StillBob)
xx(ClassicFlight)
xx(WBobSpeed)
xx(PlayerClass)
xx(MonsterClass)

View file

@ -324,15 +324,17 @@ enum // P_AimLineAttack flags
enum // P_LineAttack flags
{
LAF_ISMELEEATTACK = 1,
LAF_NORANDOMPUFFZ = 2,
LAF_NOIMPACTDECAL = 4,
LAF_NOINTERACT = 8,
LAF_TARGETISSOURCE = 16,
LAF_OVERRIDEZ = 32,
LAF_NORANDOMPUFFZ = 1 << 1,
LAF_NOIMPACTDECAL = 1 << 2,
LAF_NOINTERACT = 1 << 3,
LAF_TARGETISSOURCE= 1 << 4,
LAF_OVERRIDEZ = 1 << 5,
LAF_ABSOFFSET = 1 << 6,
LAF_ABSPOSITION = 1 << 7,
};
AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL, double sz = 0.0);
AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, FName pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL, double sz = 0.0);
AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL, double sz = 0.0, double offsetforward = 0.0, double offsetside = 0.0);
AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, FName pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL, double sz = 0.0, double offsetforward = 0.0, double offsetside = 0.0);
void P_TraceBleed(int damage, const DVector3 &pos, AActor *target, DAngle angle, DAngle pitch);
void P_TraceBleed(int damage, AActor *target, DAngle angle, DAngle pitch);

View file

@ -4395,7 +4395,8 @@ static ETraceStatus CheckForActor(FTraceResults &res, void *userdata)
//==========================================================================
AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, FTranslatedLineTarget*victim, int *actualdamage, double sz)
DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, FTranslatedLineTarget*victim, int *actualdamage,
double sz, double offsetforward, double offsetside)
{
bool nointeract = !!(flags & LAF_NOINTERACT);
DVector3 direction;
@ -4496,7 +4497,34 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
if (nointeract || (puffDefaults && puffDefaults->flags6 & MF6_NOTRIGGER)) tflags = TRACE_NoSky;
else tflags = TRACE_NoSky | TRACE_Impact;
if (!Trace(t1->PosAtZ(shootz), t1->Sector, direction, distance, MF_SHOOTABLE,
// [MC] Check the flags and set the position according to what is desired.
// LAF_ABSPOSITION: Treat the offset parameters as direct coordinates.
// LAF_ABSOFFSET: Ignore the angle.
DVector3 tempos;
if (flags & LAF_ABSPOSITION)
{
tempos = DVector3(offsetforward, offsetside, sz);
}
else if (flags & LAF_ABSOFFSET)
{
tempos = t1->Vec2OffsetZ(offsetforward, offsetside, shootz);
}
else if (0.0 == offsetforward && 0.0 == offsetside)
{
// Default case so exact comparison is enough
tempos = t1->PosAtZ(shootz);
}
else
{
const double s = angle.Sin();
const double c = angle.Cos();
tempos = t1->Vec2OffsetZ(offsetforward * c + offsetside * s, offsetforward * s - offsetside * c, shootz);
}
// Perform the trace.
if (!Trace(tempos, t1->Sector, direction, distance, MF_SHOOTABLE,
ML_BLOCKEVERYTHING | ML_BLOCKHITSCAN, t1, trace, tflags, CheckForActor, &TData))
{ // hit nothing
if (!nointeract && puffDefaults && puffDefaults->ActiveSound)
@ -4702,7 +4730,8 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
}
AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
DAngle pitch, int damage, FName damageType, FName pufftype, int flags, FTranslatedLineTarget *victim, int *actualdamage, double sz)
DAngle pitch, int damage, FName damageType, FName pufftype, int flags, FTranslatedLineTarget *victim, int *actualdamage,
double sz, double offsetforward, double offsetside)
{
PClassActor *type = PClass::FindActor(pufftype);
if (type == NULL)
@ -4716,7 +4745,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
}
else
{
return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type, flags, victim, actualdamage, sz);
return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type, flags, victim, actualdamage, sz, offsetforward, offsetside);
}
}
@ -4732,10 +4761,12 @@ DEFINE_ACTION_FUNCTION(AActor, LineAttack)
PARAM_INT_DEF(flags);
PARAM_POINTER_DEF(victim, FTranslatedLineTarget);
PARAM_FLOAT_DEF(offsetz);
PARAM_FLOAT_DEF(offsetforward);
PARAM_FLOAT_DEF(offsetside);
int acdmg;
if (puffType == nullptr) puffType = PClass::FindActor("BulletPuff"); // P_LineAttack does not work without a puff to take info from.
auto puff = P_LineAttack(self, angle, distance, pitch, damage, damageType, puffType, flags, victim, &acdmg, offsetz);
auto puff = P_LineAttack(self, angle, distance, pitch, damage, damageType, puffType, flags, victim, &acdmg, offsetz, offsetforward, offsetside);
if (numret > 0) ret[0].SetObject(puff);
if (numret > 1) ret[1].SetInt(acdmg), numret = 2;
return numret;

View file

@ -721,7 +721,7 @@ void FStateDefinitions::RetargetStates (intptr_t count, const char *target)
//
//==========================================================================
FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, PClassActor *mytype, char *name)
FState *FStateDefinitions::ResolveGotoLabel (PClassActor *mytype, char *name)
{
PClassActor *type = mytype;
FState *state;
@ -741,7 +741,6 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, PClassActor *mytype,
if (stricmp (classname, "Super") == 0)
{
type = ValidateActor(type->ParentClass);
actor = GetDefaultByType(type);
}
else
{
@ -763,7 +762,6 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, PClassActor *mytype,
if (type != stype)
{
type = static_cast<PClassActor *>(stype);
actor = GetDefaultByType (type);
}
}
}
@ -836,16 +834,16 @@ void FStateDefinitions::FixStatePointers (PClassActor *actor, TArray<FStateDefin
//
//==========================================================================
void FStateDefinitions::ResolveGotoLabels (PClassActor *actor, AActor *defaults, TArray<FStateDefine> & list)
void FStateDefinitions::ResolveGotoLabels (PClassActor *actor, TArray<FStateDefine> & list)
{
for (unsigned i = 0; i < list.Size(); i++)
{
if (list[i].State != NULL && list[i].DefineFlags == SDF_LABEL)
{ // It's not a valid state, so it must be a label string. Resolve it.
list[i].State = ResolveGotoLabel (defaults, actor, (char *)list[i].State);
list[i].State = ResolveGotoLabel (actor, (char *)list[i].State);
list[i].DefineFlags = SDF_STATE;
}
if (list[i].Children.Size() > 0) ResolveGotoLabels(actor, defaults, list[i].Children);
if (list[i].Children.Size() > 0) ResolveGotoLabels(actor, list[i].Children);
}
}
@ -1004,7 +1002,7 @@ int FStateDefinitions::AddStates(FState *state, const char *framechars, const FS
//
//==========================================================================
int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults)
int FStateDefinitions::FinishStates(PClassActor *actor)
{
int count = StateArray.Size();
@ -1023,7 +1021,7 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults)
FixStatePointers(actor, StateLabels);
// Fix state pointers that are gotos
ResolveGotoLabels(actor, defaults, StateLabels);
ResolveGotoLabels(actor, StateLabels);
for (i = 0; i < count; i++)
{
@ -1047,7 +1045,7 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults)
break;
case SDF_LABEL:
realstates[i].NextState = ResolveGotoLabel(defaults, actor, (char *)realstates[i].NextState);
realstates[i].NextState = ResolveGotoLabel(actor, (char *)realstates[i].NextState);
break;
}
}
@ -1055,7 +1053,7 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults)
else
{
// Fix state pointers that are gotos
ResolveGotoLabels(actor, defaults, StateLabels);
ResolveGotoLabels(actor, StateLabels);
}
return count;
}

View file

@ -813,6 +813,12 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetNeverSwitch)
ACTION_RETURN_BOOL(self->userinfo.GetNeverSwitch());
}
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetClassicFlight)
{
PARAM_SELF_STRUCT_PROLOGUE(player_t);
ACTION_RETURN_BOOL(self->userinfo.GetClassicFlight());
}
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetColor)
{
PARAM_SELF_STRUCT_PROLOGUE(player_t);

View file

@ -48,7 +48,7 @@ static FString BuildPath(const FString &base, const char *name)
if (base.IsNotEmpty())
{
current = base;
if (current[current.Len() - 1] != '/') current += '/';
if (current.Back() != '/') current += '/';
}
current += name;
return current;

View file

@ -46,6 +46,22 @@ public:
float A, B, C, D;
};
struct TriVertex
{
TriVertex() { }
TriVertex(float x, float y, float z, float w, float u, float v) : x(x), y(y), z(z), w(w), u(u), v(v) { }
float x, y, z, w;
float u, v;
};
struct PolyLight
{
uint32_t color;
float x, y, z;
float radius;
};
class PolyDrawArgs
{
public:
@ -64,6 +80,8 @@ public:
void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *texture, bool fullbright);
void SetTransform(const TriMatrix *objectToClip) { mObjectToClip = objectToClip; }
void SetColor(uint32_t bgra, uint8_t palindex);
void SetLights(PolyLight *lights, int numLights) { mLights = lights; mNumLights = numLights; }
void SetDynLightColor(uint32_t color) { mDynLightColor = color; }
void DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
const TriMatrix *ObjectToClip() const { return mObjectToClip; }
@ -110,6 +128,13 @@ public:
bool NearestFilter() const { return mNearestFilter; }
bool FixedLight() const { return mFixedLight; }
PolyLight *Lights() const { return mLights; }
int NumLights() const { return mNumLights; }
uint32_t DynLightColor() const { return mDynLightColor; }
const FVector3 &Normal() const { return mNormal; }
void SetNormal(const FVector3 &normal) { mNormal = normal; }
private:
const TriMatrix *mObjectToClip = nullptr;
const TriVertex *mVertices = nullptr;
@ -146,6 +171,10 @@ private:
bool mSimpleShade = true;
bool mNearestFilter = true;
bool mFixedLight = false;
PolyLight *mLights = nullptr;
int mNumLights = 0;
FVector3 mNormal;
uint32_t mDynLightColor = 0;
};
class RectDrawArgs

View file

@ -154,9 +154,62 @@ namespace TriScreenDrawerModes
}
}
template<typename ShadeModeT>
FORCEINLINE BgraColor Shade32(BgraColor fgcolor, BgraColor mlight, uint32_t desaturate, uint32_t inv_desaturate, BgraColor shade_fade, BgraColor shade_light)
FORCEINLINE BgraColor VECTORCALL AddLights(BgraColor material, BgraColor fgcolor, BgraColor dynlight)
{
fgcolor.r = MIN(fgcolor.r + ((material.r * dynlight.r) >> 8), (uint32_t)255);
fgcolor.g = MIN(fgcolor.g + ((material.g * dynlight.g) >> 8), (uint32_t)255);
fgcolor.b = MIN(fgcolor.b + ((material.b * dynlight.b) >> 8), (uint32_t)255);
return fgcolor;
}
FORCEINLINE BgraColor VECTORCALL CalcDynamicLight(const PolyLight *lights, int num_lights, FVector3 worldpos, FVector3 worldnormal, uint32_t dynlightcolor)
{
BgraColor lit = dynlightcolor;
for (int i = 0; i != num_lights; i++)
{
FVector3 lightpos = { lights[i].x, lights[i].y, lights[i].z };
float light_radius = lights[i].radius;
bool is_attenuated = light_radius < 0.0f;
if (is_attenuated)
light_radius = -light_radius;
// L = light-pos
// dist = sqrt(dot(L, L))
// distance_attenuation = 1 - MIN(dist * (1/radius), 1)
FVector3 L = lightpos - worldpos;
float dist2 = L | L;
float rcp_dist = 1.0f / sqrt(dist2);
float dist = dist2 * rcp_dist;
float distance_attenuation = 256.0f - MIN(dist * light_radius, 256.0f);
// The simple light type
float simple_attenuation = distance_attenuation;
// The point light type
// diffuse = max(dot(N,normalize(L)),0) * attenuation
float dotNL = worldnormal | (L * rcp_dist);
float point_attenuation = MAX(dotNL, 0.0f) * distance_attenuation;
uint32_t attenuation = (uint32_t)(is_attenuated ? (int32_t)point_attenuation : (int32_t)simple_attenuation);
BgraColor light_color = lights[i].color;
lit.r += (light_color.r * attenuation) >> 8;
lit.g += (light_color.g * attenuation) >> 8;
lit.b += (light_color.b * attenuation) >> 8;
}
lit.r = MIN(lit.r, (uint32_t)256);
lit.g = MIN(lit.g, (uint32_t)256);
lit.b = MIN(lit.b, (uint32_t)256);
return lit;
}
template<typename ShadeModeT>
FORCEINLINE BgraColor Shade32(BgraColor fgcolor, BgraColor mlight, uint32_t desaturate, uint32_t inv_desaturate, BgraColor shade_fade, BgraColor shade_light, BgraColor dynlight)
{
BgraColor material = fgcolor;
if (ShadeModeT::Mode == (int)ShadeMode::Simple)
{
fgcolor.r = (fgcolor.r * mlight.r) >> 8;
@ -170,7 +223,7 @@ namespace TriScreenDrawerModes
fgcolor.g = (((shade_fade.g + ((fgcolor.g * inv_desaturate + intensity) >> 8) * mlight.g) >> 8) * shade_light.g) >> 8;
fgcolor.b = (((shade_fade.b + ((fgcolor.b * inv_desaturate + intensity) >> 8) * mlight.b) >> 8) * shade_light.b) >> 8;
}
return fgcolor;
return AddLights(material, fgcolor, dynlight);
}
template<typename BlendT>
@ -322,17 +375,28 @@ private:
int fuzzpos = (ScreenTriangle::FuzzStart + destX * 123 + destY) % FUZZTABLE;
auto lights = args->uniforms->Lights();
auto num_lights = args->uniforms->NumLights();
FVector3 worldnormal = args->uniforms->Normal();
uint32_t dynlightcolor = args->uniforms->DynLightColor();
// Calculate gradients
const TriVertex &v1 = *args->v1;
const ShadedTriVertex &v1 = *args->v1;
ScreenTriangleStepVariables gradientX = args->gradientX;
ScreenTriangleStepVariables gradientY = args->gradientY;
ScreenTriangleStepVariables blockPosY;
blockPosY.W = v1.w + gradientX.W * (destX - v1.x) + gradientY.W * (destY - v1.y);
blockPosY.U = v1.u * v1.w + gradientX.U * (destX - v1.x) + gradientY.U * (destY - v1.y);
blockPosY.V = v1.v * v1.w + gradientX.V * (destX - v1.x) + gradientY.V * (destY - v1.y);
blockPosY.WorldX = v1.worldX * v1.w + gradientX.WorldX * (destX - v1.x) + gradientY.WorldX * (destY - v1.y);
blockPosY.WorldY = v1.worldY * v1.w + gradientX.WorldY * (destX - v1.x) + gradientY.WorldY * (destY - v1.y);
blockPosY.WorldZ = v1.worldZ * v1.w + gradientX.WorldZ * (destX - v1.x) + gradientY.WorldZ * (destY - v1.y);
gradientX.W *= 8.0f;
gradientX.U *= 8.0f;
gradientX.V *= 8.0f;
gradientX.WorldX *= 8.0f;
gradientX.WorldY *= 8.0f;
gradientX.WorldZ *= 8.0f;
// Output
uint32_t * RESTRICT destOrg = (uint32_t*)args->dest;
@ -401,10 +465,16 @@ private:
fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT);
lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask);
FVector3 worldpos = FVector3(blockPosY.WorldX, blockPosY.WorldY, blockPosY.WorldZ) / blockPosY.W;
BgraColor dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
ScreenTriangleStepVariables blockPosX = blockPosY;
blockPosX.W += gradientX.W;
blockPosX.U += gradientX.U;
blockPosX.V += gradientX.V;
blockPosX.WorldX += gradientX.WorldX;
blockPosX.WorldY += gradientX.WorldY;
blockPosX.WorldZ += gradientX.WorldZ;
rcpW = 0x01000000 / blockPosX.W;
int32_t nextU = (int32_t)(blockPosX.U * rcpW);
@ -416,6 +486,13 @@ private:
fixed_t lightstep = (lightnext - lightpos) / 8;
lightstep = lightstep & lightmask;
worldpos = FVector3(blockPosX.WorldX, blockPosX.WorldY, blockPosX.WorldZ) / blockPosX.W;
BgraColor dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
BgraColor dynlightstep;
dynlightstep.r = int32_t(dynlightnext.r - dynlight.r) >> 3;
dynlightstep.g = int32_t(dynlightnext.g - dynlight.g) >> 3;
dynlightstep.b = int32_t(dynlightnext.b - dynlight.b) >> 3;
for (int ix = 0; ix < 8; ix++)
{
// Load bgcolor
@ -456,16 +533,23 @@ private:
}
// Shade and blend
BgraColor fgcolor = Shade32<ShadeModeT>(ifgcolor, mlight, desaturate, inv_desaturate, shade_fade_lit, shade_light);
BgraColor fgcolor = Shade32<ShadeModeT>(ifgcolor, mlight, desaturate, inv_desaturate, shade_fade_lit, shade_light, dynlight);
BgraColor outcolor = Blend32<BlendT>(fgcolor, bgcolor, ifgcolor, ifgshade, srcalpha, destalpha);
// Store result
dest[ix] = outcolor;
dynlight.r = MAX<int32_t>(dynlight.r + dynlightstep.r, 0);
dynlight.g = MAX<int32_t>(dynlight.g + dynlightstep.g, 0);
dynlight.b = MAX<int32_t>(dynlight.b + dynlightstep.b, 0);
}
blockPosY.W += gradientY.W;
blockPosY.U += gradientY.U;
blockPosY.V += gradientY.V;
blockPosY.WorldX += gradientY.WorldX;
blockPosY.WorldY += gradientY.WorldY;
blockPosY.WorldZ += gradientY.WorldZ;
dest += pitch;
}
@ -482,10 +566,16 @@ private:
fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT);
lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask);
FVector3 worldpos = FVector3(blockPosY.WorldX, blockPosY.WorldY, blockPosY.WorldZ) / blockPosY.W;
BgraColor dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
ScreenTriangleStepVariables blockPosX = blockPosY;
blockPosX.W += gradientX.W;
blockPosX.U += gradientX.U;
blockPosX.V += gradientX.V;
blockPosX.WorldX += gradientX.WorldX;
blockPosX.WorldY += gradientX.WorldY;
blockPosX.WorldZ += gradientX.WorldZ;
rcpW = 0x01000000 / blockPosX.W;
int32_t nextU = (int32_t)(blockPosX.U * rcpW);
@ -497,6 +587,13 @@ private:
fixed_t lightstep = (lightnext - lightpos) / 8;
lightstep = lightstep & lightmask;
worldpos = FVector3(blockPosX.WorldX, blockPosX.WorldY, blockPosX.WorldZ) / blockPosX.W;
BgraColor dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
BgraColor dynlightstep;
dynlightstep.r = int32_t(dynlightnext.r - dynlight.r) >> 3;
dynlightstep.g = int32_t(dynlightnext.g - dynlight.g) >> 3;
dynlightstep.b = int32_t(dynlightnext.b - dynlight.b) >> 3;
for (int x = 0; x < 8; x++)
{
// Load bgcolor
@ -539,18 +636,25 @@ private:
}
// Shade and blend
BgraColor fgcolor = Shade32<ShadeModeT>(ifgcolor, mlight, desaturate, inv_desaturate, shade_fade_lit, shade_light);
BgraColor fgcolor = Shade32<ShadeModeT>(ifgcolor, mlight, desaturate, inv_desaturate, shade_fade_lit, shade_light, dynlight);
BgraColor outcolor = Blend32<BlendT>(fgcolor, bgcolor, ifgcolor, ifgshade, srcalpha, destalpha);
// Store result
if (mask0 & (1 << 31)) dest[x] = outcolor;
mask0 <<= 1;
dynlight.r = MAX<int32_t>(dynlight.r + dynlightstep.r, 0);
dynlight.g = MAX<int32_t>(dynlight.g + dynlightstep.g, 0);
dynlight.b = MAX<int32_t>(dynlight.b + dynlightstep.b, 0);
}
blockPosY.W += gradientY.W;
blockPosY.U += gradientY.U;
blockPosY.V += gradientY.V;
blockPosY.WorldX += gradientY.WorldX;
blockPosY.WorldY += gradientY.WorldY;
blockPosY.WorldZ += gradientY.WorldZ;
dest += pitch;
}
@ -565,10 +669,16 @@ private:
fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT);
lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask);
FVector3 worldpos = FVector3(blockPosY.WorldX, blockPosY.WorldY, blockPosY.WorldZ) / blockPosY.W;
BgraColor dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
ScreenTriangleStepVariables blockPosX = blockPosY;
blockPosX.W += gradientX.W;
blockPosX.U += gradientX.U;
blockPosX.V += gradientX.V;
blockPosX.WorldX += gradientX.WorldX;
blockPosX.WorldY += gradientX.WorldY;
blockPosX.WorldZ += gradientX.WorldZ;
rcpW = 0x01000000 / blockPosX.W;
int32_t nextU = (int32_t)(blockPosX.U * rcpW);
@ -580,6 +690,13 @@ private:
fixed_t lightstep = (lightnext - lightpos) / 8;
lightstep = lightstep & lightmask;
worldpos = FVector3(blockPosX.WorldX, blockPosX.WorldY, blockPosX.WorldZ) / blockPosX.W;
BgraColor dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
BgraColor dynlightstep;
dynlightstep.r = int32_t(dynlightnext.r - dynlight.r) >> 3;
dynlightstep.g = int32_t(dynlightnext.g - dynlight.g) >> 3;
dynlightstep.b = int32_t(dynlightnext.b - dynlight.b) >> 3;
for (int x = 0; x < 8; x++)
{
// Load bgcolor
@ -622,18 +739,25 @@ private:
}
// Shade and blend
BgraColor fgcolor = Shade32<ShadeModeT>(ifgcolor, mlight, desaturate, inv_desaturate, shade_fade_lit, shade_light);
BgraColor fgcolor = Shade32<ShadeModeT>(ifgcolor, mlight, desaturate, inv_desaturate, shade_fade_lit, shade_light, dynlight);
BgraColor outcolor = Blend32<BlendT>(fgcolor, bgcolor, ifgcolor, ifgshade, srcalpha, destalpha);
// Store result
if (mask1 & (1 << 31)) dest[x] = outcolor;
mask1 <<= 1;
dynlight.r = MAX<int32_t>(dynlight.r + dynlightstep.r, 0);
dynlight.g = MAX<int32_t>(dynlight.g + dynlightstep.g, 0);
dynlight.b = MAX<int32_t>(dynlight.b + dynlightstep.b, 0);
}
blockPosY.W += gradientY.W;
blockPosY.U += gradientY.U;
blockPosY.V += gradientY.V;
blockPosY.WorldX += gradientY.WorldX;
blockPosY.WorldY += gradientY.WorldY;
blockPosY.WorldZ += gradientY.WorldZ;
dest += pitch;
}
@ -707,6 +831,8 @@ private:
lightpos += lightpos >> 7; // 255 -> 256
BgraColor mlight;
BgraColor dynlight = 0;
// Shade constants
int inv_desaturate;
BgraColor shade_fade_lit, shade_light;
@ -774,7 +900,7 @@ private:
posU += stepU;
// Shade and blend
BgraColor fgcolor = Shade32<ShadeModeT>(ifgcolor, mlight, desaturate, inv_desaturate, shade_fade_lit, shade_light);
BgraColor fgcolor = Shade32<ShadeModeT>(ifgcolor, mlight, desaturate, inv_desaturate, shade_fade_lit, shade_light, dynlight);
BgraColor outcolor = Blend32<BlendT>(fgcolor, bgcolor, ifgcolor, ifgshade, srcalpha, destalpha);
// Store result

View file

@ -142,9 +142,69 @@ namespace TriScreenDrawerModes
}
}
template<typename ShadeModeT>
FORCEINLINE __m128i VECTORCALL Shade32(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light)
FORCEINLINE __m128i VECTORCALL AddLights(__m128i material, __m128i fgcolor, __m128i dynlight)
{
fgcolor = _mm_add_epi16(fgcolor, _mm_srli_epi16(_mm_mullo_epi16(material, dynlight), 8));
fgcolor = _mm_min_epi16(fgcolor, _mm_set1_epi16(255));
return fgcolor;
}
FORCEINLINE __m128i VECTORCALL CalcDynamicLight(const PolyLight *lights, int num_lights, __m128 worldpos, __m128 worldnormal, uint32_t dynlightcolor)
{
__m128i lit = _mm_unpacklo_epi8(_mm_cvtsi32_si128(dynlightcolor), _mm_setzero_si128());
lit = _mm_shuffle_epi32(lit, _MM_SHUFFLE(1, 0, 1, 0));
for (int i = 0; i != num_lights; i++)
{
__m128 m256 = _mm_set1_ps(256.0f);
__m128 mSignBit = _mm_set1_ps(-0.0f);
__m128 lightpos = _mm_loadu_ps(&lights[i].x);
__m128 light_radius = _mm_load_ss(&lights[i].radius);
__m128 is_attenuated = _mm_cmpge_ss(light_radius, _mm_setzero_ps());
is_attenuated = _mm_shuffle_ps(is_attenuated, is_attenuated, _MM_SHUFFLE(0, 0, 0, 0));
light_radius = _mm_andnot_ps(mSignBit, light_radius);
// L = light-pos
// dist = sqrt(dot(L, L))
// distance_attenuation = 1 - MIN(dist * (1/radius), 1)
__m128 L = _mm_sub_ps(lightpos, worldpos);
__m128 dist2 = _mm_mul_ps(L, L);
dist2 = _mm_add_ss(dist2, _mm_add_ss(_mm_shuffle_ps(dist2, dist2, _MM_SHUFFLE(0, 0, 0, 1)), _mm_shuffle_ps(dist2, dist2, _MM_SHUFFLE(0, 0, 0, 2))));
__m128 rcp_dist = _mm_rsqrt_ss(dist2);
__m128 dist = _mm_mul_ss(dist2, rcp_dist);
__m128 distance_attenuation = _mm_sub_ss(m256, _mm_min_ss(_mm_mul_ss(dist, light_radius), m256));
distance_attenuation = _mm_shuffle_ps(distance_attenuation, distance_attenuation, _MM_SHUFFLE(0, 0, 0, 0));
// The simple light type
__m128 simple_attenuation = distance_attenuation;
// The point light type
// diffuse = max(dot(N,normalize(L)),0) * attenuation
__m128 dotNL = _mm_mul_ps(worldnormal, _mm_mul_ps(L, _mm_shuffle_ps(rcp_dist, rcp_dist, _MM_SHUFFLE(0, 0, 0, 0))));
dotNL = _mm_add_ss(dotNL, _mm_add_ss(_mm_shuffle_ps(dotNL, dotNL, _MM_SHUFFLE(0, 0, 0, 1)), _mm_shuffle_ps(dotNL, dotNL, _MM_SHUFFLE(0, 0, 0, 2))));
dotNL = _mm_max_ss(dotNL, _mm_setzero_ps());
__m128 point_attenuation = _mm_mul_ss(dotNL, distance_attenuation);
point_attenuation = _mm_shuffle_ps(point_attenuation, point_attenuation, _MM_SHUFFLE(0, 0, 0, 0));
__m128i attenuation = _mm_cvtps_epi32(_mm_or_ps(_mm_and_ps(is_attenuated, simple_attenuation), _mm_andnot_ps(is_attenuated, point_attenuation)));
attenuation = _mm_packs_epi32(_mm_shuffle_epi32(attenuation, _MM_SHUFFLE(0, 0, 0, 0)), _mm_shuffle_epi32(attenuation, _MM_SHUFFLE(1, 1, 1, 1)));
__m128i light_color = _mm_cvtsi32_si128(lights[i].color);
light_color = _mm_unpacklo_epi8(light_color, _mm_setzero_si128());
light_color = _mm_shuffle_epi32(light_color, _MM_SHUFFLE(1, 0, 1, 0));
lit = _mm_add_epi16(lit, _mm_srli_epi16(_mm_mullo_epi16(light_color, attenuation), 8));
}
return _mm_min_epi16(lit, _mm_set1_epi16(256));
}
template<typename ShadeModeT>
FORCEINLINE __m128i VECTORCALL Shade32(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light, __m128i dynlight)
{
__m128i material = fgcolor;
if (ShadeModeT::Mode == (int)ShadeMode::Simple)
{
fgcolor = _mm_srli_epi16(_mm_mullo_epi16(fgcolor, mlight), 8);
@ -168,7 +228,8 @@ namespace TriScreenDrawerModes
fgcolor = _mm_srli_epi16(_mm_add_epi16(shade_fade, fgcolor), 8);
fgcolor = _mm_srli_epi16(_mm_mullo_epi16(fgcolor, shade_light), 8);
}
return fgcolor;
return AddLights(material, fgcolor, dynlight);
}
template<typename BlendT>
@ -333,17 +394,28 @@ private:
int fuzzpos = (ScreenTriangle::FuzzStart + destX * 123 + destY) % FUZZTABLE;
auto lights = args->uniforms->Lights();
auto num_lights = args->uniforms->NumLights();
__m128 worldnormal = _mm_setr_ps(args->uniforms->Normal().X, args->uniforms->Normal().Y, args->uniforms->Normal().Z, 0.0f);
uint32_t dynlightcolor = args->uniforms->DynLightColor();
// Calculate gradients
const TriVertex &v1 = *args->v1;
const ShadedTriVertex &v1 = *args->v1;
ScreenTriangleStepVariables gradientX = args->gradientX;
ScreenTriangleStepVariables gradientY = args->gradientY;
ScreenTriangleStepVariables blockPosY;
blockPosY.W = v1.w + gradientX.W * (destX - v1.x) + gradientY.W * (destY - v1.y);
blockPosY.U = v1.u * v1.w + gradientX.U * (destX - v1.x) + gradientY.U * (destY - v1.y);
blockPosY.V = v1.v * v1.w + gradientX.V * (destX - v1.x) + gradientY.V * (destY - v1.y);
blockPosY.WorldX = v1.worldX * v1.w + gradientX.WorldX * (destX - v1.x) + gradientY.WorldX * (destY - v1.y);
blockPosY.WorldY = v1.worldY * v1.w + gradientX.WorldY * (destX - v1.x) + gradientY.WorldY * (destY - v1.y);
blockPosY.WorldZ = v1.worldZ * v1.w + gradientX.WorldZ * (destX - v1.x) + gradientY.WorldZ * (destY - v1.y);
gradientX.W *= 8.0f;
gradientX.U *= 8.0f;
gradientX.V *= 8.0f;
gradientX.WorldX *= 8.0f;
gradientX.WorldY *= 8.0f;
gradientX.WorldZ *= 8.0f;
// Output
uint32_t * RESTRICT destOrg = (uint32_t*)args->dest;
@ -404,10 +476,17 @@ private:
fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT);
lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask);
__m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W);
__m128 worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW);
__m128i dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
ScreenTriangleStepVariables blockPosX = blockPosY;
blockPosX.W += gradientX.W;
blockPosX.U += gradientX.U;
blockPosX.V += gradientX.V;
blockPosX.WorldX += gradientX.WorldX;
blockPosX.WorldY += gradientX.WorldY;
blockPosX.WorldZ += gradientX.WorldZ;
rcpW = 0x01000000 / blockPosX.W;
int32_t nextU = (int32_t)(blockPosX.U * rcpW);
@ -419,6 +498,13 @@ private:
fixed_t lightstep = (lightnext - lightpos) / 8;
lightstep = lightstep & lightmask;
mrcpW = _mm_set1_ps(1.0f / blockPosX.W);
worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosX.WorldX), mrcpW);
__m128i dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
__m128i dynlightstep = _mm_srai_epi16(_mm_sub_epi16(dynlightnext, dynlight), 3);
dynlight = _mm_max_epi16(_mm_min_epi16(_mm_add_epi16(dynlight, _mm_and_si128(dynlightstep, _mm_set_epi32(0xffff,0xffff,0,0))), _mm_set1_epi16(256)), _mm_setzero_si128());
dynlightstep = _mm_slli_epi16(dynlightstep, 1);
for (int ix = 0; ix < 4; ix++)
{
// Load bgcolor
@ -462,16 +548,21 @@ private:
// Shade and blend
__m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128());
fgcolor = Shade32<ShadeModeT>(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light);
fgcolor = Shade32<ShadeModeT>(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light, dynlight);
__m128i outcolor = Blend32<BlendT>(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha);
// Store result
_mm_storel_epi64((__m128i*)(dest + ix * 2), outcolor);
dynlight = _mm_max_epi16(_mm_min_epi16(_mm_add_epi16(dynlight, dynlightstep), _mm_set1_epi16(256)), _mm_setzero_si128());
}
blockPosY.W += gradientY.W;
blockPosY.U += gradientY.U;
blockPosY.V += gradientY.V;
blockPosY.WorldX += gradientY.WorldX;
blockPosY.WorldY += gradientY.WorldY;
blockPosY.WorldZ += gradientY.WorldZ;
dest += pitch;
}
@ -488,10 +579,17 @@ private:
fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT);
lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask);
__m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W);
__m128 worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW);
__m128i dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
ScreenTriangleStepVariables blockPosX = blockPosY;
blockPosX.W += gradientX.W;
blockPosX.U += gradientX.U;
blockPosX.V += gradientX.V;
blockPosX.WorldX += gradientX.WorldX;
blockPosX.WorldY += gradientX.WorldY;
blockPosX.WorldZ += gradientX.WorldZ;
rcpW = 0x01000000 / blockPosX.W;
int32_t nextU = (int32_t)(blockPosX.U * rcpW);
@ -503,6 +601,13 @@ private:
fixed_t lightstep = (lightnext - lightpos) / 8;
lightstep = lightstep & lightmask;
mrcpW = _mm_set1_ps(1.0f / blockPosX.W);
worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosX.WorldX), mrcpW);
__m128i dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
__m128i dynlightstep = _mm_srai_epi16(_mm_sub_epi16(dynlightnext, dynlight), 3);
dynlight = _mm_max_epi16(_mm_min_epi16(_mm_add_epi16(dynlight, _mm_and_si128(dynlightstep, _mm_set_epi32(0xffff, 0xffff, 0, 0))), _mm_set1_epi16(256)), _mm_setzero_si128());
dynlightstep = _mm_slli_epi16(dynlightstep, 1);
for (int x = 0; x < 4; x++)
{
// Load bgcolor
@ -551,7 +656,7 @@ private:
// Shade and blend
__m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128());
fgcolor = Shade32<ShadeModeT>(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light);
fgcolor = Shade32<ShadeModeT>(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light, dynlight);
__m128i outcolor = Blend32<BlendT>(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha);
// Store result
@ -559,12 +664,17 @@ private:
if (mask0 & (1 << 31)) dest[x * 2] = desttmp[0];
if (mask0 & (1 << 30)) dest[x * 2 + 1] = desttmp[1];
dynlight = _mm_max_epi16(_mm_min_epi16(_mm_add_epi16(dynlight, dynlightstep), _mm_set1_epi16(256)), _mm_setzero_si128());
mask0 <<= 2;
}
blockPosY.W += gradientY.W;
blockPosY.U += gradientY.U;
blockPosY.V += gradientY.V;
blockPosY.WorldX += gradientY.WorldX;
blockPosY.WorldY += gradientY.WorldY;
blockPosY.WorldZ += gradientY.WorldZ;
dest += pitch;
}
@ -579,10 +689,17 @@ private:
fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT);
lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask);
__m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W);
__m128 worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW);
__m128i dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
ScreenTriangleStepVariables blockPosX = blockPosY;
blockPosX.W += gradientX.W;
blockPosX.U += gradientX.U;
blockPosX.V += gradientX.V;
blockPosX.WorldX += gradientX.WorldX;
blockPosX.WorldY += gradientX.WorldY;
blockPosX.WorldZ += gradientX.WorldZ;
rcpW = 0x01000000 / blockPosX.W;
int32_t nextU = (int32_t)(blockPosX.U * rcpW);
@ -594,6 +711,13 @@ private:
fixed_t lightstep = (lightnext - lightpos) / 8;
lightstep = lightstep & lightmask;
mrcpW = _mm_set1_ps(1.0f / blockPosX.W);
worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosX.WorldX), mrcpW);
__m128i dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor);
__m128i dynlightstep = _mm_srai_epi16(_mm_sub_epi16(dynlightnext, dynlight), 3);
dynlight = _mm_max_epi16(_mm_min_epi16(_mm_add_epi16(dynlight, _mm_and_si128(dynlightstep, _mm_set_epi32(0xffff, 0xffff, 0, 0))), _mm_set1_epi16(256)), _mm_setzero_si128());
dynlightstep = _mm_slli_epi16(dynlightstep, 1);
for (int x = 0; x < 4; x++)
{
// Load bgcolor
@ -642,7 +766,7 @@ private:
// Shade and blend
__m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128());
fgcolor = Shade32<ShadeModeT>(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light);
fgcolor = Shade32<ShadeModeT>(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light, dynlight);
__m128i outcolor = Blend32<BlendT>(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha);
// Store result
@ -650,12 +774,17 @@ private:
if (mask1 & (1 << 31)) dest[x * 2] = desttmp[0];
if (mask1 & (1 << 30)) dest[x * 2 + 1] = desttmp[1];
dynlight = _mm_max_epi16(_mm_min_epi16(_mm_add_epi16(dynlight, dynlightstep), _mm_set1_epi16(256)), _mm_setzero_si128());
mask1 <<= 2;
}
blockPosY.W += gradientY.W;
blockPosY.U += gradientY.U;
blockPosY.V += gradientY.V;
blockPosY.WorldX += gradientY.WorldX;
blockPosY.WorldY += gradientY.WorldY;
blockPosY.WorldZ += gradientY.WorldZ;
dest += pitch;
}
@ -798,7 +927,7 @@ private:
// Shade and blend
__m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128());
fgcolor = Shade32<ShadeModeT>(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light);
fgcolor = Shade32<ShadeModeT>(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light, _mm_setzero_si128());
__m128i outcolor = Blend32<BlendT>(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha);
// Store result
@ -826,7 +955,7 @@ private:
// Shade and blend
__m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128());
fgcolor = Shade32<ShadeModeT>(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light);
fgcolor = Shade32<ShadeModeT>(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light, _mm_setzero_si128());
__m128i outcolor = Blend32<BlendT>(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha);
// Store result

View file

@ -231,7 +231,7 @@ public:
int fuzzpos = (ScreenTriangle::FuzzStart + destX * 123 + destY) % FUZZTABLE;
// Calculate gradients
const TriVertex &v1 = *args->v1;
const ShadedTriVertex &v1 = *args->v1;
ScreenTriangleStepVariables gradientX = args->gradientX;
ScreenTriangleStepVariables gradientY = args->gradientY;
ScreenTriangleStepVariables blockPosY;

View file

@ -146,8 +146,18 @@ ShadedTriVertex PolyTriangleDrawer::shade_vertex(const PolyDrawArgs &drawargs, c
const TriMatrix &objectToClip = *drawargs.ObjectToClip();
// Apply transform to get clip coordinates:
FVector4 position = objectToClip * FVector4(v.x, v.y, v.z, v.w);
ShadedTriVertex sv;
sv.position = objectToClip * v;
sv.x = position.X;
sv.y = position.Y;
sv.z = position.Z;
sv.w = position.W;
sv.u = v.u;
sv.v = v.v;
sv.worldX = v.x;
sv.worldY = v.y;
sv.worldZ = v.z;
// Calculate gl_ClipDistance[i]
for (int i = 0; i < 3; i++)
@ -162,12 +172,12 @@ ShadedTriVertex PolyTriangleDrawer::shade_vertex(const PolyDrawArgs &drawargs, c
bool PolyTriangleDrawer::is_degenerate(const ShadedTriVertex *vert)
{
// A degenerate triangle has a zero cross product for two of its sides.
float ax = vert[1].position.x - vert[0].position.x;
float ay = vert[1].position.y - vert[0].position.y;
float az = vert[1].position.w - vert[0].position.w;
float bx = vert[2].position.x - vert[0].position.x;
float by = vert[2].position.y - vert[0].position.y;
float bz = vert[2].position.w - vert[0].position.w;
float ax = vert[1].x - vert[0].x;
float ay = vert[1].y - vert[0].y;
float az = vert[1].w - vert[0].w;
float bx = vert[2].x - vert[0].x;
float by = vert[2].y - vert[0].y;
float bz = vert[2].w - vert[0].w;
float crossx = ay * bz - az * by;
float crossy = az * bx - ax * bz;
float crossz = ax * by - ay * bx;
@ -182,7 +192,7 @@ void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool
return;
// Cull, clip and generate additional vertices as needed
TriVertex clippedvert[max_additional_vertices];
ShadedTriVertex clippedvert[max_additional_vertices];
int numclipvert = clipedge(vert, clippedvert);
#ifdef NO_SSE
@ -273,7 +283,7 @@ void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool
}
}
int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippedvert)
int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, ShadedTriVertex *clippedvert)
{
// Clip and cull so that the following is true for all vertices:
// -v.w <= v.x <= v.w
@ -288,16 +298,16 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippe
float *clipd = clipdistance;
for (int i = 0; i < 3; i++)
{
const auto &v = verts[i].position;
const auto &v = verts[i];
clipd[0] = v.x + v.w;
clipd[1] = v.w - v.x;
clipd[2] = v.y + v.w;
clipd[3] = v.w - v.y;
clipd[4] = v.z + v.w;
clipd[5] = v.w - v.z;
clipd[6] = verts[i].clipDistance[0];
clipd[7] = verts[i].clipDistance[1];
clipd[8] = verts[i].clipDistance[2];
clipd[6] = v.clipDistance[0];
clipd[7] = v.clipDistance[1];
clipd[8] = v.clipDistance[2];
for (int j = 0; j < 9; j++)
needsclipping = needsclipping || clipd[i];
clipd += numclipdistances;
@ -308,14 +318,14 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippe
{
for (int i = 0; i < 3; i++)
{
memcpy(clippedvert + i, &verts[i].position, sizeof(TriVertex));
memcpy(clippedvert + i, &verts[i], sizeof(ShadedTriVertex));
}
return 3;
}
#else
__m128 mx = _mm_loadu_ps(&verts[0].position.x);
__m128 my = _mm_loadu_ps(&verts[1].position.x);
__m128 mz = _mm_loadu_ps(&verts[2].position.x);
__m128 mx = _mm_loadu_ps(&verts[0].x);
__m128 my = _mm_loadu_ps(&verts[1].x);
__m128 mz = _mm_loadu_ps(&verts[2].x);
__m128 mw = _mm_setzero_ps();
_MM_TRANSPOSE4_PS(mx, my, mz, mw);
__m128 clipd0 = _mm_add_ps(mx, mw);
@ -340,7 +350,7 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippe
{
for (int i = 0; i < 3; i++)
{
memcpy(clippedvert + i, &verts[i].position, sizeof(TriVertex));
memcpy(clippedvert + i, &verts[i], sizeof(ShadedTriVertex));
}
return 3;
}
@ -429,16 +439,19 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippe
for (int i = 0; i < inputverts; i++)
{
auto &v = clippedvert[i];
memset(&v, 0, sizeof(TriVertex));
memset(&v, 0, sizeof(ShadedTriVertex));
for (int w = 0; w < 3; w++)
{
float weight = input[i * 3 + w];
v.x += verts[w].position.x * weight;
v.y += verts[w].position.y * weight;
v.z += verts[w].position.z * weight;
v.w += verts[w].position.w * weight;
v.u += verts[w].position.u * weight;
v.v += verts[w].position.v * weight;
v.x += verts[w].x * weight;
v.y += verts[w].y * weight;
v.z += verts[w].z * weight;
v.w += verts[w].w * weight;
v.u += verts[w].u * weight;
v.v += verts[w].v * weight;
v.worldX += verts[w].worldX * weight;
v.worldY += verts[w].worldY * weight;
v.worldZ += verts[w].worldZ * weight;
}
}
return inputverts;

View file

@ -29,12 +29,6 @@
#include "polyrenderer/drawers/poly_buffer.h"
#include "polyrenderer/drawers/poly_draw_args.h"
struct ShadedTriVertex
{
TriVertex position;
float clipDistance[3];
};
typedef void(*PolyDrawFuncPtr)(const TriDrawTriangleArgs *, WorkerThreadData *);
class PolyTriangleDrawer
@ -50,7 +44,7 @@ private:
static void draw_shaded_triangle(const ShadedTriVertex *vertices, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread);
static bool is_degenerate(const ShadedTriVertex *vertices);
static int clipedge(const ShadedTriVertex *verts, TriVertex *clippedvert);
static int clipedge(const ShadedTriVertex *verts, ShadedTriVertex *clippedvert);
static int viewport_x, viewport_y, viewport_width, viewport_height, dest_pitch, dest_width, dest_height;
static bool dest_bgra;

View file

@ -140,9 +140,9 @@ private:
TriangleBlock::TriangleBlock(const TriDrawTriangleArgs *args, WorkerThreadData *thread) : args(args), thread(thread)
{
const TriVertex &v1 = *args->v1;
const TriVertex &v2 = *args->v2;
const TriVertex &v3 = *args->v3;
const ShadedTriVertex &v1 = *args->v1;
const ShadedTriVertex &v2 = *args->v2;
const ShadedTriVertex &v3 = *args->v3;
clipright = args->clipright;
clipbottom = args->clipbottom;
@ -368,7 +368,7 @@ void TriangleBlock::DepthTest(const TriDrawTriangleArgs *args)
int block = (X >> 3) + (Y >> 3) * zbufferPitch;
float *depth = zbuffer + block * 64;
const TriVertex &v1 = *args->v1;
const ShadedTriVertex &v1 = *args->v1;
float stepXW = args->gradientX.W;
float stepYW = args->gradientY.W;
@ -416,7 +416,7 @@ void TriangleBlock::DepthTest(const TriDrawTriangleArgs *args)
int block = (X >> 3) + (Y >> 3) * zbufferPitch;
float *depth = zbuffer + block * 64;
const TriVertex &v1 = *args->v1;
const ShadedTriVertex &v1 = *args->v1;
float stepXW = args->gradientX.W;
float stepYW = args->gradientY.W;
@ -962,7 +962,7 @@ void TriangleBlock::DepthWrite(const TriDrawTriangleArgs *args)
int block = (X >> 3) + (Y >> 3) * zbufferPitch;
float *depth = zbuffer + block * 64;
const TriVertex &v1 = *args->v1;
const ShadedTriVertex &v1 = *args->v1;
float stepXW = args->gradientX.W;
float stepYW = args->gradientY.W;
@ -1023,7 +1023,7 @@ void TriangleBlock::DepthWrite(const TriDrawTriangleArgs *args)
int block = (X >> 3) + (Y >> 3) * zbufferPitch;
float *depth = zbuffer + block * 64;
const TriVertex &v1 = *args->v1;
const ShadedTriVertex &v1 = *args->v1;
float stepXW = args->gradientX.W;
float stepYW = args->gradientY.W;
@ -1081,7 +1081,7 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thr
#else
static void SortVertices(const TriDrawTriangleArgs *args, TriVertex **sortedVertices)
static void SortVertices(const TriDrawTriangleArgs *args, ShadedTriVertex **sortedVertices)
{
sortedVertices[0] = args->v1;
sortedVertices[1] = args->v2;
@ -1098,7 +1098,7 @@ static void SortVertices(const TriDrawTriangleArgs *args, TriVertex **sortedVert
void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
{
// Sort vertices by Y position
TriVertex *sortedVertices[3];
ShadedTriVertex *sortedVertices[3];
SortVertices(args, sortedVertices);
int clipright = args->clipright;

View file

@ -41,27 +41,27 @@ struct WorkerThreadData
}
};
struct TriVertex
struct ShadedTriVertex
{
TriVertex() { }
TriVertex(float x, float y, float z, float w, float u, float v) : x(x), y(y), z(z), w(w), u(u), v(v) { }
float x, y, z, w;
float u, v;
float clipDistance[3];
float worldX, worldY, worldZ;
};
struct ScreenTriangleStepVariables
{
float W, U, V;
float WorldX, WorldY, WorldZ, Padding; // Padding so it can be loaded directly into a XMM register
};
struct TriDrawTriangleArgs
{
uint8_t *dest;
int32_t pitch;
TriVertex *v1;
TriVertex *v2;
TriVertex *v3;
ShadedTriVertex *v1;
ShadedTriVertex *v2;
ShadedTriVertex *v3;
int32_t clipright;
int32_t clipbottom;
uint8_t *stencilValues;
@ -80,23 +80,37 @@ struct TriDrawTriangleArgs
if ((bottomX >= -FLT_EPSILON && bottomX <= FLT_EPSILON) || (bottomY >= -FLT_EPSILON && bottomY <= FLT_EPSILON))
return false;
gradientX.W = FindGradientX(bottomX, v1->w, v2->w, v3->w);
gradientY.W = FindGradientY(bottomY, v1->w, v2->w, v3->w);
gradientX.U = FindGradientX(bottomX, v1->u * v1->w, v2->u * v2->w, v3->u * v3->w);
gradientY.U = FindGradientY(bottomY, v1->u * v1->w, v2->u * v2->w, v3->u * v3->w);
gradientX.V = FindGradientX(bottomX, v1->v * v1->w, v2->v * v2->w, v3->v * v3->w);
gradientY.V = FindGradientY(bottomY, v1->v * v1->w, v2->v * v2->w, v3->v * v3->w);
gradientX.W = FindGradientX(bottomX, 1.0f, 1.0f, 1.0f);
gradientX.U = FindGradientX(bottomX, v1->u, v2->u, v3->u);
gradientX.V = FindGradientX(bottomX, v1->v, v2->v, v3->v);
gradientX.WorldX = FindGradientX(bottomX, v1->worldX, v2->worldX, v3->worldX);
gradientX.WorldY = FindGradientX(bottomX, v1->worldY, v2->worldY, v3->worldY);
gradientX.WorldZ = FindGradientX(bottomX, v1->worldZ, v2->worldZ, v3->worldZ);
gradientY.W = FindGradientY(bottomY, 1.0f, 1.0f, 1.0f);
gradientY.U = FindGradientY(bottomY, v1->u, v2->u, v3->u);
gradientY.V = FindGradientY(bottomY, v1->v, v2->v, v3->v);
gradientY.WorldX = FindGradientY(bottomY, v1->worldX, v2->worldX, v3->worldX);
gradientY.WorldY = FindGradientY(bottomY, v1->worldY, v2->worldY, v3->worldY);
gradientY.WorldZ = FindGradientY(bottomY, v1->worldZ, v2->worldZ, v3->worldZ);
return true;
}
private:
float FindGradientX(float bottomX, float c0, float c1, float c2)
{
c0 *= v1->w;
c1 *= v2->w;
c2 *= v3->w;
return ((c1 - c2) * (v1->y - v3->y) - (c0 - c2) * (v2->y - v3->y)) / bottomX;
}
float FindGradientY(float bottomY, float c0, float c1, float c2)
{
c0 *= v1->w;
c1 *= v2->w;
c2 *= v3->w;
return ((c1 - c2) * (v1->x - v3->x) - (c0 - c2) * (v2->x - v3->x)) / bottomY;
}
};

View file

@ -173,33 +173,27 @@ TriMatrix TriMatrix::operator*(const TriMatrix &mult) const
return result;
}
TriVertex TriMatrix::operator*(TriVertex v) const
FVector4 TriMatrix::operator*(const FVector4 &v) const
{
#ifdef NO_SSE
float vx = matrix[0 * 4 + 0] * v.x + matrix[1 * 4 + 0] * v.y + matrix[2 * 4 + 0] * v.z + matrix[3 * 4 + 0] * v.w;
float vy = matrix[0 * 4 + 1] * v.x + matrix[1 * 4 + 1] * v.y + matrix[2 * 4 + 1] * v.z + matrix[3 * 4 + 1] * v.w;
float vz = matrix[0 * 4 + 2] * v.x + matrix[1 * 4 + 2] * v.y + matrix[2 * 4 + 2] * v.z + matrix[3 * 4 + 2] * v.w;
float vw = matrix[0 * 4 + 3] * v.x + matrix[1 * 4 + 3] * v.y + matrix[2 * 4 + 3] * v.z + matrix[3 * 4 + 3] * v.w;
TriVertex sv;
sv.x = vx;
sv.y = vy;
sv.z = vz;
sv.w = vw;
float vx = matrix[0 * 4 + 0] * v.X + matrix[1 * 4 + 0] * v.Y + matrix[2 * 4 + 0] * v.Z + matrix[3 * 4 + 0] * v.W;
float vy = matrix[0 * 4 + 1] * v.X + matrix[1 * 4 + 1] * v.Y + matrix[2 * 4 + 1] * v.Z + matrix[3 * 4 + 1] * v.W;
float vz = matrix[0 * 4 + 2] * v.X + matrix[1 * 4 + 2] * v.Y + matrix[2 * 4 + 2] * v.Z + matrix[3 * 4 + 2] * v.W;
float vw = matrix[0 * 4 + 3] * v.X + matrix[1 * 4 + 3] * v.Y + matrix[2 * 4 + 3] * v.Z + matrix[3 * 4 + 3] * v.W;
return{ vx, vy, vz, vw };
#else
__m128 m0 = _mm_loadu_ps(matrix);
__m128 m1 = _mm_loadu_ps(matrix + 4);
__m128 m2 = _mm_loadu_ps(matrix + 8);
__m128 m3 = _mm_loadu_ps(matrix + 12);
__m128 mv = _mm_loadu_ps(&v.x);
__m128 mv = _mm_loadu_ps(&v.X);
m0 = _mm_mul_ps(m0, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(0, 0, 0, 0)));
m1 = _mm_mul_ps(m1, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(1, 1, 1, 1)));
m2 = _mm_mul_ps(m2, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(2, 2, 2, 2)));
m3 = _mm_mul_ps(m3, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(3, 3, 3, 3)));
mv = _mm_add_ps(_mm_add_ps(_mm_add_ps(m0, m1), m2), m3);
TriVertex sv;
_mm_storeu_ps(&sv.x, mv);
#endif
sv.u = v.u;
sv.v = v.v;
FVector4 sv;
_mm_storeu_ps(&sv.X, mv);
return sv;
#endif
}

View file

@ -39,7 +39,7 @@ struct TriMatrix
//static TriMatrix worldToView(const FRenderViewpoint &viewpoint); // Software renderer world to view space transform
//static TriMatrix viewToClip(double focalTangent, double centerY, double invZtoScale); // Software renderer shearing projection
TriVertex operator*(TriVertex v) const;
FVector4 operator*(const FVector4 &v) const;
TriMatrix operator*(const TriMatrix &m) const;
float matrix[16];

View file

@ -28,7 +28,7 @@
#include "poly_cull.h"
#include "polyrenderer/poly_renderer.h"
void PolyCull::CullScene(const TriMatrix &worldToClip, const PolyClipPlane &portalClipPlane)
void PolyCull::CullScene(const PolyClipPlane &portalClipPlane)
{
ClearSolidSegments();
MarkViewFrustum();

View file

@ -29,7 +29,7 @@
class PolyCull
{
public:
void CullScene(const TriMatrix &worldToClip, const PolyClipPlane &portalClipPlane);
void CullScene(const PolyClipPlane &portalClipPlane);
bool IsLineSegVisible(uint32_t subsectorDepth, uint32_t lineIndex)
{

View file

@ -32,253 +32,152 @@
#include "polyrenderer/scene/poly_light.h"
#include "polyrenderer/poly_renderthread.h"
#include "p_lnspec.h"
#include "a_dynlight.h"
EXTERN_CVAR(Int, r_3dfloors)
void RenderPolyPlane::RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
void RenderPolyPlane::RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
{
if (sub->sector->CenterFloor() == sub->sector->CenterCeiling())
if (fakeflat.FrontSector->CenterFloor() == fakeflat.FrontSector->CenterCeiling())
return;
RenderPolyPlane plane;
plane.Render(thread, worldToClip, clipPlane, sub, stencilValue, true, skyCeilingHeight, sectorPortals);
plane.Render(thread, worldToClip, clipPlane, sub, stencilValue, false, skyFloorHeight, sectorPortals);
plane.Render(thread, worldToClip, clipPlane, fakeflat, stencilValue, true, skyCeilingHeight, sectorPortals);
plane.Render(thread, worldToClip, clipPlane, fakeflat, stencilValue, false, skyFloorHeight, sectorPortals);
}
void RenderPolyPlane::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
void RenderPolyPlane::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
{
FSectorPortal *portal = fakeflat.FrontSector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor);
if (!portal || (portal->mFlags & PORTSF_INSKYBOX) == PORTSF_INSKYBOX) // Do not recurse into portals we already recursed into
{
RenderNormal(thread, worldToClip, clipPlane, fakeflat, stencilValue, ceiling, skyHeight);
}
else
{
RenderPortal(thread, worldToClip, clipPlane, fakeflat, stencilValue, ceiling, skyHeight, portal, sectorPortals);
}
}
void RenderPolyPlane::RenderNormal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight)
{
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
sector_t *fakesector = sub->sector->heightsec;
if (fakesector && (fakesector == sub->sector || (fakesector->MoreFlags & SECF_IGNOREHEIGHTSEC) == SECF_IGNOREHEIGHTSEC))
fakesector = nullptr;
bool fakeflooronly = fakesector && (fakesector->MoreFlags & SECF_FAKEFLOORONLY) == SECF_FAKEFLOORONLY;
FTextureID picnum;
bool ccw;
sector_t *frontsector;
if (fakesector)
FTextureID picnum = fakeflat.FrontSector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor);
if (picnum != skyflatnum)
{
// Floor and ceiling texture needs to be swapped sometimes? Why?? :(
FTexture *tex = TexMan(picnum);
if (!tex || tex->UseType == FTexture::TEX_Null)
return;
if (viewpoint.Pos.Z < fakesector->floorplane.Zat0()) // In water
{
if (ceiling)
{
picnum = fakesector->GetTexture(sector_t::ceiling);
ceiling = false;
frontsector = fakesector;
ccw = false;
}
else
{
picnum = fakesector->GetTexture(sector_t::floor);
frontsector = sub->sector;
ccw = true;
}
}
else if (viewpoint.Pos.Z >= fakesector->ceilingplane.Zat0() && !fakeflooronly) // In ceiling water
{
if (ceiling)
{
picnum = fakesector->GetTexture(sector_t::ceiling);
frontsector = sub->sector;
ccw = true;
}
else
{
picnum = fakesector->GetTexture(sector_t::floor);
frontsector = fakesector;
ccw = false;
ceiling = true;
}
}
else if (!ceiling) // Water surface
{
picnum = fakesector->GetTexture(sector_t::ceiling);
frontsector = fakesector;
ccw = true;
}
else if (!fakeflooronly) // Ceiling water surface
{
picnum = fakesector->GetTexture(sector_t::floor);
frontsector = fakesector;
ccw = true;
}
else // Upper ceiling
{
picnum = sub->sector->GetTexture(sector_t::ceiling);
ccw = true;
frontsector = sub->sector;
}
PolyPlaneUVTransform transform = PolyPlaneUVTransform(ceiling ? fakeflat.FrontSector->planes[sector_t::ceiling].xform : fakeflat.FrontSector->planes[sector_t::floor].xform, tex);
TriVertex *vertices = CreatePlaneVertices(thread, fakeflat.Subsector, transform, ceiling ? fakeflat.FrontSector->ceilingplane : fakeflat.FrontSector->floorplane);
PolyDrawArgs args;
SetLightLevel(thread, args, fakeflat, ceiling);
SetDynLights(thread, args, fakeflat.Subsector, ceiling);
args.SetTransform(&worldToClip);
args.SetFaceCullCCW(true);
args.SetStencilTestValue(stencilValue);
args.SetWriteStencil(true, stencilValue + 1);
args.SetClipPlane(0, clipPlane);
args.SetTexture(tex);
args.SetStyle(TriBlendMode::TextureOpaque);
args.DrawArray(thread, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan);
}
else
{
picnum = sub->sector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor);
ccw = true;
frontsector = sub->sector;
TriVertex *vertices = CreateSkyPlaneVertices(thread, fakeflat.Subsector, skyHeight);
PolyDrawArgs args;
args.SetTransform(&worldToClip);
args.SetFaceCullCCW(true);
args.SetStencilTestValue(stencilValue);
args.SetWriteStencil(true, stencilValue + 1);
args.SetClipPlane(0, clipPlane);
args.SetWriteStencil(true, 255);
args.SetWriteColor(false);
args.SetWriteDepth(false);
args.DrawArray(thread, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan);
RenderSkyWalls(thread, args, fakeflat.Subsector, nullptr, ceiling, skyHeight);
}
}
void RenderPolyPlane::RenderPortal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, FSectorPortal *portal, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
{
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
PolyDrawSectorPortal *polyportal = nullptr;
std::vector<PolyPortalSegment> portalSegments;
// Skip portals not facing the camera
if ((ceiling && fakeflat.FrontSector->ceilingplane.PointOnSide(viewpoint.Pos) < 0) ||
(!ceiling && fakeflat.FrontSector->floorplane.PointOnSide(viewpoint.Pos) < 0))
{
return;
}
FTexture *tex = TexMan(picnum);
if (tex->UseType == FTexture::TEX_Null)
return;
std::vector<PolyPortalSegment> portalSegments;
FSectorPortal *portal = sub->sector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor);
PolyDrawSectorPortal *polyportal = nullptr;
if (portal && (portal->mFlags & PORTSF_INSKYBOX) == PORTSF_INSKYBOX) // Do not recurse into portals we already recursed into
portal = nullptr;
bool isSky = portal || picnum == skyflatnum;
if (portal)
for (auto &p : sectorPortals)
{
// Skip portals not facing the camera
if ((ceiling && frontsector->ceilingplane.PointOnSide(viewpoint.Pos) < 0) ||
(!ceiling && frontsector->floorplane.PointOnSide(viewpoint.Pos) < 0))
if (p->Portal == portal) // To do: what other criteria do we need to check for?
{
return;
}
for (auto &p : sectorPortals)
{
if (p->Portal == portal) // To do: what other criteria do we need to check for?
{
polyportal = p.get();
break;
}
}
if (!polyportal)
{
sectorPortals.push_back(std::unique_ptr<PolyDrawSectorPortal>(new PolyDrawSectorPortal(portal, ceiling)));
polyportal = sectorPortals.back().get();
polyportal = p.get();
break;
}
}
if (!polyportal)
{
sectorPortals.push_back(std::unique_ptr<PolyDrawSectorPortal>(new PolyDrawSectorPortal(portal, ceiling)));
polyportal = sectorPortals.back().get();
}
#if 0
// Calculate portal clipping
portalSegments.reserve(sub->numlines);
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
// Calculate portal clipping
portalSegments.reserve(sub->numlines);
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
DVector2 pt1 = line->v1->fPos() - viewpoint.Pos;
DVector2 pt2 = line->v2->fPos() - viewpoint.Pos;
bool backside = pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0;
if (!backside)
{
angle_t angle1, angle2;
if (cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2))
portalSegments.push_back({ angle1, angle2 });
}
else
{
angle_t angle1, angle2;
if (cull.GetAnglesForLine(line->v2->fX(), line->v2->fY(), line->v1->fX(), line->v1->fY(), angle1, angle2))
portalSegments.push_back({ angle1, angle2 });
}
DVector2 pt1 = line->v1->fPos() - viewpoint.Pos;
DVector2 pt2 = line->v2->fPos() - viewpoint.Pos;
bool backside = pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0;
if (!backside)
{
angle_t angle1, angle2;
if (cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2))
portalSegments.push_back({ angle1, angle2 });
}
else
{
angle_t angle1, angle2;
if (cull.GetAnglesForLine(line->v2->fX(), line->v2->fY(), line->v1->fX(), line->v1->fY(), angle1, angle2))
portalSegments.push_back({ angle1, angle2 });
}
}
#endif
}
PolyPlaneUVTransform transform(ceiling ? frontsector->planes[sector_t::ceiling].xform : frontsector->planes[sector_t::floor].xform, tex);
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(sub->numlines);
if (ceiling)
{
if (!isSky)
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
vertices[sub->numlines - 1 - i] = transform.GetVertex(line->v1, frontsector->ceilingplane.ZatPoint(line->v1));
}
}
else
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
vertices[sub->numlines - 1 - i] = transform.GetVertex(line->v1, skyHeight);
}
}
}
else
{
if (!isSky)
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
vertices[i] = transform.GetVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1));
}
}
else
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
vertices[i] = transform.GetVertex(line->v1, skyHeight);
}
}
}
bool foggy = level.fadeto || frontsector->Colormap.FadeColor || (level.flags & LEVEL_HASFADETABLE);
int lightlevel = ceiling ? frontsector->GetCeilingLight() : frontsector->GetFloorLight();
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
lightlevel = clamp(lightlevel + actualextralight, 0, 255);
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
FDynamicColormap *basecolormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]);
if (cameraLight->FixedLightLevel() < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size())
{
lightlist_t *light = P_GetPlaneLight(frontsector, ceiling ? &frontsector->ceilingplane : &frontsector->floorplane, false);
basecolormap = GetColorTable(light->extra_colormap, frontsector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]);
if (light->p_lightlevel != &frontsector->lightlevel) // If this is the real ceiling, don't discard plane lighting R_FakeFlat() accounted for.
{
lightlevel = *light->p_lightlevel;
}
}
TriVertex *vertices = CreateSkyPlaneVertices(thread, fakeflat.Subsector, skyHeight);
PolyDrawArgs args;
args.SetLight(basecolormap, lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
//args.SetSubsectorDepth(isSky ? RenderPolyScene::SkySubsectorDepth : subsectorDepth);
args.SetTransform(&worldToClip);
args.SetFaceCullCCW(ccw);
args.SetFaceCullCCW(true);
args.SetStencilTestValue(stencilValue);
args.SetWriteStencil(true, stencilValue + 1);
args.SetClipPlane(0, clipPlane);
args.SetWriteStencil(true, polyportal->StencilValue);
args.SetWriteColor(false);
args.SetWriteDepth(false);
args.DrawArray(thread, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan);
if (!isSky)
{
args.SetTexture(tex);
args.SetStyle(TriBlendMode::TextureOpaque);
args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan);
}
else
{
if (portal)
{
args.SetWriteStencil(true, polyportal->StencilValue);
polyportal->Shape.push_back({ vertices, (int)sub->numlines, ccw });
}
else
{
args.SetWriteStencil(true, 255);
}
RenderSkyWalls(thread, args, fakeflat.Subsector, polyportal, ceiling, skyHeight);
args.SetWriteColor(false);
args.SetWriteDepth(false);
args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan);
RenderSkyWalls(thread, args, sub, frontsector, portal, polyportal, ceiling, skyHeight, transform);
}
polyportal->Shape.push_back({ vertices, (int)fakeflat.Subsector->numlines, true });
}
void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, sector_t *frontsector, FSectorPortal *portal, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight, const PolyPlaneUVTransform &transform)
void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight)
{
sector_t *frontsector = sub->sector;
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
@ -323,7 +222,7 @@ void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &arg
continue;
}
}
else if (portal && line->linedef && line->linedef->special == Line_Horizon)
else if (polyportal && line->linedef && line->linedef->special == Line_Horizon)
{
// Not entirely correct as this closes the line horizon rather than allowing the floor to continue to infinity
skyBottomz1 = frontsector->floorplane.ZatPoint(line->v1);
@ -334,28 +233,165 @@ void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &arg
if (ceiling)
{
wallvert[0] = transform.GetVertex(line->v1, skyHeight);
wallvert[1] = transform.GetVertex(line->v2, skyHeight);
wallvert[2] = transform.GetVertex(line->v2, skyBottomz2);
wallvert[3] = transform.GetVertex(line->v1, skyBottomz1);
wallvert[0] = GetSkyVertex(line->v1, skyHeight);
wallvert[1] = GetSkyVertex(line->v2, skyHeight);
wallvert[2] = GetSkyVertex(line->v2, skyBottomz2);
wallvert[3] = GetSkyVertex(line->v1, skyBottomz1);
}
else
{
wallvert[0] = transform.GetVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1));
wallvert[1] = transform.GetVertex(line->v2, frontsector->floorplane.ZatPoint(line->v2));
wallvert[2] = transform.GetVertex(line->v2, skyHeight);
wallvert[3] = transform.GetVertex(line->v1, skyHeight);
wallvert[0] = GetSkyVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1));
wallvert[1] = GetSkyVertex(line->v2, frontsector->floorplane.ZatPoint(line->v2));
wallvert[2] = GetSkyVertex(line->v2, skyHeight);
wallvert[3] = GetSkyVertex(line->v1, skyHeight);
}
args.DrawArray(thread, wallvert, 4, PolyDrawMode::TriangleFan);
if (portal)
if (polyportal)
{
polyportal->Shape.push_back({ wallvert, 4, args.FaceCullCCW() });
}
}
}
void RenderPolyPlane::SetLightLevel(PolyRenderThread *thread, PolyDrawArgs &args, const PolyTransferHeights &fakeflat, bool ceiling)
{
bool foggy = level.fadeto || fakeflat.FrontSector->Colormap.FadeColor || (level.flags & LEVEL_HASFADETABLE);
int lightlevel = ceiling ? fakeflat.CeilingLightLevel : fakeflat.FloorLightLevel;
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
lightlevel = clamp(lightlevel + actualextralight, 0, 255);
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
FDynamicColormap *basecolormap = GetColorTable(fakeflat.FrontSector->Colormap, fakeflat.FrontSector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]);
if (cameraLight->FixedLightLevel() < 0 && fakeflat.FrontSector->e && fakeflat.FrontSector->e->XFloor.lightlist.Size())
{
lightlist_t *light = P_GetPlaneLight(fakeflat.FrontSector, ceiling ? &fakeflat.FrontSector->ceilingplane : &fakeflat.FrontSector->floorplane, false);
basecolormap = GetColorTable(light->extra_colormap, fakeflat.FrontSector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]);
if (light->p_lightlevel != &fakeflat.FrontSector->lightlevel) // If this is the real ceiling, don't discard plane lighting R_FakeFlat() accounted for.
{
lightlevel = *light->p_lightlevel;
}
}
args.SetLight(basecolormap, lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
}
void RenderPolyPlane::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling)
{
FLightNode *light_list = sub->lighthead;
auto cameraLight = PolyCameraLight::Instance();
if ((cameraLight->FixedLightLevel() >= 0) || (cameraLight->FixedColormap() != nullptr))
{
args.SetLights(nullptr, 0); // [SP] Don't draw dynlights if invul/lightamp active
return;
}
// Calculate max lights that can touch the wall so we can allocate memory for the list
int max_lights = 0;
FLightNode *cur_node = light_list;
while (cur_node)
{
if (!(cur_node->lightsource->flags2&MF2_DORMANT))
max_lights++;
cur_node = cur_node->nextLight;
}
if (max_lights == 0)
{
args.SetLights(nullptr, 0);
return;
}
int dc_num_lights = 0;
PolyLight *dc_lights = thread->FrameMemory->AllocMemory<PolyLight>(max_lights);
// Setup lights
cur_node = light_list;
while (cur_node)
{
if (!(cur_node->lightsource->flags2&MF2_DORMANT))
{
bool is_point_light = (cur_node->lightsource->lightflags & LF_ATTENUATE) != 0;
// To do: cull lights not touching subsector
uint32_t red = cur_node->lightsource->GetRed();
uint32_t green = cur_node->lightsource->GetGreen();
uint32_t blue = cur_node->lightsource->GetBlue();
auto &light = dc_lights[dc_num_lights++];
light.x = (float)cur_node->lightsource->X();
light.y = (float)cur_node->lightsource->Y();
light.z = (float)cur_node->lightsource->Z();
light.radius = 256.0f / cur_node->lightsource->GetRadius();
light.color = (red << 16) | (green << 8) | blue;
if (is_point_light)
light.radius = -light.radius;
}
cur_node = cur_node->nextLight;
}
args.SetLights(dc_lights, dc_num_lights);
DVector3 normal = ceiling ? sub->sector->ceilingplane.Normal() : sub->sector->floorplane.Normal();
args.SetNormal({ (float)normal.X, (float)normal.Y, (float)normal.Z });
}
TriVertex *RenderPolyPlane::CreatePlaneVertices(PolyRenderThread *thread, subsector_t *sub, const PolyPlaneUVTransform &transform, const secplane_t &plane)
{
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(sub->numlines);
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
double planeZ = plane.ZatPoint(viewpoint.Pos.XY());
if (viewpoint.Pos.Z < planeZ)
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[sub->numlines - 1 - i];
vertices[i] = transform.GetVertex(line->v1, plane.ZatPoint(line->v1));
}
}
else
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
vertices[i] = transform.GetVertex(line->v1, plane.ZatPoint(line->v1));
}
}
return vertices;
}
TriVertex *RenderPolyPlane::CreateSkyPlaneVertices(PolyRenderThread *thread, subsector_t *sub, double skyHeight)
{
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(sub->numlines);
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
if (viewpoint.Pos.Z < skyHeight)
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[sub->numlines - 1 - i];
vertices[i] = GetSkyVertex(line->v1, skyHeight);
}
}
else
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
vertices[i] = GetSkyVertex(line->v1, skyHeight);
}
}
return vertices;
}
/////////////////////////////////////////////////////////////////////////////
PolyPlaneUVTransform::PolyPlaneUVTransform(const FTransform &transform, FTexture *tex)

View file

@ -57,11 +57,23 @@ private:
class RenderPolyPlane
{
public:
static void RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals);
static void RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals);
private:
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals);
void RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, sector_t *frontsector, FSectorPortal *portal, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight, const PolyPlaneUVTransform &transform);
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals);
void RenderPortal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, FSectorPortal *portal, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals);
void RenderNormal(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight);
void RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight);
void SetLightLevel(PolyRenderThread *thread, PolyDrawArgs &args, const PolyTransferHeights &fakeflat, bool ceiling);
void SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling);
TriVertex *CreatePlaneVertices(PolyRenderThread *thread, subsector_t *sub, const PolyPlaneUVTransform &transform, const secplane_t &plane);
TriVertex *CreateSkyPlaneVertices(PolyRenderThread *thread, subsector_t *sub, double skyHeight);
static TriVertex GetSkyVertex(vertex_t *v, double height) { return { (float)v->fX(), (float)v->fY(), (float)height, 1.0f, 0.0f, 0.0f }; }
};
class Render3DFloorPlane

View file

@ -57,6 +57,8 @@ void RenderPolyPlayerSprites::Render(PolyRenderThread *thread)
(r_deathcamera && viewpoint.camera->health <= 0))
return;
PolyTransferHeights fakeflat(viewpoint.camera->subsector);
FDynamicColormap *basecolormap;
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
if (cameraLight->FixedLightLevel() < 0 && viewpoint.sector->e && viewpoint.sector->e->XFloor.lightlist.Size())
@ -89,10 +91,10 @@ void RenderPolyPlayerSprites::Render(PolyRenderThread *thread)
else
{ // This used to use camera->Sector but due to interpolation that can be incorrect
// when the interpolated viewpoint is in a different sector than the camera.
//sec = FakeFlat(viewpoint.sector, &tempsec, &floorlight, &ceilinglight, nullptr, 0, 0, 0, 0);
// Softpoly has no FakeFlat (its FAKE! Everything is FAKE in Doom. Sigh. Might as well call it FooFlat!)
sec = viewpoint.camera->Sector;
floorlight = ceilinglight = sec->lightlevel;
sec = fakeflat.FrontSector;
floorlight = fakeflat.FloorLightLevel;
ceilinglight = fakeflat.CeilingLightLevel;
// [RH] set basecolormap
basecolormap = GetColorTable(sec->Colormap, sec->SpecialColors[sector_t::sprites], true);

View file

@ -60,7 +60,7 @@ void RenderPolyScene::Render(int portalDepth)
SectorPortals.clear();
LinePortals.clear();
Cull.CullScene(WorldToClip, PortalPlane);
Cull.CullScene(PortalPlane);
RenderSectors();
RenderPortals(portalDepth);
}
@ -126,15 +126,17 @@ void RenderPolyScene::RenderSubsector(PolyRenderThread *thread, subsector_t *sub
}
else
{
PolyTransferHeights fakeflat(sub);
Render3DFloorPlane::RenderPlanes(thread, WorldToClip, PortalPlane, sub, StencilValue, subsectorDepth, TranslucentObjects[thread->ThreadIndex]);
RenderPolyPlane::RenderPlanes(thread, WorldToClip, PortalPlane, sub, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals);
RenderPolyPlane::RenderPlanes(thread, WorldToClip, PortalPlane, fakeflat, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals);
for (uint32_t i = 0; i < sub->numlines; i++)
{
if (Cull.IsLineSegVisible(subsectorDepth, i))
{
seg_t *line = &sub->firstline[i];
RenderLine(thread, sub, line, frontsector, subsectorDepth);
RenderLine(thread, sub, line, fakeflat.FrontSector, subsectorDepth);
}
}
}
@ -393,3 +395,159 @@ void RenderPolyScene::RenderTranslucent(int portalDepth)
TranslucentObjects[0].clear();
}
/////////////////////////////////////////////////////////////////////////////
PolyTransferHeights::PolyTransferHeights(subsector_t *sub) : Subsector(sub)
{
sector_t *sec = sub->sector;
// If player's view height is underneath fake floor, lower the
// drawn ceiling to be just under the floor height, and replace
// the drawn floor and ceiling textures, and light level, with
// the control sector's.
//
// Similar for ceiling, only reflected.
// [RH] allow per-plane lighting
FloorLightLevel = sec->GetFloorLight();
CeilingLightLevel = sec->GetCeilingLight();
FakeSide = PolyWaterFakeSide::Center;
const sector_t *s = sec->GetHeightSec();
if (s != nullptr)
{
sector_t *heightsec = PolyRenderer::Instance()->Viewpoint.sector->heightsec;
bool underwater = (heightsec && heightsec->floorplane.PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos) <= 0);
bool doorunderwater = false;
int diffTex = (s->MoreFlags & SECF_CLIPFAKEPLANES);
// Replace sector being drawn with a copy to be hacked
tempsec = *sec;
// Replace floor and ceiling height with control sector's heights.
if (diffTex)
{
if (s->floorplane.CopyPlaneIfValid(&tempsec.floorplane, &sec->ceilingplane))
{
tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
}
else if (s->MoreFlags & SECF_FAKEFLOORONLY)
{
if (underwater)
{
tempsec.Colormap = s->Colormap;
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
{
tempsec.lightlevel = s->lightlevel;
FloorLightLevel = s->GetFloorLight();
CeilingLightLevel = s->GetCeilingLight();
}
FakeSide = PolyWaterFakeSide::BelowFloor;
FrontSector = &tempsec;
return;
}
FrontSector = sec;
return;
}
}
else
{
tempsec.floorplane = s->floorplane;
}
if (!(s->MoreFlags & SECF_FAKEFLOORONLY))
{
if (diffTex)
{
if (s->ceilingplane.CopyPlaneIfValid(&tempsec.ceilingplane, &sec->floorplane))
{
tempsec.SetTexture(sector_t::ceiling, s->GetTexture(sector_t::ceiling), false);
}
}
else
{
tempsec.ceilingplane = s->ceilingplane;
}
}
double refceilz = s->ceilingplane.ZatPoint(PolyRenderer::Instance()->Viewpoint.Pos);
double orgceilz = sec->ceilingplane.ZatPoint(PolyRenderer::Instance()->Viewpoint.Pos);
if (underwater || doorunderwater)
{
tempsec.floorplane = sec->floorplane;
tempsec.ceilingplane = s->floorplane;
tempsec.ceilingplane.FlipVert();
tempsec.ceilingplane.ChangeHeight(-1 / 65536.);
tempsec.Colormap = s->Colormap;
}
// killough 11/98: prevent sudden light changes from non-water sectors:
if (underwater || doorunderwater)
{
// head-below-floor hack
tempsec.SetTexture(sector_t::floor, diffTex ? sec->GetTexture(sector_t::floor) : s->GetTexture(sector_t::floor), false);
tempsec.planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
tempsec.ceilingplane = s->floorplane;
tempsec.ceilingplane.FlipVert();
tempsec.ceilingplane.ChangeHeight(-1 / 65536.);
if (s->GetTexture(sector_t::ceiling) == skyflatnum)
{
tempsec.floorplane = tempsec.ceilingplane;
tempsec.floorplane.FlipVert();
tempsec.floorplane.ChangeHeight(+1 / 65536.);
tempsec.SetTexture(sector_t::ceiling, tempsec.GetTexture(sector_t::floor), false);
tempsec.planes[sector_t::ceiling].xform = tempsec.planes[sector_t::floor].xform;
}
else
{
tempsec.SetTexture(sector_t::ceiling, diffTex ? s->GetTexture(sector_t::floor) : s->GetTexture(sector_t::ceiling), false);
tempsec.planes[sector_t::ceiling].xform = s->planes[sector_t::ceiling].xform;
}
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
{
tempsec.lightlevel = s->lightlevel;
FloorLightLevel = s->GetFloorLight();
CeilingLightLevel = s->GetCeilingLight();
}
FakeSide = PolyWaterFakeSide::BelowFloor;
}
else if (heightsec && heightsec->ceilingplane.PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos) <= 0 && orgceilz > refceilz && !(s->MoreFlags & SECF_FAKEFLOORONLY))
{
// Above-ceiling hack
tempsec.ceilingplane = s->ceilingplane;
tempsec.floorplane = s->ceilingplane;
tempsec.floorplane.FlipVert();
tempsec.floorplane.ChangeHeight(+1 / 65536.);
tempsec.Colormap = s->Colormap;
tempsec.SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false);
tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::ceiling), false);
tempsec.planes[sector_t::ceiling].xform = tempsec.planes[sector_t::floor].xform = s->planes[sector_t::ceiling].xform;
if (s->GetTexture(sector_t::floor) != skyflatnum)
{
tempsec.ceilingplane = sec->ceilingplane;
tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
tempsec.planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
}
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
{
tempsec.lightlevel = s->lightlevel;
FloorLightLevel = s->GetFloorLight();
CeilingLightLevel = s->GetCeilingLight();
}
FakeSide = PolyWaterFakeSide::AboveCeiling;
}
sec = &tempsec;
}
FrontSector = sec;
}

View file

@ -89,3 +89,25 @@ private:
std::vector<std::unique_ptr<PolyDrawSectorPortal>> SectorPortals;
std::vector<std::unique_ptr<PolyDrawLinePortal>> LinePortals;
};
enum class PolyWaterFakeSide
{
Center,
BelowFloor,
AboveCeiling
};
class PolyTransferHeights
{
public:
PolyTransferHeights(subsector_t *sub);
subsector_t *Subsector = nullptr;
sector_t *FrontSector = nullptr;
PolyWaterFakeSide FakeSide = PolyWaterFakeSide::Center;
int FloorLightLevel = 0;
int CeilingLightLevel = 0;
private:
sector_t tempsec;
};

View file

@ -154,6 +154,7 @@ void RenderPolySprite::Render(PolyRenderThread *thread, const TriMatrix &worldTo
int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight;
PolyDrawArgs args;
SetDynlight(thing, args);
args.SetLight(GetColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], true), lightlevel, PolyRenderer::Instance()->Light.SpriteGlobVis(foggy), fullbrightSprite);
args.SetTransform(&worldToClip);
args.SetFaceCullCCW(true);
@ -368,3 +369,58 @@ FTexture *RenderPolySprite::GetSpriteTexture(AActor *thing, /*out*/ bool &flipX)
}
}
}
void RenderPolySprite::SetDynlight(AActor *thing, PolyDrawArgs &args)
{
bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
if (fullbrightSprite)
{
args.SetDynLightColor(0);
return;
}
float lit_red = 0;
float lit_green = 0;
float lit_blue = 0;
auto node = thing->Sector->lighthead;
while (node != nullptr)
{
ADynamicLight *light = node->lightsource;
if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->lightflags&LF_DONTLIGHTSELF) || light->target != thing) && !(light->lightflags&LF_DONTLIGHTACTORS))
{
float lx = (float)(light->X() - thing->X());
float ly = (float)(light->Y() - thing->Y());
float lz = (float)(light->Z() - thing->Center());
float LdotL = lx * lx + ly * ly + lz * lz;
float radius = node->lightsource->GetRadius();
if (radius * radius >= LdotL)
{
float distance = sqrt(LdotL);
float attenuation = 1.0f - distance / radius;
if (attenuation > 0.0f)
{
float red = light->GetRed() * (1.0f / 255.0f);
float green = light->GetGreen() * (1.0f / 255.0f);
float blue = light->GetBlue() * (1.0f / 255.0f);
/*if (light->IsSubtractive())
{
float bright = FVector3(lr, lg, lb).Length();
FVector3 lightColor(lr, lg, lb);
red = (bright - lr) * -1;
green = (bright - lg) * -1;
blue = (bright - lb) * -1;
}*/
lit_red += red * attenuation;
lit_green += green * attenuation;
lit_blue += blue * attenuation;
}
}
}
node = node->nextLight;
}
lit_red = clamp(lit_red * 255.0f, 0.0f, 255.0f);
lit_green = clamp(lit_green * 255.0f, 0.0f, 255.0f);
lit_blue = clamp(lit_blue * 255.0f, 0.0f, 255.0f);
args.SetDynLightColor((((uint32_t)lit_red) << 16) | (((uint32_t)lit_green) << 8) | ((uint32_t)lit_blue));
}

View file

@ -37,6 +37,7 @@ private:
static double PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, double spriteheight, double z);
static double GetSpriteFloorZ(AActor *thing, const DVector2 &thingpos);
static double GetSpriteCeilingZ(AActor *thing, const DVector2 &thingpos);
static void SetDynlight(AActor *thing, PolyDrawArgs &args);
};
class PolyTranslucentThing : public PolyTranslucentObject

View file

@ -35,6 +35,7 @@
#include "polyrenderer/scene/poly_light.h"
#include "polyrenderer/poly_renderthread.h"
#include "g_levellocals.h"
#include "a_dynlight.h"
EXTERN_CVAR(Bool, r_drawmirrors)
EXTERN_CVAR(Bool, r_fogboundary)
@ -95,6 +96,7 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, const TriMatrix &world
wall.Masked = false;
wall.SubsectorDepth = subsectorDepth;
wall.StencilValue = stencilValue;
wall.SectorLightLevel = frontsector->lightlevel;
if (line->backsector == nullptr)
{
@ -110,9 +112,10 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, const TriMatrix &world
return true;
}
}
else
else if (line->PartnerSeg)
{
sector_t *backsector = line->backsector;
PolyTransferHeights fakeback(line->PartnerSeg->Subsector);
sector_t *backsector = fakeback.FrontSector;
double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1);
double backfloorz1 = backsector->floorplane.ZatPoint(line->v1);
@ -214,6 +217,7 @@ void RenderPolyWall::Render3DFloorLine(PolyRenderThread *thread, const TriMatrix
wall.Line = fakeFloor->master;
wall.Side = fakeFloor->master->sidedef[0];
wall.Colormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]);
wall.SectorLightLevel = frontsector->lightlevel;
wall.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS);
if (!wall.Additive && fakeFloor->alpha == 255)
{
@ -317,7 +321,7 @@ void RenderPolyWall::Render(PolyRenderThread *thread, const TriMatrix &worldToCl
}
PolyDrawArgs args;
args.SetLight(GetColorTable(Line->frontsector->Colormap, Line->frontsector->SpecialColors[sector_t::walltop]), GetLightLevel(), PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
args.SetLight(Colormap, GetLightLevel(), PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
args.SetTransform(&worldToClip);
args.SetFaceCullCCW(true);
args.SetStencilTestValue(StencilValue);
@ -326,6 +330,8 @@ void RenderPolyWall::Render(PolyRenderThread *thread, const TriMatrix &worldToCl
args.SetTexture(Texture);
args.SetClipPlane(0, clipPlane);
SetDynLights(thread, args);
if (FogBoundary)
{
args.SetStyle(TriBlendMode::FogBoundary);
@ -365,6 +371,77 @@ void RenderPolyWall::Render(PolyRenderThread *thread, const TriMatrix &worldToCl
RenderPolyDecal::RenderWallDecals(thread, worldToClip, clipPlane, LineSeg, StencilValue);
}
void RenderPolyWall::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args)
{
FLightNode *light_list = (LineSeg && LineSeg->sidedef) ? LineSeg->sidedef->lighthead : nullptr;
auto cameraLight = PolyCameraLight::Instance();
if ((cameraLight->FixedLightLevel() >= 0) || (cameraLight->FixedColormap() != nullptr))
{
args.SetLights(nullptr, 0); // [SP] Don't draw dynlights if invul/lightamp active
return;
}
// Calculate max lights that can touch the wall so we can allocate memory for the list
int max_lights = 0;
FLightNode *cur_node = light_list;
while (cur_node)
{
if (!(cur_node->lightsource->flags2&MF2_DORMANT))
max_lights++;
cur_node = cur_node->nextLight;
}
if (max_lights == 0)
{
args.SetLights(nullptr, 0);
return;
}
int dc_num_lights = 0;
PolyLight *dc_lights = thread->FrameMemory->AllocMemory<PolyLight>(max_lights);
// Setup lights
cur_node = light_list;
while (cur_node)
{
if (!(cur_node->lightsource->flags2&MF2_DORMANT))
{
bool is_point_light = (cur_node->lightsource->lightflags & LF_ATTENUATE) != 0;
// To do: cull lights not touching wall
uint32_t red = cur_node->lightsource->GetRed();
uint32_t green = cur_node->lightsource->GetGreen();
uint32_t blue = cur_node->lightsource->GetBlue();
auto &light = dc_lights[dc_num_lights++];
light.x = (float)cur_node->lightsource->X();
light.y = (float)cur_node->lightsource->Y();
light.z = (float)cur_node->lightsource->Z();
light.radius = 256.0f / cur_node->lightsource->GetRadius();
light.color = (red << 16) | (green << 8) | blue;
if (is_point_light)
light.radius = -light.radius;
}
cur_node = cur_node->nextLight;
}
args.SetLights(dc_lights, dc_num_lights);
// Face normal:
float dx = (float)(v2.X - v1.X);
float dy = (float)(v2.Y - v1.Y);
float nx = dy;
float ny = -dx;
float lensqr = nx * nx + ny * ny;
float rcplen = 1.0f / sqrt(lensqr);
nx *= rcplen;
ny *= rcplen;
args.SetNormal({ nx, ny, 0.0f });
}
void RenderPolyWall::DrawStripes(PolyRenderThread *thread, PolyDrawArgs &args, TriVertex *vertices)
{
const auto &lightlist = Line->frontsector->e->XFloor.lightlist;
@ -479,7 +556,7 @@ int RenderPolyWall::GetLightLevel()
{
bool foggy = false;
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
return clamp(Side->GetLightLevel(foggy, LineSeg->frontsector->lightlevel) + actualextralight, 0, 255);
return clamp(Side->GetLightLevel(foggy, SectorLightLevel) + actualextralight, 0, 255);
}
}

View file

@ -55,6 +55,7 @@ public:
double UnpeggedCeil1 = 0.0;
double UnpeggedCeil2 = 0.0;
FSWColormap *Colormap = nullptr;
int SectorLightLevel = 0;
bool Masked = false;
bool Additive = false;
double Alpha = 1.0;
@ -68,6 +69,8 @@ private:
int GetLightLevel();
void DrawStripes(PolyRenderThread *thread, PolyDrawArgs &args, TriVertex *vertices);
void SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args);
static bool IsFogBoundary(sector_t *front, sector_t *back);
static FTexture *GetTexture(const line_t *Line, const side_t *Side, side_t::ETexpart texpart);
};

View file

@ -307,10 +307,9 @@ void P_SpawnLinePortal(line_t* line)
port->mType = PORTT_TELEPORT;
}
}
if (port->mDestination != nullptr)
{
port->mDefFlags = port->mType == PORTT_VISUAL ? PORTF_VISIBLE : port->mType == PORTT_TELEPORT ? PORTF_TYPETELEPORT : PORTF_TYPEINTERACTIVE;
}
port->mDefFlags = port->mType == PORTT_VISUAL ? PORTF_VISIBLE :
port->mType == PORTT_TELEPORT ? PORTF_TYPETELEPORT :
PORTF_TYPEINTERACTIVE;
}
else if (line->args[2] == PORTT_LINKEDEE && line->args[0] == 0)
{
@ -360,6 +359,13 @@ void P_SpawnLinePortal(line_t* line)
void P_UpdatePortal(FLinePortal *port)
{
if (port->mType != PORTT_VISUAL && port->mOrigin->backsector == nullptr && !(port->mOrigin->sidedef[0]->Flags & WALLF_POLYOBJ))
{
Printf(TEXTCOLOR_RED "Warning: Traversable portals must have a back-sector and empty space behind them (or be on a polyobject)! Changing line %d to visual-portal!\n", port->mOrigin->Index());
port->mType = PORTT_VISUAL;
port->mDefFlags &= ~(PORTF_PASSABLE | PORTF_SOUNDTRAVERSE | PORTF_INTERACTIVE);
}
if (port->mDestination == nullptr)
{
// Portal has no destination: switch it off
@ -374,6 +380,7 @@ void P_UpdatePortal(FLinePortal *port)
// this is illegal. Demote the type to TELEPORT
port->mType = PORTT_TELEPORT;
port->mDefFlags &= ~PORTF_INTERACTIVE;
Printf(TEXTCOLOR_RED "Warning: linked portal did not have matching reverse portal. Changing line %d to teleport-portal!\n", port->mOrigin->Index());
}
}
else
@ -466,6 +473,10 @@ static bool ChangePortalLine(line_t *line, int destid)
}
SetRotation(portd);
}
else
{
port->mFlags = port->mDefFlags;
}
SetRotation(port);
return true;
}

View file

@ -56,9 +56,6 @@ extern RenderBufferOptions rbOpts;
// Version of AppKit framework we are interested in
// The following values are needed to build with earlier SDKs
#define AppKit10_4 824
#define AppKit10_5 949
#define AppKit10_6 1038
#define AppKit10_7 1138
#define AppKit10_8 1187
#define AppKit10_9 1265
@ -69,11 +66,6 @@ extern RenderBufferOptions rbOpts;
@end
inline bool I_IsHiDPISupported()
{
return NSAppKitVersionNumber >= AppKit10_7;
}
void I_ProcessEvent(NSEvent* event);
void I_ProcessJoysticks();
@ -82,124 +74,4 @@ NSSize I_GetContentViewSize(const NSWindow* window);
void I_SetMainWindowVisible(bool visible);
void I_SetNativeMouse(bool wantNative);
// The following definitions are required to build with older OS X SDKs
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
typedef unsigned int NSUInteger;
typedef int NSInteger;
typedef float CGFloat;
// From HIToolbox/Events.h
enum
{
kVK_ANSI_F = 0x03,
kVK_Return = 0x24,
kVK_Tab = 0x30,
kVK_Space = 0x31,
kVK_Delete = 0x33,
kVK_Escape = 0x35,
kVK_Command = 0x37,
kVK_Shift = 0x38,
kVK_CapsLock = 0x39,
kVK_Option = 0x3A,
kVK_Control = 0x3B,
kVK_RightShift = 0x3C,
kVK_RightOption = 0x3D,
kVK_RightControl = 0x3E,
kVK_Function = 0x3F,
kVK_F17 = 0x40,
kVK_VolumeUp = 0x48,
kVK_VolumeDown = 0x49,
kVK_Mute = 0x4A,
kVK_F18 = 0x4F,
kVK_F19 = 0x50,
kVK_F20 = 0x5A,
kVK_F5 = 0x60,
kVK_F6 = 0x61,
kVK_F7 = 0x62,
kVK_F3 = 0x63,
kVK_F8 = 0x64,
kVK_F9 = 0x65,
kVK_F11 = 0x67,
kVK_F13 = 0x69,
kVK_F16 = 0x6A,
kVK_F14 = 0x6B,
kVK_F10 = 0x6D,
kVK_F12 = 0x6F,
kVK_F15 = 0x71,
kVK_Help = 0x72,
kVK_Home = 0x73,
kVK_PageUp = 0x74,
kVK_ForwardDelete = 0x75,
kVK_F4 = 0x76,
kVK_End = 0x77,
kVK_F2 = 0x78,
kVK_PageDown = 0x79,
kVK_F1 = 0x7A,
kVK_LeftArrow = 0x7B,
kVK_RightArrow = 0x7C,
kVK_DownArrow = 0x7D,
kVK_UpArrow = 0x7E
};
static const NSOpenGLPixelFormatAttribute NSOpenGLPFAAllowOfflineRenderers = NSOpenGLPixelFormatAttribute(96);
@interface NSWindow(SetCollectionBehavior)
- (void)setCollectionBehavior:(NSUInteger)collectionBehavior;
@end
typedef NSUInteger NSWindowCollectionBehavior;
#endif // prior to 10.5
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
enum
{
NSApplicationActivationPolicyRegular
};
typedef NSInteger NSApplicationActivationPolicy;
@interface NSApplication(ActivationPolicy)
- (BOOL)setActivationPolicy:(NSApplicationActivationPolicy)activationPolicy;
@end
@interface NSWindow(SetStyleMask)
- (void)setStyleMask:(NSUInteger)styleMask;
@end
#endif // prior to 10.6
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
@interface NSView(HiDPIStubs)
- (NSPoint)convertPointToBacking:(NSPoint)aPoint;
- (NSSize)convertSizeToBacking:(NSSize)aSize;
- (NSSize)convertSizeFromBacking:(NSSize)aSize;
- (void)setWantsBestResolutionOpenGLSurface:(BOOL)flag;
@end
@interface NSView(Compatibility)
- (NSRect)convertRectToBacking:(NSRect)aRect;
@end
@interface NSScreen(HiDPIStubs)
- (NSRect)convertRectToBacking:(NSRect)aRect;
@end
static const NSWindowCollectionBehavior NSWindowCollectionBehaviorFullScreenAuxiliary = NSWindowCollectionBehavior(1 << 8);
static const auto NSOpenGLPFAOpenGLProfile = NSOpenGLPixelFormatAttribute(96);
static const auto NSOpenGLProfileVersionLegacy = NSOpenGLPixelFormatAttribute(0x1000);
static const auto NSOpenGLProfileVersion3_2Core = NSOpenGLPixelFormatAttribute(0x3200);
#endif // prior to 10.7
#endif // COCOA_I_COMMON_INCLUDED

View file

@ -479,12 +479,9 @@ void NSEventToGameMousePosition(NSEvent* inEvent, event_t* outEvent)
const NSView* view = [window contentView];
const NSPoint screenPos = [NSEvent mouseLocation];
const NSPoint windowPos = [window convertScreenToBase:screenPos];
const NSPoint viewPos = I_IsHiDPISupported()
? [view convertPointToBacking:windowPos]
: [view convertPoint:windowPos fromView:nil];
const NSRect screenRect = NSMakeRect(screenPos.x, screenPos.y, 0, 0);
const NSRect windowRect = [window convertRectFromScreen:screenRect];
const NSPoint viewPos = [view convertPointToBacking:windowRect.origin];
const CGFloat frameHeight = I_GetContentViewSize(window).height;
const CGFloat posX = ( viewPos.x - rbOpts.shiftX) / rbOpts.pixelScale;

View file

@ -273,10 +273,7 @@ int OriginalMain(int argc, char** argv)
// ---------------------------------------------------------------------------
@interface ApplicationController : NSResponder
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
<NSApplicationDelegate>
#endif
@interface ApplicationController : NSResponder<NSApplicationDelegate>
{
}
@ -554,6 +551,16 @@ int main(int argc, char** argv)
{
s_restartedFromWADPicker = true;
}
#if _DEBUG
else if (0 == strcmp(argument, "-wait_for_debugger"))
{
NSAlert* alert = [[NSAlert alloc] init];
[alert setMessageText:@GAMENAME];
[alert setInformativeText:@"Waiting for debugger..."];
[alert addButtonWithTitle:@"Continue"];
[alert runModal];
}
#endif // _DEBUG
else
{
s_argvStorage.Push(argument);

View file

@ -35,8 +35,6 @@
#include "i_common.h"
#import <Carbon/Carbon.h>
// Avoid collision between DObject class and Objective-C
#define Class ObjectClass
@ -69,19 +67,6 @@
#undef Class
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
@implementation NSView(Compatibility)
- (NSRect)convertRectToBacking:(NSRect)aRect
{
return [self convertRect:aRect toView:[self superview]];
}
@end
#endif // prior to 10.7
@implementation NSWindow(ExitAppOnClose)
- (void)exitAppOnClose
@ -304,7 +289,6 @@ private:
bool m_fullscreen;
bool m_hiDPI;
void SetStyleMask(NSUInteger styleMask);
void SetFullscreenMode(int width, int height);
void SetWindowedMode(int width, int height);
void SetMode(int width, int height, bool fullscreen, bool hiDPI);
@ -510,18 +494,14 @@ NSOpenGLPixelFormat* CreatePixelFormat(const NSOpenGLPixelFormatAttribute profil
attributes[i++] = NSOpenGLPixelFormatAttribute(24);
attributes[i++] = NSOpenGLPFAStencilSize;
attributes[i++] = NSOpenGLPixelFormatAttribute(8);
if (NSAppKitVersionNumber >= AppKit10_5 && !vid_autoswitch)
attributes[i++] = NSOpenGLPFAOpenGLProfile;
attributes[i++] = profile;
if (!vid_autoswitch)
{
attributes[i++] = NSOpenGLPFAAllowOfflineRenderers;
}
if (NSAppKitVersionNumber >= AppKit10_7)
{
attributes[i++] = NSOpenGLPFAOpenGLProfile;
attributes[i++] = profile;
}
attributes[i] = NSOpenGLPixelFormatAttribute(0);
return [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
@ -553,9 +533,9 @@ CocoaVideo::CocoaVideo()
// There is no support for OpenGL 3.3 before Mavericks
defaultProfile = NSOpenGLProfileVersionLegacy;
}
else if (0 == vid_renderer && vid_glswfb && NSAppKitVersionNumber < AppKit10_7)
else if (0 == vid_renderer && 0 == vid_glswfb)
{
// There is no support for OpenGL 3.x before Lion
// Software renderer uses OpenGL 2.1 for blitting
defaultProfile = NSOpenGLProfileVersionLegacy;
}
else if (const char* const glversion = Args->CheckValue("-glversion"))
@ -738,26 +718,6 @@ void CocoaVideo::SetWindowVisible(bool visible)
}
static bool HasModernFullscreenAPI()
{
return NSAppKitVersionNumber >= AppKit10_6;
}
void CocoaVideo::SetStyleMask(const NSUInteger styleMask)
{
// Before 10.6 it's impossible to change window's style mask
// To workaround this new window should be created with required style mask
// This method should not be called when running on Snow Leopard or newer
assert(!HasModernFullscreenAPI());
CocoaWindow* tempWindow = CreateCocoaWindow(styleMask);
[tempWindow setContentView:[m_window contentView]];
[m_window close];
m_window = tempWindow;
}
void CocoaVideo::SetFullscreenMode(const int width, const int height)
{
NSScreen* screen = [m_window screen];
@ -783,20 +743,8 @@ void CocoaVideo::SetFullscreenMode(const int width, const int height)
if (!m_fullscreen)
{
if (HasModernFullscreenAPI())
{
[m_window setLevel:LEVEL_FULLSCREEN];
[m_window setStyleMask:STYLE_MASK_FULLSCREEN];
}
else
{
// Old Carbon-based way to make fullscreen window above dock and menu
// It's supported on 64-bit, but on 10.6 and later the following is preferred:
// [NSWindow setLevel:NSMainMenuWindowLevel + 1]
SetSystemUIMode(kUIModeAllHidden, 0);
SetStyleMask(STYLE_MASK_FULLSCREEN);
}
[m_window setLevel:LEVEL_FULLSCREEN];
[m_window setStyleMask:STYLE_MASK_FULLSCREEN];
[m_window setHidesOnDeactivate:YES];
}
@ -821,16 +769,8 @@ void CocoaVideo::SetWindowedMode(const int width, const int height)
if (m_fullscreen)
{
if (HasModernFullscreenAPI())
{
[m_window setLevel:LEVEL_WINDOWED];
[m_window setStyleMask:STYLE_MASK_WINDOWED];
}
else
{
SetSystemUIMode(kUIModeNormal, 0);
SetStyleMask(STYLE_MASK_WINDOWED);
}
[m_window setLevel:LEVEL_WINDOWED];
[m_window setStyleMask:STYLE_MASK_WINDOWED];
[m_window setHidesOnDeactivate:NO];
}
@ -851,11 +791,8 @@ void CocoaVideo::SetMode(const int width, const int height, const bool fullscree
return;
}
if (I_IsHiDPISupported())
{
NSOpenGLView* const glView = [m_window contentView];
[glView setWantsBestResolutionOpenGLSurface:hiDPI];
}
NSOpenGLView* const glView = [m_window contentView];
[glView setWantsBestResolutionOpenGLSurface:hiDPI];
if (fullscreen)
{
@ -1115,11 +1052,7 @@ bool CocoaFrameBuffer::IsFullscreen()
void CocoaFrameBuffer::SetVSync(bool vsync)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
const long value = vsync ? 1 : 0;
#else // 10.5 or newer
const GLint value = vsync ? 1 : 0;
#endif // prior to 10.5
[[NSOpenGLContext currentContext] setValues:&value
forParameter:NSOpenGLCPSwapInterval];
@ -1237,11 +1170,7 @@ bool SDLGLFB::IsFullscreen()
void SDLGLFB::SetVSync(bool vsync)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
const long value = vsync ? 1 : 0;
#else // 10.5 or newer
const GLint value = vsync ? 1 : 0;
#endif // prior to 10.5
[[NSOpenGLContext currentContext] setValues:&value
forParameter:NSOpenGLCPSwapInterval];
@ -1473,14 +1402,7 @@ CUSTOM_CVAR(Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, vid_hidpi, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (I_IsHiDPISupported())
{
CocoaVideo::UseHiDPI(self);
}
else if (0 != self)
{
self = 0;
}
CocoaVideo::UseHiDPI(self);
}

View file

@ -113,11 +113,8 @@ FConsoleWindow::FConsoleWindow()
[m_window center];
[m_window exitAppOnClose];
if (NSAppKitVersionNumber >= AppKit10_7)
{
// Do not allow fullscreen mode for this window
[m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
}
// Do not allow fullscreen mode for this window
[m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
[[m_window contentView] addSubview:m_scrollView];

View file

@ -102,6 +102,8 @@ FBasicStartupScreen::FBasicStartupScreen(int maxProgress, bool showBar)
consoleWindow.AddText(TEXTCOLOR_DARKGREEN "TEXTCOLOR_DARKGREEN\n" TEXTCOLOR_DARKRED "TEXTCOLOR_DARKRED\n");
consoleWindow.AddText(TEXTCOLOR_DARKBROWN "TEXTCOLOR_DARKBROWN\n" TEXTCOLOR_PURPLE "TEXTCOLOR_PURPLE\n");
consoleWindow.AddText(TEXTCOLOR_DARKGRAY "TEXTCOLOR_DARKGRAY\n" TEXTCOLOR_CYAN "TEXTCOLOR_CYAN\n");
consoleWindow.AddText(TEXTCOLOR_ICE "TEXTCOLOR_ICE\n" TEXTCOLOR_FIRE "TEXTCOLOR_FIRE\n");
consoleWindow.AddText(TEXTCOLOR_SAPPHIRE "TEXTCOLOR_SAPPHIRE\n" TEXTCOLOR_TEAL "TEXTCOLOR_TEAL\n");
consoleWindow.AddText(TEXTCOLOR_NORMAL "TEXTCOLOR_NORMAL\n" TEXTCOLOR_BOLD "TEXTCOLOR_BOLD\n");
consoleWindow.AddText(TEXTCOLOR_CHAT "TEXTCOLOR_CHAT\n" TEXTCOLOR_TEAMCHAT "TEXTCOLOR_TEAMCHAT\n");
consoleWindow.AddText("----------------------------------------------------------------\n");

View file

@ -30,7 +30,9 @@
#include <dirent.h>
#include <ctype.h>
#define __solaris__ (defined(__sun) || defined(__sun__) || defined(__SRV4) || defined(__srv4__))
#if defined(__sun) || defined(__sun__) || defined(__SRV4) || defined(__srv4__)
#define __solaris__ 1
#endif
#include "doomtype.h"

View file

@ -50,10 +50,6 @@
#include <wordexp.h>
#include <unistd.h>
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
// Missing type definition for 10.4 and earlier
typedef unsigned int NSUInteger;
#endif // prior to 10.5
CVAR(String, osx_additional_parameters, "", CVAR_ARCHIVE | CVAR_NOSET | CVAR_GLOBALCONFIG);
@ -68,10 +64,7 @@ enum
static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" };
// Class to convert the IWAD data into a form that Cocoa can use.
@interface IWADTableData : NSObject
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
<NSTableViewDataSource>
#endif
@interface IWADTableData : NSObject<NSTableViewDataSource>
{
NSMutableArray *data;
}

View file

@ -38,6 +38,7 @@
#include "templates.h"
#include "i_system.h"
#include "i_video.h"
#include "m_argv.h"
#include "v_video.h"
#include "v_pfx.h"
#include "stats.h"
@ -343,7 +344,7 @@ bool SDLGLVideo::SetResolution (int width, int height, int bits)
//
//==========================================================================
bool SDLGLVideo::SetupPixelFormat(bool allowsoftware, int multisample)
void SDLGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, const int *glver)
{
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
@ -365,24 +366,18 @@ bool SDLGLVideo::SetupPixelFormat(bool allowsoftware, int multisample)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
return true;
}
//==========================================================================
//
//
//
//==========================================================================
bool SDLGLVideo::InitHardware (bool allowsoftware, int multisample)
{
if (!SetupPixelFormat(allowsoftware, multisample))
else if (glver[0] > 2)
{
Printf ("R_OPENGL: Reverting to software mode...\n");
return false;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, glver[0]);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, glver[1]);
}
else
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
return true;
}
@ -391,32 +386,66 @@ bool SDLGLVideo::InitHardware (bool allowsoftware, int multisample)
SDLGLFB::SDLGLFB (void *, int width, int height, int, int, bool fullscreen, bool bgra)
: SDLBaseFB (width, height, bgra)
{
// NOTE: Core profiles were added with GL 3.2, so there's no sense trying
// to set core 3.1 or 3.0. We could try a forward-compatible context
// instead, but that would be too restrictive (w.r.t. shaders).
static const int glvers[][2] = {
{ 4, 5 }, { 4, 4 }, { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 },
{ 3, 3 }, { 3, 2 }, { 2, 0 },
{ 0, 0 },
};
int glveridx = 0;
int i;
m_Lock=0;
m_Lock=0;
UpdatePending = false;
if (!static_cast<SDLGLVideo*>(Video)->InitHardware(false, 0))
const char *version = Args->CheckValue("-glversion");
if (version != NULL)
{
vid_renderer = 0;
return;
double gl_version = strtod(version, NULL) + 0.01;
int vermaj = (int)gl_version;
int vermin = (int)(gl_version*10.0) % 10;
while (glvers[glveridx][0] > vermaj || (glvers[glveridx][0] == vermaj &&
glvers[glveridx][1] > vermin))
{
glveridx++;
if (glvers[glveridx][0] == 0)
{
glveridx = 0;
break;
}
}
}
FString caption;
caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
Screen = SDL_CreateWindow (caption,
SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter), SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
width, height, (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)|SDL_WINDOW_OPENGL);
if (Screen == NULL)
return;
for ( ; glvers[glveridx][0] > 0; ++glveridx)
{
static_cast<SDLGLVideo*>(Video)->SetupPixelFormat(false, 0, glvers[glveridx]);
GLContext = SDL_GL_CreateContext(Screen);
if (GLContext == NULL)
return;
Screen = SDL_CreateWindow (caption,
SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
width, height, (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)|SDL_WINDOW_OPENGL
);
if (Screen != NULL)
{
GLContext = SDL_GL_CreateContext(Screen);
if (GLContext != NULL)
{
m_supportsGamma = -1 != SDL_GetWindowGammaRamp(Screen,
m_origGamma[0], m_origGamma[1], m_origGamma[2]
);
return;
}
m_supportsGamma = -1 != SDL_GetWindowGammaRamp(Screen, m_origGamma[0], m_origGamma[1], m_origGamma[2]);
SDL_DestroyWindow(Screen);
Screen = NULL;
}
}
}
SDLGLFB::~SDLGLFB ()

View file

@ -27,8 +27,7 @@ class SDLGLVideo : public IVideo
bool NextMode (int *width, int *height, bool *letterbox);
bool SetResolution (int width, int height, int bits);
bool SetupPixelFormat(bool allowsoftware, int multisample);
bool InitHardware (bool allowsoftware, int multisample);
void SetupPixelFormat(bool allowsoftware, int multisample, const int *glver);
private:
int IteratorMode;

View file

@ -501,14 +501,6 @@ void SDLFB::SetVSync (bool vsync)
if (CGLContextObj context = CGLGetCurrentContext())
{
// Apply vsync for native backend only (where OpenGL context is set)
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
// Inconsistency between 10.4 and 10.5 SDKs:
// third argument of CGLSetParameter() is const long* on 10.4 and const GLint* on 10.5
// So, GLint typedef'ed to long instead of int to workaround this issue
typedef long GLint;
#endif // prior to 10.5
const GLint value = vsync ? 1 : 0;
CGLSetParameter(context, kCGLCPSwapInterval, &value);
}

View file

@ -24,6 +24,7 @@
#include <math.h>
#include "c_dispatch.h"
#include "c_cvars.h"
#include "v_video.h"
#define NUMSCALEMODES 5
@ -64,6 +65,8 @@ CUSTOM_CVAR(Int, vid_scalemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
self = 0;
}
CVAR(Bool, vid_cropaspect, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
bool ViewportLinearScale()
{
if (isOutOfBounds(vid_scalemode))
@ -72,17 +75,21 @@ bool ViewportLinearScale()
return (vid_scalefactor > 1.0) ? true : vScaleTable[vid_scalemode].isLinear;
}
int ViewportScaledWidth(int width)
int ViewportScaledWidth(int width, int height)
{
if (isOutOfBounds(vid_scalemode))
vid_scalemode = 0;
if (vid_cropaspect && height > 0)
width = ((float)width/height > ActiveRatio(width, height)) ? (int)(height * ActiveRatio(width, height)) : width;
return vScaleTable[vid_scalemode].GetScaledWidth((int)((float)width * vid_scalefactor));
}
int ViewportScaledHeight(int height)
int ViewportScaledHeight(int width, int height)
{
if (isOutOfBounds(vid_scalemode))
vid_scalemode = 0;
if (vid_cropaspect && height > 0)
height = ((float)width/height < ActiveRatio(width, height)) ? (int)(width / ActiveRatio(width, height)) : height;
return vScaleTable[vid_scalemode].GetScaledHeight((int)((float)height * vid_scalefactor));
}

View file

@ -25,7 +25,7 @@
#define __VIDEOSCALE_H__
EXTERN_CVAR (Int, vid_scalemode)
bool ViewportLinearScale();
int ViewportScaledWidth(int width);
int ViewportScaledHeight(int height);
int ViewportScaledWidth(int width, int height);
int ViewportScaledHeight(int width, int height);
bool ViewportIsScaled43();
#endif //__VIDEOSCALE_H__

View file

@ -312,7 +312,7 @@ bool FZipFile::Open(bool quiet)
}
// skip Directories
if (name[len - 1] == '/' && LittleLong(zip_fh->UncompressedSize) == 0)
if (name.IsEmpty() || (name.Back() == '/' && LittleLong(zip_fh->UncompressedSize) == 0))
{
skipped++;
continue;

View file

@ -321,11 +321,11 @@ void FScanner::PrepareScript ()
{
// The scanner requires the file to end with a '\n', so add one if
// it doesn't already.
if (ScriptBuffer.Len() == 0 || ScriptBuffer[ScriptBuffer.Len() - 1] != '\n')
if (ScriptBuffer.Len() == 0 || ScriptBuffer.Back() != '\n')
{
// If the last character in the buffer is a null character, change
// it to a newline. Otherwise, append a newline to the end.
if (ScriptBuffer.Len() > 0 && ScriptBuffer[ScriptBuffer.Len() - 1] == '\0')
if (ScriptBuffer.Len() > 0 && ScriptBuffer.Back() == '\0')
{
ScriptBuffer.LockBuffer()[ScriptBuffer.Len() - 1] = '\n';
ScriptBuffer.UnlockBuffer();

View file

@ -147,4 +147,5 @@ xx(TK_Offset, "'offset'")
xx(TK_Slow, "'slow'")
xx(TK_Bright, "'bright'")
xx(TK_Let, "'let'")
xx(TK_StaticConst, "'static const'")
#undef xx

View file

@ -2698,6 +2698,8 @@ FxExpression *FxMultiAssign::Resolve(FCompileContext &ctx)
auto varaccess = new FxLocalVariable(singlevar, ScriptPosition);
auto assignee = new FxTypeCast(varaccess, Base[i]->ValueType, false);
LocalVarContainer->Add(new FxAssign(Base[i], assignee, false));
// now temporary variable owns the current item
Base[i] = nullptr;
}
auto x = LocalVarContainer->Resolve(ctx);
LocalVarContainer = nullptr;
@ -3302,6 +3304,7 @@ FxExpression *FxPow::Resolve(FCompileContext& ctx)
right = (new FxFloatCast(right))->Resolve(ctx);
ABORT(right);
}
ValueType = TypeFloat64;
if (left->isConstant() && right->isConstant())
{
double v1 = static_cast<FxConstant *>(left)->GetValue().GetFloat();
@ -6463,6 +6466,12 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
}
}
}
else
{
ScriptPosition.Message(MSG_ERROR, "%s is not a member of %s", Identifier.GetChars(), ccls->TypeName.GetChars());
delete this;
return nullptr;
}
}
}

View file

@ -319,8 +319,6 @@ protected:
}
public:
FxExpression *CheckIntForName();
virtual ~FxExpression() {}
virtual FxExpression *Resolve(FCompileContext &ctx);
@ -2132,7 +2130,6 @@ class FxLocalVariableDeclaration : public FxExpression
public:
int StackOffset = -1;
int RegNum = -1;
bool constructed = false;
FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p);
~FxLocalVariableDeclaration();

View file

@ -113,9 +113,9 @@ class FStateDefinitions
FStateDefine *FindStateAddress(const char *name);
FState *FindState(const char *name);
FState *ResolveGotoLabel(AActor *actor, PClassActor *mytype, char *name);
FState *ResolveGotoLabel(PClassActor *mytype, char *name);
static void FixStatePointers(PClassActor *actor, TArray<FStateDefine> & list);
void ResolveGotoLabels(PClassActor *actor, AActor *defaults, TArray<FStateDefine> & list);
void ResolveGotoLabels(PClassActor *actor, TArray<FStateDefine> & list);
public:
FStateDefinitions()
@ -129,7 +129,7 @@ public:
void AddStateLabel(const char *statename);
int GetStateLabelIndex (FName statename);
void InstallStates(PClassActor *info, AActor *defaults);
int FinishStates(PClassActor *actor, AActor *defaults);
int FinishStates(PClassActor *actor);
void MakeStateDefines(const PClassActor *cls);
void AddStateDefines(const FStateLabels *list);

View file

@ -1051,7 +1051,7 @@ FString FStringFormat(VM_ARGS)
if (in_fmt)
{
if ((c >= '0' && c <= '9') ||
c == '-' || c == '+' || (c == ' ' && fmt_current[fmt_current.Len() - 1] != ' ') || c == '#' || c == '.')
c == '-' || c == '+' || (c == ' ' && fmt_current.Back() != ' ') || c == '#' || c == '.')
{
fmt_current += c;
}
@ -1264,7 +1264,8 @@ DEFINE_ACTION_FUNCTION(FStringStruct, LastIndexOf)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
PARAM_STRING(substr);
ACTION_RETURN_INT(self->LastIndexOf(substr));
PARAM_INT_DEF(endIndex);
ACTION_RETURN_INT(self->LastIndexOf(substr, endIndex));
}
DEFINE_ACTION_FUNCTION(FStringStruct, ToUpper)
@ -1293,3 +1294,13 @@ DEFINE_ACTION_FUNCTION(FStringStruct, ToDouble)
PARAM_SELF_STRUCT_PROLOGUE(FString);
ACTION_RETURN_FLOAT(self->ToDouble());
}
DEFINE_ACTION_FUNCTION(FStringStruct, Split)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
PARAM_POINTER(tokens, TArray<FString>);
PARAM_STRING(delimiter);
PARAM_INT_DEF(keepEmpty);
self->Split(*tokens, delimiter, static_cast<FString::EmptyTokenType>(keepEmpty));
return 0;
}

View file

@ -899,6 +899,11 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret)
ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", BC, reg.d[a]);
return 0;
}
else if (reg.d[a] < 0)
{
ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Negative current index = %i\n", reg.d[a]);
return 0;
}
NEXTOP;
OP(BOUND_K):
@ -908,6 +913,11 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret)
ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", konstd[BC], reg.d[a]);
return 0;
}
else if (reg.d[a] < 0)
{
ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Negative current index = %i\n", reg.d[a]);
return 0;
}
NEXTOP;
OP(BOUND_R):
@ -917,6 +927,11 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret)
ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", reg.d[B], reg.d[a]);
return 0;
}
else if (reg.d[a] < 0)
{
ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Negative current index = %i\n", reg.d[a]);
return 0;
}
NEXTOP;
OP(CONCAT):

View file

@ -122,9 +122,9 @@ xx(THROW, throw, THROW, NOP, 0, 0), // A == 0: Throw exception object pB
// A == 2: (pB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH
// A == 3: (pkB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH
// for A > 0, exception is stored in pC
xx(BOUND, bound, RII16, NOP, 0, 0), // if rA >= BC, throw exception
xx(BOUND_K, bound, LKI, NOP, 0, 0), // if rA >= const[BC], throw exception
xx(BOUND_R, bound, RIRI, NOP, 0, 0), // if rA >= rB, throw exception
xx(BOUND, bound, RII16, NOP, 0, 0), // if rA < 0 or rA >= BC, throw exception
xx(BOUND_K, bound, LKI, NOP, 0, 0), // if rA < 0 or rA >= const[BC], throw exception
xx(BOUND_R, bound, RIRI, NOP, 0, 0), // if rA < 0 or rA >= rB, throw exception
// String instructions.
xx(CONCAT, concat, RSRSRS, NOP, 0, 0), // sA = sB..sC

View file

@ -3495,7 +3495,9 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
case AST_IfStmt:
{
auto iff = static_cast<ZCC_IfStmt *>(ast);
return new FxIfStatement(ConvertNode(iff->Condition), ConvertNode(iff->TruePath), ConvertNode(iff->FalsePath), *ast);
FxExpression *const truePath = ConvertImplicitScopeNode(ast, iff->TruePath);
FxExpression *const falsePath = ConvertImplicitScopeNode(ast, iff->FalsePath);
return new FxIfStatement(ConvertNode(iff->Condition), truePath, falsePath, *ast);
}
case AST_IterationStmt:
@ -3504,7 +3506,8 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
if (iter->CheckAt == ZCC_IterationStmt::End)
{
assert(iter->LoopBumper == nullptr);
return new FxDoWhileLoop(ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopStatement), *ast);
FxExpression *const loop = ConvertImplicitScopeNode(ast, iter->LoopStatement);
return new FxDoWhileLoop(ConvertNode(iter->LoopCondition), loop, *ast);
}
else if (iter->LoopBumper != nullptr)
{
@ -3520,7 +3523,8 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
}
else
{
return new FxWhileLoop(ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopStatement), *ast);
FxExpression *const loop = ConvertImplicitScopeNode(ast, iter->LoopStatement);
return new FxWhileLoop(ConvertNode(iter->LoopCondition), loop, *ast);
}
}
@ -3584,6 +3588,45 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
return nullptr;
}
//==========================================================================
//
// Wrapper around ConvertNode() that adds a scope (a compound statement)
// when needed to avoid leaking of variable or contant to an outer scope:
//
// if (true) int i; else bool b[1];
// while (false) readonly<Actor> a;
// do static const float f[] = {0}; while (false);
//
// Accessing such variables outside of their statements is now an error
//
//==========================================================================
FxExpression *ZCCCompiler::ConvertImplicitScopeNode(ZCC_TreeNode *node, ZCC_Statement *nested)
{
assert(nullptr != node);
if (nullptr == nested)
{
return nullptr;
}
FxExpression *nestedExpr = ConvertNode(nested);
assert(nullptr != nestedExpr);
const EZCCTreeNodeType nestedType = nested->NodeType;
const bool needScope = AST_LocalVarStmt == nestedType || AST_StaticArrayStatement == nestedType;
if (needScope)
{
FxCompoundStatement *implicitCompound = new FxCompoundStatement(*node);
implicitCompound->Add(nestedExpr);
nestedExpr = implicitCompound;
}
return nestedExpr;
}
FArgumentList &ZCCCompiler::ConvertNodeList(FArgumentList &args, ZCC_TreeNode *head)
{

View file

@ -145,6 +145,7 @@ private:
FxExpression *ConvertAST(PContainerType *cclass, ZCC_TreeNode *ast);
FxExpression *ConvertNode(ZCC_TreeNode *node);
FxExpression *ConvertImplicitScopeNode(ZCC_TreeNode *node, ZCC_Statement *nested);
FArgumentList &ConvertNodeList(FArgumentList &, ZCC_TreeNode *head);
DObject *Outer;

View file

@ -211,6 +211,7 @@ static void InitTokenMap()
TOKENDEF2(TK_Color, ZCC_COLOR, NAME_Color);
TOKENDEF2(TK_Sound, ZCC_SOUND, NAME_Sound);
TOKENDEF2(TK_Let, ZCC_LET, NAME_let);
TOKENDEF2(TK_StaticConst, ZCC_STATICCONST,NAME_Staticconst);
TOKENDEF (TK_Identifier, ZCC_IDENTIFIER);
TOKENDEF (TK_StringConst, ZCC_STRCONST);

View file

@ -59,7 +59,6 @@ extern void ChildSigHandler (int signum);
#include "s_sound.h"
#include "m_swap.h"
#include "i_cd.h"
#include "tempfiles.h"
#include "templates.h"
#include "stats.h"
#include "timidity/timidity.h"

View file

@ -1,5 +1,4 @@
#include "tempfiles.h"
#include "oplsynth/opl_mus_player.h"
#include "c_cvars.h"
#include "mus2midi.h"

View file

@ -42,13 +42,16 @@
#include "cmdlib.h"
#include "templates.h"
#include "version.h"
#include "tmpfileplus.h"
#ifndef _WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#ifndef __OpenBSD__
#include <wordexp.h>
#endif
#include <glob.h>
#include <signal.h>
@ -79,13 +82,12 @@ public:
protected:
bool LaunchTimidity();
FTempFileName DiskName;
char* DiskName;
#ifdef _WIN32
HANDLE ReadWavePipe;
HANDLE WriteWavePipe;
HANDLE ChildProcess;
FString CommandLine;
size_t LoopPos;
bool Validated;
bool ValidateTimidity();
#else // _WIN32
@ -164,7 +166,7 @@ CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
//==========================================================================
TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
: DiskName("zmid"),
: DiskName(nullptr),
#ifdef _WIN32
ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE),
ChildProcess(INVALID_HANDLE_VALUE),
@ -192,12 +194,6 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
CommandLine += "\" ";
}
#endif
if (DiskName == NULL)
{
Printf(PRINT_BOLD, "Could not create temp music file\n");
return;
}
}
//==========================================================================
@ -208,6 +204,12 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
TimidityPPMIDIDevice::~TimidityPPMIDIDevice ()
{
if (nullptr != DiskName)
{
remove(DiskName);
free(DiskName);
}
#if _WIN32
if (WriteWavePipe != INVALID_HANDLE_VALUE)
{
@ -250,17 +252,12 @@ bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping)
return false;
}
// Tell TiMidity++ whether it should loop or not
#ifdef _WIN32
CommandLine.LockBuffer()[LoopPos] = looping ? 'l' : ' ';
CommandLine.UnlockBuffer();
#endif
Looping = looping;
// Write MIDI song to temporary file
song->CreateSMF(midi, looping ? 0 : 1);
f = fopen(DiskName, "wb");
f = tmpfileplus(nullptr, "zmid", &DiskName, 1);
if (f == NULL)
{
Printf(PRINT_BOLD, "Could not open temp music file\n");
@ -273,6 +270,16 @@ bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping)
{
Printf(PRINT_BOLD, "Could not write temp music file\n");
}
#ifdef _WIN32
CommandLine.AppendFormat("-o - -Ors%c%c%c -id%c %s",
timidity_stereo ? 'S' : 'M',
timidity_8bit ? '8' : '1',
timidity_byteswap ? 'x' : ' ',
looping ? 'l' : ' ',
DiskName);
#endif
return false;
}
@ -340,20 +347,6 @@ int TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata)
}
}
#ifdef _WIN32
CommandLine += "-o - -Ors";
CommandLine += timidity_stereo ? 'S' : 'M';
CommandLine += timidity_8bit ? '8' : '1';
if (timidity_byteswap)
{
CommandLine += 'x';
}
LoopPos = CommandLine.Len() + 4;
CommandLine += " -idl ";
CommandLine += DiskName.GetName();
#endif
return 0;
}
@ -461,12 +454,12 @@ bool TimidityPPMIDIDevice::ValidateTimidity()
bool TimidityPPMIDIDevice::LaunchTimidity ()
{
#ifdef _WIN32
if (CommandLine.IsEmpty())
if (ExeName.IsEmpty() || nullptr == DiskName)
{
return false;
}
#ifdef _WIN32
DPrintf (DMSG_NOTIFY, "cmd: \x1cG%s\n", CommandLine.GetChars());
STARTUPINFO startup = { sizeof(startup), };
@ -514,11 +507,6 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
}
return false;
#else
if (ExeName.IsEmpty())
{
return false;
}
if (WavePipe[0] != -1 && WavePipe[1] == -1 && Stream != NULL)
{
// Timidity was previously launched, so the write end of the pipe
@ -533,7 +521,9 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
}
int forkres;
#ifndef __OpenBSD__
wordexp_t words;
#endif
glob_t glb;
// Get timidity executable path
@ -541,8 +531,10 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
glob(ExeName.GetChars(), 0, NULL, &glb);
if(glb.gl_pathc != 0)
exename = glb.gl_pathv[0];
#ifndef __OpenBSD__
// Get user-defined extra args
wordexp(timidity_extargs, &words, WRDE_NOCMD);
#endif
std::string chorusarg = std::string("-EFchorus=") + *timidity_chorus;
std::string reverbarg = std::string("-EFreverb=") + *timidity_reverb;
@ -557,8 +549,10 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
std::vector<const char*> arglist;
arglist.push_back(exename);
#ifndef __OpenBSD__
for(size_t i = 0;i < words.we_wordc;i++)
arglist.push_back(words.we_wordv[i]);
#endif
if(**timidity_config != '\0')
{
arglist.push_back("-c");
@ -571,7 +565,7 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
arglist.push_back("-");
arglist.push_back(outmodearg.c_str());
arglist.push_back(ifacearg.c_str());
arglist.push_back(DiskName.GetName());
arglist.push_back(DiskName);
DPrintf(DMSG_NOTIFY, "Timidity EXE: \x1cG%s\n", exename);
int i = 1;
@ -611,7 +605,9 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
}*/
}
#ifndef __OpenBSD__
wordfree(&words);
#endif
globfree (&glb);
return ChildProcess != -1;
#endif // _WIN32

View file

@ -57,7 +57,6 @@
#include "i_module.h"
#include "i_music.h"
#include "i_musicinterns.h"
#include "tempfiles.h"
#include "cmdlib.h"
FModule OpenALModule{"OpenAL"};
@ -72,6 +71,8 @@ CVAR (String, snd_alresampler, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
#define OPENALLIB "openal32.dll"
#elif defined(__APPLE__)
#define OPENALLIB "OpenAL.framework/OpenAL"
#elif defined(__OpenBSD__)
#define OPENALLIB "libopenal.so"
#else
#define OPENALLIB "libopenal.so.1"
#endif
@ -273,6 +274,7 @@ class OpenALSoundStream : public SoundStream
alSourcef(Source, AL_MAX_GAIN, 1.f);
alSourcef(Source, AL_GAIN, 1.f);
alSourcef(Source, AL_PITCH, 1.f);
alSourcef(Source, AL_DOPPLER_FACTOR, 0.f);
alSourcef(Source, AL_ROLLOFF_FACTOR, 0.f);
alSourcef(Source, AL_SEC_OFFSET, 0.f);
alSourcei(Source, AL_SOURCE_RELATIVE, AL_TRUE);
@ -821,8 +823,15 @@ OpenALSoundRenderer::OpenALSoundRenderer()
AL.SOFT_source_resampler = !!alIsExtensionPresent("AL_SOFT_source_resampler");
AL.SOFT_source_spatialize = !!alIsExtensionPresent("AL_SOFT_source_spatialize");
alDopplerFactor(0.5f);
alSpeedOfSound(343.3f * 96.0f);
// Speed of sound is in units per second. Presuming we want to simulate a
// typical speed of sound of 343.3 meters per second, multiply it by the
// units per meter scale (32?), and set the meters per unit to the scale's
// reciprocal. It's important to set these correctly for both doppler
// effects and reverb.
alSpeedOfSound(343.3f * 32.0f);
if(ALC.EXT_EFX)
alListenerf(AL_METERS_PER_UNIT, 1.0f/32.0f);
alDistanceModel(AL_INVERSE_DISTANCE);
if(AL.EXT_source_distance_model)
alEnable(AL_SOURCE_DISTANCE_MODEL);
@ -1568,6 +1577,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int
alSourcef(source, AL_REFERENCE_DISTANCE, 1.f);
alSourcef(source, AL_MAX_DISTANCE, 1000.f);
alSourcef(source, AL_DOPPLER_FACTOR, 0.f);
alSourcef(source, AL_ROLLOFF_FACTOR, 0.f);
alSourcef(source, AL_MAX_GAIN, SfxVolume);
alSourcef(source, AL_GAIN, SfxVolume*vol);
@ -1778,6 +1788,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener
}
alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]);
alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f);
alSourcef(source, AL_DOPPLER_FACTOR, 0.f);
alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE);

View file

@ -39,6 +39,7 @@
#include <string.h>
#include <new>
#include <utility>
#include <iterator>
#if !defined(_WIN32)
#include <inttypes.h> // for intptr_t
@ -48,13 +49,37 @@
#include "m_alloc.h"
template<typename T> class TIterator
template<typename T> class TIterator : public std::iterator<std::random_access_iterator_tag, T>
{
public:
typedef typename TIterator::value_type value_type;
typedef typename TIterator::difference_type difference_type;
typedef typename TIterator::pointer pointer;
typedef typename TIterator::reference reference;
typedef typename TIterator::iterator_category iterator_category;
TIterator(T* ptr = nullptr) { m_ptr = ptr; }
bool operator==(const TIterator<T>& other) const { return (m_ptr == other.m_ptr); }
bool operator!=(const TIterator<T>& other) const { return (m_ptr != other.m_ptr); }
TIterator<T> &operator++() { ++m_ptr; return (*this); }
// Comparison operators
bool operator==(const TIterator &other) const { return m_ptr == other.m_ptr; }
bool operator!=(const TIterator &other) const { return m_ptr != other.m_ptr; }
bool operator< (const TIterator &other) const { return m_ptr < other.m_ptr; }
bool operator<=(const TIterator &other) const { return m_ptr <= other.m_ptr; }
bool operator> (const TIterator &other) const { return m_ptr > other.m_ptr; }
bool operator>=(const TIterator &other) const { return m_ptr >= other.m_ptr; }
// Arithmetic operators
TIterator &operator++() { ++m_ptr; return *this; }
TIterator operator++(int) { pointer tmp = m_ptr; ++*this; return TIterator(tmp); }
TIterator &operator--() { --m_ptr; return *this; }
TIterator operator--(int) { pointer tmp = m_ptr; --*this; return TIterator(tmp); }
TIterator &operator+=(difference_type offset) { m_ptr += offset; return *this; }
TIterator operator+(difference_type offset) const { return TIterator(m_ptr + offset); }
friend TIterator operator+(difference_type offset, const TIterator &other) { return TIterator(offset + other.m_ptr); }
TIterator &operator-=(difference_type offset) { m_ptr -= offset; return *this; }
TIterator operator-(difference_type offset) const { return TIterator(m_ptr - offset); }
difference_type operator-(const TIterator &other) const { return m_ptr - other.m_ptr; }
T &operator*() { return *m_ptr; }
const T &operator*() const { return *m_ptr; }
T* operator->() { return m_ptr; }
@ -132,10 +157,10 @@ public:
Count = 0;
Array = NULL;
}
TArray (int max)
TArray (int max, bool reserve = false)
{
Most = max;
Count = 0;
Count = reserve? max : 0;
Array = (T *)M_Malloc (sizeof(T)*max);
}
TArray (const TArray<T,TT> &other)

View file

@ -1,57 +0,0 @@
/*
** tempfiles.cpp
** Temporary name generator. Deletes the temporary file when deconstructed.
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <stdio.h>
#include <stdlib.h>
#include "tempfiles.h"
FTempFileName::FTempFileName (const char *prefix)
{
// Under Linux, ld will complain that tempnam is dangerous, and
// mkstemp should be used instead. However, there is no mkstemp
// under VC++, and even if there was, I still need to know the
// file name so that it can be used as input to Timidity.
Name = tempnam (NULL, prefix);
}
FTempFileName::~FTempFileName ()
{
if (Name != NULL)
{
remove (Name);
free (Name);
Name = NULL;
}
}

View file

@ -1,61 +0,0 @@
/*
** tempfiles.h
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#ifndef __TEMPFILES_H__
#define __TEMPFILES_H__
#ifdef _MSC_VER
#pragma once
#endif
#include <stdlib.h>
// Returns a file name suitable for use as a temp file.
// If you create a file with this name (and presumably you
// will), it will be deleted automatically by this class's
// destructor.
class FTempFileName
{
public:
FTempFileName (const char *prefix=NULL);
~FTempFileName ();
operator const char * () { return Name; }
const char * GetName () const { return Name; }
private:
char *Name;
};
#endif //__TEMPFILES_H__

View file

@ -1202,6 +1202,20 @@ int FTextureManager::CountLumpTextures (int lumpnum)
//
//==========================================================================
DEFINE_ACTION_FUNCTION(_TexMan, GetName)
{
PARAM_PROLOGUE;
PARAM_INT(texid);
const FTexture* const tex = TexMan.ByIndex(texid);
ACTION_RETURN_STRING(nullptr == tex ? FString() : tex->Name);
}
//==========================================================================
//
//
//
//==========================================================================
DEFINE_ACTION_FUNCTION(_TexMan, GetSize)
{
PARAM_PROLOGUE;

337
src/tmpfileplus.c Normal file
View file

@ -0,0 +1,337 @@
/* $Id: tmpfileplus.c $ */
/*
* $Date: 2016-06-01 03:31Z $
* $Revision: 2.0.0 $
* $Author: dai $
*/
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2012-16 David Ireland, DI Management Services Pty Ltd
* <http://www.di-mgt.com.au/contact/>.
*/
/*
* NAME
* tmpfileplus - create a unique temporary file
*
* SYNOPSIS
* FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep)
*
* DESCRIPTION
* The tmpfileplus() function opens a unique temporary file in binary
* read/write (w+b) mode. The file is opened with the O_EXCL flag,
* guaranteeing that the caller is the only user. The filename will consist
* of the string given by `prefix` followed by 10 random characters. If
* `prefix` is NULL, then the string "tmp." will be used instead. The file
* will be created in an appropriate directory chosen by the first
* successful attempt in the following sequence:
*
* a) The directory given by the `dir` argument (so the caller can specify
* a secure directory to take precedence).
*
* b) The directory name in the environment variables:
*
* (i) "TMP" [Windows only]
* (ii) "TEMP" [Windows only]
* (iii) "TMPDIR" [Unix only]
*
* c) `P_tmpdir` as defined in <stdio.h> [Unix only] (in Windows, this is
* usually "\", which is no good).
*
* d) The current working directory.
*
* If a file cannot be created in any of the above directories, then the
* function fails and NULL is returned.
*
* If the argument `pathname` is not a null pointer, then it will point to
* the full pathname of the file. The pathname is allocated using `malloc`
* and therefore should be freed by `free`.
*
* If `keep` is nonzero and `pathname` is not a null pointer, then the file
* will be kept after it is closed. Otherwise the file will be
* automatically deleted when it is closed or the program terminates.
*
*
* RETURN VALUE
* The tmpfileplus() function returns a pointer to the open file stream,
* or NULL if a unique file cannot be opened.
*
*
* ERRORS
* ENOMEM Not enough memory to allocate filename.
*
*/
/* ADDED IN v2.0 */
/*
* NAME
* tmpfileplus_f - create a unique temporary file with filename stored in a fixed-length buffer
*
* SYNOPSIS
* FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep);
*
* DESCRIPTION
* Same as tmpfileplus() except receives filename in a fixed-length buffer. No allocated memory to free.
* ERRORS
* E2BIG Resulting filename is too big for the buffer `pathnamebuf`.
*/
#include "tmpfileplus.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
/* Non-ANSI include files that seem to work in both MSVC and Linux */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef _WIN32
#include <io.h>
#endif
#ifdef _WIN32
/* MSVC nags to enforce ISO C++ conformant function names with leading "_",
* so we define our own function names to avoid whingeing compilers...
*/
#define OPEN_ _open
#define FDOPEN_ _fdopen
#else
#define OPEN_ open
#define FDOPEN_ fdopen
#endif
/* DEBUGGING STUFF */
#if defined(_DEBUG) && defined(SHOW_DPRINTF)
#define DPRINTF1(s, a1) printf(s, a1)
#else
#define DPRINTF1(s, a1)
#endif
#ifdef _WIN32
#define FILE_SEPARATOR "\\"
#else
#define FILE_SEPARATOR "/"
#endif
#define RANDCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
#define NRANDCHARS (sizeof(RANDCHARS) - 1)
/** Replace each byte in string s with a random character from TEMPCHARS */
static char *set_randpart(char *s)
{
size_t i;
unsigned int r;
static unsigned int seed; /* NB static */
if (seed == 0)
{ /* First time set our seed using current time and clock */
seed = ((unsigned)time(NULL)<<8) ^ (unsigned)clock();
}
srand(seed++);
for (i = 0; i < strlen(s); i++)
{
r = rand() % NRANDCHARS;
s[i] = (RANDCHARS)[r];
}
return s;
}
/** Return 1 if path is a valid directory otherwise 0 */
static int is_valid_dir(const char *path)
{
struct stat st;
if ((stat(path, &st) == 0) && (st.st_mode & S_IFDIR))
return 1;
return 0;
}
/** Call getenv and save a copy in buf */
static char *getenv_save(const char *varname, char *buf, size_t bufsize)
{
char *ptr = getenv(varname);
buf[0] = '\0';
if (ptr)
{
strncpy(buf, ptr, bufsize);
buf[bufsize-1] = '\0';
return buf;
}
return NULL;
}
/**
* Try and create a randomly-named file in directory `tmpdir`.
* If successful, allocate memory and set `tmpname_ptr` to full filepath, and return file pointer;
* otherwise return NULL.
* If `keep` is zero then create the file as temporary and it should not exist once closed.
*/
static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmpname_ptr, int keep)
/* PRE:
* pfx is not NULL and points to a valid null-terminated string
* tmpname_ptr is not NULL.
*/
{
FILE *fp;
int fd;
char randpart[] = "1234567890";
size_t lentempname;
int i;
char *tmpname = NULL;
int oflag, pmode;
/* In Windows, we use the _O_TEMPORARY flag with `open` to ensure the file is deleted when closed.
* In Unix, we use the unlink function after opening the file. (This does not work in Windows,
* which does not allow an open file to be unlinked.)
*/
#ifdef _WIN32
/* MSVC flags */
oflag = _O_BINARY|_O_CREAT|_O_RDWR;
if (!keep)
oflag |= _O_TEMPORARY;
pmode = _S_IREAD | _S_IWRITE;
#else
/* Standard POSIX flags */
oflag = O_CREAT|O_RDWR;
pmode = S_IRUSR|S_IWUSR;
#endif
if (!tmpdir || !is_valid_dir(tmpdir)) {
errno = ENOENT;
return NULL;
}
lentempname = strlen(tmpdir) + strlen(FILE_SEPARATOR) + strlen(pfx) + strlen(randpart);
DPRINTF1("lentempname=%d\n", lentempname);
tmpname = malloc(lentempname + 1);
if (!tmpname)
{
errno = ENOMEM;
return NULL;
}
/* If we don't manage to create a file after 10 goes, there is something wrong... */
for (i = 0; i < 10; i++)
{
sprintf(tmpname, "%s%s%s%s", tmpdir, FILE_SEPARATOR, pfx, set_randpart(randpart));
DPRINTF1("[%s]\n", tmpname);
fd = OPEN_(tmpname, oflag, pmode);
if (fd != -1) break;
}
DPRINTF1("strlen(tmpname)=%d\n", strlen(tmpname));
if (fd != -1)
{ /* Success, so return user a proper ANSI C file pointer */
fp = FDOPEN_(fd, "w+b");
errno = 0;
#ifndef _WIN32
/* [Unix only] And make sure the file will be deleted once closed */
if (!keep) remove(tmpname);
#endif
}
else
{ /* We failed */
fp = NULL;
}
if (!fp)
{
free(tmpname);
tmpname = NULL;
}
*tmpname_ptr = tmpname;
return fp;
}
/**********************/
/* EXPORTED FUNCTIONS */
/**********************/
FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep)
{
FILE *fp = NULL;
char *tmpname = NULL;
char *tmpdir = NULL;
const char *pfx = (prefix ? prefix : "tmp.");
char *tempdirs[12] = { 0 };
char env1[FILENAME_MAX+1] = { 0 };
char env2[FILENAME_MAX+1] = { 0 };
char env3[FILENAME_MAX+1] = { 0 };
int ntempdirs = 0;
int i;
/* Set up a list of temp directories we will try in order */
i = 0;
tempdirs[i++] = (char *)dir;
#ifdef _WIN32
tempdirs[i++] = getenv_save("TMP", env1, sizeof(env1));
tempdirs[i++] = getenv_save("TEMP", env2, sizeof(env2));
#else
tempdirs[i++] = getenv_save("TMPDIR", env3, sizeof(env3));
tempdirs[i++] = P_tmpdir;
#endif
tempdirs[i++] = ".";
ntempdirs = i;
errno = 0;
/* Work through list we set up before, and break once we are successful */
for (i = 0; i < ntempdirs; i++)
{
tmpdir = tempdirs[i];
DPRINTF1("Trying tmpdir=[%s]\n", tmpdir);
fp = mktempfile_internal(tmpdir, pfx, &tmpname, keep);
if (fp) break;
}
/* If we succeeded and the user passed a pointer, set it to the alloc'd pathname: the user must free this */
if (fp && pathname)
*pathname = tmpname;
else /* Otherwise, free the alloc'd memory */
free(tmpname);
return fp;
}
/* Same as tmpfileplus() but with fixed length buffer for output filename and no memory allocation */
FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep)
{
char *tmpbuf = NULL;
FILE *fp;
/* If no buffer provided, do the normal way */
if (!pathnamebuf || (int)pathsize <= 0) {
return tmpfileplus(dir, prefix, NULL, keep);
}
/* Call with a temporary buffer */
fp = tmpfileplus(dir, prefix, &tmpbuf, keep);
if (fp && strlen(tmpbuf) > pathsize - 1) {
/* Succeeded but not enough room in output buffer, so clean up and return an error */
pathnamebuf[0] = 0;
fclose(fp);
if (keep) remove(tmpbuf);
free(tmpbuf);
errno = E2BIG;
return NULL;
}
/* Copy name into buffer */
strcpy(pathnamebuf, tmpbuf);
free(tmpbuf);
return fp;
}

61
src/tmpfileplus.h Normal file
View file

@ -0,0 +1,61 @@
/* $Id: tmpfileplus.h $ */
/*
* $Date: 2016-06-01 03:31Z $
* $Revision: 2.0.0 $
* $Author: dai $
*/
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2012-16 David Ireland, DI Management Services Pty Ltd
* <http://www.di-mgt.com.au/contact/>.
*/
#if _MSC_VER > 1000
#pragma once
#endif
#ifndef TMPFILEPLUS_H_
#define TMPFILEPLUS_H_
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Create a unique temporary file.
@param dir (optional) directory to create file. If NULL use default TMP directory.
@param prefix (optional) prefix for file name. If NULL use "tmp.".
@param pathname (optional) pointer to a buffer to receive the temp filename.
Allocated using `malloc()`; user to free. Ignored if NULL.
@param keep If `keep` is nonzero and `pathname` is not NULL, then keep the file after closing.
Otherwise file is automatically deleted when closed.
@return Pointer to stream opened in binary read/write (w+b) mode, or a null pointer on error.
@exception ENOMEM Not enough memory to allocate filename.
*/
FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep);
/** Create a unique temporary file with filename stored in a fixed-length buffer.
@param dir (optional) directory to create file. If NULL use default directory.
@param prefix (optional) prefix for file name. If NULL use "tmp.".
@param pathnamebuf (optional) buffer to receive full pathname of temporary file. Ignored if NULL.
@param pathsize Size of buffer to receive filename and its terminating null character.
@param keep If `keep` is nonzero and `pathname` is not NULL, then keep the file after closing.
Otherwise file is automatically deleted when closed.
@return Pointer to stream opened in binary read/write (w+b) mode, or a null pointer on error.
@exception E2BIG Resulting filename is too big for the buffer `pathnamebuf`.
*/
FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep);
#define TMPFILE_KEEP 1
#ifdef __cplusplus
}
#endif
#endif /* end TMPFILEPLUS_H_ */

View file

@ -2361,7 +2361,7 @@ void V_InitFontColors ()
// which are used by the menu. So we have no choice but to skip this lump so that
// all colors work properly.
// The text colors should be the end user's choice anyway.
if (Wads.GetLumpFile(lump) == 1) continue;
if (Wads.GetLumpFile(lump) == Wads.GetIwadNum()) continue;
}
FScanner sc(lump);
while (sc.GetString())
@ -2666,7 +2666,7 @@ EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int
}
else // Incomplete!
{
color_value = ch - (*ch == '\0');
color_value = ch - (newcolor == '\0');
return CR_UNDEFINED;
}
color_value = ch;
@ -2772,4 +2772,4 @@ DEFINE_ACTION_FUNCTION(FFont, GetCursor)
{
PARAM_SELF_STRUCT_PROLOGUE(FFont);
ACTION_RETURN_STRING(FString(self->GetCursor()));
}
}

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