Merge ../qzdoom

# Conflicts:
#	CMakeLists.txt
#	src/CMakeLists.txt
#	src/posix/sdl/hardware.cpp
#	src/r_3dfloors.cpp
#	src/r_3dfloors.h
#	src/r_bsp.cpp
#	src/r_bsp.h
#	src/r_draw.cpp
#	src/r_draw.h
#	src/r_local.h
#	src/r_main.cpp
#	src/r_main.h
#	src/r_plane.cpp
#	src/r_plane.h
#	src/r_segs.cpp
#	src/r_segs.h
#	src/r_swrenderer.cpp
#	src/r_swrenderer.h
#	src/r_things.cpp
#	src/r_things.h
#	src/win32/fb_d3d9.cpp
#	src/win32/hardware.cpp
#	src/win32/zdoom.rc
This commit is contained in:
Rachael Alexanderson 2017-03-06 22:25:22 -05:00
commit 0f1b39f138
250 changed files with 52711 additions and 21351 deletions

3
.gitignore vendored
View file

@ -47,3 +47,6 @@
/build_vc2015-32
/build_vc2015-64
/build
/llvm
/src/r_drawersasm.obj
/src/r_drawersasm.o

73
.travis.yml Normal file
View file

@ -0,0 +1,73 @@
language: c++
dist: trusty
sudo: required
matrix:
include:
- os: osx
osx_image: xcode8.2
env:
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_OSX_DEPLOYMENT_TARGET=10.7"
- os: osx
osx_image: xcode8.2
env:
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 -DFORCE_INTERNAL_ZLIB=YES -DFORCE_INTERNAL_JPEG=YES -DFORCE_INTERNAL_BZIP2=YES -DFORCE_INTERNAL_GME=YES"
- os: linux
compiler: gcc
env:
- GCC_VERSION=5
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- kubuntu-backports
packages:
- g++-5
- libsdl2-dev
- libgme-dev
- libopenal-dev
- libmpg123-dev
- libsndfile-dev
- libfluidsynth-dev
- libgtk-3-dev
- os: linux
compiler: clang
env:
- CLANG_VERSION=3.9
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=RelWithDebInfo -DDYN_OPENAL=NO -DDYN_FLUIDSYNTH=NO"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-3.9
- kubuntu-backports
packages:
- clang-3.9
- libstdc++-5-dev
- libsdl2-dev
- libgme-dev
- libopenal-dev
- libmpg123-dev
- libsndfile-dev
- libfluidsynth-dev
- libgtk-3-dev
before_install:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; brew install mpg123 libsndfile fluidsynth; fi
- if [ -n "$GCC_VERSION" ]; then export CC="gcc-${GCC_VERSION}" CXX="g++-${GCC_VERSION}"; fi
- if [ -n "$CLANG_VERSION" ]; then export CC="clang-${CLANG_VERSION}" CXX="clang++-${CLANG_VERSION}"; fi
- $CC --version
- $CXX --version
script:
- mkdir build
- cd build
- cmake ${CMAKE_OPTIONS} ..
- make -j2
notifications:
email: false

View file

@ -1,5 +1,5 @@
cmake_minimum_required( VERSION 2.8.7 )
project(GZDoom)
project(QZDoom)
if( COMMAND cmake_policy )
if( POLICY CMP0011 )
@ -122,7 +122,7 @@ IF( NOT CMAKE_BUILD_TYPE )
ENDIF()
set( ZDOOM_OUTPUT_DIR ${CMAKE_BINARY_DIR} CACHE PATH "Directory where zdoom.pk3 and the executable will be created." )
set( ZDOOM_EXE_NAME "gzdoom" CACHE FILEPATH "Name of the executable to create" )
set( ZDOOM_EXE_NAME "qzdoom" CACHE FILEPATH "Name of the executable to create" )
if( MSVC )
# Allow the user to use ZDOOM_OUTPUT_DIR as a single release point.
# Use zdoom, zdoomd, zdoom64, and zdoomd64 for the binary names
@ -173,20 +173,23 @@ if( MSVC )
# Disable run-time type information
set( ALL_C_FLAGS "/GF /Gy /GR-" )
if( CMAKE_SIZEOF_VOID_P MATCHES "4")
# SSE2 option (to allow x87 in 32 bit and disallow extended feature sets which have not yet been checked for precision)
option (ZDOOM_USE_SSE2 "Use SSE2 instruction set")
if (ZDOOM_USE_SSE2)
set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2")
else ()
if (MSVC_VERSION GREATER 1699)
# On Visual C++ 2012 and later SSE2 is the default, so we need to switch it off explicitly
set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:IA32")
endif ()
endif ()
else()
set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2")
endif()
# Use SSE 2 as minimum always as the true color drawers needs it for __vectorcall
set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2")
# if( CMAKE_SIZEOF_VOID_P MATCHES "4")
# # SSE2 option (to allow x87 in 32 bit and disallow extended feature sets which have not yet been checked for precision)
# option (ZDOOM_USE_SSE2 "Use SSE2 instruction set")
# if (ZDOOM_USE_SSE2)
# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2")
# else ()
# if (MSVC_VERSION GREATER 1699)
# # On Visual C++ 2012 and later SSE2 is the default, so we need to switch it off explicitly
# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:IA32")
# endif ()
# endif ()
# else()
# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2")
# endif()
# Avoid CRT DLL dependancies in release builds, optionally generate assembly output for checking crash locations.
option( ZDOOM_GENERATE_ASM "Generate assembly output." OFF )

View file

@ -543,6 +543,7 @@ if( HAVE_MMX )
PROPERTIES COMPILE_FLAGS "-mmmx" )
endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
endif( HAVE_MMX )
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h
COMMAND lemon -C${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y
DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y )
@ -605,6 +606,19 @@ file( GLOB HEADER_FILES
scripting/zscript/*.h
scripting/vm/*.h
xlat/*.h
swrenderer/*.h
swrenderer/drawers/*.h
swrenderer/scene/*.h
swrenderer/segments/*.h
swrenderer/line/*.h
swrenderer/plane/*.h
swrenderer/things/*.h
swrenderer/viewport/*.h
polyrenderer/*.h
polyrenderer/math/*.h
polyrenderer/drawers/*.h
polyrenderer/drawers/*.php
polyrenderer/scene/*.h
gl/*.h
gl/api/*.h
gl/data/*.h
@ -639,16 +653,67 @@ set( NOT_COMPILED_SOURCE_FILES
)
set( FASTMATH_PCH_SOURCES
r_swrenderer.cpp
r_3dfloors.cpp
r_bsp.cpp
r_draw.cpp
r_drawt.cpp
r_main.cpp
r_plane.cpp
r_segs.cpp
swrenderer/r_swcanvas.cpp
swrenderer/r_swrenderer.cpp
swrenderer/r_memory.cpp
swrenderer/r_renderthread.cpp
swrenderer/drawers/r_draw.cpp
swrenderer/drawers/r_draw_pal.cpp
swrenderer/drawers/r_draw_rgba.cpp
swrenderer/drawers/r_thread.cpp
swrenderer/scene/r_3dfloors.cpp
swrenderer/scene/r_light.cpp
swrenderer/scene/r_opaque_pass.cpp
swrenderer/scene/r_portal.cpp
swrenderer/scene/r_scene.cpp
swrenderer/scene/r_translucent_pass.cpp
swrenderer/viewport/r_drawerargs.cpp
swrenderer/viewport/r_skydrawer.cpp
swrenderer/viewport/r_spandrawer.cpp
swrenderer/viewport/r_spritedrawer.cpp
swrenderer/viewport/r_viewport.cpp
swrenderer/viewport/r_walldrawer.cpp
swrenderer/line/r_line.cpp
swrenderer/line/r_walldraw.cpp
swrenderer/line/r_wallsetup.cpp
swrenderer/line/r_fogboundary.cpp
swrenderer/line/r_renderdrawsegment.cpp
swrenderer/segments/r_clipsegment.cpp
swrenderer/segments/r_drawsegment.cpp
swrenderer/segments/r_portalsegment.cpp
swrenderer/things/r_visiblesprite.cpp
swrenderer/things/r_visiblespritelist.cpp
swrenderer/things/r_voxel.cpp
swrenderer/things/r_particle.cpp
swrenderer/things/r_playersprite.cpp
swrenderer/things/r_sprite.cpp
swrenderer/things/r_wallsprite.cpp
swrenderer/things/r_decal.cpp
swrenderer/plane/r_visibleplane.cpp
swrenderer/plane/r_visibleplanelist.cpp
swrenderer/plane/r_skyplane.cpp
swrenderer/plane/r_planerenderer.cpp
swrenderer/plane/r_flatplane.cpp
swrenderer/plane/r_slopeplane.cpp
polyrenderer/poly_renderer.cpp
polyrenderer/scene/poly_scene.cpp
polyrenderer/scene/poly_portal.cpp
polyrenderer/scene/poly_cull.cpp
polyrenderer/scene/poly_decal.cpp
polyrenderer/scene/poly_particle.cpp
polyrenderer/scene/poly_plane.cpp
polyrenderer/scene/poly_playersprite.cpp
polyrenderer/scene/poly_wall.cpp
polyrenderer/scene/poly_wallsprite.cpp
polyrenderer/scene/poly_sprite.cpp
polyrenderer/scene/poly_sky.cpp
polyrenderer/drawers/poly_triangle.cpp
polyrenderer/drawers/poly_buffer.cpp
polyrenderer/drawers/poly_draw_args.cpp
polyrenderer/drawers/screen_triangle.cpp
polyrenderer/math/tri_matrix.cpp
polyrenderer/math/poly_intersection.cpp
r_sky.cpp
r_things.cpp
s_advsound.cpp
s_environment.cpp
s_playlist.cpp
@ -789,6 +854,8 @@ set( FASTMATH_SOURCES
gl/shaders/gl_fxaashader.cpp
gl/system/gl_interface.cpp
gl/system/gl_framebuffer.cpp
gl/system/gl_swframebuffer.cpp
gl/system/gl_swwipe.cpp
gl/system/gl_debug.cpp
gl/system/gl_menu.cpp
gl/system/gl_wipe.cpp
@ -1060,6 +1127,10 @@ set_source_files_properties( sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRE
set_source_files_properties( ${NOT_COMPILED_SOURCE_FILES} PROPERTIES HEADER_FILE_ONLY TRUE )
if ( WIN32 )
set_source_files_properties( win32/fb_d3d9.cpp win32/fb_d3d9_wipe.cpp PROPERTIES COMPILE_FLAGS ${ZD_FASTMATH_FLAG} )
# Supress C4244: 'initializing': conversion from '__int64' to 'unsigned int', possible loss of data
# For some reason using #pragma warning(disable: 4244) is not working..
set_source_files_properties( ${PCH_SOURCES} PROPERTIES COMPILE_FLAGS /wd4244 )
endif()
@ -1069,6 +1140,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS")
endif()
target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma )
include_directories( .
g_statusbar
g_shared
@ -1179,8 +1251,18 @@ source_group("OpenGL Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOU
source_group("OpenGL Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/system/.+")
source_group("OpenGL Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/textures/.+")
source_group("OpenGL Renderer\\Utilities" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/utility/.+")
source_group("Render Core\\Render Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_.+\\.h$")
source_group("Render Core\\Render Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_.+\\.cpp$")
source_group("Software Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/.+")
source_group("Software Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/drawers/.+")
source_group("Software Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/scene/.+")
source_group("Software Renderer\\Segments" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/segments/.+")
source_group("Software Renderer\\Line" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/line/.+")
source_group("Software Renderer\\Plane" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/plane/.+")
source_group("Software Renderer\\Things" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/things/.+")
source_group("Software Renderer\\Viewport" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/viewport/.+")
source_group("Poly Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/polyrenderer/.+")
source_group("Poly Renderer\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/polyrenderer/math/.+")
source_group("Poly Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/polyrenderer/drawers/.+")
source_group("Poly Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/polyrenderer/scene/.+")
source_group("Render Data\\Resource Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/.+\\.h$")
source_group("Render Data\\Resource Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/.+\\.cpp$")
source_group("Render Data\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/.+")

View file

@ -1933,7 +1933,7 @@ void AM_drawSubsectors()
points[j].Y = float(f_y + (f_h - (pt.y - m_y) * scale));
}
// For lighting and texture determination
sector_t *sec = Renderer->FakeFlat(subsectors[i].render_sector, &tempsec, &floorlight, &ceilinglight, false);
sector_t *sec = Renderer->FakeFlat(subsectors[i].render_sector, &tempsec, &floorlight, &ceilinglight);
// Find texture origin.
originpt.x = -sec->GetXOffset(sector_t::floor);
originpt.y = sec->GetYOffset(sector_t::floor);

View file

@ -162,10 +162,14 @@ int active_con_scale()
int scale = con_scale;
if (scale <= 0)
{
scale = CleanXfac - 1;
if (scale <= 0)
scale = uiscale;
if (scale == 0)
{
scale = 1;
scale = CleanXfac - 1;
if (scale <= 0)
{
scale = 1;
}
}
}
return scale;

View file

@ -114,6 +114,7 @@ static FCompatOption Options[] =
{ "linkfrozenprops", BCOMPATF_LINKFROZENPROPS, SLOT_BCOMPAT },
{ "floatbob", BCOMPATF_FLOATBOB, SLOT_BCOMPAT },
{ "noslopeid", BCOMPATF_NOSLOPEID, SLOT_BCOMPAT },
{ "clipmidtex", BCOMPATF_CLIPMIDTEX, SLOT_BCOMPAT },
// list copied from g_mapinfo.cpp
{ "shorttex", COMPATF_SHORTTEX, SLOT_COMPAT },
@ -152,7 +153,6 @@ static FCompatOption Options[] =
{ "multiexit", COMPATF2_MULTIEXIT, SLOT_COMPAT2 },
{ "teleport", COMPATF2_TELEPORT, SLOT_COMPAT2 },
{ "disablepushwindowcheck", COMPATF2_PUSHWINDOW, SLOT_COMPAT2 },
{ NULL, 0, 0 }
};

View file

@ -698,8 +698,6 @@ void D_Display ()
}
}
RenderTarget = screen;
// change the view size if needed
if (setsizeneeded && StatusBar != NULL)
{
@ -974,7 +972,6 @@ void D_ErrorCleanup ()
menuactive = MENU_Off;
}
insave = false;
Renderer->ErrorCleanup();
}
//==========================================================================

View file

@ -2677,7 +2677,8 @@ void Net_DoCommand (int type, BYTE **stream, int player)
int arg[3] = { 0, 0, 0 };
for (int i = 0; i < 3; i++)
arg[i] = ReadLong(stream);
E_Console(player, s, arg[0], arg[1], arg[2]);
bool manual = !!ReadByte(stream);
E_Console(player, s, arg[0], arg[1], arg[2], manual);
}
break;
@ -2728,7 +2729,7 @@ void Net_SkipCommand (int type, BYTE **stream)
break;
case DEM_NETEVENT:
skip = strlen((char *)(*stream)) + 14;
skip = strlen((char *)(*stream)) + 15;
break;
case DEM_SUMMON2:

View file

@ -360,6 +360,7 @@ enum
BCOMPATF_LINKFROZENPROPS = 1 << 6, // Clearing PROP_TOTALLYFROZEN or PROP_FROZEN also clears the other
BCOMPATF_FLOATBOB = 1 << 8, // Use Hexen's original method of preventing floatbobbing items from falling down
BCOMPATF_NOSLOPEID = 1 << 9, // disable line IDs on slopes.
BCOMPATF_CLIPMIDTEX = 1 << 10, // Always Clip midtex's in the software renderer (required to run certain GZDoom maps)
};
// phares 3/20/98:

View file

@ -117,7 +117,7 @@ bool E_UnregisterHandler(DStaticEventHandler* handler)
return true;
}
bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3)
bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual)
{
if (gamestate != GS_LEVEL)
return false;
@ -128,6 +128,7 @@ bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3)
Net_WriteLong(arg1);
Net_WriteLong(arg2);
Net_WriteLong(arg3);
Net_WriteByte(manual);
return true;
}
@ -433,10 +434,10 @@ bool E_Responder(event_t* ev)
return false;
}
void E_Console(int player, FString name, int arg1, int arg2, int arg3)
void E_Console(int player, FString name, int arg1, int arg2, int arg3, bool manual)
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
handler->ConsoleProcess(player, name, arg1, arg2, arg3);
handler->ConsoleProcess(player, name, arg1, arg2, arg3, manual);
}
bool E_CheckUiProcessors()
@ -472,57 +473,51 @@ IMPLEMENT_POINTER(prev)
IMPLEMENT_POINTERS_END
IMPLEMENT_CLASS(DEventHandler, false, false);
IMPLEMENT_CLASS(DBaseEvent, false, false)
IMPLEMENT_CLASS(DRenderEvent, false, false)
IMPLEMENT_CLASS(DWorldEvent, false, false)
IMPLEMENT_CLASS(DPlayerEvent, false, false)
IMPLEMENT_CLASS(DUiEvent, false, false)
IMPLEMENT_CLASS(DInputEvent, false, false)
IMPLEMENT_CLASS(DConsoleEvent, false, false)
DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, Order);
DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, IsUiProcessor);
DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, RequireMouse);
DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewPos);
DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewAngle);
DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewPitch);
DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewRoll);
DEFINE_FIELD_X(RenderEvent, DRenderEvent, FracTic);
DEFINE_FIELD_X(RenderEvent, DRenderEvent, Camera);
DEFINE_FIELD_X(RenderEvent, FRenderEvent, ViewPos);
DEFINE_FIELD_X(RenderEvent, FRenderEvent, ViewAngle);
DEFINE_FIELD_X(RenderEvent, FRenderEvent, ViewPitch);
DEFINE_FIELD_X(RenderEvent, FRenderEvent, ViewRoll);
DEFINE_FIELD_X(RenderEvent, FRenderEvent, FracTic);
DEFINE_FIELD_X(RenderEvent, FRenderEvent, Camera);
DEFINE_FIELD_X(WorldEvent, DWorldEvent, IsSaveGame);
DEFINE_FIELD_X(WorldEvent, DWorldEvent, IsReopen);
DEFINE_FIELD_X(WorldEvent, DWorldEvent, Thing);
DEFINE_FIELD_X(WorldEvent, DWorldEvent, Inflictor);
DEFINE_FIELD_X(WorldEvent, DWorldEvent, Damage);
DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageSource);
DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageType);
DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageFlags);
DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageAngle);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, IsSaveGame);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, IsReopen);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, Thing);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, Inflictor);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, Damage);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, DamageSource);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, DamageType);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, DamageFlags);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, DamageAngle);
DEFINE_FIELD_X(PlayerEvent, DPlayerEvent, PlayerNumber);
DEFINE_FIELD_X(PlayerEvent, DPlayerEvent, IsReturn);
DEFINE_FIELD_X(PlayerEvent, FPlayerEvent, PlayerNumber);
DEFINE_FIELD_X(PlayerEvent, FPlayerEvent, IsReturn);
DEFINE_FIELD_X(UiEvent, DUiEvent, Type);
DEFINE_FIELD_X(UiEvent, DUiEvent, KeyString);
DEFINE_FIELD_X(UiEvent, DUiEvent, KeyChar);
DEFINE_FIELD_X(UiEvent, DUiEvent, MouseX);
DEFINE_FIELD_X(UiEvent, DUiEvent, MouseY);
DEFINE_FIELD_X(UiEvent, DUiEvent, IsShift);
DEFINE_FIELD_X(UiEvent, DUiEvent, IsAlt);
DEFINE_FIELD_X(UiEvent, DUiEvent, IsCtrl);
DEFINE_FIELD_X(UiEvent, FUiEvent, Type);
DEFINE_FIELD_X(UiEvent, FUiEvent, KeyString);
DEFINE_FIELD_X(UiEvent, FUiEvent, KeyChar);
DEFINE_FIELD_X(UiEvent, FUiEvent, MouseX);
DEFINE_FIELD_X(UiEvent, FUiEvent, MouseY);
DEFINE_FIELD_X(UiEvent, FUiEvent, IsShift);
DEFINE_FIELD_X(UiEvent, FUiEvent, IsAlt);
DEFINE_FIELD_X(UiEvent, FUiEvent, IsCtrl);
DEFINE_FIELD_X(InputEvent, DInputEvent, Type);
DEFINE_FIELD_X(InputEvent, DInputEvent, KeyScan);
DEFINE_FIELD_X(InputEvent, DInputEvent, KeyString);
DEFINE_FIELD_X(InputEvent, DInputEvent, KeyChar);
DEFINE_FIELD_X(InputEvent, DInputEvent, MouseX);
DEFINE_FIELD_X(InputEvent, DInputEvent, MouseY);
DEFINE_FIELD_X(InputEvent, FInputEvent, Type);
DEFINE_FIELD_X(InputEvent, FInputEvent, KeyScan);
DEFINE_FIELD_X(InputEvent, FInputEvent, KeyString);
DEFINE_FIELD_X(InputEvent, FInputEvent, KeyChar);
DEFINE_FIELD_X(InputEvent, FInputEvent, MouseX);
DEFINE_FIELD_X(InputEvent, FInputEvent, MouseY);
DEFINE_FIELD_X(ConsoleEvent, DConsoleEvent, Player)
DEFINE_FIELD_X(ConsoleEvent, DConsoleEvent, Name)
DEFINE_FIELD_X(ConsoleEvent, DConsoleEvent, Args)
DEFINE_FIELD_X(ConsoleEvent, FConsoleEvent, Player)
DEFINE_FIELD_X(ConsoleEvent, FConsoleEvent, Name)
DEFINE_FIELD_X(ConsoleEvent, FConsoleEvent, Args)
DEFINE_FIELD_X(ConsoleEvent, FConsoleEvent, IsManual)
DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder)
{
@ -545,7 +540,7 @@ DEFINE_ACTION_FUNCTION(DEventHandler, SendNetworkEvent)
PARAM_INT(arg3);
//
ACTION_RETURN_BOOL(E_SendNetworkEvent(name, arg1, arg2, arg3));
ACTION_RETURN_BOOL(E_SendNetworkEvent(name, arg1, arg2, arg3, false));
}
DEFINE_ACTION_FUNCTION(DEventHandler, Create)
@ -717,19 +712,12 @@ void DStaticEventHandler::OnUnregister()
}
}
static DWorldEvent* E_SetupWorldEvent()
static FWorldEvent E_SetupWorldEvent()
{
static DWorldEvent* e = nullptr;
if (!e) e = (DWorldEvent*)RUNTIME_CLASS(DWorldEvent)->CreateNew();
e->IsSaveGame = savegamerestore;
e->IsReopen = level.FromSnapshot && !savegamerestore; // each one by itself isnt helpful, but with hub load we have savegamerestore==0 and level.FromSnapshot==1.
e->Thing = nullptr;
e->Inflictor = nullptr;
e->Damage = 0;
e->DamageAngle = 0.0;
e->DamageFlags = 0;
e->DamageSource = 0;
e->DamageType = NAME_None;
FWorldEvent e;
e.IsSaveGame = savegamerestore;
e.IsReopen = level.FromSnapshot && !savegamerestore; // each one by itself isnt helpful, but with hub load we have savegamerestore==0 and level.FromSnapshot==1.
e.DamageAngle = 0.0;
return e;
}
@ -740,8 +728,8 @@ void DStaticEventHandler::WorldLoaded()
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_WorldLoaded_VMPtr)
return;
DWorldEvent* e = E_SetupWorldEvent();
VMValue params[2] = { (DStaticEventHandler*)this, e };
FWorldEvent e = E_SetupWorldEvent();
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -753,8 +741,8 @@ void DStaticEventHandler::WorldUnloaded()
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_WorldUnloaded_VMPtr)
return;
DWorldEvent* e = E_SetupWorldEvent();
VMValue params[2] = { (DStaticEventHandler*)this, e };
FWorldEvent e = E_SetupWorldEvent();
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -766,9 +754,9 @@ void DStaticEventHandler::WorldThingSpawned(AActor* actor)
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_WorldThingSpawned_VMPtr)
return;
DWorldEvent* e = E_SetupWorldEvent();
e->Thing = actor;
VMValue params[2] = { (DStaticEventHandler*)this, e };
FWorldEvent e = E_SetupWorldEvent();
e.Thing = actor;
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -780,10 +768,10 @@ void DStaticEventHandler::WorldThingDied(AActor* actor, AActor* inflictor)
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_WorldThingDied_VMPtr)
return;
DWorldEvent* e = E_SetupWorldEvent();
e->Thing = actor;
e->Inflictor = inflictor;
VMValue params[2] = { (DStaticEventHandler*)this, e };
FWorldEvent e = E_SetupWorldEvent();
e.Thing = actor;
e.Inflictor = inflictor;
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -795,9 +783,9 @@ void DStaticEventHandler::WorldThingRevived(AActor* actor)
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_WorldThingRevived_VMPtr)
return;
DWorldEvent* e = E_SetupWorldEvent();
e->Thing = actor;
VMValue params[2] = { (DStaticEventHandler*)this, e };
FWorldEvent e = E_SetupWorldEvent();
e.Thing = actor;
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -809,14 +797,14 @@ void DStaticEventHandler::WorldThingDamaged(AActor* actor, AActor* inflictor, AA
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_WorldThingDamaged_VMPtr)
return;
DWorldEvent* e = E_SetupWorldEvent();
e->Thing = actor;
e->Damage = damage;
e->DamageSource = source;
e->DamageType = mod;
e->DamageFlags = flags;
e->DamageAngle = angle;
VMValue params[2] = { (DStaticEventHandler*)this, e };
FWorldEvent e = E_SetupWorldEvent();
e.Thing = actor;
e.Damage = damage;
e.DamageSource = source;
e.DamageType = mod;
e.DamageFlags = flags;
e.DamageAngle = angle;
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -828,9 +816,9 @@ void DStaticEventHandler::WorldThingDestroyed(AActor* actor)
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_WorldThingDestroyed_VMPtr)
return;
DWorldEvent* e = E_SetupWorldEvent();
e->Thing = actor;
VMValue params[2] = { (DStaticEventHandler*)this, e };
FWorldEvent e = E_SetupWorldEvent();
e.Thing = actor;
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -842,8 +830,8 @@ void DStaticEventHandler::WorldLightning()
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_WorldLightning_VMPtr)
return;
DWorldEvent* e = E_SetupWorldEvent();
VMValue params[2] = { (DStaticEventHandler*)this, e };
FWorldEvent e = E_SetupWorldEvent();
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -855,22 +843,21 @@ void DStaticEventHandler::WorldTick()
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_WorldTick_VMPtr)
return;
DWorldEvent* e = E_SetupWorldEvent();
VMValue params[2] = { (DStaticEventHandler*)this, e };
FWorldEvent e = E_SetupWorldEvent();
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
static DRenderEvent* E_SetupRenderEvent()
static FRenderEvent E_SetupRenderEvent()
{
static DRenderEvent* e = nullptr;
if (!e) e = (DRenderEvent*)RUNTIME_CLASS(DRenderEvent)->CreateNew();
e->ViewPos = ::ViewPos;
e->ViewAngle = ::ViewAngle;
e->ViewPitch = ::ViewPitch;
e->ViewRoll = ::ViewRoll;
e->FracTic = ::r_TicFracF;
e->Camera = ::camera;
FRenderEvent e;
e.ViewPos = ::ViewPos;
e.ViewAngle = ::ViewAngle;
e.ViewPitch = ::ViewPitch;
e.ViewRoll = ::ViewRoll;
e.FracTic = ::r_TicFracF;
e.Camera = ::camera;
return e;
}
@ -881,8 +868,8 @@ void DStaticEventHandler::RenderFrame()
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_RenderFrame_VMPtr)
return;
DRenderEvent* e = E_SetupRenderEvent();
VMValue params[2] = { (DStaticEventHandler*)this, e };
FRenderEvent e = E_SetupRenderEvent();
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -894,21 +881,12 @@ void DStaticEventHandler::RenderOverlay()
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_RenderOverlay_VMPtr)
return;
DRenderEvent* e = E_SetupRenderEvent();
VMValue params[2] = { (DStaticEventHandler*)this, e };
FRenderEvent e = E_SetupRenderEvent();
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
static DPlayerEvent* E_SetupPlayerEvent()
{
static DPlayerEvent* e = nullptr;
if (!e) e = (DPlayerEvent*)RUNTIME_CLASS(DPlayerEvent)->CreateNew();
e->PlayerNumber = -1;
e->IsReturn = false;
return e;
}
void DStaticEventHandler::PlayerEntered(int num, bool fromhub)
{
IFVIRTUAL(DStaticEventHandler, PlayerEntered)
@ -916,10 +894,8 @@ void DStaticEventHandler::PlayerEntered(int num, bool fromhub)
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_PlayerEntered_VMPtr)
return;
DPlayerEvent* e = E_SetupPlayerEvent();
e->IsReturn = fromhub;
e->PlayerNumber = num;
VMValue params[2] = { (DStaticEventHandler*)this, e };
FPlayerEvent e = { num, fromhub };
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -931,9 +907,8 @@ void DStaticEventHandler::PlayerRespawned(int num)
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_PlayerRespawned_VMPtr)
return;
DPlayerEvent* e = E_SetupPlayerEvent();
e->PlayerNumber = num;
VMValue params[2] = { (DStaticEventHandler*)this, e };
FPlayerEvent e = { num, false };
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -945,9 +920,8 @@ void DStaticEventHandler::PlayerDied(int num)
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_PlayerDied_VMPtr)
return;
DPlayerEvent* e = E_SetupPlayerEvent();
e->PlayerNumber = num;
VMValue params[2] = { (DStaticEventHandler*)this, e };
FPlayerEvent e = { num, false };
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -959,25 +933,50 @@ void DStaticEventHandler::PlayerDisconnected(int num)
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_PlayerDisconnected_VMPtr)
return;
DPlayerEvent* e = E_SetupPlayerEvent();
e->PlayerNumber = num;
VMValue params[2] = { (DStaticEventHandler*)this, e };
FPlayerEvent e = { num, false };
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
static DUiEvent* E_SetupUiEvent()
FUiEvent::FUiEvent(event_t *ev)
{
static DUiEvent* e = nullptr;
if (!e) e = (DUiEvent*)RUNTIME_CLASS(DUiEvent)->CreateNew();
e->Type = EV_GUI_None;
e->IsShift = false;
e->IsAlt = false;
e->IsCtrl = false;
e->MouseX = e->MouseY = 0;
e->KeyChar = 0;
e->KeyString = "";
return e;
Type = (EGUIEvent)ev->subtype;
KeyChar = 0;
IsShift = false;
IsAlt = false;
IsCtrl = false;
MouseX = 0;
MouseY = 0;
// we don't want the modders to remember what weird fields mean what for what events.
switch (ev->subtype)
{
case EV_GUI_None:
break;
case EV_GUI_KeyDown:
case EV_GUI_KeyRepeat:
case EV_GUI_KeyUp:
KeyChar = ev->data1;
KeyString = FString(char(ev->data1));
IsShift = !!(ev->data3 & GKM_SHIFT);
IsAlt = !!(ev->data3 & GKM_ALT);
IsCtrl = !!(ev->data3 & GKM_CTRL);
break;
case EV_GUI_Char:
KeyChar = ev->data1;
KeyString = FString(char(ev->data1));
IsAlt = !!ev->data2; // only true for Win32, not sure about SDL
break;
default: // mouse event
// note: SDL input doesn't seem to provide these at all
//Printf("Mouse data: %d, %d, %d, %d\n", ev->x, ev->y, ev->data1, ev->data2);
MouseX = ev->data1;
MouseY = ev->data2;
IsShift = !!(ev->data3 & GKM_SHIFT);
IsAlt = !!(ev->data3 & GKM_ALT);
IsCtrl = !!(ev->data3 & GKM_CTRL);
break;
}
}
bool DStaticEventHandler::UiProcess(event_t* ev)
@ -987,43 +986,11 @@ bool DStaticEventHandler::UiProcess(event_t* ev)
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_UiProcess_VMPtr)
return false;
DUiEvent* e = E_SetupUiEvent();
//
e->Type = (EGUIEvent)ev->subtype;
// we don't want the modders to remember what weird fields mean what for what events.
switch (e->Type)
{
case EV_GUI_None:
break;
case EV_GUI_KeyDown:
case EV_GUI_KeyRepeat:
case EV_GUI_KeyUp:
e->KeyChar = ev->data1;
e->KeyString.Format("%c", e->KeyChar);
e->IsShift = !!(ev->data3 & GKM_SHIFT);
e->IsAlt = !!(ev->data3 & GKM_ALT);
e->IsCtrl = !!(ev->data3 & GKM_CTRL);
break;
case EV_GUI_Char:
e->KeyChar = ev->data1;
e->KeyString.Format("%c", e->KeyChar);
e->IsAlt = !!ev->data2; // only true for Win32, not sure about SDL
break;
default: // mouse event
// note: SDL input doesn't seem to provide these at all
//Printf("Mouse data: %d, %d, %d, %d\n", ev->x, ev->y, ev->data1, ev->data2);
e->MouseX = ev->data1;
e->MouseY = ev->data2;
e->IsShift = !!(ev->data3 & GKM_SHIFT);
e->IsAlt = !!(ev->data3 & GKM_ALT);
e->IsCtrl = !!(ev->data3 & GKM_CTRL);
break;
}
FUiEvent e = ev;
int processed;
VMReturn results[1] = { &processed };
VMValue params[2] = { (DStaticEventHandler*)this, e };
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, results, 1, nullptr);
return !!processed;
}
@ -1031,16 +998,31 @@ bool DStaticEventHandler::UiProcess(event_t* ev)
return false;
}
static DInputEvent* E_SetupInputEvent()
FInputEvent::FInputEvent(event_t *ev)
{
static DInputEvent* e = nullptr;
if (!e) e = (DInputEvent*)RUNTIME_CLASS(DInputEvent)->CreateNew();
e->Type = EV_None;
e->KeyScan = 0;
e->KeyChar = 0;
e->KeyString = "";
e->MouseX = e->MouseY = 0;
return e;
Type = (EGenericEvent)ev->type;
// we don't want the modders to remember what weird fields mean what for what events.
KeyScan = 0;
KeyChar = 0;
MouseX = 0;
MouseY = 0;
switch (Type)
{
case EV_None:
break;
case EV_KeyDown:
case EV_KeyUp:
KeyScan = ev->data1;
KeyChar = ev->data2;
KeyString = FString(char(ev->data1));
break;
case EV_Mouse:
MouseX = ev->x;
MouseY = ev->y;
break;
default:
break; // EV_DeviceChange = wat?
}
}
bool DStaticEventHandler::InputProcess(event_t* ev)
@ -1050,32 +1032,13 @@ bool DStaticEventHandler::InputProcess(event_t* ev)
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_InputProcess_VMPtr)
return false;
DInputEvent* e = E_SetupInputEvent();
FInputEvent e = ev;
//
e->Type = (EGenericEvent)ev->type;
// we don't want the modders to remember what weird fields mean what for what events.
switch (e->Type)
{
case EV_None:
break;
case EV_KeyDown:
case EV_KeyUp:
e->KeyScan = ev->data1;
e->KeyChar = ev->data2;
e->KeyString.Format("%c", e->KeyChar);
break;
case EV_Mouse:
e->MouseX = ev->x;
e->MouseY = ev->y;
break;
default:
break; // EV_DeviceChange = wat?
}
int processed;
VMReturn results[1] = { &processed };
VMValue params[2] = { (DStaticEventHandler*)this, e };
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, results, 1, nullptr);
return !!processed;
}
@ -1083,18 +1046,7 @@ bool DStaticEventHandler::InputProcess(event_t* ev)
return false;
}
static DConsoleEvent* E_SetupConsoleEvent()
{
static DConsoleEvent* e = nullptr;
if (!e) e = (DConsoleEvent*)RUNTIME_CLASS(DConsoleEvent)->CreateNew();
e->Player = -1;
e->Name = "";
for (size_t i = 0; i < countof(e->Args); i++)
e->Args[i] = 0;
return e;
}
void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3)
void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual)
{
if (player < 0)
{
@ -1103,16 +1055,17 @@ void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_ConsoleProcess_VMPtr)
return;
DConsoleEvent* e = E_SetupConsoleEvent();
FConsoleEvent e;
//
e->Player = player;
e->Name = name;
e->Args[0] = arg1;
e->Args[1] = arg2;
e->Args[2] = arg3;
e.Player = player;
e.Name = name;
e.Args[0] = arg1;
e.Args[1] = arg2;
e.Args[2] = arg3;
e.IsManual = manual;
VMValue params[2] = { (DStaticEventHandler*)this, e };
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -1123,16 +1076,17 @@ void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_NetworkProcess_VMPtr)
return;
DConsoleEvent* e = E_SetupConsoleEvent();
FConsoleEvent e;
//
e->Player = player;
e->Name = name;
e->Args[0] = arg1;
e->Args[1] = arg2;
e->Args[2] = arg3;
e.Player = player;
e.Name = name;
e.Args[0] = arg1;
e.Args[1] = arg2;
e.Args[2] = arg3;
e.IsManual = manual;
VMValue params[2] = { (DStaticEventHandler*)this, e };
VMValue params[2] = { (DStaticEventHandler*)this, &e };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
}
}
@ -1162,7 +1116,7 @@ CCMD(event)
for (int i = 0; i < argn; i++)
arg[i] = atoi(argv[2 + i]);
// call locally
E_Console(-1, argv[1], arg[0], arg[1], arg[2]);
E_Console(-1, argv[1], arg[0], arg[1], arg[2], true);
}
}
@ -1187,6 +1141,6 @@ CCMD(netevent)
for (int i = 0; i < argn; i++)
arg[i] = atoi(argv[2 + i]);
// call networked
E_SendNetworkEvent(argv[1], arg[0], arg[1], arg[2]);
E_SendNetworkEvent(argv[1], arg[0], arg[1], arg[2], true);
}
}

View file

@ -58,10 +58,10 @@ void E_PlayerDisconnected(int num);
// this executes on events.
bool E_Responder(event_t* ev); // splits events into InputProcess and UiProcess
// this executes on console/net events.
void E_Console(int player, FString name, int arg1, int arg2, int arg3);
void E_Console(int player, FString name, int arg1, int arg2, int arg3, bool manual);
// send networked event. unified function.
bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3);
bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual);
// check if there is anything that should receive GUI events
bool E_CheckUiProcessors();
@ -152,7 +152,7 @@ public:
bool UiProcess(event_t* ev);
//
void ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3);
void ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual);
};
class DEventHandler : public DStaticEventHandler
{
@ -163,76 +163,34 @@ public:
extern DStaticEventHandler* E_FirstEventHandler;
extern DStaticEventHandler* E_LastEventHandler;
// we cannot call this DEvent because in ZScript, 'event' is a keyword
class DBaseEvent : public DObject
struct FRenderEvent
{
DECLARE_CLASS(DBaseEvent, DObject)
public:
DBaseEvent()
{
// each type of event is created only once to avoid new/delete hell
// since from what I remember object creation and deletion results in a lot of GC processing
// (and we aren't supposed to pass event objects around anyway)
this->ObjectFlags |= OF_Fixed;
// we don't want to store events into the savegames because they are global.
this->ObjectFlags |= OF_Transient;
}
};
class DRenderEvent : public DBaseEvent
{
DECLARE_CLASS(DRenderEvent, DBaseEvent)
public:
// these are for all render events
DVector3 ViewPos;
DAngle ViewAngle;
DAngle ViewPitch;
DAngle ViewRoll;
double FracTic; // 0..1 value that describes where we are inside the current gametic, render-wise.
AActor* Camera;
DRenderEvent()
{
FracTic = 0;
Camera = nullptr;
}
double FracTic = 0; // 0..1 value that describes where we are inside the current gametic, render-wise.
AActor* Camera = nullptr;
};
class DWorldEvent : public DBaseEvent
struct FWorldEvent
{
DECLARE_CLASS(DWorldEvent, DBaseEvent)
public:
// for loaded/unloaded
bool IsSaveGame;
bool IsReopen;
bool IsSaveGame = false;
bool IsReopen = false;
// for thingspawned, thingdied, thingdestroyed
AActor* Thing;
// for thingdied
AActor* Inflictor; // can be null
// for damagemobj
int Damage;
AActor* DamageSource; // can be null
AActor* Thing = nullptr; // for thingdied
AActor* Inflictor = nullptr; // can be null - for damagemobj
AActor* DamageSource = nullptr; // can be null
int Damage = 0;
FName DamageType;
int DamageFlags;
int DamageFlags = 0;
DAngle DamageAngle;
DWorldEvent()
{
IsSaveGame = false;
IsReopen = false;
Thing = nullptr;
Inflictor = nullptr;
Damage = 0;
DamageSource = nullptr;
DamageFlags = 0;
}
};
class DPlayerEvent : public DBaseEvent
struct FPlayerEvent
{
DECLARE_CLASS(DPlayerEvent, DBaseEvent)
public:
// we currently have only one member: player index
// in ZScript, we have global players[] array from which we can
// get both the player itself and player's body,
@ -240,18 +198,10 @@ public:
int PlayerNumber;
// we set this to true if level was reopened (RETURN scripts)
bool IsReturn;
DPlayerEvent()
{
PlayerNumber = -1;
IsReturn = false;
}
};
class DUiEvent : public DBaseEvent
struct FUiEvent
{
DECLARE_CLASS(DUiEvent, DBaseEvent)
public:
// this essentially translates event_t UI events to ZScript.
EGUIEvent Type;
// for keys/chars/whatever
@ -265,18 +215,13 @@ public:
bool IsCtrl;
bool IsAlt;
DUiEvent()
{
Type = EV_GUI_None;
}
FUiEvent(event_t *ev);
};
class DInputEvent : public DBaseEvent
struct FInputEvent
{
DECLARE_CLASS(DInputEvent, DBaseEvent)
public:
// this translates regular event_t events to ZScript (not UI, UI events are sent via DUiEvent and only if requested!)
EGenericEvent Type;
EGenericEvent Type = EV_None;
// for keys
int KeyScan;
FString KeyString;
@ -285,26 +230,18 @@ public:
int MouseX;
int MouseY;
DInputEvent()
{
Type = EV_None;
}
FInputEvent(event_t *ev);
};
class DConsoleEvent : public DBaseEvent
struct FConsoleEvent
{
DECLARE_CLASS(DConsoleEvent, DBaseEvent)
public:
// player that activated this event. note that it's always -1 for non-playsim events (i.e. these not called with netevent)
int Player;
//
FString Name;
int Args[3];
DConsoleEvent()
{
Player = -1;
}
//
bool IsManual;
};
#endif

View file

@ -29,6 +29,9 @@
#include "f_wipe.h"
#include "c_cvars.h"
#include "templates.h"
#include "v_palette.h"
EXTERN_CVAR(Bool, r_blendmethod)
//
// SCREEN WIPE PACKAGE
@ -281,39 +284,80 @@ bool wipe_doBurn (int ticks)
fromold = (BYTE *)wipe_scr_start;
fromnew = (BYTE *)wipe_scr_end;
for (y = 0, firey = 0; y < SCREENHEIGHT; y++, firey += ystep)
if (!r_blendmethod)
{
for (x = 0, firex = 0; x < SCREENWIDTH; x++, firex += xstep)
for (y = 0, firey = 0; y < SCREENHEIGHT; y++, firey += ystep)
{
int fglevel;
for (x = 0, firex = 0; x < SCREENWIDTH; x++, firex += xstep)
{
int fglevel;
fglevel = burnarray[(firex>>SHIFT)+(firey>>SHIFT)*FIREWIDTH] / 2;
if (fglevel >= 63)
{
to[x] = fromnew[x];
}
else if (fglevel == 0)
{
to[x] = fromold[x];
done = false;
}
else
{
int bglevel = 64-fglevel;
DWORD *fg2rgb = Col2RGB8[fglevel];
DWORD *bg2rgb = Col2RGB8[bglevel];
DWORD fg = fg2rgb[fromnew[x]];
DWORD bg = bg2rgb[fromold[x]];
fg = (fg+bg) | 0x1f07c1f;
to[x] = RGB32k.All[fg & (fg>>15)];
done = false;
fglevel = burnarray[(firex>>SHIFT)+(firey>>SHIFT)*FIREWIDTH] / 2;
if (fglevel >= 63)
{
to[x] = fromnew[x];
}
else if (fglevel == 0)
{
to[x] = fromold[x];
done = false;
}
else
{
int bglevel = 64-fglevel;
DWORD *fg2rgb = Col2RGB8[fglevel];
DWORD *bg2rgb = Col2RGB8[bglevel];
DWORD fg = fg2rgb[fromnew[x]];
DWORD bg = bg2rgb[fromold[x]];
fg = (fg+bg) | 0x1f07c1f;
to[x] = RGB32k.All[fg & (fg>>15)];
done = false;
}
}
fromold += SCREENWIDTH;
fromnew += SCREENWIDTH;
to += SCREENPITCH;
}
fromold += SCREENWIDTH;
fromnew += SCREENWIDTH;
to += SCREENPITCH;
}
}
else
{
for (y = 0, firey = 0; y < SCREENHEIGHT; y++, firey += ystep)
{
for (x = 0, firex = 0; x < SCREENWIDTH; x++, firex += xstep)
{
int fglevel;
fglevel = burnarray[(firex>>SHIFT)+(firey>>SHIFT)*FIREWIDTH] / 2;
if (fglevel >= 63)
{
to[x] = fromnew[x];
}
else if (fglevel == 0)
{
to[x] = fromold[x];
done = false;
}
else
{
int bglevel = 64-fglevel;
const PalEntry* pal = GPalette.BaseColors;
DWORD fg = fromnew[x];
DWORD bg = fromold[x];
int r = MIN((pal[fg].r * fglevel + pal[bg].r * bglevel) >> 8, 63);
int g = MIN((pal[fg].g * fglevel + pal[bg].g * bglevel) >> 8, 63);
int b = MIN((pal[fg].b * fglevel + pal[bg].b * bglevel) >> 8, 63);
to[x] = RGB256k.RGB[r][g][b];
done = false;
}
}
fromold += SCREENWIDTH;
fromnew += SCREENWIDTH;
to += SCREENPITCH;
}
}
return done || (burntime > 40);
}
@ -348,19 +392,41 @@ bool wipe_doFade (int ticks)
BYTE *fromnew = (BYTE *)wipe_scr_end;
BYTE *fromold = (BYTE *)wipe_scr_start;
BYTE *to = screen->GetBuffer();
const PalEntry *pal = GPalette.BaseColors;
for (y = 0; y < SCREENHEIGHT; y++)
if (!r_blendmethod)
{
for (x = 0; x < SCREENWIDTH; x++)
for (y = 0; y < SCREENHEIGHT; y++)
{
DWORD fg = fg2rgb[fromnew[x]];
DWORD bg = bg2rgb[fromold[x]];
fg = (fg+bg) | 0x1f07c1f;
to[x] = RGB32k.All[fg & (fg>>15)];
for (x = 0; x < SCREENWIDTH; x++)
{
DWORD fg = fg2rgb[fromnew[x]];
DWORD bg = bg2rgb[fromold[x]];
fg = (fg+bg) | 0x1f07c1f;
to[x] = RGB32k.All[fg & (fg>>15)];
}
fromnew += SCREENWIDTH;
fromold += SCREENWIDTH;
to += SCREENPITCH;
}
}
else
{
for (y = 0; y < SCREENHEIGHT; y++)
{
for (x = 0; x < SCREENWIDTH; x++)
{
DWORD fg = fromnew[x];
DWORD bg = fromold[x];
int r = MIN((pal[fg].r * (64-bglevel) + pal[bg].r * bglevel) >> 8, 63);
int g = MIN((pal[fg].g * (64-bglevel) + pal[bg].g * bglevel) >> 8, 63);
int b = MIN((pal[fg].b * (64-bglevel) + pal[bg].b * bglevel) >> 8, 63);
to[x] = RGB256k.RGB[r][g][b];
}
fromnew += SCREENWIDTH;
fromold += SCREENWIDTH;
to += SCREENPITCH;
}
fromnew += SCREENWIDTH;
fromold += SCREENWIDTH;
to += SCREENPITCH;
}
}
return false;
@ -383,6 +449,9 @@ static bool (*wipes[])(int) =
// Returns true if the wipe should be performed.
bool wipe_StartScreen (int type)
{
if (screen->IsBgra())
return false;
CurrentWipeType = clamp(type, 0, wipe_NUMWIPES - 1);
if (CurrentWipeType)
@ -396,11 +465,15 @@ bool wipe_StartScreen (int type)
void wipe_EndScreen (void)
{
if (screen->IsBgra())
return;
if (CurrentWipeType)
{
wipe_scr_end = new short[SCREENWIDTH * SCREENHEIGHT / 2];
screen->GetBlock (0, 0, SCREENWIDTH, SCREENHEIGHT, (BYTE *)wipe_scr_end);
screen->DrawBlock (0, 0, SCREENWIDTH, SCREENHEIGHT, (BYTE *)wipe_scr_start); // restore start scr.
// Initialize the wipe
(*wipes[(CurrentWipeType-1)*3])(0);
}
@ -411,6 +484,9 @@ bool wipe_ScreenWipe (int ticks)
{
bool rc;
if (screen->IsBgra())
return true;
if (CurrentWipeType == wipe_None)
return true;
@ -424,6 +500,9 @@ bool wipe_ScreenWipe (int ticks)
// Final things for the wipe
void wipe_Cleanup()
{
if (screen->IsBgra())
return;
if (wipe_scr_start != NULL)
{
delete[] wipe_scr_start;

View file

@ -1389,7 +1389,7 @@ void G_InitLevelLocals ()
level_info_t *info;
BaseBlendA = 0.0f; // Remove underwater blend effect, if any
NormalLight.Maps = realcolormaps;
NormalLight.Maps = realcolormaps.Maps;
// [BB] Instead of just setting the color, we also have to reset Desaturate and build the lights.
NormalLight.ChangeColor (PalEntry (255, 255, 255), 0);
@ -1417,6 +1417,7 @@ void G_InitLevelLocals ()
R_SetDefaultColormap (info->FadeTable);
if (strnicmp (info->FadeTable, "COLORMAP", 8) != 0)
{
level.fadeto = 0xff939393; //[SP] Hexen True-color compatibility, just use gray.
level.flags |= LEVEL_HASFADETABLE;
}
/*

View file

@ -36,7 +36,6 @@ public:
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
const BYTE *GetPixels ();
bool CheckModified ();
void Unload ();
void SetVial (int level);
@ -91,10 +90,6 @@ bool FHealthBar::CheckModified ()
return NeedRefresh;
}
void FHealthBar::Unload ()
{
}
const BYTE *FHealthBar::GetColumn (unsigned int column, const Span **spans_out)
{
if (NeedRefresh)

View file

@ -81,7 +81,6 @@
#include "gl/utility/gl_templates.h"
#include "gl/system//gl_interface.h"
EXTERN_CVAR(Int, vid_renderer)
//==========================================================================
@ -233,10 +232,6 @@ void ADynamicLight::Deactivate(AActor *activator)
//==========================================================================
void ADynamicLight::Tick()
{
if (vid_renderer == 0)
{
return;
}
if (IsOwned())
{
if (!target || !target->state)

View file

@ -79,5 +79,4 @@ struct FColormap
};
#endif

View file

@ -189,9 +189,9 @@ public:
void SetFixedColormap (player_t *player);
void WriteSavePic (player_t *player, FileWriter *file, int width, int height);
void EndDrawScene(sector_t * viewsector);
void UpdateCameraExposure();
void PostProcessScene();
void AmbientOccludeScene();
void UpdateCameraExposure();
void BloomScene();
void TonemapScene();
void ColormapScene();

View file

@ -1017,14 +1017,14 @@ struct FGLInterface : public FRenderer
void StartSerialize(FSerializer &arc) override;
void EndSerialize(FSerializer &arc) override;
void RenderTextureView (FCanvasTexture *self, AActor *viewpoint, int fov) override;
sector_t *FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel, bool back) override;
sector_t *FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel) override;
void SetFogParams(int _fogdensity, PalEntry _outsidefogcolor, int _outsidefogdensity, int _skyfog) override;
void PreprocessLevel() override;
void CleanLevelData() override;
bool RequireGLNodes() override;
int GetMaxViewPitch(bool down) override;
void ClearBuffer(int color) override;
void SetClearColor(int color) override;
void Init() override;
};
@ -1279,7 +1279,7 @@ int FGLInterface::GetMaxViewPitch(bool down)
//
//===========================================================================
void FGLInterface::ClearBuffer(int color)
void FGLInterface::SetClearColor(int color)
{
PalEntry pe = GPalette.BaseColors[color];
GLRenderer->mSceneClearColor[0] = pe.r / 255.f;
@ -1379,7 +1379,7 @@ void FGLInterface::RenderTextureView (FCanvasTexture *tex, AActor *Viewpoint, in
//
//==========================================================================
sector_t *FGLInterface::FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel, bool back)
sector_t *FGLInterface::FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel)
{
if (floorlightlevel != NULL)
{
@ -1389,7 +1389,7 @@ sector_t *FGLInterface::FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlig
{
*ceilinglightlevel = sec->GetCeilingLight ();
}
return gl_FakeFlat(sec, tempsec, back);
return gl_FakeFlat(sec, tempsec, false);
}
//===========================================================================

View file

@ -79,7 +79,7 @@ CUSTOM_CVAR(Int, vid_hwgamma, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITC
//==========================================================================
OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen) :
Super(hMonitor, width, height, bits, refreshHz, fullscreen)
Super(hMonitor, width, height, bits, refreshHz, fullscreen, false)
{
// SetVSync needs to be at the very top to workaround a bug in Nvidia's OpenGL driver.
// If wglSwapIntervalEXT is called after glBindFramebuffer in a frame the setting is not changed!

View file

@ -130,8 +130,16 @@ void gl_LoadExtensions()
InitContext();
CollectExtensions();
const char *version = Args->CheckValue("-glversion");
const char *glversion = (const char*)glGetString(GL_VERSION);
gl.es = false;
if (glversion && strlen(glversion) > 10 && memcmp(glversion, "OpenGL ES ", 10) == 0)
{
glversion += 10;
gl.es = true;
}
const char *version = Args->CheckValue("-glversion");
if (version == NULL)
{
@ -147,90 +155,117 @@ void gl_LoadExtensions()
float gl_version = (float)strtod(version, NULL) + 0.01f;
// Don't even start if it's lower than 2.0 or no framebuffers are available (The framebuffer extension is needed for glGenerateMipmapsEXT!)
if ((gl_version < 2.0f || !CheckExtension("GL_EXT_framebuffer_object")) && gl_version < 3.0f)
if (gl.es)
{
I_FatalError("Unsupported OpenGL version.\nAt least OpenGL 2.0 with framebuffer support is required to run " GAMENAME ".\n");
}
if (gl_version < 2.0f)
{
I_FatalError("Unsupported OpenGL ES version.\nAt least OpenGL ES 2.0 is required to run " GAMENAME ".\n");
}
const char *glslversion = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
if (glslversion && strlen(glslversion) > 18 && memcmp(glslversion, "OpenGL ES GLSL ES ", 10) == 0)
{
glslversion += 18;
}
// add 0.01 to account for roundoff errors making the number a tad smaller than the actual version
gl.glslversion = strtod(glslversion, NULL) + 0.01f;
gl.vendorstring = (char*)glGetString(GL_VENDOR);
// add 0.01 to account for roundoff errors making the number a tad smaller than the actual version
gl.glslversion = strtod((char*)glGetString(GL_SHADING_LANGUAGE_VERSION), NULL) + 0.01f;
gl.vendorstring = (char*)glGetString(GL_VENDOR);
// first test for optional features
if (CheckExtension("GL_ARB_texture_compression")) gl.flags |= RFL_TEXTURE_COMPRESSION;
if (CheckExtension("GL_EXT_texture_compression_s3tc")) gl.flags |= RFL_TEXTURE_COMPRESSION_S3TC;
if ((gl_version >= 3.3f || CheckExtension("GL_ARB_sampler_objects")) && !Args->CheckParm("-nosampler"))
{
gl.flags |= RFL_SAMPLER_OBJECTS;
}
// The minimum requirement for the modern render path are GL 3.0 + uniform buffers. Also exclude the Linux Mesa driver at GL 3.0 because it errors out on shader compilation.
if (gl_version < 3.0f || (gl_version < 3.1f && (!CheckExtension("GL_ARB_uniform_buffer_object") || strstr(gl.vendorstring, "X.Org") != nullptr)))
{
gl.legacyMode = true;
gl.lightmethod = LM_LEGACY;
gl.buffermethod = BM_LEGACY;
gl.glslversion = 0;
gl.flags |= RFL_NO_CLIP_PLANES;
}
else
{
// Use the slowest/oldest modern path for now
gl.legacyMode = false;
gl.lightmethod = LM_DEFERRED;
gl.buffermethod = BM_DEFERRED;
if (gl_version < 4.f)
}
else
{
// Don't even start if it's lower than 2.0 or no framebuffers are available (The framebuffer extension is needed for glGenerateMipmapsEXT!)
if ((gl_version < 2.0f || !CheckExtension("GL_EXT_framebuffer_object")) && gl_version < 3.0f)
{
#ifdef _WIN32
if (strstr(gl.vendorstring, "ATI Tech"))
{
gl.flags |= RFL_NO_CLIP_PLANES; // gl_ClipDistance is horribly broken on ATI GL3 drivers for Windows.
}
#endif
I_FatalError("Unsupported OpenGL version.\nAt least OpenGL 2.0 with framebuffer support is required to run " GAMENAME ".\n");
}
else if (gl_version < 4.5f)
gl.es = false;
// add 0.01 to account for roundoff errors making the number a tad smaller than the actual version
gl.glslversion = strtod((char*)glGetString(GL_SHADING_LANGUAGE_VERSION), NULL) + 0.01f;
gl.vendorstring = (char*)glGetString(GL_VENDOR);
// first test for optional features
if (CheckExtension("GL_ARB_texture_compression")) gl.flags |= RFL_TEXTURE_COMPRESSION;
if (CheckExtension("GL_EXT_texture_compression_s3tc")) gl.flags |= RFL_TEXTURE_COMPRESSION_S3TC;
if ((gl_version >= 3.3f || CheckExtension("GL_ARB_sampler_objects")) && !Args->CheckParm("-nosampler"))
{
// don't use GL 4.x features when running a GL 3.x context.
if (CheckExtension("GL_ARB_buffer_storage"))
{
// work around a problem with older AMD drivers: Their implementation of shader storage buffer objects is piss-poor and does not match uniform buffers even closely.
// Recent drivers, GL 4.4 don't have this problem, these can easily be recognized by also supporting the GL_ARB_buffer_storage extension.
if (CheckExtension("GL_ARB_shader_storage_buffer_object"))
{
// Shader storage buffer objects are broken on current Intel drivers.
if (strstr(gl.vendorstring, "Intel") == NULL)
{
gl.flags |= RFL_SHADER_STORAGE_BUFFER;
}
}
gl.flags |= RFL_BUFFER_STORAGE;
gl.lightmethod = LM_DIRECT;
gl.buffermethod = BM_PERSISTENT;
}
gl.flags |= RFL_SAMPLER_OBJECTS;
}
// The minimum requirement for the modern render path are GL 3.0 + uniform buffers. Also exclude the Linux Mesa driver at GL 3.0 because it errors out on shader compilation.
if (gl_version < 3.0f || (gl_version < 3.1f && (!CheckExtension("GL_ARB_uniform_buffer_object") || strstr(gl.vendorstring, "X.Org") != nullptr)))
{
gl.legacyMode = true;
gl.lightmethod = LM_LEGACY;
gl.buffermethod = BM_LEGACY;
gl.glslversion = 0;
gl.flags |= RFL_NO_CLIP_PLANES;
}
else
{
// Assume that everything works without problems on GL 4.5 drivers where these things are core features.
gl.flags |= RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE;
gl.lightmethod = LM_DIRECT;
gl.buffermethod = BM_PERSISTENT;
}
gl.legacyMode = false;
gl.lightmethod = LM_DEFERRED;
gl.buffermethod = BM_DEFERRED;
if (gl_version < 4.f)
{
#ifdef _WIN32
if (strstr(gl.vendorstring, "ATI Tech"))
{
gl.flags |= RFL_NO_CLIP_PLANES; // gl_ClipDistance is horribly broken on ATI GL3 drivers for Windows.
}
#endif
}
else if (gl_version < 4.5f)
{
// don't use GL 4.x features when running a GL 3.x context.
if (CheckExtension("GL_ARB_buffer_storage"))
{
// work around a problem with older AMD drivers: Their implementation of shader storage buffer objects is piss-poor and does not match uniform buffers even closely.
// Recent drivers, GL 4.4 don't have this problem, these can easily be recognized by also supporting the GL_ARB_buffer_storage extension.
if (CheckExtension("GL_ARB_shader_storage_buffer_object"))
{
// Shader storage buffer objects are broken on current Intel drivers.
if (strstr(gl.vendorstring, "Intel") == NULL)
{
gl.flags |= RFL_SHADER_STORAGE_BUFFER;
}
}
gl.flags |= RFL_BUFFER_STORAGE;
gl.lightmethod = LM_DIRECT;
gl.buffermethod = BM_PERSISTENT;
}
}
else
{
// Assume that everything works without problems on GL 4.5 drivers where these things are core features.
gl.flags |= RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE;
gl.lightmethod = LM_DIRECT;
gl.buffermethod = BM_PERSISTENT;
}
if (gl_version >= 4.3f || CheckExtension("GL_ARB_invalidate_subdata")) gl.flags |= RFL_INVALIDATE_BUFFER;
if (gl_version >= 4.3f || CheckExtension("GL_KHR_debug")) gl.flags |= RFL_DEBUG;
if (gl_version >= 4.3f || CheckExtension("GL_ARB_invalidate_subdata")) gl.flags |= RFL_INVALIDATE_BUFFER;
if (gl_version >= 4.3f || CheckExtension("GL_KHR_debug")) gl.flags |= RFL_DEBUG;
const char *lm = Args->CheckValue("-lightmethod");
if (lm != NULL)
{
if (!stricmp(lm, "deferred") && gl.lightmethod == LM_DIRECT) gl.lightmethod = LM_DEFERRED;
}
const char *lm = Args->CheckValue("-lightmethod");
if (lm != NULL)
{
if (!stricmp(lm, "deferred") && gl.lightmethod == LM_DIRECT) gl.lightmethod = LM_DEFERRED;
}
lm = Args->CheckValue("-buffermethod");
if (lm != NULL)
{
if (!stricmp(lm, "deferred") && gl.buffermethod == BM_PERSISTENT) gl.buffermethod = BM_DEFERRED;
lm = Args->CheckValue("-buffermethod");
if (lm != NULL)
{
if (!stricmp(lm, "deferred") && gl.buffermethod == BM_PERSISTENT) gl.buffermethod = BM_DEFERRED;
}
}
}

View file

@ -66,6 +66,7 @@ struct RenderContext
int max_texturesize;
char * vendorstring;
bool legacyMode;
bool es;
int MaxLights() const
{

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,505 @@
#ifndef __GL_SWFRAMEBUFFER
#define __GL_SWFRAMEBUFFER
#ifdef _WIN32
#include "win32iface.h"
#include "win32gliface.h"
#endif
#include "SkylineBinPack.h"
#include <memory>
class FGLDebug;
#ifdef _WIN32
class OpenGLSWFrameBuffer : public Win32GLFrameBuffer
{
typedef Win32GLFrameBuffer Super;
DECLARE_CLASS(OpenGLSWFrameBuffer, Win32GLFrameBuffer)
#else
#include "sdlglvideo.h"
class OpenGLSWFrameBuffer : public SDLGLFB
{
// typedef SDLGLFB Super; //[C]commented, DECLARE_CLASS defines this in linux
DECLARE_CLASS(OpenGLSWFrameBuffer, SDLGLFB)
#endif
public:
explicit OpenGLSWFrameBuffer() {}
OpenGLSWFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen, bool bgra);
~OpenGLSWFrameBuffer();
bool IsValid() override;
bool Lock(bool buffered) override;
void Unlock() override;
void Update() override;
PalEntry *GetPalette() override;
void GetFlashedPalette(PalEntry palette[256]) override;
void UpdatePalette() override;
bool SetGamma(float gamma) override;
bool SetFlash(PalEntry rgb, int amount) override;
void GetFlash(PalEntry &rgb, int &amount) override;
int GetPageCount() override;
void SetVSync(bool vsync) override;
void NewRefreshRate() override;
void GetScreenshotBuffer(const uint8_t *&buffer, int &pitch, ESSType &color_type) override;
void ReleaseScreenshotBuffer() override;
void SetBlendingRect(int x1, int y1, int x2, int y2) override;
bool Begin2D(bool copy3d) override;
void DrawBlendingRect() override;
FNativeTexture *CreateTexture(FTexture *gametex, bool wrapping) override;
FNativePalette *CreatePalette(FRemapTable *remap) override;
void DrawTextureParms(FTexture *img, DrawParms &parms) override;
void Clear(int left, int top, int right, int bottom, int palcolor, uint32 color) override;
void Dim(PalEntry color, float amount, int x1, int y1, int w, int h) override;
void FlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin) override;
void DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32 realcolor) override;
void DrawPixel(int x, int y, int palcolor, uint32 rgbcolor) override;
void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, FDynamicColormap *colormap, PalEntry flatcolor, int lightlevel, int bottomclip) override;
bool WipeStartScreen(int type) override;
void WipeEndScreen() override;
bool WipeDo(int ticks) override;
void WipeCleanup() override;
#ifdef WIN32
void PaletteChanged() override { }
int QueryNewPalette() override { return 0; }
void Blank() override { }
bool PaintToWindow() override;
bool Is8BitMode() override { return false; }
int GetTrueHeight() override { return TrueHeight; }
#endif
private:
struct FBVERTEX
{
float x, y, z, rhw;
uint32_t color0, color1;
float tu, tv;
};
struct BURNVERTEX
{
float x, y, z, rhw;
float tu0, tv0;
float tu1, tv1;
};
enum
{
PSCONST_Desaturation,
PSCONST_PaletteMod,
PSCONST_Weights,
PSCONST_Gamma,
PSCONST_ScreenSize,
NumPSCONST
};
struct GammaRamp
{
uint16_t red[256], green[256], blue[256];
};
struct LTRBRect
{
int left, top, right, bottom;
};
class HWTexture
{
public:
HWTexture() { Buffers[0] = 0; Buffers[1] = 0; }
~HWTexture();
int Texture = 0;
int Buffers[2];
int CurrentBuffer = 0;
int WrapS = 0;
int WrapT = 0;
int Format = 0;
std::vector<uint8_t> MapBuffer;
};
class HWFrameBuffer
{
public:
~HWFrameBuffer();
int Framebuffer = 0;
HWTexture *Texture = nullptr;
};
class HWVertexBuffer
{
public:
~HWVertexBuffer();
FBVERTEX *Lock();
void Unlock();
int VertexArray = 0;
int Buffer = 0;
int Size = 0;
};
class HWIndexBuffer
{
public:
~HWIndexBuffer();
uint16_t *Lock();
void Unlock();
int Buffer = 0;
int Size = 0;
private:
int LockedOldBinding = 0;
};
class HWPixelShader
{
public:
~HWPixelShader();
int Program = 0;
int VertexShader = 0;
int FragmentShader = 0;
int ConstantLocations[NumPSCONST];
int ImageLocation = -1;
int PaletteLocation = -1;
int NewScreenLocation = -1;
int BurnLocation = -1;
};
bool CreateFrameBuffer(const FString &name, int width, int height, HWFrameBuffer **outFramebuffer);
bool CreatePixelShader(FString vertexsrc, FString fragmentsrc, const FString &defines, HWPixelShader **outShader);
bool CreateVertexBuffer(int size, HWVertexBuffer **outVertexBuffer);
bool CreateIndexBuffer(int size, HWIndexBuffer **outIndexBuffer);
bool CreateTexture(const FString &name, int width, int height, int levels, int format, HWTexture **outTexture);
void SetGammaRamp(const GammaRamp *ramp);
void SetPixelShaderConstantF(int uniformIndex, const float *data, int vec4fcount);
void SetHWPixelShader(HWPixelShader *shader);
void SetStreamSource(HWVertexBuffer *vertexBuffer);
void SetIndices(HWIndexBuffer *indexBuffer);
void DrawTriangleFans(int count, const FBVERTEX *vertices);
void DrawTriangleFans(int count, const BURNVERTEX *vertices);
void DrawPoints(int count, const FBVERTEX *vertices);
void DrawLineList(int count);
void DrawTriangleList(int minIndex, int numVertices, int startIndex, int primitiveCount);
void Present();
static void BgraToRgba(uint32_t *dest, const uint32_t *src, int width, int height, int srcpitch);
void BindFBBuffer();
void *MappedMemBuffer = nullptr;
bool UseMappedMemBuffer = true;
static uint32_t ColorARGB(uint32_t a, uint32_t r, uint32_t g, uint32_t b) { return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | ((b) & 0xff); }
static uint32_t ColorRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) { return ColorARGB(a, r, g, b); }
static uint32_t ColorXRGB(uint32_t r, uint32_t g, uint32_t b) { return ColorARGB(0xff, r, g, b); }
static uint32_t ColorValue(float r, float g, float b, float a) { return ColorRGBA((uint32_t)(r * 255.0f), (uint32_t)(g * 255.0f), (uint32_t)(b * 255.0f), (uint32_t)(a * 255.0f)); }
static void *MapBuffer(int target, int size);
// The number of points for the vertex buffer.
enum { NUM_VERTS = 10240 };
// The number of indices for the index buffer.
enum { NUM_INDEXES = ((NUM_VERTS * 6) / 4) };
// The number of quads we can batch together.
enum { MAX_QUAD_BATCH = (NUM_INDEXES / 6) };
// The default size for a texture atlas.
enum { DEF_ATLAS_WIDTH = 512 };
enum { DEF_ATLAS_HEIGHT = 512 };
// TYPES -------------------------------------------------------------------
struct Atlas;
struct PackedTexture
{
Atlas *Owner;
PackedTexture **Prev, *Next;
// Pixels this image covers
LTRBRect Area;
// Texture coordinates for this image
float Left, Top, Right, Bottom;
// Texture has extra space on the border?
bool Padded;
};
struct Atlas
{
Atlas(OpenGLSWFrameBuffer *fb, int width, int height, int format);
~Atlas();
PackedTexture *AllocateImage(const Rect &rect, bool padded);
void FreeBox(PackedTexture *box);
SkylineBinPack Packer;
Atlas *Next;
HWTexture *Tex;
int Format;
PackedTexture *UsedList; // Boxes that contain images
int Width, Height;
bool OneUse;
};
class OpenGLTex : public FNativeTexture
{
public:
OpenGLTex(FTexture *tex, OpenGLSWFrameBuffer *fb, bool wrapping);
~OpenGLTex();
FTexture *GameTex;
PackedTexture *Box;
OpenGLTex **Prev;
OpenGLTex *Next;
bool IsGray;
bool Create(OpenGLSWFrameBuffer *fb, bool wrapping);
bool Update();
bool CheckWrapping(bool wrapping);
int GetTexFormat();
FTextureFormat ToTexFmt(int fmt);
};
class OpenGLPal : public FNativePalette
{
public:
OpenGLPal(FRemapTable *remap, OpenGLSWFrameBuffer *fb);
~OpenGLPal();
OpenGLPal **Prev;
OpenGLPal *Next;
HWTexture *Tex;
uint32_t BorderColor;
bool DoColorSkip;
bool Update();
FRemapTable *Remap;
int RoundedPaletteSize;
};
// Flags for a buffered quad
enum
{
BQF_GamePalette = 1,
BQF_CustomPalette = 7,
BQF_Paletted = 7,
BQF_Bilinear = 8,
BQF_WrapUV = 16,
BQF_InvertSource = 32,
BQF_DisableAlphaTest = 64,
BQF_Desaturated = 128,
};
// Shaders for a buffered quad
enum
{
BQS_PalTex,
BQS_Plain,
BQS_RedToAlpha,
BQS_ColorOnly,
BQS_SpecialColormap,
BQS_InGameColormap,
};
struct BufferedTris
{
uint8_t Flags;
uint8_t ShaderNum;
int BlendOp;
int SrcBlend;
int DestBlend;
uint8_t Desat;
OpenGLPal *Palette;
HWTexture *Texture;
uint16_t NumVerts; // Number of _unique_ vertices used by this set.
uint16_t NumTris; // Number of triangles used by this set.
void ClearSetup()
{
Flags = 0;
ShaderNum = 0;
BlendOp = 0;
SrcBlend = 0;
DestBlend = 0;
}
bool IsSameSetup(const BufferedTris &other) const
{
return Flags == other.Flags && ShaderNum == other.ShaderNum && BlendOp == other.BlendOp && SrcBlend == other.SrcBlend && DestBlend == other.DestBlend;
}
};
enum
{
SHADER_NormalColor,
SHADER_NormalColorPal,
SHADER_NormalColorInv,
SHADER_NormalColorPalInv,
SHADER_RedToAlpha,
SHADER_RedToAlphaInv,
SHADER_VertexColor,
SHADER_SpecialColormap,
SHADER_SpecialColormapPal,
SHADER_InGameColormap,
SHADER_InGameColormapDesat,
SHADER_InGameColormapInv,
SHADER_InGameColormapInvDesat,
SHADER_InGameColormapPal,
SHADER_InGameColormapPalDesat,
SHADER_InGameColormapPalInv,
SHADER_InGameColormapPalInvDesat,
SHADER_BurnWipe,
SHADER_GammaCorrection,
NUM_SHADERS
};
static const char *const ShaderDefines[NUM_SHADERS];
void Flip();
void SetInitialState();
bool CreateResources();
void ReleaseResources();
bool LoadShaders();
bool CreateFBTexture();
bool CreatePaletteTexture();
bool CreateVertexes();
void UploadPalette();
void CalcFullscreenCoords(FBVERTEX verts[4], bool viewarea_only, uint32_t color0, uint32_t color1) const;
bool Reset();
HWTexture *CopyCurrentScreen();
void ReleaseDefaultPoolItems();
void KillNativePals();
void KillNativeTexs();
PackedTexture *AllocPackedTexture(int width, int height, bool wrapping, int format);
void DrawPackedTextures(int packnum);
void DrawLetterbox(int x, int y, int width, int height);
void Draw3DPart(bool copy3d);
bool SetStyle(OpenGLTex *tex, DrawParms &parms, uint32_t &color0, uint32_t &color1, BufferedTris &quad);
static int GetStyleAlpha(int type);
static void SetColorOverlay(uint32_t color, float alpha, uint32_t &color0, uint32_t &color1);
void AddColorOnlyQuad(int left, int top, int width, int height, uint32_t color);
void AddColorOnlyRect(int left, int top, int width, int height, uint32_t color);
void CheckQuadBatch(int numtris = 2, int numverts = 4);
void BeginQuadBatch();
void EndQuadBatch();
void BeginLineBatch();
void EndLineBatch();
void EndBatch();
// State
void EnableAlphaTest(bool enabled);
void SetAlphaBlend(int op, int srcblend = 0, int destblend = 0);
void SetConstant(int cnum, float r, float g, float b, float a);
void SetPixelShader(HWPixelShader *shader);
void SetTexture(int tnum, HWTexture *texture);
void SetSamplerWrapS(int tnum, int mode);
void SetSamplerWrapT(int tnum, int mode);
void SetPaletteTexture(HWTexture *texture, int count, uint32_t border_color);
template<typename T> static void SafeRelease(T &x) { if (x != nullptr) { delete x; x = nullptr; } }
bool Valid = false;
std::shared_ptr<FGLDebug> Debug;
std::unique_ptr<HWVertexBuffer> StreamVertexBuffer, StreamVertexBufferBurn;
float ShaderConstants[NumPSCONST * 4];
HWPixelShader *CurrentShader = nullptr;
HWFrameBuffer *OutputFB = nullptr;
bool AlphaTestEnabled = false;
bool AlphaBlendEnabled = false;
int AlphaBlendOp = 0;
int AlphaSrcBlend = 0;
int AlphaDestBlend = 0;
float Constant[3][4];
uint32_t CurBorderColor;
HWPixelShader *CurPixelShader;
HWTexture *Texture[5];
int SamplerWrapS[5], SamplerWrapT[5];
PalEntry SourcePalette[256];
uint32_t BorderColor;
uint32_t FlashColor0, FlashColor1;
PalEntry FlashColor;
int FlashAmount;
int TrueHeight;
int PixelDoubling;
float Gamma;
bool UpdatePending;
bool NeedPalUpdate;
bool NeedGammaUpdate;
LTRBRect BlendingRect;
int In2D;
bool InScene;
bool GatheringWipeScreen;
bool AALines;
uint8_t BlockNum;
OpenGLPal *Palettes = nullptr;
OpenGLTex *Textures = nullptr;
Atlas *Atlases = nullptr;
HWTexture *FBTexture = nullptr;
HWTexture *PaletteTexture = nullptr;
HWTexture *ScreenshotTexture = nullptr;
HWVertexBuffer *VertexBuffer = nullptr;
FBVERTEX *VertexData = nullptr;
HWIndexBuffer *IndexBuffer = nullptr;
uint16_t *IndexData = nullptr;
BufferedTris *QuadExtra = nullptr;
int VertexPos;
int IndexPos;
int QuadBatchPos;
enum { BATCH_None, BATCH_Quads, BATCH_Lines } BatchType;
HWPixelShader *Shaders[NUM_SHADERS];
HWTexture *InitialWipeScreen = nullptr, *FinalWipeScreen = nullptr;
class Wiper
{
public:
virtual ~Wiper();
virtual bool Run(int ticks, OpenGLSWFrameBuffer *fb) = 0;
void DrawScreen(OpenGLSWFrameBuffer *fb, HWTexture *tex, int blendop = 0, uint32_t color0 = 0, uint32_t color1 = 0xFFFFFFF);
};
class Wiper_Melt; friend class Wiper_Melt;
class Wiper_Burn; friend class Wiper_Burn;
class Wiper_Crossfade; friend class Wiper_Crossfade;
Wiper *ScreenWipe;
};
#endif //__GL_SWFRAMEBUFFER

587
src/gl/system/gl_swwipe.cpp Normal file
View file

@ -0,0 +1,587 @@
/*
** gl_swwipe.cpp
** Implements the different screen wipes using OpenGL calls.
**
**---------------------------------------------------------------------------
** Copyright 1998-2008 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.
**---------------------------------------------------------------------------
**
*/
// HEADER FILES ------------------------------------------------------------
#include "gl/system/gl_system.h"
#include "files.h"
#include "m_swap.h"
#include "v_video.h"
#include "doomstat.h"
#include "m_png.h"
#include "m_crc32.h"
#include "vectors.h"
#include "v_palette.h"
#include "templates.h"
#include "c_dispatch.h"
#include "templates.h"
#include "i_system.h"
#include "i_video.h"
#include "i_input.h"
#include "v_pfx.h"
#include "stats.h"
#include "doomerrors.h"
#include "r_data/r_translate.h"
#include "f_wipe.h"
#include "sbar.h"
#include "w_wad.h"
#include "r_data/colormaps.h"
#include "gl/system/gl_interface.h"
#include "gl/system/gl_swframebuffer.h"
#include "gl/data/gl_data.h"
#include "gl/utility/gl_clock.h"
#include "gl/utility/gl_templates.h"
#include "gl/gl_functions.h"
#include "gl_debug.h"
#include "m_random.h"
class OpenGLSWFrameBuffer::Wiper_Crossfade : public OpenGLSWFrameBuffer::Wiper
{
public:
Wiper_Crossfade();
bool Run(int ticks, OpenGLSWFrameBuffer *fb);
private:
int Clock;
};
class OpenGLSWFrameBuffer::Wiper_Melt : public OpenGLSWFrameBuffer::Wiper
{
public:
Wiper_Melt();
bool Run(int ticks, OpenGLSWFrameBuffer *fb);
private:
// Match the strip sizes that oldschool Doom used.
static const int WIDTH = 160, HEIGHT = 200;
int y[WIDTH];
};
class OpenGLSWFrameBuffer::Wiper_Burn : public OpenGLSWFrameBuffer::Wiper
{
public:
Wiper_Burn(OpenGLSWFrameBuffer *fb);
~Wiper_Burn();
bool Run(int ticks, OpenGLSWFrameBuffer *fb);
private:
static const int WIDTH = 64, HEIGHT = 64;
uint8_t BurnArray[WIDTH * (HEIGHT + 5)];
HWTexture *BurnTexture;
int Density;
int BurnTime;
};
//==========================================================================
//
// OpenGLSWFrameBuffer :: WipeStartScreen
//
// Called before the current screen has started rendering. This needs to
// save what was drawn the previous frame so that it can be animated into
// what gets drawn this frame.
//
// In fullscreen mode, we use GetFrontBufferData() to grab the data that
// is visible on screen right now.
//
// In windowed mode, we can't do that because we'll get the whole desktop.
// Instead, we can conveniently use the TempRenderTexture, which is normally
// used for gamma-correcting copying the image to the back buffer.
//
//==========================================================================
bool OpenGLSWFrameBuffer::WipeStartScreen(int type)
{
if (!Accel2D)
{
return Super::WipeStartScreen(type);
}
switch (type)
{
case wipe_Melt:
ScreenWipe = new Wiper_Melt;
break;
case wipe_Burn:
ScreenWipe = new Wiper_Burn(this);
break;
case wipe_Fade:
ScreenWipe = new Wiper_Crossfade;
break;
default:
return false;
}
InitialWipeScreen = CopyCurrentScreen();
// Make even fullscreen model render to the TempRenderTexture, so
// we can have a copy of the new screen readily available.
GatheringWipeScreen = true;
return true;
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: WipeEndScreen
//
// The screen we want to animate to has just been drawn. This function is
// called in place of Update(), so it has not been Presented yet.
//
//==========================================================================
void OpenGLSWFrameBuffer::WipeEndScreen()
{
if (!Accel2D)
{
Super::WipeEndScreen();
return;
}
// Don't do anything if there is no starting point.
if (InitialWipeScreen == NULL)
{
return;
}
// If the whole screen was drawn without 2D accel, get it in to
// video memory now.
if (!In2D)
{
Begin2D(true);
}
EndBatch(); // Make sure all batched primitives have been drawn.
FinalWipeScreen = CopyCurrentScreen();
// At this point, InitialWipeScreen holds the screen we are wiping from.
// FinalWipeScreen holds the screen we are wiping to, which may be the
// same texture as TempRenderTexture.
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: WipeDo
//
// Perform the actual wipe animation. The number of tics since the last
// time this function was called is passed in. Returns true when the wipe
// is over. The first time this function has been called, the screen is
// still locked from before and EndScene() still has not been called.
// Successive times need to call BeginScene().
//
//==========================================================================
bool OpenGLSWFrameBuffer::WipeDo(int ticks)
{
if (!Accel2D)
{
return Super::WipeDo(ticks);
}
// Sanity checks.
if (InitialWipeScreen == NULL || FinalWipeScreen == NULL)
{
return true;
}
if (GatheringWipeScreen)
{ // This is the first time we've been called for this wipe.
GatheringWipeScreen = false;
}
else
{ // This is the second or later time we've been called for this wipe.
InScene = true;
}
In2D = 3;
EnableAlphaTest(false);
bool done = ScreenWipe->Run(ticks, this);
return done;
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: WipeCleanup
//
// Release any resources that were specifically created for the wipe.
//
//==========================================================================
void OpenGLSWFrameBuffer::WipeCleanup()
{
if (ScreenWipe != NULL)
{
delete ScreenWipe;
ScreenWipe = NULL;
}
SafeRelease( InitialWipeScreen );
SafeRelease( FinalWipeScreen );
GatheringWipeScreen = false;
if (!Accel2D)
{
Super::WipeCleanup();
return;
}
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: Wiper Constructor
//
//==========================================================================
OpenGLSWFrameBuffer::Wiper::~Wiper()
{
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: Wiper :: DrawScreen
//
// Draw either the initial or target screen completely to the screen.
//
//==========================================================================
void OpenGLSWFrameBuffer::Wiper::DrawScreen(OpenGLSWFrameBuffer *fb, HWTexture *tex,
int blendop, uint32_t color0, uint32_t color1)
{
FBVERTEX verts[4];
fb->CalcFullscreenCoords(verts, false, color0, color1);
fb->SetTexture(0, tex);
fb->SetAlphaBlend(blendop, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
fb->SetPixelShader(fb->Shaders[SHADER_NormalColor]);
fb->DrawTriangleFans(2, verts);
}
// WIPE: CROSSFADE ---------------------------------------------------------
//==========================================================================
//
// OpenGLSWFrameBuffer :: Wiper_Crossfade Constructor
//
//==========================================================================
OpenGLSWFrameBuffer::Wiper_Crossfade::Wiper_Crossfade()
: Clock(0)
{
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: Wiper_Crossfade :: Run
//
// Fades the old screen into the new one over 32 ticks.
//
//==========================================================================
bool OpenGLSWFrameBuffer::Wiper_Crossfade::Run(int ticks, OpenGLSWFrameBuffer *fb)
{
Clock += ticks;
// Put the initial screen back to the buffer.
DrawScreen(fb, fb->InitialWipeScreen);
// Draw the new screen on top of it.
DrawScreen(fb, fb->FinalWipeScreen, GL_FUNC_ADD, ColorValue(0,0,0,Clock / 32.f), ColorRGBA(255,255,255,0));
return Clock >= 32;
}
// WIPE: MELT --------------------------------------------------------------
//==========================================================================
//
// OpenGLSWFrameBuffer :: Wiper_Melt Constructor
//
//==========================================================================
OpenGLSWFrameBuffer::Wiper_Melt::Wiper_Melt()
{
int i, r;
// setup initial column positions
// (y<0 => not ready to scroll yet)
y[0] = -(M_Random() & 15);
for (i = 1; i < WIDTH; ++i)
{
r = (M_Random()%3) - 1;
y[i] = clamp(y[i-1] + r, -15, 0);
}
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: Wiper_Melt :: Run
//
// Fades the old screen into the new one over 32 ticks.
//
//==========================================================================
bool OpenGLSWFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLSWFrameBuffer *fb)
{
// Draw the new screen on the bottom.
DrawScreen(fb, fb->FinalWipeScreen);
int i, dy;
int fbwidth = fb->Width;
int fbheight = fb->Height;
bool done = true;
// Copy the old screen in vertical strips on top of the new one.
while (ticks--)
{
done = true;
for (i = 0; i < WIDTH; i++)
{
if (y[i] < 0)
{
y[i]++;
done = false;
}
else if (y[i] < HEIGHT)
{
dy = (y[i] < 16) ? y[i]+1 : 8;
y[i] = MIN(y[i] + dy, HEIGHT);
done = false;
}
if (ticks == 0)
{ // Only draw for the final tick.
LTRBRect rect;
struct Point { int x, y; } dpt;
dpt.x = i * fbwidth / WIDTH;
dpt.y = MAX(0, y[i] * fbheight / HEIGHT);
rect.left = dpt.x;
rect.top = 0;
rect.right = (i + 1) * fbwidth / WIDTH;
rect.bottom = fbheight - dpt.y;
if (rect.bottom > rect.top)
{
fb->CheckQuadBatch();
BufferedTris *quad = &fb->QuadExtra[fb->QuadBatchPos];
FBVERTEX *vert = &fb->VertexData[fb->VertexPos];
WORD *index = &fb->IndexData[fb->IndexPos];
quad->ClearSetup();
quad->Flags = BQF_DisableAlphaTest;
quad->ShaderNum = BQS_Plain;
quad->Palette = NULL;
quad->Texture = fb->InitialWipeScreen;
quad->NumVerts = 4;
quad->NumTris = 2;
// Fill the vertex buffer.
float u0 = rect.left / float(fb->Width);
float v0 = 0;
float u1 = rect.right / float(fb->Width);
float v1 = (rect.bottom - rect.top) / float(fb->Height);
float x0 = float(rect.left);
float x1 = float(rect.right);
float y0 = float(dpt.y);
float y1 = float(fbheight);
vert[0].x = x0;
vert[0].y = y0;
vert[0].z = 0;
vert[0].rhw = 1;
vert[0].color0 = 0;
vert[0].color1 = 0xFFFFFFF;
vert[0].tu = u0;
vert[0].tv = v0;
vert[1].x = x1;
vert[1].y = y0;
vert[1].z = 0;
vert[1].rhw = 1;
vert[1].color0 = 0;
vert[1].color1 = 0xFFFFFFF;
vert[1].tu = u1;
vert[1].tv = v0;
vert[2].x = x1;
vert[2].y = y1;
vert[2].z = 0;
vert[2].rhw = 1;
vert[2].color0 = 0;
vert[2].color1 = 0xFFFFFFF;
vert[2].tu = u1;
vert[2].tv = v1;
vert[3].x = x0;
vert[3].y = y1;
vert[3].z = 0;
vert[3].rhw = 1;
vert[3].color0 = 0;
vert[3].color1 = 0xFFFFFFF;
vert[3].tu = u0;
vert[3].tv = v1;
// Fill the vertex index buffer.
index[0] = fb->VertexPos;
index[1] = fb->VertexPos + 1;
index[2] = fb->VertexPos + 2;
index[3] = fb->VertexPos;
index[4] = fb->VertexPos + 2;
index[5] = fb->VertexPos + 3;
// Batch the quad.
fb->QuadBatchPos++;
fb->VertexPos += 4;
fb->IndexPos += 6;
}
}
}
}
fb->EndQuadBatch();
return done;
}
// WIPE: BURN --------------------------------------------------------------
//==========================================================================
//
// OpenGLSWFrameBuffer :: Wiper_Burn Constructor
//
//==========================================================================
OpenGLSWFrameBuffer::Wiper_Burn::Wiper_Burn(OpenGLSWFrameBuffer *fb)
{
Density = 4;
BurnTime = 0;
memset(BurnArray, 0, sizeof(BurnArray));
if (fb->Shaders[SHADER_BurnWipe] == NULL || !fb->CreateTexture("BurnWipe", WIDTH, HEIGHT, 1, GL_R8, &BurnTexture))
{
BurnTexture = NULL;
}
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: Wiper_Burn Destructor
//
//==========================================================================
OpenGLSWFrameBuffer::Wiper_Burn::~Wiper_Burn()
{
SafeRelease( BurnTexture );
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: Wiper_Burn :: Run
//
//==========================================================================
bool OpenGLSWFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLSWFrameBuffer *fb)
{
bool done;
BurnTime += ticks;
ticks *= 2;
// Make the fire burn
done = false;
while (!done && ticks--)
{
Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density);
done = (Density < 0);
}
// Update the burn texture with the new burn data
if (BurnTexture->Buffers[0] == 0)
{
glGenBuffers(2, (GLuint*)BurnTexture->Buffers);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, BurnTexture->Buffers[0]);
glBufferData(GL_PIXEL_UNPACK_BUFFER, WIDTH * HEIGHT, nullptr, GL_STREAM_DRAW);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, BurnTexture->Buffers[1]);
glBufferData(GL_PIXEL_UNPACK_BUFFER, WIDTH * HEIGHT, nullptr, GL_STREAM_DRAW);
}
else
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, BurnTexture->Buffers[BurnTexture->CurrentBuffer]);
BurnTexture->CurrentBuffer = (BurnTexture->CurrentBuffer + 1) & 1;
}
uint8_t *dest = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, WIDTH * HEIGHT, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
if (dest)
{
memcpy(dest, BurnArray, WIDTH * HEIGHT);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
GLint oldBinding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding);
glBindTexture(GL_TEXTURE_2D, BurnTexture->Texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT, GL_RED, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, oldBinding);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
// Put the initial screen back to the buffer.
DrawScreen(fb, fb->InitialWipeScreen);
// Burn the new screen on top of it.
float right = float(fb->Width);
float bot = float(fb->Height);
BURNVERTEX verts[4] =
{
{ 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0, 0 },
{ right, 0.f, 0.f, 1.f, 1.f, 0.f, 1, 0 },
{ right, bot, 0.f, 1.f, 1.f, 1.f, 1, 1 },
{ 0.f, bot, 0.f, 1.f, 0.f, 1.f, 0, 1 }
};
fb->SetTexture(0, fb->FinalWipeScreen);
fb->SetTexture(1, BurnTexture);
fb->SetAlphaBlend(GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
fb->SetPixelShader(fb->Shaders[SHADER_BurnWipe]);
glActiveTexture(GL_TEXTURE1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
fb->DrawTriangleFans(2, verts);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glActiveTexture(GL_TEXTURE0);
// The fire may not always stabilize, so the wipe is forced to end
// after an arbitrary maximum time.
return done || (BurnTime > 40);
}

View file

@ -56,6 +56,7 @@
#include "menu/menu.h"
#include "textures/textures.h"
#include "virtual.h"
#include "events.h"
//
// Todo: Move these elsewhere
@ -173,15 +174,31 @@ DMenu::DMenu(DMenu *parent)
bool DMenu::CallResponder(event_t *ev)
{
IFVIRTUAL(DMenu, Responder)
if (ev->type == EV_GUI_Event)
{
VMValue params[] = { (DObject*)this, ev};
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr);
return !!retval;
IFVIRTUAL(DMenu, OnUIEvent)
{
FUiEvent e = ev;
VMValue params[] = { (DObject*)this, &e };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr);
return !!retval;
}
}
else return false;
else
{
IFVIRTUAL(DMenu, OnInputEvent)
{
FInputEvent e = ev;
VMValue params[] = { (DObject*)this, &e };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr);
return !!retval;
}
}
return false;
}
//=============================================================================

View file

@ -129,8 +129,6 @@ static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flag
ffloor->top.copied = ffloor->bottom.copied = false;
ffloor->top.model = ffloor->bottom.model = ffloor->model = sec2;
ffloor->target = sec;
ffloor->ceilingclip = ffloor->floorclip = NULL;
ffloor->validcount = 0;
if (!(flags&FF_THINFLOOR))
{

View file

@ -95,11 +95,6 @@ struct F3DFloor
int lastlight;
int alpha;
// kg3D - for software
short *floorclip;
short *ceilingclip;
int validcount;
FDynamicColormap *GetColormap();
void UpdateColormap(FDynamicColormap *&map);
PalEntry GetBlend();

View file

@ -31,6 +31,8 @@
**
*/
#pragma once
#include "vectors.h"
#define FX_ROCKET 0x00000001

View file

@ -120,6 +120,8 @@ DEFINE_FIELD(DPSprite, oldx)
DEFINE_FIELD(DPSprite, oldy)
DEFINE_FIELD(DPSprite, firstTic)
DEFINE_FIELD(DPSprite, Tics)
DEFINE_FIELD(DPSprite, alpha)
DEFINE_FIELD(DPSprite, RenderStyle)
DEFINE_FIELD_BIT(DPSprite, Flags, bAddWeapon, PSPF_ADDWEAPON)
DEFINE_FIELD_BIT(DPSprite, Flags, bAddBob, PSPF_ADDBOB)
DEFINE_FIELD_BIT(DPSprite, Flags, bPowDouble, PSPF_POWDOUBLE)
@ -141,7 +143,9 @@ DPSprite::DPSprite(player_t *owner, AActor *caller, int id)
Owner(owner),
Sprite(0),
ID(id),
processPending(true)
processPending(true),
alpha(1),
RenderStyle(STYLE_Normal)
{
DPSprite *prev = nullptr;
DPSprite *next = Owner->psprites;
@ -1037,7 +1041,7 @@ void A_OverlayOffset(AActor *self, int layer, double wx, double wy, int flags)
player_t *player = self->player;
DPSprite *psp;
if (player && (player->playerstate != PST_DEAD))
if (player)
{
psp = player->FindPSprite(layer);
@ -1184,7 +1188,69 @@ DEFINE_ACTION_FUNCTION(AActor, OverlayID)
ACTION_RETURN_INT(0);
}
//---------------------------------------------------------------------------
//
// PROC A_OverlayAlpha
// Sets the alpha of an overlay.
//---------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_OverlayAlpha)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_INT(layer);
PARAM_FLOAT(alph);
if (ACTION_CALL_FROM_PSPRITE())
{
DPSprite *pspr = self->player->FindPSprite((layer != 0) ? layer : stateinfo->mPSPIndex);
if (pspr != nullptr)
pspr->alpha = clamp<double>(alph, 0.0, 1.0);
}
return 0;
}
// NON-ACTION function to get the overlay alpha of a layer.
DEFINE_ACTION_FUNCTION(AActor, OverlayAlpha)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_INT_DEF(layer);
if (ACTION_CALL_FROM_PSPRITE())
{
DPSprite *pspr = self->player->FindPSprite((layer != 0) ? layer : stateinfo->mPSPIndex);
if (pspr != nullptr)
{
ACTION_RETURN_FLOAT(pspr->alpha);
}
}
ACTION_RETURN_FLOAT(0.0);
}
//---------------------------------------------------------------------------
//
// PROC A_OverlayRenderStyle
//
//---------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_OverlayRenderStyle)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_INT(layer);
PARAM_INT(style);
if (ACTION_CALL_FROM_PSPRITE())
{
DPSprite *pspr = self->player->FindPSprite((layer != 0) ? layer : stateinfo->mPSPIndex);
if (pspr == nullptr || style >= STYLE_Count || style < 0)
return 0;
pspr->RenderStyle = style;
}
return 0;
}
//---------------------------------------------------------------------------
//
@ -1414,7 +1480,9 @@ void DPSprite::Serialize(FSerializer &arc)
("x", x)
("y", y)
("oldx", oldx)
("oldy", oldy);
("oldy", oldy)
("alpha", alpha)
("renderstyle", RenderStyle);
}
//------------------------------------------------------------------------

View file

@ -50,11 +50,15 @@ enum PSPLayers
enum PSPFlags
{
PSPF_ADDWEAPON = 1 << 0,
PSPF_ADDBOB = 1 << 1,
PSPF_POWDOUBLE = 1 << 2,
PSPF_CVARFAST = 1 << 3,
PSPF_FLIP = 1 << 6,
PSPF_ADDWEAPON = 1 << 0,
PSPF_ADDBOB = 1 << 1,
PSPF_POWDOUBLE = 1 << 2,
PSPF_CVARFAST = 1 << 3,
PSPF_ALPHA = 1 << 4,
PSPF_RENDERSTYLE = 1 << 5,
PSPF_FLIP = 1 << 6,
PSPF_FORCEALPHA = 1 << 7,
PSPF_FORCESTYLE = 1 << 8,
};
class DPSprite : public DObject
@ -78,11 +82,12 @@ public:
void ResetInterpolation() { oldx = x; oldy = y; }
void OnDestroy() override;
double x, y;
double x, y, alpha;
double oldx, oldy;
bool firstTic;
int Tics;
int Flags;
int RenderStyle;
private:
DPSprite () {}

View file

@ -2039,11 +2039,12 @@ void P_CalcHeight (player_t *player)
return;
}
//[SP] Added (x*player->mo->ViewBob) to allow DECORATE changes to view bobbing speed.
if (still)
{
if (player->health > 0)
{
angle = level.time / (120 * TICRATE / 35.) * 360.;
angle = level.time / (120 * TICRATE / 35.) * 360. * player->mo->ViewBob;
bob = player->userinfo.GetStillBob() * angle.Sin();
}
else
@ -2053,7 +2054,7 @@ void P_CalcHeight (player_t *player)
}
else
{
angle = level.time / (20 * TICRATE / 35.) * 360.;
angle = level.time / (20 * TICRATE / 35.) * 360. * player->mo->ViewBob;
bob = player->bob * angle.Sin() * (player->mo->waterlevel > 1 ? 0.25f : 0.5f);
}

View file

@ -0,0 +1,100 @@
/*
** Triangle drawers
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stddef.h>
#include "templates.h"
#include "doomdef.h"
#include "i_system.h"
#include "w_wad.h"
#include "v_video.h"
#include "doomstat.h"
#include "st_stuff.h"
#include "g_game.h"
#include "g_level.h"
#include "r_data/r_translate.h"
#include "v_palette.h"
#include "r_data/colormaps.h"
#include "poly_buffer.h"
#include "screen_triangle.h"
/////////////////////////////////////////////////////////////////////////////
PolySubsectorGBuffer *PolySubsectorGBuffer::Instance()
{
static PolySubsectorGBuffer buffer;
return &buffer;
}
void PolySubsectorGBuffer::Resize(int newwidth, int newheight)
{
width = newwidth;
height = newheight;
values.resize(width * height);
}
/////////////////////////////////////////////////////////////////////////////
PolyStencilBuffer *PolyStencilBuffer::Instance()
{
static PolyStencilBuffer buffer;
return &buffer;
}
void PolyStencilBuffer::Clear(int newwidth, int newheight, uint8_t stencil_value)
{
width = newwidth;
height = newheight;
int count = BlockWidth() * BlockHeight();
values.resize(count * 64);
masks.resize(count);
uint8_t *v = Values();
uint32_t *m = Masks();
for (int i = 0; i < count; i++)
{
m[i] = 0xffffff00 | stencil_value;
}
}
/////////////////////////////////////////////////////////////////////////////
namespace
{
int NextBufferVertex = 0;
}
TriVertex *PolyVertexBuffer::GetVertices(int count)
{
enum { VertexBufferSize = 256 * 1024 };
static TriVertex Vertex[VertexBufferSize];
if (NextBufferVertex + count > VertexBufferSize)
return nullptr;
TriVertex *v = Vertex + NextBufferVertex;
NextBufferVertex += count;
return v;
}
void PolyVertexBuffer::Clear()
{
NextBufferVertex = 0;
}

View file

@ -0,0 +1,68 @@
/*
** Frame buffers
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
struct TriVertex;
class PolySubsectorGBuffer
{
public:
static PolySubsectorGBuffer *Instance();
void Resize(int newwidth, int newheight);
int Width() const { return width; }
int Height() const { return height; }
uint32_t *Values() { return values.data(); }
private:
int width;
int height;
std::vector<uint32_t> values;
};
class PolyStencilBuffer
{
public:
static PolyStencilBuffer *Instance();
void Clear(int newwidth, int newheight, uint8_t stencil_value = 0);
int Width() const { return width; }
int Height() const { return height; }
int BlockWidth() const { return (width + 7) / 8; }
int BlockHeight() const { return (height + 7) / 8; }
uint8_t *Values() { return values.data(); }
uint32_t *Masks() { return masks.data(); }
private:
int width;
int height;
// 8x8 blocks of stencil values, plus a mask for each block indicating if values are the same for early out stencil testing
std::vector<uint8_t> values;
std::vector<uint32_t> masks;
};
class PolyVertexBuffer
{
public:
static TriVertex *GetVertices(int count);
static void Clear();
};

View file

@ -0,0 +1,107 @@
/*
** Triangle drawers
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stddef.h>
#include "templates.h"
#include "doomdef.h"
#include "i_system.h"
#include "w_wad.h"
#include "v_video.h"
#include "doomstat.h"
#include "st_stuff.h"
#include "g_game.h"
#include "g_level.h"
#include "r_data/r_translate.h"
#include "v_palette.h"
#include "r_data/colormaps.h"
#include "poly_draw_args.h"
#include "swrenderer/viewport/r_viewport.h"
void PolyDrawArgs::SetClipPlane(float a, float b, float c, float d)
{
clipPlane[0] = a;
clipPlane[1] = b;
clipPlane[2] = c;
clipPlane[3] = d;
}
void PolyDrawArgs::SetTexture(FTexture *texture)
{
textureWidth = texture->GetWidth();
textureHeight = texture->GetHeight();
auto viewport = swrenderer::RenderViewport::Instance();
if (viewport->RenderTarget->IsBgra())
texturePixels = (const uint8_t *)texture->GetPixelsBgra();
else
texturePixels = texture->GetPixels();
translation = nullptr;
}
void PolyDrawArgs::SetTexture(FTexture *texture, uint32_t translationID, bool forcePal)
{
if (translationID != 0xffffffff && translationID != 0)
{
FRemapTable *table = TranslationToTable(translationID);
if (table != nullptr && !table->Inactive)
{
if (swrenderer::RenderViewport::Instance()->RenderTarget->IsBgra())
translation = (uint8_t*)table->Palette;
else
translation = table->Remap;
textureWidth = texture->GetWidth();
textureHeight = texture->GetHeight();
texturePixels = texture->GetPixels();
return;
}
}
if (forcePal)
{
textureWidth = texture->GetWidth();
textureHeight = texture->GetHeight();
texturePixels = texture->GetPixels();
}
else
{
SetTexture(texture);
}
}
void PolyDrawArgs::SetColormap(FSWColormap *base_colormap)
{
uniforms.light_red = base_colormap->Color.r * 256 / 255;
uniforms.light_green = base_colormap->Color.g * 256 / 255;
uniforms.light_blue = base_colormap->Color.b * 256 / 255;
uniforms.light_alpha = base_colormap->Color.a * 256 / 255;
uniforms.fade_red = base_colormap->Fade.r;
uniforms.fade_green = base_colormap->Fade.g;
uniforms.fade_blue = base_colormap->Fade.b;
uniforms.fade_alpha = base_colormap->Fade.a;
uniforms.desaturate = MIN(abs(base_colormap->Desaturate), 255) * 255 / 256;
bool simple_shade = (base_colormap->Color.d == 0x00ffffff && base_colormap->Fade.d == 0x00000000 && base_colormap->Desaturate == 0);
if (simple_shade)
uniforms.flags |= TriUniforms::simple_shade;
else
uniforms.flags &= ~TriUniforms::simple_shade;
colormaps = base_colormap->Maps;
}

View file

@ -0,0 +1,69 @@
/*
** Triangle drawers
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "r_data/r_translate.h"
#include "r_data/colormaps.h"
#include "screen_triangle.h"
class FTexture;
enum class TriangleDrawMode
{
Normal,
Fan,
Strip
};
struct TriDrawTriangleArgs;
struct TriMatrix;
class PolyDrawArgs
{
public:
TriUniforms uniforms;
const TriMatrix *objectToClip = nullptr;
const TriVertex *vinput = nullptr;
int vcount = 0;
TriangleDrawMode mode = TriangleDrawMode::Normal;
bool ccw = false;
// bool stencilTest = true; // Always true for now
bool subsectorTest = false;
bool writeStencil = true;
bool writeColor = true;
bool writeSubsector = true;
const uint8_t *texturePixels = nullptr;
int textureWidth = 0;
int textureHeight = 0;
const uint8_t *translation = nullptr;
uint8_t stenciltestvalue = 0;
uint8_t stencilwritevalue = 0;
const uint8_t *colormaps = nullptr;
float clipPlane[4];
TriBlendMode blendmode = TriBlendMode::Copy;
void SetClipPlane(float a, float b, float c, float d);
void SetTexture(FTexture *texture);
void SetTexture(FTexture *texture, uint32_t translationID, bool forcePal = false);
void SetColormap(FSWColormap *base_colormap);
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,449 @@
/*
** Projected triangle drawer
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
/*
Warning: this C++ source file has been auto-generated. Please modify the original php script that generated it.
*/
#pragma once
#include "screen_triangle.h"
static float FindGradientX(float x0, float y0, float x1, float y1, float x2, float y2, float c0, float c1, float c2)
{
float top = (c1 - c2) * (y0 - y2) - (c0 - c2) * (y1 - y2);
float bottom = (x1 - x2) * (y0 - y2) - (x0 - x2) * (y1 - y2);
return top / bottom;
}
static float FindGradientY(float x0, float y0, float x1, float y1, float x2, float y2, float c0, float c1, float c2)
{
float top = (c1 - c2) * (x0 - x2) - (c0 - c2) * (x1 - x2);
float bottom = (x0 - x2) * (y1 - y2) - (x1 - x2) * (y0 - y2);
return top / bottom;
}
<?
OutputDrawers(true, true, false);
OutputDrawers(true, false, false);
OutputDrawers(false, true, false);
OutputDrawers(false, false, false);
OutputDrawers(true, true, true);
OutputDrawers(true, false, true);
OutputDrawers(false, true, true);
OutputDrawers(false, false, true);
function OutputDrawers($isTruecolor, $isColorFill, $isListEntry)
{
$namePrefix = "";
if ($isTruecolor == true && $isColorFill == true)
{
$namePrefix = "TriFill32";
}
else if ($isTruecolor == true)
{
$namePrefix = "TriDraw32";
}
else if ($isColorFill == true)
{
$namePrefix = "TriFill8";
}
else
{
$namePrefix = "TriDraw8";
}
if ($isListEntry)
{ ?>
std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> ScreenTriangle::<?=$namePrefix?> =
{
<? }
OutputDrawer($namePrefix."Copy", "opaque", false, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."AlphaBlend", "masked", false, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."AddSolid", "translucent", false, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."Add", "add", false, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."Sub", "sub", false, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."RevSub", "revsub", false, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."Stencil", "stencil", false, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."Shaded", "shaded", false, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."TranslateCopy", "opaque", true, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."TranslateAlphaBlend", "masked", true, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."TranslateAdd", "add", true, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."TranslateSub", "sub", true, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."TranslateRevSub", "revsub", true, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."AddSrcColorOneMinusSrcColor", "addsrccolor", false, $isTruecolor, $isColorFill, $isListEntry);
OutputDrawer($namePrefix."Skycap", "skycap", false, $isTruecolor, $isColorFill, $isListEntry);
if ($isListEntry)
{ ?>
};
<? }
}
function OutputDrawer($drawerName, $blendmode, $isTranslated, $isTruecolor, $isColorFill, $isListEntry)
{
if ($isListEntry)
{ ?>
&<?=$drawerName?>,
<? }
else
{
GenerateDrawer($drawerName, $blendmode, $isTranslated, $isTruecolor, $isColorFill);
}
}
function GenerateDrawer($drawerName, $blendmode, $isTranslated, $isTruecolor, $isColorFill)
{
$pixeltype = $isTruecolor ? "uint32_t" : "uint8_t";
?>
static void <?=$drawerName?>(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
{
int numSpans = thread->NumFullSpans;
auto fullSpans = thread->FullSpans;
int numBlocks = thread->NumPartialBlocks;
auto partialBlocks = thread->PartialBlocks;
int startX = thread->StartX;
int startY = thread->StartY;
auto flags = args->uniforms->flags;
bool is_simple_shade = (flags & TriUniforms::simple_shade) == TriUniforms::simple_shade;
bool is_nearest_filter = (flags & TriUniforms::nearest_filter) == TriUniforms::nearest_filter;
bool is_fixed_light = (flags & TriUniforms::fixed_light) == TriUniforms::fixed_light;
uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff;
auto colormaps = args->colormaps;
uint32_t srcalpha = args->uniforms->srcalpha;
uint32_t destalpha = args->uniforms->destalpha;
// Calculate gradients
const TriVertex &v1 = *args->v1;
const TriVertex &v2 = *args->v2;
const TriVertex &v3 = *args->v3;
ScreenTriangleStepVariables gradientX;
ScreenTriangleStepVariables gradientY;
ScreenTriangleStepVariables start;
gradientX.W = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w);
gradientY.W = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w);
start.W = v1.w + gradientX.W * (startX - v1.x) + gradientY.W * (startY - v1.y);
for (int i = 0; i < TriVertex::NumVarying; i++)
{
gradientX.Varying[i] = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.varying[i] * v1.w, v2.varying[i] * v2.w, v3.varying[i] * v3.w);
gradientY.Varying[i] = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.varying[i] * v1.w, v2.varying[i] * v2.w, v3.varying[i] * v3.w);
start.Varying[i] = v1.varying[i] * v1.w + gradientX.Varying[i] * (startX - v1.x) + gradientY.Varying[i] * (startY - v1.y);
}
<? if ($isTranslated || $blendmode == "shaded")
{ ?>
const uint8_t * RESTRICT texPixels = args->texturePixels;
const <?=$pixeltype?> * RESTRICT translation = (const <?=$pixeltype?> *)args->translation;
<? }
else
{ ?>
const <?=$pixeltype?> * RESTRICT texPixels = (const <?=$pixeltype?> *)args->texturePixels;
<? }?>
uint32_t texWidth = args->textureWidth;
uint32_t texHeight = args->textureHeight;
<?=$pixeltype?> * RESTRICT destOrg = (<?=$pixeltype?>*)args->dest;
int pitch = args->pitch;
uint32_t light = args->uniforms->light;
float shade = (64.0f - (light * 255 / 256 + 12.0f) * 32.0f / 128.0f) / 32.0f;
float globVis = args->uniforms->globvis * (1.0f / 32.0f);
<?=$pixeltype?> color = args->uniforms->color;
for (int i = 0; i < numSpans; i++)
{
const auto &span = fullSpans[i];
<?=$pixeltype?> *dest = destOrg + span.X + span.Y * pitch;
int width = span.Length;
int height = 8;
ScreenTriangleStepVariables blockPosY;
blockPosY.W = start.W + gradientX.W * (span.X - startX) + gradientY.W * (span.Y - startY);
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosY.Varying[j] = start.Varying[j] + gradientX.Varying[j] * (span.X - startX) + gradientY.Varying[j] * (span.Y - startY);
for (int y = 0; y < height; y++)
{
ScreenTriangleStepVariables blockPosX = blockPosY;
float rcpW = 0x01000000 / blockPosX.W;
int32_t varyingPos[TriVertex::NumVarying];
for (int j = 0; j < TriVertex::NumVarying; j++)
varyingPos[j] = (int32_t)(blockPosX.Varying[j] * rcpW);
int 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);
for (int x = 0; x < width; x++)
{
blockPosX.W += gradientX.W * 8;
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosX.Varying[j] += gradientX.Varying[j] * 8;
rcpW = 0x01000000 / blockPosX.W;
int32_t varyingStep[TriVertex::NumVarying];
for (int j = 0; j < TriVertex::NumVarying; j++)
{
int32_t nextPos = (int32_t)(blockPosX.Varying[j] * rcpW);
varyingStep[j] = (nextPos - varyingPos[j]) / 8;
}
int lightnext = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT);
int lightstep = (lightnext - lightpos) / 8;
lightstep = lightstep & lightmask;
for (int ix = 0; ix < 8; ix++)
{
<?=$pixeltype?> *destptr = dest + x * 8 + ix;
<? ProcessPixel($blendmode, $isTranslated, $isTruecolor, $isColorFill, $pixeltype); ?>
*destptr = fg;
for (int j = 0; j < TriVertex::NumVarying; j++)
varyingPos[j] += varyingStep[j];
lightpos += lightstep;
}
}
blockPosY.W += gradientY.W;
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosY.Varying[j] += gradientY.Varying[j];
dest += pitch;
}
}
for (int i = 0; i < numBlocks; i++)
{
const auto &block = partialBlocks[i];
ScreenTriangleStepVariables blockPosY;
blockPosY.W = start.W + gradientX.W * (block.X - startX) + gradientY.W * (block.Y - startY);
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosY.Varying[j] = start.Varying[j] + gradientX.Varying[j] * (block.X - startX) + gradientY.Varying[j] * (block.Y - startY);
<?=$pixeltype?> *dest = destOrg + block.X + block.Y * pitch;
uint32_t mask0 = block.Mask0;
uint32_t mask1 = block.Mask1;
<?
for ($i = 0; $i < 2; $i++)
{
$coveragemask = ($i == 0) ? "mask0" : "mask1";
?>
for (int y = 0; y < 4; y++)
{
ScreenTriangleStepVariables blockPosX = blockPosY;
float rcpW = 0x01000000 / blockPosX.W;
int32_t varyingPos[TriVertex::NumVarying];
for (int j = 0; j < TriVertex::NumVarying; j++)
varyingPos[j] = (int32_t)(blockPosX.Varying[j] * rcpW);
int 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);
blockPosX.W += gradientX.W * 8;
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosX.Varying[j] += gradientX.Varying[j] * 8;
rcpW = 0x01000000 / blockPosX.W;
int32_t varyingStep[TriVertex::NumVarying];
for (int j = 0; j < TriVertex::NumVarying; j++)
{
int32_t nextPos = (int32_t)(blockPosX.Varying[j] * rcpW);
varyingStep[j] = (nextPos - varyingPos[j]) / 8;
}
int lightnext = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT);
int lightstep = (lightnext - lightpos) / 8;
lightstep = lightstep & lightmask;
for (int x = 0; x < 8; x++)
{
if (<?=$coveragemask?> & (1 << 31))
{
<?=$pixeltype?> *destptr = dest + x;
<? ProcessPixel($blendmode, $isTranslated, $isTruecolor, $isColorFill, $pixeltype); ?>
*destptr = fg;
}
<?=$coveragemask?> <<= 1;
for (int j = 0; j < TriVertex::NumVarying; j++)
varyingPos[j] += varyingStep[j];
lightpos += lightstep;
}
blockPosY.W += gradientY.W;
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosY.Varying[j] += gradientY.Varying[j];
dest += pitch;
}
<? } ?>
}
}
<?
}
function ProcessPixel($blendmode, $isTranslated, $isTruecolor, $isColorFill, $pixeltype)
{
if ($isColorFill || $blendmode == "shaded")
{ ?>
<?=$pixeltype?> fg = color;
<? }
else
{ ?>
int texelX = ((((uint32_t)varyingPos[0] << 8) >> 16) * texWidth) >> 16;
int texelY = ((((uint32_t)varyingPos[1] << 8) >> 16) * texHeight) >> 16;
<?=$pixeltype?> fg = texPixels[texelX * texHeight + texelY];
<? }
if ($isTranslated)
{ ?>
fg = translation[fg];
<? }
if ($isTruecolor)
{ ?>
uint32_t r = RPART(fg);
uint32_t g = GPART(fg);
uint32_t b = BPART(fg);
r = (r * lightpos) >> 16;
g = (g * lightpos) >> 16;
b = (b * lightpos) >> 16;
<? TruecolorBlend($blendmode); ?>
fg = 0xff000000 | (r << 16) | (g << 8) | b;
<?
}
else
{ ?>
int colormapindex = MIN(((256 - (lightpos >> 8)) * 32) >> 8, 31) << 8;
fg = colormaps[colormapindex + fg];
<? }
}
function TruecolorBlend($blendmode)
{
if ($blendmode == "opaque")
{
}
else if ($blendmode == "masked")
{ ?>
uint32_t a = APART(fg);
a += a >> 7;
uint32_t inv_a = 256 - a;
uint32_t bg = *destptr;
uint32_t bg_red = RPART(bg);
uint32_t bg_green = GPART(bg);
uint32_t bg_blue = BPART(bg);
r = (r * a + bg_red * inv_a + 127) >> 8;
g = (g * a + bg_green * inv_a + 127) >> 8;
b = (b * a + bg_blue * inv_a + 127) >> 8;
<? }
else if ($blendmode == "translucent")
{ ?>
<? }
else if ($blendmode == "shaded")
{ ?>
int texelX = ((((uint32_t)varyingPos[0] << 8) >> 16) * texWidth) >> 16;
int texelY = ((((uint32_t)varyingPos[1] << 8) >> 16) * texHeight) >> 16;
int sample = texPixels[texelX * texHeight + texelY];
uint32_t fgalpha = sample;//clamp(sample, 0, 64) * 4;
uint32_t inv_fgalpha = 256 - fgalpha;
int a = (fgalpha * srcalpha + 128) >> 8;
int inv_a = (destalpha * fgalpha + 256 * inv_fgalpha + 128) >> 8;
uint32_t bg = *destptr;
uint32_t bg_red = RPART(bg);
uint32_t bg_green = GPART(bg);
uint32_t bg_blue = BPART(bg);
r = (r * a + bg_red * inv_a + 127) >> 8;
g = (g * a + bg_green * inv_a + 127) >> 8;
b = (b * a + bg_blue * inv_a + 127) >> 8;
<? }
else if ($blendmode == "stencil")
{ ?>
uint32_t fgalpha = APART(fg);
uint32_t inv_fgalpha = 256 - fgalpha;
int a = (fgalpha * srcalpha + 128) >> 8;
int inv_a = (destalpha * fgalpha + 256 * inv_fgalpha + 128) >> 8;
uint32_t bg = *destptr;
uint32_t bg_red = RPART(bg);
uint32_t bg_green = GPART(bg);
uint32_t bg_blue = BPART(bg);
r = (r * a + bg_red * inv_a + 127) >> 8;
g = (g * a + bg_green * inv_a + 127) >> 8;
b = (b * a + bg_blue * inv_a + 127) >> 8;
<? }
else if ($blendmode == "addsrccolor")
{ ?>
uint32_t inv_r = 256 - (r + (r >> 7));
uint32_t inv_g = 256 - (g + (r >> 7));
uint32_t inv_b = 256 - (b + (r >> 7));
uint32_t bg = *destptr;
uint32_t bg_red = RPART(bg);
uint32_t bg_green = GPART(bg);
uint32_t bg_blue = BPART(bg);
r = r + ((bg_red * inv_r + 127) >> 8);
g = g + ((bg_green * inv_g + 127) >> 8);
b = b + ((bg_blue * inv_b + 127) >> 8);
<? }
else if ($blendmode == "skycap")
{ ?>
int start_fade = 2; // How fast it should fade out
int alpha_top = clamp(varyingPos[1] >> (16 - start_fade), 0, 256);
int alpha_bottom = clamp(((2 << 24) - varyingPos[1]) >> (16 - start_fade), 0, 256);
int a = MIN(alpha_top, alpha_bottom);
int inv_a = 256 - a;
uint32_t bg_red = RPART(color);
uint32_t bg_green = GPART(color);
uint32_t bg_blue = BPART(color);
r = (r * a + bg_red * inv_a + 127) >> 8;
g = (g * a + bg_green * inv_a + 127) >> 8;
b = (b * a + bg_blue * inv_a + 127) >> 8;
<? }
else
{ ?>
uint32_t a = APART(fg);
a += a >> 7;
uint32_t inv_a = 256 - a;
uint32_t bg = *destptr;
uint32_t bg_red = RPART(bg);
uint32_t bg_green = GPART(bg);
uint32_t bg_blue = BPART(bg);
r = (r * a + bg_red * inv_a + 127) >> 8;
g = (g * a + bg_green * inv_a + 127) >> 8;
b = (b * a + bg_blue * inv_a + 127) >> 8;
<? }
}
?>

View file

@ -0,0 +1,413 @@
/*
** Triangle drawers
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stddef.h>
#include "templates.h"
#include "doomdef.h"
#include "i_system.h"
#include "w_wad.h"
#include "v_video.h"
#include "doomstat.h"
#include "st_stuff.h"
#include "g_game.h"
#include "g_level.h"
#include "r_data/r_translate.h"
#include "v_palette.h"
#include "r_data/colormaps.h"
#include "poly_triangle.h"
#include "polyrenderer/poly_renderer.h"
#include "swrenderer/drawers/r_draw_rgba.h"
#include "screen_triangle.h"
CVAR(Bool, r_debug_trisetup, false, 0);
int PolyTriangleDrawer::viewport_x;
int PolyTriangleDrawer::viewport_y;
int PolyTriangleDrawer::viewport_width;
int PolyTriangleDrawer::viewport_height;
int PolyTriangleDrawer::dest_pitch;
int PolyTriangleDrawer::dest_width;
int PolyTriangleDrawer::dest_height;
uint8_t *PolyTriangleDrawer::dest;
bool PolyTriangleDrawer::dest_bgra;
bool PolyTriangleDrawer::mirror;
void PolyTriangleDrawer::set_viewport(int x, int y, int width, int height, DCanvas *canvas)
{
dest = (uint8_t*)canvas->GetBuffer();
dest_width = canvas->GetWidth();
dest_height = canvas->GetHeight();
dest_pitch = canvas->GetPitch();
dest_bgra = canvas->IsBgra();
int offsetx = clamp(x, 0, dest_width);
int offsety = clamp(y, 0, dest_height);
int pixelsize = dest_bgra ? 4 : 1;
viewport_x = x - offsetx;
viewport_y = y - offsety;
viewport_width = width;
viewport_height = height;
dest += (offsetx + offsety * dest_pitch) * pixelsize;
dest_width = clamp(viewport_x + viewport_width, 0, dest_width - offsetx);
dest_height = clamp(viewport_y + viewport_height, 0, dest_height - offsety);
mirror = false;
}
void PolyTriangleDrawer::toggle_mirror()
{
mirror = !mirror;
}
void PolyTriangleDrawer::draw(const PolyDrawArgs &args)
{
PolyRenderer::Instance()->Thread.DrawQueue->Push<DrawPolyTrianglesCommand>(args, mirror);
}
void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadData *thread)
{
if (drawargs.vcount < 3)
return;
PolyDrawFuncPtr drawfuncs[4];
int num_drawfuncs = 0;
drawfuncs[num_drawfuncs++] = drawargs.subsectorTest ? &ScreenTriangle::SetupSubsector : &ScreenTriangle::SetupNormal;
if (!r_debug_trisetup) // For profiling how much time is spent in setup vs drawal
{
int bmode = (int)drawargs.blendmode;
if (drawargs.writeColor && drawargs.texturePixels)
drawfuncs[num_drawfuncs++] = dest_bgra ? ScreenTriangle::TriDraw32[bmode] : ScreenTriangle::TriDraw8[bmode];
else if (drawargs.writeColor)
drawfuncs[num_drawfuncs++] = dest_bgra ? ScreenTriangle::TriFill32[bmode] : ScreenTriangle::TriFill8[bmode];
}
if (drawargs.writeStencil)
drawfuncs[num_drawfuncs++] = &ScreenTriangle::StencilWrite;
if (drawargs.writeSubsector)
drawfuncs[num_drawfuncs++] = &ScreenTriangle::SubsectorWrite;
TriDrawTriangleArgs args;
args.dest = dest;
args.pitch = dest_pitch;
args.clipleft = 0;
args.clipright = dest_width;
args.cliptop = 0;
args.clipbottom = dest_height;
args.texturePixels = drawargs.texturePixels;
args.textureWidth = drawargs.textureWidth;
args.textureHeight = drawargs.textureHeight;
args.translation = drawargs.translation;
args.uniforms = &drawargs.uniforms;
args.stencilTestValue = drawargs.stenciltestvalue;
args.stencilWriteValue = drawargs.stencilwritevalue;
args.stencilPitch = PolyStencilBuffer::Instance()->BlockWidth();
args.stencilValues = PolyStencilBuffer::Instance()->Values();
args.stencilMasks = PolyStencilBuffer::Instance()->Masks();
args.subsectorGBuffer = PolySubsectorGBuffer::Instance()->Values();
args.colormaps = drawargs.colormaps;
args.RGB256k = RGB256k.All;
args.BaseColors = (const uint8_t *)GPalette.BaseColors;
bool ccw = drawargs.ccw;
const TriVertex *vinput = drawargs.vinput;
int vcount = drawargs.vcount;
ShadedTriVertex vert[3];
if (drawargs.mode == TriangleDrawMode::Normal)
{
for (int i = 0; i < vcount / 3; i++)
{
for (int j = 0; j < 3; j++)
vert[j] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
draw_shaded_triangle(vert, ccw, &args, thread, drawfuncs, num_drawfuncs);
}
}
else if (drawargs.mode == TriangleDrawMode::Fan)
{
vert[0] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
vert[1] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
for (int i = 2; i < vcount; i++)
{
vert[2] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
draw_shaded_triangle(vert, ccw, &args, thread, drawfuncs, num_drawfuncs);
vert[1] = vert[2];
}
}
else // TriangleDrawMode::Strip
{
vert[0] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
vert[1] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
for (int i = 2; i < vcount; i++)
{
vert[2] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++));
draw_shaded_triangle(vert, ccw, &args, thread, drawfuncs, num_drawfuncs);
vert[0] = vert[1];
vert[1] = vert[2];
ccw = !ccw;
}
}
}
ShadedTriVertex PolyTriangleDrawer::shade_vertex(const TriMatrix &objectToClip, const float *clipPlane, const TriVertex &v)
{
// Apply transform to get clip coordinates:
ShadedTriVertex sv = objectToClip * v;
// Calculate gl_ClipDistance[0]
sv.clipDistance0 = v.x * clipPlane[0] + v.y * clipPlane[1] + v.z * clipPlane[2] + v.w * clipPlane[3];
return sv;
}
void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread, PolyDrawFuncPtr *drawfuncs, int num_drawfuncs)
{
// Cull, clip and generate additional vertices as needed
TriVertex clippedvert[max_additional_vertices];
int numclipvert;
clipedge(vert, clippedvert, numclipvert);
// Map to 2D viewport:
for (int j = 0; j < numclipvert; j++)
{
auto &v = clippedvert[j];
// Calculate normalized device coordinates:
v.w = 1.0f / v.w;
v.x *= v.w;
v.y *= v.w;
v.z *= v.w;
// Apply viewport scale to get screen coordinates:
v.x = viewport_x + viewport_width * (1.0f + v.x) * 0.5f;
v.y = viewport_y + viewport_height * (1.0f - v.y) * 0.5f;
}
// Keep varyings in -128 to 128 range if possible
if (numclipvert > 0)
{
for (int j = 0; j < TriVertex::NumVarying; j++)
{
float newOrigin = floorf(clippedvert[0].varying[j] * 0.1f) * 10.0f;
for (int i = 0; i < numclipvert; i++)
{
clippedvert[i].varying[j] -= newOrigin;
}
}
}
// Draw screen triangles
if (ccw)
{
for (int i = numclipvert; i > 1; i--)
{
args->v1 = &clippedvert[numclipvert - 1];
args->v2 = &clippedvert[i - 1];
args->v3 = &clippedvert[i - 2];
for (int j = 0; j < num_drawfuncs; j++)
drawfuncs[j](args, thread);
}
}
else
{
for (int i = 2; i < numclipvert; i++)
{
args->v1 = &clippedvert[0];
args->v2 = &clippedvert[i - 1];
args->v3 = &clippedvert[i];
for (int j = 0; j < num_drawfuncs; j++)
drawfuncs[j](args, thread);
}
}
}
bool PolyTriangleDrawer::cullhalfspace(float clipdistance1, float clipdistance2, float &t1, float &t2)
{
if (clipdistance1 < 0.0f && clipdistance2 < 0.0f)
return true;
if (clipdistance1 < 0.0f)
t1 = MAX(-clipdistance1 / (clipdistance2 - clipdistance1), 0.0f);
else
t1 = 0.0f;
if (clipdistance2 < 0.0f)
t2 = MIN(1.0f + clipdistance2 / (clipdistance1 - clipdistance2), 1.0f);
else
t2 = 1.0f;
return false;
}
void PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippedvert, int &numclipvert)
{
// Clip and cull so that the following is true for all vertices:
// -v.w <= v.x <= v.w
// -v.w <= v.y <= v.w
// -v.w <= v.z <= v.w
// use barycentric weights while clipping vertices
float weights[max_additional_vertices * 3 * 2];
for (int i = 0; i < 3; i++)
{
weights[i * 3 + 0] = 0.0f;
weights[i * 3 + 1] = 0.0f;
weights[i * 3 + 2] = 0.0f;
weights[i * 3 + i] = 1.0f;
}
// halfspace clip distances
static const int numclipdistances = 7;
float clipdistance[numclipdistances * 3];
for (int i = 0; i < 3; i++)
{
const auto &v = verts[i];
clipdistance[i * numclipdistances + 0] = v.x + v.w;
clipdistance[i * numclipdistances + 1] = v.w - v.x;
clipdistance[i * numclipdistances + 2] = v.y + v.w;
clipdistance[i * numclipdistances + 3] = v.w - v.y;
clipdistance[i * numclipdistances + 4] = v.z + v.w;
clipdistance[i * numclipdistances + 5] = v.w - v.z;
clipdistance[i * numclipdistances + 6] = v.clipDistance0;
}
// Clip against each halfspace
float *input = weights;
float *output = weights + max_additional_vertices * 3;
int inputverts = 3;
int outputverts = 0;
for (int p = 0; p < numclipdistances; p++)
{
// Clip each edge
outputverts = 0;
for (int i = 0; i < inputverts; i++)
{
int j = (i + 1) % inputverts;
float clipdistance1 =
clipdistance[0 * numclipdistances + p] * input[i * 3 + 0] +
clipdistance[1 * numclipdistances + p] * input[i * 3 + 1] +
clipdistance[2 * numclipdistances + p] * input[i * 3 + 2];
float clipdistance2 =
clipdistance[0 * numclipdistances + p] * input[j * 3 + 0] +
clipdistance[1 * numclipdistances + p] * input[j * 3 + 1] +
clipdistance[2 * numclipdistances + p] * input[j * 3 + 2];
float t1, t2;
if (!cullhalfspace(clipdistance1, clipdistance2, t1, t2) && outputverts + 1 < max_additional_vertices)
{
// add t1 vertex
for (int k = 0; k < 3; k++)
output[outputverts * 3 + k] = input[i * 3 + k] * (1.0f - t1) + input[j * 3 + k] * t1;
outputverts++;
if (t2 != 1.0f && t2 > t1)
{
// add t2 vertex
for (int k = 0; k < 3; k++)
output[outputverts * 3 + k] = input[i * 3 + k] * (1.0f - t2) + input[j * 3 + k] * t2;
outputverts++;
}
}
}
std::swap(input, output);
std::swap(inputverts, outputverts);
if (inputverts == 0)
break;
}
// Convert barycentric weights to actual vertices
numclipvert = inputverts;
for (int i = 0; i < numclipvert; i++)
{
auto &v = clippedvert[i];
memset(&v, 0, sizeof(TriVertex));
for (int w = 0; w < 3; w++)
{
float weight = input[i * 3 + w];
v.x += verts[w].x * weight;
v.y += verts[w].y * weight;
v.z += verts[w].z * weight;
v.w += verts[w].w * weight;
for (int iv = 0; iv < TriVertex::NumVarying; iv++)
v.varying[iv] += verts[w].varying[iv] * weight;
}
}
}
/////////////////////////////////////////////////////////////////////////////
DrawPolyTrianglesCommand::DrawPolyTrianglesCommand(const PolyDrawArgs &args, bool mirror)
: args(args)
{
if (mirror)
this->args.ccw = !this->args.ccw;
}
void DrawPolyTrianglesCommand::Execute(DrawerThread *thread)
{
WorkerThreadData thread_data;
thread_data.core = thread->core;
thread_data.num_cores = thread->num_cores;
thread_data.pass_start_y = thread->pass_start_y;
thread_data.pass_end_y = thread->pass_end_y;
thread_data.FullSpans = thread->FullSpansBuffer.data();
thread_data.PartialBlocks = thread->PartialBlocksBuffer.data();
PolyTriangleDrawer::draw_arrays(args, &thread_data);
}
FString DrawPolyTrianglesCommand::DebugInfo()
{
FString blendmodestr;
switch (args.blendmode)
{
default: blendmodestr = "Unknown"; break;
case TriBlendMode::Copy: blendmodestr = "Copy"; break;
case TriBlendMode::AlphaBlend: blendmodestr = "AlphaBlend"; break;
case TriBlendMode::AddSolid: blendmodestr = "AddSolid"; break;
case TriBlendMode::Add: blendmodestr = "Add"; break;
case TriBlendMode::Sub: blendmodestr = "Sub"; break;
case TriBlendMode::RevSub: blendmodestr = "RevSub"; break;
case TriBlendMode::Stencil: blendmodestr = "Stencil"; break;
case TriBlendMode::Shaded: blendmodestr = "Shaded"; break;
case TriBlendMode::TranslateCopy: blendmodestr = "TranslateCopy"; break;
case TriBlendMode::TranslateAlphaBlend: blendmodestr = "TranslateAlphaBlend"; break;
case TriBlendMode::TranslateAdd: blendmodestr = "TranslateAdd"; break;
case TriBlendMode::TranslateSub: blendmodestr = "TranslateSub"; break;
case TriBlendMode::TranslateRevSub: blendmodestr = "TranslateRevSub"; break;
case TriBlendMode::AddSrcColorOneMinusSrcColor: blendmodestr = "AddSrcColorOneMinusSrcColor"; break;
}
FString info;
info.Format("DrawPolyTriangles: blend mode = %s, color = %d, light = %d, textureWidth = %d, textureHeight = %d, texture = %s, translation = %s, colormaps = %s",
blendmodestr.GetChars(), args.uniforms.color, args.uniforms.light, args.textureWidth, args.textureHeight,
args.texturePixels ? "ptr" : "null", args.translation ? "ptr" : "null", args.colormaps ? "ptr" : "null");
return info;
}

View file

@ -0,0 +1,73 @@
/*
** Triangle drawers
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "swrenderer/drawers/r_draw.h"
#include "swrenderer/drawers/r_thread.h"
#include "polyrenderer/drawers/screen_triangle.h"
#include "polyrenderer/math/tri_matrix.h"
#include "polyrenderer/drawers/poly_buffer.h"
#include "polyrenderer/drawers/poly_draw_args.h"
struct ShadedTriVertex : public TriVertex
{
float clipDistance0;
};
typedef void(*PolyDrawFuncPtr)(const TriDrawTriangleArgs *, WorkerThreadData *);
class PolyTriangleDrawer
{
public:
static void set_viewport(int x, int y, int width, int height, DCanvas *canvas);
static void draw(const PolyDrawArgs &args);
static void toggle_mirror();
private:
static ShadedTriVertex shade_vertex(const TriMatrix &objectToClip, const float *clipPlane, const TriVertex &v);
static void draw_arrays(const PolyDrawArgs &args, WorkerThreadData *thread);
static void draw_shaded_triangle(const ShadedTriVertex *vertices, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread, PolyDrawFuncPtr *drawfuncs, int num_drawfuncs);
static bool cullhalfspace(float clipdistance1, float clipdistance2, float &t1, float &t2);
static void clipedge(const ShadedTriVertex *verts, TriVertex *clippedvert, int &numclipvert);
static int viewport_x, viewport_y, viewport_width, viewport_height, dest_pitch, dest_width, dest_height;
static bool dest_bgra;
static uint8_t *dest;
static bool mirror;
enum { max_additional_vertices = 16 };
friend class DrawPolyTrianglesCommand;
};
class DrawPolyTrianglesCommand : public DrawerCommand
{
public:
DrawPolyTrianglesCommand(const PolyDrawArgs &args, bool mirror);
void Execute(DrawerThread *thread) override;
FString DebugInfo() override;
private:
PolyDrawArgs args;
};

View file

@ -0,0 +1,966 @@
/*
** Triangle drawers
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stddef.h>
#include "templates.h"
#include "doomdef.h"
#include "i_system.h"
#include "w_wad.h"
#include "v_video.h"
#include "doomstat.h"
#include "st_stuff.h"
#include "g_game.h"
#include "g_level.h"
#include "r_data/r_translate.h"
#include "v_palette.h"
#include "r_data/colormaps.h"
#include "poly_triangle.h"
#include "swrenderer/drawers/r_draw_rgba.h"
#include "screen_triangle.h"
#include "poly_drawers.h"
void ScreenTriangle::SetupNormal(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
{
const TriVertex &v1 = *args->v1;
const TriVertex &v2 = *args->v2;
const TriVertex &v3 = *args->v3;
int clipright = args->clipright;
int clipbottom = args->clipbottom;
int stencilPitch = args->stencilPitch;
uint8_t * RESTRICT stencilValues = args->stencilValues;
uint32_t * RESTRICT stencilMasks = args->stencilMasks;
uint8_t stencilTestValue = args->stencilTestValue;
TriFullSpan * RESTRICT span = thread->FullSpans;
TriPartialBlock * RESTRICT partial = thread->PartialBlocks;
// 28.4 fixed-point coordinates
const int Y1 = (int)round(16.0f * v1.y);
const int Y2 = (int)round(16.0f * v2.y);
const int Y3 = (int)round(16.0f * v3.y);
const int X1 = (int)round(16.0f * v1.x);
const int X2 = (int)round(16.0f * v2.x);
const int X3 = (int)round(16.0f * v3.x);
// Deltas
const int DX12 = X1 - X2;
const int DX23 = X2 - X3;
const int DX31 = X3 - X1;
const int DY12 = Y1 - Y2;
const int DY23 = Y2 - Y3;
const int DY31 = Y3 - Y1;
// Fixed-point deltas
const int FDX12 = DX12 << 4;
const int FDX23 = DX23 << 4;
const int FDX31 = DX31 << 4;
const int FDY12 = DY12 << 4;
const int FDY23 = DY23 << 4;
const int FDY31 = DY31 << 4;
// Bounding rectangle
int minx = MAX((MIN(MIN(X1, X2), X3) + 0xF) >> 4, 0);
int maxx = MIN((MAX(MAX(X1, X2), X3) + 0xF) >> 4, clipright - 1);
int miny = MAX((MIN(MIN(Y1, Y2), Y3) + 0xF) >> 4, 0);
int maxy = MIN((MAX(MAX(Y1, Y2), Y3) + 0xF) >> 4, clipbottom - 1);
if (minx >= maxx || miny >= maxy)
{
thread->NumFullSpans = 0;
thread->NumPartialBlocks = 0;
return;
}
// Block size, standard 8x8 (must be power of two)
const int q = 8;
// Start in corner of 8x8 block
minx &= ~(q - 1);
miny &= ~(q - 1);
// Half-edge constants
int C1 = DY12 * X1 - DX12 * Y1;
int C2 = DY23 * X2 - DX23 * Y2;
int C3 = DY31 * X3 - DX31 * Y3;
// Correct for fill convention
if (DY12 < 0 || (DY12 == 0 && DX12 > 0)) C1++;
if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++;
if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++;
// First block line for this thread
int core = thread->core;
int num_cores = thread->num_cores;
int core_skip = (num_cores - ((miny / q) - core) % num_cores) % num_cores;
miny += core_skip * q;
thread->StartX = minx;
thread->StartY = miny;
span->Length = 0;
// Loop through blocks
for (int y = miny; y < maxy; y += q * num_cores)
{
for (int x = minx; x < maxx; x += q)
{
// Corners of block
int x0 = x << 4;
int x1 = (x + q - 1) << 4;
int y0 = y << 4;
int y1 = (y + q - 1) << 4;
// Evaluate half-space functions
bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0;
bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0;
bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0;
bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0;
int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3);
bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0;
bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0;
bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0;
bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0;
int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3);
bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0;
bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0;
bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0;
bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0;
int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3);
// Stencil test the whole block, if possible
int block = x / 8 + y / 8 * stencilPitch;
uint8_t *stencilBlock = &stencilValues[block * 64];
uint32_t *stencilBlockMask = &stencilMasks[block];
bool blockIsSingleStencil = ((*stencilBlockMask) & 0xffffff00) == 0xffffff00;
bool skipBlock = blockIsSingleStencil && ((*stencilBlockMask) & 0xff) != stencilTestValue;
// Skip block when outside an edge
if (a == 0 || b == 0 || c == 0 || skipBlock)
{
if (span->Length != 0)
{
span++;
span->Length = 0;
}
continue;
}
// Accept whole block when totally covered
if (a == 0xf && b == 0xf && c == 0xf && x + q <= clipright && y + q <= clipbottom && blockIsSingleStencil)
{
if (span->Length != 0)
{
span->Length++;
}
else
{
span->X = x;
span->Y = y;
span->Length = 1;
}
}
else // Partially covered block
{
x0 = x << 4;
x1 = (x + q - 1) << 4;
int CY1 = C1 + DX12 * y0 - DY12 * x0;
int CY2 = C2 + DX23 * y0 - DY23 * x0;
int CY3 = C3 + DX31 * y0 - DY31 * x0;
uint32_t mask0 = 0;
uint32_t mask1 = 0;
for (int iy = 0; iy < 4; iy++)
{
int CX1 = CY1;
int CX2 = CY2;
int CX3 = CY3;
for (int ix = 0; ix < q; ix++)
{
bool passStencilTest = blockIsSingleStencil || stencilBlock[ix + iy * q] == stencilTestValue;
bool covered = (CX1 > 0 && CX2 > 0 && CX3 > 0 && (x + ix) < clipright && (y + iy) < clipbottom && passStencilTest);
mask0 <<= 1;
mask0 |= (uint32_t)covered;
CX1 -= FDY12;
CX2 -= FDY23;
CX3 -= FDY31;
}
CY1 += FDX12;
CY2 += FDX23;
CY3 += FDX31;
}
for (int iy = 4; iy < q; iy++)
{
int CX1 = CY1;
int CX2 = CY2;
int CX3 = CY3;
for (int ix = 0; ix < q; ix++)
{
bool passStencilTest = blockIsSingleStencil || stencilBlock[ix + iy * q] == stencilTestValue;
bool covered = (CX1 > 0 && CX2 > 0 && CX3 > 0 && (x + ix) < clipright && (y + iy) < clipbottom && passStencilTest);
mask1 <<= 1;
mask1 |= (uint32_t)covered;
CX1 -= FDY12;
CX2 -= FDY23;
CX3 -= FDY31;
}
CY1 += FDX12;
CY2 += FDX23;
CY3 += FDX31;
}
if (mask0 != 0xffffffff || mask1 != 0xffffffff)
{
if (span->Length > 0)
{
span++;
span->Length = 0;
}
if (mask0 == 0 && mask1 == 0)
continue;
partial->X = x;
partial->Y = y;
partial->Mask0 = mask0;
partial->Mask1 = mask1;
partial++;
}
else if (span->Length != 0)
{
span->Length++;
}
else
{
span->X = x;
span->Y = y;
span->Length = 1;
}
}
}
if (span->Length != 0)
{
span++;
span->Length = 0;
}
}
thread->NumFullSpans = (int)(span - thread->FullSpans);
thread->NumPartialBlocks = (int)(partial - thread->PartialBlocks);
}
void ScreenTriangle::SetupSubsector(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
{
const TriVertex &v1 = *args->v1;
const TriVertex &v2 = *args->v2;
const TriVertex &v3 = *args->v3;
int clipright = args->clipright;
int clipbottom = args->clipbottom;
int stencilPitch = args->stencilPitch;
uint8_t * RESTRICT stencilValues = args->stencilValues;
uint32_t * RESTRICT stencilMasks = args->stencilMasks;
uint8_t stencilTestValue = args->stencilTestValue;
uint32_t * RESTRICT subsectorGBuffer = args->subsectorGBuffer;
uint32_t subsectorDepth = args->uniforms->subsectorDepth;
int32_t pitch = args->pitch;
TriFullSpan * RESTRICT span = thread->FullSpans;
TriPartialBlock * RESTRICT partial = thread->PartialBlocks;
// 28.4 fixed-point coordinates
const int Y1 = (int)round(16.0f * v1.y);
const int Y2 = (int)round(16.0f * v2.y);
const int Y3 = (int)round(16.0f * v3.y);
const int X1 = (int)round(16.0f * v1.x);
const int X2 = (int)round(16.0f * v2.x);
const int X3 = (int)round(16.0f * v3.x);
// Deltas
const int DX12 = X1 - X2;
const int DX23 = X2 - X3;
const int DX31 = X3 - X1;
const int DY12 = Y1 - Y2;
const int DY23 = Y2 - Y3;
const int DY31 = Y3 - Y1;
// Fixed-point deltas
const int FDX12 = DX12 << 4;
const int FDX23 = DX23 << 4;
const int FDX31 = DX31 << 4;
const int FDY12 = DY12 << 4;
const int FDY23 = DY23 << 4;
const int FDY31 = DY31 << 4;
// Bounding rectangle
int minx = MAX((MIN(MIN(X1, X2), X3) + 0xF) >> 4, 0);
int maxx = MIN((MAX(MAX(X1, X2), X3) + 0xF) >> 4, clipright - 1);
int miny = MAX((MIN(MIN(Y1, Y2), Y3) + 0xF) >> 4, 0);
int maxy = MIN((MAX(MAX(Y1, Y2), Y3) + 0xF) >> 4, clipbottom - 1);
if (minx >= maxx || miny >= maxy)
{
thread->NumFullSpans = 0;
thread->NumPartialBlocks = 0;
return;
}
// Block size, standard 8x8 (must be power of two)
const int q = 8;
// Start in corner of 8x8 block
minx &= ~(q - 1);
miny &= ~(q - 1);
// Half-edge constants
int C1 = DY12 * X1 - DX12 * Y1;
int C2 = DY23 * X2 - DX23 * Y2;
int C3 = DY31 * X3 - DX31 * Y3;
// Correct for fill convention
if (DY12 < 0 || (DY12 == 0 && DX12 > 0)) C1++;
if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++;
if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++;
// First block line for this thread
int core = thread->core;
int num_cores = thread->num_cores;
int core_skip = (num_cores - ((miny / q) - core) % num_cores) % num_cores;
miny += core_skip * q;
thread->StartX = minx;
thread->StartY = miny;
span->Length = 0;
// Loop through blocks
for (int y = miny; y < maxy; y += q * num_cores)
{
for (int x = minx; x < maxx; x += q)
{
// Corners of block
int x0 = x << 4;
int x1 = (x + q - 1) << 4;
int y0 = y << 4;
int y1 = (y + q - 1) << 4;
// Evaluate half-space functions
bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0;
bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0;
bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0;
bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0;
int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3);
bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0;
bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0;
bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0;
bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0;
int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3);
bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0;
bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0;
bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0;
bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0;
int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3);
// Stencil test the whole block, if possible
int block = x / 8 + y / 8 * stencilPitch;
uint8_t *stencilBlock = &stencilValues[block * 64];
uint32_t *stencilBlockMask = &stencilMasks[block];
bool blockIsSingleStencil = ((*stencilBlockMask) & 0xffffff00) == 0xffffff00;
bool skipBlock = blockIsSingleStencil && ((*stencilBlockMask) & 0xff) < stencilTestValue;
// Skip block when outside an edge
if (a == 0 || b == 0 || c == 0 || skipBlock)
{
if (span->Length != 0)
{
span++;
span->Length = 0;
}
continue;
}
// Accept whole block when totally covered
if (a == 0xf && b == 0xf && c == 0xf && x + q <= clipright && y + q <= clipbottom && blockIsSingleStencil)
{
// Totally covered block still needs a subsector coverage test:
uint32_t *subsector = subsectorGBuffer + x + y * pitch;
uint32_t mask0 = 0;
uint32_t mask1 = 0;
for (int iy = 0; iy < 4; iy++)
{
for (int ix = 0; ix < q; ix++)
{
bool covered = subsector[ix] >= subsectorDepth;
mask0 <<= 1;
mask0 |= (uint32_t)covered;
}
subsector += pitch;
}
for (int iy = 4; iy < q; iy++)
{
for (int ix = 0; ix < q; ix++)
{
bool covered = subsector[ix] >= subsectorDepth;
mask1 <<= 1;
mask1 |= (uint32_t)covered;
}
subsector += pitch;
}
if (mask0 != 0xffffffff || mask1 != 0xffffffff)
{
if (span->Length > 0)
{
span++;
span->Length = 0;
}
if (mask0 == 0 && mask1 == 0)
continue;
partial->X = x;
partial->Y = y;
partial->Mask0 = mask0;
partial->Mask1 = mask1;
partial++;
}
else if (span->Length != 0)
{
span->Length++;
}
else
{
span->X = x;
span->Y = y;
span->Length = 1;
}
}
else // Partially covered block
{
x0 = x << 4;
x1 = (x + q - 1) << 4;
int CY1 = C1 + DX12 * y0 - DY12 * x0;
int CY2 = C2 + DX23 * y0 - DY23 * x0;
int CY3 = C3 + DX31 * y0 - DY31 * x0;
uint32_t *subsector = subsectorGBuffer + x + y * pitch;
uint32_t mask0 = 0;
uint32_t mask1 = 0;
for (int iy = 0; iy < 4; iy++)
{
int CX1 = CY1;
int CX2 = CY2;
int CX3 = CY3;
for (int ix = 0; ix < q; ix++)
{
bool passStencilTest = blockIsSingleStencil || stencilBlock[ix + iy * q] >= stencilTestValue;
bool covered = (CX1 > 0 && CX2 > 0 && CX3 > 0 && (x + ix) < clipright && (y + iy) < clipbottom && passStencilTest && subsector[ix] >= subsectorDepth);
mask0 <<= 1;
mask0 |= (uint32_t)covered;
CX1 -= FDY12;
CX2 -= FDY23;
CX3 -= FDY31;
}
CY1 += FDX12;
CY2 += FDX23;
CY3 += FDX31;
subsector += pitch;
}
for (int iy = 4; iy < q; iy++)
{
int CX1 = CY1;
int CX2 = CY2;
int CX3 = CY3;
for (int ix = 0; ix < q; ix++)
{
bool passStencilTest = blockIsSingleStencil || stencilBlock[ix + iy * q] >= stencilTestValue;
bool covered = (CX1 > 0 && CX2 > 0 && CX3 > 0 && (x + ix) < clipright && (y + iy) < clipbottom && passStencilTest && subsector[ix] >= subsectorDepth);
mask1 <<= 1;
mask1 |= (uint32_t)covered;
CX1 -= FDY12;
CX2 -= FDY23;
CX3 -= FDY31;
}
CY1 += FDX12;
CY2 += FDX23;
CY3 += FDX31;
subsector += pitch;
}
if (mask0 != 0xffffffff || mask1 != 0xffffffff)
{
if (span->Length > 0)
{
span++;
span->Length = 0;
}
if (mask0 == 0 && mask1 == 0)
continue;
partial->X = x;
partial->Y = y;
partial->Mask0 = mask0;
partial->Mask1 = mask1;
partial++;
}
else if (span->Length != 0)
{
span->Length++;
}
else
{
span->X = x;
span->Y = y;
span->Length = 1;
}
}
}
if (span->Length != 0)
{
span++;
span->Length = 0;
}
}
thread->NumFullSpans = (int)(span - thread->FullSpans);
thread->NumPartialBlocks = (int)(partial - thread->PartialBlocks);
}
void ScreenTriangle::StencilWrite(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
{
uint8_t * RESTRICT stencilValues = args->stencilValues;
uint32_t * RESTRICT stencilMasks = args->stencilMasks;
uint32_t stencilWriteValue = args->stencilWriteValue;
uint32_t stencilPitch = args->stencilPitch;
int numSpans = thread->NumFullSpans;
auto fullSpans = thread->FullSpans;
int numBlocks = thread->NumPartialBlocks;
auto partialBlocks = thread->PartialBlocks;
for (int i = 0; i < numSpans; i++)
{
const auto &span = fullSpans[i];
int block = span.X / 8 + span.Y / 8 * stencilPitch;
uint8_t *stencilBlock = &stencilValues[block * 64];
uint32_t *stencilBlockMask = &stencilMasks[block];
int width = span.Length;
for (int x = 0; x < width; x++)
stencilBlockMask[x] = 0xffffff00 | stencilWriteValue;
}
for (int i = 0; i < numBlocks; i++)
{
const auto &block = partialBlocks[i];
uint32_t mask0 = block.Mask0;
uint32_t mask1 = block.Mask1;
int sblock = block.X / 8 + block.Y / 8 * stencilPitch;
uint8_t *stencilBlock = &stencilValues[sblock * 64];
uint32_t *stencilBlockMask = &stencilMasks[sblock];
bool isSingleValue = ((*stencilBlockMask) & 0xffffff00) == 0xffffff00;
if (isSingleValue)
{
uint8_t value = (*stencilBlockMask) & 0xff;
for (int v = 0; v < 64; v++)
stencilBlock[v] = value;
*stencilBlockMask = 0;
}
int count = 0;
for (int v = 0; v < 32; v++)
{
if ((mask0 & (1 << 31)) || stencilBlock[v] == stencilWriteValue)
{
stencilBlock[v] = stencilWriteValue;
count++;
}
mask0 <<= 1;
}
for (int v = 32; v < 64; v++)
{
if ((mask1 & (1 << 31)) || stencilBlock[v] == stencilWriteValue)
{
stencilBlock[v] = stencilWriteValue;
count++;
}
mask1 <<= 1;
}
if (count == 64)
*stencilBlockMask = 0xffffff00 | stencilWriteValue;
}
}
void ScreenTriangle::SubsectorWrite(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
{
uint32_t * RESTRICT subsectorGBuffer = args->subsectorGBuffer;
uint32_t subsectorDepth = args->uniforms->subsectorDepth;
int pitch = args->pitch;
int numSpans = thread->NumFullSpans;
auto fullSpans = thread->FullSpans;
int numBlocks = thread->NumPartialBlocks;
auto partialBlocks = thread->PartialBlocks;
for (int i = 0; i < numSpans; i++)
{
const auto &span = fullSpans[i];
uint32_t *subsector = subsectorGBuffer + span.X + span.Y * pitch;
int width = span.Length * 8;
int height = 8;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
subsector[x] = subsectorDepth;
subsector += pitch;
}
}
for (int i = 0; i < numBlocks; i++)
{
const auto &block = partialBlocks[i];
uint32_t *subsector = subsectorGBuffer + block.X + block.Y * pitch;
uint32_t mask0 = block.Mask0;
uint32_t mask1 = block.Mask1;
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 8; x++)
{
if (mask0 & (1 << 31))
subsector[x] = subsectorDepth;
mask0 <<= 1;
}
subsector += pitch;
}
for (int y = 4; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
if (mask1 & (1 << 31))
subsector[x] = subsectorDepth;
mask1 <<= 1;
}
subsector += pitch;
}
}
}
#if 0
float ScreenTriangle::FindGradientX(float x0, float y0, float x1, float y1, float x2, float y2, float c0, float c1, float c2)
{
float top = (c1 - c2) * (y0 - y2) - (c0 - c2) * (y1 - y2);
float bottom = (x1 - x2) * (y0 - y2) - (x0 - x2) * (y1 - y2);
return top / bottom;
}
float ScreenTriangle::FindGradientY(float x0, float y0, float x1, float y1, float x2, float y2, float c0, float c1, float c2)
{
float top = (c1 - c2) * (x0 - x2) - (c0 - c2) * (x1 - x2);
float bottom = (x0 - x2) * (y1 - y2) - (x1 - x2) * (y0 - y2);
return top / bottom;
}
void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
{
int numSpans = thread->NumFullSpans;
auto fullSpans = thread->FullSpans;
int numBlocks = thread->NumPartialBlocks;
auto partialBlocks = thread->PartialBlocks;
int startX = thread->StartX;
int startY = thread->StartY;
// Calculate gradients
const TriVertex &v1 = *args->v1;
const TriVertex &v2 = *args->v2;
const TriVertex &v3 = *args->v3;
ScreenTriangleStepVariables gradientX;
ScreenTriangleStepVariables gradientY;
ScreenTriangleStepVariables start;
gradientX.W = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w);
gradientY.W = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w);
start.W = v1.w + gradientX.W * (startX - v1.x) + gradientY.W * (startY - v1.y);
for (int i = 0; i < TriVertex::NumVarying; i++)
{
gradientX.Varying[i] = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.varying[i] * v1.w, v2.varying[i] * v2.w, v3.varying[i] * v3.w);
gradientY.Varying[i] = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.varying[i] * v1.w, v2.varying[i] * v2.w, v3.varying[i] * v3.w);
start.Varying[i] = v1.varying[i] * v1.w + gradientX.Varying[i] * (startX - v1.x) + gradientY.Varying[i] * (startY - v1.y);
}
const uint32_t * RESTRICT texPixels = (const uint32_t *)args->texturePixels;
uint32_t texWidth = args->textureWidth;
uint32_t texHeight = args->textureHeight;
uint32_t * RESTRICT destOrg = (uint32_t*)args->dest;
uint32_t * RESTRICT subsectorGBuffer = (uint32_t*)args->subsectorGBuffer;
int pitch = args->pitch;
uint32_t subsectorDepth = args->uniforms->subsectorDepth;
uint32_t light = args->uniforms->light;
float shade = (64.0f - (light * 255 / 256 + 12.0f) * 32.0f / 128.0f) / 32.0f;
float globVis = 1706.0f;
for (int i = 0; i < numSpans; i++)
{
const auto &span = fullSpans[i];
uint32_t *dest = destOrg + span.X + span.Y * pitch;
uint32_t *subsector = subsectorGBuffer + span.X + span.Y * pitch;
int width = span.Length;
int height = 8;
ScreenTriangleStepVariables blockPosY;
blockPosY.W = start.W + gradientX.W * (span.X - startX) + gradientY.W * (span.Y - startY);
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosY.Varying[j] = start.Varying[j] + gradientX.Varying[j] * (span.X - startX) + gradientY.Varying[j] * (span.Y - startY);
for (int y = 0; y < height; y++)
{
ScreenTriangleStepVariables blockPosX = blockPosY;
float rcpW = 0x01000000 / blockPosX.W;
int32_t varyingPos[TriVertex::NumVarying];
for (int j = 0; j < TriVertex::NumVarying; j++)
varyingPos[j] = (int32_t)(blockPosX.Varying[j] * rcpW);
int lightpos = 256 - (int)(clamp(shade - MIN(24.0f, globVis * blockPosX.W) / 32.0f, 0.0f, 31.0f / 32.0f) * 256.0f);
for (int x = 0; x < width; x++)
{
blockPosX.W += gradientX.W * 8;
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosX.Varying[j] += gradientX.Varying[j] * 8;
rcpW = 0x01000000 / blockPosX.W;
int32_t varyingStep[TriVertex::NumVarying];
for (int j = 0; j < TriVertex::NumVarying; j++)
{
int32_t nextPos = (int32_t)(blockPosX.Varying[j] * rcpW);
varyingStep[j] = (nextPos - varyingPos[j]) / 8;
}
int lightnext = 256 - (int)(clamp(shade - MIN(24.0f, globVis * blockPosX.W) / 32.0f, 0.0f, 31.0f / 32.0f) * 256.0f);
int lightstep = (lightnext - lightpos) / 8;
for (int ix = 0; ix < 8; ix++)
{
int texelX = ((((uint32_t)varyingPos[0] << 8) >> 16) * texWidth) >> 16;
int texelY = ((((uint32_t)varyingPos[1] << 8) >> 16) * texHeight) >> 16;
uint32_t fg = texPixels[texelX * texHeight + texelY];
uint32_t r = RPART(fg);
uint32_t g = GPART(fg);
uint32_t b = BPART(fg);
r = r * lightpos / 256;
g = g * lightpos / 256;
b = b * lightpos / 256;
fg = 0xff000000 | (r << 16) | (g << 8) | b;
dest[x * 8 + ix] = fg;
subsector[x * 8 + ix] = subsectorDepth;
for (int j = 0; j < TriVertex::NumVarying; j++)
varyingPos[j] += varyingStep[j];
lightpos += lightstep;
}
}
blockPosY.W += gradientY.W;
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosY.Varying[j] += gradientY.Varying[j];
dest += pitch;
subsector += pitch;
}
}
for (int i = 0; i < numBlocks; i++)
{
const auto &block = partialBlocks[i];
ScreenTriangleStepVariables blockPosY;
blockPosY.W = start.W + gradientX.W * (block.X - startX) + gradientY.W * (block.Y - startY);
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosY.Varying[j] = start.Varying[j] + gradientX.Varying[j] * (block.X - startX) + gradientY.Varying[j] * (block.Y - startY);
uint32_t *dest = destOrg + block.X + block.Y * pitch;
uint32_t *subsector = subsectorGBuffer + block.X + block.Y * pitch;
uint32_t mask0 = block.Mask0;
uint32_t mask1 = block.Mask1;
for (int y = 0; y < 4; y++)
{
ScreenTriangleStepVariables blockPosX = blockPosY;
float rcpW = 0x01000000 / blockPosX.W;
int32_t varyingPos[TriVertex::NumVarying];
for (int j = 0; j < TriVertex::NumVarying; j++)
varyingPos[j] = (int32_t)(blockPosX.Varying[j] * rcpW);
int lightpos = 256 - (int)(clamp(shade - MIN(24.0f, globVis * blockPosX.W) / 32.0f, 0.0f, 31.0f / 32.0f) * 256.0f);
blockPosX.W += gradientX.W * 8;
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosX.Varying[j] += gradientX.Varying[j] * 8;
rcpW = 0x01000000 / blockPosX.W;
int32_t varyingStep[TriVertex::NumVarying];
for (int j = 0; j < TriVertex::NumVarying; j++)
{
int32_t nextPos = (int32_t)(blockPosX.Varying[j] * rcpW);
varyingStep[j] = (nextPos - varyingPos[j]) / 8;
}
int lightnext = 256 - (int)(clamp(shade - MIN(24.0f, globVis * blockPosX.W) / 32.0f, 0.0f, 31.0f / 32.0f) * 256.0f);
int lightstep = (lightnext - lightpos) / 8;
for (int x = 0; x < 8; x++)
{
if (mask0 & (1 << 31))
{
int texelX = ((((uint32_t)varyingPos[0] << 8) >> 16) * texWidth) >> 16;
int texelY = ((((uint32_t)varyingPos[1] << 8) >> 16) * texHeight) >> 16;
uint32_t fg = texPixels[texelX * texHeight + texelY];
uint32_t r = RPART(fg);
uint32_t g = GPART(fg);
uint32_t b = BPART(fg);
r = r * lightpos / 256;
g = g * lightpos / 256;
b = b * lightpos / 256;
fg = 0xff000000 | (r << 16) | (g << 8) | b;
dest[x] = fg;
subsector[x] = subsectorDepth;
}
mask0 <<= 1;
for (int j = 0; j < TriVertex::NumVarying; j++)
varyingPos[j] += varyingStep[j];
lightpos += lightstep;
}
blockPosY.W += gradientY.W;
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosY.Varying[j] += gradientY.Varying[j];
dest += pitch;
subsector += pitch;
}
for (int y = 4; y < 8; y++)
{
ScreenTriangleStepVariables blockPosX = blockPosY;
float rcpW = 0x01000000 / blockPosX.W;
int32_t varyingPos[TriVertex::NumVarying];
for (int j = 0; j < TriVertex::NumVarying; j++)
varyingPos[j] = (int32_t)(blockPosX.Varying[j] * rcpW);
int lightpos = 256 - (int)(clamp(shade - MIN(24.0f, globVis * blockPosX.W) / 32.0f, 0.0f, 31.0f / 32.0f) * 256.0f);
blockPosX.W += gradientX.W * 8;
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosX.Varying[j] += gradientX.Varying[j] * 8;
rcpW = 0x01000000 / blockPosX.W;
int32_t varyingStep[TriVertex::NumVarying];
for (int j = 0; j < TriVertex::NumVarying; j++)
{
int32_t nextPos = (int32_t)(blockPosX.Varying[j] * rcpW);
varyingStep[j] = (nextPos - varyingPos[j]) / 8;
}
int lightnext = 256 - (int)(clamp(shade - MIN(24.0f, globVis * blockPosX.W) / 32.0f, 0.0f, 31.0f / 32.0f) * 256.0f);
int lightstep = (lightnext - lightpos) / 8;
for (int x = 0; x < 8; x++)
{
if (mask1 & (1 << 31))
{
int texelX = ((((uint32_t)varyingPos[0] << 8) >> 16) * texWidth) >> 16;
int texelY = ((((uint32_t)varyingPos[1] << 8) >> 16) * texHeight) >> 16;
uint32_t fg = texPixels[texelX * texHeight + texelY];
uint32_t r = RPART(fg);
uint32_t g = GPART(fg);
uint32_t b = BPART(fg);
r = r * lightpos / 256;
g = g * lightpos / 256;
b = b * lightpos / 256;
fg = 0xff000000 | (r << 16) | (g << 8) | b;
dest[x] = fg;
subsector[x] = subsectorDepth;
}
mask1 <<= 1;
for (int j = 0; j < TriVertex::NumVarying; j++)
varyingPos[j] += varyingStep[j];
lightpos += lightstep;
}
blockPosY.W += gradientY.W;
for (int j = 0; j < TriVertex::NumVarying; j++)
blockPosY.Varying[j] += gradientY.Varying[j];
dest += pitch;
subsector += pitch;
}
}
}
#endif

View file

@ -0,0 +1,164 @@
/*
** Projected triangle drawer
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include <cstdint>
#include <vector>
class FString;
struct TriFullSpan
{
uint16_t X;
uint16_t Y;
uint32_t Length;
};
struct TriPartialBlock
{
uint16_t X;
uint16_t Y;
uint32_t Mask0;
uint32_t Mask1;
};
struct WorkerThreadData
{
int32_t core;
int32_t num_cores;
int32_t pass_start_y;
int32_t pass_end_y;
uint32_t *temp;
// Triangle working data:
TriFullSpan *FullSpans;
TriPartialBlock *PartialBlocks;
uint32_t NumFullSpans;
uint32_t NumPartialBlocks;
int32_t StartX;
int32_t StartY;
};
struct TriVertex
{
TriVertex() { }
TriVertex(float x, float y, float z, float w, float u, float v) : x(x), y(y), z(z), w(w) { varying[0] = u; varying[1] = v; }
enum { NumVarying = 2 };
float x, y, z, w;
float varying[NumVarying];
};
struct TriUniforms
{
uint32_t light;
uint32_t subsectorDepth;
uint32_t color;
uint32_t srcalpha;
uint32_t destalpha;
uint16_t light_alpha;
uint16_t light_red;
uint16_t light_green;
uint16_t light_blue;
uint16_t fade_alpha;
uint16_t fade_red;
uint16_t fade_green;
uint16_t fade_blue;
uint16_t desaturate;
float globvis;
uint32_t flags;
enum Flags
{
simple_shade = 1,
nearest_filter = 2,
fixed_light = 4
};
};
struct TriDrawTriangleArgs
{
uint8_t *dest;
int32_t pitch;
TriVertex *v1;
TriVertex *v2;
TriVertex *v3;
int32_t clipleft;
int32_t clipright;
int32_t cliptop;
int32_t clipbottom;
const uint8_t *texturePixels;
uint32_t textureWidth;
uint32_t textureHeight;
const uint8_t *translation;
const TriUniforms *uniforms;
uint8_t *stencilValues;
uint32_t *stencilMasks;
int32_t stencilPitch;
uint8_t stencilTestValue;
uint8_t stencilWriteValue;
uint32_t *subsectorGBuffer;
const uint8_t *colormaps;
const uint8_t *RGB256k;
const uint8_t *BaseColors;
};
enum class TriBlendMode
{
Copy, // blend_copy(shade(fg))
AlphaBlend, // blend_alpha_blend(shade(fg), bg)
AddSolid, // blend_add(shade(fg), bg, srcalpha, destalpha)
Add, // blend_add(shade(fg), bg, srcalpha, calc_blend_bgalpha(fg, destalpha))
Sub, // blend_sub(shade(fg), bg, srcalpha, calc_blend_bgalpha(fg, destalpha))
RevSub, // blend_revsub(shade(fg), bg, srcalpha, calc_blend_bgalpha(fg, destalpha))
Stencil, // blend_stencil(shade(color), fg.a, bg, srcalpha, calc_blend_bgalpha(fg, destalpha))
Shaded, // blend_stencil(shade(color), fg.index, bg, srcalpha, calc_blend_bgalpha(fg, destalpha))
TranslateCopy, // blend_copy(shade(translate(fg)))
TranslateAlphaBlend, // blend_alpha_blend(shade(translate(fg)), bg)
TranslateAdd, // blend_add(shade(translate(fg)), bg, srcalpha, calc_blend_bgalpha(fg, destalpha))
TranslateSub, // blend_sub(shade(translate(fg)), bg, srcalpha, calc_blend_bgalpha(fg, destalpha))
TranslateRevSub,// blend_revsub(shade(translate(fg)), bg, srcalpha, calc_blend_bgalpha(fg, destalpha))
AddSrcColorOneMinusSrcColor, // glBlendMode(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR) used by GZDoom's fullbright additive sprites
Skycap // Fade to sky color when the V texture coordinate go beyond the [-1, 1] range
};
inline int NumTriBlendModes() { return (int)TriBlendMode::Skycap + 1; }
class ScreenTriangle
{
public:
static void SetupNormal(const TriDrawTriangleArgs *args, WorkerThreadData *thread);
static void SetupSubsector(const TriDrawTriangleArgs *args, WorkerThreadData *thread);
static void StencilWrite(const TriDrawTriangleArgs *args, WorkerThreadData *thread);
static void SubsectorWrite(const TriDrawTriangleArgs *args, WorkerThreadData *thread);
static std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> TriDraw8;
static std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> TriDraw32;
static std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> TriFill8;
static std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> TriFill32;
};
struct ScreenTriangleStepVariables
{
float W;
float Varying[TriVertex::NumVarying];
};

View file

@ -0,0 +1,235 @@
/*
** Various 3D intersection tests
** Copyright (c) 1997-2015 The UICore Team
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "poly_intersection.h"
IntersectionTest::Result IntersectionTest::plane_aabb(const Vec4f &plane, const AxisAlignedBoundingBox &aabb)
{
Vec3f center = aabb.center();
Vec3f extents = aabb.extents();
float e = extents.x * std::abs(plane.x) + extents.y * std::abs(plane.y) + extents.z * std::abs(plane.z);
float s = center.x * plane.x + center.y * plane.y + center.z * plane.z + plane.w;
if (s - e > 0)
return inside;
else if (s + e < 0)
return outside;
else
return intersecting;
}
IntersectionTest::Result IntersectionTest::plane_obb(const Vec4f &plane, const OrientedBoundingBox &obb)
{
Vec3f n(plane);
float d = plane.w;
float e = obb.extents.x * std::abs(Vec3f::dot(obb.axis_x, n)) + obb.extents.y * std::abs(Vec3f::dot(obb.axis_y, n)) + obb.extents.z * std::abs(Vec3f::dot(obb.axis_z, n));
float s = Vec3f::dot(obb.center, n) + d;
if (s - e > 0)
return inside;
else if (s + e < 0)
return outside;
else
return intersecting;
}
IntersectionTest::OverlapResult IntersectionTest::sphere(const Vec3f &center1, float radius1, const Vec3f &center2, float radius2)
{
Vec3f h = center1 - center2;
float square_distance = Vec3f::dot(h, h);
float radius_sum = radius1 + radius2;
if (square_distance > radius_sum * radius_sum)
return disjoint;
else
return overlap;
}
IntersectionTest::OverlapResult IntersectionTest::sphere_aabb(const Vec3f &center, float radius, const AxisAlignedBoundingBox &aabb)
{
Vec3f a = aabb.aabb_min - center;
Vec3f b = center - aabb.aabb_max;
a.x = std::max(a.x, 0.0f);
a.y = std::max(a.y, 0.0f);
a.z = std::max(a.z, 0.0f);
b.x = std::max(b.x, 0.0f);
b.y = std::max(b.y, 0.0f);
b.z = std::max(b.z, 0.0f);
Vec3f e = a + b;
float d = Vec3f::dot(e, e);
if (d > radius * radius)
return disjoint;
else
return overlap;
}
IntersectionTest::OverlapResult IntersectionTest::aabb(const AxisAlignedBoundingBox &a, const AxisAlignedBoundingBox &b)
{
if (a.aabb_min.x > b.aabb_max.x || b.aabb_min.x > a.aabb_max.x ||
a.aabb_min.y > b.aabb_max.y || b.aabb_min.y > a.aabb_max.y ||
a.aabb_min.z > b.aabb_max.z || b.aabb_min.z > a.aabb_max.z)
{
return disjoint;
}
else
{
return overlap;
}
}
IntersectionTest::Result IntersectionTest::frustum_aabb(const FrustumPlanes &frustum, const AxisAlignedBoundingBox &box)
{
bool is_intersecting = false;
for (int i = 0; i < 6; i++)
{
Result result = plane_aabb(frustum.planes[i], box);
if (result == outside)
return outside;
else if (result == intersecting)
is_intersecting = true;
break;
}
if (is_intersecting)
return intersecting;
else
return inside;
}
IntersectionTest::Result IntersectionTest::frustum_obb(const FrustumPlanes &frustum, const OrientedBoundingBox &box)
{
bool is_intersecting = false;
for (int i = 0; i < 6; i++)
{
Result result = plane_obb(frustum.planes[i], box);
if (result == outside)
return outside;
else if (result == intersecting)
is_intersecting = true;
}
if (is_intersecting)
return intersecting;
else
return inside;
}
IntersectionTest::OverlapResult IntersectionTest::ray_aabb(const Vec3f &ray_start, const Vec3f &ray_end, const AxisAlignedBoundingBox &aabb)
{
Vec3f c = (ray_start + ray_end) * 0.5f;
Vec3f w = ray_end - c;
Vec3f h = aabb.extents();
c -= aabb.center();
Vec3f v(std::abs(w.x), std::abs(w.y), std::abs(w.z));
if (std::abs(c.x) > v.x + h.x || std::abs(c.y) > v.y + h.y || std::abs(c.z) > v.z + h.z)
return disjoint;
if (std::abs(c.y * w.z - c.z * w.y) > h.y * v.z + h.z * v.y ||
std::abs(c.x * w.z - c.z * w.x) > h.x * v.z + h.z * v.x ||
std::abs(c.x * w.y - c.y * w.x) > h.x * v.y + h.y * v.x)
return disjoint;
return overlap;
}
/////////////////////////////////////////////////////////////////////////////
FrustumPlanes::FrustumPlanes()
{
}
FrustumPlanes::FrustumPlanes(const Mat4f &world_to_projection)
{
planes[0] = near_frustum_plane(world_to_projection);
planes[1] = far_frustum_plane(world_to_projection);
planes[2] = left_frustum_plane(world_to_projection);
planes[3] = right_frustum_plane(world_to_projection);
planes[4] = top_frustum_plane(world_to_projection);
planes[5] = bottom_frustum_plane(world_to_projection);
}
Vec4f FrustumPlanes::left_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] + m.matrix[0 + 0 * 4],
m.matrix[3 + 1 * 4] + m.matrix[0 + 1 * 4],
m.matrix[3 + 2 * 4] + m.matrix[0 + 2 * 4],
m.matrix[3 + 3 * 4] + m.matrix[0 + 3 * 4]);
plane /= plane.length3();
return plane;
}
Vec4f FrustumPlanes::right_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] - m.matrix[0 + 0 * 4],
m.matrix[3 + 1 * 4] - m.matrix[0 + 1 * 4],
m.matrix[3 + 2 * 4] - m.matrix[0 + 2 * 4],
m.matrix[3 + 3 * 4] - m.matrix[0 + 3 * 4]);
plane /= plane.length3();
return plane;
}
Vec4f FrustumPlanes::top_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] - m.matrix[1 + 0 * 4],
m.matrix[3 + 1 * 4] - m.matrix[1 + 1 * 4],
m.matrix[3 + 2 * 4] - m.matrix[1 + 2 * 4],
m.matrix[3 + 3 * 4] - m.matrix[1 + 3 * 4]);
plane /= plane.length3();
return plane;
}
Vec4f FrustumPlanes::bottom_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] + m.matrix[1 + 0 * 4],
m.matrix[3 + 1 * 4] + m.matrix[1 + 1 * 4],
m.matrix[3 + 2 * 4] + m.matrix[1 + 2 * 4],
m.matrix[3 + 3 * 4] + m.matrix[1 + 3 * 4]);
plane /= plane.length3();
return plane;
}
Vec4f FrustumPlanes::near_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] + m.matrix[2 + 0 * 4],
m.matrix[3 + 1 * 4] + m.matrix[2 + 1 * 4],
m.matrix[3 + 2 * 4] + m.matrix[2 + 2 * 4],
m.matrix[3 + 3 * 4] + m.matrix[2 + 3 * 4]);
plane /= plane.length3();
return plane;
}
Vec4f FrustumPlanes::far_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] - m.matrix[2 + 0 * 4],
m.matrix[3 + 1 * 4] - m.matrix[2 + 1 * 4],
m.matrix[3 + 2 * 4] - m.matrix[2 + 2 * 4],
m.matrix[3 + 3 * 4] - m.matrix[2 + 3 * 4]);
plane /= plane.length3();
return plane;
}

View file

@ -0,0 +1,179 @@
/*
** Various 3D intersection tests
** Copyright (c) 1997-2015 The UICore Team
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "polyrenderer/drawers/poly_triangle.h"
#include <algorithm>
#include <cmath>
class Vec3f;
class Vec4f
{
public:
Vec4f() = default;
Vec4f(const Vec4f &) = default;
Vec4f(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) { }
Vec4f(float v) : x(v), y(v), z(v), w(v) { }
Vec4f(const Vec3f &xyz, float w);
static float dot(const Vec4f &a, const Vec4f &b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; }
static float dot3(const Vec4f &a, const Vec4f &b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
float length3() const { return std::sqrt(dot3(*this, *this)); }
float magnitude() const { return std::sqrt(dot(*this, *this)); }
Vec4f &operator+=(const Vec4f &b) { *this = Vec4f(x + b.x, y + b.y, z + b.z, w + b.w); return *this; }
Vec4f &operator-=(const Vec4f &b) { *this = Vec4f(x - b.x, y - b.y, z - b.z, w - b.w); return *this; }
Vec4f &operator*=(const Vec4f &b) { *this = Vec4f(x * b.x, y * b.y, z * b.z, w * b.w); return *this; }
Vec4f &operator/=(const Vec4f &b) { *this = Vec4f(x / b.x, y / b.y, z / b.z, w / b.w); return *this; }
Vec4f &operator+=(float b) { *this = Vec4f(x + b, y + b, z + b, w + b); return *this; }
Vec4f &operator-=(float b) { *this = Vec4f(x - b, y - b, z - b, w - b); return *this; }
Vec4f &operator*=(float b) { *this = Vec4f(x * b, y * b, z * b, w * b); return *this; }
Vec4f &operator/=(float b) { *this = Vec4f(x / b, y / b, z / b, w / b); return *this; }
float x, y, z, w;
};
inline bool operator==(const Vec4f &a, const Vec4f &b) { return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; }
inline bool operator!=(const Vec4f &a, const Vec4f &b) { return a.x != b.x || a.y != b.y || a.z != b.z || a.w == b.w; }
class Vec3f
{
public:
Vec3f() = default;
Vec3f(const Vec3f &) = default;
Vec3f(const Vec4f &v) : x(v.x), y(v.y), z(v.z) { }
Vec3f(float x, float y, float z) : x(x), y(y), z(z) { }
Vec3f(float v) : x(v), y(v), z(v) { }
static float dot(const Vec3f &a, const Vec3f &b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
float length() const { return std::sqrt(dot(*this, *this)); }
Vec3f &operator+=(const Vec3f &b) { *this = Vec3f(x + b.x, y + b.y, z + b.z); return *this; }
Vec3f &operator-=(const Vec3f &b) { *this = Vec3f(x - b.x, y - b.y, z - b.z); return *this; }
Vec3f &operator*=(const Vec3f &b) { *this = Vec3f(x * b.x, y * b.y, z * b.z); return *this; }
Vec3f &operator/=(const Vec3f &b) { *this = Vec3f(x / b.x, y / b.y, z / b.z); return *this; }
Vec3f &operator+=(float b) { *this = Vec3f(x + b, y + b, z + b); return *this; }
Vec3f &operator-=(float b) { *this = Vec3f(x - b, y - b, z - b); return *this; }
Vec3f &operator*=(float b) { *this = Vec3f(x * b, y * b, z * b); return *this; }
Vec3f &operator/=(float b) { *this = Vec3f(x / b, y / b, z / b); return *this; }
float x, y, z;
};
inline bool operator==(const Vec3f &a, const Vec3f &b) { return a.x == b.x && a.y == b.y && a.z == b.z; }
inline bool operator!=(const Vec3f &a, const Vec3f &b) { return a.x != b.x || a.y != b.y || a.z != b.z; }
inline Vec3f operator+(const Vec3f &a, const Vec3f &b) { return Vec3f(a.x + b.x, a.y + b.y, a.z + b.z); }
inline Vec3f operator-(const Vec3f &a, const Vec3f &b) { return Vec3f(a.x - b.x, a.y - b.y, a.z - b.z); }
inline Vec3f operator*(const Vec3f &a, const Vec3f &b) { return Vec3f(a.x * b.x, a.y * b.y, a.z * b.z); }
inline Vec3f operator/(const Vec3f &a, const Vec3f &b) { return Vec3f(a.x / b.x, a.y / b.y, a.z / b.z); }
inline Vec3f operator+(const Vec3f &a, float b) { return Vec3f(a.x + b, a.y + b, a.z + b); }
inline Vec3f operator-(const Vec3f &a, float b) { return Vec3f(a.x - b, a.y - b, a.z - b); }
inline Vec3f operator*(const Vec3f &a, float b) { return Vec3f(a.x * b, a.y * b, a.z * b); }
inline Vec3f operator/(const Vec3f &a, float b) { return Vec3f(a.x / b, a.y / b, a.z / b); }
inline Vec3f operator+(float a, const Vec3f &b) { return Vec3f(a + b.x, a + b.y, a + b.z); }
inline Vec3f operator-(float a, const Vec3f &b) { return Vec3f(a - b.x, a - b.y, a - b.z); }
inline Vec3f operator*(float a, const Vec3f &b) { return Vec3f(a * b.x, a * b.y, a * b.z); }
inline Vec3f operator/(float a, const Vec3f &b) { return Vec3f(a / b.x, a / b.y, a / b.z); }
inline Vec4f::Vec4f(const Vec3f &xyz, float w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { }
typedef TriMatrix Mat4f;
class AxisAlignedBoundingBox
{
public:
AxisAlignedBoundingBox() : aabb_min(), aabb_max() {}
AxisAlignedBoundingBox(const Vec3f &aabb_min, const Vec3f &aabb_max) : aabb_min(aabb_min), aabb_max(aabb_max) { }
AxisAlignedBoundingBox(const AxisAlignedBoundingBox &aabb, const Vec3f &barycentric_min, const Vec3f &barycentric_max)
: aabb_min(mix(aabb.aabb_min, aabb.aabb_max, barycentric_min)), aabb_max(mix(aabb.aabb_min, aabb.aabb_max, barycentric_max)) { }
Vec3f center() const { return (aabb_max + aabb_min) * 0.5f; }
Vec3f extents() const { return (aabb_max - aabb_min) * 0.5f; }
Vec3f aabb_min;
Vec3f aabb_max;
private:
template<typename A, typename B, typename C>
inline A mix(A a, B b, C mix)
{
return a * (C(1) - mix) + b * mix;
}
};
class OrientedBoundingBox
{
public:
Vec3f center;
Vec3f extents;
Vec3f axis_x;
Vec3f axis_y;
Vec3f axis_z;
};
class FrustumPlanes
{
public:
FrustumPlanes();
explicit FrustumPlanes(const Mat4f &world_to_projection);
Vec4f planes[6];
private:
static Vec4f left_frustum_plane(const Mat4f &matrix);
static Vec4f right_frustum_plane(const Mat4f &matrix);
static Vec4f top_frustum_plane(const Mat4f &matrix);
static Vec4f bottom_frustum_plane(const Mat4f &matrix);
static Vec4f near_frustum_plane(const Mat4f &matrix);
static Vec4f far_frustum_plane(const Mat4f &matrix);
};
class IntersectionTest
{
public:
enum Result
{
outside,
inside,
intersecting,
};
enum OverlapResult
{
disjoint,
overlap
};
static Result plane_aabb(const Vec4f &plane, const AxisAlignedBoundingBox &aabb);
static Result plane_obb(const Vec4f &plane, const OrientedBoundingBox &obb);
static OverlapResult sphere(const Vec3f &center1, float radius1, const Vec3f &center2, float radius2);
static OverlapResult sphere_aabb(const Vec3f &center, float radius, const AxisAlignedBoundingBox &aabb);
static OverlapResult aabb(const AxisAlignedBoundingBox &a, const AxisAlignedBoundingBox &b);
static Result frustum_aabb(const FrustumPlanes &frustum, const AxisAlignedBoundingBox &box);
static Result frustum_obb(const FrustumPlanes &frustum, const OrientedBoundingBox &box);
static OverlapResult ray_aabb(const Vec3f &ray_start, const Vec3f &ray_end, const AxisAlignedBoundingBox &box);
};

View file

@ -0,0 +1,189 @@
/*
** Triangle drawers
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stddef.h>
#include "templates.h"
#include "doomdef.h"
#include "i_system.h"
#include "w_wad.h"
#include "v_video.h"
#include "doomstat.h"
#include "st_stuff.h"
#include "g_game.h"
#include "g_level.h"
#include "r_data/r_translate.h"
#include "v_palette.h"
#include "r_data/colormaps.h"
#include "r_utility.h"
#include "tri_matrix.h"
#include "polyrenderer/drawers/poly_triangle.h"
#include "swrenderer/drawers/r_draw_rgba.h"
#include "swrenderer/viewport/r_viewport.h"
TriMatrix TriMatrix::null()
{
TriMatrix m;
memset(m.matrix, 0, sizeof(m.matrix));
return m;
}
TriMatrix TriMatrix::identity()
{
TriMatrix m = null();
m.matrix[0] = 1.0f;
m.matrix[5] = 1.0f;
m.matrix[10] = 1.0f;
m.matrix[15] = 1.0f;
return m;
}
TriMatrix TriMatrix::translate(float x, float y, float z)
{
TriMatrix m = identity();
m.matrix[0 + 3 * 4] = x;
m.matrix[1 + 3 * 4] = y;
m.matrix[2 + 3 * 4] = z;
return m;
}
TriMatrix TriMatrix::scale(float x, float y, float z)
{
TriMatrix m = null();
m.matrix[0 + 0 * 4] = x;
m.matrix[1 + 1 * 4] = y;
m.matrix[2 + 2 * 4] = z;
m.matrix[3 + 3 * 4] = 1;
return m;
}
TriMatrix TriMatrix::rotate(float angle, float x, float y, float z)
{
float c = cosf(angle);
float s = sinf(angle);
TriMatrix m = null();
m.matrix[0 + 0 * 4] = (x*x*(1.0f - c) + c);
m.matrix[0 + 1 * 4] = (x*y*(1.0f - c) - z*s);
m.matrix[0 + 2 * 4] = (x*z*(1.0f - c) + y*s);
m.matrix[1 + 0 * 4] = (y*x*(1.0f - c) + z*s);
m.matrix[1 + 1 * 4] = (y*y*(1.0f - c) + c);
m.matrix[1 + 2 * 4] = (y*z*(1.0f - c) - x*s);
m.matrix[2 + 0 * 4] = (x*z*(1.0f - c) - y*s);
m.matrix[2 + 1 * 4] = (y*z*(1.0f - c) + x*s);
m.matrix[2 + 2 * 4] = (z*z*(1.0f - c) + c);
m.matrix[3 + 3 * 4] = 1.0f;
return m;
}
TriMatrix TriMatrix::swapYZ()
{
TriMatrix m = null();
m.matrix[0 + 0 * 4] = 1.0f;
m.matrix[1 + 2 * 4] = 1.0f;
m.matrix[2 + 1 * 4] = -1.0f;
m.matrix[3 + 3 * 4] = 1.0f;
return m;
}
TriMatrix TriMatrix::perspective(float fovy, float aspect, float z_near, float z_far)
{
float f = (float)(1.0 / tan(fovy * M_PI / 360.0));
TriMatrix m = null();
m.matrix[0 + 0 * 4] = f / aspect;
m.matrix[1 + 1 * 4] = f;
m.matrix[2 + 2 * 4] = (z_far + z_near) / (z_near - z_far);
m.matrix[2 + 3 * 4] = (2.0f * z_far * z_near) / (z_near - z_far);
m.matrix[3 + 2 * 4] = -1.0f;
return m;
}
TriMatrix TriMatrix::frustum(float left, float right, float bottom, float top, float near, float far)
{
float a = (right + left) / (right - left);
float b = (top + bottom) / (top - bottom);
float c = -(far + near) / (far - near);
float d = -(2.0f * far) / (far - near);
TriMatrix m = null();
m.matrix[0 + 0 * 4] = 2.0f * near / (right - left);
m.matrix[1 + 1 * 4] = 2.0f * near / (top - bottom);
m.matrix[0 + 2 * 4] = a;
m.matrix[1 + 2 * 4] = b;
m.matrix[2 + 2 * 4] = c;
m.matrix[2 + 3 * 4] = d;
m.matrix[3 + 2 * 4] = -1;
return m;
}
TriMatrix TriMatrix::worldToView()
{
TriMatrix m = null();
m.matrix[0 + 0 * 4] = (float)ViewSin;
m.matrix[0 + 1 * 4] = (float)-ViewCos;
m.matrix[1 + 2 * 4] = 1.0f;
m.matrix[2 + 0 * 4] = (float)-ViewCos;
m.matrix[2 + 1 * 4] = (float)-ViewSin;
m.matrix[3 + 3 * 4] = 1.0f;
return m * translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z);
}
TriMatrix TriMatrix::viewToClip()
{
auto viewport = swrenderer::RenderViewport::Instance();
float near = 5.0f;
float far = 65536.0f;
float width = (float)(FocalTangent * near);
float top = (float)(viewport->CenterY / viewport->InvZtoScale * near);
float bottom = (float)(top - viewheight / viewport->InvZtoScale * near);
return frustum(-width, width, bottom, top, near, far);
}
TriMatrix TriMatrix::operator*(const TriMatrix &mult) const
{
TriMatrix result;
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 4; y++)
{
result.matrix[x + y * 4] =
matrix[0 * 4 + x] * mult.matrix[y * 4 + 0] +
matrix[1 * 4 + x] * mult.matrix[y * 4 + 1] +
matrix[2 * 4 + x] * mult.matrix[y * 4 + 2] +
matrix[3 * 4 + x] * mult.matrix[y * 4 + 3];
}
}
return result;
}
ShadedTriVertex TriMatrix::operator*(TriVertex v) const
{
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;
ShadedTriVertex sv;
sv.x = vx;
sv.y = vy;
sv.z = vz;
sv.w = vw;
for (int i = 0; i < TriVertex::NumVarying; i++)
sv.varying[i] = v.varying[i];
return sv;
}

View file

@ -0,0 +1,46 @@
/*
** Triangle drawers
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
struct TriVertex;
struct ShadedTriVertex;
struct TriMatrix
{
static TriMatrix null();
static TriMatrix identity();
static TriMatrix translate(float x, float y, float z);
static TriMatrix scale(float x, float y, float z);
static TriMatrix rotate(float angle, float x, float y, float z);
static TriMatrix swapYZ();
static TriMatrix perspective(float fovy, float aspect, float near, float far);
static TriMatrix frustum(float left, float right, float bottom, float top, float near, float far);
static TriMatrix worldToView(); // Software renderer world to view space transform
static TriMatrix viewToClip(); // Software renderer shearing projection
ShadedTriVertex operator*(TriVertex v) const;
TriMatrix operator*(const TriMatrix &m) const;
float matrix[16];
};

View file

@ -0,0 +1,225 @@
/*
** Polygon Doom software renderer
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "sbar.h"
#include "st_stuff.h"
#include "r_data/r_translate.h"
#include "r_data/r_interpolate.h"
#include "poly_renderer.h"
#include "gl/data/gl_data.h"
#include "d_net.h"
#include "po_man.h"
#include "st_stuff.h"
#include "swrenderer/scene/r_scene.h"
#include "swrenderer/scene/r_light.h"
#include "swrenderer/drawers/r_draw_rgba.h"
#include "swrenderer/viewport/r_viewport.h"
EXTERN_CVAR(Bool, r_shadercolormaps)
EXTERN_CVAR(Int, screenblocks)
void InitGLRMapinfoData();
extern bool r_showviewer;
/////////////////////////////////////////////////////////////////////////////
PolyRenderer *PolyRenderer::Instance()
{
static PolyRenderer scene;
return &scene;
}
PolyRenderer::PolyRenderer() : Thread(nullptr)
{
}
void PolyRenderer::RenderView(player_t *player)
{
using namespace swrenderer;
auto viewport = RenderViewport::Instance();
viewport->RenderTarget = screen;
int width = SCREENWIDTH;
int height = SCREENHEIGHT;
int stHeight = gST_Y;
float trueratio;
ActiveRatio(width, height, &trueratio);
viewport->SetViewport(width, height, trueratio);
RenderActorView(player->mo, false);
// Apply special colormap if the target cannot do it
CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->ShaderColormap() && viewport->RenderTarget->IsBgra() && !(r_shadercolormaps && screen->Accel2D))
{
Thread.DrawQueue->Push<ApplySpecialColormapRGBACommand>(cameraLight->ShaderColormap(), screen);
}
DrawerThreads::Execute({ Thread.DrawQueue });
}
void PolyRenderer::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines)
{
auto viewport = swrenderer::RenderViewport::Instance();
const bool savedviewactive = viewactive;
viewwidth = width;
viewport->RenderTarget = canvas;
R_SetWindow(12, width, height, height, true);
viewport->SetViewport(width, height, WidescreenRatio);
viewwindowx = x;
viewwindowy = y;
viewactive = true;
canvas->Lock(true);
RenderActorView(actor, dontmaplines);
DrawerThreads::Execute({ Thread.DrawQueue });
canvas->Unlock();
viewport->RenderTarget = screen;
R_ExecuteSetViewSize();
float trueratio;
ActiveRatio(width, height, &trueratio);
viewport->SetViewport(width, height, WidescreenRatio);
viewactive = savedviewactive;
}
void PolyRenderer::RenderActorView(AActor *actor, bool dontmaplines)
{
NetUpdate();
DontMapLines = dontmaplines;
P_FindParticleSubsectors();
PO_LinkToSubsectors();
R_SetupFrame(actor);
swrenderer::CameraLight::Instance()->SetCamera(actor);
swrenderer::RenderViewport::Instance()->SetupFreelook();
ActorRenderFlags savedflags = camera->renderflags;
// Never draw the player unless in chasecam mode
if (!r_showviewer)
camera->renderflags |= RF_INVISIBLE;
ClearBuffers();
SetSceneViewport();
SetupPerspectiveMatrix();
MainPortal.SetViewpoint(WorldToClip, Vec4f(0.0f, 0.0f, 0.0f, 1.0f), GetNextStencilValue());
MainPortal.Render(0);
Skydome.Render(WorldToClip);
MainPortal.RenderTranslucent(0);
PlayerSprites.Render();
camera->renderflags = savedflags;
interpolator.RestoreInterpolations ();
NetUpdate();
}
void PolyRenderer::RenderRemainingPlayerSprites()
{
PlayerSprites.RenderRemainingSprites();
}
void PolyRenderer::ClearBuffers()
{
PolyVertexBuffer::Clear();
auto viewport = swrenderer::RenderViewport::Instance();
PolyStencilBuffer::Instance()->Clear(viewport->RenderTarget->GetWidth(), viewport->RenderTarget->GetHeight(), 0);
PolySubsectorGBuffer::Instance()->Resize(viewport->RenderTarget->GetPitch(), viewport->RenderTarget->GetHeight());
NextStencilValue = 0;
SeenLinePortals.clear();
SeenMirrors.clear();
}
void PolyRenderer::SetSceneViewport()
{
using namespace swrenderer;
auto viewport = RenderViewport::Instance();
if (viewport->RenderTarget == screen) // Rendering to screen
{
int height;
if (screenblocks >= 10)
height = SCREENHEIGHT;
else
height = (screenblocks*SCREENHEIGHT / 10) & ~7;
int bottom = SCREENHEIGHT - (height + viewwindowy - ((height - viewheight) / 2));
PolyTriangleDrawer::set_viewport(viewwindowx, SCREENHEIGHT - bottom - height, viewwidth, height, viewport->RenderTarget);
}
else // Rendering to camera texture
{
PolyTriangleDrawer::set_viewport(0, 0, viewport->RenderTarget->GetWidth(), viewport->RenderTarget->GetHeight(), viewport->RenderTarget);
}
}
void PolyRenderer::SetupPerspectiveMatrix()
{
static bool bDidSetup = false;
if (!bDidSetup)
{
InitGLRMapinfoData();
bDidSetup = true;
}
// Code provided courtesy of Graf Zahl. Now we just have to plug it into the viewmatrix code...
// We have to scale the pitch to account for the pixel stretching, because the playsim doesn't know about this and treats it as 1:1.
double radPitch = ViewPitch.Normalized180().Radians();
double angx = cos(radPitch);
double angy = sin(radPitch) * glset.pixelstretch;
double alen = sqrt(angx*angx + angy*angy);
float adjustedPitch = (float)asin(angy / alen);
float adjustedViewAngle = (float)(ViewAngle - 90).Radians();
float ratio = WidescreenRatio;
float fovratio = (WidescreenRatio >= 1.3f) ? 1.333333f : ratio;
float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(FieldOfView.Radians() / 2) / fovratio)).Degrees);
TriMatrix worldToView =
TriMatrix::rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) *
TriMatrix::rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) *
TriMatrix::scale(1.0f, glset.pixelstretch, 1.0f) *
TriMatrix::swapYZ() *
TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z);
WorldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
}
bool PolyRenderer::InsertSeenLinePortal(FLinePortal *portal)
{
return SeenLinePortals.insert(portal).second;
}
bool PolyRenderer::InsertSeenMirror(line_t *mirrorLine)
{
return SeenMirrors.insert(mirrorLine).second;
}

View file

@ -0,0 +1,75 @@
/*
** Polygon Doom software renderer
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include <vector>
#include <memory>
#include <algorithm>
#include <functional>
#include "doomdata.h"
#include "r_utility.h"
#include "scene/poly_portal.h"
#include "scene/poly_playersprite.h"
#include "scene/poly_sky.h"
#include "swrenderer/r_renderthread.h"
class AActor;
class DCanvas;
class DrawerCommandQueue;
typedef std::shared_ptr<DrawerCommandQueue> DrawerCommandQueuePtr;
class PolyRenderer
{
public:
PolyRenderer();
void RenderView(player_t *player);
void RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines);
void RenderRemainingPlayerSprites();
static PolyRenderer *Instance();
uint32_t GetNextStencilValue() { uint32_t value = NextStencilValue; NextStencilValue += 2; return value; }
bool InsertSeenLinePortal(FLinePortal *portal);
bool InsertSeenMirror(line_t *mirrorLine);
bool DontMapLines = false;
swrenderer::RenderThread Thread;
private:
void RenderActorView(AActor *actor, bool dontmaplines);
void ClearBuffers();
void SetSceneViewport();
void SetupPerspectiveMatrix();
TriMatrix WorldToClip;
RenderPolyScene MainPortal;
PolySkyDome Skydome;
RenderPolyPlayerSprites PlayerSprites;
uint32_t NextStencilValue = 0;
std::set<FLinePortal *> SeenLinePortals;
std::set<line_t *> SeenMirrors;
};

View file

@ -0,0 +1,311 @@
/*
** Potential visible set (PVS) handling
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "sbar.h"
#include "r_data/r_translate.h"
#include "poly_cull.h"
#include "polyrenderer/poly_renderer.h"
void PolyCull::CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPlane)
{
PvsSectors.clear();
frustumPlanes = FrustumPlanes(worldToClip);
PortalClipPlane = portalClipPlane;
// Cull front to back
MaxCeilingHeight = 0.0;
MinFloorHeight = 0.0;
if (numnodes == 0)
CullSubsector(subsectors);
else
CullNode(nodes + numnodes - 1); // The head node is the last node output.
}
void PolyCull::CullNode(void *node)
{
while (!((size_t)node & 1)) // Keep going until found a subsector
{
node_t *bsp = (node_t *)node;
// Decide which side the view point is on.
int side = PointOnSide(ViewPos, bsp);
// Recursively divide front space (toward the viewer).
CullNode(bsp->children[side]);
// Possibly divide back space (away from the viewer).
side ^= 1;
if (!CheckBBox(bsp->bbox[side]))
return;
node = bsp->children[side];
}
subsector_t *sub = (subsector_t *)((BYTE *)node - 1);
CullSubsector(sub);
}
void PolyCull::CullSubsector(subsector_t *sub)
{
// Update sky heights for the scene
MaxCeilingHeight = MAX(MaxCeilingHeight, sub->sector->ceilingplane.Zat0());
MinFloorHeight = MIN(MinFloorHeight, sub->sector->floorplane.Zat0());
// Mark that we need to render this
PvsSectors.push_back(sub);
// Update culling info for further bsp clipping
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
if ((line->sidedef == nullptr || !(line->sidedef->Flags & WALLF_POLYOBJ)) && line->backsector == nullptr)
{
// Skip lines not facing viewer
DVector2 pt1 = line->v1->fPos() - ViewPos;
DVector2 pt2 = line->v2->fPos() - ViewPos;
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
continue;
int sx1, sx2;
if (GetSegmentRangeForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), sx1, sx2) == LineSegmentRange::HasSegment)
{
MarkSegmentCulled(sx1, sx2);
}
}
}
}
void PolyCull::ClearSolidSegments()
{
SolidSegments.clear();
SolidSegments.reserve(SolidCullScale + 2);
SolidSegments.push_back({ -0x7fff, -SolidCullScale });
SolidSegments.push_back({ SolidCullScale , 0x7fff });
}
void PolyCull::InvertSegments()
{
TempInvertSolidSegments.swap(SolidSegments);
ClearSolidSegments();
int x = -0x7fff;
for (const auto &segment : TempInvertSolidSegments)
{
MarkSegmentCulled(x, segment.X1 - 1);
x = segment.X2 + 1;
}
}
bool PolyCull::IsSegmentCulled(int x1, int x2) const
{
x1 = clamp(x1, -0x7ffe, 0x7ffd);
x2 = clamp(x2, -0x7ffd, 0x7ffe);
int next = 0;
while (SolidSegments[next].X2 <= x2)
next++;
return (x1 >= SolidSegments[next].X1 && x2 <= SolidSegments[next].X2);
}
void PolyCull::MarkSegmentCulled(int x1, int x2)
{
if (x1 >= x2)
return;
x1 = clamp(x1, -0x7ffe, 0x7ffd);
x2 = clamp(x2, -0x7ffd, 0x7ffe);
int cur = 0;
while (true)
{
if (SolidSegments[cur].X1 <= x1 && SolidSegments[cur].X2 >= x2) // Already fully marked
{
break;
}
else if (SolidSegments[cur].X2 >= x1 && SolidSegments[cur].X1 <= x2) // Merge segments
{
// Find last segment
int merge = cur;
while (merge + 1 != (int)SolidSegments.size() && SolidSegments[merge + 1].X1 <= x2)
merge++;
// Apply new merged range
SolidSegments[cur].X1 = MIN(SolidSegments[cur].X1, x1);
SolidSegments[cur].X2 = MAX(SolidSegments[merge].X2, x2);
// Remove additional segments we merged with
if (merge > cur)
SolidSegments.erase(SolidSegments.begin() + (cur + 1), SolidSegments.begin() + (merge + 1));
break;
}
else if (SolidSegments[cur].X1 > x1) // Insert new segment
{
SolidSegments.insert(SolidSegments.begin() + cur, { x1, x2 });
break;
}
cur++;
}
}
int PolyCull::PointOnSide(const DVector2 &pos, const node_t *node)
{
return DMulScale32(FLOAT2FIXED(pos.Y) - node->y, node->dx, node->x - FLOAT2FIXED(pos.X), node->dy) > 0;
}
bool PolyCull::CheckBBox(float *bspcoord)
{
// Start using a quick frustum AABB test:
AxisAlignedBoundingBox aabb(Vec3f(bspcoord[BOXLEFT], bspcoord[BOXBOTTOM], (float)ViewPos.Z - 1000.0f), Vec3f(bspcoord[BOXRIGHT], bspcoord[BOXTOP], (float)ViewPos.Z + 1000.0f));
auto result = IntersectionTest::frustum_aabb(frustumPlanes, aabb);
if (result == IntersectionTest::outside)
return false;
// Skip if its in front of the portal:
if (IntersectionTest::plane_aabb(PortalClipPlane, aabb) == IntersectionTest::outside)
return false;
// Occlusion test using solid segments:
static const int lines[4][4] =
{
{ BOXLEFT, BOXBOTTOM, BOXRIGHT, BOXBOTTOM },
{ BOXRIGHT, BOXBOTTOM, BOXRIGHT, BOXTOP },
{ BOXRIGHT, BOXTOP, BOXLEFT, BOXTOP },
{ BOXLEFT, BOXTOP, BOXLEFT, BOXBOTTOM }
};
bool foundline = false;
int minsx1, maxsx2;
for (int i = 0; i < 4; i++)
{
int j = i < 3 ? i + 1 : 0;
float x1 = bspcoord[lines[i][0]];
float y1 = bspcoord[lines[i][1]];
float x2 = bspcoord[lines[i][2]];
float y2 = bspcoord[lines[i][3]];
int sx1, sx2;
LineSegmentRange result = GetSegmentRangeForLine(x1, y1, x2, y2, sx1, sx2);
if (result == LineSegmentRange::HasSegment)
{
if (foundline)
{
minsx1 = MIN(minsx1, sx1);
maxsx2 = MAX(maxsx2, sx2);
}
else
{
minsx1 = sx1;
maxsx2 = sx2;
foundline = true;
}
}
else if (result == LineSegmentRange::AlwaysVisible)
{
return true;
}
}
if (!foundline)
return false;
return !IsSegmentCulled(minsx1, maxsx2);
}
LineSegmentRange PolyCull::GetSegmentRangeForLine(double x1, double y1, double x2, double y2, int &sx1, int &sx2) const
{
double znear = 5.0;
double updownnear = -400.0;
double sidenear = 400.0;
// Clip line to the portal clip plane
float distance1 = Vec4f::dot(PortalClipPlane, Vec4f((float)x1, (float)y1, 0.0f, 1.0f));
float distance2 = Vec4f::dot(PortalClipPlane, Vec4f((float)x2, (float)y2, 0.0f, 1.0f));
if (distance1 < 0.0f && distance2 < 0.0f)
{
return LineSegmentRange::NotVisible;
}
else if (distance1 < 0.0f || distance2 < 0.0f)
{
double t1 = 0.0f, t2 = 1.0f;
if (distance1 < 0.0f)
t1 = clamp(distance1 / (distance1 - distance2), 0.0f, 1.0f);
else
t2 = clamp(distance2 / (distance1 - distance2), 0.0f, 1.0f);
double nx1 = x1 * (1.0 - t1) + x2 * t1;
double ny1 = y1 * (1.0 - t1) + y2 * t1;
double nx2 = x1 * (1.0 - t2) + x2 * t2;
double ny2 = y1 * (1.0 - t2) + y2 * t2;
x1 = nx1;
x2 = nx2;
y1 = ny1;
y2 = ny2;
}
// Transform to 2D view space:
x1 = x1 - ViewPos.X;
y1 = y1 - ViewPos.Y;
x2 = x2 - ViewPos.X;
y2 = y2 - ViewPos.Y;
double rx1 = x1 * ViewSin - y1 * ViewCos;
double rx2 = x2 * ViewSin - y2 * ViewCos;
double ry1 = x1 * ViewCos + y1 * ViewSin;
double ry2 = x2 * ViewCos + y2 * ViewSin;
// Is it potentially visible when looking straight up or down?
if (!(ry1 < updownnear && ry2 < updownnear) && !(ry1 > znear && ry2 > znear) &&
!(rx1 < -sidenear && rx2 < -sidenear) && !(rx1 > sidenear && rx2 > sidenear))
return LineSegmentRange::AlwaysVisible;
// Cull if line is entirely behind view
if (ry1 < znear && ry2 < znear)
return LineSegmentRange::NotVisible;
// Clip line, if needed
double t1 = 0.0f, t2 = 1.0f;
if (ry1 < znear)
t1 = clamp((znear - ry1) / (ry2 - ry1), 0.0, 1.0);
if (ry2 < znear)
t2 = clamp((znear - ry2) / (ry2 - ry1), 0.0, 1.0);
if (t1 != 0.0 || t2 != 1.0)
{
double nx1 = rx1 * (1.0 - t1) + rx2 * t1;
double ny1 = ry1 * (1.0 - t1) + ry2 * t1;
double nx2 = rx1 * (1.0 - t2) + rx2 * t2;
double ny2 = ry1 * (1.0 - t2) + ry2 * t2;
rx1 = nx1;
rx2 = nx2;
ry1 = ny1;
ry2 = ny2;
}
sx1 = (int)floor(clamp(rx1 / ry1 * (SolidCullScale / 3), (double)-SolidCullScale, (double)SolidCullScale));
sx2 = (int)floor(clamp(rx2 / ry2 * (SolidCullScale / 3), (double)-SolidCullScale, (double)SolidCullScale));
if (sx1 > sx2)
std::swap(sx1, sx2);
return (sx1 != sx2) ? LineSegmentRange::HasSegment : LineSegmentRange::AlwaysVisible;
}

View file

@ -0,0 +1,71 @@
/*
** Potential visible set (PVS) handling
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "polyrenderer/drawers/poly_triangle.h"
#include "polyrenderer/math/poly_intersection.h"
enum class LineSegmentRange
{
NotVisible,
HasSegment,
AlwaysVisible
};
class PolyCull
{
public:
void ClearSolidSegments();
void CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPlane);
LineSegmentRange GetSegmentRangeForLine(double x1, double y1, double x2, double y2, int &sx1, int &sx2) const;
void MarkSegmentCulled(int x1, int x2);
bool IsSegmentCulled(int x1, int x2) const;
void InvertSegments();
std::vector<subsector_t *> PvsSectors;
double MaxCeilingHeight = 0.0;
double MinFloorHeight = 0.0;
private:
struct SolidSegment
{
SolidSegment(int x1, int x2) : X1(x1), X2(x2) { }
int X1, X2;
};
void CullNode(void *node);
void CullSubsector(subsector_t *sub);
int PointOnSide(const DVector2 &pos, const node_t *node);
// Checks BSP node/subtree bounding box.
// Returns true if some part of the bbox might be visible.
bool CheckBBox(float *bspcoord);
std::vector<SolidSegment> SolidSegments;
std::vector<SolidSegment> TempInvertSolidSegments;
const int SolidCullScale = 3000;
FrustumPlanes frustumPlanes;
Vec4f PortalClipPlane;
};

View file

@ -0,0 +1,180 @@
/*
** Handling drawing a decal
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "sbar.h"
#include "r_data/r_translate.h"
#include "poly_decal.h"
#include "polyrenderer/poly_renderer.h"
#include "a_sharedglobal.h"
#include "swrenderer/scene/r_scene.h"
#include "swrenderer/scene/r_light.h"
void RenderPolyDecal::RenderWallDecals(const TriMatrix &worldToClip, const Vec4f &clipPlane, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue)
{
if (line->linedef == nullptr && line->sidedef == nullptr)
return;
for (DBaseDecal *decal = line->sidedef->AttachedDecals; decal != nullptr; decal = decal->WallNext)
{
RenderPolyDecal render;
render.Render(worldToClip, clipPlane, decal, line, subsectorDepth, stencilValue);
}
}
void RenderPolyDecal::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue)
{
if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid())
return;
FTexture *tex = TexMan(decal->PicNum, true);
if (tex == nullptr || tex->UseType == FTexture::TEX_Null)
return;
double edge_right = tex->GetWidth();
double edge_left = tex->LeftOffset;
edge_right = (edge_right - edge_left) * decal->ScaleX;
edge_left *= decal->ScaleX;
double dcx, dcy;
decal->GetXY(line->sidedef, dcx, dcy);
DVector2 decal_pos = { dcx, dcy };
DVector2 angvec = (line->v2->fPos() - line->v1->fPos()).Unit();
DVector2 decal_left = decal_pos - edge_left * angvec;
DVector2 decal_right = decal_pos + edge_right * angvec;
// Determine actor z
double zpos = decal->Z;
sector_t *front = line->frontsector;
sector_t *back = (line->backsector != nullptr) ? line->backsector : line->frontsector;
switch (decal->RenderFlags & RF_RELMASK)
{
default:
zpos = decal->Z;
break;
case RF_RELUPPER:
if (line->linedef->flags & ML_DONTPEGTOP)
zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
else
zpos = decal->Z + back->GetPlaneTexZ(sector_t::ceiling);
break;
case RF_RELLOWER:
if (line->linedef->flags & ML_DONTPEGBOTTOM)
zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
else
zpos = decal->Z + back->GetPlaneTexZ(sector_t::floor);
break;
case RF_RELMID:
if (line->linedef->flags & ML_DONTPEGBOTTOM)
zpos = decal->Z + front->GetPlaneTexZ(sector_t::floor);
else
zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
}
DVector2 spriteScale = { decal->ScaleX, decal->ScaleY };
double thingxscalemul = spriteScale.X / tex->Scale.X;
double thingyscalemul = spriteScale.Y / tex->Scale.Y;
double spriteHeight = thingyscalemul * tex->GetHeight();
bool flipTextureX = (decal->RenderFlags & RF_XFLIP) == RF_XFLIP;
DVector2 points[2] = { decal_left, decal_right };
TriVertex *vertices = PolyVertexBuffer::GetVertices(4);
if (!vertices)
return;
bool foggy = false;
int actualextralight = foggy ? 0 : extralight << 4;
std::pair<float, float> offsets[4] =
{
{ 0.0f, 1.0f },
{ 1.0f, 1.0f },
{ 1.0f, 0.0f },
{ 0.0f, 0.0f },
};
for (int i = 0; i < 4; i++)
{
auto &p = (i == 0 || i == 3) ? points[0] : points[1];
vertices[i].x = (float)p.X;
vertices[i].y = (float)p.Y;
vertices[i].z = (float)(zpos + spriteHeight * offsets[i].second - spriteHeight * 0.5);
vertices[i].w = 1.0f;
vertices[i].varying[0] = (float)(offsets[i].first * tex->Scale.X);
vertices[i].varying[1] = (float)((1.0f - offsets[i].second) * tex->Scale.Y);
if (flipTextureX)
vertices[i].varying[0] = 1.0f - vertices[i].varying[0];
}
bool fullbrightSprite = (decal->RenderFlags & RF_FULLBRIGHT) == RF_FULLBRIGHT;
swrenderer::CameraLight *cameraLight = swrenderer::CameraLight::Instance();
PolyDrawArgs args;
args.uniforms.flags = 0;
args.SetColormap(front->ColorMap);
args.SetTexture(tex, decal->Translation, true);
args.uniforms.globvis = (float)swrenderer::LightVisibility::Instance()->WallGlobVis(foggy);
if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
{
args.uniforms.light = 256;
args.uniforms.flags |= TriUniforms::fixed_light;
}
else
{
args.uniforms.light = (uint32_t)((front->lightlevel + actualextralight) / 255.0f * 256.0f);
}
args.uniforms.subsectorDepth = subsectorDepth;
if (swrenderer::RenderViewport::Instance()->RenderTarget->IsBgra())
{
args.uniforms.color = 0xff000000 | decal->AlphaColor;
}
else
{
args.uniforms.color = ((uint32_t)decal->AlphaColor) >> 24;
}
args.uniforms.srcalpha = (uint32_t)(decal->Alpha * 256.0 + 0.5);
args.uniforms.destalpha = 256 - args.uniforms.srcalpha;
args.objectToClip = &worldToClip;
args.vinput = vertices;
args.vcount = 4;
args.mode = TriangleDrawMode::Fan;
args.ccw = true;
args.stenciltestvalue = stencilValue;
args.stencilwritevalue = stencilValue;
//mode = R_SetPatchStyle (decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor);
args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
args.blendmode = TriBlendMode::Shaded;
args.subsectorTest = true;
args.writeStencil = false;
args.writeSubsector = false;
PolyTriangleDrawer::draw(args);
}

View file

@ -0,0 +1,36 @@
/*
** Handling drawing a decal
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "polyrenderer/drawers/poly_triangle.h"
class Vec4f;
class RenderPolyDecal
{
public:
static void RenderWallDecals(const TriMatrix &worldToClip, const Vec4f &clipPlane, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue);
private:
void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue);
};

View file

@ -0,0 +1,118 @@
/*
** Particle drawing
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "sbar.h"
#include "r_data/r_translate.h"
#include "poly_particle.h"
#include "polyrenderer/poly_renderer.h"
#include "swrenderer/scene/r_light.h"
void RenderPolyParticle::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue)
{
DVector3 pos = particle->Pos;
double psize = particle->size / 8.0;
double zpos = pos.Z;
DVector2 points[2] =
{
{ pos.X - ViewSin * psize, pos.Y + ViewCos * psize },
{ pos.X + ViewSin * psize, pos.Y - ViewCos * psize }
};
TriVertex *vertices = PolyVertexBuffer::GetVertices(4);
if (!vertices)
return;
bool foggy = false;
int actualextralight = foggy ? 0 : extralight << 4;
std::pair<float, float> offsets[4] =
{
{ 0.0f, 1.0f },
{ 1.0f, 1.0f },
{ 1.0f, 0.0f },
{ 0.0f, 0.0f },
};
for (int i = 0; i < 4; i++)
{
auto &p = (i == 0 || i == 3) ? points[0] : points[1];
vertices[i].x = (float)p.X;
vertices[i].y = (float)p.Y;
vertices[i].z = (float)(zpos + psize * (2.0 * offsets[i].second - 1.0));
vertices[i].w = 1.0f;
vertices[i].varying[0] = (float)(offsets[i].first);
vertices[i].varying[1] = (float)(1.0f - offsets[i].second);
}
// int color = (particle->color >> 24) & 0xff; // pal index, I think
bool fullbrightSprite = particle->bright != 0;
swrenderer::CameraLight *cameraLight = swrenderer::CameraLight::Instance();
PolyDrawArgs args;
args.uniforms.globvis = (float)swrenderer::LightVisibility::Instance()->ParticleGlobVis(foggy);
if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
{
args.uniforms.light = 256;
args.uniforms.flags = TriUniforms::fixed_light;
}
else
{
args.uniforms.light = (uint32_t)((sub->sector->lightlevel + actualextralight) / 255.0f * 256.0f);
args.uniforms.flags = 0;
}
args.uniforms.subsectorDepth = subsectorDepth;
uint32_t alpha = (uint32_t)clamp(particle->alpha * 255.0f + 0.5f, 0.0f, 255.0f);
if (swrenderer::RenderViewport::Instance()->RenderTarget->IsBgra())
{
args.uniforms.color = (alpha << 24) | (particle->color & 0xffffff);
}
else
{
args.uniforms.color = ((uint32_t)particle->color) >> 24;
args.uniforms.srcalpha = alpha;
args.uniforms.destalpha = 255 - alpha;
}
args.objectToClip = &worldToClip;
args.vinput = vertices;
args.vcount = 4;
args.mode = TriangleDrawMode::Fan;
args.ccw = true;
args.stenciltestvalue = stencilValue;
args.stencilwritevalue = stencilValue;
args.SetColormap(sub->sector->ColorMap);
args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
args.subsectorTest = true;
args.writeStencil = false;
args.writeSubsector = false;
args.blendmode = TriBlendMode::AlphaBlend;
PolyTriangleDrawer::draw(args);
}

View file

@ -0,0 +1,34 @@
/*
** Handling drawing a particle
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "polyrenderer/drawers/poly_triangle.h"
#include "p_effect.h"
class Vec4f;
class RenderPolyParticle
{
public:
void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue);
};

View file

@ -0,0 +1,505 @@
/*
** Handling drawing a plane (ceiling, floor)
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "sbar.h"
#include "r_data/r_translate.h"
#include "poly_plane.h"
#include "poly_portal.h"
#include "polyrenderer/poly_renderer.h"
#include "r_sky.h"
#include "swrenderer/scene/r_light.h"
EXTERN_CVAR(Int, r_3dfloors)
void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
{
RenderPolyPlane plane;
if (r_3dfloors)
{
auto frontsector = sub->sector;
auto &ffloors = frontsector->e->XFloor.ffloors;
// 3D floor floors
for (int i = 0; i < (int)ffloors.Size(); i++)
{
F3DFloor *fakeFloor = ffloors[i];
if (!(fakeFloor->flags & FF_EXISTS)) continue;
if (!fakeFloor->model) continue;
if (fakeFloor->bottom.plane->isSlope()) continue;
//if (!(fakeFloor->flags & FF_NOSHADE) || (fakeFloor->flags & (FF_RENDERPLANES | FF_RENDERSIDES)))
// R_3D_AddHeight(fakeFloor->top.plane, frontsector);
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
if (fakeFloor->alpha == 0) continue;
if (fakeFloor->flags & FF_THISINSIDE && fakeFloor->flags & FF_INVERTSECTOR) continue;
//fakeFloor->alpha
double fakeHeight = fakeFloor->top.plane->ZatPoint(frontsector->centerspot);
if (fakeHeight < ViewPos.Z && fakeHeight > frontsector->floorplane.ZatPoint(frontsector->centerspot))
{
plane.Render3DFloor(worldToClip, clipPlane, sub, subsectorDepth, stencilValue, false, fakeFloor);
}
}
// 3D floor ceilings
for (int i = 0; i < (int)ffloors.Size(); i++)
{
F3DFloor *fakeFloor = ffloors[i];
if (!(fakeFloor->flags & FF_EXISTS)) continue;
if (!fakeFloor->model) continue;
if (fakeFloor->top.plane->isSlope()) continue;
//if (!(fakeFloor->flags & FF_NOSHADE) || (fakeFloor->flags & (FF_RENDERPLANES | FF_RENDERSIDES)))
// R_3D_AddHeight(fakeFloor->bottom.plane, frontsector);
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
if (fakeFloor->alpha == 0) continue;
if (!(fakeFloor->flags & FF_THISINSIDE) && (fakeFloor->flags & (FF_SWIMMABLE | FF_INVERTSECTOR)) == (FF_SWIMMABLE | FF_INVERTSECTOR)) continue;
//fakeFloor->alpha
double fakeHeight = fakeFloor->bottom.plane->ZatPoint(frontsector->centerspot);
if (fakeHeight > ViewPos.Z && fakeHeight < frontsector->ceilingplane.ZatPoint(frontsector->centerspot))
{
plane.Render3DFloor(worldToClip, clipPlane, sub, subsectorDepth, stencilValue, true, fakeFloor);
}
}
}
plane.Render(worldToClip, clipPlane, cull, sub, subsectorDepth, stencilValue, true, skyCeilingHeight, sectorPortals);
plane.Render(worldToClip, clipPlane, cull, sub, subsectorDepth, stencilValue, false, skyFloorHeight, sectorPortals);
}
void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakeFloor)
{
FTextureID picnum = ceiling ? *fakeFloor->bottom.texture : *fakeFloor->top.texture;
FTexture *tex = TexMan(picnum);
if (tex->UseType == FTexture::TEX_Null)
return;
swrenderer::CameraLight *cameraLight = swrenderer::CameraLight::Instance();
int lightlevel = 255;
bool foggy = false;
if (cameraLight->FixedLightLevel() < 0 && sub->sector->e->XFloor.lightlist.Size())
{
lightlist_t *light = P_GetPlaneLight(sub->sector, &sub->sector->ceilingplane, false);
//basecolormap = light->extra_colormap;
lightlevel = *light->p_lightlevel;
}
UVTransform xform(ceiling ? fakeFloor->top.model->planes[sector_t::ceiling].xform : fakeFloor->top.model->planes[sector_t::floor].xform, tex);
PolyDrawArgs args;
args.uniforms.globvis = (float)swrenderer::LightVisibility::Instance()->SlopePlaneGlobVis(foggy) * 48.0f;
args.uniforms.light = (uint32_t)(lightlevel / 255.0f * 256.0f);
if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
args.uniforms.light = 256;
args.uniforms.flags = 0;
args.uniforms.subsectorDepth = subsectorDepth;
TriVertex *vertices = PolyVertexBuffer::GetVertices(sub->numlines);
if (!vertices)
return;
if (ceiling)
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
vertices[sub->numlines - 1 - i] = PlaneVertex(line->v1, fakeFloor->bottom.plane->ZatPoint(line->v1), xform);
}
}
else
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
vertices[i] = PlaneVertex(line->v1, fakeFloor->top.plane->ZatPoint(line->v1), xform);
}
}
args.objectToClip = &worldToClip;
args.vinput = vertices;
args.vcount = sub->numlines;
args.mode = TriangleDrawMode::Fan;
args.ccw = true;
args.stenciltestvalue = stencilValue;
args.stencilwritevalue = stencilValue + 1;
args.SetTexture(tex);
args.SetColormap(sub->sector->ColorMap);
args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
args.blendmode = TriBlendMode::Copy;
PolyTriangleDrawer::draw(args);
}
void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals)
{
std::vector<PolyPortalSegment> portalSegments;
FSectorPortal *portal = nullptr;// sub->sector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor);
bool foggy = false;
PolyDrawSectorPortal *polyportal = nullptr;
if (portal && (portal->mFlags & PORTSF_INSKYBOX) == PORTSF_INSKYBOX) // Do not recurse into portals we already recursed into
portal = nullptr;
if (portal)
{
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::make_unique<PolyDrawSectorPortal>(portal, ceiling));
polyportal = sectorPortals.back().get();
}
// Calculate portal clipping
DVector2 v;
bool inside = true;
double vdist = 1.0e10;
portalSegments.reserve(sub->numlines);
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
DVector2 pt1 = line->v1->fPos() - ViewPos;
DVector2 pt2 = line->v2->fPos() - ViewPos;
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
inside = false;
double dist = pt1.LengthSquared();
if (dist < vdist)
{
v = line->v1->fPos();
vdist = dist;
}
dist = pt2.LengthSquared();
if (dist < vdist)
{
v = line->v2->fPos();
vdist = dist;
}
int sx1, sx2;
LineSegmentRange range = cull.GetSegmentRangeForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), sx1, sx2);
if (range == LineSegmentRange::HasSegment)
portalSegments.push_back({ sx1, sx2 });
}
if (inside)
{
polyportal->PortalPlane = Vec4f(0.0f, 0.0f, 0.0f, 1.0f);
}
else if(polyportal->PortalPlane == Vec4f(0.0f) || Vec4f::dot(polyportal->PortalPlane, Vec4f((float)v.X, (float)v.Y, 0.0f, 1.0f)) > 0.0f)
{
DVector2 planePos = v;
DVector2 planeNormal = v - ViewPos;
planeNormal.MakeUnit();
double planeD = -(planeNormal | (planePos + planeNormal * 0.001));
polyportal->PortalPlane = Vec4f((float)planeNormal.X, (float)planeNormal.Y, 0.0f, (float)planeD);
}
}
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)
{
// Floor and ceiling texture needs to be swapped sometimes? Why?? :(
if (ViewPos.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 (ViewPos.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;
}
}
else
{
picnum = sub->sector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor);
ccw = true;
frontsector = sub->sector;
}
FTexture *tex = TexMan(picnum);
if (tex->UseType == FTexture::TEX_Null)
return;
bool isSky = picnum == skyflatnum;
UVTransform transform(ceiling ? frontsector->planes[sector_t::ceiling].xform : frontsector->planes[sector_t::floor].xform, tex);
swrenderer::CameraLight *cameraLight = swrenderer::CameraLight::Instance();
PolyDrawArgs args;
args.uniforms.globvis = (float)swrenderer::LightVisibility::Instance()->SlopePlaneGlobVis(foggy) * 48.0f;
args.uniforms.light = (uint32_t)(frontsector->lightlevel / 255.0f * 256.0f);
if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
args.uniforms.light = 256;
args.uniforms.flags = 0;
args.uniforms.subsectorDepth = isSky ? RenderPolyScene::SkySubsectorDepth : subsectorDepth;
TriVertex *vertices = PolyVertexBuffer::GetVertices(sub->numlines);
if (!vertices)
return;
if (ceiling)
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
vertices[sub->numlines - 1 - i] = PlaneVertex(line->v1, isSky ? skyHeight : frontsector->ceilingplane.ZatPoint(line->v1), transform);
}
}
else
{
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
vertices[i] = PlaneVertex(line->v1, isSky ? skyHeight : frontsector->floorplane.ZatPoint(line->v1), transform);
}
}
args.objectToClip = &worldToClip;
args.vinput = vertices;
args.vcount = sub->numlines;
args.mode = TriangleDrawMode::Fan;
args.ccw = ccw;
args.stenciltestvalue = stencilValue;
args.stencilwritevalue = stencilValue + 1;
args.SetColormap(frontsector->ColorMap);
args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
if (!isSky)
{
if (!portal)
{
args.SetTexture(tex);
args.blendmode = TriBlendMode::Copy;
PolyTriangleDrawer::draw(args);
}
else
{
args.stencilwritevalue = polyportal->StencilValue;
args.writeColor = false;
args.writeSubsector = false;
PolyTriangleDrawer::draw(args);
polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, subsectorDepth });
polyportal->Segments.insert(polyportal->Segments.end(), portalSegments.begin(), portalSegments.end());
}
}
else
{
if (portal)
{
args.stencilwritevalue = polyportal->StencilValue;
polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, subsectorDepth });
polyportal->Segments.insert(polyportal->Segments.end(), portalSegments.begin(), portalSegments.end());
}
else
{
args.stencilwritevalue = 255;
}
args.writeColor = false;
args.writeSubsector = false;
PolyTriangleDrawer::draw(args);
for (uint32_t i = 0; i < sub->numlines; i++)
{
TriVertex *wallvert = PolyVertexBuffer::GetVertices(4);
if (!wallvert)
return;
seg_t *line = &sub->firstline[i];
double skyBottomz1 = frontsector->ceilingplane.ZatPoint(line->v1);
double skyBottomz2 = frontsector->ceilingplane.ZatPoint(line->v2);
if (line->backsector)
{
sector_t *backsector = (line->backsector != line->frontsector) ? line->backsector : line->frontsector;
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2);
double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2);
double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1);
double backfloorz1 = backsector->floorplane.ZatPoint(line->v1);
double backceilz2 = backsector->ceilingplane.ZatPoint(line->v2);
double backfloorz2 = backsector->floorplane.ZatPoint(line->v2);
double topceilz1 = frontceilz1;
double topceilz2 = frontceilz2;
double topfloorz1 = MIN(backceilz1, frontceilz1);
double topfloorz2 = MIN(backceilz2, frontceilz2);
double bottomceilz1 = MAX(frontfloorz1, backfloorz1);
double bottomceilz2 = MAX(frontfloorz2, backfloorz2);
double middleceilz1 = topfloorz1;
double middleceilz2 = topfloorz2;
double middlefloorz1 = MIN(bottomceilz1, middleceilz1);
double middlefloorz2 = MIN(bottomceilz2, middleceilz2);
bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum;
bool closedSector = backceilz1 == backfloorz1 && backceilz2 == backfloorz2;
if (ceiling && bothSkyCeiling && closedSector)
{
skyBottomz1 = middlefloorz1;
skyBottomz2 = middlefloorz2;
}
else if (bothSkyCeiling)
{
continue;
}
}
if (ceiling)
{
wallvert[0] = PlaneVertex(line->v1, skyHeight, transform);
wallvert[1] = PlaneVertex(line->v2, skyHeight, transform);
wallvert[2] = PlaneVertex(line->v2, skyBottomz2, transform);
wallvert[3] = PlaneVertex(line->v1, skyBottomz1, transform);
}
else
{
wallvert[0] = PlaneVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1), transform);
wallvert[1] = PlaneVertex(line->v2, frontsector->floorplane.ZatPoint(line->v2), transform);
wallvert[2] = PlaneVertex(line->v2, skyHeight, transform);
wallvert[3] = PlaneVertex(line->v1, skyHeight, transform);
}
args.vinput = wallvert;
args.vcount = 4;
PolyTriangleDrawer::draw(args);
if (portal)
{
polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, subsectorDepth });
polyportal->Segments.insert(polyportal->Segments.end(), portalSegments.begin(), portalSegments.end());
}
}
}
}
TriVertex RenderPolyPlane::PlaneVertex(vertex_t *v1, double height, const UVTransform &transform)
{
TriVertex v;
v.x = (float)v1->fPos().X;
v.y = (float)v1->fPos().Y;
v.z = (float)height;
v.w = 1.0f;
v.varying[0] = transform.GetU(v.x, v.y);
v.varying[1] = transform.GetV(v.x, v.y);
return v;
}
RenderPolyPlane::UVTransform::UVTransform(const FTransform &transform, FTexture *tex)
{
if (tex)
{
xscale = (float)(transform.xScale * tex->Scale.X / tex->GetWidth());
yscale = (float)(transform.yScale * tex->Scale.Y / tex->GetHeight());
double planeang = (transform.Angle + transform.baseAngle).Radians();
cosine = (float)cos(planeang);
sine = (float)sin(planeang);
xOffs = (float)transform.xOffs;
yOffs = (float)transform.yOffs;
}
else
{
xscale = 1.0f / 64.0f;
yscale = 1.0f / 64.0f;
cosine = 1.0f;
sine = 0.0f;
xOffs = 0.0f;
yOffs = 0.0f;
}
}
float RenderPolyPlane::UVTransform::GetU(float x, float y) const
{
return (xOffs + x * cosine - y * sine) * xscale;
}
float RenderPolyPlane::UVTransform::GetV(float x, float y) const
{
return (yOffs - x * sine - y * cosine) * yscale;
}

View file

@ -0,0 +1,54 @@
/*
** Handling drawing a plane (ceiling, floor)
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "polyrenderer/drawers/poly_triangle.h"
class PolyDrawSectorPortal;
class PolyCull;
class Vec4f;
class RenderPolyPlane
{
public:
static void RenderPlanes(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals);
private:
struct UVTransform
{
UVTransform(const FTransform &transform, FTexture *tex);
float GetU(float x, float y) const;
float GetV(float x, float y) const;
float xscale;
float yscale;
float cosine;
float sine;
float xOffs, yOffs;
};
void Render3DFloor(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakefloor);
void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> &sectorPortals);
TriVertex PlaneVertex(vertex_t *v1, double height, const UVTransform &transform);
};

View file

@ -0,0 +1,445 @@
/*
** Handling drawing a player sprite
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "sbar.h"
#include "r_data/r_translate.h"
#include "poly_playersprite.h"
#include "polyrenderer/poly_renderer.h"
#include "d_player.h"
#include "swrenderer/viewport/r_viewport.h"
#include "swrenderer/scene/r_light.h"
EXTERN_CVAR(Bool, r_drawplayersprites)
EXTERN_CVAR(Bool, r_deathcamera)
EXTERN_CVAR(Bool, st_scale)
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
EXTERN_CVAR(Bool, r_shadercolormaps)
void RenderPolyPlayerSprites::Render()
{
// This code cannot be moved directly to RenderRemainingSprites because the engine
// draws the canvas textures between this call and the final call to RenderRemainingSprites..
if (!r_drawplayersprites ||
!camera ||
!camera->player ||
(players[consoleplayer].cheats & CF_CHASECAM) ||
(r_deathcamera && camera->health <= 0))
return;
float bobx, boby;
P_BobWeapon(camera->player, &bobx, &boby, r_TicFracF);
// Interpolate the main weapon layer once so as to be able to add it to other layers.
double wx, wy;
DPSprite *weapon = camera->player->FindPSprite(PSP_WEAPON);
if (weapon)
{
if (weapon->firstTic)
{
wx = weapon->x;
wy = weapon->y;
}
else
{
wx = weapon->oldx + (weapon->x - weapon->oldx) * r_TicFracF;
wy = weapon->oldy + (weapon->y - weapon->oldy) * r_TicFracF;
}
}
else
{
wx = 0;
wy = 0;
}
for (DPSprite *sprite = camera->player->psprites; sprite != nullptr; sprite = sprite->GetNext())
{
// [RH] Don't draw the targeter's crosshair if the player already has a crosshair set.
// It's possible this psprite's caller is now null but the layer itself hasn't been destroyed
// because it didn't tick yet (if we typed 'take all' while in the console for example).
// In this case let's simply not draw it to avoid crashing.
if ((sprite->GetID() != PSP_TARGETCENTER || CrosshairImage == nullptr) && sprite->GetCaller() != nullptr)
{
RenderSprite(sprite, camera, bobx, boby, wx, wy, r_TicFracF);
}
}
}
void RenderPolyPlayerSprites::RenderRemainingSprites()
{
for (auto &sprite : ScreenSprites)
sprite.Render();
ScreenSprites.clear();
}
void RenderPolyPlayerSprites::RenderSprite(DPSprite *sprite, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac)
{
// decide which patch to use
if ((unsigned)sprite->GetSprite() >= (unsigned)sprites.Size())
{
DPrintf(DMSG_ERROR, "RenderPlayerSprite: invalid sprite number %i\n", sprite->GetSprite());
return;
}
spritedef_t *def = &sprites[sprite->GetSprite()];
if (sprite->GetFrame() >= def->numframes)
{
DPrintf(DMSG_ERROR, "RenderPlayerSprite: invalid sprite frame %i : %i\n", sprite->GetSprite(), sprite->GetFrame());
return;
}
spriteframe_t *frame = &SpriteFrames[def->spriteframes + sprite->GetFrame()];
FTextureID picnum = frame->Texture[0];
bool flip = (frame->Flip & 1) != 0;
FTexture *tex = TexMan(picnum);
if (tex->UseType == FTexture::TEX_Null)
return;
// Can't interpolate the first tic.
if (sprite->firstTic)
{
sprite->firstTic = false;
sprite->oldx = sprite->x;
sprite->oldy = sprite->y;
}
double sx = sprite->oldx + (sprite->x - sprite->oldx) * ticfrac;
double sy = sprite->oldy + (sprite->y - sprite->oldy) * ticfrac;
if (sprite->Flags & PSPF_ADDBOB)
{
sx += bobx;
sy += boby;
}
if (sprite->Flags & PSPF_ADDWEAPON && sprite->GetID() != PSP_WEAPON)
{
sx += wx;
sy += wy;
}
auto viewport = swrenderer::RenderViewport::Instance();
double pspritexscale = centerxwide / 160.0;
double pspriteyscale = pspritexscale * viewport->YaspectMul;
double pspritexiscale = 1 / pspritexscale;
// calculate edges of the shape
double tx = sx - BaseXCenter;
tx -= tex->GetScaledLeftOffset();
int x1 = xs_RoundToInt(viewport->CenterX + tx * pspritexscale);
// off the right side
if (x1 > viewwidth)
return;
tx += tex->GetScaledWidth();
int x2 = xs_RoundToInt(viewport->CenterX + tx * pspritexscale);
// off the left side
if (x2 <= 0)
return;
double texturemid = (BaseYCenter - sy) * tex->Scale.Y + tex->TopOffset;
// Adjust PSprite for fullscreen views
if (camera->player && (viewport->RenderTarget != screen || viewheight == viewport->RenderTarget->GetHeight() || (viewport->RenderTarget->GetWidth() > (BaseXCenter * 2) && !st_scale)))
{
AWeapon *weapon = dyn_cast<AWeapon>(sprite->GetCaller());
if (weapon != nullptr && weapon->YAdjust != 0)
{
if (viewport->RenderTarget != screen || viewheight == viewport->RenderTarget->GetHeight())
{
texturemid -= weapon->YAdjust;
}
else
{
texturemid -= StatusBar->GetDisplacement() * weapon->YAdjust;
}
}
}
// Move the weapon down for 1280x1024.
if (sprite->GetID() < PSP_TARGETCENTER)
{
texturemid -= AspectPspriteOffset(WidescreenRatio);
}
int clipped_x1 = MAX(x1, 0);
int clipped_x2 = MIN(x2, viewwidth);
double xscale = pspritexscale / tex->Scale.X;
double yscale = pspriteyscale / tex->Scale.Y;
uint32_t translation = 0; // [RH] Use default colors
double xiscale, startfrac;
if (flip)
{
xiscale = -pspritexiscale * tex->Scale.X;
startfrac = 1;
}
else
{
xiscale = pspritexiscale * tex->Scale.X;
startfrac = 0;
}
if (clipped_x1 > x1)
startfrac += xiscale * (clipped_x1 - x1);
bool noaccel = false;
FDynamicColormap *basecolormap = viewsector->ColorMap;
FDynamicColormap *colormap_to_use = basecolormap;
int ColormapNum = 0;
FSWColormap *BaseColormap = basecolormap;
float Alpha = 0;
FRenderStyle RenderStyle;
RenderStyle = STYLE_Normal;
bool foggy = false;
int actualextralight = foggy ? 0 : extralight << 4;
int spriteshade = swrenderer::LightVisibility::LightLevelToShade(owner->Sector->lightlevel + actualextralight, foggy);
double minz = double((2048 * 4) / double(1 << 20));
ColormapNum = GETPALOOKUP(swrenderer::LightVisibility::Instance()->SpriteGlobVis(foggy) / minz, spriteshade);
if (sprite->GetID() < PSP_TARGETCENTER)
{
Alpha = float(owner->Alpha);
RenderStyle = owner->RenderStyle;
// The software renderer cannot invert the source without inverting the overlay
// too. That means if the source is inverted, we need to do the reverse of what
// the invert overlay flag says to do.
INTBOOL invertcolormap = (RenderStyle.Flags & STYLEF_InvertOverlay);
if (RenderStyle.Flags & STYLEF_InvertSource)
{
invertcolormap = !invertcolormap;
}
FDynamicColormap *mybasecolormap = basecolormap;
if (RenderStyle.Flags & STYLEF_FadeToBlack)
{
if (invertcolormap)
{ // Fade to white
mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(255, 255, 255), mybasecolormap->Desaturate);
invertcolormap = false;
}
else
{ // Fade to black
mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(0, 0, 0), mybasecolormap->Desaturate);
}
}
/*
if (swrenderer::realfixedcolormap != nullptr && (!swrenderer::r_swtruecolor || (r_shadercolormaps && screen->Accel2D)))
{ // fixed color
BaseColormap = swrenderer::realfixedcolormap;
ColormapNum = 0;
}
else
{
if (invertcolormap)
{
mybasecolormap = GetSpecialLights(mybasecolormap->Color, mybasecolormap->Fade.InverseColor(), mybasecolormap->Desaturate);
}
if (swrenderer::fixedlightlev >= 0)
{
BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : mybasecolormap;
ColormapNum = swrenderer::fixedlightlev >> COLORMAPSHIFT;
}
else if (!foggy && sprite->GetState()->GetFullbright())
{ // full bright
BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : mybasecolormap; // [RH] use basecolormap
ColormapNum = 0;
}
else
{ // local light
BaseColormap = mybasecolormap;
ColormapNum = GETPALOOKUP(0, spriteshade);
}
}
*/
if (camera->Inventory != nullptr)
{
visstyle_t visstyle;
visstyle.Alpha = Alpha;
visstyle.RenderStyle = STYLE_Count;
visstyle.Invert = false;
camera->Inventory->AlterWeaponSprite(&visstyle);
Alpha = visstyle.Alpha;
if (visstyle.RenderStyle != STYLE_Count)
{
RenderStyle = visstyle.RenderStyle;
}
if (visstyle.Invert)
{
BaseColormap = &SpecialColormaps[INVERSECOLORMAP];
ColormapNum = 0;
if (BaseColormap->Maps < mybasecolormap->Maps || BaseColormap->Maps >= mybasecolormap->Maps + NUMCOLORMAPS * 256)
{
noaccel = true;
}
}
}
// If we're drawing with a special colormap, but shaders for them are disabled, do
// not accelerate.
if (!r_shadercolormaps && (BaseColormap >= &SpecialColormaps[0] &&
BaseColormap <= &SpecialColormaps.Last()))
{
noaccel = true;
}
// If drawing with a BOOM colormap, disable acceleration.
if (mybasecolormap == &NormalLight && NormalLight.Maps != realcolormaps.Maps)
{
noaccel = true;
}
// If the main colormap has fixed lights, and this sprite is being drawn with that
// colormap, disable acceleration so that the lights can remain fixed.
swrenderer::CameraLight *cameraLight = swrenderer::CameraLight::Instance();
if (!noaccel && cameraLight->ShaderColormap() == nullptr &&
NormalLightHasFixedLights && mybasecolormap == &NormalLight &&
tex->UseBasePalette())
{
noaccel = true;
}
// [SP] If emulating GZDoom fullbright, disable acceleration
if (r_fullbrightignoresectorcolor && cameraLight->FixedLightLevel() >= 0)
mybasecolormap = &FullNormalLight;
if (r_fullbrightignoresectorcolor && !foggy && sprite->GetState()->GetFullbright())
mybasecolormap = &FullNormalLight;
colormap_to_use = mybasecolormap;
}
// Check for hardware-assisted 2D. If it's available, and this sprite is not
// fuzzy, don't draw it until after the switch to 2D mode.
if (!noaccel && swrenderer::RenderViewport::Instance()->RenderTarget == screen && (DFrameBuffer *)screen->Accel2D)
{
FRenderStyle style = RenderStyle;
style.CheckFuzz();
if (style.BlendOp != STYLEOP_Fuzz)
{
PolyScreenSprite screenSprite;
screenSprite.Pic = tex;
screenSprite.X1 = viewwindowx + x1;
screenSprite.Y1 = viewwindowy + viewheight / 2 - texturemid * yscale - 0.5;
screenSprite.Width = tex->GetWidth() * xscale;
screenSprite.Height = tex->GetHeight() * yscale;
screenSprite.Translation = TranslationToTable(translation);
//screenSprite.Translation = translation;
screenSprite.Flip = xiscale < 0;
screenSprite.Alpha = Alpha;
screenSprite.RenderStyle = RenderStyle;
screenSprite.BaseColormap = BaseColormap;
screenSprite.ColormapNum = ColormapNum;
screenSprite.Colormap = colormap_to_use;
ScreenSprites.push_back(screenSprite);
return;
}
}
// To do: draw sprite same way as R_DrawVisSprite(vis) here
// Draw the fuzzy weapon:
FRenderStyle style = RenderStyle;
style.CheckFuzz();
if (style.BlendOp == STYLEOP_Fuzz)
{
RenderStyle = LegacyRenderStyles[STYLE_Shadow];
PolyScreenSprite screenSprite;
screenSprite.Pic = tex;
screenSprite.X1 = viewwindowx + x1;
screenSprite.Y1 = viewwindowy + viewheight / 2 - texturemid * yscale - 0.5;
screenSprite.Width = tex->GetWidth() * xscale;
screenSprite.Height = tex->GetHeight() * yscale;
screenSprite.Translation = TranslationToTable(translation);
screenSprite.Flip = xiscale < 0;
screenSprite.Alpha = Alpha;
screenSprite.RenderStyle = RenderStyle;
screenSprite.BaseColormap = BaseColormap;
screenSprite.ColormapNum = ColormapNum;
screenSprite.Colormap = colormap_to_use;
ScreenSprites.push_back(screenSprite);
}
}
void PolyScreenSprite::Render()
{
FSpecialColormap *special = nullptr;
FColormapStyle colormapstyle;
PalEntry overlay = 0;
bool usecolormapstyle = false;
if (BaseColormap >= &SpecialColormaps[0] &&
BaseColormap < &SpecialColormaps[SpecialColormaps.Size()])
{
special = static_cast<FSpecialColormap*>(BaseColormap);
}
else if (Colormap->Color == PalEntry(255, 255, 255) &&
Colormap->Desaturate == 0)
{
overlay = Colormap->Fade;
overlay.a = BYTE(ColormapNum * 255 / NUMCOLORMAPS);
}
else
{
usecolormapstyle = true;
colormapstyle.Color = Colormap->Color;
colormapstyle.Fade = Colormap->Fade;
colormapstyle.Desaturate = Colormap->Desaturate;
colormapstyle.FadeLevel = ColormapNum / float(NUMCOLORMAPS);
}
screen->DrawTexture(Pic,
X1,
Y1,
DTA_DestWidthF, Width,
DTA_DestHeightF, Height,
DTA_TranslationIndex, Translation,
DTA_FlipX, Flip,
DTA_TopOffset, 0,
DTA_LeftOffset, 0,
DTA_ClipLeft, viewwindowx,
DTA_ClipTop, viewwindowy,
DTA_ClipRight, viewwindowx + viewwidth,
DTA_ClipBottom, viewwindowy + viewheight,
DTA_Alpha, Alpha,
DTA_RenderStyle, RenderStyle,
DTA_FillColor, FillColor,
DTA_SpecialColormap, special,
DTA_ColorOverlay, overlay.d,
DTA_ColormapStyle, usecolormapstyle ? &colormapstyle : nullptr,
TAG_DONE);
}

View file

@ -0,0 +1,65 @@
/*
** Handling drawing a player sprite
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "r_defs.h"
class PolyScreenSprite;
class DPSprite;
struct FSWColormap;
class RenderPolyPlayerSprites
{
public:
void Render();
void RenderRemainingSprites();
private:
void RenderSprite(DPSprite *sprite, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac);
const int BaseXCenter = 160;
const int BaseYCenter = 100;
std::vector<PolyScreenSprite> ScreenSprites;
};
// DScreen accelerated sprite to be rendered
class PolyScreenSprite
{
public:
void Render();
FTexture *Pic = nullptr;
double X1 = 0.0;
double Y1 = 0.0;
double Width = 0.0;
double Height = 0.0;
FRemapTable *Translation = nullptr;
bool Flip = false;
float Alpha = 1;
FRenderStyle RenderStyle;
FSWColormap *BaseColormap = nullptr;
int ColormapNum = 0;
uint32_t FillColor = 0;
FDynamicColormap *Colormap = nullptr;
};

View file

@ -0,0 +1,298 @@
/*
** Polygon Doom software renderer
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "p_maputl.h"
#include "sbar.h"
#include "g_levellocals.h"
#include "r_data/r_translate.h"
#include "poly_portal.h"
#include "polyrenderer/poly_renderer.h"
#include "swrenderer/scene/r_light.h"
#include "gl/data/gl_data.h"
extern bool r_showviewer;
/////////////////////////////////////////////////////////////////////////////
PolyDrawSectorPortal::PolyDrawSectorPortal(FSectorPortal *portal, bool ceiling) : Portal(portal), Ceiling(ceiling)
{
StencilValue = PolyRenderer::Instance()->GetNextStencilValue();
}
void PolyDrawSectorPortal::Render(int portalDepth)
{
if (Portal->mType == PORTS_HORIZON || Portal->mType == PORTS_PLANE)
return;
SaveGlobals();
// To do: get this information from PolyRenderer instead of duplicating the code..
double radPitch = ViewPitch.Normalized180().Radians();
double angx = cos(radPitch);
double angy = sin(radPitch) * glset.pixelstretch;
double alen = sqrt(angx*angx + angy*angy);
float adjustedPitch = (float)asin(angy / alen);
float adjustedViewAngle = (float)(ViewAngle - 90).Radians();
float ratio = WidescreenRatio;
float fovratio = (WidescreenRatio >= 1.3f) ? 1.333333f : ratio;
float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(FieldOfView.Radians() / 2) / fovratio)).Degrees);
TriMatrix worldToView =
TriMatrix::rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) *
TriMatrix::rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) *
TriMatrix::scale(1.0f, glset.pixelstretch, 1.0f) *
TriMatrix::swapYZ() *
TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z);
TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
RenderPortal.SetViewpoint(worldToClip, PortalPlane, StencilValue);
RenderPortal.SetPortalSegments(Segments);
RenderPortal.Render(portalDepth);
RestoreGlobals();
}
void PolyDrawSectorPortal::RenderTranslucent(int portalDepth)
{
if (Portal->mType == PORTS_HORIZON || Portal->mType == PORTS_PLANE)
return;
SaveGlobals();
RenderPortal.RenderTranslucent(portalDepth);
RestoreGlobals();
}
void PolyDrawSectorPortal::SaveGlobals()
{
savedextralight = extralight;
savedpos = ViewPos;
savedangle = ViewAngle;
savedvisibility = swrenderer::LightVisibility::Instance()->GetVisibility();
savedcamera = camera;
savedsector = viewsector;
if (Portal->mType == PORTS_SKYVIEWPOINT)
{
// Don't let gun flashes brighten the sky box
AActor *sky = Portal->mSkybox;
extralight = 0;
swrenderer::LightVisibility::Instance()->SetVisibility(sky->args[0] * 0.25f);
ViewPos = sky->InterpolatedPosition(r_TicFracF);
ViewAngle = savedangle + (sky->PrevAngles.Yaw + deltaangle(sky->PrevAngles.Yaw, sky->Angles.Yaw) * r_TicFracF);
}
else //if (Portal->mType == PORTS_STACKEDSECTORTHING || Portal->mType == PORTS_PORTAL || Portal->mType == PORTS_LINKEDPORTAL)
{
//extralight = pl->extralight;
//swrenderer::R_SetVisibility(pl->visibility);
ViewPos.X += Portal->mDisplacement.X;
ViewPos.Y += Portal->mDisplacement.Y;
}
camera = nullptr;
viewsector = Portal->mDestination;
R_SetViewAngle();
Portal->mFlags |= PORTSF_INSKYBOX;
if (Portal->mPartner > 0) level.sectorPortals[Portal->mPartner].mFlags |= PORTSF_INSKYBOX;
}
void PolyDrawSectorPortal::RestoreGlobals()
{
Portal->mFlags &= ~PORTSF_INSKYBOX;
if (Portal->mPartner > 0) level.sectorPortals[Portal->mPartner].mFlags &= ~PORTSF_INSKYBOX;
camera = savedcamera;
viewsector = savedsector;
ViewPos = savedpos;
swrenderer::LightVisibility::Instance()->SetVisibility(savedvisibility);
extralight = savedextralight;
ViewAngle = savedangle;
R_SetViewAngle();
}
/////////////////////////////////////////////////////////////////////////////
PolyDrawLinePortal::PolyDrawLinePortal(FLinePortal *portal) : Portal(portal)
{
StencilValue = PolyRenderer::Instance()->GetNextStencilValue();
}
PolyDrawLinePortal::PolyDrawLinePortal(line_t *mirror) : Mirror(mirror)
{
StencilValue = PolyRenderer::Instance()->GetNextStencilValue();
}
void PolyDrawLinePortal::Render(int portalDepth)
{
SaveGlobals();
// To do: get this information from PolyRenderer instead of duplicating the code..
double radPitch = ViewPitch.Normalized180().Radians();
double angx = cos(radPitch);
double angy = sin(radPitch) * glset.pixelstretch;
double alen = sqrt(angx*angx + angy*angy);
float adjustedPitch = (float)asin(angy / alen);
float adjustedViewAngle = (float)(ViewAngle - 90).Radians();
float ratio = WidescreenRatio;
float fovratio = (WidescreenRatio >= 1.3f) ? 1.333333f : ratio;
float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(FieldOfView.Radians() / 2) / fovratio)).Degrees);
TriMatrix worldToView =
TriMatrix::rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) *
TriMatrix::rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) *
TriMatrix::scale(1.0f, glset.pixelstretch, 1.0f) *
TriMatrix::swapYZ() *
TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z);
if (Mirror)
worldToView = TriMatrix::scale(-1.0f, 1.0f, 1.0f) * worldToView;
TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
// Calculate plane clipping
line_t *clipLine = Portal ? Portal->mDestination : Mirror;
DVector2 planePos = clipLine->v1->fPos();
DVector2 planeNormal = (clipLine->v2->fPos() - clipLine->v1->fPos()).Rotated90CW();
planeNormal.MakeUnit();
double planeD = -(planeNormal | (planePos + planeNormal * 0.001));
Vec4f portalPlane((float)planeNormal.X, (float)planeNormal.Y, 0.0f, (float)planeD);
RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue);
RenderPortal.SetPortalSegments(Segments);
RenderPortal.Render(portalDepth);
RestoreGlobals();
}
void PolyDrawLinePortal::RenderTranslucent(int portalDepth)
{
SaveGlobals();
RenderPortal.RenderTranslucent(portalDepth);
RestoreGlobals();
}
void PolyDrawLinePortal::SaveGlobals()
{
savedextralight = extralight;
savedpos = ViewPos;
savedangle = ViewAngle;
savedcamera = camera;
savedsector = viewsector;
savedinvisibility = camera ? (camera->renderflags & RF_INVISIBLE) == RF_INVISIBLE : false;
savedViewPath[0] = ViewPath[0];
savedViewPath[1] = ViewPath[1];
if (Mirror)
{
DAngle startang = ViewAngle;
DVector3 startpos = ViewPos;
vertex_t *v1 = Mirror->v1;
// Reflect the current view behind the mirror.
if (Mirror->Delta().X == 0)
{ // vertical mirror
ViewPos.X = v1->fX() - startpos.X + v1->fX();
}
else if (Mirror->Delta().Y == 0)
{ // horizontal mirror
ViewPos.Y = v1->fY() - startpos.Y + v1->fY();
}
else
{ // any mirror
vertex_t *v2 = Mirror->v2;
double dx = v2->fX() - v1->fX();
double dy = v2->fY() - v1->fY();
double x1 = v1->fX();
double y1 = v1->fY();
double x = startpos.X;
double y = startpos.Y;
// the above two cases catch len == 0
double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy);
ViewPos.X = (x1 + r * dx) * 2 - x;
ViewPos.Y = (y1 + r * dy) * 2 - y;
}
ViewAngle = Mirror->Delta().Angle() * 2 - startang;
if (camera)
camera->renderflags &= ~RF_INVISIBLE;
}
else
{
auto src = Portal->mOrigin;
auto dst = Portal->mDestination;
P_TranslatePortalXY(src, ViewPos.X, ViewPos.Y);
P_TranslatePortalZ(src, ViewPos.Z);
P_TranslatePortalAngle(src, ViewAngle);
P_TranslatePortalXY(src, ViewPath[0].X, ViewPath[0].Y);
P_TranslatePortalXY(src, ViewPath[1].X, ViewPath[1].Y);
if (!r_showviewer && camera && P_PointOnLineSidePrecise(ViewPath[0], dst) != P_PointOnLineSidePrecise(ViewPath[1], dst))
{
double distp = (ViewPath[0] - ViewPath[1]).Length();
if (distp > EQUAL_EPSILON)
{
double dist1 = (ViewPos - ViewPath[0]).Length();
double dist2 = (ViewPos - ViewPath[1]).Length();
if (dist1 + dist2 < distp + 1)
{
camera->renderflags |= RF_INVISIBLE;
}
}
}
}
//camera = nullptr;
//viewsector = R_PointInSubsector(ViewPos)->sector;
R_SetViewAngle();
if (Mirror)
PolyTriangleDrawer::toggle_mirror();
}
void PolyDrawLinePortal::RestoreGlobals()
{
if (camera)
{
if (savedinvisibility)
camera->renderflags |= RF_INVISIBLE;
else
camera->renderflags &= ~RF_INVISIBLE;
}
camera = savedcamera;
viewsector = savedsector;
ViewPos = savedpos;
extralight = savedextralight;
ViewAngle = savedangle;
ViewPath[0] = savedViewPath[0];
ViewPath[1] = savedViewPath[1];
R_SetViewAngle();
if (Mirror)
PolyTriangleDrawer::toggle_mirror();
}

View file

@ -0,0 +1,100 @@
/*
** Polygon Doom software renderer
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "poly_scene.h"
struct PolyPortalVertexRange
{
PolyPortalVertexRange(const TriVertex *vertices, int count, bool ccw, uint32_t subsectorDepth) : Vertices(vertices), Count(count), Ccw(ccw), SubsectorDepth(subsectorDepth) { }
const TriVertex *Vertices;
int Count;
bool Ccw;
uint32_t SubsectorDepth;
};
class PolyPortalSegment
{
public:
PolyPortalSegment(int x1, int x2) : X1(x1), X2(x2) { }
int X1, X2;
};
class PolyDrawSectorPortal
{
public:
PolyDrawSectorPortal(FSectorPortal *portal, bool ceiling);
void Render(int portalDepth);
void RenderTranslucent(int portalDepth);
FSectorPortal *Portal = nullptr;
uint32_t StencilValue = 0;
std::vector<PolyPortalVertexRange> Shape;
std::vector<PolyPortalSegment> Segments;
Vec4f PortalPlane = Vec4f(0.0f);
private:
void SaveGlobals();
void RestoreGlobals();
bool Ceiling;
RenderPolyScene RenderPortal;
int savedextralight;
DVector3 savedpos;
DAngle savedangle;
double savedvisibility;
AActor *savedcamera;
sector_t *savedsector;
};
class PolyDrawLinePortal
{
public:
PolyDrawLinePortal(FLinePortal *portal);
PolyDrawLinePortal(line_t *mirror);
void Render(int portalDepth);
void RenderTranslucent(int portalDepth);
FLinePortal *Portal = nullptr;
line_t *Mirror = nullptr;
uint32_t StencilValue = 0;
std::vector<PolyPortalVertexRange> Shape;
std::vector<PolyPortalSegment> Segments;
private:
void SaveGlobals();
void RestoreGlobals();
RenderPolyScene RenderPortal;
int savedextralight;
DVector3 savedpos;
DAngle savedangle;
AActor *savedcamera;
sector_t *savedsector;
bool savedinvisibility;
DVector3 savedViewPath[2];
};

View file

@ -0,0 +1,368 @@
/*
** Polygon Doom software renderer
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "p_maputl.h"
#include "sbar.h"
#include "r_data/r_translate.h"
#include "polyrenderer/scene/poly_scene.h"
#include "polyrenderer/poly_renderer.h"
#include "gl/data/gl_data.h"
#include "swrenderer/scene/r_light.h"
CVAR(Bool, r_debug_cull, 0, 0)
EXTERN_CVAR(Int, r_portal_recursions)
/////////////////////////////////////////////////////////////////////////////
RenderPolyScene::RenderPolyScene()
{
}
RenderPolyScene::~RenderPolyScene()
{
}
void RenderPolyScene::SetViewpoint(const TriMatrix &worldToClip, const Vec4f &portalPlane, uint32_t stencilValue)
{
WorldToClip = worldToClip;
StencilValue = stencilValue;
PortalPlane = portalPlane;
}
void RenderPolyScene::SetPortalSegments(const std::vector<PolyPortalSegment> &segments)
{
Cull.ClearSolidSegments();
for (const auto &segment : segments)
{
Cull.MarkSegmentCulled(segment.X1, segment.X2);
}
Cull.InvertSegments();
PortalSegmentsAdded = true;
}
void RenderPolyScene::Render(int portalDepth)
{
ClearBuffers();
if (!PortalSegmentsAdded)
Cull.ClearSolidSegments();
Cull.CullScene(WorldToClip, PortalPlane);
Cull.ClearSolidSegments();
RenderSectors();
RenderPortals(portalDepth);
}
void RenderPolyScene::ClearBuffers()
{
SeenSectors.clear();
SubsectorDepths.clear();
TranslucentObjects.clear();
SectorPortals.clear();
LinePortals.clear();
NextSubsectorDepth = 0;
}
void RenderPolyScene::RenderSectors()
{
if (r_debug_cull)
{
for (auto it = Cull.PvsSectors.rbegin(); it != Cull.PvsSectors.rend(); ++it)
RenderSubsector(*it);
}
else
{
for (auto it = Cull.PvsSectors.begin(); it != Cull.PvsSectors.end(); ++it)
RenderSubsector(*it);
}
}
void RenderPolyScene::RenderSubsector(subsector_t *sub)
{
sector_t *frontsector = sub->sector;
frontsector->MoreFlags |= SECF_DRAWN;
uint32_t subsectorDepth = NextSubsectorDepth++;
if (sub->sector->CenterFloor() != sub->sector->CenterCeiling())
{
RenderPolyPlane::RenderPlanes(WorldToClip, PortalPlane, Cull, sub, subsectorDepth, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals);
}
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
if (line->sidedef == nullptr || !(line->sidedef->Flags & WALLF_POLYOBJ))
{
RenderLine(sub, line, frontsector, subsectorDepth);
}
}
bool mainBSP = ((unsigned int)(sub - subsectors) < (unsigned int)numsubsectors);
if (mainBSP)
{
int subsectorIndex = (int)(sub - subsectors);
for (int i = ParticlesInSubsec[subsectorIndex]; i != NO_PARTICLE; i = Particles[i].snext)
{
particle_t *particle = Particles + i;
TranslucentObjects.push_back({ particle, sub, subsectorDepth });
}
}
SeenSectors.insert(sub->sector);
SubsectorDepths[sub] = subsectorDepth;
}
void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right)
{
if (numnodes == 0)
{
subsector_t *sub = subsectors;
auto it = SubsectorDepths.find(sub);
if (it != SubsectorDepths.end())
TranslucentObjects.push_back({ thing, sub, it->second, sortDistance, 0.0f, 1.0f });
}
else
{
RenderSprite(thing, sortDistance, left, right, 0.0, 1.0, nodes + numnodes - 1); // The head node is the last node output.
}
}
void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node)
{
while (!((size_t)node & 1)) // Keep going until found a subsector
{
node_t *bsp = (node_t *)node;
DVector2 planePos(FIXED2DBL(bsp->x), FIXED2DBL(bsp->y));
DVector2 planeNormal = DVector2(FIXED2DBL(-bsp->dy), FIXED2DBL(bsp->dx));
double planeD = planeNormal | planePos;
int sideLeft = (left | planeNormal) > planeD;
int sideRight = (right | planeNormal) > planeD;
if (sideLeft != sideRight)
{
double dotLeft = planeNormal | left;
double dotRight = planeNormal | right;
double t = (planeD - dotLeft) / (dotRight - dotLeft);
DVector2 mid = left * (1.0 - t) + right * t;
double tmid = t1 * (1.0 - t) + t2 * t;
RenderSprite(thing, sortDistance, mid, right, tmid, t2, bsp->children[sideRight]);
right = mid;
t2 = tmid;
}
node = bsp->children[sideLeft];
}
subsector_t *sub = (subsector_t *)((BYTE *)node - 1);
auto it = SubsectorDepths.find(sub);
if (it != SubsectorDepths.end())
TranslucentObjects.push_back({ thing, sub, it->second, sortDistance, (float)t1, (float)t2 });
}
void RenderPolyScene::RenderLine(subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth)
{
// Reject lines not facing viewer
DVector2 pt1 = line->v1->fPos() - ViewPos;
DVector2 pt2 = line->v2->fPos() - ViewPos;
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
return;
// Cull wall if not visible
int sx1, sx2;
LineSegmentRange segmentRange = Cull.GetSegmentRangeForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), sx1, sx2);
if (segmentRange == LineSegmentRange::NotVisible || (segmentRange == LineSegmentRange::HasSegment && Cull.IsSegmentCulled(sx1, sx2)))
return;
// Tell automap we saw this
if (!PolyRenderer::Instance()->DontMapLines && line->linedef && segmentRange != LineSegmentRange::AlwaysVisible)
{
line->linedef->flags |= ML_MAPPED;
sub->flags |= SSECF_DRAWN;
}
// Render 3D floor sides
if (line->backsector && frontsector->e && line->backsector->e->XFloor.ffloors.Size())
{
for (unsigned int i = 0; i < line->backsector->e->XFloor.ffloors.Size(); i++)
{
F3DFloor *fakeFloor = line->backsector->e->XFloor.ffloors[i];
if (!(fakeFloor->flags & FF_EXISTS)) continue;
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
if (!fakeFloor->model) continue;
RenderPolyWall::Render3DFloorLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, fakeFloor, TranslucentObjects);
}
}
// Render wall, and update culling info if its an occlusion blocker
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals))
{
if (segmentRange == LineSegmentRange::HasSegment)
Cull.MarkSegmentCulled(sx1, sx2);
}
}
void RenderPolyScene::RenderPortals(int portalDepth)
{
bool foggy = false;
if (portalDepth < r_portal_recursions)
{
for (auto &portal : SectorPortals)
portal->Render(portalDepth + 1);
for (auto &portal : LinePortals)
portal->Render(portalDepth + 1);
}
else // Fill with black
{
PolyDrawArgs args;
args.objectToClip = &WorldToClip;
args.mode = TriangleDrawMode::Fan;
args.uniforms.globvis = (float)swrenderer::LightVisibility::Instance()->WallGlobVis(foggy);
args.uniforms.color = 0;
args.uniforms.light = 256;
args.uniforms.flags = TriUniforms::fixed_light;
args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w);
for (auto &portal : SectorPortals)
{
args.stenciltestvalue = portal->StencilValue;
args.stencilwritevalue = portal->StencilValue + 1;
for (const auto &verts : portal->Shape)
{
args.vinput = verts.Vertices;
args.vcount = verts.Count;
args.ccw = verts.Ccw;
args.uniforms.subsectorDepth = verts.SubsectorDepth;
args.blendmode = TriBlendMode::Copy;
PolyTriangleDrawer::draw(args);
}
}
for (auto &portal : LinePortals)
{
args.stenciltestvalue = portal->StencilValue;
args.stencilwritevalue = portal->StencilValue + 1;
for (const auto &verts : portal->Shape)
{
args.vinput = verts.Vertices;
args.vcount = verts.Count;
args.ccw = verts.Ccw;
args.uniforms.subsectorDepth = verts.SubsectorDepth;
PolyTriangleDrawer::draw(args);
}
}
}
}
void RenderPolyScene::RenderTranslucent(int portalDepth)
{
if (portalDepth < r_portal_recursions)
{
for (auto it = SectorPortals.rbegin(); it != SectorPortals.rend(); ++it)
{
auto &portal = *it;
portal->RenderTranslucent(portalDepth + 1);
PolyDrawArgs args;
args.objectToClip = &WorldToClip;
args.mode = TriangleDrawMode::Fan;
args.stenciltestvalue = portal->StencilValue + 1;
args.stencilwritevalue = StencilValue + 1;
args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w);
for (const auto &verts : portal->Shape)
{
args.vinput = verts.Vertices;
args.vcount = verts.Count;
args.ccw = verts.Ccw;
args.uniforms.subsectorDepth = verts.SubsectorDepth;
args.writeColor = false;
PolyTriangleDrawer::draw(args);
}
}
for (auto it = LinePortals.rbegin(); it != LinePortals.rend(); ++it)
{
auto &portal = *it;
portal->RenderTranslucent(portalDepth + 1);
PolyDrawArgs args;
args.objectToClip = &WorldToClip;
args.mode = TriangleDrawMode::Fan;
args.stenciltestvalue = portal->StencilValue + 1;
args.stencilwritevalue = StencilValue + 1;
args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w);
for (const auto &verts : portal->Shape)
{
args.vinput = verts.Vertices;
args.vcount = verts.Count;
args.ccw = verts.Ccw;
args.uniforms.subsectorDepth = verts.SubsectorDepth;
args.writeColor = false;
PolyTriangleDrawer::draw(args);
}
}
}
for (sector_t *sector : SeenSectors)
{
for (AActor *thing = sector->thinglist; thing != nullptr; thing = thing->snext)
{
DVector2 left, right;
if (!RenderPolySprite::GetLine(thing, left, right))
continue;
double distanceSquared = (thing->Pos() - ViewPos).LengthSquared();
RenderSprite(thing, distanceSquared, left, right);
}
}
std::stable_sort(TranslucentObjects.begin(), TranslucentObjects.end());
for (auto it = TranslucentObjects.rbegin(); it != TranslucentObjects.rend(); ++it)
{
auto &obj = *it;
if (obj.particle)
{
RenderPolyParticle spr;
spr.Render(WorldToClip, PortalPlane, obj.particle, obj.sub, obj.subsectorDepth, StencilValue + 1);
}
else if (!obj.thing)
{
obj.wall.Render(WorldToClip, PortalPlane, Cull);
}
else if ((obj.thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
{
RenderPolyWallSprite wallspr;
wallspr.Render(WorldToClip, PortalPlane, obj.thing, obj.sub, obj.subsectorDepth, StencilValue + 1);
}
else
{
RenderPolySprite spr;
spr.Render(WorldToClip, PortalPlane, obj.thing, obj.sub, obj.subsectorDepth, StencilValue + 1, obj.SpriteLeft, obj.SpriteRight);
}
}
}

View file

@ -0,0 +1,105 @@
/*
** Polygon Doom software renderer
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include <vector>
#include <memory>
#include <algorithm>
#include <functional>
#include "doomdata.h"
#include "r_utility.h"
#include "polyrenderer/drawers/poly_triangle.h"
#include "polyrenderer/math/poly_intersection.h"
#include "poly_wall.h"
#include "poly_sprite.h"
#include "poly_wallsprite.h"
#include "poly_playersprite.h"
#include "poly_particle.h"
#include "poly_plane.h"
#include "poly_cull.h"
#include <set>
#include <unordered_map>
class PolyTranslucentObject
{
public:
PolyTranslucentObject(particle_t *particle, subsector_t *sub, uint32_t subsectorDepth) : particle(particle), sub(sub), subsectorDepth(subsectorDepth) { }
PolyTranslucentObject(AActor *thing, subsector_t *sub, uint32_t subsectorDepth, double dist, float t1, float t2) : thing(thing), sub(sub), subsectorDepth(subsectorDepth), DistanceSquared(dist), SpriteLeft(t1), SpriteRight(t2) { }
PolyTranslucentObject(RenderPolyWall wall) : wall(wall), subsectorDepth(wall.SubsectorDepth), DistanceSquared(1.e6) { }
bool operator<(const PolyTranslucentObject &other) const
{
return subsectorDepth != other.subsectorDepth ? subsectorDepth < other.subsectorDepth : DistanceSquared < other.DistanceSquared;
}
particle_t *particle = nullptr;
AActor *thing = nullptr;
subsector_t *sub = nullptr;
RenderPolyWall wall;
uint32_t subsectorDepth = 0;
double DistanceSquared = 0.0;
float SpriteLeft = 0.0f, SpriteRight = 1.0f;
};
class PolyDrawSectorPortal;
class PolyDrawLinePortal;
class PolyPortalSegment;
// Renders everything from a specific viewpoint
class RenderPolyScene
{
public:
RenderPolyScene();
~RenderPolyScene();
void SetViewpoint(const TriMatrix &worldToClip, const Vec4f &portalPlane, uint32_t stencilValue);
void SetPortalSegments(const std::vector<PolyPortalSegment> &segments);
void Render(int portalDepth);
void RenderTranslucent(int portalDepth);
static const uint32_t SkySubsectorDepth = 0x7fffffff;
private:
void ClearBuffers();
void RenderPortals(int portalDepth);
void RenderSectors();
void RenderSubsector(subsector_t *sub);
void RenderLine(subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth);
void RenderSprite(AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right);
void RenderSprite(AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node);
TriMatrix WorldToClip;
Vec4f PortalPlane;
uint32_t StencilValue = 0;
PolyCull Cull;
uint32_t NextSubsectorDepth = 0;
std::set<sector_t *> SeenSectors;
std::unordered_map<subsector_t *, uint32_t> SubsectorDepths;
std::vector<PolyTranslucentObject> TranslucentObjects;
std::vector<std::unique_ptr<PolyDrawSectorPortal>> SectorPortals;
std::vector<std::unique_ptr<PolyDrawLinePortal>> LinePortals;
bool PortalSegmentsAdded = false;
};

View file

@ -0,0 +1,187 @@
/*
** Sky dome rendering
** Copyright(C) 2003-2016 Christoph Oelckers
** All rights reserved.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program. If not, see http:**www.gnu.org/licenses/
**
** Loosely based on the JDoom sky and the ZDoomGL 0.66.2 sky.
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "sbar.h"
#include "r_data/r_translate.h"
#include "poly_sky.h"
#include "poly_portal.h"
#include "r_sky.h" // for skyflatnum
#include "g_levellocals.h"
#include "swrenderer/scene/r_light.h"
PolySkyDome::PolySkyDome()
{
CreateDome();
}
void PolySkyDome::Render(const TriMatrix &worldToClip)
{
FTextureID sky1tex, sky2tex;
bool foggy = false;
if ((level.flags & LEVEL_SWAPSKIES) && !(level.flags & LEVEL_DOUBLESKY))
sky1tex = sky2texture;
else
sky1tex = sky1texture;
sky2tex = sky2texture;
FTexture *frontskytex = TexMan(sky1tex, true);
FTexture *backskytex = nullptr;
if (level.flags & LEVEL_DOUBLESKY)
backskytex = TexMan(sky2tex, true);
TriMatrix objectToWorld = TriMatrix::translate((float)ViewPos.X, (float)ViewPos.Y, (float)ViewPos.Z);
objectToClip = worldToClip * objectToWorld;
int rc = mRows + 1;
PolyDrawArgs args;
args.uniforms.globvis = (float)swrenderer::LightVisibility::Instance()->WallGlobVis(foggy);
args.uniforms.light = 256;
args.uniforms.flags = 0;
args.uniforms.subsectorDepth = RenderPolyScene::SkySubsectorDepth;
args.objectToClip = &objectToClip;
args.stenciltestvalue = 255;
args.stencilwritevalue = 1;
args.SetColormap(&NormalLight);
args.SetClipPlane(0.0f, 0.0f, 0.0f, 0.0f);
RenderCapColorRow(args, frontskytex, 0, false);
RenderCapColorRow(args, frontskytex, rc, true);
args.SetTexture(frontskytex);
uint32_t topcapcolor = frontskytex->GetSkyCapColor(false);
uint32_t bottomcapcolor = frontskytex->GetSkyCapColor(true);
for (int i = 1; i <= mRows; i++)
{
RenderRow(args, i, topcapcolor);
RenderRow(args, rc + i, bottomcapcolor);
}
}
void PolySkyDome::RenderRow(PolyDrawArgs &args, int row, uint32_t capcolor)
{
args.vinput = &mVertices[mPrimStart[row]];
args.vcount = mPrimStart[row + 1] - mPrimStart[row];
args.mode = TriangleDrawMode::Strip;
args.ccw = false;
args.uniforms.color = capcolor;
args.blendmode = TriBlendMode::Skycap;
PolyTriangleDrawer::draw(args);
}
void PolySkyDome::RenderCapColorRow(PolyDrawArgs &args, FTexture *skytex, int row, bool bottomCap)
{
uint32_t solid = skytex->GetSkyCapColor(bottomCap);
if (!swrenderer::RenderViewport::Instance()->RenderTarget->IsBgra())
solid = RGB32k.RGB[(RPART(solid) >> 3)][(GPART(solid) >> 3)][(BPART(solid) >> 3)];
args.vinput = &mVertices[mPrimStart[row]];
args.vcount = mPrimStart[row + 1] - mPrimStart[row];
args.mode = TriangleDrawMode::Fan;
args.ccw = bottomCap;
args.uniforms.color = solid;
args.blendmode = TriBlendMode::Copy;
PolyTriangleDrawer::draw(args);
}
void PolySkyDome::CreateDome()
{
mColumns = 16;// 128;
mRows = 4;
CreateSkyHemisphere(false);
CreateSkyHemisphere(true);
mPrimStart.Push(mVertices.Size());
}
void PolySkyDome::CreateSkyHemisphere(bool zflip)
{
int r, c;
mPrimStart.Push(mVertices.Size());
for (c = 0; c < mColumns; c++)
{
SkyVertex(1, c, zflip);
}
// The total number of triangles per hemisphere can be calculated
// as follows: rows * columns * 2 + 2 (for the top cap).
for (r = 0; r < mRows; r++)
{
mPrimStart.Push(mVertices.Size());
for (c = 0; c <= mColumns; c++)
{
SkyVertex(r + zflip, c, zflip);
SkyVertex(r + 1 - zflip, c, zflip);
}
}
}
TriVertex PolySkyDome::SetVertexXYZ(float xx, float yy, float zz, float uu, float vv)
{
TriVertex v;
v.x = xx;
v.y = zz;
v.z = yy;
v.w = 1.0f;
v.varying[0] = uu;
v.varying[1] = vv;
return v;
}
void PolySkyDome::SkyVertex(int r, int c, bool zflip)
{
static const FAngle maxSideAngle = 60.f;
static const float scale = 10000.;
FAngle topAngle = (c / (float)mColumns * 360.f);
FAngle sideAngle = maxSideAngle * (float)(mRows - r) / (float)mRows;
float height = sideAngle.Sin();
float realRadius = scale * sideAngle.Cos();
FVector2 pos = topAngle.ToVector(realRadius);
float z = (!zflip) ? scale * height : -scale * height;
float u, v;
// And the texture coordinates.
if (!zflip) // Flipped Y is for the lower hemisphere.
{
u = (-c / (float)mColumns);
v = (r / (float)mRows);
}
else
{
u = (-c / (float)mColumns);
v = 1.0f + ((mRows - r) / (float)mRows);
}
if (r != 4) z += 300;
// And finally the vertex.
TriVertex vert;
vert = SetVertexXYZ(-pos.X, z - 1.f, pos.Y, u * 4.0f, v * 1.2f - 0.5f);
mVertices.Push(vert);
}

View file

@ -0,0 +1,45 @@
/*
** Sky dome rendering
** Copyright(C) 2003-2016 Christoph Oelckers
** All rights reserved.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program. If not, see http:**www.gnu.org/licenses/
**
** Loosely based on the JDoom sky and the ZDoomGL 0.66.2 sky.
*/
#pragma once
#include "polyrenderer/drawers/poly_triangle.h"
class PolySkyDome
{
public:
PolySkyDome();
void Render(const TriMatrix &worldToClip);
private:
TArray<TriVertex> mVertices;
TArray<unsigned int> mPrimStart;
int mRows, mColumns;
TriMatrix objectToClip;
void SkyVertex(int r, int c, bool yflip);
void CreateSkyHemisphere(bool zflip);
void CreateDome();
void RenderRow(PolyDrawArgs &args, int row, uint32_t capcolor);
void RenderCapColorRow(PolyDrawArgs &args, FTexture *skytex, int row, bool bottomCap);
TriVertex SetVertexXYZ(float xx, float yy, float zz, float uu = 0, float vv = 0);
};

View file

@ -0,0 +1,439 @@
/*
** Handling drawing a sprite
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "sbar.h"
#include "r_data/r_translate.h"
#include "poly_sprite.h"
#include "polyrenderer/poly_renderer.h"
#include "polyrenderer/math/poly_intersection.h"
#include "swrenderer/scene/r_light.h"
EXTERN_CVAR(Float, transsouls)
EXTERN_CVAR(Int, r_drawfuzz)
bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right)
{
if (IsThingCulled(thing))
return false;
DVector3 pos = thing->InterpolatedPosition(r_TicFracF);
bool flipTextureX = false;
FTexture *tex = GetSpriteTexture(thing, flipTextureX);
if (tex == nullptr)
return false;
DVector2 spriteScale = thing->Scale;
double thingxscalemul = spriteScale.X / tex->Scale.X;
double thingyscalemul = spriteScale.Y / tex->Scale.Y;
if (flipTextureX)
pos.X -= (tex->GetWidth() - tex->LeftOffset) * thingxscalemul;
else
pos.X -= tex->LeftOffset * thingxscalemul;
double spriteHalfWidth = thingxscalemul * tex->GetWidth() * 0.5;
double spriteHeight = thingyscalemul * tex->GetHeight();
pos.X += spriteHalfWidth;
left = DVector2(pos.X - ViewSin * spriteHalfWidth, pos.Y + ViewCos * spriteHalfWidth);
right = DVector2(pos.X + ViewSin * spriteHalfWidth, pos.Y - ViewCos * spriteHalfWidth);
return true;
}
void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, float t1, float t2)
{
DVector2 line[2];
if (!GetLine(thing, line[0], line[1]))
return;
DVector3 pos = thing->InterpolatedPosition(r_TicFracF);
pos.Z += thing->GetBobOffset(r_TicFracF);
bool flipTextureX = false;
FTexture *tex = GetSpriteTexture(thing, flipTextureX);
if (tex == nullptr || tex->UseType == FTexture::TEX_Null)
return;
DVector2 spriteScale = thing->Scale;
double thingxscalemul = spriteScale.X / tex->Scale.X;
double thingyscalemul = spriteScale.Y / tex->Scale.Y;
if (flipTextureX)
pos.X -= (tex->GetWidth() - tex->LeftOffset) * thingxscalemul;
else
pos.X -= tex->LeftOffset * thingxscalemul;
//pos.Z -= tex->TopOffset * thingyscalemul;
pos.Z -= (tex->GetHeight() - tex->TopOffset) * thingyscalemul + thing->Floorclip;
double spriteHalfWidth = thingxscalemul * tex->GetWidth() * 0.5;
double spriteHeight = thingyscalemul * tex->GetHeight();
pos.X += spriteHalfWidth;
//double depth = 1.0;
//visstyle_t visstyle = GetSpriteVisStyle(thing, depth);
// Rumor has it that AlterWeaponSprite needs to be called with visstyle passed in somewhere around here..
//R_SetColorMapLight(visstyle.BaseColormap, 0, visstyle.ColormapNum << FRACBITS);
TriVertex *vertices = PolyVertexBuffer::GetVertices(4);
if (!vertices)
return;
bool foggy = false;
int actualextralight = foggy ? 0 : extralight << 4;
std::pair<float, float> offsets[4] =
{
{ t1, 1.0f },
{ t2, 1.0f },
{ t2, 0.0f },
{ t1, 0.0f },
};
DVector2 points[2] =
{
line[0] * (1.0 - t1) + line[1] * t1,
line[0] * (1.0 - t2) + line[1] * t2
};
for (int i = 0; i < 4; i++)
{
auto &p = (i == 0 || i == 3) ? points[0] : points[1];
vertices[i].x = (float)p.X;
vertices[i].y = (float)p.Y;
vertices[i].z = (float)(pos.Z + spriteHeight * offsets[i].second);
vertices[i].w = 1.0f;
vertices[i].varying[0] = (float)(offsets[i].first * tex->Scale.X);
vertices[i].varying[1] = (float)((1.0f - offsets[i].second) * tex->Scale.Y);
if (flipTextureX)
vertices[i].varying[0] = 1.0f - vertices[i].varying[0];
}
bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
swrenderer::CameraLight *cameraLight = swrenderer::CameraLight::Instance();
PolyDrawArgs args;
args.uniforms.globvis = (float)swrenderer::LightVisibility::Instance()->SpriteGlobVis(foggy);
args.uniforms.flags = 0;
if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
{
args.uniforms.light = 256;
args.uniforms.flags |= TriUniforms::fixed_light;
}
else
{
args.uniforms.light = (uint32_t)((thing->Sector->lightlevel + actualextralight) / 255.0f * 256.0f);
}
args.uniforms.subsectorDepth = subsectorDepth;
args.objectToClip = &worldToClip;
args.vinput = vertices;
args.vcount = 4;
args.mode = TriangleDrawMode::Fan;
args.ccw = true;
args.stenciltestvalue = stencilValue;
args.stencilwritevalue = stencilValue;
args.SetTexture(tex, thing->Translation);
args.SetColormap(sub->sector->ColorMap);
args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
TriBlendMode blendmode;
if (thing->RenderStyle == LegacyRenderStyles[STYLE_Normal] ||
(r_drawfuzz == 0 && thing->RenderStyle == LegacyRenderStyles[STYLE_OptFuzzy]))
{
args.uniforms.destalpha = 0;
args.uniforms.srcalpha = 256;
blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
}
else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Add] && fullbrightSprite && thing->Alpha == 1.0 && args.translation == nullptr)
{
args.uniforms.destalpha = 256;
args.uniforms.srcalpha = 256;
blendmode = TriBlendMode::AddSrcColorOneMinusSrcColor;
}
else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Add])
{
args.uniforms.destalpha = (uint32_t)(1.0 * 256);
args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
}
else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Subtract])
{
args.uniforms.destalpha = (uint32_t)(1.0 * 256);
args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
blendmode = args.translation ? TriBlendMode::TranslateRevSub : TriBlendMode::RevSub;
}
else if (thing->RenderStyle == LegacyRenderStyles[STYLE_SoulTrans])
{
args.uniforms.destalpha = (uint32_t)(256 - transsouls * 256);
args.uniforms.srcalpha = (uint32_t)(transsouls * 256);
blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
}
else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Fuzzy] ||
(r_drawfuzz == 2 && thing->RenderStyle == LegacyRenderStyles[STYLE_OptFuzzy]))
{ // NYI - Fuzzy - for now, just a copy of "Shadow"
args.uniforms.destalpha = 160;
args.uniforms.srcalpha = 0;
blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
}
else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Shadow] ||
(r_drawfuzz == 1 && thing->RenderStyle == LegacyRenderStyles[STYLE_OptFuzzy]))
{
args.uniforms.destalpha = 160;
args.uniforms.srcalpha = 0;
blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
}
else if (thing->RenderStyle == LegacyRenderStyles[STYLE_TranslucentStencil])
{
args.uniforms.destalpha = (uint32_t)(256 - thing->Alpha * 256);
args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
args.uniforms.color = 0xff000000 | thing->fillcolor;
blendmode = TriBlendMode::Stencil;
}
else if (thing->RenderStyle == LegacyRenderStyles[STYLE_AddStencil])
{
args.uniforms.destalpha = 256;
args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
args.uniforms.color = 0xff000000 | thing->fillcolor;
blendmode = TriBlendMode::Stencil;
}
else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Shaded])
{
args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
args.uniforms.destalpha = 256 - args.uniforms.srcalpha;
args.uniforms.color = 0;
blendmode = TriBlendMode::Shaded;
}
else if (thing->RenderStyle == LegacyRenderStyles[STYLE_AddShaded])
{
args.uniforms.destalpha = 256;
args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
args.uniforms.color = 0;
blendmode = TriBlendMode::Shaded;
}
else
{
args.uniforms.destalpha = (uint32_t)(256 - thing->Alpha * 256);
args.uniforms.srcalpha = (uint32_t)(thing->Alpha * 256);
blendmode = args.translation ? TriBlendMode::TranslateAdd : TriBlendMode::Add;
}
if (blendmode == TriBlendMode::Shaded)
{
args.SetTexture(tex, thing->Translation, true);
}
if (!swrenderer::RenderViewport::Instance()->RenderTarget->IsBgra())
{
uint32_t r = (args.uniforms.color >> 16) & 0xff;
uint32_t g = (args.uniforms.color >> 8) & 0xff;
uint32_t b = args.uniforms.color & 0xff;
args.uniforms.color = RGB32k.RGB[r >> 3][g >> 3][b >> 3];
if (blendmode == TriBlendMode::Sub) // Sub crashes in pal mode for some weird reason.
blendmode = TriBlendMode::Add;
}
args.subsectorTest = true;
args.writeSubsector = false;
args.writeStencil = false;
args.blendmode = blendmode;
PolyTriangleDrawer::draw(args);
}
bool RenderPolySprite::IsThingCulled(AActor *thing)
{
FIntCVar *cvar = thing->GetClass()->distancecheck;
if (cvar != nullptr && *cvar >= 0)
{
double dist = (thing->Pos() - ViewPos).LengthSquared();
double check = (double)**cvar;
if (dist >= check * check)
return true;
}
// Don't waste time projecting sprites that are definitely not visible.
if (thing == nullptr ||
(thing->renderflags & RF_INVISIBLE) ||
!thing->RenderStyle.IsVisible(thing->Alpha) ||
!thing->IsVisibleToPlayer())
{
return true;
}
return false;
}
#if 0
visstyle_t RenderPolySprite::GetSpriteVisStyle(AActor *thing, double z)
{
visstyle_t visstyle;
bool foggy = false;
int actualextralight = foggy ? 0 : extralight << 4;
int spriteshade = LIGHT2SHADE(thing->Sector->lightlevel + actualextralight);
FRenderStyle RenderStyle;
RenderStyle = thing->RenderStyle;
float Alpha = float(thing->Alpha);
int ColormapNum = 0;
// The software renderer cannot invert the source without inverting the overlay
// too. That means if the source is inverted, we need to do the reverse of what
// the invert overlay flag says to do.
bool invertcolormap = (RenderStyle.Flags & STYLEF_InvertOverlay) != 0;
if (RenderStyle.Flags & STYLEF_InvertSource)
{
invertcolormap = !invertcolormap;
}
FDynamicColormap *mybasecolormap = thing->Sector->ColorMap;
// Sprites that are added to the scene must fade to black.
if (RenderStyle == LegacyRenderStyles[STYLE_Add] && mybasecolormap->Fade != 0)
{
mybasecolormap = GetSpecialLights(mybasecolormap->Color, 0, mybasecolormap->Desaturate);
}
if (RenderStyle.Flags & STYLEF_FadeToBlack)
{
if (invertcolormap)
{ // Fade to white
mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(255, 255, 255), mybasecolormap->Desaturate);
invertcolormap = false;
}
else
{ // Fade to black
mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(0, 0, 0), mybasecolormap->Desaturate);
}
}
// get light level
if (swrenderer::fixedcolormap != nullptr)
{ // fixed map
BaseColormap = swrenderer::fixedcolormap;
ColormapNum = 0;
}
else
{
if (invertcolormap)
{
mybasecolormap = GetSpecialLights(mybasecolormap->Color, mybasecolormap->Fade.InverseColor(), mybasecolormap->Desaturate);
}
if (swrenderer::fixedlightlev >= 0)
{
BaseColormap = mybasecolormap;
ColormapNum = swrenderer::fixedlightlev >> COLORMAPSHIFT;
}
else if (!foggy && ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)))
{ // full bright
BaseColormap = mybasecolormap;
ColormapNum = 0;
}
else
{ // diminished light
double minz = double((2048 * 4) / double(1 << 20));
ColormapNum = GETPALOOKUP(swrenderer::r_SpriteVisibility / MAX(z, minz), spriteshade);
BaseColormap = mybasecolormap;
}
}
return visstyle;
}
#endif
FTexture *RenderPolySprite::GetSpriteTexture(AActor *thing, /*out*/ bool &flipX)
{
flipX = false;
if (thing->picnum.isValid())
{
FTexture *tex = TexMan(thing->picnum);
if (tex->UseType == FTexture::TEX_Null)
{
return nullptr;
}
if (tex->Rotations != 0xFFFF)
{
// choose a different rotation based on player view
spriteframe_t *sprframe = &SpriteFrames[tex->Rotations];
DVector3 pos = thing->InterpolatedPosition(r_TicFracF);
pos.Z += thing->GetBobOffset(r_TicFracF);
DAngle ang = (pos - ViewPos).Angle();
angle_t rot;
if (sprframe->Texture[0] == sprframe->Texture[1])
{
rot = (ang - thing->Angles.Yaw + 45.0 / 2 * 9).BAMs() >> 28;
}
else
{
rot = (ang - thing->Angles.Yaw + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
}
flipX = (sprframe->Flip & (1 << rot)) != 0;
tex = TexMan[sprframe->Texture[rot]]; // Do not animate the rotation
}
return tex;
}
else
{
// decide which texture to use for the sprite
int spritenum = thing->sprite;
if (spritenum >= (signed)sprites.Size() || spritenum < 0)
return nullptr;
spritedef_t *sprdef = &sprites[spritenum];
if (thing->frame >= sprdef->numframes)
{
// If there are no frames at all for this sprite, don't draw it.
return nullptr;
}
else
{
//picnum = SpriteFrames[sprdef->spriteframes + thing->frame].Texture[0];
// choose a different rotation based on player view
spriteframe_t *sprframe = &SpriteFrames[sprdef->spriteframes + thing->frame];
DVector3 pos = thing->InterpolatedPosition(r_TicFracF);
pos.Z += thing->GetBobOffset(r_TicFracF);
DAngle ang = (pos - ViewPos).Angle();
angle_t rot;
if (sprframe->Texture[0] == sprframe->Texture[1])
{
rot = (ang - thing->Angles.Yaw + 45.0 / 2 * 9).BAMs() >> 28;
}
else
{
rot = (ang - thing->Angles.Yaw + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
}
flipX = (sprframe->Flip & (1 << rot)) != 0;
return TexMan[sprframe->Texture[rot]]; // Do not animate the rotation
}
}
}

View file

@ -0,0 +1,40 @@
/*
** Handling drawing a sprite
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "polyrenderer/drawers/poly_triangle.h"
class Vec4f;
class RenderPolySprite
{
public:
void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, float t1, float t2);
static bool GetLine(AActor *thing, DVector2 &left, DVector2 &right);
static bool IsThingCulled(AActor *thing);
static FTexture *GetSpriteTexture(AActor *thing, /*out*/ bool &flipX);
private:
//visstyle_t GetSpriteVisStyle(AActor *thing, double z);
};

View file

@ -0,0 +1,482 @@
/*
** Handling drawing a wall
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "doomstat.h"
#include "doomdata.h"
#include "p_lnspec.h"
#include "sbar.h"
#include "r_data/r_translate.h"
#include "poly_wall.h"
#include "poly_decal.h"
#include "polyrenderer/poly_renderer.h"
#include "r_sky.h"
#include "swrenderer/scene/r_light.h"
EXTERN_CVAR(Bool, r_drawmirrors)
bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals)
{
PolyDrawLinePortal *polyportal = nullptr;
if (line->backsector == nullptr && line->linedef && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors))
{
if (PolyRenderer::Instance()->InsertSeenMirror(line->linedef))
{
linePortals.push_back(std::make_unique<PolyDrawLinePortal>(line->linedef));
polyportal = linePortals.back().get();
}
}
else if (line->linedef && line->linedef->isVisualPortal())
{
FLinePortal *portal = line->linedef->getPortal();
if (PolyRenderer::Instance()->InsertSeenLinePortal(portal))
{
for (auto &p : linePortals)
{
if (p->Portal == portal) // To do: what other criterias do we need to check for?
{
polyportal = p.get();
break;
}
}
if (!polyportal)
{
linePortals.push_back(std::make_unique<PolyDrawLinePortal>(portal));
polyportal = linePortals.back().get();
}
}
}
RenderPolyWall wall;
wall.LineSeg = line;
wall.Line = line->linedef;
wall.Side = line->sidedef;
wall.Colormap = frontsector->ColorMap;
wall.Masked = false;
wall.SubsectorDepth = subsectorDepth;
wall.StencilValue = stencilValue;
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2);
double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2);
if (line->backsector == nullptr)
{
if (line->sidedef)
{
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), frontceilz1, frontfloorz1, frontceilz2, frontfloorz2);
wall.TopZ = frontceilz1;
wall.BottomZ = frontfloorz1;
wall.UnpeggedCeil = frontceilz1;
wall.Texpart = side_t::mid;
wall.Polyportal = polyportal;
wall.Render(worldToClip, clipPlane, cull);
return true;
}
}
else
{
sector_t *backsector = (line->backsector != line->frontsector) ? line->backsector : line->frontsector;
double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1);
double backfloorz1 = backsector->floorplane.ZatPoint(line->v1);
double backceilz2 = backsector->ceilingplane.ZatPoint(line->v2);
double backfloorz2 = backsector->floorplane.ZatPoint(line->v2);
double topceilz1 = frontceilz1;
double topceilz2 = frontceilz2;
double topfloorz1 = MIN(backceilz1, frontceilz1);
double topfloorz2 = MIN(backceilz2, frontceilz2);
double bottomceilz1 = MAX(frontfloorz1, backfloorz1);
double bottomceilz2 = MAX(frontfloorz2, backfloorz2);
double bottomfloorz1 = frontfloorz1;
double bottomfloorz2 = frontfloorz2;
double middleceilz1 = topfloorz1;
double middleceilz2 = topfloorz2;
double middlefloorz1 = MIN(bottomceilz1, middleceilz1);
double middlefloorz2 = MIN(bottomceilz2, middleceilz2);
bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum;
if ((topceilz1 > topfloorz1 || topceilz2 > topfloorz2) && line->sidedef && !bothSkyCeiling)
{
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), topceilz1, topfloorz1, topceilz2, topfloorz2);
wall.TopZ = topceilz1;
wall.BottomZ = topfloorz1;
wall.UnpeggedCeil = topceilz1;
wall.Texpart = side_t::top;
wall.Render(worldToClip, clipPlane, cull);
}
if ((bottomfloorz1 < bottomceilz1 || bottomfloorz2 < bottomceilz2) && line->sidedef)
{
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), bottomceilz1, bottomfloorz1, bottomceilz2, bottomfloorz2);
wall.TopZ = bottomceilz1;
wall.BottomZ = bottomfloorz2;
wall.UnpeggedCeil = topceilz1;
wall.Texpart = side_t::bottom;
wall.Render(worldToClip, clipPlane, cull);
}
if (line->sidedef)
{
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), middleceilz1, middlefloorz1, middleceilz2, middlefloorz2);
wall.TopZ = middleceilz1;
wall.BottomZ = middlefloorz1;
wall.UnpeggedCeil = topceilz1;
wall.Texpart = side_t::mid;
wall.Masked = true;
FTexture *midtex = TexMan(line->sidedef->GetTexture(side_t::mid), true);
if (midtex && midtex->UseType != FTexture::TEX_Null)
translucentWallsOutput.push_back({ wall });
if (polyportal)
{
wall.Polyportal = polyportal;
wall.Render(worldToClip, clipPlane, cull);
}
}
}
return polyportal != nullptr;
}
void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject> &translucentWallsOutput)
{
double frontceilz1 = fakeFloor->top.plane->ZatPoint(line->v1);
double frontfloorz1 = fakeFloor->bottom.plane->ZatPoint(line->v1);
double frontceilz2 = fakeFloor->top.plane->ZatPoint(line->v2);
double frontfloorz2 = fakeFloor->bottom.plane->ZatPoint(line->v2);
RenderPolyWall wall;
wall.LineSeg = line;
wall.Line = fakeFloor->master;
wall.Side = fakeFloor->master->sidedef[0];
wall.Colormap = frontsector->ColorMap;
wall.Masked = false;
wall.SubsectorDepth = subsectorDepth;
wall.StencilValue = stencilValue;
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), frontceilz1, frontfloorz1, frontceilz2, frontfloorz2);
wall.TopZ = frontceilz1;
wall.BottomZ = frontfloorz1;
wall.UnpeggedCeil = frontceilz1;
wall.Texpart = side_t::mid;
wall.Render(worldToClip, clipPlane, cull);
}
void RenderPolyWall::SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2)
{
this->v1 = v1;
this->v2 = v2;
this->ceil1 = ceil1;
this->floor1 = floor1;
this->ceil2 = ceil2;
this->floor2 = floor2;
}
void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull)
{
bool foggy = false;
FTexture *tex = GetTexture();
if (!tex && !Polyportal)
return;
TriVertex *vertices = PolyVertexBuffer::GetVertices(4);
if (!vertices)
return;
vertices[0].x = (float)v1.X;
vertices[0].y = (float)v1.Y;
vertices[0].z = (float)ceil1;
vertices[0].w = 1.0f;
vertices[1].x = (float)v2.X;
vertices[1].y = (float)v2.Y;
vertices[1].z = (float)ceil2;
vertices[1].w = 1.0f;
vertices[2].x = (float)v2.X;
vertices[2].y = (float)v2.Y;
vertices[2].z = (float)floor2;
vertices[2].w = 1.0f;
vertices[3].x = (float)v1.X;
vertices[3].y = (float)v1.Y;
vertices[3].z = (float)floor1;
vertices[3].w = 1.0f;
if (tex)
{
PolyWallTextureCoords texcoords(tex, LineSeg, Line, Side, Texpart, TopZ, BottomZ, UnpeggedCeil);
vertices[0].varying[0] = (float)texcoords.u1;
vertices[0].varying[1] = (float)texcoords.v1;
vertices[1].varying[0] = (float)texcoords.u2;
vertices[1].varying[1] = (float)texcoords.v1;
vertices[2].varying[0] = (float)texcoords.u2;
vertices[2].varying[1] = (float)texcoords.v2;
vertices[3].varying[0] = (float)texcoords.u1;
vertices[3].varying[1] = (float)texcoords.v2;
}
// Masked walls clamp to the 0-1 range (no texture repeat)
if (Masked)
{
ClampHeight(vertices[0], vertices[3]);
ClampHeight(vertices[1], vertices[2]);
}
PolyDrawArgs args;
args.uniforms.globvis = (float)swrenderer::LightVisibility::Instance()->WallGlobVis(foggy);
args.uniforms.light = (uint32_t)(GetLightLevel() / 255.0f * 256.0f);
args.uniforms.flags = 0;
args.uniforms.subsectorDepth = SubsectorDepth;
args.objectToClip = &worldToClip;
args.vinput = vertices;
args.vcount = 4;
args.mode = TriangleDrawMode::Fan;
args.ccw = true;
args.stenciltestvalue = StencilValue;
args.stencilwritevalue = StencilValue + 1;
if (tex)
args.SetTexture(tex);
args.SetColormap(Line->frontsector->ColorMap);
args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
//if (Side && Side->lighthead)
// args.uniforms.light = 255; // Make walls touched by a light fullbright!
if (Polyportal)
{
args.stencilwritevalue = Polyportal->StencilValue;
args.writeColor = false;
args.writeSubsector = false;
PolyTriangleDrawer::draw(args);
Polyportal->Shape.push_back({ args.vinput, args.vcount, args.ccw, args.uniforms.subsectorDepth });
int sx1, sx2;
LineSegmentRange range = cull.GetSegmentRangeForLine(v1.X, v1.Y, v2.X, v2.Y, sx1, sx2);
if (range == LineSegmentRange::HasSegment)
Polyportal->Segments.push_back({ sx1, sx2 });
}
else if (!Masked)
{
args.blendmode = TriBlendMode::Copy;
PolyTriangleDrawer::draw(args);
}
else
{
args.uniforms.destalpha = (Line->flags & ML_ADDTRANS) ? 256 : (uint32_t)(256 - Line->alpha * 256);
args.uniforms.srcalpha = (uint32_t)(Line->alpha * 256);
args.subsectorTest = true;
args.writeSubsector = false;
args.writeStencil = false;
if (args.uniforms.destalpha == 0 && args.uniforms.srcalpha == 256)
args.blendmode = TriBlendMode::AlphaBlend;
else
args.blendmode = TriBlendMode::Add;
PolyTriangleDrawer::draw(args);
}
RenderPolyDecal::RenderWallDecals(worldToClip, clipPlane, LineSeg, SubsectorDepth, StencilValue);
}
void RenderPolyWall::ClampHeight(TriVertex &v1, TriVertex &v2)
{
float top = v1.z;
float bottom = v2.z;
float texv1 = v1.varying[1];
float texv2 = v2.varying[1];
float delta = (texv2 - texv1);
float t1 = texv1 < 0.0f ? -texv1 / delta : 0.0f;
float t2 = texv2 > 1.0f ? (1.0f - texv1) / delta : 1.0f;
float inv_t1 = 1.0f - t1;
float inv_t2 = 1.0f - t2;
v1.z = top * inv_t1 + bottom * t1;
v1.varying[1] = texv1 * inv_t1 + texv2 * t1;
v2.z = top * inv_t2 + bottom * t2;
v2.varying[1] = texv1 * inv_t2 + texv2 * t2;
}
FTexture *RenderPolyWall::GetTexture()
{
FTexture *tex = TexMan(Side->GetTexture(Texpart), true);
if (tex == nullptr || tex->UseType == FTexture::TEX_Null)
{
// Mapping error. Doom floodfills this with a plane.
// This code doesn't do that, but at least it uses the "right" texture..
if (Line && Line->backsector && Line->sidedef[0] == Side)
{
if (Texpart == side_t::top)
tex = TexMan(Line->backsector->GetTexture(sector_t::ceiling), true);
else if (Texpart == side_t::bottom)
tex = TexMan(Line->backsector->GetTexture(sector_t::floor), true);
}
if (Line && Line->backsector && Line->sidedef[1] == Side)
{
if (Texpart == side_t::top)
tex = TexMan(Line->frontsector->GetTexture(sector_t::ceiling), true);
else if (Texpart == side_t::bottom)
tex = TexMan(Line->frontsector->GetTexture(sector_t::floor), true);
}
if (tex == nullptr || tex->UseType == FTexture::TEX_Null)
return nullptr;
}
return tex;
}
int RenderPolyWall::GetLightLevel()
{
swrenderer::CameraLight *cameraLight = swrenderer::CameraLight::Instance();
if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
{
return 255;
}
else
{
bool foggy = false;
int actualextralight = foggy ? 0 : extralight << 4;
return clamp(Side->GetLightLevel(foggy, LineSeg->frontsector->lightlevel) + actualextralight, 0, 255);
}
}
/////////////////////////////////////////////////////////////////////////////
PolyWallTextureCoords::PolyWallTextureCoords(FTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart texpart, double topz, double bottomz, double unpeggedceil)
{
CalcU(tex, lineseg, line, side, texpart);
CalcV(tex, line, side, texpart, topz, bottomz, unpeggedceil);
}
void PolyWallTextureCoords::CalcU(FTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart texpart)
{
double lineLength = side->TexelLength;
double lineStart = 0.0;
bool entireSegment = ((lineseg->v1 == line->v1) && (lineseg->v2 == line->v2)) || ((lineseg->v2 == line->v1) && (lineseg->v1 == line->v2));
if (!entireSegment)
{
lineLength = (lineseg->v2->fPos() - lineseg->v1->fPos()).Length();
lineStart = (lineseg->v1->fPos() - line->v1->fPos()).Length();
}
int texWidth = tex->GetWidth();
double uscale = side->GetTextureXScale(texpart) * tex->Scale.X;
u1 = lineStart + side->GetTextureXOffset(texpart);
u2 = u1 + lineLength;
u1 *= uscale;
u2 *= uscale;
u1 /= texWidth;
u2 /= texWidth;
}
void PolyWallTextureCoords::CalcV(FTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart texpart, double topz, double bottomz, double unpeggedceil)
{
double vscale = side->GetTextureYScale(texpart) * tex->Scale.Y;
double yoffset = side->GetTextureYOffset(texpart);
if (tex->bWorldPanning)
yoffset *= vscale;
switch (texpart)
{
default:
case side_t::mid:
CalcVMidPart(tex, line, side, topz, bottomz, vscale, yoffset);
break;
case side_t::top:
CalcVTopPart(tex, line, side, topz, bottomz, vscale, yoffset);
break;
case side_t::bottom:
CalcVBottomPart(tex, line, side, topz, bottomz, unpeggedceil, vscale, yoffset);
break;
}
int texHeight = tex->GetHeight();
v1 /= texHeight;
v2 /= texHeight;
}
void PolyWallTextureCoords::CalcVTopPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double vscale, double yoffset)
{
bool pegged = (line->flags & ML_DONTPEGTOP) == 0;
if (pegged) // bottom to top
{
int texHeight = tex->GetHeight();
v1 = -yoffset;
v2 = v1 + (topz - bottomz);
v1 *= vscale;
v2 *= vscale;
v1 = texHeight - v1;
v2 = texHeight - v2;
std::swap(v1, v2);
}
else // top to bottom
{
v1 = yoffset;
v2 = v1 + (topz - bottomz);
v1 *= vscale;
v2 *= vscale;
}
}
void PolyWallTextureCoords::CalcVMidPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double vscale, double yoffset)
{
bool pegged = (line->flags & ML_DONTPEGBOTTOM) == 0;
if (pegged) // top to bottom
{
v1 = yoffset * vscale;
v2 = (yoffset + (topz - bottomz)) * vscale;
}
else // bottom to top
{
int texHeight = tex->GetHeight();
v1 = texHeight - (-yoffset + (topz - bottomz)) * vscale;
v2 = texHeight + yoffset * vscale;
}
}
void PolyWallTextureCoords::CalcVBottomPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double vscale, double yoffset)
{
bool pegged = (line->flags & ML_DONTPEGBOTTOM) == 0;
if (pegged) // top to bottom
{
v1 = yoffset;
v2 = v1 + (topz - bottomz);
v1 *= vscale;
v2 *= vscale;
}
else
{
v1 = yoffset + (unpeggedceil - topz);
v2 = v1 + (topz - bottomz);
v1 *= vscale;
v2 *= vscale;
}
}

View file

@ -0,0 +1,82 @@
/*
** Handling drawing a wall
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "polyrenderer/drawers/poly_triangle.h"
class PolyTranslucentObject;
class PolyDrawLinePortal;
class PolyCull;
class Vec4f;
class RenderPolyWall
{
public:
static bool RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals);
static void Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject> &translucentWallsOutput);
void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);
void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull);
DVector2 v1;
DVector2 v2;
double ceil1 = 0.0;
double floor1 = 0.0;
double ceil2 = 0.0;
double floor2 = 0.0;
const seg_t *LineSeg = nullptr;
const line_t *Line = nullptr;
const side_t *Side = nullptr;
side_t::ETexpart Texpart = side_t::mid;
double TopZ = 0.0;
double BottomZ = 0.0;
double UnpeggedCeil = 0.0;
FSWColormap *Colormap = nullptr;
bool Masked = false;
uint32_t SubsectorDepth = 0;
uint32_t StencilValue = 0;
PolyDrawLinePortal *Polyportal = nullptr;
private:
void ClampHeight(TriVertex &v1, TriVertex &v2);
FTexture *GetTexture();
int GetLightLevel();
};
// Texture coordinates for a wall
class PolyWallTextureCoords
{
public:
PolyWallTextureCoords(FTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart texpart, double topz, double bottomz, double unpeggedceil);
double u1, u2;
double v1, v2;
private:
void CalcU(FTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart texpart);
void CalcV(FTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart texpart, double topz, double bottomz, double unpeggedceil);
void CalcVTopPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double vscale, double yoffset);
void CalcVMidPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double vscale, double yoffset);
void CalcVBottomPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double vscale, double yoffset);
};

View file

@ -0,0 +1,132 @@
/*
** Handling drawing a sprite
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "sbar.h"
#include "r_data/r_translate.h"
#include "poly_wallsprite.h"
#include "polyrenderer/poly_renderer.h"
#include "swrenderer/scene/r_light.h"
void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue)
{
if (RenderPolySprite::IsThingCulled(thing))
return;
DVector3 pos = thing->InterpolatedPosition(r_TicFracF);
pos.Z += thing->GetBobOffset(r_TicFracF);
bool flipTextureX = false;
FTexture *tex = RenderPolySprite::GetSpriteTexture(thing, flipTextureX);
if (tex == nullptr || tex->UseType == FTexture::TEX_Null)
return;
DVector2 spriteScale = thing->Scale;
double thingxscalemul = spriteScale.X / tex->Scale.X;
double thingyscalemul = spriteScale.Y / tex->Scale.Y;
double spriteHeight = thingyscalemul * tex->GetHeight();
DAngle ang = thing->Angles.Yaw + 90;
double angcos = ang.Cos();
double angsin = ang.Sin();
// Determine left and right edges of sprite. The sprite's angle is its normal,
// so the edges are 90 degrees each side of it.
double x2 = tex->GetScaledWidth() * spriteScale.X;
double x1 = tex->GetScaledLeftOffset() * spriteScale.X;
DVector2 left, right;
left.X = pos.X - x1 * angcos;
left.Y = pos.Y - x1 * angsin;
right.X = left.X + x2 * angcos;
right.Y = right.Y + x2 * angsin;
//int scaled_to = tex->GetScaledTopOffset();
//int scaled_bo = scaled_to - tex->GetScaledHeight();
//gzt = pos.Z + scale.Y * scaled_to;
//gzb = pos.Z + scale.Y * scaled_bo;
DVector2 points[2] = { left, right };
TriVertex *vertices = PolyVertexBuffer::GetVertices(4);
if (!vertices)
return;
bool foggy = false;
int actualextralight = foggy ? 0 : extralight << 4;
std::pair<float, float> offsets[4] =
{
{ 0.0f, 1.0f },
{ 1.0f, 1.0f },
{ 1.0f, 0.0f },
{ 0.0f, 0.0f },
};
for (int i = 0; i < 4; i++)
{
auto &p = (i == 0 || i == 3) ? points[0] : points[1];
vertices[i].x = (float)p.X;
vertices[i].y = (float)p.Y;
vertices[i].z = (float)(pos.Z + spriteHeight * offsets[i].second);
vertices[i].w = 1.0f;
vertices[i].varying[0] = (float)(offsets[i].first * tex->Scale.X);
vertices[i].varying[1] = (float)((1.0f - offsets[i].second) * tex->Scale.Y);
if (flipTextureX)
vertices[i].varying[0] = 1.0f - vertices[i].varying[0];
}
bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
swrenderer::CameraLight *cameraLight = swrenderer::CameraLight::Instance();
PolyDrawArgs args;
args.uniforms.globvis = (float)swrenderer::LightVisibility::Instance()->WallGlobVis(foggy);
if (fullbrightSprite || cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
{
args.uniforms.light = 256;
args.uniforms.flags = TriUniforms::fixed_light;
}
else
{
args.uniforms.light = (uint32_t)((thing->Sector->lightlevel + actualextralight) / 255.0f * 256.0f);
args.uniforms.flags = 0;
}
args.uniforms.subsectorDepth = subsectorDepth;
args.objectToClip = &worldToClip;
args.vinput = vertices;
args.vcount = 4;
args.mode = TriangleDrawMode::Fan;
args.ccw = true;
args.stenciltestvalue = stencilValue;
args.stencilwritevalue = stencilValue;
args.SetTexture(tex);
args.SetColormap(sub->sector->ColorMap);
args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w);
args.subsectorTest = true;
args.writeSubsector = false;
args.writeStencil = false;
args.blendmode = TriBlendMode::AlphaBlend;
PolyTriangleDrawer::draw(args);
}

View file

@ -0,0 +1,33 @@
/*
** Handling drawing a wall sprite
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "polyrenderer/drawers/poly_triangle.h"
class Vec4f;
class RenderPolyWallSprite
{
public:
void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue);
};

View file

@ -48,7 +48,7 @@
#include "m_argv.h"
#include "m_png.h"
#include "r_renderer.h"
#include "r_swrenderer.h"
#include "swrenderer/r_swrenderer.h"
#include "st_console.h"
#include "stats.h"
#include "textures.h"
@ -114,11 +114,23 @@
@end
DFrameBuffer *CreateGLSWFrameBuffer(int width, int height, bool bgra, bool fullscreen);
EXTERN_CVAR(Bool, ticker )
EXTERN_CVAR(Bool, vid_vsync)
EXTERN_CVAR(Bool, vid_hidpi)
CUSTOM_CVAR(Bool, swtruecolor, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
// Strictly speaking this doesn't require a mode switch, but it is the easiest
// way to force a CreateFramebuffer call without a lot of refactoring.
extern int NewWidth, NewHeight, NewBits, DisplayBits;
NewWidth = screen->GetWidth();
NewHeight = screen->GetHeight();
NewBits = DisplayBits;
setmodeneeded = true;
}
CUSTOM_CVAR(Bool, fullscreen, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
extern int NewWidth, NewHeight, NewBits, DisplayBits;
@ -136,7 +148,7 @@ CUSTOM_CVAR(Bool, vid_autoswitch, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_
static int s_currentRenderer;
CUSTOM_CVAR(Int, vid_renderer, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
CUSTOM_CVAR(Int, vid_renderer, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
// 0: Software renderer
// 1: OpenGL renderer
@ -251,7 +263,7 @@ public:
virtual EDisplayType GetDisplayType() { return DISPLAY_Both; }
virtual void SetWindowedScale(float scale);
virtual DFrameBuffer* CreateFrameBuffer(int width, int height, bool fs, DFrameBuffer* old);
virtual DFrameBuffer* CreateFrameBuffer(int width, int height, bool bgra, bool fs, DFrameBuffer* old);
virtual void StartModeIterator(int bits, bool fullscreen);
virtual bool NextMode(int* width, int* height, bool* letterbox);
@ -293,7 +305,7 @@ private:
class CocoaFrameBuffer : public DFrameBuffer
{
public:
CocoaFrameBuffer(int width, int height, bool fullscreen);
CocoaFrameBuffer(int width, int height, bool bgra, bool fullscreen);
~CocoaFrameBuffer();
virtual bool Lock(bool buffer);
@ -496,7 +508,7 @@ NSOpenGLPixelFormat* CreatePixelFormat(const OpenGLProfile profile)
attributes[i++] = NSOpenGLPFAAllowOfflineRenderers;
}
if (NSAppKitVersionNumber >= AppKit10_7 && OpenGLProfile::Core == profile && 1 == vid_renderer)
if (NSAppKitVersionNumber >= AppKit10_7 && OpenGLProfile::Core == profile)
{
NSOpenGLPixelFormatAttribute profile = NSOpenGLProfileVersion3_2Core;
const char* const glversion = Args->CheckValue("-glversion");
@ -606,14 +618,14 @@ bool CocoaVideo::NextMode(int* const width, int* const height, bool* const lette
return false;
}
DFrameBuffer* CocoaVideo::CreateFrameBuffer(const int width, const int height, const bool fullscreen, DFrameBuffer* const old)
DFrameBuffer* CocoaVideo::CreateFrameBuffer(const int width, const int height, const bool bgra, const bool fullscreen, DFrameBuffer* const old)
{
PalEntry flashColor = 0;
int flashAmount = 0;
if (NULL != old)
{
if (width == m_width && height == m_height)
if (width == m_width && height == m_height && bgra == old->IsBgra())
{
SetMode(width, height, fullscreen, vid_hidpi);
return old;
@ -638,7 +650,8 @@ DFrameBuffer* CocoaVideo::CreateFrameBuffer(const int width, const int height, c
}
else
{
fb = new CocoaFrameBuffer(width, height, fullscreen);
//fb = new CocoaFrameBuffer(width, height, bgra, fullscreen);
fb = CreateGLSWFrameBuffer(width, height, bgra, fullscreen);
}
fb->SetFlash(flashColor, flashAmount);
@ -862,8 +875,8 @@ CocoaVideo* CocoaVideo::GetInstance()
// ---------------------------------------------------------------------------
CocoaFrameBuffer::CocoaFrameBuffer(int width, int height, bool fullscreen)
: DFrameBuffer(width, height)
CocoaFrameBuffer::CocoaFrameBuffer(int width, int height, bool bgra, bool fullscreen)
: DFrameBuffer(width, height, bgra)
, m_needPaletteUpdate(false)
, m_gamma(0.0f)
, m_needGammaUpdate(false)
@ -965,8 +978,15 @@ void CocoaFrameBuffer::Update()
FlipCycles.Reset();
BlitCycles.Clock();
GPfx.Convert(MemBuffer, Pitch, m_pixelBuffer, Width * BYTES_PER_PIXEL,
Width, Height, FRACUNIT, FRACUNIT, 0, 0);
if (IsBgra())
{
CopyWithGammaBgra(m_pixelBuffer, Width * BYTES_PER_PIXEL, m_gammaTable[0], m_gammaTable[1], m_gammaTable[2], m_flashColor, m_flashAmount);
}
else
{
GPfx.Convert(MemBuffer, Pitch, m_pixelBuffer, Width * BYTES_PER_PIXEL,
Width, Height, FRACUNIT, FRACUNIT, 0, 0);
}
FlipCycles.Clock();
Flip();
@ -1098,8 +1118,10 @@ void CocoaFrameBuffer::Flip()
static const GLenum format = GL_ABGR_EXT;
#endif // __LITTLE_ENDIAN__
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
Width, Height, 0, format, GL_UNSIGNED_BYTE, m_pixelBuffer);
if (IsBgra())
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, Width, Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, m_pixelBuffer);
else
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, Width, Height, 0, format, GL_UNSIGNED_BYTE, m_pixelBuffer);
glBegin(GL_QUADS);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
@ -1122,8 +1144,8 @@ void CocoaFrameBuffer::Flip()
// ---------------------------------------------------------------------------
SDLGLFB::SDLGLFB(void*, const int width, const int height, int, int, const bool fullscreen)
: DFrameBuffer(width, height)
SDLGLFB::SDLGLFB(void*, const int width, const int height, int, int, const bool fullscreen, bool bgra)
: DFrameBuffer(width, height, bgra)
, m_lock(-1)
, m_isUpdatePending(false)
{
@ -1329,7 +1351,7 @@ void I_CreateRenderer()
DFrameBuffer* I_SetMode(int &width, int &height, DFrameBuffer* old)
{
return Video->CreateFrameBuffer(width, height, fullscreen, old);
return Video->CreateFrameBuffer(width, height, swtruecolor, fullscreen, old);
}
bool I_CheckResolution(const int width, const int height, const int bits)

View file

@ -52,7 +52,7 @@ class SDLGLFB : public DFrameBuffer
{
public:
// This must have the same parameters as the Windows version, even if they are not used!
SDLGLFB(void *hMonitor, int width, int height, int, int, bool fullscreen);
SDLGLFB(void *hMonitor, int width, int height, int, int, bool fullscreen, bool bgra);
~SDLGLFB();
virtual bool Lock(bool buffered = true);

View file

@ -74,7 +74,7 @@ class IVideo
virtual EDisplayType GetDisplayType () = 0;
virtual void SetWindowedScale (float scale) = 0;
virtual DFrameBuffer *CreateFrameBuffer (int width, int height, bool fs, DFrameBuffer *old) = 0;
virtual DFrameBuffer *CreateFrameBuffer (int width, int height, bool bgra, bool fs, DFrameBuffer *old) = 0;
virtual void StartModeIterator (int bits, bool fs) = 0;
virtual bool NextMode (int *width, int *height, bool *letterbox) = 0;

View file

@ -49,10 +49,11 @@
#include "m_argv.h"
#include "sdlglvideo.h"
#include "r_renderer.h"
#include "r_swrenderer.h"
#include "swrenderer/r_swrenderer.h"
EXTERN_CVAR (Bool, ticker)
EXTERN_CVAR (Bool, fullscreen)
EXTERN_CVAR (Bool, swtruecolor)
EXTERN_CVAR (Float, vid_winscale)
IVideo *Video;
@ -64,7 +65,7 @@ void I_RestartRenderer();
int currentrenderer;
// [ZDoomGL]
CUSTOM_CVAR (Int, vid_renderer, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
CUSTOM_CVAR (Int, vid_renderer, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
// 0: Software renderer
// 1: OpenGL renderer
@ -119,8 +120,7 @@ void I_InitGraphics ()
ticker.SetGenericRepDefault (val, CVAR_Bool);
currentrenderer = vid_renderer;
if (currentrenderer==1) Video = new SDLGLVideo(0);
else Video = new SDLVideo (0);
Video = new SDLGLVideo(0);
if (Video == NULL)
I_FatalError ("Failed to initialize display");
@ -166,7 +166,7 @@ DFrameBuffer *I_SetMode (int &width, int &height, DFrameBuffer *old)
fs = fullscreen;
break;
}
DFrameBuffer *res = Video->CreateFrameBuffer (width, height, fs, old);
DFrameBuffer *res = Video->CreateFrameBuffer (width, height, swtruecolor, fs, old);
/* Right now, CreateFrameBuffer cannot return NULL
if (res == NULL)
@ -320,6 +320,16 @@ CUSTOM_CVAR (Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
extern int NewWidth, NewHeight, NewBits, DisplayBits;
CUSTOM_CVAR(Bool, swtruecolor, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
{
// Strictly speaking this doesn't require a mode switch, but it is the easiest
// way to force a CreateFramebuffer call without a lot of refactoring.
NewWidth = screen->GetWidth();
NewHeight = screen->GetHeight();
NewBits = DisplayBits;
setmodeneeded = true;
}
CUSTOM_CVAR (Bool, fullscreen, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
NewWidth = screen->GetWidth();

View file

@ -13,6 +13,7 @@
#include "c_console.h"
#include "sdlglvideo.h"
#include "sdlvideo.h"
#include "gl/system/gl_system.h"
#include "r_defs.h"
#include "gl/gl_functions.h"
@ -29,6 +30,7 @@
// TYPES -------------------------------------------------------------------
IMPLEMENT_CLASS(SDLBaseFB, true, false)
IMPLEMENT_CLASS(SDLGLFB, true, false)
struct MiniModeInfo
@ -52,12 +54,30 @@ EXTERN_CVAR (Int, vid_renderer)
EXTERN_CVAR (Int, vid_maxfps)
EXTERN_CVAR (Bool, cl_capfps)
DFrameBuffer *CreateGLSWFrameBuffer(int width, int height, bool bgra, bool fullscreen);
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CUSTOM_CVAR(Bool, gl_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
CUSTOM_CVAR(Bool, vid_glswfb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
#ifdef __arm__
CUSTOM_CVAR(Bool, gl_es, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
#else
CUSTOM_CVAR(Bool, gl_es, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
#endif
// PRIVATE DATA DEFINITIONS ------------------------------------------------
@ -159,7 +179,7 @@ bool SDLGLVideo::NextMode (int *width, int *height, bool *letterbox)
return false;
}
DFrameBuffer *SDLGLVideo::CreateFrameBuffer (int width, int height, bool fullscreen, DFrameBuffer *old)
DFrameBuffer *SDLGLVideo::CreateFrameBuffer (int width, int height, bool bgra, bool fullscreen, DFrameBuffer *old)
{
static int retry = 0;
static int owidth, oheight;
@ -169,15 +189,15 @@ DFrameBuffer *SDLGLVideo::CreateFrameBuffer (int width, int height, bool fullscr
if (old != NULL)
{ // Reuse the old framebuffer if its attributes are the same
SDLGLFB *fb = static_cast<SDLGLFB *> (old);
SDLBaseFB *fb = static_cast<SDLBaseFB *> (old);
if (fb->Width == width &&
fb->Height == height)
{
bool fsnow = (SDL_GetWindowFlags (fb->Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
bool fsnow = (SDL_GetWindowFlags (fb->GetSDLWindow()) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
if (fsnow != fullscreen)
{
SDL_SetWindowFullscreen (fb->Screen, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
SDL_SetWindowFullscreen (fb->GetSDLWindow(), fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
}
return old;
}
@ -190,7 +210,22 @@ DFrameBuffer *SDLGLVideo::CreateFrameBuffer (int width, int height, bool fullscr
// flashAmount = 0;
}
SDLGLFB *fb = new OpenGLFrameBuffer (0, width, height, 32, 60, fullscreen);
SDLBaseFB *fb;
if (vid_renderer == 1)
{
fb = new OpenGLFrameBuffer(0, width, height, 32, 60, fullscreen);
}
else if (vid_glswfb == 0)
{
fb = new SDLFB(width, height, bgra, fullscreen, nullptr);
}
else
{
fb = (SDLBaseFB*)CreateGLSWFrameBuffer(width, height, bgra, fullscreen);
if (!fb->IsValid())
fb = new SDLFB(width, height, bgra, fullscreen, nullptr);
}
retry = 0;
// If we could not create the framebuffer, try again with slightly
@ -233,7 +268,7 @@ DFrameBuffer *SDLGLVideo::CreateFrameBuffer (int width, int height, bool fullscr
}
++retry;
fb = static_cast<SDLGLFB *>(CreateFrameBuffer (width, height, fullscreen, NULL));
fb = static_cast<SDLBaseFB *>(CreateFrameBuffer (width, height, false, fullscreen, NULL));
}
// fb->SetFlash (flashColor, flashAmount);
@ -288,6 +323,14 @@ bool SDLGLVideo::SetupPixelFormat(bool allowsoftware, int multisample)
}
if (gl_debug)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
if (gl_es)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
return true;
}
@ -310,8 +353,8 @@ bool SDLGLVideo::InitHardware (bool allowsoftware, int multisample)
// FrameBuffer implementation -----------------------------------------------
SDLGLFB::SDLGLFB (void *, int width, int height, int, int, bool fullscreen)
: DFrameBuffer (width, height)
SDLGLFB::SDLGLFB (void *, int width, int height, int, int, bool fullscreen, bool bgra)
: SDLBaseFB (width, height, bgra)
{
int i;

View file

@ -21,7 +21,7 @@ class SDLGLVideo : public IVideo
EDisplayType GetDisplayType () { return DISPLAY_Both; }
void SetWindowedScale (float scale);
DFrameBuffer *CreateFrameBuffer (int width, int height, bool fs, DFrameBuffer *old);
DFrameBuffer *CreateFrameBuffer (int width, int height, bool bgra, bool fs, DFrameBuffer *old);
void StartModeIterator (int bits, bool fs);
bool NextMode (int *width, int *height, bool *letterbox);
@ -34,12 +34,23 @@ private:
int IteratorMode;
int IteratorBits;
};
class SDLGLFB : public DFrameBuffer
class SDLBaseFB : public DFrameBuffer
{
DECLARE_CLASS(SDLGLFB, DFrameBuffer)
DECLARE_CLASS(SDLBaseFB, DFrameBuffer)
public:
using DFrameBuffer::DFrameBuffer;
virtual SDL_Window *GetSDLWindow() = 0;
friend class SDLGLVideo;
};
class SDLGLFB : public SDLBaseFB
{
DECLARE_CLASS(SDLGLFB, SDLBaseFB)
public:
// this must have the same parameters as the Windows version, even if they are not used!
SDLGLFB (void *hMonitor, int width, int height, int, int, bool fullscreen);
SDLGLFB (void *hMonitor, int width, int height, int, int, bool fullscreen, bool bgra);
~SDLGLFB ();
void ForceBuffering (bool force);
@ -61,6 +72,8 @@ public:
int GetClientWidth();
int GetClientHeight();
SDL_Window *GetSDLWindow() override { return Screen; }
protected:
bool CanUpdate();
void SetGammaTable(WORD *tbl);

View file

@ -11,7 +11,7 @@
#include "stats.h"
#include "v_palette.h"
#include "sdlvideo.h"
#include "r_swrenderer.h"
#include "swrenderer/r_swrenderer.h"
#include "version.h"
#include <SDL.h>
@ -24,61 +24,6 @@
// TYPES -------------------------------------------------------------------
class SDLFB : public DFrameBuffer
{
DECLARE_CLASS(SDLFB, DFrameBuffer)
public:
SDLFB (int width, int height, bool fullscreen, SDL_Window *oldwin);
~SDLFB ();
bool Lock (bool buffer);
void Unlock ();
bool Relock ();
void ForceBuffering (bool force);
bool IsValid ();
void Update ();
PalEntry *GetPalette ();
void GetFlashedPalette (PalEntry pal[256]);
void UpdatePalette ();
bool SetGamma (float gamma);
bool SetFlash (PalEntry rgb, int amount);
void GetFlash (PalEntry &rgb, int &amount);
void SetFullscreen (bool fullscreen);
int GetPageCount ();
bool IsFullscreen ();
friend class SDLVideo;
virtual void SetVSync (bool vsync);
virtual void ScaleCoordsFromWindow(SWORD &x, SWORD &y);
private:
PalEntry SourcePalette[256];
BYTE GammaTable[3][256];
PalEntry Flash;
int FlashAmount;
float Gamma;
bool UpdatePending;
SDL_Window *Screen;
SDL_Renderer *Renderer;
union
{
SDL_Texture *Texture;
SDL_Surface *Surface;
};
bool UsingRenderer;
bool NeedPalUpdate;
bool NeedGammaUpdate;
bool NotPaletted;
void UpdateColors ();
void ResetSDLRenderer ();
SDLFB () {}
};
IMPLEMENT_CLASS(SDLFB, false, false)
struct MiniModeInfo
@ -132,72 +77,6 @@ CUSTOM_CVAR (Float, bgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
// PRIVATE DATA DEFINITIONS ------------------------------------------------
// Dummy screen sizes to pass when windowed
static MiniModeInfo WinModes[] =
{
{ 320, 200 },
{ 320, 240 },
{ 400, 225 }, // 16:9
{ 400, 300 },
{ 480, 270 }, // 16:9
{ 480, 360 },
{ 512, 288 }, // 16:9
{ 512, 384 },
{ 640, 360 }, // 16:9
{ 640, 400 },
{ 640, 480 },
{ 720, 480 }, // 16:10
{ 720, 540 },
{ 800, 450 }, // 16:9
{ 800, 480 },
{ 800, 500 }, // 16:10
{ 800, 600 },
{ 848, 480 }, // 16:9
{ 960, 600 }, // 16:10
{ 960, 720 },
{ 1024, 576 }, // 16:9
{ 1024, 600 }, // 17:10
{ 1024, 640 }, // 16:10
{ 1024, 768 },
{ 1088, 612 }, // 16:9
{ 1152, 648 }, // 16:9
{ 1152, 720 }, // 16:10
{ 1152, 864 },
{ 1280, 540 }, // 21:9
{ 1280, 720 }, // 16:9
{ 1280, 854 },
{ 1280, 800 }, // 16:10
{ 1280, 960 },
{ 1280, 1024 }, // 5:4
{ 1360, 768 }, // 16:9
{ 1366, 768 },
{ 1400, 787 }, // 16:9
{ 1400, 875 }, // 16:10
{ 1400, 1050 },
{ 1440, 900 },
{ 1440, 960 },
{ 1440, 1080 },
{ 1600, 900 }, // 16:9
{ 1600, 1000 }, // 16:10
{ 1600, 1200 },
{ 1680, 1050 }, // 16:10
{ 1920, 1080 },
{ 1920, 1200 },
{ 2048, 1536 },
{ 2560, 1080 }, // 21:9
{ 2560, 1440 },
{ 2560, 1600 },
{ 2560, 2048 },
{ 2880, 1800 },
{ 3200, 1800 },
{ 3440, 1440 }, // 21:9
{ 3840, 2160 },
{ 3840, 2400 },
{ 4096, 2160 },
{ 5120, 2160 }, // 21:9
{ 5120, 2880 }
};
static cycle_t BlitCycles;
static cycle_t SDLFlipCycles;
@ -228,131 +107,10 @@ void ScaleWithAspect (int &w, int &h, int Width, int Height)
h = y;
}
SDLVideo::SDLVideo (int parm)
{
IteratorBits = 0;
}
SDLVideo::~SDLVideo ()
{
}
void SDLVideo::StartModeIterator (int bits, bool fs)
{
IteratorMode = 0;
IteratorBits = bits;
}
bool SDLVideo::NextMode (int *width, int *height, bool *letterbox)
{
if (IteratorBits != 8)
return false;
if ((unsigned)IteratorMode < sizeof(WinModes)/sizeof(WinModes[0]))
{
*width = WinModes[IteratorMode].Width;
*height = WinModes[IteratorMode].Height;
++IteratorMode;
return true;
}
return false;
}
DFrameBuffer *SDLVideo::CreateFrameBuffer (int width, int height, bool fullscreen, DFrameBuffer *old)
{
static int retry = 0;
static int owidth, oheight;
PalEntry flashColor;
int flashAmount;
SDL_Window *oldwin = NULL;
if (old != NULL)
{ // Reuse the old framebuffer if its attributes are the same
SDLFB *fb = static_cast<SDLFB *> (old);
if (fb->Width == width &&
fb->Height == height)
{
bool fsnow = (SDL_GetWindowFlags (fb->Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
if (fsnow != fullscreen)
{
fb->SetFullscreen (fullscreen);
}
return old;
}
oldwin = fb->Screen;
fb->Screen = NULL;
old->GetFlash (flashColor, flashAmount);
old->ObjectFlags |= OF_YesReallyDelete;
if (screen == old) screen = NULL;
delete old;
}
else
{
flashColor = 0;
flashAmount = 0;
}
SDLFB *fb = new SDLFB (width, height, fullscreen, oldwin);
// If we could not create the framebuffer, try again with slightly
// different parameters in this order:
// 1. Try with the closest size
// 2. Try in the opposite screen mode with the original size
// 3. Try in the opposite screen mode with the closest size
// This is a somewhat confusing mass of recursion here.
while (fb == NULL || !fb->IsValid ())
{
if (fb != NULL)
{
delete fb;
}
switch (retry)
{
case 0:
owidth = width;
oheight = height;
case 2:
// Try a different resolution. Hopefully that will work.
I_ClosestResolution (&width, &height, 8);
break;
case 1:
// Try changing fullscreen mode. Maybe that will work.
width = owidth;
height = oheight;
fullscreen = !fullscreen;
break;
default:
// I give up!
I_FatalError ("Could not create new screen (%d x %d)", owidth, oheight);
}
++retry;
fb = static_cast<SDLFB *>(CreateFrameBuffer (width, height, fullscreen, NULL));
}
retry = 0;
fb->SetFlash (flashColor, flashAmount);
return fb;
}
void SDLVideo::SetWindowedScale (float scale)
{
}
// FrameBuffer implementation -----------------------------------------------
SDLFB::SDLFB (int width, int height, bool fullscreen, SDL_Window *oldwin)
: DFrameBuffer (width, height)
SDLFB::SDLFB (int width, int height, bool bgra, bool fullscreen, SDL_Window *oldwin)
: SDLBaseFB (width, height, bgra)
{
int i;
@ -495,7 +253,11 @@ void SDLFB::Update ()
pitch = Surface->pitch;
}
if (NotPaletted)
if (Bgra)
{
CopyWithGammaBgra(pixels, pitch, GammaTable[0], GammaTable[1], GammaTable[2], Flash, FlashAmount);
}
else if (NotPaletted)
{
GPfx.Convert (MemBuffer, Pitch,
pixels, pitch, Width, Height,
@ -675,13 +437,20 @@ void SDLFB::ResetSDLRenderer ()
SDL_SetRenderDrawColor(Renderer, 0, 0, 0, 255);
Uint32 fmt;
switch(vid_displaybits)
if (Bgra)
{
default: fmt = SDL_PIXELFORMAT_ARGB8888; break;
case 30: fmt = SDL_PIXELFORMAT_ARGB2101010; break;
case 24: fmt = SDL_PIXELFORMAT_RGB888; break;
case 16: fmt = SDL_PIXELFORMAT_RGB565; break;
case 15: fmt = SDL_PIXELFORMAT_ARGB1555; break;
fmt = SDL_PIXELFORMAT_ARGB8888;
}
else
{
switch (vid_displaybits)
{
default: fmt = SDL_PIXELFORMAT_ARGB8888; break;
case 30: fmt = SDL_PIXELFORMAT_ARGB2101010; break;
case 24: fmt = SDL_PIXELFORMAT_RGB888; break;
case 16: fmt = SDL_PIXELFORMAT_RGB565; break;
case 15: fmt = SDL_PIXELFORMAT_ARGB1555; break;
}
}
Texture = SDL_CreateTexture (Renderer, fmt, SDL_TEXTUREACCESS_STREAMING, Width, Height);

View file

@ -1,21 +1,60 @@
#include "hardware.h"
#include "v_video.h"
#include "sdlglvideo.h"
class SDLVideo : public IVideo
class SDLFB : public SDLBaseFB
{
public:
SDLVideo (int parm);
~SDLVideo ();
DECLARE_CLASS(SDLFB, SDLBaseFB)
public:
SDLFB(int width, int height, bool bgra, bool fullscreen, SDL_Window *oldwin);
~SDLFB();
EDisplayType GetDisplayType () { return DISPLAY_Both; }
void SetWindowedScale (float scale);
bool Lock(bool buffer);
void Unlock();
bool Relock();
void ForceBuffering(bool force);
bool IsValid();
void Update();
PalEntry *GetPalette();
void GetFlashedPalette(PalEntry pal[256]);
void UpdatePalette();
bool SetGamma(float gamma);
bool SetFlash(PalEntry rgb, int amount);
void GetFlash(PalEntry &rgb, int &amount);
void SetFullscreen(bool fullscreen);
int GetPageCount();
bool IsFullscreen();
DFrameBuffer *CreateFrameBuffer (int width, int height, bool fs, DFrameBuffer *old);
friend class SDLGLVideo;
void StartModeIterator (int bits, bool fs);
bool NextMode (int *width, int *height, bool *letterbox);
virtual void SetVSync(bool vsync);
virtual void ScaleCoordsFromWindow(SWORD &x, SWORD &y);
SDL_Window *GetSDLWindow() override { return Screen; }
private:
int IteratorMode;
int IteratorBits;
PalEntry SourcePalette[256];
BYTE GammaTable[3][256];
PalEntry Flash;
int FlashAmount;
float Gamma;
bool UpdatePending;
SDL_Window *Screen;
SDL_Renderer *Renderer;
union
{
SDL_Texture *Texture;
SDL_Surface *Surface;
};
bool UsingRenderer;
bool NeedPalUpdate;
bool NeedGammaUpdate;
bool NotPaletted;
void UpdateColors();
void ResetSDLRenderer();
SDLFB() {}
};

View file

@ -1,163 +0,0 @@
/*
** r_3dfloors.cpp
** software 3D floors addon
**
** by kgsws
*/
#include "templates.h"
#include "doomdef.h"
#include "p_local.h"
#include "c_dispatch.h"
#include "r_local.h"
#include "r_bsp.h"
#include "r_plane.h"
#include "c_cvars.h"
#include "r_3dfloors.h"
// external variables
int fake3D;
F3DFloor *fakeFloor;
fixed_t fakeHeight;
fixed_t fakeAlpha;
int fakeActive = 0;
double sclipBottom;
double sclipTop;
HeightLevel *height_top = NULL;
HeightLevel *height_cur = NULL;
int CurrentMirror = 0;
int CurrentSkybox = 0;
CVAR(Int, r_3dfloors, true, 0);
// private variables
int height_max = -1;
TArray<HeightStack> toplist;
ClipStack *clip_top = NULL;
ClipStack *clip_cur = NULL;
void R_3D_DeleteHeights()
{
height_cur = height_top;
while(height_cur) {
height_top = height_cur;
height_cur = height_cur->next;
M_Free(height_top);
}
height_max = -1;
height_top = height_cur = NULL;
}
void R_3D_AddHeight(secplane_t *add, sector_t *sec)
{
HeightLevel *near;
HeightLevel *curr;
double fheight = add->ZatPoint(ViewPos);
if(fheight >= sec->CenterCeiling()) return;
if(fheight <= sec->CenterFloor()) return;
fixed_t height = FLOAT2FIXED(fheight);
fakeActive = 1;
if(height_max >= 0) {
near = height_top;
while(near && near->height < height) near = near->next;
if(near) {
if(near->height == height) return;
curr = (HeightLevel*)M_Malloc(sizeof(HeightLevel));
curr->height = height;
curr->prev = near->prev;
curr->next = near;
if(near->prev) near->prev->next = curr;
else height_top = curr;
near->prev = curr;
} else {
curr = (HeightLevel*)M_Malloc(sizeof(HeightLevel));
curr->height = height;
curr->prev = height_cur;
curr->next = NULL;
height_cur->next = curr;
height_cur = curr;
}
} else {
height_top = height_cur = (HeightLevel*)M_Malloc(sizeof(HeightLevel));
height_top->height = height;
height_top->prev = NULL;
height_top->next = NULL;
}
height_max++;
}
void R_3D_NewClip()
{
ClipStack *curr;
// extern short floorclip[MAXWIDTH];
// extern short ceilingclip[MAXWIDTH];
curr = (ClipStack*)M_Malloc(sizeof(ClipStack));
curr->next = 0;
memcpy(curr->floorclip, floorclip, sizeof(short) * MAXWIDTH);
memcpy(curr->ceilingclip, ceilingclip, sizeof(short) * MAXWIDTH);
curr->ffloor = fakeFloor;
assert(fakeFloor->floorclip == NULL);
assert(fakeFloor->ceilingclip == NULL);
fakeFloor->floorclip = curr->floorclip;
fakeFloor->ceilingclip = curr->ceilingclip;
if(clip_top) {
clip_cur->next = curr;
clip_cur = curr;
} else {
clip_top = clip_cur = curr;
}
}
void R_3D_ResetClip()
{
clip_cur = clip_top;
while(clip_cur)
{
assert(clip_cur->ffloor->floorclip != NULL);
assert(clip_cur->ffloor->ceilingclip != NULL);
clip_cur->ffloor->ceilingclip = clip_cur->ffloor->floorclip = NULL;
clip_top = clip_cur;
clip_cur = clip_cur->next;
M_Free(clip_top);
}
clip_cur = clip_top = NULL;
}
void R_3D_EnterSkybox()
{
HeightStack current;
current.height_top = height_top;
current.height_cur = height_cur;
current.height_max = height_max;
toplist.Push(current);
height_top = NULL;
height_cur = NULL;
height_max = -1;
CurrentSkybox++;
}
void R_3D_LeaveSkybox()
{
HeightStack current;
current.height_top = NULL;
current.height_cur = NULL;
current.height_max = -1;
toplist.Pop(current);
height_top = current.height_top;
height_cur = current.height_cur;
height_max = current.height_max;
CurrentSkybox--;
}

View file

@ -1,70 +0,0 @@
#ifndef SOFT_FAKE3D_H
#define SOFT_FAKE3D_H
#include "p_3dfloors.h"
// special types
struct HeightLevel
{
double height;
struct HeightLevel *prev;
struct HeightLevel *next;
};
struct HeightStack
{
HeightLevel *height_top;
HeightLevel *height_cur;
int height_max;
};
struct ClipStack
{
short floorclip[MAXWIDTH];
short ceilingclip[MAXWIDTH];
F3DFloor *ffloor;
ClipStack *next;
};
// external varialbes
// fake3D flags:
enum
{
// BSP stage:
FAKE3D_FAKEFLOOR = 1, // fake floor, mark seg as FAKE
FAKE3D_FAKECEILING = 2, // fake ceiling, mark seg as FAKE
FAKE3D_FAKEBACK = 4, // R_AddLine with fake backsector, mark seg as FAKE
FAKE3D_FAKEMASK = 7,
FAKE3D_CLIPBOTFRONT = 8, // use front sector clipping info (bottom)
FAKE3D_CLIPTOPFRONT = 16, // use front sector clipping info (top)
// sorting stage:
FAKE3D_CLIPBOTTOM = 1, // clip bottom
FAKE3D_CLIPTOP = 2, // clip top
FAKE3D_REFRESHCLIP = 4, // refresh clip info
FAKE3D_DOWN2UP = 8, // rendering from down to up (floors)
};
extern int fake3D;
extern F3DFloor *fakeFloor;
extern fixed_t fakeAlpha;
extern int fakeActive;
extern double sclipBottom;
extern double sclipTop;
extern HeightLevel *height_top;
extern HeightLevel *height_cur;
extern int CurrentMirror;
extern int CurrentSkybox;
EXTERN_CVAR(Int, r_3dfloors);
// functions
void R_3D_DeleteHeights();
void R_3D_AddHeight(secplane_t *add, sector_t *sec);
void R_3D_NewClip();
void R_3D_ResetClip();
void R_3D_EnterSkybox();
void R_3D_LeaveSkybox();
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,123 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Refresh module, BSP traversal and handling.
//
//-----------------------------------------------------------------------------
#ifndef __R_BSP__
#define __R_BSP__
#include "tarray.h"
#include <stddef.h>
#include "r_defs.h"
// The 3072 below is just an arbitrary value picked to avoid
// drawing lines the player is too close to that would overflow
// the texture calculations.
#define TOO_CLOSE_Z (3072.0 / (1<<12))
struct FWallCoords
{
FVector2 tleft; // coords at left of wall in view space rx1,ry1
FVector2 tright; // coords at right of wall in view space rx2,ry2
float sz1, sz2; // depth at left, right of wall in screen space yb1,yb2
short sx1, sx2; // x coords at left, right of wall in screen space xb1,xb2
bool Init(const DVector2 &pt1, const DVector2 &pt2, double too_close);
};
struct FWallTmapVals
{
float UoverZorg, UoverZstep;
float InvZorg, InvZstep;
void InitFromWallCoords(const FWallCoords *wallc);
void InitFromLine(const DVector2 &left, const DVector2 &right);
};
extern FWallCoords WallC;
extern FWallTmapVals WallT;
enum
{
FAKED_Center,
FAKED_BelowFloor,
FAKED_AboveCeiling
};
struct drawseg_t
{
seg_t* curline;
float light, lightstep;
float iscale, iscalestep;
short x1, x2; // Same as sx1 and sx2, but clipped to the drawseg
short sx1, sx2; // left, right of parent seg on screen
float sz1, sz2; // z for left, right of parent seg on screen
float siz1, siz2; // 1/z for left, right of parent seg on screen
float cx, cy, cdx, cdy;
float yscale;
BYTE silhouette; // 0=none, 1=bottom, 2=top, 3=both
BYTE bFogBoundary;
BYTE bFakeBoundary; // for fake walls
int shade;
// Pointers to lists for sprite clipping,
// all three adjusted so [x1] is first value.
ptrdiff_t sprtopclip; // type short
ptrdiff_t sprbottomclip; // type short
ptrdiff_t maskedtexturecol; // type short
ptrdiff_t swall; // type float
int fake; // ident fake drawseg, don't draw and clip sprites
// backups
ptrdiff_t bkup; // sprtopclip backup, for mid and fake textures
FWallTmapVals tmapvals;
int CurrentPortalUniq; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping.
};
extern seg_t* curline;
extern side_t* sidedef;
extern line_t* linedef;
extern sector_t* frontsector;
extern sector_t* backsector;
extern drawseg_t *drawsegs;
extern drawseg_t *firstdrawseg;
extern drawseg_t* ds_p;
extern TArray<size_t> InterestingDrawsegs; // drawsegs that have something drawn on them
extern size_t FirstInterestingDrawseg;
extern int WindowLeft, WindowRight;
extern WORD MirrorFlags;
typedef void (*drawfunc_t) (int start, int stop);
EXTERN_CVAR (Bool, r_drawflat) // [RH] Don't texture segs?
// BSP?
void R_ClearClipSegs (short left, short right);
void R_ClearDrawSegs ();
void R_RenderBSPNode (void *node);
// killough 4/13/98: fake floors/ceilings for deep water / fake ceilings:
sector_t *R_FakeFlat(sector_t *, sector_t *, int *, int *, bool);
#endif

View file

@ -72,8 +72,8 @@ struct FakeCmap
};
TArray<FakeCmap> fakecmaps;
BYTE *realcolormaps;
BYTE *realfbcolormaps; //[SP] For fullbright use
FSWColormap realcolormaps;
FSWColormap realfbcolormaps; //[SP] For fullbright use
size_t numfakecmaps;
@ -410,7 +410,7 @@ void R_SetDefaultColormap (const char *name)
foo.Color = 0xFFFFFF;
foo.Fade = 0;
foo.Maps = realcolormaps;
foo.Maps = realcolormaps.Maps;
foo.Desaturate = 0;
foo.Next = NULL;
foo.BuildLights ();
@ -432,7 +432,7 @@ void R_SetDefaultColormap (const char *name)
remap[0] = 0;
for (i = 0; i < NUMCOLORMAPS; ++i)
{
BYTE *map2 = &realcolormaps[i*256];
BYTE *map2 = &realcolormaps.Maps[i*256];
lumpr.Read (map, 256);
for (j = 0; j < 256; ++j)
{
@ -456,15 +456,11 @@ void R_DeinitColormaps ()
{
SpecialColormaps.Clear();
fakecmaps.Clear();
if (realcolormaps != NULL)
delete[] realcolormaps.Maps;
if (realfbcolormaps.Maps)
{
delete[] realcolormaps;
realcolormaps = NULL;
}
if (realfbcolormaps != NULL)
{
delete[] realfbcolormaps;
realfbcolormaps = NULL;
delete[] realfbcolormaps.Maps;
realfbcolormaps.Maps = nullptr;
}
FreeSpecialLights();
}
@ -508,7 +504,7 @@ void R_InitColormaps ()
}
}
}
realcolormaps = new BYTE[256*NUMCOLORMAPS*fakecmaps.Size()];
realcolormaps.Maps = new BYTE[256*NUMCOLORMAPS*fakecmaps.Size()];
R_SetDefaultColormap ("COLORMAP");
if (fakecmaps.Size() > 1)
@ -530,7 +526,7 @@ void R_InitColormaps ()
{
int k, r, g, b;
FWadLump lump = Wads.OpenLumpNum (fakecmaps[j].lump);
BYTE *const map = realcolormaps + NUMCOLORMAPS*256*j;
BYTE *const map = realcolormaps.Maps + NUMCOLORMAPS*256*j;
for (k = 0; k < NUMCOLORMAPS; ++k)
{
@ -557,19 +553,19 @@ void R_InitColormaps ()
}
// [SP] Create a copy of the colormap
if (!realfbcolormaps)
if (!realfbcolormaps.Maps)
{
realfbcolormaps = new BYTE[256*NUMCOLORMAPS*fakecmaps.Size()];
memcpy(realfbcolormaps, realcolormaps, 256*NUMCOLORMAPS*fakecmaps.Size());
realfbcolormaps.Maps = new BYTE[256*NUMCOLORMAPS*fakecmaps.Size()];
memcpy(realfbcolormaps.Maps, realcolormaps.Maps, 256*NUMCOLORMAPS*fakecmaps.Size());
}
NormalLight.Color = PalEntry (255, 255, 255);
NormalLight.Fade = 0;
NormalLight.Maps = realcolormaps;
NormalLight.Maps = realcolormaps.Maps;
FullNormalLight.Color = PalEntry (255, 255, 255);
FullNormalLight.Fade = 0;
FullNormalLight.Maps = realfbcolormaps;
NormalLightHasFixedLights = R_CheckForFixedLights(realcolormaps);
FullNormalLight.Maps = realfbcolormaps.Maps;
NormalLightHasFixedLights = R_CheckForFixedLights(realcolormaps.Maps);
numfakecmaps = fakecmaps.Size();
// build default special maps (e.g. invulnerability)

View file

@ -1,18 +1,26 @@
#ifndef __RES_CMAP_H
#define __RES_CMAP_H
struct FSWColormap;
void R_InitColormaps ();
void R_DeinitColormaps ();
DWORD R_ColormapNumForName(const char *name); // killough 4/4/98
void R_SetDefaultColormap (const char *name); // [RH] change normal fadetable
DWORD R_BlendForColormap (DWORD map); // [RH] return calculated blend for a colormap
extern BYTE *realcolormaps; // [RH] make the colormaps externally visible
extern FSWColormap realcolormaps; // [RH] make the colormaps externally visible
extern size_t numfakecmaps;
struct FSWColormap
{
BYTE *Maps = nullptr;
PalEntry Color = 0xffffffff;
PalEntry Fade = 0xff000000;
int Desaturate = 0;
};
struct FDynamicColormap
struct FDynamicColormap : FSWColormap
{
void ChangeFade (PalEntry fadecolor);
void ChangeColor (PalEntry lightcolor, int desaturate);
@ -21,10 +29,6 @@ struct FDynamicColormap
void BuildLights ();
static void RebuildAllLights();
BYTE *Maps;
PalEntry Color;
PalEntry Fade;
int Desaturate;
FDynamicColormap *Next;
};
@ -44,8 +48,13 @@ enum
};
struct FSpecialColormap
struct FSpecialColormap : FSWColormap
{
FSpecialColormap()
{
Maps = Colormap;
}
float ColorizeStart[3];
float ColorizeEnd[3];
BYTE Colormap[256];

View file

@ -121,6 +121,9 @@ enum ERenderFlags
// Actors only: Ignore sector fade and fade to black. To fade to white,
// combine this with STYLEF_InvertOverlay.
STYLEF_FadeToBlack = 64,
// Force alpha.
STYLEF_ForceAlpha = 128,
};
union FRenderStyle

View file

@ -392,6 +392,52 @@ FVoxel::~FVoxel()
if (Palette != NULL) delete [] Palette;
}
//==========================================================================
//
// Create true color version of the slab data
//
//==========================================================================
void FVoxel::CreateBgraSlabData()
{
assert(Palette != NULL);
for (int i = 0; i < NumMips; ++i)
{
int size = Mips[i].OffsetX[Mips[i].SizeX];
if (size <= 0) continue;
Mips[i].SlabDataBgra.Resize(size);
kvxslab_t *src = (kvxslab_t*)Mips[i].SlabData;
kvxslab_bgra_t *dest = (kvxslab_bgra_t*)&Mips[i].SlabDataBgra[0];
while (size >= 3)
{
dest->backfacecull = src->backfacecull;
dest->ztop = src->ztop;
dest->zleng = src->zleng;
int slabzleng = src->zleng;
for (int j = 0; j < slabzleng; ++j)
{
int colorIndex = src->col[j];
uint32_t red = (Palette[colorIndex * 3 + 0] << 2) | (Palette[colorIndex * 3 + 0] >> 4);
uint32_t green = (Palette[colorIndex * 3 + 1] << 2) | (Palette[colorIndex * 3 + 1] >> 4);
uint32_t blue = (Palette[colorIndex * 3 + 2] << 2) | (Palette[colorIndex * 3 + 2] >> 4);
dest->col[j] = 0xff000000 | (red << 16) | (green << 8) | blue;
}
slabzleng += 3;
dest = (kvxslab_bgra_t *)((uint32_t *)dest + slabzleng);
src = (kvxslab_t *)((BYTE *)src + slabzleng);
size -= slabzleng;
}
}
}
//==========================================================================
//
// Remap the voxel to the game palette

View file

@ -15,6 +15,14 @@ struct kvxslab_t
BYTE col[1/*zleng*/];// color data from top to bottom
};
struct kvxslab_bgra_t
{
uint32_t ztop; // starting z coordinate of top of slab
uint32_t zleng; // # of bytes in the color array - slab height
uint32_t backfacecull; // low 6 bits tell which of 6 faces are exposed
uint32_t col[1/*zleng*/];// color data from top to bottom
};
struct FVoxelMipLevel
{
FVoxelMipLevel();
@ -27,6 +35,7 @@ struct FVoxelMipLevel
int *OffsetX;
short *OffsetXY;
BYTE *SlabData;
TArray<uint32_t> SlabDataBgra;
};
struct FVoxel
@ -39,6 +48,7 @@ struct FVoxel
FVoxel();
~FVoxel();
void CreateBgraSlabData();
void Remap();
void RemovePalette();
};

View file

@ -60,7 +60,6 @@ enum
SIL_BOTH
};
namespace swrenderer { extern size_t MaxDrawSegs; }
struct FDisplacement;
//

File diff suppressed because it is too large Load diff

View file

@ -1,296 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// System specific interface stuff.
//
//-----------------------------------------------------------------------------
#ifndef __R_DRAW__
#define __R_DRAW__
#include "r_defs.h"
extern "C" int ylookup[MAXHEIGHT];
extern "C" int dc_pitch; // [RH] Distance between rows
extern "C" lighttable_t*dc_colormap;
extern "C" int dc_x;
extern "C" int dc_yl;
extern "C" int dc_yh;
extern "C" fixed_t dc_iscale;
extern double dc_texturemid;
extern "C" fixed_t dc_texturefrac;
extern "C" int dc_color; // [RH] For flat colors (no texturing)
extern "C" DWORD dc_srccolor;
extern "C" DWORD *dc_srcblend;
extern "C" DWORD *dc_destblend;
// first pixel in a column
extern "C" const BYTE* dc_source;
extern "C" BYTE *dc_dest, *dc_destorg;
extern "C" int dc_count;
extern "C" DWORD vplce[4];
extern "C" DWORD vince[4];
extern "C" BYTE* palookupoffse[4];
extern "C" const BYTE* bufplce[4];
// [RH] Temporary buffer for column drawing
extern "C" BYTE *dc_temp;
extern "C" unsigned int dc_tspans[4][MAXHEIGHT];
extern "C" unsigned int *dc_ctspan[4];
extern "C" unsigned int horizspans[4];
// [RH] Pointers to the different column and span drawers...
// The span blitting interface.
// Hook in assembler or system specific BLT here.
extern void (*R_DrawColumn)(void);
extern DWORD (*dovline1) ();
extern DWORD (*doprevline1) ();
#ifdef X64_ASM
#define dovline4 vlinetallasm4
extern "C" void vlinetallasm4();
#else
extern void (*dovline4) ();
#endif
extern void setupvline (int);
extern DWORD (*domvline1) ();
extern void (*domvline4) ();
extern void setupmvline (int);
extern void setuptmvline (int);
// The Spectre/Invisibility effect.
extern void (*R_DrawFuzzColumn)(void);
// [RH] Draw shaded column
extern void (*R_DrawShadedColumn)(void);
// Draw with color translation tables, for player sprite rendering,
// Green/Red/Blue/Indigo shirts.
extern void (*R_DrawTranslatedColumn)(void);
// Span drawing for rows, floor/ceiling. No Spectre effect needed.
extern void (*R_DrawSpan)(void);
void R_SetupSpanBits(FTexture *tex);
void R_SetSpanColormap(BYTE *colormap);
void R_SetSpanSource(const BYTE *pixels);
// Span drawing for masked textures.
extern void (*R_DrawSpanMasked)(void);
// Span drawing for translucent textures.
extern void (*R_DrawSpanTranslucent)(void);
// Span drawing for masked, translucent textures.
extern void (*R_DrawSpanMaskedTranslucent)(void);
// Span drawing for translucent, additive textures.
extern void (*R_DrawSpanAddClamp)(void);
// Span drawing for masked, translucent, additive textures.
extern void (*R_DrawSpanMaskedAddClamp)(void);
// [RH] Span blit into an interleaved intermediate buffer
extern void (*R_DrawColumnHoriz)(void);
void R_DrawMaskedColumnHoriz (const BYTE *column, const FTexture::Span *spans);
// [RH] Initialize the above pointers
void R_InitColumnDrawers ();
// [RH] Moves data from the temporary buffer to the screen.
extern "C"
{
void rt_copy1col_c (int hx, int sx, int yl, int yh);
void rt_copy4cols_c (int sx, int yl, int yh);
void rt_shaded1col (int hx, int sx, int yl, int yh);
void rt_shaded4cols_c (int sx, int yl, int yh);
void rt_shaded4cols_asm (int sx, int yl, int yh);
void rt_map1col_c (int hx, int sx, int yl, int yh);
void rt_add1col (int hx, int sx, int yl, int yh);
void rt_addclamp1col (int hx, int sx, int yl, int yh);
void rt_subclamp1col (int hx, int sx, int yl, int yh);
void rt_revsubclamp1col (int hx, int sx, int yl, int yh);
void rt_tlate1col (int hx, int sx, int yl, int yh);
void rt_tlateadd1col (int hx, int sx, int yl, int yh);
void rt_tlateaddclamp1col (int hx, int sx, int yl, int yh);
void rt_tlatesubclamp1col (int hx, int sx, int yl, int yh);
void rt_tlaterevsubclamp1col (int hx, int sx, int yl, int yh);
void rt_map4cols_c (int sx, int yl, int yh);
void rt_add4cols_c (int sx, int yl, int yh);
void rt_addclamp4cols_c (int sx, int yl, int yh);
void rt_subclamp4cols (int sx, int yl, int yh);
void rt_revsubclamp4cols (int sx, int yl, int yh);
void rt_tlate4cols (int sx, int yl, int yh);
void rt_tlateadd4cols (int sx, int yl, int yh);
void rt_tlateaddclamp4cols (int sx, int yl, int yh);
void rt_tlatesubclamp4cols (int sx, int yl, int yh);
void rt_tlaterevsubclamp4cols (int sx, int yl, int yh);
void rt_copy1col_asm (int hx, int sx, int yl, int yh);
void rt_map1col_asm (int hx, int sx, int yl, int yh);
void rt_copy4cols_asm (int sx, int yl, int yh);
void rt_map4cols_asm1 (int sx, int yl, int yh);
void rt_map4cols_asm2 (int sx, int yl, int yh);
void rt_add4cols_asm (int sx, int yl, int yh);
void rt_addclamp4cols_asm (int sx, int yl, int yh);
}
extern void (*rt_map4cols)(int sx, int yl, int yh);
#ifdef X86_ASM
#define rt_copy1col rt_copy1col_asm
#define rt_copy4cols rt_copy4cols_asm
#define rt_map1col rt_map1col_asm
#define rt_shaded4cols rt_shaded4cols_asm
#define rt_add4cols rt_add4cols_asm
#define rt_addclamp4cols rt_addclamp4cols_asm
#else
#define rt_copy1col rt_copy1col_c
#define rt_copy4cols rt_copy4cols_c
#define rt_map1col rt_map1col_c
#define rt_shaded4cols rt_shaded4cols_c
#define rt_add4cols rt_add4cols_c
#define rt_addclamp4cols rt_addclamp4cols_c
#endif
void rt_draw4cols (int sx);
// [RH] Preps the temporary horizontal buffer.
void rt_initcols (BYTE *buffer=NULL);
void R_DrawFogBoundary (int x1, int x2, short *uclip, short *dclip);
#ifdef X86_ASM
extern "C" void R_DrawColumnP_Unrolled (void);
extern "C" void R_DrawColumnHorizP_ASM (void);
extern "C" void R_DrawColumnP_ASM (void);
extern "C" void R_DrawFuzzColumnP_ASM (void);
void R_DrawTranslatedColumnP_C (void);
void R_DrawShadedColumnP_C (void);
extern "C" void R_DrawSpanP_ASM (void);
extern "C" void R_DrawSpanMaskedP_ASM (void);
#else
void R_DrawColumnHorizP_C (void);
void R_DrawColumnP_C (void);
void R_DrawFuzzColumnP_C (void);
void R_DrawTranslatedColumnP_C (void);
void R_DrawShadedColumnP_C (void);
void R_DrawSpanP_C (void);
void R_DrawSpanMaskedP_C (void);
#endif
void R_DrawSpanTranslucentP_C (void);
void R_DrawSpanMaskedTranslucentP_C (void);
void R_DrawTlatedLucentColumnP_C (void);
#define R_DrawTlatedLucentColumn R_DrawTlatedLucentColumnP_C
void R_FillColumnP (void);
void R_FillColumnHorizP (void);
void R_FillSpan (void);
#ifdef X86_ASM
#define R_SetupDrawSlab R_SetupDrawSlabA
#define R_DrawSlab R_DrawSlabA
#else
#define R_SetupDrawSlab R_SetupDrawSlabC
#define R_DrawSlab R_DrawSlabC
#endif
extern "C" void R_SetupDrawSlab(const BYTE *colormap);
extern "C" void R_DrawSlab(int dx, fixed_t v, int dy, fixed_t vi, const BYTE *vptr, BYTE *p);
extern "C" int ds_y;
extern "C" int ds_x1;
extern "C" int ds_x2;
extern "C" lighttable_t* ds_colormap;
extern "C" dsfixed_t ds_xfrac;
extern "C" dsfixed_t ds_yfrac;
extern "C" dsfixed_t ds_xstep;
extern "C" dsfixed_t ds_ystep;
extern "C" int ds_xbits;
extern "C" int ds_ybits;
extern "C" fixed_t ds_alpha;
// start of a 64*64 tile image
extern "C" const BYTE* ds_source;
extern "C" int ds_color; // [RH] For flat color (no texturing)
extern BYTE shadetables[/*NUMCOLORMAPS*16*256*/];
extern FDynamicColormap ShadeFakeColormap[16];
extern BYTE identitymap[256];
extern BYTE *dc_translation;
// [RH] Added for muliresolution support
void R_InitShadeMaps();
void R_InitFuzzTable (int fuzzoff);
// [RH] Consolidate column drawer selection
enum ESPSResult
{
DontDraw, // not useful to draw this
DoDraw0, // draw this as if r_columnmethod is 0
DoDraw1, // draw this as if r_columnmethod is 1
};
ESPSResult R_SetPatchStyle (FRenderStyle style, fixed_t alpha, int translation, DWORD color);
inline ESPSResult R_SetPatchStyle(FRenderStyle style, float alpha, int translation, DWORD color)
{
return R_SetPatchStyle(style, FLOAT2FIXED(alpha), translation, color);
}
// Call this after finished drawing the current thing, in case its
// style was STYLE_Shade
void R_FinishSetPatchStyle ();
// transmaskwallscan calls this to find out what column drawers to use
bool R_GetTransMaskDrawers (fixed_t (**tmvline1)(), void (**tmvline4)());
// Retrieve column data for wallscan. Should probably be removed
// to just use the texture's GetColumn() method. It just exists
// for double-layer skies.
const BYTE *R_GetColumn (FTexture *tex, int col);
void wallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int col)=R_GetColumn);
// maskwallscan is exactly like wallscan but does not draw anything where the texture is color 0.
void maskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int col)=R_GetColumn);
// transmaskwallscan is like maskwallscan, but it can also blend to the background
void transmaskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int col)=R_GetColumn);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,329 +0,0 @@
#pragma once
#include "r_draw.h"
#include "v_palette.h"
#include "r_thread.h"
namespace swrenderer
{
class PalWall1Command : public DrawerCommand
{
public:
PalWall1Command();
FString DebugInfo() override { return "PalWallCommand"; }
protected:
uint32_t _iscale;
uint32_t _texturefrac;
uint8_t *_colormap;
int _count;
const uint8_t *_source;
uint8_t *_dest;
int _fracbits;
int _pitch;
uint32_t *_srcblend;
uint32_t *_destblend;
};
class PalWall4Command : public DrawerCommand
{
public:
PalWall4Command();
FString DebugInfo() override { return "PalWallCommand"; }
protected:
uint8_t *_dest;
int _count;
int _pitch;
int _fracbits;
uint8_t *_colormap[4];
const uint8_t *_source[4];
uint32_t _iscale[4];
uint32_t _texturefrac[4];
uint32_t *_srcblend;
uint32_t *_destblend;
};
class DrawWall1PalCommand : public PalWall1Command { public: void Execute(DrawerThread *thread) override; };
class DrawWall4PalCommand : public PalWall4Command { public: void Execute(DrawerThread *thread) override; };
class DrawWallMasked1PalCommand : public PalWall1Command { public: void Execute(DrawerThread *thread) override; };
class DrawWallMasked4PalCommand : public PalWall4Command { public: void Execute(DrawerThread *thread) override; };
class DrawWallAdd1PalCommand : public PalWall1Command { public: void Execute(DrawerThread *thread) override; };
class DrawWallAdd4PalCommand : public PalWall4Command { public: void Execute(DrawerThread *thread) override; };
class DrawWallAddClamp1PalCommand : public PalWall1Command { public: void Execute(DrawerThread *thread) override; };
class DrawWallAddClamp4PalCommand : public PalWall4Command { public: void Execute(DrawerThread *thread) override; };
class DrawWallSubClamp1PalCommand : public PalWall1Command { public: void Execute(DrawerThread *thread) override; };
class DrawWallSubClamp4PalCommand : public PalWall4Command { public: void Execute(DrawerThread *thread) override; };
class DrawWallRevSubClamp1PalCommand : public PalWall1Command { public: void Execute(DrawerThread *thread) override; };
class DrawWallRevSubClamp4PalCommand : public PalWall4Command { public: void Execute(DrawerThread *thread) override; };
class PalSkyCommand : public DrawerCommand
{
public:
PalSkyCommand(uint32_t solid_top, uint32_t solid_bottom);
FString DebugInfo() override { return "PalSkyCommand"; }
protected:
uint32_t solid_top;
uint32_t solid_bottom;
uint8_t *_dest;
int _count;
int _pitch;
const uint8_t *_source[4];
const uint8_t *_source2[4];
int _sourceheight[4];
uint32_t _iscale[4];
uint32_t _texturefrac[4];
};
class DrawSingleSky1PalCommand : public PalSkyCommand { public: using PalSkyCommand::PalSkyCommand; void Execute(DrawerThread *thread) override; };
class DrawSingleSky4PalCommand : public PalSkyCommand { public: using PalSkyCommand::PalSkyCommand; void Execute(DrawerThread *thread) override; };
class DrawDoubleSky1PalCommand : public PalSkyCommand { public: using PalSkyCommand::PalSkyCommand; void Execute(DrawerThread *thread) override; };
class DrawDoubleSky4PalCommand : public PalSkyCommand { public: using PalSkyCommand::PalSkyCommand; void Execute(DrawerThread *thread) override; };
class PalColumnCommand : public DrawerCommand
{
public:
PalColumnCommand();
FString DebugInfo() override { return "PalColumnCommand"; }
protected:
int _count;
uint8_t *_dest;
int _pitch;
fixed_t _iscale;
fixed_t _texturefrac;
const uint8_t *_colormap;
const uint8_t *_source;
const uint8_t *_translation;
int _color;
uint32_t *_srcblend;
uint32_t *_destblend;
uint32_t _srccolor;
};
class DrawColumnPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class FillColumnPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class FillColumnAddPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class FillColumnAddClampPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class FillColumnSubClampPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class FillColumnRevSubClampPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class DrawColumnAddPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class DrawColumnTranslatedPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class DrawColumnTlatedAddPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class DrawColumnShadedPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class DrawColumnAddClampPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class DrawColumnAddClampTranslatedPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class DrawColumnSubClampPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class DrawColumnSubClampTranslatedPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class DrawColumnRevSubClampPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class DrawColumnRevSubClampTranslatedPalCommand : public PalColumnCommand { public: void Execute(DrawerThread *thread) override; };
class DrawFuzzColumnPalCommand : public DrawerCommand
{
public:
DrawFuzzColumnPalCommand();
void Execute(DrawerThread *thread) override;
FString DebugInfo() override { return "DrawFuzzColumnPalCommand"; }
private:
int _yl;
int _yh;
int _x;
uint8_t *_destorg;
int _pitch;
int _fuzzpos;
int _fuzzviewheight;
};
class PalSpanCommand : public DrawerCommand
{
public:
PalSpanCommand();
FString DebugInfo() override { return "PalSpanCommand"; }
protected:
const uint8_t *_source;
const uint8_t *_colormap;
dsfixed_t _xfrac;
dsfixed_t _yfrac;
int _y;
int _x1;
int _x2;
uint8_t *_destorg;
dsfixed_t _xstep;
dsfixed_t _ystep;
int _xbits;
int _ybits;
uint32_t *_srcblend;
uint32_t *_destblend;
int _color;
};
class DrawSpanPalCommand : public PalSpanCommand { public: void Execute(DrawerThread *thread) override; };
class DrawSpanMaskedPalCommand : public PalSpanCommand { public: void Execute(DrawerThread *thread) override; };
class DrawSpanTranslucentPalCommand : public PalSpanCommand { public: void Execute(DrawerThread *thread) override; };
class DrawSpanMaskedTranslucentPalCommand : public PalSpanCommand { public: void Execute(DrawerThread *thread) override; };
class DrawSpanAddClampPalCommand : public PalSpanCommand { public: void Execute(DrawerThread *thread) override; };
class DrawSpanMaskedAddClampPalCommand : public PalSpanCommand { public: void Execute(DrawerThread *thread) override; };
class FillSpanPalCommand : public PalSpanCommand { public: void Execute(DrawerThread *thread) override; };
class DrawTiltedSpanPalCommand : public DrawerCommand
{
public:
DrawTiltedSpanPalCommand(int y, int x1, int x2, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy);
void Execute(DrawerThread *thread) override;
FString DebugInfo() override { return "DrawTiltedSpanPalCommand"; }
private:
void CalcTiltedLighting(double lval, double lend, int width, DrawerThread *thread);
int y;
int x1;
int x2;
FVector3 plane_sz;
FVector3 plane_su;
FVector3 plane_sv;
bool plane_shade;
int planeshade;
float planelightfloat;
fixed_t pviewx;
fixed_t pviewy;
const uint8_t *_colormap;
uint8_t *_destorg;
int _ybits;
int _xbits;
const uint8_t *_source;
uint8_t *basecolormapdata;
};
class DrawColoredSpanPalCommand : public PalSpanCommand
{
public:
DrawColoredSpanPalCommand(int y, int x1, int x2);
void Execute(DrawerThread *thread) override;
FString DebugInfo() override { return "DrawColoredSpanPalCommand"; }
private:
int y;
int x1;
int x2;
int color;
uint8_t *destorg;
};
class DrawSlabPalCommand : public PalSpanCommand
{
public:
DrawSlabPalCommand(int dx, fixed_t v, int dy, fixed_t vi, const uint8_t *vptr, uint8_t *p, const uint8_t *colormap);
void Execute(DrawerThread *thread) override;
private:
int _dx;
fixed_t _v;
int _dy;
fixed_t _vi;
const uint8_t *_vvptr;
uint8_t *_p;
const uint8_t *_colormap;
int _pitch;
int _start_y;
};
class DrawFogBoundaryLinePalCommand : public PalSpanCommand
{
public:
DrawFogBoundaryLinePalCommand(int y, int x1, int x2);
void Execute(DrawerThread *thread) override;
private:
int y, x1, x2;
const uint8_t *_colormap;
uint8_t *_destorg;
};
class RtInitColsPalCommand : public DrawerCommand
{
public:
RtInitColsPalCommand(uint8_t *buff);
void Execute(DrawerThread *thread) override;
FString DebugInfo() override { return "RtInitColsPalCommand"; }
private:
uint8_t *buff;
};
class PalColumnHorizCommand : public DrawerCommand
{
public:
PalColumnHorizCommand();
protected:
const uint8_t *_source;
fixed_t _iscale;
fixed_t _texturefrac;
int _count;
int _color;
int _x;
int _yl;
};
class DrawColumnHorizPalCommand : public PalColumnHorizCommand
{
public:
void Execute(DrawerThread *thread) override;
FString DebugInfo() override { return "DrawColumnHorizPalCommand"; }
};
class FillColumnHorizPalCommand : public PalColumnHorizCommand
{
public:
void Execute(DrawerThread *thread) override;
FString DebugInfo() override { return "FillColumnHorizPalCommand"; }
};
class PalRtCommand : public DrawerCommand
{
public:
PalRtCommand(int hx, int sx, int yl, int yh);
FString DebugInfo() override { return "PalRtCommand"; }
protected:
int hx, sx, yl, yh;
uint8_t *_destorg;
int _pitch;
const uint8_t *_colormap;
const uint32_t *_srcblend;
const uint32_t *_destblend;
const uint8_t *_translation;
int _color;
};
class DrawColumnRt1CopyPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt4CopyPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt1PalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt4PalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt1TranslatedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt4TranslatedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt1AddPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt4AddPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
//class DrawColumnRt1AddTranslatedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
//class DrawColumnRt4AddTranslatedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt1ShadedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt4ShadedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt1AddClampPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt4AddClampPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
//class DrawColumnRt1AddClampTranslatedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
//class DrawColumnRt4AddClampTranslatedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt1SubClampPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt4SubClampPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
//class DrawColumnRt1SubClampTranslatedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
//class DrawColumnRt4SubClampTranslatedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt1RevSubClampPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
class DrawColumnRt4RevSubClampPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
//class DrawColumnRt1RevSubClampTranslatedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
//class DrawColumnRt4RevSubClampTranslatedPalCommand : public PalRtCommand { public: using PalRtCommand::PalRtCommand; void Execute(DrawerThread *thread) override; };
}

View file

@ -1,867 +0,0 @@
/*
** r_drawt.cpp
** Faster column drawers for modern processors
**
**---------------------------------------------------------------------------
** 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.
**---------------------------------------------------------------------------
**
** These functions stretch columns into a temporary buffer and then
** map them to the screen. On modern machines, this is faster than drawing
** them directly to the screen.
**
** Will I be able to even understand any of this if I come back to it later?
** Let's hope so. :-)
*/
#include "templates.h"
#include "doomtype.h"
#include "doomdef.h"
#include "r_defs.h"
#include "r_draw.h"
#include "r_main.h"
#include "r_things.h"
#include "v_video.h"
#include "r_draw_pal.h"
// I should have commented this stuff better.
//
// dc_temp is the buffer R_DrawColumnHoriz writes into.
// dc_tspans points into it.
// dc_ctspan points into dc_tspans.
// horizspan also points into dc_tspans.
// dc_ctspan is advanced while drawing into dc_temp.
// horizspan is advanced up to dc_ctspan when drawing from dc_temp to the screen.
namespace swrenderer
{
RtInitColsPalCommand::RtInitColsPalCommand(uint8_t *buff) : buff(buff)
{
}
void RtInitColsPalCommand::Execute(DrawerThread *thread)
{
thread->dc_temp = buff == nullptr ? thread->dc_temp_buff : buff;
}
/////////////////////////////////////////////////////////////////////
PalColumnHorizCommand::PalColumnHorizCommand()
{
using namespace drawerargs;
_source = dc_source;
_iscale = dc_iscale;
_texturefrac = dc_texturefrac;
_count = dc_count;
_color = dc_color;
_x = dc_x;
_yl = dc_yl;
}
void DrawColumnHorizPalCommand::Execute(DrawerThread *thread)
{
int count = _count;
uint8_t *dest;
fixed_t fracstep;
fixed_t frac;
count = thread->count_for_thread(_yl, count);
if (count <= 0)
return;
fracstep = _iscale;
frac = _texturefrac;
const uint8_t *source = _source;
int x = _x & 3;
dest = &thread->dc_temp[x + thread->temp_line_for_thread(_yl) * 4];
frac += fracstep * thread->skipped_by_thread(_yl);
fracstep *= thread->num_cores;
if (count & 1) {
*dest = source[frac >> FRACBITS]; dest += 4; frac += fracstep;
}
if (count & 2) {
dest[0] = source[frac >> FRACBITS]; frac += fracstep;
dest[4] = source[frac >> FRACBITS]; frac += fracstep;
dest += 8;
}
if (count & 4) {
dest[0] = source[frac >> FRACBITS]; frac += fracstep;
dest[4] = source[frac >> FRACBITS]; frac += fracstep;
dest[8] = source[frac >> FRACBITS]; frac += fracstep;
dest[12] = source[frac >> FRACBITS]; frac += fracstep;
dest += 16;
}
count >>= 3;
if (!count) return;
do
{
dest[0] = source[frac >> FRACBITS]; frac += fracstep;
dest[4] = source[frac >> FRACBITS]; frac += fracstep;
dest[8] = source[frac >> FRACBITS]; frac += fracstep;
dest[12] = source[frac >> FRACBITS]; frac += fracstep;
dest[16] = source[frac >> FRACBITS]; frac += fracstep;
dest[20] = source[frac >> FRACBITS]; frac += fracstep;
dest[24] = source[frac >> FRACBITS]; frac += fracstep;
dest[28] = source[frac >> FRACBITS]; frac += fracstep;
dest += 32;
} while (--count);
}
void FillColumnHorizPalCommand::Execute(DrawerThread *thread)
{
int count = _count;
uint8_t color = _color;
uint8_t *dest;
count = thread->count_for_thread(_yl, count);
if (count <= 0)
return;
int x = _x & 3;
dest = &thread->dc_temp[x + thread->temp_line_for_thread(_yl) * 4];
if (count & 1) {
*dest = color;
dest += 4;
}
if (!(count >>= 1))
return;
do {
dest[0] = color; dest[4] = color;
dest += 8;
} while (--count);
}
/////////////////////////////////////////////////////////////////////
PalRtCommand::PalRtCommand(int hx, int sx, int yl, int yh) : hx(hx), sx(sx), yl(yl), yh(yh)
{
using namespace drawerargs;
_destorg = dc_destorg;
_pitch = dc_pitch;
_colormap = dc_colormap;
_srcblend = dc_srcblend;
_destblend = dc_destblend;
_translation = dc_translation;
_color = dc_color;
}
void DrawColumnRt1CopyPalCommand::Execute(DrawerThread *thread)
{
uint8_t *source;
uint8_t *dest;
int count;
int pitch;
count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4 + hx];
pitch = _pitch * thread->num_cores;
if (count & 1) {
*dest = *source;
source += 4;
dest += pitch;
}
if (count & 2) {
dest[0] = source[0];
dest[pitch] = source[4];
source += 8;
dest += pitch*2;
}
if (!(count >>= 2))
return;
do {
dest[0] = source[0];
dest[pitch] = source[4];
dest[pitch*2] = source[8];
dest[pitch*3] = source[12];
source += 16;
dest += pitch*4;
} while (--count);
}
void DrawColumnRt4CopyPalCommand::Execute(DrawerThread *thread)
{
int *source;
int *dest;
int count;
int pitch;
count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
dest = (int *)(ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg);
source = (int *)(&thread->dc_temp[thread->temp_line_for_thread(yl)*4]);
pitch = _pitch*thread->num_cores/sizeof(int);
if (count & 1) {
*dest = *source;
source += 4/sizeof(int);
dest += pitch;
}
if (!(count >>= 1))
return;
do {
dest[0] = source[0];
dest[pitch] = source[4/sizeof(int)];
source += 8/sizeof(int);
dest += pitch*2;
} while (--count);
}
void DrawColumnRt1PalCommand::Execute(DrawerThread *thread)
{
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int count;
int pitch;
count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
colormap = _colormap;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl) *4 + hx];
pitch = _pitch*thread->num_cores;
if (count & 1) {
*dest = colormap[*source];
source += 4;
dest += pitch;
}
if (!(count >>= 1))
return;
do {
dest[0] = colormap[source[0]];
dest[pitch] = colormap[source[4]];
source += 8;
dest += pitch*2;
} while (--count);
}
void DrawColumnRt4PalCommand::Execute(DrawerThread *thread)
{
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int count;
int pitch;
count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
colormap = _colormap;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4];
pitch = _pitch*thread->num_cores;
if (count & 1) {
dest[0] = colormap[source[0]];
dest[1] = colormap[source[1]];
dest[2] = colormap[source[2]];
dest[3] = colormap[source[3]];
source += 4;
dest += pitch;
}
if (!(count >>= 1))
return;
do {
dest[0] = colormap[source[0]];
dest[1] = colormap[source[1]];
dest[2] = colormap[source[2]];
dest[3] = colormap[source[3]];
dest[pitch] = colormap[source[4]];
dest[pitch+1] = colormap[source[5]];
dest[pitch+2] = colormap[source[6]];
dest[pitch+3] = colormap[source[7]];
source += 8;
dest += pitch*2;
} while (--count);
}
void DrawColumnRt1TranslatedPalCommand::Execute(DrawerThread *thread)
{
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
uint8_t *source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4 + hx];
const uint8_t *translation = _translation;
// Things we do to hit the compiler's optimizer with a clue bat:
// 1. Parallelism is explicitly spelled out by using a separate
// C instruction for each assembly instruction. GCC lets me
// have four temporaries, but VC++ spills to the stack with
// more than two. Two is probably optimal, anyway.
// 2. The results of the translation lookups are explicitly
// stored in byte-sized variables. This causes the VC++ code
// to use byte mov instructions in most cases; for apparently
// random reasons, it will use movzx for some places. GCC
// ignores this and uses movzx always.
// Do 8 rows at a time.
for (int count8 = count >> 3; count8; --count8)
{
int c0, c1;
uint8_t b0, b1;
c0 = source[0]; c1 = source[4];
b0 = translation[c0]; b1 = translation[c1];
source[0] = b0; source[4] = b1;
c0 = source[8]; c1 = source[12];
b0 = translation[c0]; b1 = translation[c1];
source[8] = b0; source[12] = b1;
c0 = source[16]; c1 = source[20];
b0 = translation[c0]; b1 = translation[c1];
source[16] = b0; source[20] = b1;
c0 = source[24]; c1 = source[28];
b0 = translation[c0]; b1 = translation[c1];
source[24] = b0; source[28] = b1;
source += 32;
}
// Finish by doing 1 row at a time.
for (count &= 7; count; --count, source += 4)
{
source[0] = translation[source[0]];
}
}
void DrawColumnRt4TranslatedPalCommand::Execute(DrawerThread *thread)
{
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
uint8_t *source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4];
const uint8_t *translation = _translation;
int c0, c1;
uint8_t b0, b1;
// Do 2 rows at a time.
for (int count8 = count >> 1; count8; --count8)
{
c0 = source[0]; c1 = source[1];
b0 = translation[c0]; b1 = translation[c1];
source[0] = b0; source[1] = b1;
c0 = source[2]; c1 = source[3];
b0 = translation[c0]; b1 = translation[c1];
source[2] = b0; source[3] = b1;
c0 = source[4]; c1 = source[5];
b0 = translation[c0]; b1 = translation[c1];
source[4] = b0; source[5] = b1;
c0 = source[6]; c1 = source[7];
b0 = translation[c0]; b1 = translation[c1];
source[6] = b0; source[7] = b1;
source += 8;
}
// Do the final row if count was odd.
if (count & 1)
{
c0 = source[0]; c1 = source[1];
b0 = translation[c0]; b1 = translation[c1];
source[0] = b0; source[1] = b1;
c0 = source[2]; c1 = source[3];
b0 = translation[c0]; b1 = translation[c1];
source[2] = b0; source[3] = b1;
}
}
void DrawColumnRt1AddPalCommand::Execute(DrawerThread *thread)
{
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int pitch;
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
const uint32_t *fg2rgb = _srcblend;
const uint32_t *bg2rgb = _destblend;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4 + hx];
pitch = _pitch * thread->num_cores;
colormap = _colormap;
do {
uint32_t fg = colormap[*source];
uint32_t bg = *dest;
fg = fg2rgb[fg];
bg = bg2rgb[bg];
fg = (fg+bg) | 0x1f07c1f;
*dest = RGB32k.All[fg & (fg>>15)];
source += 4;
dest += pitch;
} while (--count);
}
void DrawColumnRt4AddPalCommand::Execute(DrawerThread *thread)
{
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int pitch;
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
const uint32_t *fg2rgb = _srcblend;
const uint32_t *bg2rgb = _destblend;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4];
pitch = _pitch * thread->num_cores;
colormap = _colormap;
do {
uint32_t fg = colormap[source[0]];
uint32_t bg = dest[0];
fg = fg2rgb[fg];
bg = bg2rgb[bg];
fg = (fg+bg) | 0x1f07c1f;
dest[0] = RGB32k.All[fg & (fg>>15)];
fg = colormap[source[1]];
bg = dest[1];
fg = fg2rgb[fg];
bg = bg2rgb[bg];
fg = (fg+bg) | 0x1f07c1f;
dest[1] = RGB32k.All[fg & (fg>>15)];
fg = colormap[source[2]];
bg = dest[2];
fg = fg2rgb[fg];
bg = bg2rgb[bg];
fg = (fg+bg) | 0x1f07c1f;
dest[2] = RGB32k.All[fg & (fg>>15)];
fg = colormap[source[3]];
bg = dest[3];
fg = fg2rgb[fg];
bg = bg2rgb[bg];
fg = (fg+bg) | 0x1f07c1f;
dest[3] = RGB32k.All[fg & (fg>>15)];
source += 4;
dest += pitch;
} while (--count);
}
void DrawColumnRt1ShadedPalCommand::Execute(DrawerThread *thread)
{
uint32_t *fgstart;
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int pitch;
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
fgstart = &Col2RGB8[0][_color];
colormap = _colormap;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4 + hx];
pitch = _pitch * thread->num_cores;
do {
uint32_t val = colormap[*source];
uint32_t fg = fgstart[val<<8];
val = (Col2RGB8[64-val][*dest] + fg) | 0x1f07c1f;
*dest = RGB32k.All[val & (val>>15)];
source += 4;
dest += pitch;
} while (--count);
}
void DrawColumnRt4ShadedPalCommand::Execute(DrawerThread *thread)
{
uint32_t *fgstart;
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int pitch;
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
fgstart = &Col2RGB8[0][_color];
colormap = _colormap;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4];
pitch = _pitch * thread->num_cores;
do {
uint32_t val;
val = colormap[source[0]];
val = (Col2RGB8[64-val][dest[0]] + fgstart[val<<8]) | 0x1f07c1f;
dest[0] = RGB32k.All[val & (val>>15)];
val = colormap[source[1]];
val = (Col2RGB8[64-val][dest[1]] + fgstart[val<<8]) | 0x1f07c1f;
dest[1] = RGB32k.All[val & (val>>15)];
val = colormap[source[2]];
val = (Col2RGB8[64-val][dest[2]] + fgstart[val<<8]) | 0x1f07c1f;
dest[2] = RGB32k.All[val & (val>>15)];
val = colormap[source[3]];
val = (Col2RGB8[64-val][dest[3]] + fgstart[val<<8]) | 0x1f07c1f;
dest[3] = RGB32k.All[val & (val>>15)];
source += 4;
dest += pitch;
} while (--count);
}
void DrawColumnRt1AddClampPalCommand::Execute(DrawerThread *thread)
{
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int pitch;
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
const uint32_t *fg2rgb = _srcblend;
const uint32_t *bg2rgb = _destblend;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4 + hx];
pitch = _pitch * thread->num_cores;
colormap = _colormap;
do {
uint32_t a = fg2rgb[colormap[*source]] + bg2rgb[*dest];
uint32_t b = a;
a |= 0x01f07c1f;
b &= 0x40100400;
a &= 0x3fffffff;
b = b - (b >> 5);
a |= b;
*dest = RGB32k.All[(a>>15) & a];
source += 4;
dest += pitch;
} while (--count);
}
void DrawColumnRt4AddClampPalCommand::Execute(DrawerThread *thread)
{
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int pitch;
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4];
pitch = _pitch * thread->num_cores;
colormap = _colormap;
const uint32_t *fg2rgb = _srcblend;
const uint32_t *bg2rgb = _destblend;
do {
uint32_t a = fg2rgb[colormap[source[0]]] + bg2rgb[dest[0]];
uint32_t b = a;
a |= 0x01f07c1f;
b &= 0x40100400;
a &= 0x3fffffff;
b = b - (b >> 5);
a |= b;
dest[0] = RGB32k.All[(a>>15) & a];
a = fg2rgb[colormap[source[1]]] + bg2rgb[dest[1]];
b = a;
a |= 0x01f07c1f;
b &= 0x40100400;
a &= 0x3fffffff;
b = b - (b >> 5);
a |= b;
dest[1] = RGB32k.All[(a>>15) & a];
a = fg2rgb[colormap[source[2]]] + bg2rgb[dest[2]];
b = a;
a |= 0x01f07c1f;
b &= 0x40100400;
a &= 0x3fffffff;
b = b - (b >> 5);
a |= b;
dest[2] = RGB32k.All[(a>>15) & a];
a = fg2rgb[colormap[source[3]]] + bg2rgb[dest[3]];
b = a;
a |= 0x01f07c1f;
b &= 0x40100400;
a &= 0x3fffffff;
b = b - (b >> 5);
a |= b;
dest[3] = RGB32k.All[(a>>15) & a];
source += 4;
dest += pitch;
} while (--count);
}
void DrawColumnRt1SubClampPalCommand::Execute(DrawerThread *thread)
{
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int pitch;
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
const uint32_t *fg2rgb = _srcblend;
const uint32_t *bg2rgb = _destblend;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4 + hx];
pitch = _pitch * thread->num_cores;
colormap = _colormap;
do {
uint32_t a = (fg2rgb[colormap[*source]] | 0x40100400) - bg2rgb[*dest];
uint32_t b = a;
b &= 0x40100400;
b = b - (b >> 5);
a &= b;
a |= 0x01f07c1f;
*dest = RGB32k.All[(a>>15) & a];
source += 4;
dest += pitch;
} while (--count);
}
void DrawColumnRt4SubClampPalCommand::Execute(DrawerThread *thread)
{
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int pitch;
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
const uint32_t *fg2rgb = _srcblend;
const uint32_t *bg2rgb = _destblend;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4];
pitch = _pitch * thread->num_cores;
colormap = _colormap;
do {
uint32_t a = (fg2rgb[colormap[source[0]]] | 0x40100400) - bg2rgb[dest[0]];
uint32_t b = a;
b &= 0x40100400;
b = b - (b >> 5);
a &= b;
a |= 0x01f07c1f;
dest[0] = RGB32k.All[(a>>15) & a];
a = (fg2rgb[colormap[source[1]]] | 0x40100400) - bg2rgb[dest[1]];
b = a;
b &= 0x40100400;
b = b - (b >> 5);
a &= b;
a |= 0x01f07c1f;
dest[1] = RGB32k.All[(a>>15) & a];
a = (fg2rgb[colormap[source[2]]] | 0x40100400) - bg2rgb[dest[2]];
b = a;
b &= 0x40100400;
b = b - (b >> 5);
a &= b;
a |= 0x01f07c1f;
dest[2] = RGB32k.All[(a>>15) & a];
a = (fg2rgb[colormap[source[3]]] | 0x40100400) - bg2rgb[dest[3]];
b = a;
b &= 0x40100400;
b = b - (b >> 5);
a &= b;
a |= 0x01f07c1f;
dest[3] = RGB32k.All[(a>>15) & a];
source += 4;
dest += pitch;
} while (--count);
}
void DrawColumnRt1RevSubClampPalCommand::Execute(DrawerThread *thread)
{
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int pitch;
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
const uint32_t *fg2rgb = _srcblend;
const uint32_t *bg2rgb = _destblend;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4 + hx];
pitch = _pitch * thread->num_cores;
colormap = _colormap;
do {
uint32_t a = (bg2rgb[*dest] | 0x40100400) - fg2rgb[colormap[*source]];
uint32_t b = a;
b &= 0x40100400;
b = b - (b >> 5);
a &= b;
a |= 0x01f07c1f;
*dest = RGB32k.All[(a>>15) & a];
source += 4;
dest += pitch;
} while (--count);
}
void DrawColumnRt4RevSubClampPalCommand::Execute(DrawerThread *thread)
{
const uint8_t *colormap;
uint8_t *source;
uint8_t *dest;
int pitch;
int count = yh - yl + 1;
count = thread->count_for_thread(yl, count);
if (count <= 0)
return;
const uint32_t *fg2rgb = _srcblend;
const uint32_t *bg2rgb = _destblend;
dest = ylookup[yl + thread->skipped_by_thread(yl)] + sx + _destorg;
source = &thread->dc_temp[thread->temp_line_for_thread(yl)*4];
pitch = _pitch * thread->num_cores;
colormap = _colormap;
do {
uint32_t a = (bg2rgb[dest[0]] | 0x40100400) - fg2rgb[colormap[source[0]]];
uint32_t b = a;
b &= 0x40100400;
b = b - (b >> 5);
a &= b;
a |= 0x01f07c1f;
dest[0] = RGB32k.All[(a>>15) & a];
a = (bg2rgb[dest[1]] | 0x40100400) - fg2rgb[colormap[source[1]]];
b = a;
b &= 0x40100400;
b = b - (b >> 5);
a &= b;
a |= 0x01f07c1f;
dest[1] = RGB32k.All[(a>>15) & a];
a = (bg2rgb[dest[2]] | 0x40100400) - fg2rgb[colormap[source[2]]];
b = a;
b &= 0x40100400;
b = b - (b >> 5);
a &= b;
a |= 0x01f07c1f;
dest[2] = RGB32k.All[(a>>15) & a];
a = (bg2rgb[dest[3]] | 0x40100400) - fg2rgb[colormap[source[3]]];
b = a;
b &= 0x40100400;
b = b - (b >> 5);
a &= b;
a |= 0x01f07c1f;
dest[3] = RGB32k.All[(a>>15) & a];
source += 4;
dest += pitch;
} while (--count);
}
}

View file

@ -1,41 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Refresh (R_*) module, global header.
// All the rendering/drawing stuff is here.
//
//-----------------------------------------------------------------------------
#ifndef __R_LOCAL_H__
#define __R_LOCAL_H__
// Binary Angles, sine/cosine/atan lookups.
#include "tables.h"
// Screen size related parameters.
#include "doomdef.h"
// Include the refresh/render data structs.
//
// Separate header file for each module.
//
#include "r_main.h"
#include "r_things.h"
#include "r_draw.h"
#endif // __R_LOCAL_H__

File diff suppressed because it is too large Load diff

View file

@ -1,146 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// System specific interface stuff.
//
//-----------------------------------------------------------------------------
#ifndef __R_MAIN_H__
#define __R_MAIN_H__
#include "r_utility.h"
#include "d_player.h"
#include "v_palette.h"
#include "r_data/colormaps.h"
typedef BYTE lighttable_t; // This could be wider for >8 bit display.
//
// POV related.
//
extern bool bRenderingToCanvas;
extern double ViewCos;
extern double ViewSin;
extern fixed_t viewingrangerecip;
extern double FocalLengthX, FocalLengthY;
extern double InvZtoScale;
extern double WallTMapScale2;
extern int viewwindowx;
extern int viewwindowy;
extern double CenterX;
extern double CenterY;
extern double YaspectMul;
extern double IYaspectMul;
extern FDynamicColormap*basecolormap; // [RH] Colormap for sector currently being drawn
extern int linecount;
extern int loopcount;
extern bool r_dontmaplines;
//
// Lighting.
//
// [RH] This has changed significantly from Doom, which used lookup
// tables based on 1/z for walls and z for flats and only recognized
// 16 discrete light levels. The terminology I use is borrowed from Build.
//
// The size of a single colormap, in bits
#define COLORMAPSHIFT 8
// Convert a light level into an unbounded colormap index (shade). Result is
// fixed point. Why the +12? I wish I knew, but experimentation indicates it
// is necessary in order to best reproduce Doom's original lighting.
#define LIGHT2SHADE(l) ((NUMCOLORMAPS*2*FRACUNIT)-(((l)+12)*(FRACUNIT*NUMCOLORMAPS/128)))
// MAXLIGHTSCALE from original DOOM, divided by 2.
#define MAXLIGHTVIS (24.0)
// Convert a shade and visibility to a clamped colormap index.
// Result is not fixed point.
// Change R_CalcTiltedLighting() when this changes.
#define GETPALOOKUP(vis,shade) (clamp<int> (((shade)-FLOAT2FIXED(MIN(MAXLIGHTVIS,double(vis))))>>FRACBITS, 0, NUMCOLORMAPS-1))
extern double GlobVis;
void R_SetVisibility(double visibility);
double R_GetVisibility();
extern double r_BaseVisibility;
extern double r_WallVisibility;
extern double r_FloorVisibility;
extern float r_TiltVisibility;
extern double r_SpriteVisibility;
extern int r_actualextralight;
extern bool foggy;
extern int fixedlightlev;
extern lighttable_t* fixedcolormap;
extern FSpecialColormap*realfixedcolormap;
//
// Function pointers to switch refresh/drawing functions.
// Used to select shadow mode etc.
//
extern void (*colfunc) (void);
extern void (*basecolfunc) (void);
extern void (*fuzzcolfunc) (void);
extern void (*transcolfunc) (void);
// No shadow effects on floors.
extern void (*spanfunc) (void);
// [RH] Function pointers for the horizontal column drawers.
extern void (*hcolfunc_pre) (void);
extern void (*hcolfunc_post1) (int hx, int sx, int yl, int yh);
extern void (*hcolfunc_post2) (int hx, int sx, int yl, int yh);
extern void (*hcolfunc_post4) (int sx, int yl, int yh);
void R_InitTextureMapping ();
//
// REFRESH - the actual rendering functions.
//
// Called by G_Drawer.
void R_RenderActorView (AActor *actor, bool dontmaplines = false);
void R_SetupBuffer ();
void R_RenderViewToCanvas (AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines = false);
// [RH] Initialize multires stuff for renderer
void R_MultiresInit (void);
extern int stacked_extralight;
extern double stacked_visibility;
extern DVector3 stacked_viewpos;
extern DAngle stacked_angle;
extern void R_CopyStackedViewParameters();
#endif // __R_MAIN_H__

File diff suppressed because it is too large Load diff

View file

@ -1,117 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Refresh, visplane stuff (floor, ceilings).
//
//-----------------------------------------------------------------------------
#ifndef __R_PLANE_H__
#define __R_PLANE_H__
#include <stddef.h>
class ASkyViewpoint;
//
// The infamous visplane
//
struct visplane_s
{
struct visplane_s *next; // Next visplane in hash chain -- killough
secplane_t height;
FTextureID picnum;
int lightlevel;
fixed_t xoffs, yoffs; // killough 2/28/98: Support scrolling flats
int left, right;
FDynamicColormap *colormap; // [RH] Support multiple colormaps
fixed_t xscale, yscale; // [RH] Support flat scaling
angle_t angle; // [RH] Support flat rotation
int sky;
FSectorPortal *portal; // [RH] Support sky boxes
// [RH] This set of variables copies information from the time when the
// visplane is created. They are only used by stacks so that you can
// have stacked sectors inside a skybox. If the visplane is not for a
// stack, then they are unused.
int extralight;
double visibility;
DVector3 viewpos;
DAngle viewangle;
fixed_t Alpha;
bool Additive;
// kg3D - keep track of mirror and skybox owner
int CurrentSkybox;
int CurrentPortalUniq; // mirror counter, counts all of them
int MirrorFlags; // this is not related to CurrentMirror
unsigned short *bottom; // [RH] bottom and top arrays are dynamically
unsigned short pad; // allocated immediately after the
unsigned short top[]; // visplane.
};
typedef struct visplane_s visplane_t;
// Visplane related.
extern ptrdiff_t lastopening; // type short
typedef void (*planefunction_t) (int top, int bottom);
extern planefunction_t floorfunc;
extern planefunction_t ceilingfunc_t;
extern short floorclip[MAXWIDTH];
extern short ceilingclip[MAXWIDTH];
extern fixed_t yslope[MAXHEIGHT];
void R_InitPlanes ();
void R_DeinitPlanes ();
void R_ClearPlanes (bool fullclear);
int R_DrawPlanes ();
void R_DrawPortals ();
void R_DrawSkyPlane (visplane_t *pl);
void R_DrawNormalPlane (visplane_t *pl, fixed_t alpha, bool additive, bool masked);
void R_DrawTiltedPlane (visplane_t *pl, fixed_t alpha, bool additive, bool masked);
void R_MapVisPlane (visplane_t *pl, void (*mapfunc)(int y, int x1));
visplane_t *R_FindPlane
( const secplane_t &height,
FTextureID picnum,
int lightlevel,
double alpha,
bool additive,
const FTransform &xform,
int sky,
FSectorPortal *portal);
visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop);
// [RH] Added for multires support
bool R_PlaneInitData (void);
extern visplane_t* floorplane;
extern visplane_t* ceilingplane;
#endif // __R_PLANE_H__

View file

@ -53,14 +53,10 @@ struct FRenderer
virtual int GetMaxViewPitch(bool down) = 0; // return value is in plain degrees
virtual void OnModeSet () {}
virtual void ErrorCleanup () {}
virtual void ClearBuffer(int color) = 0;
virtual void SetClearColor(int color) = 0;
virtual void Init() = 0;
virtual void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio) {}
virtual void SetupFrame(player_t *player) {}
virtual void CopyStackedViewParameters() {}
virtual void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov) = 0;
virtual sector_t *FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel, bool back) = 0;
virtual sector_t *FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel) = 0;
virtual void SetFogParams(int _fogdensity, PalEntry _outsidefogcolor, int _outsidefogdensity, int _skyfog) {}
virtual void PreprocessLevel() {}
virtual void CleanLevelData() {}

File diff suppressed because it is too large Load diff

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