mirror of https://github.com/ZDoom/gzdoom.git
Merge branch 'make-qzdoom-gzdoom-again' of https://github.com/raa-eruanna/qzdoom into 3.0_work
# Conflicts: # src/win32/win32gliface.h # src/win32/win32iface.h This compiles but no guarantees otherwise.
This commit is contained in:
commit
cc1241a4b8
|
@ -47,3 +47,6 @@
|
|||
/build_vc2015-32
|
||||
/build_vc2015-64
|
||||
/build
|
||||
/llvm
|
||||
/src/r_drawersasm.obj
|
||||
/src/r_drawersasm.o
|
||||
|
|
|
@ -174,20 +174,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 )
|
||||
|
|
|
@ -692,6 +692,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 )
|
||||
|
@ -758,6 +759,19 @@ file( GLOB HEADER_FILES
|
|||
timidity/*.h
|
||||
wildmidi/*.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
|
||||
|
@ -792,19 +806,67 @@ set( NOT_COMPILED_SOURCE_FILES
|
|||
)
|
||||
|
||||
set( FASTMATH_PCH_SOURCES
|
||||
r_swrenderer.cpp
|
||||
r_3dfloors.cpp
|
||||
r_bsp.cpp
|
||||
r_draw.cpp
|
||||
r_draw_pal.cpp
|
||||
r_drawt_pal.cpp
|
||||
r_thread.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
|
||||
r_walldraw.cpp
|
||||
s_advsound.cpp
|
||||
s_environment.cpp
|
||||
s_playlist.cpp
|
||||
|
@ -956,6 +1018,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
|
||||
|
@ -1236,6 +1300,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS")
|
|||
endif()
|
||||
|
||||
target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma )
|
||||
|
||||
include_directories( .
|
||||
g_statusbar
|
||||
g_shared
|
||||
|
@ -1383,8 +1448,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/.+")
|
||||
|
|
|
@ -1932,7 +1932,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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
@ -697,8 +697,6 @@ void D_Display ()
|
|||
}
|
||||
}
|
||||
|
||||
RenderTarget = screen;
|
||||
|
||||
// change the view size if needed
|
||||
if (setsizeneeded && StatusBar != NULL)
|
||||
{
|
||||
|
@ -973,7 +971,6 @@ void D_ErrorCleanup ()
|
|||
menuactive = MENU_Off;
|
||||
}
|
||||
insave = false;
|
||||
Renderer->ErrorCleanup();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -359,6 +359,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:
|
||||
|
|
151
src/f_wipe.cpp
151
src/f_wipe.cpp
|
@ -28,6 +28,9 @@
|
|||
#include "f_wipe.h"
|
||||
#include "c_cvars.h"
|
||||
#include "templates.h"
|
||||
#include "v_palette.h"
|
||||
|
||||
EXTERN_CVAR(Bool, r_blendmethod)
|
||||
|
||||
//
|
||||
// SCREEN WIPE PACKAGE
|
||||
|
@ -280,39 +283,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);
|
||||
}
|
||||
|
||||
|
@ -347,19 +391,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;
|
||||
|
@ -382,6 +448,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)
|
||||
|
@ -395,11 +464,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);
|
||||
}
|
||||
|
@ -410,6 +483,9 @@ bool wipe_ScreenWipe (int ticks)
|
|||
{
|
||||
bool rc;
|
||||
|
||||
if (screen->IsBgra())
|
||||
return true;
|
||||
|
||||
if (CurrentWipeType == wipe_None)
|
||||
return true;
|
||||
|
||||
|
@ -423,6 +499,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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -79,5 +79,4 @@ struct FColormap
|
|||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vectors.h"
|
||||
|
||||
#define FX_ROCKET 0x00000001
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
|
17
src/p_pspr.h
17
src/p_pspr.h
|
@ -49,11 +49,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
|
||||
|
@ -77,11 +81,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 () {}
|
||||
|
|
|
@ -2038,11 +2038,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
|
||||
|
@ -2052,7 +2053,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
<? }
|
||||
}
|
||||
|
||||
?>
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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
|
|
@ -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];
|
||||
};
|
|
@ -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 ¢er1, float radius1, const Vec3f ¢er2, 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 ¢er, 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;
|
||||
}
|
|
@ -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 ¢er1, float radius1, const Vec3f ¢er2, float radius2);
|
||||
static OverlapResult sphere_aabb(const Vec3f ¢er, 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);
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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];
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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>> §orPortals)
|
||||
{
|
||||
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>> §orPortals)
|
||||
{
|
||||
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;
|
||||
}
|
|
@ -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>> §orPortals);
|
||||
|
||||
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>> §orPortals);
|
||||
TriVertex PlaneVertex(vertex_t *v1, double height, const UVTransform &transform);
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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();
|
||||
}
|
|
@ -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];
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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;
|
||||
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(uint16_t *tbl);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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() {}
|
||||
};
|
||||
|
|
|
@ -1,166 +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"
|
||||
|
||||
CVAR(Int, r_3dfloors, true, 0);
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
|
||||
// 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;
|
||||
|
||||
// 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 height = add->ZatPoint(ViewPos);
|
||||
if(height >= sec->CenterCeiling()) return;
|
||||
if(height <= sec->CenterFloor()) return;
|
||||
|
||||
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--;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
#ifndef SOFT_FAKE3D_H
|
||||
#define SOFT_FAKE3D_H
|
||||
|
||||
#include "p_3dfloors.h"
|
||||
|
||||
EXTERN_CVAR(Int, r_3dfloors);
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
|
||||
// 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;
|
||||
|
||||
// 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
|
1400
src/r_bsp.cpp
1400
src/r_bsp.cpp
File diff suppressed because it is too large
Load Diff
127
src/r_bsp.h
127
src/r_bsp.h
|
@ -1,127 +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"
|
||||
|
||||
EXTERN_CVAR (Bool, r_drawflat) // [RH] Don't texture segs?
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
|
||||
// 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);
|
||||
|
||||
// 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
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -59,7 +59,6 @@ enum
|
|||
SIL_BOTH
|
||||
};
|
||||
|
||||
namespace swrenderer { extern size_t MaxDrawSegs; }
|
||||
struct FDisplacement;
|
||||
|
||||
//
|
||||
|
|
1298
src/r_draw.cpp
1298
src/r_draw.cpp
File diff suppressed because it is too large
Load Diff
197
src/r_draw.h
197
src/r_draw.h
|
@ -1,197 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "r_defs.h"
|
||||
|
||||
EXTERN_CVAR(Bool, r_multithreaded);
|
||||
EXTERN_CVAR(Int, r_drawfuzz);
|
||||
EXTERN_CVAR(Bool, r_drawtrans);
|
||||
EXTERN_CVAR(Float, transsouls);
|
||||
EXTERN_CVAR(Int, r_columnmethod);
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
struct vissprite_t;
|
||||
|
||||
extern double dc_texturemid;
|
||||
|
||||
namespace drawerargs
|
||||
{
|
||||
extern int dc_pitch;
|
||||
extern lighttable_t *dc_colormap;
|
||||
extern int dc_x;
|
||||
extern int dc_yl;
|
||||
extern int dc_yh;
|
||||
extern fixed_t dc_iscale;
|
||||
extern fixed_t dc_texturefrac;
|
||||
extern uint32_t dc_textureheight;
|
||||
extern int dc_color;
|
||||
extern uint32_t dc_srccolor;
|
||||
extern uint32_t dc_srccolor_bgra;
|
||||
extern uint32_t *dc_srcblend;
|
||||
extern uint32_t *dc_destblend;
|
||||
extern fixed_t dc_srcalpha;
|
||||
extern fixed_t dc_destalpha;
|
||||
extern const uint8_t *dc_source;
|
||||
extern const uint8_t *dc_source2;
|
||||
extern uint32_t dc_texturefracx;
|
||||
extern uint8_t *dc_translation;
|
||||
extern uint8_t *dc_dest;
|
||||
extern uint8_t *dc_destorg;
|
||||
extern int dc_destheight;
|
||||
extern int dc_count;
|
||||
|
||||
extern uint32_t dc_wall_texturefrac[4];
|
||||
extern uint32_t dc_wall_iscale[4];
|
||||
extern uint8_t *dc_wall_colormap[4];
|
||||
extern fixed_t dc_wall_light[4];
|
||||
extern const uint8_t *dc_wall_source[4];
|
||||
extern const uint8_t *dc_wall_source2[4];
|
||||
extern uint32_t dc_wall_texturefracx[4];
|
||||
extern uint32_t dc_wall_sourceheight[4];
|
||||
extern int dc_wall_fracbits;
|
||||
|
||||
extern int ds_y;
|
||||
extern int ds_x1;
|
||||
extern int ds_x2;
|
||||
extern lighttable_t * ds_colormap;
|
||||
extern dsfixed_t ds_light;
|
||||
extern dsfixed_t ds_xfrac;
|
||||
extern dsfixed_t ds_yfrac;
|
||||
extern dsfixed_t ds_xstep;
|
||||
extern dsfixed_t ds_ystep;
|
||||
extern int ds_xbits;
|
||||
extern int ds_ybits;
|
||||
extern fixed_t ds_alpha;
|
||||
extern double ds_lod;
|
||||
extern const uint8_t *ds_source;
|
||||
extern int ds_color;
|
||||
|
||||
extern unsigned int dc_tspans[4][MAXHEIGHT];
|
||||
extern unsigned int *dc_ctspan[4];
|
||||
extern unsigned int *horizspan[4];
|
||||
}
|
||||
|
||||
extern int ylookup[MAXHEIGHT];
|
||||
extern uint8_t shadetables[/*NUMCOLORMAPS*16*256*/];
|
||||
extern FDynamicColormap ShadeFakeColormap[16];
|
||||
extern uint8_t identitymap[256];
|
||||
extern FDynamicColormap identitycolormap;
|
||||
|
||||
// Spectre/Invisibility.
|
||||
#define FUZZTABLE 50
|
||||
extern int fuzzoffset[FUZZTABLE + 1];
|
||||
extern int fuzzpos;
|
||||
extern int fuzzviewheight;
|
||||
|
||||
void R_InitColumnDrawers();
|
||||
void R_InitShadeMaps();
|
||||
void R_InitFuzzTable(int fuzzoff);
|
||||
|
||||
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, uint32_t color);
|
||||
ESPSResult R_SetPatchStyle(FRenderStyle style, float alpha, int translation, uint32_t color);
|
||||
void R_FinishSetPatchStyle(); // Call this after finished drawing the current thing, in case its style was STYLE_Shade
|
||||
bool R_GetTransMaskDrawers(void(**drawCol1)(), void(**drawCol4)());
|
||||
|
||||
const uint8_t *R_GetColumn(FTexture *tex, int col);
|
||||
|
||||
void rt_initcols(uint8_t *buffer = nullptr);
|
||||
void rt_span_coverage(int x, int start, int stop);
|
||||
void rt_draw4cols(int sx);
|
||||
void rt_flip_posts();
|
||||
void rt_copy1col(int hx, int sx, int yl, int yh);
|
||||
void rt_copy4cols(int sx, int yl, int yh);
|
||||
void rt_shaded1col(int hx, int sx, int yl, int yh);
|
||||
void rt_shaded4cols(int sx, int yl, int yh);
|
||||
void rt_map1col(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(int sx, int yl, int yh);
|
||||
void rt_add4cols(int sx, int yl, int yh);
|
||||
void rt_addclamp4cols(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 R_DrawColumnHoriz();
|
||||
void R_DrawColumn();
|
||||
void R_DrawFuzzColumn();
|
||||
void R_DrawTranslatedColumn();
|
||||
void R_DrawShadedColumn();
|
||||
void R_FillColumn();
|
||||
void R_FillAddColumn();
|
||||
void R_FillAddClampColumn();
|
||||
void R_FillSubClampColumn();
|
||||
void R_FillRevSubClampColumn();
|
||||
void R_DrawAddColumn();
|
||||
void R_DrawTlatedAddColumn();
|
||||
void R_DrawAddClampColumn();
|
||||
void R_DrawAddClampTranslatedColumn();
|
||||
void R_DrawSubClampColumn();
|
||||
void R_DrawSubClampTranslatedColumn();
|
||||
void R_DrawRevSubClampColumn();
|
||||
void R_DrawRevSubClampTranslatedColumn();
|
||||
void R_DrawSpan();
|
||||
void R_DrawSpanMasked();
|
||||
void R_DrawSpanTranslucent();
|
||||
void R_DrawSpanMaskedTranslucent();
|
||||
void R_DrawSpanAddClamp();
|
||||
void R_DrawSpanMaskedAddClamp();
|
||||
void R_FillSpan();
|
||||
void R_DrawTiltedSpan(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 R_DrawColoredSpan(int y, int x1, int x2);
|
||||
void R_SetupDrawSlab(uint8_t *colormap);
|
||||
void R_DrawSlab(int dx, fixed_t v, int dy, fixed_t vi, const uint8_t *vptr, uint8_t *p);
|
||||
void R_DrawFogBoundary(int x1, int x2, short *uclip, short *dclip);
|
||||
void R_FillColumnHoriz();
|
||||
void R_FillSpan();
|
||||
|
||||
void R_DrawWallCol1();
|
||||
void R_DrawWallCol4();
|
||||
void R_DrawWallMaskedCol1();
|
||||
void R_DrawWallMaskedCol4();
|
||||
void R_DrawWallAddCol1();
|
||||
void R_DrawWallAddCol4();
|
||||
void R_DrawWallAddClampCol1();
|
||||
void R_DrawWallAddClampCol4();
|
||||
void R_DrawWallSubClampCol1();
|
||||
void R_DrawWallSubClampCol4();
|
||||
void R_DrawWallRevSubClampCol1();
|
||||
void R_DrawWallRevSubClampCol4();
|
||||
|
||||
void R_DrawSingleSkyCol1(uint32_t solid_top, uint32_t solid_bottom);
|
||||
void R_DrawSingleSkyCol4(uint32_t solid_top, uint32_t solid_bottom);
|
||||
void R_DrawDoubleSkyCol1(uint32_t solid_top, uint32_t solid_bottom);
|
||||
void R_DrawDoubleSkyCol4(uint32_t solid_top, uint32_t solid_bottom);
|
||||
|
||||
void R_SetColorMapLight(lighttable_t *base_colormap, float light, int shade);
|
||||
void R_SetColorMapLight(FDynamicColormap *base_colormap, float light, int shade);
|
||||
void R_SetDSColorMapLight(lighttable_t *base_colormap, float light, int shade);
|
||||
void R_SetDSColorMapLight(FDynamicColormap *base_colormap, float light, int shade);
|
||||
void R_SetTranslationMap(lighttable_t *translation);
|
||||
|
||||
void R_SetupSpanBits(FTexture *tex);
|
||||
void R_SetSpanColormap(lighttable_t *colormap);
|
||||
void R_SetSpanSource(FTexture *tex);
|
||||
|
||||
void R_MapTiltedPlane(int y, int x1);
|
||||
void R_MapColoredPlane(int y, int x1);
|
||||
void R_DrawParticle(vissprite_t *);
|
||||
}
|
2622
src/r_draw_pal.cpp
2622
src/r_draw_pal.cpp
File diff suppressed because it is too large
Load Diff
329
src/r_draw_pal.h
329
src/r_draw_pal.h
|
@ -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; };
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,40 +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.
|
||||
|
||||
// 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__
|
1077
src/r_main.cpp
1077
src/r_main.cpp
File diff suppressed because it is too large
Load Diff
153
src/r_main.h
153
src/r_main.h
|
@ -1,153 +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"
|
||||
|
||||
extern double ViewCos;
|
||||
extern double ViewSin;
|
||||
extern int viewwindowx;
|
||||
extern int viewwindowy;
|
||||
|
||||
typedef BYTE lighttable_t; // This could be wider for >8 bit display.
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
|
||||
//
|
||||
// POV related.
|
||||
//
|
||||
extern bool bRenderingToCanvas;
|
||||
extern fixed_t viewingrangerecip;
|
||||
extern double FocalLengthX, FocalLengthY;
|
||||
extern double InvZtoScale;
|
||||
|
||||
extern double WallTMapScale2;
|
||||
|
||||
|
||||
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))
|
||||
|
||||
// Converts fixedlightlev into a shade value
|
||||
#define FIXEDLIGHT2SHADE(lightlev) (((lightlev) >> COLORMAPSHIFT) << FRACBITS)
|
||||
|
||||
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__
|
1789
src/r_plane.cpp
1789
src/r_plane.cpp
File diff suppressed because it is too large
Load Diff
119
src/r_plane.h
119
src/r_plane.h
|
@ -1,119 +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>
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
|
||||
//
|
||||
// The infamous visplane
|
||||
//
|
||||
struct visplane_s
|
||||
{
|
||||
struct visplane_s *next; // Next visplane in hash chain -- killough
|
||||
|
||||
FDynamicColormap *colormap; // [RH] Support multiple colormaps
|
||||
FSectorPortal *portal; // [RH] Support sky boxes
|
||||
|
||||
FTransform xform;
|
||||
secplane_t height;
|
||||
FTextureID picnum;
|
||||
int lightlevel;
|
||||
int left, right;
|
||||
int sky;
|
||||
|
||||
// [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 float 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, double xscale, double yscale, fixed_t alpha, bool additive, bool masked);
|
||||
void R_DrawTiltedPlane (visplane_t *pl, double xscale, double yscale, 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__
|
|
@ -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() {}
|
||||
|
|
2410
src/r_segs.cpp
2410
src/r_segs.cpp
File diff suppressed because it is too large
Load Diff
83
src/r_segs.h
83
src/r_segs.h
|
@ -1,83 +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, drawing LineSegs from BSP.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __R_SEGS_H__
|
||||
#define __R_SEGS_H__
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
|
||||
struct drawseg_t;
|
||||
|
||||
void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2);
|
||||
|
||||
extern short *openings;
|
||||
extern ptrdiff_t lastopening;
|
||||
extern size_t maxopenings;
|
||||
|
||||
int R_CreateWallSegmentY (short *outbuf, double z1, double z2, const FWallCoords *wallc);
|
||||
int R_CreateWallSegmentYSloped (short *outbuf, const secplane_t &plane, const FWallCoords *wallc);
|
||||
inline int R_CreateWallSegmentY(short *outbuf, double z, const FWallCoords *wallc)
|
||||
{
|
||||
return R_CreateWallSegmentY(outbuf, z, z, wallc);
|
||||
}
|
||||
|
||||
void PrepWall (float *swall, fixed_t *lwall, double walxrepeat, int x1, int x2);
|
||||
void PrepLWall (fixed_t *lwall, double walxrepeat, int x1, int x2);
|
||||
|
||||
ptrdiff_t R_NewOpening (ptrdiff_t len);
|
||||
|
||||
void R_CheckDrawSegs ();
|
||||
|
||||
void R_RenderSegLoop ();
|
||||
|
||||
extern float swall[MAXWIDTH];
|
||||
extern fixed_t lwall[MAXWIDTH];
|
||||
extern float rw_light; // [RH] Scale lights with viewsize adjustments
|
||||
extern float rw_lightstep;
|
||||
extern float rw_lightleft;
|
||||
extern fixed_t rw_offset;
|
||||
|
||||
/* portal structure, this is used in r_ code in order to store drawsegs with portals (and mirrors) */
|
||||
struct PortalDrawseg
|
||||
{
|
||||
line_t* src; // source line (the one drawn) this doesn't change over render loops
|
||||
line_t* dst; // destination line (the one that the portal is linked with, equals 'src' for mirrors)
|
||||
|
||||
int x1; // drawseg x1
|
||||
int x2; // drawseg x2
|
||||
|
||||
int len;
|
||||
TArray<short> ceilingclip;
|
||||
TArray<short> floorclip;
|
||||
|
||||
bool mirror; // true if this is a mirror (src should equal dst)
|
||||
};
|
||||
|
||||
extern PortalDrawseg* CurrentPortal;
|
||||
extern int CurrentPortalUniq;
|
||||
extern bool CurrentPortalInSkybox;
|
||||
extern TArray<PortalDrawseg> WallPortals;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -68,7 +68,6 @@ extern int numgamesubsectors;
|
|||
extern AActor* camera; // [RH] camera instead of viewplayer
|
||||
extern sector_t* viewsector; // [RH] keep track of sector viewing from
|
||||
|
||||
namespace swrenderer { extern angle_t xtoviewangle[MAXWIDTH+1]; }
|
||||
extern DAngle FieldOfView;
|
||||
|
||||
int R_FindSkin (const char *name, int pclass); // [RH] Find a skin
|
||||
|
|
|
@ -1,357 +0,0 @@
|
|||
/*
|
||||
** r_swrender.cpp
|
||||
** Software renderer interface
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2011 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#include "r_local.h"
|
||||
#include "v_palette.h"
|
||||
#include "v_video.h"
|
||||
#include "m_png.h"
|
||||
#include "r_bsp.h"
|
||||
#include "r_swrenderer.h"
|
||||
#include "r_3dfloors.h"
|
||||
#include "textures/textures.h"
|
||||
#include "r_data/voxels.h"
|
||||
#include "r_thread.h"
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
|
||||
void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio);
|
||||
void R_SetupColormap(player_t *);
|
||||
void R_SetupFreelook();
|
||||
void R_InitRenderer();
|
||||
|
||||
}
|
||||
|
||||
using namespace swrenderer;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas :: Init
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FSoftwareRenderer::Init()
|
||||
{
|
||||
R_InitRenderer();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas :: UsesColormap
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FSoftwareRenderer::UsesColormap() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Texture precaching
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FSoftwareRenderer::PrecacheTexture(FTexture *tex, int cache)
|
||||
{
|
||||
if (tex != NULL)
|
||||
{
|
||||
if (cache & FTextureManager::HIT_Columnmode)
|
||||
{
|
||||
const FTexture::Span *spanp;
|
||||
tex->GetColumn(0, &spanp);
|
||||
}
|
||||
else if (cache != 0)
|
||||
{
|
||||
tex->GetPixels ();
|
||||
}
|
||||
else
|
||||
{
|
||||
tex->Unload ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FSoftwareRenderer::Precache(BYTE *texhitlist, TMap<PClassActor*, bool> &actorhitlist)
|
||||
{
|
||||
BYTE *spritelist = new BYTE[sprites.Size()];
|
||||
TMap<PClassActor*, bool>::Iterator it(actorhitlist);
|
||||
TMap<PClassActor*, bool>::Pair *pair;
|
||||
|
||||
memset(spritelist, 0, sprites.Size());
|
||||
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
PClassActor *cls = pair->Key;
|
||||
|
||||
for (int i = 0; i < cls->NumOwnedStates; i++)
|
||||
{
|
||||
spritelist[cls->OwnedStates[i].sprite] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Precache textures (and sprites).
|
||||
|
||||
for (int i = (int)(sprites.Size() - 1); i >= 0; i--)
|
||||
{
|
||||
if (spritelist[i])
|
||||
{
|
||||
int j, k;
|
||||
for (j = 0; j < sprites[i].numframes; j++)
|
||||
{
|
||||
const spriteframe_t *frame = &SpriteFrames[sprites[i].spriteframes + j];
|
||||
|
||||
for (k = 0; k < 16; k++)
|
||||
{
|
||||
FTextureID pic = frame->Texture[k];
|
||||
if (pic.isValid())
|
||||
{
|
||||
texhitlist[pic.GetIndex()] = FTextureManager::HIT_Sprite;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] spritelist;
|
||||
|
||||
int cnt = TexMan.NumTextures();
|
||||
for (int i = cnt - 1; i >= 0; i--)
|
||||
{
|
||||
PrecacheTexture(TexMan.ByIndex(i), texhitlist[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Render the view
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FSoftwareRenderer::RenderView(player_t *player)
|
||||
{
|
||||
R_BeginDrawerCommands();
|
||||
R_RenderActorView (player->mo);
|
||||
// [RH] Let cameras draw onto textures that were visible this frame.
|
||||
FCanvasTextureInfo::UpdateAll ();
|
||||
R_EndDrawerCommands();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FSoftwareRenderer::RemapVoxels()
|
||||
{
|
||||
for (unsigned i=0; i<Voxels.Size(); i++)
|
||||
{
|
||||
Voxels[i]->Remap();
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Render the view to a savegame picture
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FSoftwareRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, int height)
|
||||
{
|
||||
DCanvas *pic = new DSimpleCanvas (width, height);
|
||||
PalEntry palette[256];
|
||||
|
||||
// Take a snapshot of the player's view
|
||||
pic->ObjectFlags |= OF_Fixed;
|
||||
pic->Lock ();
|
||||
R_RenderViewToCanvas (player->mo, pic, 0, 0, width, height);
|
||||
screen->GetFlashedPalette (palette);
|
||||
M_CreatePNG (file, pic->GetBuffer(), palette, SS_PAL, width, height, pic->GetPitch());
|
||||
pic->Unlock ();
|
||||
pic->Destroy();
|
||||
pic->ObjectFlags |= OF_YesReallyDelete;
|
||||
delete pic;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FSoftwareRenderer::DrawRemainingPlayerSprites()
|
||||
{
|
||||
R_DrawRemainingPlayerSprites();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Get max. view angle (renderer specific information so it goes here now)
|
||||
//
|
||||
//===========================================================================
|
||||
#define MAX_DN_ANGLE 56 // Max looking down angle
|
||||
#define MAX_UP_ANGLE 32 // Max looking up angle
|
||||
|
||||
int FSoftwareRenderer::GetMaxViewPitch(bool down)
|
||||
{
|
||||
return down ? MAX_DN_ANGLE : MAX_UP_ANGLE;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OnModeSet
|
||||
//
|
||||
// Called from V_SetResolution()
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FSoftwareRenderer::OnModeSet ()
|
||||
{
|
||||
R_MultiresInit ();
|
||||
|
||||
RenderTarget = screen;
|
||||
screen->Lock (true);
|
||||
R_SetupBuffer ();
|
||||
screen->Unlock ();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FSoftwareRenderer::ErrorCleanup ()
|
||||
{
|
||||
fakeActive = 0;
|
||||
fake3D = 0;
|
||||
while (CurrentSkybox)
|
||||
{
|
||||
R_3D_DeleteHeights();
|
||||
R_3D_LeaveSkybox();
|
||||
}
|
||||
R_3D_ResetClip();
|
||||
R_3D_DeleteHeights();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FSoftwareRenderer::ClearBuffer(int color)
|
||||
{
|
||||
memset(RenderTarget->GetBuffer(), color, RenderTarget->GetPitch() * RenderTarget->GetHeight());
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FSoftwareRenderer::SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio)
|
||||
{
|
||||
R_SWRSetWindow(windowSize, fullWidth, fullHeight, stHeight, trueratio);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FSoftwareRenderer::SetupFrame(player_t *player)
|
||||
{
|
||||
R_SetupColormap(player);
|
||||
R_SetupFreelook();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_CopyStackedViewParameters
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FSoftwareRenderer::CopyStackedViewParameters()
|
||||
{
|
||||
R_CopyStackedViewParameters();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov)
|
||||
{
|
||||
BYTE *Pixels = const_cast<BYTE*>(tex->GetPixels());
|
||||
DSimpleCanvas *Canvas = tex->GetCanvas();
|
||||
|
||||
// curse Doom's overuse of global variables in the renderer.
|
||||
// These get clobbered by rendering to a camera texture but they need to be preserved so the final rendering can be done with the correct palette.
|
||||
unsigned char *savecolormap = fixedcolormap;
|
||||
FSpecialColormap *savecm = realfixedcolormap;
|
||||
|
||||
DAngle savedfov = FieldOfView;
|
||||
R_SetFOV ((double)fov);
|
||||
R_RenderViewToCanvas (viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), tex->bFirstUpdate);
|
||||
R_SetFOV (savedfov);
|
||||
if (Pixels == Canvas->GetBuffer())
|
||||
{
|
||||
FTexture::FlipSquareBlockRemap (Pixels, tex->GetWidth(), tex->GetHeight(), GPalette.Remap);
|
||||
}
|
||||
else
|
||||
{
|
||||
FTexture::FlipNonSquareBlockRemap (Pixels, Canvas->GetBuffer(), tex->GetWidth(), tex->GetHeight(), Canvas->GetPitch(), GPalette.Remap);
|
||||
}
|
||||
tex->SetUpdated();
|
||||
fixedcolormap = savecolormap;
|
||||
realfixedcolormap = savecm;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
sector_t *FSoftwareRenderer::FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel, bool back)
|
||||
{
|
||||
return R_FakeFlat(sec, tempsec, floorlightlevel, ceilinglightlevel, back);
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#ifndef __R_SWRENDERER_H
|
||||
#define __R_SWRENDERER_H
|
||||
|
||||
#include "r_renderer.h"
|
||||
|
||||
struct FSoftwareRenderer : public FRenderer
|
||||
{
|
||||
// Can be overridden so that the colormaps for sector color/fade won't be built.
|
||||
virtual bool UsesColormap() const override;
|
||||
|
||||
// precache one texture
|
||||
void PrecacheTexture(FTexture *tex, int cache);
|
||||
virtual void Precache(BYTE *texhitlist, TMap<PClassActor*, bool> &actorhitlist) override;
|
||||
|
||||
// render 3D view
|
||||
virtual void RenderView(player_t *player) override;
|
||||
|
||||
// Remap voxel palette
|
||||
virtual void RemapVoxels() override;
|
||||
|
||||
// renders view to a savegame picture
|
||||
virtual void WriteSavePic (player_t *player, FileWriter *file, int width, int height) override;
|
||||
|
||||
// draws player sprites with hardware acceleration (only useful for software rendering)
|
||||
virtual void DrawRemainingPlayerSprites() override;
|
||||
|
||||
virtual int GetMaxViewPitch(bool down) override;
|
||||
|
||||
void OnModeSet () override;
|
||||
void ErrorCleanup () override;
|
||||
void ClearBuffer(int color) override;
|
||||
void Init() override;
|
||||
void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio) override;
|
||||
void SetupFrame(player_t *player) override;
|
||||
void CopyStackedViewParameters() override;
|
||||
void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov) override;
|
||||
sector_t *FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel, bool back) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
3263
src/r_things.cpp
3263
src/r_things.cpp
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
Loading…
Reference in New Issue