mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-01-30 20:41:00 +00:00
Merge branch 'master' into edf-gl
This commit is contained in:
commit
76b0971067
688 changed files with 82349 additions and 2381 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -7,6 +7,7 @@
|
|||
/Release
|
||||
/wadsrc_wad
|
||||
*.user
|
||||
/build
|
||||
/debug
|
||||
/release
|
||||
*/debug
|
||||
|
@ -37,3 +38,6 @@
|
|||
/jpeg-6b/x64/
|
||||
/lzma/x64/
|
||||
/zlib/x64/
|
||||
/build_vc2013_64bit
|
||||
/build_vc2015
|
||||
build_cmake
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
cmake_minimum_required( VERSION 2.4 )
|
||||
project(ZDoom)
|
||||
project(GZDoom)
|
||||
|
||||
if( COMMAND cmake_policy )
|
||||
if( POLICY CMP0011 )
|
||||
|
@ -78,7 +78,7 @@ IF( NOT CMAKE_BUILD_TYPE )
|
|||
ENDIF( NOT CMAKE_BUILD_TYPE )
|
||||
|
||||
set( ZDOOM_OUTPUT_DIR ${CMAKE_BINARY_DIR} CACHE PATH "Directory where zdoom.pk3 and the executable will be created." )
|
||||
set( ZDOOM_EXE_NAME "zdoom" CACHE FILEPATH "Name of the executable to create." )
|
||||
set( ZDOOM_EXE_NAME "gzdoom" CACHE FILEPATH "Name of the executable to create" )
|
||||
if( MSVC )
|
||||
# Allow the user to use ZDOOM_OUTPUT_DIR as a single release point.
|
||||
# Use zdoom, zdoomd, zdoom64, and zdoomd64 for the binary names
|
||||
|
@ -113,7 +113,7 @@ find_package( BZip2 )
|
|||
find_package( JPEG )
|
||||
find_package( ZLIB )
|
||||
# GME
|
||||
find_path( GME_INCLUDE_DIR gme.h )
|
||||
find_path( GME_INCLUDE_DIR gme/gme.h )
|
||||
find_library( GME_LIBRARIES gme )
|
||||
mark_as_advanced( GME_INCLUDE_DIR GME_LIBRARIES )
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS( GME
|
||||
|
@ -128,7 +128,8 @@ if( MSVC )
|
|||
# String pooling
|
||||
# Function-level linking
|
||||
# Disable run-time type information
|
||||
set( ALL_C_FLAGS "/GF /Gy /GR-" )
|
||||
# Set floating point model to fast or the GL render will suffer for it.
|
||||
set( ALL_C_FLAGS "/GF /Gy /GR- /fp:fast" )
|
||||
|
||||
if( CMAKE_SIZEOF_VOID_P MATCHES "4")
|
||||
# SSE2 option (mostly to switch it off in VC2012 and later where it's the default
|
||||
|
@ -250,6 +251,8 @@ add_subdirectory( tools )
|
|||
add_subdirectory( dumb )
|
||||
add_subdirectory( gdtoa )
|
||||
add_subdirectory( wadsrc )
|
||||
add_subdirectory( wadsrc_bm )
|
||||
add_subdirectory( wadsrc_lights )
|
||||
add_subdirectory( src )
|
||||
|
||||
if( NOT WIN32 AND NOT APPLE )
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Version="9,00"
|
||||
Name="bzip2"
|
||||
ProjectGUID="{A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}"
|
||||
RootNamespace="bzip2"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Version="9,00"
|
||||
Name="game-music-emu"
|
||||
ProjectGUID="{9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}"
|
||||
RootNamespace="gamemusicemu"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
|
@ -326,6 +327,8 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
|
@ -345,9 +348,6 @@
|
|||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
|
@ -402,6 +402,8 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
|
@ -422,9 +424,6 @@
|
|||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
|
@ -602,10 +601,6 @@
|
|||
RelativePath=".\gme\Spc_Emu.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gme\Spc_Filter.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gme\Vgm_Emu.cpp"
|
||||
>
|
||||
|
@ -708,10 +703,6 @@
|
|||
RelativePath=".\gme\Gme_File.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gme\gme_types.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gme\Gym_Emu.h"
|
||||
>
|
||||
|
@ -832,10 +823,6 @@
|
|||
RelativePath=".\gme\Spc_Emu.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gme\Spc_Filter.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gme\Vgm_Emu.h"
|
||||
>
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Version="9,00"
|
||||
Name="gdtoa"
|
||||
ProjectGUID="{B68E0ABF-B627-48A3-A92F-D8F827A75054}"
|
||||
RootNamespace="gdtoa"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Version="9,00"
|
||||
Name="jpeg-6b"
|
||||
ProjectGUID="{AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}"
|
||||
RootNamespace="jpeg6b"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
|
|
|
@ -9,6 +9,7 @@ include( CheckFunctionExists )
|
|||
include( CheckCXXCompilerFlag )
|
||||
include( CheckLibraryExists )
|
||||
include( FindPkgConfig )
|
||||
include( FindOpenGL )
|
||||
|
||||
if( NOT APPLE )
|
||||
option( NO_ASM "Disable assembly code" OFF )
|
||||
|
@ -213,6 +214,18 @@ else( WIN32 )
|
|||
endif( FPU_CONTROL_DIR )
|
||||
endif( WIN32 )
|
||||
|
||||
if( X64 )
|
||||
set( NO_ASM ON )
|
||||
endif( X64 )
|
||||
|
||||
# Check if we have OpenGL
|
||||
|
||||
if( NOT OPENGL_FOUND )
|
||||
message( FATAL_ERROR "OpenGL is required for building." )
|
||||
endif( NOT OPENGL_FOUND )
|
||||
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} ${OPENGL_LIBRARIES} )
|
||||
include_directories( ${OPENGL_INCLUDE_DIR} )
|
||||
|
||||
if( NOT NO_OPENAL )
|
||||
find_package( OpenAL )
|
||||
|
@ -437,6 +450,22 @@ else( SSE_MATTERS )
|
|||
set( BACKPATCH 0 )
|
||||
endif( SSE_MATTERS )
|
||||
|
||||
if( X64 )
|
||||
set( HAVE_MMX 1 )
|
||||
else( X64 )
|
||||
set( SAFE_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} )
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmmx")
|
||||
endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
|
||||
CHECK_CXX_SOURCE_COMPILES("#include <mmintrin.h>
|
||||
int main(void) { __m64 v = _m_from_int(0); }"
|
||||
HAVE_MMX)
|
||||
|
||||
set( CMAKE_CXX_FLAGS ${SAFE_CMAKE_CXX_FLAGS} )
|
||||
endif( X64 )
|
||||
|
||||
# Set up flags for GCC
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
|
@ -587,6 +616,7 @@ set( PLAT_WIN32_SOURCES
|
|||
win32/i_movie.cpp
|
||||
win32/i_system.cpp
|
||||
win32/st_start.cpp
|
||||
win32/win32gliface.cpp
|
||||
win32/win32video.cpp )
|
||||
set( PLAT_POSIX_SOURCES
|
||||
posix/i_cd.cpp
|
||||
|
@ -602,7 +632,8 @@ set( PLAT_SDL_SOURCES
|
|||
posix/sdl/i_joystick.cpp
|
||||
posix/sdl/i_main.cpp
|
||||
posix/sdl/i_timer.cpp
|
||||
posix/sdl/sdlvideo.cpp )
|
||||
posix/sdl/sdlvideo.cpp
|
||||
posix/sdl/sdlglvideo.cpp )
|
||||
set( PLAT_OSX_SOURCES
|
||||
posix/osx/iwadpicker_cocoa.mm
|
||||
posix/osx/zdoom.icns )
|
||||
|
@ -650,6 +681,25 @@ else( WIN32 )
|
|||
set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} )
|
||||
endif( WIN32 )
|
||||
|
||||
if( HAVE_MMX )
|
||||
add_definitions( -DHAVE_MMX=1 )
|
||||
|
||||
set( SYSTEM_SOURCES ${SYSTEM_SOURCES}
|
||||
gl/hqnx_asm/hq2x_asm.cpp
|
||||
gl/hqnx_asm/hq3x_asm.cpp
|
||||
gl/hqnx_asm/hq4x_asm.cpp
|
||||
gl/hqnx_asm/hqnx_asm_Image.cpp)
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
set_source_files_properties(
|
||||
gl/hqnx_asm/hq2x_asm.cpp
|
||||
gl/hqnx_asm/hq3x_asm.cpp
|
||||
gl/hqnx_asm/hq4x_asm.cpp
|
||||
gl/textures/gl_hqresize.cpp
|
||||
PROPERTIES COMPILE_FLAGS "-mmmx" )
|
||||
endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
endif( HAVE_MMX )
|
||||
|
||||
if( NOT ASM_SOURCES )
|
||||
set( ASM_SOURCES "" )
|
||||
endif( NOT ASM_SOURCES )
|
||||
|
@ -740,6 +790,20 @@ file( GLOB HEADER_FILES
|
|||
textures/*.h
|
||||
thingdef/*.h
|
||||
xlat/*.h
|
||||
gl/*.h
|
||||
gl/api/*.h
|
||||
gl/data/*.h
|
||||
gl/dynlights/*.h
|
||||
gl/hqnx/*.h
|
||||
gl/hqnx_asm/*.h
|
||||
gl/models/*.h
|
||||
gl/renderer/*.h
|
||||
gl/scene/*.h
|
||||
gl/stereo3d/*.h
|
||||
gl/shaders/*.h
|
||||
gl/system/*.h
|
||||
gl/textures/*.h
|
||||
gl/utility/*.h
|
||||
*.h
|
||||
)
|
||||
|
||||
|
@ -1056,6 +1120,68 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
|
|||
menu/playermenu.cpp
|
||||
menu/readthis.cpp
|
||||
menu/videomenu.cpp
|
||||
gl/data/gl_data.cpp
|
||||
gl/data/gl_portaldata.cpp
|
||||
gl/data/gl_setup.cpp
|
||||
gl/data/gl_matrix.cpp
|
||||
gl/data/gl_vertexbuffer.cpp
|
||||
gl/dynlights/a_dynlight.cpp
|
||||
gl/utility/gl_clock.cpp
|
||||
gl/utility/gl_cycler.cpp
|
||||
gl/utility/gl_geometric.cpp
|
||||
gl/renderer/gl_renderer.cpp
|
||||
gl/renderer/gl_renderstate.cpp
|
||||
gl/renderer/gl_lightdata.cpp
|
||||
gl/hqnx/init.cpp
|
||||
gl/hqnx/hq2x.cpp
|
||||
gl/hqnx/hq3x.cpp
|
||||
gl/hqnx/hq4x.cpp
|
||||
gl/textures/gl_hwtexture.cpp
|
||||
gl/textures/gl_texture.cpp
|
||||
gl/textures/gl_material.cpp
|
||||
gl/textures/gl_hirestex.cpp
|
||||
gl/textures/gl_bitmap.cpp
|
||||
gl/textures/gl_samplers.cpp
|
||||
gl/textures/gl_translate.cpp
|
||||
gl/textures/gl_hqresize.cpp
|
||||
gl/textures/gl_skyboxtexture.cpp
|
||||
gl/scene/gl_bsp.cpp
|
||||
gl/scene/gl_fakeflat.cpp
|
||||
gl/scene/gl_clipper.cpp
|
||||
gl/scene/gl_decal.cpp
|
||||
gl/scene/gl_drawinfo.cpp
|
||||
gl/scene/gl_flats.cpp
|
||||
gl/scene/gl_walls.cpp
|
||||
gl/scene/gl_sprite.cpp
|
||||
gl/scene/gl_skydome.cpp
|
||||
gl/scene/gl_renderhacks.cpp
|
||||
gl/scene/gl_weapon.cpp
|
||||
gl/scene/gl_scene.cpp
|
||||
gl/scene/gl_sky.cpp
|
||||
gl/scene/gl_portal.cpp
|
||||
gl/scene/gl_walls_draw.cpp
|
||||
gl/scene/gl_vertex.cpp
|
||||
gl/scene/gl_spritelight.cpp
|
||||
gl/stereo3d/gl_stereo3d.cpp
|
||||
gl/stereo3d/gl_stereo_cvars.cpp
|
||||
gl/stereo3d/gl_stereo_leftright.cpp
|
||||
gl/stereo3d/scoped_view_shifter.cpp
|
||||
gl/stereo3d/gl_anaglyph.cpp
|
||||
gl/dynlights/gl_dynlight.cpp
|
||||
gl/dynlights/gl_glow.cpp
|
||||
gl/dynlights/gl_dynlight1.cpp
|
||||
gl/dynlights/gl_lightbuffer.cpp
|
||||
gl/shaders/gl_shader.cpp
|
||||
gl/shaders/gl_texshader.cpp
|
||||
gl/system/gl_interface.cpp
|
||||
gl/system/gl_framebuffer.cpp
|
||||
gl/system/gl_menu.cpp
|
||||
gl/system/gl_wipe.cpp
|
||||
gl/system/gl_load.c
|
||||
gl/models/gl_models_md3.cpp
|
||||
gl/models/gl_models_md2.cpp
|
||||
gl/models/gl_models.cpp
|
||||
gl/models/gl_voxels.cpp
|
||||
oplsynth/fmopl.cpp
|
||||
oplsynth/mlopl.cpp
|
||||
oplsynth/mlopl_io.cpp
|
||||
|
@ -1292,6 +1418,19 @@ source_group("Games\\Raven Shared" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_D
|
|||
source_group("Games\\Strife Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_strife/.+")
|
||||
source_group("Intermission" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/intermission/.+")
|
||||
source_group("Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/menu/.+")
|
||||
source_group("OpenGL Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/.+")
|
||||
source_group("OpenGL Renderer\\Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/data/.+")
|
||||
source_group("OpenGL Renderer\\Dynamic Lights" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/dynlights/.+")
|
||||
source_group("OpenGL Renderer\\HQ Resize" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/hqnx/.+")
|
||||
source_group("OpenGL Renderer\\HQ Resize Assembly version" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/hqnx_asm/.+")
|
||||
source_group("OpenGL Renderer\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/models/.+")
|
||||
source_group("OpenGL Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/renderer/.+")
|
||||
source_group("OpenGL Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/scene/.+")
|
||||
source_group("OpenGL Renderer\\Stereo3D" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/stereo3d/.+")
|
||||
source_group("OpenGL Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/shaders/.+")
|
||||
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("Render Data\\Resource Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/.+\\.h$")
|
||||
|
|
|
@ -1099,6 +1099,14 @@ public:
|
|||
}
|
||||
|
||||
bool HasSpecialDeathStates () const;
|
||||
|
||||
// begin of GZDoom specific additions
|
||||
TArray<TObjPtr<AActor> > dynamiclights;
|
||||
void * lightassociations;
|
||||
bool hasmodel;
|
||||
// end of GZDoom specific additions
|
||||
|
||||
size_t PropagateMark();
|
||||
};
|
||||
|
||||
class FActorIterator
|
||||
|
|
|
@ -1449,12 +1449,14 @@ void G_AirControlChanged ()
|
|||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void gl_SerializeGlobals(FArchive &arc);
|
||||
|
||||
void G_SerializeLevel (FArchive &arc, bool hubLoad)
|
||||
{
|
||||
int i = level.totaltime;
|
||||
|
||||
Renderer->StartSerialize(arc);
|
||||
gl_SerializeGlobals(arc);
|
||||
|
||||
arc << level.flags
|
||||
<< level.flags2
|
||||
|
|
539
src/gl/data/gl_data.cpp
Normal file
539
src/gl/data/gl_data.cpp
Normal file
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
** gl_data.cpp
|
||||
** Maintenance data for GL renderer (mostly to handle rendering hacks)
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "colormatcher.h"
|
||||
#include "i_system.h"
|
||||
#include "p_local.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "r_sky.h"
|
||||
#include "sc_man.h"
|
||||
#include "w_wad.h"
|
||||
#include "gi.h"
|
||||
#include "g_level.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/dynlights/gl_dynlight.h"
|
||||
#include "gl/dynlights/gl_glow.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/gl_functions.h"
|
||||
|
||||
GLRenderSettings glset;
|
||||
long gl_frameMS;
|
||||
long gl_frameCount;
|
||||
|
||||
EXTERN_CVAR(Int, gl_lightmode)
|
||||
EXTERN_CVAR(Bool, gl_brightfog)
|
||||
|
||||
CUSTOM_CVAR(Float, maxviewpitch, 90.f, CVAR_ARCHIVE|CVAR_SERVERINFO)
|
||||
{
|
||||
if (self>90.f) self=90.f;
|
||||
else if (self<-90.f) self=-90.f;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, gl_notexturefill, false, 0)
|
||||
{
|
||||
glset.notexturefill = self;
|
||||
}
|
||||
|
||||
|
||||
CUSTOM_CVAR(Bool, gl_nocoloredspritelighting, false, 0)
|
||||
{
|
||||
glset.nocoloredspritelighting = self;
|
||||
}
|
||||
|
||||
void gl_CreateSections();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Adjust sprite offsets for GL rendering (IWAD resources only)
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void AdjustSpriteOffsets()
|
||||
{
|
||||
static bool done=false;
|
||||
char name[30];
|
||||
|
||||
if (done) return;
|
||||
done=true;
|
||||
|
||||
mysnprintf(name, countof(name), "sprofs/%s.sprofs", GameNames[gameinfo.gametype]);
|
||||
int lump = Wads.CheckNumForFullName(name);
|
||||
if (lump>=0)
|
||||
{
|
||||
FScanner sc;
|
||||
sc.OpenLumpNum(lump);
|
||||
GLRenderer->FlushTextures();
|
||||
int ofslumpno = Wads.GetLumpFile(lump);
|
||||
while (sc.GetString())
|
||||
{
|
||||
int x,y;
|
||||
FTextureID texno = TexMan.CheckForTexture(sc.String, FTexture::TEX_Sprite);
|
||||
sc.GetNumber();
|
||||
x=sc.Number;
|
||||
sc.GetNumber();
|
||||
y=sc.Number;
|
||||
|
||||
if (texno.isValid())
|
||||
{
|
||||
FTexture * tex = TexMan[texno];
|
||||
|
||||
int lumpnum = tex->GetSourceLump();
|
||||
// We only want to change texture offsets for sprites in the IWAD or the file this lump originated from.
|
||||
if (lumpnum >= 0 && lumpnum < Wads.GetNumLumps())
|
||||
{
|
||||
int wadno = Wads.GetLumpFile(lumpnum);
|
||||
if (wadno==FWadCollection::IWAD_FILENUM || wadno == ofslumpno)
|
||||
{
|
||||
tex->LeftOffset=x;
|
||||
tex->TopOffset=y;
|
||||
tex->KillNative();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Normally this would be better placed in p_lnspec.cpp.
|
||||
// But I have accidentally overwritten that file several times
|
||||
// so I'd rather place it here.
|
||||
static int LS_Sector_SetPlaneReflection (line_t *ln, AActor *it, bool backSide,
|
||||
int arg0, int arg1, int arg2, int arg3, int arg4)
|
||||
{
|
||||
// Sector_SetPlaneReflection (tag, floor, ceiling)
|
||||
int secnum;
|
||||
FSectorTagIterator itr(arg0);
|
||||
|
||||
while ((secnum = itr.Next()) >= 0)
|
||||
{
|
||||
sector_t * s = §ors[secnum];
|
||||
if (s->floorplane.a==0 && s->floorplane.b==0) s->reflect[sector_t::floor] = arg1/255.f;
|
||||
if (s->ceilingplane.a==0 && s->ceilingplane.b==0) sectors[secnum].reflect[sector_t::ceiling] = arg2/255.f;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int LS_SetGlobalFogParameter (line_t *ln, AActor *it, bool backSide,
|
||||
int arg0, int arg1, int arg2, int arg3, int arg4)
|
||||
{
|
||||
// SetGlobalFogParameter (type, value)
|
||||
switch(arg0)
|
||||
{
|
||||
case 0:
|
||||
fogdensity = arg1>>1;
|
||||
return true;
|
||||
|
||||
case 1:
|
||||
outsidefogdensity = arg1>>1;
|
||||
return true;
|
||||
|
||||
case 2:
|
||||
skyfog = arg1;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Portal identifier lists
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// MAPINFO stuff
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FGLROptions : public FOptionalMapinfoData
|
||||
{
|
||||
FGLROptions()
|
||||
{
|
||||
identifier = "gl_renderer";
|
||||
fogdensity = 0;
|
||||
outsidefogdensity = 0;
|
||||
skyfog = 0;
|
||||
brightfog = false;
|
||||
lightmode = -1;
|
||||
nocoloredspritelighting = -1;
|
||||
notexturefill = -1;
|
||||
skyrotatevector = FVector3(0,0,1);
|
||||
skyrotatevector2 = FVector3(0,0,1);
|
||||
pixelstretch = 1.2f;
|
||||
}
|
||||
virtual FOptionalMapinfoData *Clone() const
|
||||
{
|
||||
FGLROptions *newopt = new FGLROptions;
|
||||
newopt->identifier = identifier;
|
||||
newopt->fogdensity = fogdensity;
|
||||
newopt->outsidefogdensity = outsidefogdensity;
|
||||
newopt->skyfog = skyfog;
|
||||
newopt->lightmode = lightmode;
|
||||
newopt->nocoloredspritelighting = nocoloredspritelighting;
|
||||
newopt->notexturefill = notexturefill;
|
||||
newopt->skyrotatevector = skyrotatevector;
|
||||
newopt->skyrotatevector2 = skyrotatevector2;
|
||||
newopt->pixelstretch = pixelstretch;
|
||||
return newopt;
|
||||
}
|
||||
int fogdensity;
|
||||
int outsidefogdensity;
|
||||
int skyfog;
|
||||
int lightmode;
|
||||
int brightfog;
|
||||
SBYTE nocoloredspritelighting;
|
||||
SBYTE notexturefill;
|
||||
FVector3 skyrotatevector;
|
||||
FVector3 skyrotatevector2;
|
||||
float pixelstretch;
|
||||
};
|
||||
|
||||
DEFINE_MAP_OPTION(fogdensity, false)
|
||||
{
|
||||
FGLROptions *opt = info->GetOptData<FGLROptions>("gl_renderer");
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetNumber();
|
||||
opt->fogdensity = parse.sc.Number;
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(brightfog, false)
|
||||
{
|
||||
FGLROptions *opt = info->GetOptData<FGLROptions>("gl_renderer");
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetNumber();
|
||||
opt->brightfog = parse.sc.Number;
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(outsidefogdensity, false)
|
||||
{
|
||||
FGLROptions *opt = info->GetOptData<FGLROptions>("gl_renderer");
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetNumber();
|
||||
opt->outsidefogdensity = parse.sc.Number;
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(skyfog, false)
|
||||
{
|
||||
FGLROptions *opt = info->GetOptData<FGLROptions>("gl_renderer");
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetNumber();
|
||||
opt->skyfog = parse.sc.Number;
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(lightmode, false)
|
||||
{
|
||||
FGLROptions *opt = info->GetOptData<FGLROptions>("gl_renderer");
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetNumber();
|
||||
opt->lightmode = BYTE(parse.sc.Number);
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(nocoloredspritelighting, false)
|
||||
{
|
||||
FGLROptions *opt = info->GetOptData<FGLROptions>("gl_renderer");
|
||||
if (parse.CheckAssign())
|
||||
{
|
||||
parse.sc.MustGetNumber();
|
||||
opt->nocoloredspritelighting = !!parse.sc.Number;
|
||||
}
|
||||
else
|
||||
{
|
||||
opt->nocoloredspritelighting = true;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(notexturefill, false)
|
||||
{
|
||||
FGLROptions *opt = info->GetOptData<FGLROptions>("gl_renderer");
|
||||
if (parse.CheckAssign())
|
||||
{
|
||||
parse.sc.MustGetNumber();
|
||||
opt->notexturefill = !!parse.sc.Number;
|
||||
}
|
||||
else
|
||||
{
|
||||
opt->notexturefill = true;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(skyrotate, false)
|
||||
{
|
||||
FGLROptions *opt = info->GetOptData<FGLROptions>("gl_renderer");
|
||||
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetFloat();
|
||||
opt->skyrotatevector.X = (float)parse.sc.Float;
|
||||
if (parse.format_type == FMapInfoParser::FMT_New) parse.sc.MustGetStringName(",");
|
||||
parse.sc.MustGetFloat();
|
||||
opt->skyrotatevector.Y = (float)parse.sc.Float;
|
||||
if (parse.format_type == FMapInfoParser::FMT_New) parse.sc.MustGetStringName(",");
|
||||
parse.sc.MustGetFloat();
|
||||
opt->skyrotatevector.Z = (float)parse.sc.Float;
|
||||
opt->skyrotatevector.MakeUnit();
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(skyrotate2, false)
|
||||
{
|
||||
FGLROptions *opt = info->GetOptData<FGLROptions>("gl_renderer");
|
||||
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetFloat();
|
||||
opt->skyrotatevector2.X = (float)parse.sc.Float;
|
||||
if (parse.format_type == FMapInfoParser::FMT_New) parse.sc.MustGetStringName(",");
|
||||
parse.sc.MustGetFloat();
|
||||
opt->skyrotatevector2.Y = (float)parse.sc.Float;
|
||||
if (parse.format_type == FMapInfoParser::FMT_New) parse.sc.MustGetStringName(",");
|
||||
parse.sc.MustGetFloat();
|
||||
opt->skyrotatevector2.Z = (float)parse.sc.Float;
|
||||
opt->skyrotatevector2.MakeUnit();
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(pixelratio, false)
|
||||
{
|
||||
FGLROptions *opt = info->GetOptData<FGLROptions>("gl_renderer");
|
||||
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetFloat();
|
||||
opt->pixelstretch = (float)parse.sc.Float;
|
||||
}
|
||||
|
||||
bool IsLightmodeValid()
|
||||
{
|
||||
return (glset.map_lightmode >= 0 && glset.map_lightmode <= 4) || glset.map_lightmode == 8;
|
||||
}
|
||||
|
||||
void InitGLRMapinfoData()
|
||||
{
|
||||
FGLROptions *opt = level.info->GetOptData<FGLROptions>("gl_renderer", false);
|
||||
|
||||
if (opt != NULL)
|
||||
{
|
||||
gl_SetFogParams(opt->fogdensity, level.info->outsidefog, opt->outsidefogdensity, opt->skyfog);
|
||||
glset.map_lightmode = opt->lightmode;
|
||||
glset.map_brightfog = opt->brightfog;
|
||||
glset.map_nocoloredspritelighting = opt->nocoloredspritelighting;
|
||||
glset.map_notexturefill = opt->notexturefill;
|
||||
glset.skyrotatevector = opt->skyrotatevector;
|
||||
glset.skyrotatevector2 = opt->skyrotatevector2;
|
||||
glset.pixelstretch = opt->pixelstretch;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_SetFogParams(0, level.info->outsidefog, 0, 0);
|
||||
glset.map_lightmode = -1;
|
||||
glset.map_brightfog = -1;
|
||||
glset.map_nocoloredspritelighting = -1;
|
||||
glset.map_notexturefill = -1;
|
||||
glset.skyrotatevector = FVector3(0,0,1);
|
||||
glset.skyrotatevector2 = FVector3(0,0,1);
|
||||
glset.pixelstretch = 1.2f;
|
||||
}
|
||||
|
||||
if (!IsLightmodeValid()) glset.lightmode = gl_lightmode;
|
||||
else glset.lightmode = glset.map_lightmode;
|
||||
if (glset.map_nocoloredspritelighting == -1) glset.nocoloredspritelighting = gl_nocoloredspritelighting;
|
||||
else glset.nocoloredspritelighting = !!glset.map_nocoloredspritelighting;
|
||||
if (glset.map_notexturefill == -1) glset.notexturefill = gl_notexturefill;
|
||||
else glset.notexturefill = !!glset.map_notexturefill;
|
||||
if (glset.map_brightfog == -1) glset.brightfog = gl_brightfog;
|
||||
else glset.brightfog = !!glset.map_brightfog;
|
||||
}
|
||||
|
||||
CCMD(gl_resetmap)
|
||||
{
|
||||
if (!IsLightmodeValid()) glset.lightmode = gl_lightmode;
|
||||
else glset.lightmode = glset.map_lightmode;
|
||||
if (glset.map_nocoloredspritelighting == -1) glset.nocoloredspritelighting = gl_nocoloredspritelighting;
|
||||
else glset.nocoloredspritelighting = !!glset.map_nocoloredspritelighting;
|
||||
if (glset.map_notexturefill == -1) glset.notexturefill = gl_notexturefill;
|
||||
else glset.notexturefill = !!glset.map_notexturefill;
|
||||
if (glset.map_brightfog == -1) glset.brightfog = gl_brightfog;
|
||||
else glset.brightfog = !!glset.map_brightfog;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Gets the texture index for a sprite frame
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FTextureID gl_GetSpriteFrame(unsigned sprite, int frame, int rot, angle_t ang, bool *mirror)
|
||||
{
|
||||
spritedef_t *sprdef = &sprites[sprite];
|
||||
if (frame >= sprdef->numframes)
|
||||
{
|
||||
// If there are no frames at all for this sprite, don't draw it.
|
||||
return FNullTextureID();
|
||||
}
|
||||
else
|
||||
{
|
||||
//picnum = SpriteFrames[sprdef->spriteframes + thing->frame].Texture[0];
|
||||
// choose a different rotation based on player view
|
||||
spriteframe_t *sprframe = &SpriteFrames[sprdef->spriteframes + frame];
|
||||
if (rot==-1)
|
||||
{
|
||||
if (sprframe->Texture[0] == sprframe->Texture[1])
|
||||
{
|
||||
rot = (ang + (angle_t)(ANGLE_45/2)*9) >> 28;
|
||||
}
|
||||
else
|
||||
{
|
||||
rot = (ang + (angle_t)(ANGLE_45/2)*9-(angle_t)(ANGLE_180/16)) >> 28;
|
||||
}
|
||||
}
|
||||
if (mirror) *mirror = !!(sprframe->Flip&(1<<rot));
|
||||
return sprframe->Texture[rot];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Recalculate all heights affectting this vertex.
|
||||
//
|
||||
//==========================================================================
|
||||
void gl_RecalcVertexHeights(vertex_t * v)
|
||||
{
|
||||
int i,j,k;
|
||||
float height;
|
||||
|
||||
v->numheights=0;
|
||||
for(i=0;i<v->numsectors;i++)
|
||||
{
|
||||
for(j=0;j<2;j++)
|
||||
{
|
||||
if (j==0) height=FIXED2FLOAT(v->sectors[i]->ceilingplane.ZatPoint(v));
|
||||
else height=FIXED2FLOAT(v->sectors[i]->floorplane.ZatPoint(v));
|
||||
|
||||
for(k=0;k<v->numheights;k++)
|
||||
{
|
||||
if (height == v->heightlist[k]) break;
|
||||
if (height < v->heightlist[k])
|
||||
{
|
||||
memmove(&v->heightlist[k+1], &v->heightlist[k], sizeof(float) * (v->numheights-k));
|
||||
v->heightlist[k]=height;
|
||||
v->numheights++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k==v->numheights) v->heightlist[v->numheights++]=height;
|
||||
}
|
||||
}
|
||||
if (v->numheights<=2) v->numheights=0; // is not in need of any special attention
|
||||
v->dirty = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void gl_InitData()
|
||||
{
|
||||
LineSpecials[157] = LS_SetGlobalFogParameter;
|
||||
LineSpecials[159] = LS_Sector_SetPlaneReflection;
|
||||
AdjustSpriteOffsets();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// dumpgeometry
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD(dumpgeometry)
|
||||
{
|
||||
for(int i=0;i<numsectors;i++)
|
||||
{
|
||||
sector_t * sector = §ors[i];
|
||||
|
||||
Printf(PRINT_LOG, "Sector %d\n",i);
|
||||
for(int j=0;j<sector->subsectorcount;j++)
|
||||
{
|
||||
subsector_t * sub = sector->subsectors[j];
|
||||
|
||||
Printf(PRINT_LOG, " Subsector %d - real sector = %d - %s\n", int(sub-subsectors), sub->sector->sectornum, sub->hacked&1? "hacked":"");
|
||||
for(DWORD k=0;k<sub->numlines;k++)
|
||||
{
|
||||
seg_t * seg = sub->firstline + k;
|
||||
if (seg->linedef)
|
||||
{
|
||||
Printf(PRINT_LOG, " (%4.4f, %4.4f), (%4.4f, %4.4f) - seg %d, linedef %d, side %d",
|
||||
FIXED2FLOAT(seg->v1->x), FIXED2FLOAT(seg->v1->y), FIXED2FLOAT(seg->v2->x), FIXED2FLOAT(seg->v2->y),
|
||||
int(seg-segs), int(seg->linedef-lines), seg->sidedef != seg->linedef->sidedef[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf(PRINT_LOG, " (%4.4f, %4.4f), (%4.4f, %4.4f) - seg %d, miniseg",
|
||||
FIXED2FLOAT(seg->v1->x), FIXED2FLOAT(seg->v1->y), FIXED2FLOAT(seg->v2->x), FIXED2FLOAT(seg->v2->y),
|
||||
int(seg-segs));
|
||||
}
|
||||
if (seg->PartnerSeg)
|
||||
{
|
||||
subsector_t * sub2 = seg->PartnerSeg->Subsector;
|
||||
Printf(PRINT_LOG, ", back sector = %d, real back sector = %d", sub2->render_sector->sectornum, seg->PartnerSeg->frontsector->sectornum);
|
||||
}
|
||||
else if (seg->backsector)
|
||||
{
|
||||
Printf(PRINT_LOG, ", back sector = %d (no partnerseg)", seg->backsector->sectornum);
|
||||
}
|
||||
|
||||
Printf(PRINT_LOG, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
src/gl/data/gl_data.h
Normal file
66
src/gl/data/gl_data.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
|
||||
#ifndef __GLC_DATA_H
|
||||
#define __GLC_DATA_H
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
struct GLRenderSettings
|
||||
{
|
||||
|
||||
SBYTE lightmode;
|
||||
bool nocoloredspritelighting;
|
||||
bool notexturefill;
|
||||
bool brightfog;
|
||||
|
||||
SBYTE map_lightmode;
|
||||
SBYTE map_nocoloredspritelighting;
|
||||
SBYTE map_notexturefill;
|
||||
SBYTE map_brightfog;
|
||||
|
||||
FVector3 skyrotatevector;
|
||||
FVector3 skyrotatevector2;
|
||||
|
||||
float pixelstretch;
|
||||
|
||||
};
|
||||
|
||||
extern GLRenderSettings glset;
|
||||
|
||||
#include "r_defs.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "c_cvars.h"
|
||||
|
||||
extern int extralight;
|
||||
EXTERN_CVAR(Int, gl_weaponlight);
|
||||
|
||||
inline int getExtraLight()
|
||||
{
|
||||
return extralight * gl_weaponlight;
|
||||
}
|
||||
|
||||
void gl_RecalcVertexHeights(vertex_t * v);
|
||||
FTextureID gl_GetSpriteFrame(unsigned sprite, int frame, int rot, angle_t ang, bool *mirror);
|
||||
|
||||
class AStackPoint;
|
||||
struct GLSectorStackPortal;
|
||||
|
||||
struct FPortal
|
||||
{
|
||||
fixed_t xDisplacement;
|
||||
fixed_t yDisplacement;
|
||||
int plane;
|
||||
GLSectorStackPortal *glportal; // for quick access to the render data. This is only valid during BSP traversal!
|
||||
|
||||
GLSectorStackPortal *GetGLPortal();
|
||||
};
|
||||
|
||||
extern TArray<FPortal *> portals;
|
||||
extern TArray<BYTE> currentmapsection;
|
||||
|
||||
void gl_InitPortals();
|
||||
void gl_BuildPortalCoverage(FPortalCoverage *coverage, subsector_t *subsector, FPortal *portal);
|
||||
void gl_InitData();
|
||||
|
||||
extern long gl_frameMS;
|
||||
|
||||
#endif
|
495
src/gl/data/gl_matrix.cpp
Normal file
495
src/gl/data/gl_matrix.cpp
Normal file
|
@ -0,0 +1,495 @@
|
|||
/* --------------------------------------------------
|
||||
|
||||
Lighthouse3D
|
||||
|
||||
VSMatrix - Very Simple Matrix Library
|
||||
|
||||
http://www.lighthouse3d.com/very-simple-libs
|
||||
|
||||
This is a simplified version of VSMatrix that has been adjusted for GZDoom's needs.
|
||||
|
||||
----------------------------------------------------*/
|
||||
|
||||
#include "gl/system/gl_system.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "doomtype.h"
|
||||
#include "gl/data/gl_matrix.h"
|
||||
|
||||
static inline FLOATTYPE
|
||||
DegToRad(FLOATTYPE degrees)
|
||||
{
|
||||
return (FLOATTYPE)(degrees * (M_PI / 180.0f));
|
||||
};
|
||||
|
||||
// sets the square matrix mat to the identity matrix,
|
||||
// size refers to the number of rows (or columns)
|
||||
void
|
||||
VSMatrix::setIdentityMatrix( FLOATTYPE *mat, int size) {
|
||||
|
||||
// fill matrix with 0s
|
||||
for (int i = 0; i < size * size; ++i)
|
||||
mat[i] = 0.0f;
|
||||
|
||||
// fill diagonal with 1s
|
||||
for (int i = 0; i < size; ++i)
|
||||
mat[i + i * size] = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// gl LoadIdentity implementation
|
||||
void
|
||||
VSMatrix::loadIdentity()
|
||||
{
|
||||
// fill matrix with 0s
|
||||
for (int i = 0; i < 16; ++i)
|
||||
mMatrix[i] = 0.0f;
|
||||
|
||||
// fill diagonal with 1s
|
||||
for (int i = 0; i < 4; ++i)
|
||||
mMatrix[i + i * 4] = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
// gl MultMatrix implementation
|
||||
void
|
||||
VSMatrix::multMatrix(const FLOATTYPE *aMatrix)
|
||||
{
|
||||
|
||||
FLOATTYPE res[16];
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
res[j*4 + i] = 0.0f;
|
||||
for (int k = 0; k < 4; ++k)
|
||||
{
|
||||
res[j*4 + i] += mMatrix[k*4 + i] * aMatrix[j*4 + k];
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(mMatrix, res, 16 * sizeof(FLOATTYPE));
|
||||
}
|
||||
|
||||
#ifdef USE_DOUBLE
|
||||
// gl MultMatrix implementation
|
||||
void
|
||||
VSMatrix::multMatrix(const float *aMatrix)
|
||||
{
|
||||
|
||||
FLOATTYPE res[16];
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
res[j * 4 + i] = 0.0f;
|
||||
for (int k = 0; k < 4; ++k)
|
||||
{
|
||||
res[j*4 + i] += mMatrix[k*4 + i] * aMatrix[j*4 + k];
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(mMatrix, res, 16 * sizeof(FLOATTYPE));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// gl LoadMatrix implementation
|
||||
void
|
||||
VSMatrix::loadMatrix(const FLOATTYPE *aMatrix)
|
||||
{
|
||||
memcpy(mMatrix, aMatrix, 16 * sizeof(FLOATTYPE));
|
||||
}
|
||||
|
||||
#ifdef USE_DOUBLE
|
||||
// gl LoadMatrix implementation
|
||||
void
|
||||
VSMatrix::loadMatrix(const float *aMatrix)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
mMatrix[i] = aMatrix[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// gl Translate implementation with matrix selection
|
||||
void
|
||||
VSMatrix::translate(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z)
|
||||
{
|
||||
FLOATTYPE mat[16];
|
||||
|
||||
setIdentityMatrix(mat);
|
||||
mat[12] = x;
|
||||
mat[13] = y;
|
||||
mat[14] = z;
|
||||
|
||||
multMatrix(mat);
|
||||
}
|
||||
|
||||
|
||||
// gl Scale implementation with matrix selection
|
||||
void
|
||||
VSMatrix::scale(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z)
|
||||
{
|
||||
FLOATTYPE mat[16];
|
||||
|
||||
setIdentityMatrix(mat,4);
|
||||
mat[0] = x;
|
||||
mat[5] = y;
|
||||
mat[10] = z;
|
||||
|
||||
multMatrix(mat);
|
||||
}
|
||||
|
||||
|
||||
// gl Rotate implementation with matrix selection
|
||||
void
|
||||
VSMatrix::rotate(FLOATTYPE angle, FLOATTYPE x, FLOATTYPE y, FLOATTYPE z)
|
||||
{
|
||||
FLOATTYPE mat[16];
|
||||
FLOATTYPE v[3];
|
||||
|
||||
v[0] = x;
|
||||
v[1] = y;
|
||||
v[2] = z;
|
||||
|
||||
FLOATTYPE radAngle = DegToRad(angle);
|
||||
FLOATTYPE co = cos(radAngle);
|
||||
FLOATTYPE si = sin(radAngle);
|
||||
normalize(v);
|
||||
FLOATTYPE x2 = v[0]*v[0];
|
||||
FLOATTYPE y2 = v[1]*v[1];
|
||||
FLOATTYPE z2 = v[2]*v[2];
|
||||
|
||||
// mat[0] = x2 + (y2 + z2) * co;
|
||||
mat[0] = co + x2 * (1 - co);// + (y2 + z2) * co;
|
||||
mat[4] = v[0] * v[1] * (1 - co) - v[2] * si;
|
||||
mat[8] = v[0] * v[2] * (1 - co) + v[1] * si;
|
||||
mat[12]= 0.0f;
|
||||
|
||||
mat[1] = v[0] * v[1] * (1 - co) + v[2] * si;
|
||||
// mat[5] = y2 + (x2 + z2) * co;
|
||||
mat[5] = co + y2 * (1 - co);
|
||||
mat[9] = v[1] * v[2] * (1 - co) - v[0] * si;
|
||||
mat[13]= 0.0f;
|
||||
|
||||
mat[2] = v[0] * v[2] * (1 - co) - v[1] * si;
|
||||
mat[6] = v[1] * v[2] * (1 - co) + v[0] * si;
|
||||
// mat[10]= z2 + (x2 + y2) * co;
|
||||
mat[10]= co + z2 * (1 - co);
|
||||
mat[14]= 0.0f;
|
||||
|
||||
mat[3] = 0.0f;
|
||||
mat[7] = 0.0f;
|
||||
mat[11]= 0.0f;
|
||||
mat[15]= 1.0f;
|
||||
|
||||
multMatrix(mat);
|
||||
}
|
||||
|
||||
|
||||
// gluLookAt implementation
|
||||
void
|
||||
VSMatrix::lookAt(FLOATTYPE xPos, FLOATTYPE yPos, FLOATTYPE zPos,
|
||||
FLOATTYPE xLook, FLOATTYPE yLook, FLOATTYPE zLook,
|
||||
FLOATTYPE xUp, FLOATTYPE yUp, FLOATTYPE zUp)
|
||||
{
|
||||
FLOATTYPE dir[3], right[3], up[3];
|
||||
|
||||
up[0] = xUp; up[1] = yUp; up[2] = zUp;
|
||||
|
||||
dir[0] = (xLook - xPos);
|
||||
dir[1] = (yLook - yPos);
|
||||
dir[2] = (zLook - zPos);
|
||||
normalize(dir);
|
||||
|
||||
crossProduct(dir,up,right);
|
||||
normalize(right);
|
||||
|
||||
crossProduct(right,dir,up);
|
||||
normalize(up);
|
||||
|
||||
FLOATTYPE m1[16],m2[16];
|
||||
|
||||
m1[0] = right[0];
|
||||
m1[4] = right[1];
|
||||
m1[8] = right[2];
|
||||
m1[12] = 0.0f;
|
||||
|
||||
m1[1] = up[0];
|
||||
m1[5] = up[1];
|
||||
m1[9] = up[2];
|
||||
m1[13] = 0.0f;
|
||||
|
||||
m1[2] = -dir[0];
|
||||
m1[6] = -dir[1];
|
||||
m1[10] = -dir[2];
|
||||
m1[14] = 0.0f;
|
||||
|
||||
m1[3] = 0.0f;
|
||||
m1[7] = 0.0f;
|
||||
m1[11] = 0.0f;
|
||||
m1[15] = 1.0f;
|
||||
|
||||
setIdentityMatrix(m2,4);
|
||||
m2[12] = -xPos;
|
||||
m2[13] = -yPos;
|
||||
m2[14] = -zPos;
|
||||
|
||||
multMatrix(m1);
|
||||
multMatrix(m2);
|
||||
}
|
||||
|
||||
|
||||
// gluPerspective implementation
|
||||
void
|
||||
VSMatrix::perspective(FLOATTYPE fov, FLOATTYPE ratio, FLOATTYPE nearp, FLOATTYPE farp)
|
||||
{
|
||||
FLOATTYPE f = 1.0f / tan (fov * (M_PI / 360.0f));
|
||||
|
||||
loadIdentity();
|
||||
mMatrix[0] = f / ratio;
|
||||
mMatrix[1 * 4 + 1] = f;
|
||||
mMatrix[2 * 4 + 2] = (farp + nearp) / (nearp - farp);
|
||||
mMatrix[3 * 4 + 2] = (2.0f * farp * nearp) / (nearp - farp);
|
||||
mMatrix[2 * 4 + 3] = -1.0f;
|
||||
mMatrix[3 * 4 + 3] = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
// gl Ortho implementation
|
||||
void
|
||||
VSMatrix::ortho(FLOATTYPE left, FLOATTYPE right,
|
||||
FLOATTYPE bottom, FLOATTYPE top,
|
||||
FLOATTYPE nearp, FLOATTYPE farp)
|
||||
{
|
||||
loadIdentity();
|
||||
|
||||
mMatrix[0 * 4 + 0] = 2 / (right - left);
|
||||
mMatrix[1 * 4 + 1] = 2 / (top - bottom);
|
||||
mMatrix[2 * 4 + 2] = -2 / (farp - nearp);
|
||||
mMatrix[3 * 4 + 0] = -(right + left) / (right - left);
|
||||
mMatrix[3 * 4 + 1] = -(top + bottom) / (top - bottom);
|
||||
mMatrix[3 * 4 + 2] = -(farp + nearp) / (farp - nearp);
|
||||
}
|
||||
|
||||
|
||||
// gl Frustum implementation
|
||||
void
|
||||
VSMatrix::frustum(FLOATTYPE left, FLOATTYPE right,
|
||||
FLOATTYPE bottom, FLOATTYPE top,
|
||||
FLOATTYPE nearp, FLOATTYPE farp)
|
||||
{
|
||||
FLOATTYPE m[16];
|
||||
|
||||
setIdentityMatrix(m,4);
|
||||
|
||||
m[0 * 4 + 0] = 2 * nearp / (right-left);
|
||||
m[1 * 4 + 1] = 2 * nearp / (top - bottom);
|
||||
m[2 * 4 + 0] = (right + left) / (right - left);
|
||||
m[2 * 4 + 1] = (top + bottom) / (top - bottom);
|
||||
m[2 * 4 + 2] = - (farp + nearp) / (farp - nearp);
|
||||
m[2 * 4 + 3] = -1.0f;
|
||||
m[3 * 4 + 2] = - 2 * farp * nearp / (farp-nearp);
|
||||
m[3 * 4 + 3] = 0.0f;
|
||||
|
||||
multMatrix(m);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// returns a pointer to the requested matrix
|
||||
FLOATTYPE *
|
||||
VSMatrix::get(MatrixTypes aType)
|
||||
{
|
||||
return mMatrix[aType];
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/* -----------------------------------------------------
|
||||
SEND MATRICES TO OPENGL
|
||||
------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
|
||||
// universal
|
||||
void
|
||||
VSMatrix::matrixToGL(int loc)
|
||||
{
|
||||
#ifdef USE_DOUBLE
|
||||
float copyto[16];
|
||||
copy(copyto);
|
||||
glUniformMatrix4fv(loc, 1, false, copyto);
|
||||
#else
|
||||
glUniformMatrix4fv(loc, 1, false, mMatrix);
|
||||
#endif
|
||||
}
|
||||
|
||||
// -----------------------------------------------------
|
||||
// AUX functions
|
||||
// -----------------------------------------------------
|
||||
|
||||
|
||||
// Compute res = M * point
|
||||
void
|
||||
VSMatrix::multMatrixPoint(const FLOATTYPE *point, FLOATTYPE *res)
|
||||
{
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
|
||||
res[i] = 0.0f;
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
|
||||
res[i] += point[j] * mMatrix[j*4 + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// res = a cross b;
|
||||
void
|
||||
VSMatrix::crossProduct(const FLOATTYPE *a, const FLOATTYPE *b, FLOATTYPE *res) {
|
||||
|
||||
res[0] = a[1] * b[2] - b[1] * a[2];
|
||||
res[1] = a[2] * b[0] - b[2] * a[0];
|
||||
res[2] = a[0] * b[1] - b[0] * a[1];
|
||||
}
|
||||
|
||||
|
||||
// returns a . b
|
||||
FLOATTYPE
|
||||
VSMatrix::dotProduct(const FLOATTYPE *a, const FLOATTYPE *b) {
|
||||
|
||||
FLOATTYPE res = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Normalize a vec3
|
||||
void
|
||||
VSMatrix::normalize(FLOATTYPE *a) {
|
||||
|
||||
FLOATTYPE mag = sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
|
||||
|
||||
a[0] /= mag;
|
||||
a[1] /= mag;
|
||||
a[2] /= mag;
|
||||
}
|
||||
|
||||
|
||||
// res = b - a
|
||||
void
|
||||
VSMatrix::subtract(const FLOATTYPE *a, const FLOATTYPE *b, FLOATTYPE *res) {
|
||||
|
||||
res[0] = b[0] - a[0];
|
||||
res[1] = b[1] - a[1];
|
||||
res[2] = b[2] - a[2];
|
||||
}
|
||||
|
||||
|
||||
// res = a + b
|
||||
void
|
||||
VSMatrix::add(const FLOATTYPE *a, const FLOATTYPE *b, FLOATTYPE *res) {
|
||||
|
||||
res[0] = b[0] + a[0];
|
||||
res[1] = b[1] + a[1];
|
||||
res[2] = b[2] + a[2];
|
||||
}
|
||||
|
||||
|
||||
// returns |a|
|
||||
FLOATTYPE
|
||||
VSMatrix::length(const FLOATTYPE *a) {
|
||||
|
||||
return(sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]));
|
||||
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
M3(int i, int j)
|
||||
{
|
||||
return (i*3+j);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// computes the derived normal matrix for the view matrix
|
||||
void
|
||||
VSMatrix::computeNormalMatrix(const FLOATTYPE *aMatrix)
|
||||
{
|
||||
|
||||
FLOATTYPE mMat3x3[9];
|
||||
|
||||
mMat3x3[0] = aMatrix[0];
|
||||
mMat3x3[1] = aMatrix[1];
|
||||
mMat3x3[2] = aMatrix[2];
|
||||
|
||||
mMat3x3[3] = aMatrix[4];
|
||||
mMat3x3[4] = aMatrix[5];
|
||||
mMat3x3[5] = aMatrix[6];
|
||||
|
||||
mMat3x3[6] = aMatrix[8];
|
||||
mMat3x3[7] = aMatrix[9];
|
||||
mMat3x3[8] = aMatrix[10];
|
||||
|
||||
FLOATTYPE det, invDet;
|
||||
|
||||
det = mMat3x3[0] * (mMat3x3[4] * mMat3x3[8] - mMat3x3[5] * mMat3x3[7]) +
|
||||
mMat3x3[1] * (mMat3x3[5] * mMat3x3[6] - mMat3x3[8] * mMat3x3[3]) +
|
||||
mMat3x3[2] * (mMat3x3[3] * mMat3x3[7] - mMat3x3[4] * mMat3x3[6]);
|
||||
|
||||
invDet = 1.0f/det;
|
||||
|
||||
mMatrix[0] = (mMat3x3[4] * mMat3x3[8] - mMat3x3[5] * mMat3x3[7]) * invDet;
|
||||
mMatrix[1] = (mMat3x3[5] * mMat3x3[6] - mMat3x3[8] * mMat3x3[3]) * invDet;
|
||||
mMatrix[2] = (mMat3x3[3] * mMat3x3[7] - mMat3x3[4] * mMat3x3[6]) * invDet;
|
||||
mMatrix[3] = 0.0f;
|
||||
mMatrix[4] = (mMat3x3[2] * mMat3x3[7] - mMat3x3[1] * mMat3x3[8]) * invDet;
|
||||
mMatrix[5] = (mMat3x3[0] * mMat3x3[8] - mMat3x3[2] * mMat3x3[6]) * invDet;
|
||||
mMatrix[6] = (mMat3x3[1] * mMat3x3[6] - mMat3x3[7] * mMat3x3[0]) * invDet;
|
||||
mMatrix[7] = 0.0f;
|
||||
mMatrix[8] = (mMat3x3[1] * mMat3x3[5] - mMat3x3[4] * mMat3x3[2]) * invDet;
|
||||
mMatrix[9] = (mMat3x3[2] * mMat3x3[3] - mMat3x3[0] * mMat3x3[5]) * invDet;
|
||||
mMatrix[10] =(mMat3x3[0] * mMat3x3[4] - mMat3x3[3] * mMat3x3[1]) * invDet;
|
||||
mMatrix[11] = 0.0;
|
||||
mMatrix[12] = 0.0;
|
||||
mMatrix[13] = 0.0;
|
||||
mMatrix[14] = 0.0;
|
||||
mMatrix[15] = 1.0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// aux function resMat = resMat * aMatrix
|
||||
void
|
||||
VSMatrix::multMatrix(FLOATTYPE *resMat, const FLOATTYPE *aMatrix)
|
||||
{
|
||||
|
||||
FLOATTYPE res[16];
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
res[j*4 + i] = 0.0f;
|
||||
for (int k = 0; k < 4; ++k)
|
||||
{
|
||||
res[j*4 + i] += resMat[k*4 + i] * aMatrix[j*4 + k];
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(resMat, res, 16 * sizeof(FLOATTYPE));
|
||||
}
|
112
src/gl/data/gl_matrix.h
Normal file
112
src/gl/data/gl_matrix.h
Normal file
|
@ -0,0 +1,112 @@
|
|||
|
||||
// Matrix class based on code from VSML:
|
||||
|
||||
/** ----------------------------------------------------------
|
||||
* \class VSMathLib
|
||||
*
|
||||
* Lighthouse3D
|
||||
*
|
||||
* VSMathLib - Very Simple Matrix Library
|
||||
*
|
||||
* Full documentation at
|
||||
* http://www.lighthouse3d.com/very-simple-libs
|
||||
*
|
||||
* This class aims at easing geometric transforms, camera
|
||||
* placement and projection definition for programmers
|
||||
* working with OpenGL core versions.
|
||||
*
|
||||
*
|
||||
---------------------------------------------------------------*/
|
||||
#ifndef __VSMatrix__
|
||||
#define __VSMatrix__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef USE_DOUBLE
|
||||
typedef double FLOATTYPE;
|
||||
#else
|
||||
typedef float FLOATTYPE;
|
||||
#endif
|
||||
|
||||
class VSMatrix {
|
||||
|
||||
public:
|
||||
|
||||
VSMatrix()
|
||||
{
|
||||
}
|
||||
|
||||
VSMatrix(int)
|
||||
{
|
||||
loadIdentity();
|
||||
}
|
||||
|
||||
void translate(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z);
|
||||
void scale(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z);
|
||||
void rotate(FLOATTYPE angle, FLOATTYPE x, FLOATTYPE y, FLOATTYPE z);
|
||||
void loadIdentity();
|
||||
#ifdef USE_DOUBLE
|
||||
void multMatrix(const float *aMatrix);
|
||||
#endif
|
||||
void multMatrix(const FLOATTYPE *aMatrix);
|
||||
void multMatrix(const VSMatrix &aMatrix)
|
||||
{
|
||||
multMatrix(aMatrix.mMatrix);
|
||||
}
|
||||
void loadMatrix(const FLOATTYPE *aMatrix);
|
||||
#ifdef USE_DOUBLE
|
||||
void loadMatrix(const float *aMatrix);
|
||||
#endif
|
||||
void lookAt(FLOATTYPE xPos, FLOATTYPE yPos, FLOATTYPE zPos, FLOATTYPE xLook, FLOATTYPE yLook, FLOATTYPE zLook, FLOATTYPE xUp, FLOATTYPE yUp, FLOATTYPE zUp);
|
||||
void perspective(FLOATTYPE fov, FLOATTYPE ratio, FLOATTYPE nearp, FLOATTYPE farp);
|
||||
void ortho(FLOATTYPE left, FLOATTYPE right, FLOATTYPE bottom, FLOATTYPE top, FLOATTYPE nearp=-1.0f, FLOATTYPE farp=1.0f);
|
||||
void frustum(FLOATTYPE left, FLOATTYPE right, FLOATTYPE bottom, FLOATTYPE top, FLOATTYPE nearp, FLOATTYPE farp);
|
||||
void copy(FLOATTYPE * pDest)
|
||||
{
|
||||
memcpy(pDest, mMatrix, 16 * sizeof(FLOATTYPE));
|
||||
}
|
||||
|
||||
#ifdef USE_DOUBLE
|
||||
void copy(float * pDest)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
pDest[i] = (float)mMatrix[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const FLOATTYPE *get() const
|
||||
{
|
||||
return mMatrix;
|
||||
}
|
||||
|
||||
void matrixToGL(int location);
|
||||
void multMatrixPoint(const FLOATTYPE *point, FLOATTYPE *res);
|
||||
|
||||
#ifdef USE_DOUBLE
|
||||
void computeNormalMatrix(const float *aMatrix);
|
||||
#endif
|
||||
void computeNormalMatrix(const FLOATTYPE *aMatrix);
|
||||
void computeNormalMatrix(const VSMatrix &aMatrix)
|
||||
{
|
||||
computeNormalMatrix(aMatrix.mMatrix);
|
||||
}
|
||||
|
||||
protected:
|
||||
static void crossProduct(const FLOATTYPE *a, const FLOATTYPE *b, FLOATTYPE *res);
|
||||
static FLOATTYPE dotProduct(const FLOATTYPE *a, const FLOATTYPE * b);
|
||||
static void normalize(FLOATTYPE *a);
|
||||
static void subtract(const FLOATTYPE *a, const FLOATTYPE *b, FLOATTYPE *res);
|
||||
static void add(const FLOATTYPE *a, const FLOATTYPE *b, FLOATTYPE *res);
|
||||
static FLOATTYPE length(const FLOATTYPE *a);
|
||||
static void multMatrix(FLOATTYPE *resMatrix, const FLOATTYPE *aMatrix);
|
||||
|
||||
static void setIdentityMatrix(FLOATTYPE *mat, int size = 4);
|
||||
|
||||
/// The storage for matrices
|
||||
FLOATTYPE mMatrix[16];
|
||||
|
||||
};
|
||||
|
||||
#endif
|
473
src/gl/data/gl_portaldata.cpp
Normal file
473
src/gl/data/gl_portaldata.cpp
Normal file
|
@ -0,0 +1,473 @@
|
|||
/*
|
||||
** gl_setup.cpp
|
||||
** Initializes the data structures required by the GL renderer to handle
|
||||
** a level
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "doomtype.h"
|
||||
#include "colormatcher.h"
|
||||
#include "i_system.h"
|
||||
#include "p_local.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "r_sky.h"
|
||||
#include "sc_man.h"
|
||||
#include "w_wad.h"
|
||||
#include "gi.h"
|
||||
#include "g_level.h"
|
||||
#include "a_sharedglobal.h"
|
||||
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/scene/gl_clipper.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/dynlights/gl_dynlight.h"
|
||||
#include "gl/dynlights/gl_glow.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/gl_functions.h"
|
||||
|
||||
struct FPortalID
|
||||
{
|
||||
fixed_t mXDisplacement;
|
||||
fixed_t mYDisplacement;
|
||||
|
||||
// for the hash code
|
||||
operator intptr_t() const { return (mXDisplacement >> 8) + (mYDisplacement << 8); }
|
||||
bool operator != (const FPortalID &other) const
|
||||
{
|
||||
return mXDisplacement != other.mXDisplacement ||
|
||||
mYDisplacement != other.mYDisplacement;
|
||||
}
|
||||
};
|
||||
|
||||
struct FPortalSector
|
||||
{
|
||||
sector_t *mSub;
|
||||
int mPlane;
|
||||
};
|
||||
|
||||
typedef TArray<FPortalSector> FPortalSectors;
|
||||
|
||||
typedef TMap<FPortalID, FPortalSectors> FPortalMap;
|
||||
|
||||
TArray<FPortal *> portals;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
GLSectorStackPortal *FPortal::GetGLPortal()
|
||||
{
|
||||
if (glportal == NULL) glportal = new GLSectorStackPortal(this);
|
||||
return glportal;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FCoverageVertex
|
||||
{
|
||||
fixed_t x, y;
|
||||
|
||||
bool operator !=(FCoverageVertex &other)
|
||||
{
|
||||
return x != other.x || y != other.y;
|
||||
}
|
||||
};
|
||||
|
||||
struct FCoverageLine
|
||||
{
|
||||
FCoverageVertex v[2];
|
||||
};
|
||||
|
||||
struct FCoverageBuilder
|
||||
{
|
||||
subsector_t *target;
|
||||
FPortal *portal;
|
||||
TArray<int> collect;
|
||||
FCoverageVertex center;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FCoverageBuilder(subsector_t *sub, FPortal *port)
|
||||
{
|
||||
target = sub;
|
||||
portal = port;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// GetIntersection
|
||||
//
|
||||
// adapted from P_InterceptVector
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool GetIntersection(FCoverageVertex *v1, FCoverageVertex *v2, node_t *bsp, FCoverageVertex *v)
|
||||
{
|
||||
double frac;
|
||||
double num;
|
||||
double den;
|
||||
|
||||
double v2x = (double)v1->x;
|
||||
double v2y = (double)v1->y;
|
||||
double v2dx = (double)(v2->x - v1->x);
|
||||
double v2dy = (double)(v2->y - v1->y);
|
||||
double v1x = (double)bsp->x;
|
||||
double v1y = (double)bsp->y;
|
||||
double v1dx = (double)bsp->dx;
|
||||
double v1dy = (double)bsp->dy;
|
||||
|
||||
den = v1dy*v2dx - v1dx*v2dy;
|
||||
|
||||
if (den == 0)
|
||||
return false; // parallel
|
||||
|
||||
num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
|
||||
frac = num / den;
|
||||
|
||||
if (frac < 0. || frac > 1.) return false;
|
||||
|
||||
v->x = xs_RoundToInt(v2x + frac * v2dx);
|
||||
v->y = xs_RoundToInt(v2y + frac * v2dy);
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
double PartitionDistance(FCoverageVertex *vt, node_t *node)
|
||||
{
|
||||
return fabs(double(-node->dy) * (vt->x - node->x) + double(node->dx) * (vt->y - node->y)) / node->len;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int PointOnSide(FCoverageVertex *vt, node_t *node)
|
||||
{
|
||||
return R_PointOnSide(vt->x, vt->y, node);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// adapted from polyobject splitter
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void CollectNode(void *node, TArray<FCoverageVertex> &shape)
|
||||
{
|
||||
static TArray<FCoverageLine> lists[2];
|
||||
const double COVERAGE_EPSILON = 6.; // same epsilon as the node builder
|
||||
|
||||
if (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
node_t *bsp = (node_t *)node;
|
||||
|
||||
int centerside = R_PointOnSide(center.x, center.y, bsp);
|
||||
|
||||
lists[0].Clear();
|
||||
lists[1].Clear();
|
||||
for(unsigned i=0;i<shape.Size(); i++)
|
||||
{
|
||||
FCoverageVertex *v1 = &shape[i];
|
||||
FCoverageVertex *v2 = &shape[(i+1) % shape.Size()];
|
||||
FCoverageLine vl = {{*v1, *v2}};
|
||||
|
||||
double dist_v1 = PartitionDistance(v1, bsp);
|
||||
double dist_v2 = PartitionDistance(v2, bsp);
|
||||
|
||||
if(dist_v1 <= COVERAGE_EPSILON)
|
||||
{
|
||||
if (dist_v2 <= COVERAGE_EPSILON)
|
||||
{
|
||||
lists[centerside].Push(vl);
|
||||
}
|
||||
else
|
||||
{
|
||||
int side = PointOnSide(v2, bsp);
|
||||
lists[side].Push(vl);
|
||||
}
|
||||
}
|
||||
else if (dist_v2 <= COVERAGE_EPSILON)
|
||||
{
|
||||
int side = PointOnSide(v1, bsp);
|
||||
lists[side].Push(vl);
|
||||
}
|
||||
else
|
||||
{
|
||||
int side1 = PointOnSide(v1, bsp);
|
||||
int side2 = PointOnSide(v2, bsp);
|
||||
|
||||
if(side1 != side2)
|
||||
{
|
||||
// if the partition line crosses this seg, we must split it.
|
||||
|
||||
FCoverageVertex vert;
|
||||
|
||||
if (GetIntersection(v1, v2, bsp, &vert))
|
||||
{
|
||||
lists[0].Push(vl);
|
||||
lists[1].Push(vl);
|
||||
lists[side1].Last().v[1] = vert;
|
||||
lists[side2].Last().v[0] = vert;
|
||||
}
|
||||
else
|
||||
{
|
||||
// should never happen
|
||||
lists[side1].Push(vl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// both points on the same side.
|
||||
lists[side1].Push(vl);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lists[1].Size() == 0)
|
||||
{
|
||||
CollectNode(bsp->children[0], shape);
|
||||
}
|
||||
else if (lists[0].Size() == 0)
|
||||
{
|
||||
CollectNode(bsp->children[1], shape);
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy the static arrays into local ones
|
||||
TArray<FCoverageVertex> locallists[2];
|
||||
|
||||
for(int l=0;l<2;l++)
|
||||
{
|
||||
for (unsigned i=0;i<lists[l].Size(); i++)
|
||||
{
|
||||
locallists[l].Push(lists[l][i].v[0]);
|
||||
unsigned i1= (i+1)%lists[l].Size();
|
||||
if (lists[l][i1].v[0] != lists[l][i].v[1])
|
||||
{
|
||||
locallists[l].Push(lists[l][i].v[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CollectNode(bsp->children[0], locallists[0]);
|
||||
CollectNode(bsp->children[1], locallists[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we reached a subsector so we can link the node with this subsector
|
||||
subsector_t *sub = (subsector_t *)((BYTE *)node - 1);
|
||||
collect.Push(int(sub-subsectors));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Calculate portal coverage for a single subsector
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_BuildPortalCoverage(FPortalCoverage *coverage, subsector_t *subsector, FPortal *portal)
|
||||
{
|
||||
TArray<FCoverageVertex> shape;
|
||||
double centerx=0, centery=0;
|
||||
|
||||
shape.Resize(subsector->numlines);
|
||||
for(unsigned i=0; i<subsector->numlines; i++)
|
||||
{
|
||||
centerx += (shape[i].x = subsector->firstline[i].v1->x + portal->xDisplacement);
|
||||
centery += (shape[i].y = subsector->firstline[i].v1->y + portal->yDisplacement);
|
||||
}
|
||||
|
||||
FCoverageBuilder build(subsector, portal);
|
||||
build.center.x = xs_CRoundToInt(centerx / subsector->numlines);
|
||||
build.center.y = xs_CRoundToInt(centery / subsector->numlines);
|
||||
|
||||
build.CollectNode(nodes + numnodes - 1, shape);
|
||||
coverage->subsectors = new DWORD[build.collect.Size()];
|
||||
coverage->sscount = build.collect.Size();
|
||||
memcpy(coverage->subsectors, &build.collect[0], build.collect.Size() * sizeof(DWORD));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// portal initialization
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void CollectPortalSectors(FPortalMap &collection)
|
||||
{
|
||||
for (int i=0;i<numsectors;i++)
|
||||
{
|
||||
sector_t *sec = §ors[i];
|
||||
if (sec->CeilingSkyBox != NULL && sec->CeilingSkyBox->bAlways && sec->CeilingSkyBox->Mate != NULL)
|
||||
{
|
||||
FPortalID id = { sec->CeilingSkyBox->x - sec->CeilingSkyBox->Mate->x,
|
||||
sec->CeilingSkyBox->y - sec->CeilingSkyBox->Mate->y};
|
||||
|
||||
FPortalSectors &sss = collection[id];
|
||||
FPortalSector ss = { sec, sector_t::ceiling };
|
||||
sss.Push(ss);
|
||||
}
|
||||
|
||||
if (sec->FloorSkyBox != NULL && sec->FloorSkyBox->bAlways && sec->FloorSkyBox->Mate != NULL)
|
||||
{
|
||||
FPortalID id = { sec->FloorSkyBox->x - sec->FloorSkyBox->Mate->x,
|
||||
sec->FloorSkyBox->y - sec->FloorSkyBox->Mate->y };
|
||||
|
||||
FPortalSectors &sss = collection[id];
|
||||
FPortalSector ss = { sec, sector_t::floor };
|
||||
sss.Push(ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_InitPortals()
|
||||
{
|
||||
FPortalMap collection;
|
||||
|
||||
if (numnodes == 0) return;
|
||||
|
||||
for(int i=0;i<numnodes;i++)
|
||||
{
|
||||
node_t *no = &nodes[i];
|
||||
double fdx = (double)no->dx;
|
||||
double fdy = (double)no->dy;
|
||||
no->len = (float)sqrt(fdx * fdx + fdy * fdy);
|
||||
}
|
||||
|
||||
CollectPortalSectors(collection);
|
||||
portals.Clear();
|
||||
|
||||
FPortalMap::Iterator it(collection);
|
||||
FPortalMap::Pair *pair;
|
||||
int c = 0;
|
||||
int planeflags = 0;
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
for(unsigned i=0;i<pair->Value.Size(); i++)
|
||||
{
|
||||
if (pair->Value[i].mPlane == sector_t::floor) planeflags |= 1;
|
||||
else if (pair->Value[i].mPlane == sector_t::ceiling) planeflags |= 2;
|
||||
}
|
||||
for (int i=1;i<=2;i<<=1)
|
||||
{
|
||||
// For now, add separate portals for floor and ceiling. They can be merged once
|
||||
// proper plane clipping is in.
|
||||
if (planeflags & i)
|
||||
{
|
||||
FPortal *portal = new FPortal;
|
||||
portal->xDisplacement = pair->Key.mXDisplacement;
|
||||
portal->yDisplacement = pair->Key.mYDisplacement;
|
||||
portal->plane = (i==1? sector_t::floor : sector_t::ceiling); /**/
|
||||
portal->glportal = NULL;
|
||||
portals.Push(portal);
|
||||
for(unsigned j=0;j<pair->Value.Size(); j++)
|
||||
{
|
||||
sector_t *sec = pair->Value[j].mSub;
|
||||
int plane = pair->Value[j].mPlane;
|
||||
if (portal->plane == plane)
|
||||
{
|
||||
for(int k=0;k<sec->subsectorcount; k++)
|
||||
{
|
||||
subsector_t *sub = sec->subsectors[k];
|
||||
gl_BuildPortalCoverage(&sub->portalcoverage[plane], sub, portal);
|
||||
}
|
||||
sec->portals[plane] = portal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCMD(dumpportals)
|
||||
{
|
||||
for(unsigned i=0;i<portals.Size(); i++)
|
||||
{
|
||||
double xdisp = portals[i]->xDisplacement/65536.;
|
||||
double ydisp = portals[i]->yDisplacement/65536.;
|
||||
Printf(PRINT_LOG, "Portal #%d, %s, displacement = (%f,%f)\n", i, portals[i]->plane==0? "floor":"ceiling",
|
||||
xdisp, ydisp);
|
||||
Printf(PRINT_LOG, "Coverage:\n");
|
||||
for(int j=0;j<numsubsectors;j++)
|
||||
{
|
||||
subsector_t *sub = &subsectors[j];
|
||||
FPortal *port = sub->render_sector->portals[portals[i]->plane];
|
||||
if (port == portals[i])
|
||||
{
|
||||
Printf(PRINT_LOG, "\tSubsector %d (%d):\n\t\t", j, sub->render_sector->sectornum);
|
||||
for(unsigned k = 0;k< sub->numlines; k++)
|
||||
{
|
||||
Printf(PRINT_LOG, "(%.3f,%.3f), ", sub->firstline[k].v1->x/65536. + xdisp, sub->firstline[k].v1->y/65536. + ydisp);
|
||||
}
|
||||
Printf(PRINT_LOG, "\n\t\tCovered by subsectors:\n");
|
||||
FPortalCoverage *cov = &sub->portalcoverage[portals[i]->plane];
|
||||
for(int l = 0;l< cov->sscount; l++)
|
||||
{
|
||||
subsector_t *csub = &subsectors[cov->subsectors[l]];
|
||||
Printf(PRINT_LOG, "\t\t\t%5d (%4d): ", cov->subsectors[l], csub->render_sector->sectornum);
|
||||
for(unsigned m = 0;m< csub->numlines; m++)
|
||||
{
|
||||
Printf(PRINT_LOG, "(%.3f,%.3f), ", csub->firstline[m].v1->x/65536., csub->firstline[m].v1->y/65536.);
|
||||
}
|
||||
Printf(PRINT_LOG, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
751
src/gl/data/gl_setup.cpp
Normal file
751
src/gl/data/gl_setup.cpp
Normal file
|
@ -0,0 +1,751 @@
|
|||
/*
|
||||
** gl_setup.cpp
|
||||
** Initializes the data structures required by the GL renderer to handle
|
||||
** a level
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "doomtype.h"
|
||||
#include "colormatcher.h"
|
||||
#include "i_system.h"
|
||||
#include "p_local.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "r_sky.h"
|
||||
#include "sc_man.h"
|
||||
#include "w_wad.h"
|
||||
#include "gi.h"
|
||||
#include "p_setup.h"
|
||||
#include "g_level.h"
|
||||
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/dynlights/gl_dynlight.h"
|
||||
#include "gl/dynlights/gl_glow.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/gl_functions.h"
|
||||
|
||||
void InitGLRMapinfoData();
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void DoSetMapSection(subsector_t *sub, int num)
|
||||
{
|
||||
sub->mapsection = num;
|
||||
|
||||
for(DWORD i=0;i<sub->numlines;i++)
|
||||
{
|
||||
seg_t * seg = sub->firstline + i;
|
||||
|
||||
if (seg->PartnerSeg)
|
||||
{
|
||||
subsector_t * sub2 = seg->PartnerSeg->Subsector;
|
||||
|
||||
if (sub2->mapsection != num)
|
||||
{
|
||||
assert(sub2->mapsection == 0);
|
||||
DoSetMapSection(sub2, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Merge sections. This is needed in case the map contains errors
|
||||
// like overlapping lines resulting in abnormal subsectors.
|
||||
//
|
||||
// This function ensures that any vertex position can only be in one section.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct cvertex_t
|
||||
{
|
||||
fixed_t x, y;
|
||||
|
||||
operator int () const { return ((x>>16)&0xffff) | y; }
|
||||
bool operator!= (const cvertex_t &other) const { return x != other.x || y != other.y; }
|
||||
cvertex_t& operator =(const vertex_t *v) { x = v->x; y = v->y; return *this; }
|
||||
};
|
||||
|
||||
typedef TMap<cvertex_t, int> FSectionVertexMap;
|
||||
|
||||
static int MergeMapSections(int num)
|
||||
{
|
||||
FSectionVertexMap vmap;
|
||||
FSectionVertexMap::Pair *pair;
|
||||
TArray<int> sectmap;
|
||||
TArray<bool> sectvalid;
|
||||
sectmap.Resize(num);
|
||||
sectvalid.Resize(num);
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
sectmap[i] = -1;
|
||||
sectvalid[i] = true;
|
||||
}
|
||||
int mergecount = 1;
|
||||
|
||||
|
||||
cvertex_t vt;
|
||||
|
||||
// first step: Set mapsection for all vertex positions.
|
||||
for(DWORD i=0;i<(DWORD)numsegs;i++)
|
||||
{
|
||||
seg_t * seg = &segs[i];
|
||||
int section = seg->Subsector->mapsection;
|
||||
for(int j=0;j<2;j++)
|
||||
{
|
||||
vt = j==0? seg->v1:seg->v2;
|
||||
vmap[vt] = section;
|
||||
}
|
||||
}
|
||||
|
||||
// second step: Check if any seg references more than one mapsection, either by subsector or by vertex
|
||||
for(DWORD i=0;i<(DWORD)numsegs;i++)
|
||||
{
|
||||
seg_t * seg = &segs[i];
|
||||
int section = seg->Subsector->mapsection;
|
||||
for(int j=0;j<2;j++)
|
||||
{
|
||||
vt = j==0? seg->v1:seg->v2;
|
||||
int vsection = vmap[vt];
|
||||
|
||||
if (vsection != section)
|
||||
{
|
||||
// These 2 sections should be merged
|
||||
for(int k=0;k<numsubsectors;k++)
|
||||
{
|
||||
if (subsectors[k].mapsection == vsection) subsectors[k].mapsection = section;
|
||||
}
|
||||
FSectionVertexMap::Iterator it(vmap);
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
if (pair->Value == vsection) pair->Value = section;
|
||||
}
|
||||
sectvalid[vsection-1] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
if (sectvalid[i]) sectmap[i] = mergecount++;
|
||||
}
|
||||
for(int i=0;i<numsubsectors;i++)
|
||||
{
|
||||
subsectors[i].mapsection = sectmap[subsectors[i].mapsection-1];
|
||||
assert(subsectors[i].mapsection!=-1);
|
||||
}
|
||||
return mergecount-1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void SetMapSections()
|
||||
{
|
||||
bool set;
|
||||
int num = 0;
|
||||
do
|
||||
{
|
||||
set = false;
|
||||
for(int i=0; i<numsubsectors; i++)
|
||||
{
|
||||
if (subsectors[i].mapsection == 0)
|
||||
{
|
||||
num++;
|
||||
DoSetMapSection(&subsectors[i], num);
|
||||
set = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (set);
|
||||
num = MergeMapSections(num);
|
||||
currentmapsection.Resize(1 + num/8);
|
||||
#ifdef DEBUG
|
||||
Printf("%d map sections found\n", num);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// prepare subsectors for GL rendering
|
||||
// - analyze rendering hacks using open sectors
|
||||
// - assign a render sector (for self referencing sectors)
|
||||
// - calculate a bounding box
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void SpreadHackedFlag(subsector_t * sub)
|
||||
{
|
||||
// The subsector pointer hasn't been set yet!
|
||||
for(DWORD i=0;i<sub->numlines;i++)
|
||||
{
|
||||
seg_t * seg = sub->firstline + i;
|
||||
|
||||
if (seg->PartnerSeg)
|
||||
{
|
||||
subsector_t * sub2 = seg->PartnerSeg->Subsector;
|
||||
|
||||
if (!(sub2->hacked&1) && sub2->render_sector == sub->render_sector)
|
||||
{
|
||||
sub2->hacked|=1;
|
||||
sub->hacked &= ~4;
|
||||
SpreadHackedFlag (sub2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void PrepareSectorData()
|
||||
{
|
||||
int i;
|
||||
TArray<subsector_t *> undetermined;
|
||||
subsector_t * ss;
|
||||
|
||||
// now group the subsectors by sector
|
||||
subsector_t ** subsectorbuffer = new subsector_t * [numsubsectors];
|
||||
|
||||
for(i=0, ss=subsectors; i<numsubsectors; i++, ss++)
|
||||
{
|
||||
ss->render_sector->subsectorcount++;
|
||||
}
|
||||
|
||||
for (i=0; i<numsectors; i++)
|
||||
{
|
||||
sectors[i].subsectors = subsectorbuffer;
|
||||
subsectorbuffer += sectors[i].subsectorcount;
|
||||
sectors[i].subsectorcount = 0;
|
||||
}
|
||||
|
||||
for(i=0, ss = subsectors; i<numsubsectors; i++, ss++)
|
||||
{
|
||||
ss->render_sector->subsectors[ss->render_sector->subsectorcount++]=ss;
|
||||
}
|
||||
|
||||
// marks all malformed subsectors so rendering tricks using them can be handled more easily
|
||||
for (i = 0; i < numsubsectors; i++)
|
||||
{
|
||||
if (subsectors[i].sector == subsectors[i].render_sector)
|
||||
{
|
||||
seg_t * seg = subsectors[i].firstline;
|
||||
for(DWORD j=0;j<subsectors[i].numlines;j++)
|
||||
{
|
||||
if (!(subsectors[i].hacked&1) && seg[j].linedef==0 &&
|
||||
seg[j].PartnerSeg!=NULL &&
|
||||
subsectors[i].render_sector != seg[j].PartnerSeg->Subsector->render_sector)
|
||||
{
|
||||
DPrintf("Found hack: (%d,%d) (%d,%d)\n", seg[j].v1->x>>16, seg[j].v1->y>>16, seg[j].v2->x>>16, seg[j].v2->y>>16);
|
||||
subsectors[i].hacked|=5;
|
||||
SpreadHackedFlag(&subsectors[i]);
|
||||
}
|
||||
if (seg[j].PartnerSeg==NULL) subsectors[i].hacked|=2; // used for quick termination checks
|
||||
}
|
||||
}
|
||||
}
|
||||
SetMapSections();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Some processing for transparent door hacks using a floor raised by 1 map unit
|
||||
// - This will be used to lower the floor of such sectors by one map unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void PrepareTransparentDoors(sector_t * sector)
|
||||
{
|
||||
bool solidwall=false;
|
||||
int notextures=0;
|
||||
int nobtextures=0;
|
||||
int selfref=0;
|
||||
int i;
|
||||
sector_t * nextsec=NULL;
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (sector-sectors==2)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
P_Recalculate3DFloors(sector);
|
||||
if (sector->subsectorcount==0) return;
|
||||
|
||||
sector->transdoorheight=sector->GetPlaneTexZ(sector_t::floor);
|
||||
sector->transdoor= !(sector->e->XFloor.ffloors.Size() || sector->heightsec || sector->floorplane.a || sector->floorplane.b);
|
||||
|
||||
if (sector->transdoor)
|
||||
{
|
||||
for (i=0; i<sector->linecount; i++)
|
||||
{
|
||||
if (sector->lines[i]->frontsector==sector->lines[i]->backsector)
|
||||
{
|
||||
selfref++;
|
||||
continue;
|
||||
}
|
||||
|
||||
sector_t * sec=getNextSector(sector->lines[i], sector);
|
||||
if (sec==NULL)
|
||||
{
|
||||
solidwall=true;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextsec=sec;
|
||||
|
||||
int side = sector->lines[i]->sidedef[0]->sector == sec;
|
||||
|
||||
if (sector->GetPlaneTexZ(sector_t::floor)!=sec->GetPlaneTexZ(sector_t::floor)+FRACUNIT)
|
||||
{
|
||||
sector->transdoor=false;
|
||||
return;
|
||||
}
|
||||
if (!sector->lines[i]->sidedef[1-side]->GetTexture(side_t::top).isValid()) notextures++;
|
||||
if (!sector->lines[i]->sidedef[1-side]->GetTexture(side_t::bottom).isValid()) nobtextures++;
|
||||
}
|
||||
}
|
||||
if (sector->GetTexture(sector_t::ceiling)==skyflatnum)
|
||||
{
|
||||
sector->transdoor=false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (selfref+nobtextures!=sector->linecount)
|
||||
{
|
||||
sector->transdoor=false;
|
||||
}
|
||||
|
||||
if (selfref+notextures!=sector->linecount)
|
||||
{
|
||||
// This is a crude attempt to fix an incorrect transparent door effect I found in some
|
||||
// WolfenDoom maps but considering the amount of code required to handle it I left it in.
|
||||
// Do this only if the sector only contains one-sided walls or ones with no lower texture.
|
||||
if (solidwall)
|
||||
{
|
||||
if (solidwall+nobtextures+selfref==sector->linecount && nextsec)
|
||||
{
|
||||
sector->heightsec=nextsec;
|
||||
sector->heightsec->MoreFlags=0;
|
||||
}
|
||||
sector->transdoor=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void AddToVertex(const sector_t * sec, TArray<int> & list)
|
||||
{
|
||||
int secno = int(sec-sectors);
|
||||
|
||||
for(unsigned i=0;i<list.Size();i++)
|
||||
{
|
||||
if (list[i]==secno) return;
|
||||
}
|
||||
list.Push(secno);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Attach sectors to vertices - used to generate vertex height lists
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void InitVertexData()
|
||||
{
|
||||
TArray<int> * vt_sectorlists;
|
||||
|
||||
int i,j,k;
|
||||
unsigned int l;
|
||||
|
||||
vt_sectorlists = new TArray<int>[numvertexes];
|
||||
|
||||
|
||||
for(i=0;i<numlines;i++)
|
||||
{
|
||||
line_t * line = &lines[i];
|
||||
|
||||
for(j=0;j<2;j++)
|
||||
{
|
||||
vertex_t * v = j==0? line->v1 : line->v2;
|
||||
|
||||
for(k=0;k<2;k++)
|
||||
{
|
||||
sector_t * sec = k==0? line->frontsector : line->backsector;
|
||||
|
||||
if (sec)
|
||||
{
|
||||
extsector_t::xfloor &x = sec->e->XFloor;
|
||||
|
||||
AddToVertex(sec, vt_sectorlists[v-vertexes]);
|
||||
if (sec->heightsec) AddToVertex(sec->heightsec, vt_sectorlists[v-vertexes]);
|
||||
|
||||
for(l=0;l<x.ffloors.Size();l++)
|
||||
{
|
||||
F3DFloor * rover = x.ffloors[l];
|
||||
if(!(rover->flags & FF_EXISTS)) continue;
|
||||
if (rover->flags&FF_NOSHADE) continue; // FF_NOSHADE doesn't create any wall splits
|
||||
|
||||
AddToVertex(rover->model, vt_sectorlists[v-vertexes]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<numvertexes;i++)
|
||||
{
|
||||
int cnt = vt_sectorlists[i].Size();
|
||||
|
||||
vertexes[i].dirty = true;
|
||||
vertexes[i].numheights=0;
|
||||
if (cnt>1)
|
||||
{
|
||||
vertexes[i].numsectors= cnt;
|
||||
vertexes[i].sectors=new sector_t*[cnt];
|
||||
vertexes[i].heightlist = new float[cnt*2];
|
||||
for(int j=0;j<cnt;j++)
|
||||
{
|
||||
vertexes[i].sectors[j] = §ors[vt_sectorlists[i][j]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vertexes[i].numsectors=0;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] vt_sectorlists;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void GetSideVertices(int sdnum, FVector2 *v1, FVector2 *v2)
|
||||
{
|
||||
line_t *ln = sides[sdnum].linedef;
|
||||
if (ln->sidedef[0] == &sides[sdnum])
|
||||
{
|
||||
v1->X = ln->v1->fx;
|
||||
v1->Y = ln->v1->fy;
|
||||
v2->X = ln->v2->fx;
|
||||
v2->Y = ln->v2->fy;
|
||||
}
|
||||
else
|
||||
{
|
||||
v2->X = ln->v1->fx;
|
||||
v2->Y = ln->v1->fy;
|
||||
v1->X = ln->v2->fx;
|
||||
v1->Y = ln->v2->fy;
|
||||
}
|
||||
}
|
||||
|
||||
static int STACK_ARGS segcmp(const void *a, const void *b)
|
||||
{
|
||||
seg_t *A = *(seg_t**)a;
|
||||
seg_t *B = *(seg_t**)b;
|
||||
return xs_RoundToInt(FRACUNIT*(A->sidefrac - B->sidefrac));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Group segs to sidedefs
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void PrepareSegs()
|
||||
{
|
||||
int *segcount = new int[numsides];
|
||||
int realsegs = 0;
|
||||
|
||||
// Get floatng point coordinates of vertices
|
||||
for(int i = 0; i < numvertexes; i++)
|
||||
{
|
||||
vertexes[i].fx = FIXED2FLOAT(vertexes[i].x);
|
||||
vertexes[i].fy = FIXED2FLOAT(vertexes[i].y);
|
||||
vertexes[i].dirty = true;
|
||||
}
|
||||
|
||||
// count the segs
|
||||
memset(segcount, 0, numsides * sizeof(int));
|
||||
|
||||
// set up the extra data in case the map was loaded with regular nodes that might pass as GL nodes.
|
||||
if (glsegextras == NULL)
|
||||
{
|
||||
for(int i=0;i<numsegs;i++)
|
||||
{
|
||||
segs[i].PartnerSeg = NULL;
|
||||
}
|
||||
for (int i=0; i<numsubsectors; i++)
|
||||
{
|
||||
int seg = int(subsectors[i].firstline-segs);
|
||||
for(DWORD j=0;j<subsectors[i].numlines;j++)
|
||||
{
|
||||
segs[j+seg].Subsector = &subsectors[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i=0;i<numsegs;i++)
|
||||
{
|
||||
seg_t *seg = &segs[i];
|
||||
|
||||
// Account for ZDoom space optimizations that cannot be done for GL
|
||||
unsigned int partner= glsegextras[i].PartnerSeg;
|
||||
if (partner < unsigned(numsegs)) seg->PartnerSeg = &segs[partner];
|
||||
else seg->PartnerSeg = NULL;
|
||||
seg->Subsector = glsegextras[i].Subsector;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0;i<numsegs;i++)
|
||||
{
|
||||
seg_t *seg = &segs[i];
|
||||
|
||||
if (seg->sidedef == NULL) continue; // miniseg
|
||||
int sidenum = int(seg->sidedef - sides);
|
||||
|
||||
realsegs++;
|
||||
segcount[sidenum]++;
|
||||
FVector2 sidestart, sideend, segend(seg->v2->fx, seg->v2->fy);
|
||||
GetSideVertices(sidenum, &sidestart, &sideend);
|
||||
|
||||
sideend -=sidestart;
|
||||
segend -= sidestart;
|
||||
|
||||
seg->sidefrac = float(segend.Length() / sideend.Length());
|
||||
}
|
||||
|
||||
// allocate memory
|
||||
sides[0].segs = new seg_t*[realsegs];
|
||||
sides[0].numsegs = 0;
|
||||
|
||||
for(int i = 1; i < numsides; i++)
|
||||
{
|
||||
sides[i].segs = sides[i-1].segs + segcount[i-1];
|
||||
sides[i].numsegs = 0;
|
||||
}
|
||||
delete [] segcount;
|
||||
|
||||
// assign the segs
|
||||
for(int i=0;i<numsegs;i++)
|
||||
{
|
||||
seg_t *seg = &segs[i];
|
||||
if (seg->sidedef != NULL) seg->sidedef->segs[seg->sidedef->numsegs++] = seg;
|
||||
}
|
||||
|
||||
// sort the segs
|
||||
for(int i = 0; i < numsides; i++)
|
||||
{
|
||||
if (sides[i].numsegs > 1) qsort(sides[i].segs, sides[i].numsegs, sizeof(seg_t*), segcmp);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Initialize the level data for the GL renderer
|
||||
//
|
||||
//==========================================================================
|
||||
extern int restart;
|
||||
|
||||
void gl_PreprocessLevel()
|
||||
{
|
||||
int i;
|
||||
|
||||
PrepareSegs();
|
||||
PrepareSectorData();
|
||||
InitVertexData();
|
||||
int *checkmap = new int[numvertexes];
|
||||
memset(checkmap, -1, sizeof(int)*numvertexes);
|
||||
for(i=0;i<numsectors;i++)
|
||||
{
|
||||
sectors[i].sectornum = i;
|
||||
PrepareTransparentDoors(§ors[i]);
|
||||
|
||||
// This ignores vertices only used for seg splitting because those aren't needed here
|
||||
for(int j = 0; j < sectors[i].linecount; j++)
|
||||
{
|
||||
line_t *l = sectors[i].lines[j];
|
||||
if (l->sidedef[0]->Flags & WALLF_POLYOBJ) continue; // don't bother with polyobjects
|
||||
|
||||
int vtnum1 = int(l->v1 - vertexes);
|
||||
int vtnum2 = int(l->v2 - vertexes);
|
||||
|
||||
if (checkmap[vtnum1] < i)
|
||||
{
|
||||
checkmap[vtnum1] = i;
|
||||
sectors[i].e->vertices.Push(&vertexes[vtnum1]);
|
||||
vertexes[vtnum1].dirty = true;
|
||||
}
|
||||
|
||||
if (checkmap[vtnum2] < i)
|
||||
{
|
||||
checkmap[vtnum2] = i;
|
||||
sectors[i].e->vertices.Push(&vertexes[vtnum2]);
|
||||
vertexes[vtnum2].dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] checkmap;
|
||||
|
||||
gl_InitPortals();
|
||||
|
||||
if (GLRenderer != NULL)
|
||||
{
|
||||
GLRenderer->SetupLevel();
|
||||
}
|
||||
|
||||
#if 0
|
||||
gl_CreateSections();
|
||||
#endif
|
||||
|
||||
InitGLRMapinfoData();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Cleans up all the GL data for the last level
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_CleanLevelData()
|
||||
{
|
||||
// Dynamic lights must be destroyed before the sector information here is deleted.
|
||||
TThinkerIterator<ADynamicLight> it(STAT_DLIGHT);
|
||||
AActor * mo=it.Next();
|
||||
while (mo)
|
||||
{
|
||||
AActor * next = it.Next();
|
||||
mo->Destroy();
|
||||
mo=next;
|
||||
}
|
||||
|
||||
if (vertexes != NULL)
|
||||
{
|
||||
for(int i = 0; i < numvertexes; i++) if (vertexes[i].numsectors > 0)
|
||||
{
|
||||
if (vertexes[i].sectors != NULL)
|
||||
{
|
||||
delete [] vertexes[i].sectors;
|
||||
vertexes[i].sectors = NULL;
|
||||
}
|
||||
if (vertexes[i].heightlist != NULL)
|
||||
{
|
||||
delete [] vertexes[i].heightlist;
|
||||
vertexes[i].heightlist = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sides && sides[0].segs)
|
||||
{
|
||||
delete [] sides[0].segs;
|
||||
sides[0].segs = NULL;
|
||||
}
|
||||
if (sectors && sectors[0].subsectors)
|
||||
{
|
||||
delete [] sectors[0].subsectors;
|
||||
sectors[0].subsectors = NULL;
|
||||
}
|
||||
for (int i=0;i<numsubsectors;i++)
|
||||
{
|
||||
for(int j=0;j<2;j++)
|
||||
{
|
||||
if (subsectors[i].portalcoverage[j].subsectors != NULL)
|
||||
{
|
||||
delete [] subsectors[i].portalcoverage[j].subsectors;
|
||||
subsectors[i].portalcoverage[j].subsectors = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(unsigned i=0;i<portals.Size(); i++)
|
||||
{
|
||||
delete portals[i];
|
||||
}
|
||||
portals.Clear();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD(listmapsections)
|
||||
{
|
||||
for(int i=0;i<100;i++)
|
||||
{
|
||||
for (int j=0;j<numsubsectors;j++)
|
||||
{
|
||||
if (subsectors[j].mapsection == i)
|
||||
{
|
||||
Printf("Mapsection %d, sector %d, line %d\n", i, subsectors[j].render_sector->sectornum, int(subsectors[j].firstline->linedef-lines));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
383
src/gl/data/gl_vertexbuffer.cpp
Normal file
383
src/gl/data/gl_vertexbuffer.cpp
Normal file
|
@ -0,0 +1,383 @@
|
|||
/*
|
||||
** glc_vertexbuffer.cpp
|
||||
** Vertex buffer handling.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "doomtype.h"
|
||||
#include "p_local.h"
|
||||
#include "m_argv.h"
|
||||
#include "c_cvars.h"
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Create / destroy the VBO
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FVertexBuffer::FVertexBuffer()
|
||||
{
|
||||
vao_id = vbo_id = 0;
|
||||
glGenBuffers(1, &vbo_id);
|
||||
glGenVertexArrays(1, &vao_id);
|
||||
|
||||
}
|
||||
|
||||
FVertexBuffer::~FVertexBuffer()
|
||||
{
|
||||
if (vbo_id != 0)
|
||||
{
|
||||
glDeleteBuffers(1, &vbo_id);
|
||||
}
|
||||
if (vao_id != 0)
|
||||
{
|
||||
glDeleteVertexArrays(1, &vao_id);
|
||||
}
|
||||
}
|
||||
|
||||
void FVertexBuffer::BindVBO()
|
||||
{
|
||||
glBindVertexArray(vao_id);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FFlatVertexBuffer::FFlatVertexBuffer()
|
||||
: FVertexBuffer()
|
||||
{
|
||||
if (gl.flags & RFL_BUFFER_STORAGE)
|
||||
{
|
||||
unsigned int bytesize = BUFFER_SIZE * sizeof(FFlatVertex);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||||
glBufferStorage(GL_ARRAY_BUFFER, bytesize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
map = (FFlatVertex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, bytesize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
|
||||
glBindVertexArray(vao_id);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||||
glVertexAttribPointer(VATTR_VERTEX, 3,GL_FLOAT, false, sizeof(FFlatVertex), &VTO->x);
|
||||
glVertexAttribPointer(VATTR_TEXCOORD, 2,GL_FLOAT, false, sizeof(FFlatVertex), &VTO->u);
|
||||
glEnableVertexAttribArray(VATTR_VERTEX);
|
||||
glEnableVertexAttribArray(VATTR_TEXCOORD);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
vbo_shadowdata.Reserve(BUFFER_SIZE);
|
||||
map = &vbo_shadowdata[0];
|
||||
}
|
||||
mNumReserved = mIndex = mCurIndex = 0;
|
||||
}
|
||||
|
||||
FFlatVertexBuffer::~FFlatVertexBuffer()
|
||||
{
|
||||
if (gl.flags & RFL_BUFFER_STORAGE)
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// immediate mode fallback for drivers without GL_ARB_buffer_storage
|
||||
//
|
||||
// No single core method is performant enough to handle this adequately
|
||||
// so we have to resort to immediate mode instead...
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FFlatVertexBuffer::ImmRenderBuffer(unsigned int primtype, unsigned int offset, unsigned int count)
|
||||
{
|
||||
// this will only get called if we can't acquire a persistently mapped buffer.
|
||||
#ifndef CORE_PROFILE
|
||||
glBegin(primtype);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
glVertexAttrib2fv(VATTR_TEXCOORD, &map[offset + i].u);
|
||||
glVertexAttrib3fv(VATTR_VERTEX, &map[offset + i].x);
|
||||
}
|
||||
glEnd();
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Initialize a single vertex
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FFlatVertex::SetFlatVertex(vertex_t *vt, const secplane_t & plane)
|
||||
{
|
||||
x = vt->fx;
|
||||
y = vt->fy;
|
||||
z = plane.ZatPoint(vt->fx, vt->fy);
|
||||
u = vt->fx/64.f;
|
||||
v = -vt->fy/64.f;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Find a 3D floor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static F3DFloor *Find3DFloor(sector_t *target, sector_t *model)
|
||||
{
|
||||
for(unsigned i=0; i<target->e->XFloor.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *ffloor = target->e->XFloor.ffloors[i];
|
||||
if (ffloor->model == model) return ffloor;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates the vertices for one plane in one subsector
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FFlatVertexBuffer::CreateSubsectorVertices(subsector_t *sub, const secplane_t &plane, int floor)
|
||||
{
|
||||
int idx = vbo_shadowdata.Reserve(sub->numlines);
|
||||
for(unsigned int k=0; k<sub->numlines; k++, idx++)
|
||||
{
|
||||
vbo_shadowdata[idx].SetFlatVertex(sub->firstline[k].v1, plane);
|
||||
if (sub->sector->transdoor && floor) vbo_shadowdata[idx].z -= 1.f;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates the vertices for one plane in one subsector
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FFlatVertexBuffer::CreateSectorVertices(sector_t *sec, const secplane_t &plane, int floor)
|
||||
{
|
||||
int rt = vbo_shadowdata.Size();
|
||||
// First calculate the vertices for the sector itself
|
||||
for(int j=0; j<sec->subsectorcount; j++)
|
||||
{
|
||||
subsector_t *sub = sec->subsectors[j];
|
||||
CreateSubsectorVertices(sub, plane, floor);
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FFlatVertexBuffer::CreateVertices(int h, sector_t *sec, const secplane_t &plane, int floor)
|
||||
{
|
||||
// First calculate the vertices for the sector itself
|
||||
sec->vboheight[h] = sec->GetPlaneTexZ(h);
|
||||
sec->vboindex[h] = CreateSectorVertices(sec, plane, floor);
|
||||
|
||||
// Next are all sectors using this one as heightsec
|
||||
TArray<sector_t *> &fakes = sec->e->FakeFloor.Sectors;
|
||||
for (unsigned g=0; g<fakes.Size(); g++)
|
||||
{
|
||||
sector_t *fsec = fakes[g];
|
||||
fsec->vboindex[2+h] = CreateSectorVertices(fsec, plane, false);
|
||||
}
|
||||
|
||||
// and finally all attached 3D floors
|
||||
TArray<sector_t *> &xf = sec->e->XFloor.attached;
|
||||
for (unsigned g=0; g<xf.Size(); g++)
|
||||
{
|
||||
sector_t *fsec = xf[g];
|
||||
F3DFloor *ffloor = Find3DFloor(fsec, sec);
|
||||
|
||||
if (ffloor != NULL && ffloor->flags & FF_RENDERPLANES)
|
||||
{
|
||||
bool dotop = (ffloor->top.model == sec) && (ffloor->top.isceiling == h);
|
||||
bool dobottom = (ffloor->bottom.model == sec) && (ffloor->bottom.isceiling == h);
|
||||
|
||||
if (dotop || dobottom)
|
||||
{
|
||||
if (dotop) ffloor->top.vindex = vbo_shadowdata.Size();
|
||||
if (dobottom) ffloor->bottom.vindex = vbo_shadowdata.Size();
|
||||
|
||||
CreateSectorVertices(fsec, plane, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
sec->vbocount[h] = vbo_shadowdata.Size() - sec->vboindex[h];
|
||||
return sec->vboindex[h];
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FFlatVertexBuffer::CreateFlatVBO()
|
||||
{
|
||||
for (int h = sector_t::floor; h <= sector_t::ceiling; h++)
|
||||
{
|
||||
for(int i=0; i<numsectors;i++)
|
||||
{
|
||||
CreateVertices(h, §ors[i], sectors[i].GetSecPlane(h), h == sector_t::floor);
|
||||
}
|
||||
}
|
||||
|
||||
// We need to do a final check for Vavoom water and FF_FIX sectors.
|
||||
// No new vertices are needed here. The planes come from the actual sector
|
||||
for(int i=0; i<numsectors;i++)
|
||||
{
|
||||
for(unsigned j=0;j<sectors[i].e->XFloor.ffloors.Size(); j++)
|
||||
{
|
||||
F3DFloor *ff = sectors[i].e->XFloor.ffloors[j];
|
||||
|
||||
if (ff->top.model == §ors[i])
|
||||
{
|
||||
ff->top.vindex = sectors[i].vboindex[ff->top.isceiling];
|
||||
}
|
||||
if (ff->bottom.model == §ors[i])
|
||||
{
|
||||
ff->bottom.vindex = sectors[i].vboindex[ff->top.isceiling];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FFlatVertexBuffer::UpdatePlaneVertices(sector_t *sec, int plane)
|
||||
{
|
||||
int startvt = sec->vboindex[plane];
|
||||
int countvt = sec->vbocount[plane];
|
||||
secplane_t &splane = sec->GetSecPlane(plane);
|
||||
FFlatVertex *vt = &vbo_shadowdata[startvt];
|
||||
FFlatVertex *mapvt = &map[startvt];
|
||||
for(int i=0; i<countvt; i++, vt++, mapvt++)
|
||||
{
|
||||
vt->z = splane.ZatPoint(vt->x, vt->y);
|
||||
if (plane == sector_t::floor && sec->transdoor) vt->z -= 1;
|
||||
mapvt->z = vt->z;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FFlatVertexBuffer::CreateVBO()
|
||||
{
|
||||
if (gl.flags & RFL_BUFFER_STORAGE)
|
||||
{
|
||||
vbo_shadowdata.Resize(mNumReserved);
|
||||
CreateFlatVBO();
|
||||
mCurIndex = mIndex = vbo_shadowdata.Size();
|
||||
memcpy(map, &vbo_shadowdata[0], vbo_shadowdata.Size() * sizeof(FFlatVertex));
|
||||
}
|
||||
else if (sectors)
|
||||
{
|
||||
// set all VBO info to invalid values so that we can save some checks in the rendering code
|
||||
for(int i=0;i<numsectors;i++)
|
||||
{
|
||||
sectors[i].vboindex[3] = sectors[i].vboindex[2] =
|
||||
sectors[i].vboindex[1] = sectors[i].vboindex[0] = -1;
|
||||
sectors[i].vboheight[1] = sectors[i].vboheight[0] = FIXED_MIN;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FFlatVertexBuffer::CheckPlanes(sector_t *sector)
|
||||
{
|
||||
if (sector->GetPlaneTexZ(sector_t::ceiling) != sector->vboheight[sector_t::ceiling])
|
||||
{
|
||||
UpdatePlaneVertices(sector, sector_t::ceiling);
|
||||
sector->vboheight[sector_t::ceiling] = sector->GetPlaneTexZ(sector_t::ceiling);
|
||||
}
|
||||
if (sector->GetPlaneTexZ(sector_t::floor) != sector->vboheight[sector_t::floor])
|
||||
{
|
||||
UpdatePlaneVertices(sector, sector_t::floor);
|
||||
sector->vboheight[sector_t::floor] = sector->GetPlaneTexZ(sector_t::floor);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// checks the validity of all planes attached to this sector
|
||||
// and updates them if possible.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FFlatVertexBuffer::CheckUpdate(sector_t *sector)
|
||||
{
|
||||
if (gl.flags & RFL_BUFFER_STORAGE)
|
||||
{
|
||||
CheckPlanes(sector);
|
||||
sector_t *hs = sector->GetHeightSec();
|
||||
if (hs != NULL) CheckPlanes(hs);
|
||||
for (unsigned i = 0; i < sector->e->XFloor.ffloors.Size(); i++)
|
||||
CheckPlanes(sector->e->XFloor.ffloors[i]->model);
|
||||
}
|
||||
}
|
216
src/gl/data/gl_vertexbuffer.h
Normal file
216
src/gl/data/gl_vertexbuffer.h
Normal file
|
@ -0,0 +1,216 @@
|
|||
#ifndef __VERTEXBUFFER_H
|
||||
#define __VERTEXBUFFER_H
|
||||
|
||||
#include "tarray.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/system/gl_interface.h"
|
||||
|
||||
struct vertex_t;
|
||||
struct secplane_t;
|
||||
struct subsector_t;
|
||||
struct sector_t;
|
||||
|
||||
|
||||
class FVertexBuffer
|
||||
{
|
||||
protected:
|
||||
unsigned int vbo_id;
|
||||
unsigned int vao_id;
|
||||
|
||||
public:
|
||||
FVertexBuffer();
|
||||
virtual ~FVertexBuffer();
|
||||
void BindVBO();
|
||||
};
|
||||
|
||||
struct FFlatVertex
|
||||
{
|
||||
float x,z,y; // world position
|
||||
float u,v; // texture coordinates
|
||||
|
||||
void SetFlatVertex(vertex_t *vt, const secplane_t &plane);
|
||||
void Set(float xx, float zz, float yy, float uu, float vv)
|
||||
{
|
||||
x = xx;
|
||||
z = zz;
|
||||
y = yy;
|
||||
u = uu;
|
||||
v = vv;
|
||||
}
|
||||
};
|
||||
|
||||
#define VTO ((FFlatVertex*)NULL)
|
||||
|
||||
|
||||
class FFlatVertexBuffer : public FVertexBuffer
|
||||
{
|
||||
FFlatVertex *map;
|
||||
unsigned int mIndex;
|
||||
unsigned int mCurIndex;
|
||||
unsigned int mNumReserved;
|
||||
|
||||
void CheckPlanes(sector_t *sector);
|
||||
|
||||
static const unsigned int BUFFER_SIZE = 2000000;
|
||||
static const unsigned int BUFFER_SIZE_TO_USE = 1999500;
|
||||
|
||||
void ImmRenderBuffer(unsigned int primtype, unsigned int offset, unsigned int count);
|
||||
|
||||
public:
|
||||
TArray<FFlatVertex> vbo_shadowdata; // this is kept around for updating the actual (non-readable) buffer and as stand-in for pre GL 4.x
|
||||
|
||||
FFlatVertexBuffer();
|
||||
~FFlatVertexBuffer();
|
||||
|
||||
void CreateVBO();
|
||||
void CheckUpdate(sector_t *sector);
|
||||
|
||||
FFlatVertex *GetBuffer()
|
||||
{
|
||||
return &map[mCurIndex];
|
||||
}
|
||||
unsigned int GetCount(FFlatVertex *newptr, unsigned int *poffset)
|
||||
{
|
||||
|
||||
unsigned int newofs = (unsigned int)(newptr - map);
|
||||
unsigned int diff = newofs - mCurIndex;
|
||||
*poffset = mCurIndex;
|
||||
mCurIndex = newofs;
|
||||
if (mCurIndex >= BUFFER_SIZE_TO_USE) mCurIndex = mIndex;
|
||||
return diff;
|
||||
}
|
||||
#ifdef __GL_PCH_H // we need the system includes for this but we cannot include them ourselves without creating #define clashes. The affected files wouldn't try to draw anyway.
|
||||
void RenderArray(unsigned int primtype, unsigned int offset, unsigned int count)
|
||||
{
|
||||
drawcalls.Clock();
|
||||
if (gl.flags & RFL_BUFFER_STORAGE)
|
||||
{
|
||||
glDrawArrays(primtype, offset, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImmRenderBuffer(primtype, offset, count);
|
||||
}
|
||||
drawcalls.Unclock();
|
||||
}
|
||||
|
||||
void RenderCurrent(FFlatVertex *newptr, unsigned int primtype, unsigned int *poffset = NULL, unsigned int *pcount = NULL)
|
||||
{
|
||||
unsigned int offset;
|
||||
unsigned int count = GetCount(newptr, &offset);
|
||||
RenderArray(primtype, offset, count);
|
||||
if (poffset) *poffset = offset;
|
||||
if (pcount) *pcount = count;
|
||||
}
|
||||
|
||||
#endif
|
||||
void Reset()
|
||||
{
|
||||
mCurIndex = mIndex;
|
||||
}
|
||||
|
||||
private:
|
||||
int CreateSubsectorVertices(subsector_t *sub, const secplane_t &plane, int floor);
|
||||
int CreateSectorVertices(sector_t *sec, const secplane_t &plane, int floor);
|
||||
int CreateVertices(int h, sector_t *sec, const secplane_t &plane, int floor);
|
||||
void CreateFlatVBO();
|
||||
void UpdatePlaneVertices(sector_t *sec, int plane);
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct FSkyVertex
|
||||
{
|
||||
float x, y, z, u, v;
|
||||
PalEntry color;
|
||||
|
||||
void Set(float xx, float zz, float yy, float uu=0, float vv=0, PalEntry col=0xffffffff)
|
||||
{
|
||||
x = xx;
|
||||
z = zz;
|
||||
y = yy;
|
||||
u = uu;
|
||||
v = vv;
|
||||
color = col;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class FSkyVertexBuffer : public FVertexBuffer
|
||||
{
|
||||
public:
|
||||
static const int SKYHEMI_UPPER = 1;
|
||||
static const int SKYHEMI_LOWER = 2;
|
||||
|
||||
enum
|
||||
{
|
||||
SKYMODE_MAINLAYER = 0,
|
||||
SKYMODE_SECONDLAYER = 1,
|
||||
SKYMODE_FOGLAYER = 2
|
||||
};
|
||||
|
||||
private:
|
||||
TArray<FSkyVertex> mVertices;
|
||||
TArray<unsigned int> mPrimStart;
|
||||
|
||||
int mRows, mColumns;
|
||||
|
||||
void SkyVertex(int r, int c, bool yflip);
|
||||
void CreateSkyHemisphere(int hemi);
|
||||
void CreateDome();
|
||||
void RenderRow(int prim, int row);
|
||||
|
||||
public:
|
||||
|
||||
FSkyVertexBuffer();
|
||||
virtual ~FSkyVertexBuffer();
|
||||
void RenderDome(FMaterial *tex, int mode);
|
||||
|
||||
};
|
||||
|
||||
#define VSO ((FSkyVertex*)NULL)
|
||||
|
||||
struct FModelVertex
|
||||
{
|
||||
float x, y, z; // world position
|
||||
float u, v; // texture coordinates
|
||||
|
||||
void Set(float xx, float yy, float zz, float uu, float vv)
|
||||
{
|
||||
x = xx;
|
||||
y = yy;
|
||||
z = zz;
|
||||
u = uu;
|
||||
v = vv;
|
||||
}
|
||||
|
||||
void SetNormal(float nx, float ny, float nz)
|
||||
{
|
||||
// GZDoom currently doesn't use normals. This function is so that the high level code can pretend it does.
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class FModelVertexBuffer : public FVertexBuffer
|
||||
{
|
||||
int mIndexFrame[2];
|
||||
unsigned int ibo_id;
|
||||
|
||||
public:
|
||||
|
||||
FModelVertexBuffer(bool needindex);
|
||||
~FModelVertexBuffer();
|
||||
|
||||
FModelVertex *LockVertexBuffer(unsigned int size);
|
||||
void UnlockVertexBuffer();
|
||||
|
||||
unsigned int *LockIndexBuffer(unsigned int size);
|
||||
void UnlockIndexBuffer();
|
||||
|
||||
unsigned int SetupFrame(unsigned int frame1, unsigned int frame2);
|
||||
};
|
||||
|
||||
#define VMO ((FModelVertex*)NULL)
|
||||
|
||||
|
||||
#endif
|
768
src/gl/dynlights/a_dynlight.cpp
Normal file
768
src/gl/dynlights/a_dynlight.cpp
Normal file
|
@ -0,0 +1,768 @@
|
|||
/*
|
||||
** a_dynlight.cpp
|
||||
** Implements actors representing dynamic lights (hardware independent)
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2003 Timothy Stump
|
||||
** Copyright 2005 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.
|
||||
** 4. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "templates.h"
|
||||
#include "m_random.h"
|
||||
#include "p_local.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "g_level.h"
|
||||
#include "thingdef/thingdef.h"
|
||||
#include "i_system.h"
|
||||
|
||||
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/dynlights/gl_dynlight.h"
|
||||
#include "gl/utility/gl_convert.h"
|
||||
#include "gl/utility/gl_templates.h"
|
||||
|
||||
EXTERN_CVAR (Float, gl_lights_size);
|
||||
EXTERN_CVAR (Bool, gl_lights_additive);
|
||||
EXTERN_CVAR(Int, vid_renderer)
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY(type, S, DynamicLight)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
static const char * ltype_names[]={
|
||||
"Point","Pulse","Flicker","Sector","RandomFlicker", "ColorPulse", "ColorFlicker", "RandomColorFlicker", NULL};
|
||||
|
||||
static const int ltype_values[]={
|
||||
PointLight, PulseLight, FlickerLight, SectorLight, RandomFlickerLight, ColorPulseLight, ColorFlickerLight, RandomColorFlickerLight };
|
||||
|
||||
int style = MatchString(str, ltype_names);
|
||||
if (style < 0) I_Error("Unknown light type '%s'", str);
|
||||
defaults->lighttype = ltype_values[style];
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Actor classes
|
||||
//
|
||||
// For flexibility all functionality has been packed into a single class
|
||||
// which is controlled by flags
|
||||
//
|
||||
//==========================================================================
|
||||
IMPLEMENT_CLASS (ADynamicLight)
|
||||
IMPLEMENT_CLASS (AVavoomLight)
|
||||
IMPLEMENT_CLASS (AVavoomLightWhite)
|
||||
IMPLEMENT_CLASS (AVavoomLightColor)
|
||||
|
||||
void AVavoomLight::BeginPlay ()
|
||||
{
|
||||
// This must not call Super::BeginPlay!
|
||||
ChangeStatNum(STAT_DLIGHT);
|
||||
if (Sector) z -= Sector->floorplane.ZatPoint(x, y);
|
||||
lighttype = PointLight;
|
||||
}
|
||||
|
||||
void AVavoomLightWhite::BeginPlay ()
|
||||
{
|
||||
m_intensity[0] = args[0] * 4;
|
||||
args[LIGHT_RED] = 128;
|
||||
args[LIGHT_GREEN] = 128;
|
||||
args[LIGHT_BLUE] = 128;
|
||||
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
void AVavoomLightColor::BeginPlay ()
|
||||
{
|
||||
int l_args[5];
|
||||
memcpy(l_args, args, sizeof(l_args));
|
||||
memset(args, 0, sizeof(args));
|
||||
m_intensity[0] = l_args[0] * 4;
|
||||
args[LIGHT_RED] = l_args[1] >> 1;
|
||||
args[LIGHT_GREEN] = l_args[2] >> 1;
|
||||
args[LIGHT_BLUE] = l_args[3] >> 1;
|
||||
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
static FRandom randLight;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Base class
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void ADynamicLight::Serialize(FArchive &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
arc << lightflags << lighttype;
|
||||
arc << m_tickCount << m_currentIntensity;
|
||||
arc << m_intensity[0] << m_intensity[1];
|
||||
|
||||
if (lighttype == PulseLight) arc << m_lastUpdate << m_cycler;
|
||||
if (arc.IsLoading()) LinkLight();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void ADynamicLight::BeginPlay()
|
||||
{
|
||||
//Super::BeginPlay();
|
||||
ChangeStatNum(STAT_DLIGHT);
|
||||
|
||||
m_intensity[0] = args[LIGHT_INTENSITY];
|
||||
m_intensity[1] = args[LIGHT_SECONDARY_INTENSITY];
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void ADynamicLight::PostBeginPlay()
|
||||
{
|
||||
Super::PostBeginPlay();
|
||||
|
||||
if (!(SpawnFlags & MTF_DORMANT))
|
||||
{
|
||||
Activate (NULL);
|
||||
}
|
||||
|
||||
subsector = R_PointInSubsector(x,y);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void ADynamicLight::Activate(AActor *activator)
|
||||
{
|
||||
//Super::Activate(activator);
|
||||
flags2&=~MF2_DORMANT;
|
||||
|
||||
m_currentIntensity = float(m_intensity[0]);
|
||||
m_tickCount = 0;
|
||||
|
||||
if (lighttype == PulseLight)
|
||||
{
|
||||
float pulseTime = ANGLE_TO_FLOAT(this->angle) / TICRATE;
|
||||
|
||||
m_lastUpdate = level.maptime;
|
||||
m_cycler.SetParams(float(m_intensity[1]), float(m_intensity[0]), pulseTime);
|
||||
m_cycler.ShouldCycle(true);
|
||||
m_cycler.SetCycleType(CYCLE_Sin);
|
||||
m_currentIntensity = (BYTE)m_cycler.GetVal();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void ADynamicLight::Deactivate(AActor *activator)
|
||||
{
|
||||
//Super::Deactivate(activator);
|
||||
flags2|=MF2_DORMANT;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void ADynamicLight::Tick()
|
||||
{
|
||||
if (vid_renderer == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (IsOwned())
|
||||
{
|
||||
if (!target || !target->state)
|
||||
{
|
||||
this->Destroy();
|
||||
return;
|
||||
}
|
||||
if (target->flags & MF_UNMORPHED) return;
|
||||
}
|
||||
|
||||
// Don't bother if the light won't be shown
|
||||
if (!IsActive()) return;
|
||||
|
||||
// I am doing this with a type field so that I can dynamically alter the type of light
|
||||
// without having to create or maintain multiple objects.
|
||||
switch(lighttype)
|
||||
{
|
||||
case PulseLight:
|
||||
{
|
||||
float diff = (level.maptime - m_lastUpdate) / (float)TICRATE;
|
||||
|
||||
m_lastUpdate = level.maptime;
|
||||
m_cycler.Update(diff);
|
||||
m_currentIntensity = m_cycler.GetVal();
|
||||
break;
|
||||
}
|
||||
|
||||
case FlickerLight:
|
||||
{
|
||||
BYTE rnd = randLight();
|
||||
float pct = ANGLE_TO_FLOAT(angle)/360.f;
|
||||
|
||||
m_currentIntensity = float(m_intensity[rnd >= pct * 255]);
|
||||
break;
|
||||
}
|
||||
|
||||
case RandomFlickerLight:
|
||||
{
|
||||
int flickerRange = m_intensity[1] - m_intensity[0];
|
||||
float amt = randLight() / 255.f;
|
||||
|
||||
m_tickCount++;
|
||||
|
||||
if (m_tickCount > ANGLE_TO_FLOAT(angle))
|
||||
{
|
||||
m_currentIntensity = float(m_intensity[0] + (amt * flickerRange));
|
||||
m_tickCount = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// These need some more work elsewhere
|
||||
case ColorFlickerLight:
|
||||
{
|
||||
BYTE rnd = randLight();
|
||||
float pct = ANGLE_TO_FLOAT(angle)/360.f;
|
||||
|
||||
m_currentIntensity = m_intensity[rnd >= pct * 255];
|
||||
break;
|
||||
}
|
||||
|
||||
case RandomColorFlickerLight:
|
||||
{
|
||||
int flickerRange = m_intensity[1] - m_intensity[0];
|
||||
float amt = randLight() / 255.f;
|
||||
|
||||
m_tickCount++;
|
||||
|
||||
if (m_tickCount > ANGLE_TO_FLOAT(angle))
|
||||
{
|
||||
m_currentIntensity = m_intensity[0] + (amt * flickerRange);
|
||||
m_tickCount = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case SectorLight:
|
||||
{
|
||||
float intensity;
|
||||
float scale = args[LIGHT_SCALE] / 8.f;
|
||||
|
||||
if (scale == 0.f) scale = 1.f;
|
||||
|
||||
intensity = Sector->lightlevel * scale;
|
||||
intensity = clamp<float>(intensity, 0.f, 255.f);
|
||||
|
||||
m_currentIntensity = intensity;
|
||||
break;
|
||||
}
|
||||
|
||||
case PointLight:
|
||||
m_currentIntensity = float(m_intensity[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateLocation();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void ADynamicLight::UpdateLocation()
|
||||
{
|
||||
fixed_t oldx=x;
|
||||
fixed_t oldy=y;
|
||||
fixed_t oldradius=radius;
|
||||
float intensity;
|
||||
|
||||
if (IsActive())
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
angle_t angle = target->angle>>ANGLETOFINESHIFT;
|
||||
PrevX = x = target->x + FixedMul(m_offX, finecosine[angle]) + FixedMul(m_offZ, finesine[angle]);
|
||||
PrevY = y = target->y + FixedMul(m_offX, finesine[angle]) - FixedMul(m_offZ, finecosine[angle]);
|
||||
PrevZ = z = target->z + m_offY + target->GetBobOffset();
|
||||
subsector = R_PointInSubsector(x, y);
|
||||
Sector = subsector->sector;
|
||||
}
|
||||
|
||||
|
||||
// The radius being used here is always the maximum possible with the
|
||||
// current settings. This avoids constant relinking of flickering lights
|
||||
|
||||
if (lighttype == FlickerLight || lighttype == RandomFlickerLight)
|
||||
{
|
||||
intensity = float(m_intensity[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
intensity = m_currentIntensity;
|
||||
}
|
||||
radius = FLOAT2FIXED(intensity * 2.0f * gl_lights_size);
|
||||
|
||||
if (x!=oldx || y!=oldy || radius!=oldradius)
|
||||
{
|
||||
//Update the light lists
|
||||
LinkLight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void ADynamicLight::SetOffset(fixed_t x, fixed_t y, fixed_t z)
|
||||
{
|
||||
m_offX = x;
|
||||
m_offY = y;
|
||||
m_offZ = z;
|
||||
UpdateLocation();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// The target pointer in dynamic lights should never be substituted unless
|
||||
// notOld is NULL (which indicates that the object was destroyed by force.)
|
||||
//
|
||||
//==========================================================================
|
||||
size_t ADynamicLight::PointerSubstitution (DObject *old, DObject *notOld)
|
||||
{
|
||||
AActor *saved_target = target;
|
||||
size_t ret = Super::PointerSubstitution(old, notOld);
|
||||
if (notOld != NULL) target = saved_target;
|
||||
return ret;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// These have been copied from the secnode code and modified for the light links
|
||||
//
|
||||
// P_AddSecnode() searches the current list to see if this sector is
|
||||
// already there. If not, it adds a sector node at the head of the list of
|
||||
// sectors this object appears in. This is called when creating a list of
|
||||
// nodes that will get linked in later. Returns a pointer to the new node.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FLightNode * AddLightNode(FLightNode ** thread, void * linkto, ADynamicLight * light, FLightNode *& nextnode)
|
||||
{
|
||||
FLightNode * node;
|
||||
|
||||
node = nextnode;
|
||||
while (node)
|
||||
{
|
||||
if (node->targ==linkto) // Already have a node for this sector?
|
||||
{
|
||||
node->lightsource = light; // Yes. Setting m_thing says 'keep it'.
|
||||
return(nextnode);
|
||||
}
|
||||
node = node->nextTarget;
|
||||
}
|
||||
|
||||
// Couldn't find an existing node for this sector. Add one at the head
|
||||
// of the list.
|
||||
|
||||
node = new FLightNode;
|
||||
|
||||
node->targ = linkto;
|
||||
node->lightsource = light;
|
||||
|
||||
node->prevTarget = &nextnode;
|
||||
node->nextTarget = nextnode;
|
||||
|
||||
if (nextnode) nextnode->prevTarget = &node->nextTarget;
|
||||
|
||||
// Add new node at head of sector thread starting at s->touching_thinglist
|
||||
|
||||
node->prevLight = thread;
|
||||
node->nextLight = *thread;
|
||||
if (node->nextLight) node->nextLight->prevLight=&node->nextLight;
|
||||
*thread = node;
|
||||
return(node);
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// P_DelSecnode() deletes a sector node from the list of
|
||||
// sectors this object appears in. Returns a pointer to the next node
|
||||
// on the linked list, or NULL.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static FLightNode * DeleteLightNode(FLightNode * node)
|
||||
{
|
||||
FLightNode * tn; // next node on thing thread
|
||||
|
||||
if (node)
|
||||
{
|
||||
|
||||
*node->prevTarget = node->nextTarget;
|
||||
if (node->nextTarget) node->nextTarget->prevTarget=node->prevTarget;
|
||||
|
||||
*node->prevLight = node->nextLight;
|
||||
if (node->nextLight) node->nextLight->prevLight=node->prevLight;
|
||||
|
||||
// Return this node to the freelist
|
||||
tn=node->nextTarget;
|
||||
delete node;
|
||||
return(tn);
|
||||
}
|
||||
return(NULL);
|
||||
} // phares 3/13/98
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Gets the light's distance to a line
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
float ADynamicLight::DistToSeg(seg_t *seg)
|
||||
{
|
||||
float u, px, py;
|
||||
|
||||
float seg_dx = FIXED2FLOAT(seg->v2->x - seg->v1->x);
|
||||
float seg_dy = FIXED2FLOAT(seg->v2->y - seg->v1->y);
|
||||
float seg_length_sq = seg_dx * seg_dx + seg_dy * seg_dy;
|
||||
|
||||
u = ( FIXED2FLOAT(x - seg->v1->x) * seg_dx + FIXED2FLOAT(y - seg->v1->y) * seg_dy) / seg_length_sq;
|
||||
if (u < 0.f) u = 0.f; // clamp the test point to the line segment
|
||||
if (u > 1.f) u = 1.f;
|
||||
|
||||
px = FIXED2FLOAT(seg->v1->x) + (u * seg_dx);
|
||||
py = FIXED2FLOAT(seg->v1->y) + (u * seg_dy);
|
||||
|
||||
px -= FIXED2FLOAT(x);
|
||||
py -= FIXED2FLOAT(y);
|
||||
|
||||
return (px*px) + (py*py);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Collect all touched sidedefs and subsectors
|
||||
// to sidedefs and sector parts.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ADynamicLight::CollectWithinRadius(subsector_t *subSec, float radius)
|
||||
{
|
||||
if (!subSec) return;
|
||||
|
||||
subSec->validcount = ::validcount;
|
||||
|
||||
touching_subsectors = AddLightNode(&subSec->lighthead, subSec, this, touching_subsectors);
|
||||
if (subSec->sector->validcount != ::validcount)
|
||||
{
|
||||
touching_sector = AddLightNode(&subSec->render_sector->lighthead, subSec->sector, this, touching_sector);
|
||||
subSec->sector->validcount = ::validcount;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < subSec->numlines; i++)
|
||||
{
|
||||
seg_t * seg = subSec->firstline + i;
|
||||
|
||||
if (seg->sidedef && seg->linedef && seg->linedef->validcount!=::validcount)
|
||||
{
|
||||
// light is in front of the seg
|
||||
if (DMulScale32 (y-seg->v1->y, seg->v2->x-seg->v1->x, seg->v1->x-x, seg->v2->y-seg->v1->y) <=0)
|
||||
{
|
||||
seg->linedef->validcount=validcount;
|
||||
touching_sides = AddLightNode(&seg->sidedef->lighthead, seg->sidedef, this, touching_sides);
|
||||
}
|
||||
}
|
||||
|
||||
seg_t *partner = seg->PartnerSeg;
|
||||
if (partner)
|
||||
{
|
||||
subsector_t *sub = partner->Subsector;
|
||||
if (sub != NULL && sub->validcount!=::validcount)
|
||||
{
|
||||
// check distance from x/y to seg and if within radius add opposing subsector (lather/rinse/repeat)
|
||||
if (DistToSeg(seg) <= radius)
|
||||
{
|
||||
CollectWithinRadius(sub, radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Link the light into the world
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ADynamicLight::LinkLight()
|
||||
{
|
||||
// mark the old light nodes
|
||||
FLightNode * node;
|
||||
|
||||
node = touching_sides;
|
||||
while (node)
|
||||
{
|
||||
node->lightsource = NULL;
|
||||
node = node->nextTarget;
|
||||
}
|
||||
node = touching_subsectors;
|
||||
while (node)
|
||||
{
|
||||
node->lightsource = NULL;
|
||||
node = node->nextTarget;
|
||||
}
|
||||
node = touching_sector;
|
||||
while (node)
|
||||
{
|
||||
node->lightsource = NULL;
|
||||
node = node->nextTarget;
|
||||
}
|
||||
|
||||
if (radius>0)
|
||||
{
|
||||
// passing in radius*radius allows us to do a distance check without any calls to sqrtf
|
||||
subsector_t * subSec = R_PointInSubsector(x, y);
|
||||
if (subSec)
|
||||
{
|
||||
float fradius = FIXED2FLOAT(radius);
|
||||
::validcount++;
|
||||
CollectWithinRadius(subSec, fradius*fradius);
|
||||
}
|
||||
}
|
||||
|
||||
// Now delete any nodes that won't be used. These are the ones where
|
||||
// m_thing is still NULL.
|
||||
|
||||
node = touching_sides;
|
||||
while (node)
|
||||
{
|
||||
if (node->lightsource == NULL)
|
||||
{
|
||||
node = DeleteLightNode(node);
|
||||
}
|
||||
else
|
||||
node = node->nextTarget;
|
||||
}
|
||||
|
||||
node = touching_subsectors;
|
||||
while (node)
|
||||
{
|
||||
if (node->lightsource == NULL)
|
||||
{
|
||||
node = DeleteLightNode(node);
|
||||
}
|
||||
else
|
||||
node = node->nextTarget;
|
||||
}
|
||||
|
||||
node = touching_sector;
|
||||
while (node)
|
||||
{
|
||||
if (node->lightsource == NULL)
|
||||
{
|
||||
node = DeleteLightNode(node);
|
||||
}
|
||||
else
|
||||
node = node->nextTarget;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Deletes the link lists
|
||||
//
|
||||
//==========================================================================
|
||||
void ADynamicLight::UnlinkLight ()
|
||||
{
|
||||
if (owned && target != NULL)
|
||||
{
|
||||
// Delete reference in owning actor
|
||||
for(int c=target->dynamiclights.Size()-1; c>=0; c--)
|
||||
{
|
||||
if (target->dynamiclights[c] == this)
|
||||
{
|
||||
target->dynamiclights.Delete(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (touching_sides) touching_sides = DeleteLightNode(touching_sides);
|
||||
while (touching_subsectors) touching_subsectors = DeleteLightNode(touching_subsectors);
|
||||
while (touching_sector) touching_sector = DeleteLightNode(touching_sector);
|
||||
}
|
||||
|
||||
void ADynamicLight::Destroy()
|
||||
{
|
||||
UnlinkLight();
|
||||
Super::Destroy();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Needed for garbage collection
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
size_t AActor::PropagateMark()
|
||||
{
|
||||
for (unsigned i=0; i<dynamiclights.Size(); i++)
|
||||
{
|
||||
GC::Mark(dynamiclights[i]);
|
||||
}
|
||||
return Super::PropagateMark();
|
||||
}
|
||||
|
||||
|
||||
|
||||
CCMD(listlights)
|
||||
{
|
||||
int walls, sectors, subsecs;
|
||||
int allwalls=0, allsectors=0, allsubsecs = 0;
|
||||
int i=0;
|
||||
ADynamicLight * dl;
|
||||
TThinkerIterator<ADynamicLight> it;
|
||||
|
||||
while ((dl=it.Next()))
|
||||
{
|
||||
walls=0;
|
||||
sectors=0;
|
||||
subsecs = 0;
|
||||
Printf("%s at (%f, %f, %f), color = 0x%02x%02x%02x, radius = %f ",
|
||||
dl->target? dl->target->GetClass()->TypeName.GetChars() : dl->GetClass()->TypeName.GetChars(),
|
||||
FIXED2FLOAT(dl->x), FIXED2FLOAT(dl->y), FIXED2FLOAT(dl->z), dl->args[LIGHT_RED],
|
||||
dl->args[LIGHT_GREEN], dl->args[LIGHT_BLUE], FIXED2FLOAT(dl->radius));
|
||||
i++;
|
||||
|
||||
if (dl->target)
|
||||
{
|
||||
FTextureID spr = gl_GetSpriteFrame(dl->target->sprite, dl->target->frame, 0, 0, NULL);
|
||||
Printf(", frame = %s ", TexMan[spr]->Name.GetChars());
|
||||
}
|
||||
|
||||
|
||||
FLightNode * node;
|
||||
|
||||
node=dl->touching_sides;
|
||||
|
||||
while (node)
|
||||
{
|
||||
walls++;
|
||||
allwalls++;
|
||||
node = node->nextTarget;
|
||||
}
|
||||
|
||||
node=dl->touching_subsectors;
|
||||
|
||||
while (node)
|
||||
{
|
||||
allsubsecs++;
|
||||
subsecs++;
|
||||
node = node->nextTarget;
|
||||
}
|
||||
|
||||
node = dl->touching_sector;
|
||||
|
||||
while (node)
|
||||
{
|
||||
allsectors++;
|
||||
sectors++;
|
||||
node = node->nextTarget;
|
||||
}
|
||||
Printf("- %d walls, %d subsectors, %d sectors\n", walls, subsecs, sectors);
|
||||
|
||||
}
|
||||
Printf("%i dynamic lights, %d walls, %d subsectors, %d sectors\n\n\n", i, allwalls, allsubsecs, allsectors);
|
||||
}
|
||||
|
||||
CCMD(listsublights)
|
||||
{
|
||||
for(int i=0;i<numsubsectors;i++)
|
||||
{
|
||||
subsector_t *sub = &subsectors[i];
|
||||
int lights = 0;
|
||||
|
||||
FLightNode * node = sub->lighthead;
|
||||
while (node != NULL)
|
||||
{
|
||||
lights++;
|
||||
node = node->nextLight;
|
||||
}
|
||||
|
||||
Printf(PRINT_LOG, "Subsector %d - %d lights\n", i, lights);
|
||||
}
|
||||
}
|
||||
|
||||
|
1365
src/gl/dynlights/gl_dynlight.cpp
Normal file
1365
src/gl/dynlights/gl_dynlight.cpp
Normal file
File diff suppressed because it is too large
Load diff
190
src/gl/dynlights/gl_dynlight.h
Normal file
190
src/gl/dynlights/gl_dynlight.h
Normal file
|
@ -0,0 +1,190 @@
|
|||
#ifndef __GLC_DYNLIGHT_H
|
||||
#define __GLC_DYNLIGHT_H
|
||||
|
||||
#include "c_cvars.h"
|
||||
#include "gl/utility/gl_geometric.h"
|
||||
#include "gl/utility/gl_cycler.h"
|
||||
|
||||
|
||||
EXTERN_CVAR(Bool, gl_lights)
|
||||
EXTERN_CVAR(Bool, gl_attachedlights)
|
||||
|
||||
class ADynamicLight;
|
||||
class FArchive;
|
||||
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
LIGHT_RED = 0,
|
||||
LIGHT_GREEN = 1,
|
||||
LIGHT_BLUE = 2,
|
||||
LIGHT_INTENSITY = 3,
|
||||
LIGHT_SECONDARY_INTENSITY = 4,
|
||||
LIGHT_SCALE = 3,
|
||||
};
|
||||
|
||||
// This is as good as something new - and it can be set directly in the ActorInfo!
|
||||
#define MF4_SUBTRACTIVE MF4_MISSILEEVENMORE
|
||||
#define MF4_ADDITIVE MF4_MISSILEMORE
|
||||
#define MF4_DONTLIGHTSELF MF4_SEESDAGGERS
|
||||
|
||||
enum ELightType
|
||||
{
|
||||
PointLight,
|
||||
PulseLight,
|
||||
FlickerLight,
|
||||
RandomFlickerLight,
|
||||
SectorLight,
|
||||
SpotLight,
|
||||
ColorPulseLight,
|
||||
ColorFlickerLight,
|
||||
RandomColorFlickerLight
|
||||
};
|
||||
|
||||
|
||||
struct FLightNode
|
||||
{
|
||||
FLightNode ** prevTarget;
|
||||
FLightNode * nextTarget;
|
||||
FLightNode ** prevLight;
|
||||
FLightNode * nextLight;
|
||||
ADynamicLight * lightsource;
|
||||
union
|
||||
{
|
||||
side_t * targLine;
|
||||
subsector_t * targSubsector;
|
||||
void * targ;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Base class
|
||||
//
|
||||
// [CO] I merged everything together in this one class so that I don't have
|
||||
// to create and re-create an excessive amount of objects
|
||||
//
|
||||
|
||||
class ADynamicLight : public AActor
|
||||
{
|
||||
DECLARE_CLASS (ADynamicLight, AActor)
|
||||
public:
|
||||
virtual void Tick();
|
||||
void Serialize(FArchive &arc);
|
||||
BYTE GetRed() const { return args[LIGHT_RED]; }
|
||||
BYTE GetGreen() const { return args[LIGHT_GREEN]; }
|
||||
BYTE GetBlue() const { return args[LIGHT_BLUE]; }
|
||||
float GetIntensity() const { return m_currentIntensity; }
|
||||
float GetRadius() const { return (IsActive() ? GetIntensity() * 2.f : 0.f); }
|
||||
void LinkLight();
|
||||
void UnlinkLight();
|
||||
size_t PointerSubstitution (DObject *old, DObject *notOld);
|
||||
|
||||
virtual void BeginPlay();
|
||||
void PostBeginPlay();
|
||||
void Destroy();
|
||||
void Activate(AActor *activator);
|
||||
void Deactivate(AActor *activator);
|
||||
void SetOffset(fixed_t x, fixed_t y, fixed_t z);
|
||||
void UpdateLocation();
|
||||
bool IsOwned() const { return owned; }
|
||||
bool IsActive() const { return !(flags2&MF2_DORMANT); }
|
||||
bool IsSubtractive() { return !!(flags4&MF4_SUBTRACTIVE); }
|
||||
bool IsAdditive() { return !!(flags4&MF4_ADDITIVE); }
|
||||
FState *targetState;
|
||||
FLightNode * touching_sides;
|
||||
FLightNode * touching_subsectors;
|
||||
FLightNode * touching_sector;
|
||||
|
||||
private:
|
||||
float DistToSeg(seg_t *seg);
|
||||
void CollectWithinRadius(subsector_t *subSec, float radius);
|
||||
|
||||
protected:
|
||||
fixed_t m_offX, m_offY, m_offZ;
|
||||
float m_currentIntensity;
|
||||
int m_tickCount;
|
||||
unsigned int m_lastUpdate;
|
||||
FCycler m_cycler;
|
||||
subsector_t * subsector;
|
||||
|
||||
public:
|
||||
int m_intensity[2];
|
||||
BYTE lightflags;
|
||||
BYTE lighttype;
|
||||
bool owned;
|
||||
bool halo;
|
||||
BYTE color2[3];
|
||||
int bufferindex;
|
||||
|
||||
// intermediate texture coordinate data
|
||||
// this is stored in the light object to avoid recalculating it
|
||||
// several times during rendering of a flat
|
||||
Vector nearPt, up, right;
|
||||
float scale;
|
||||
|
||||
};
|
||||
|
||||
class AVavoomLight : public ADynamicLight
|
||||
{
|
||||
DECLARE_CLASS (AVavoomLight, ADynamicLight)
|
||||
public:
|
||||
virtual void BeginPlay();
|
||||
};
|
||||
|
||||
class AVavoomLightWhite : public AVavoomLight
|
||||
{
|
||||
DECLARE_CLASS (AVavoomLightWhite, AVavoomLight)
|
||||
public:
|
||||
virtual void BeginPlay();
|
||||
};
|
||||
|
||||
class AVavoomLightColor : public AVavoomLight
|
||||
{
|
||||
DECLARE_CLASS (AVavoomLightColor, AVavoomLight)
|
||||
public:
|
||||
void BeginPlay();
|
||||
};
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
STAT_DLIGHT=64
|
||||
};
|
||||
|
||||
struct FDynLightData
|
||||
{
|
||||
TArray<float> arrays[3];
|
||||
|
||||
void Clear()
|
||||
{
|
||||
arrays[0].Clear();
|
||||
arrays[1].Clear();
|
||||
arrays[2].Clear();
|
||||
}
|
||||
|
||||
void Combine(int *siz, int max)
|
||||
{
|
||||
siz[0] = arrays[0].Size();
|
||||
siz[1] = siz[0] + arrays[1].Size();
|
||||
siz[2] = siz[1] + arrays[2].Size();
|
||||
arrays[0].Resize(arrays[0].Size() + arrays[1].Size() + arrays[2].Size());
|
||||
memcpy(&arrays[0][siz[0]], &arrays[1][0], arrays[1].Size() * sizeof(float));
|
||||
memcpy(&arrays[0][siz[1]], &arrays[2][0], arrays[2].Size() * sizeof(float));
|
||||
siz[0]>>=2;
|
||||
siz[1]>>=2;
|
||||
siz[2]>>=2;
|
||||
if (siz[0] > max) siz[0] = max;
|
||||
if (siz[1] > max) siz[1] = max;
|
||||
if (siz[2] > max) siz[2] = max;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
bool gl_GetLight(Plane & p, ADynamicLight * light, bool checkside, bool forceadditive, FDynLightData &data);
|
||||
void gl_UploadLights(FDynLightData &data);
|
||||
|
||||
|
||||
#endif
|
146
src/gl/dynlights/gl_dynlight1.cpp
Normal file
146
src/gl/dynlights/gl_dynlight1.cpp
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
** gl_dynlight1.cpp
|
||||
** dynamic light application
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "p_local.h"
|
||||
#include "vectors.h"
|
||||
#include "gl/gl_functions.h"
|
||||
#include "g_level.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/dynlights/gl_dynlight.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Light related CVARs
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CUSTOM_CVAR (Bool, gl_lights, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
if (self) gl_RecreateAllAttachedLights();
|
||||
else gl_DeleteAllAttachedLights();
|
||||
}
|
||||
|
||||
CVAR (Bool, gl_attachedlights, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
CVAR (Bool, gl_lights_checkside, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
CVAR (Float, gl_lights_intensity, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
CVAR (Float, gl_lights_size, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
CVAR (Bool, gl_light_sprites, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
CVAR (Bool, gl_light_particles, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
CUSTOM_CVAR (Bool, gl_lights_additive, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
gl_DeleteAllAttachedLights();
|
||||
gl_RecreateAllAttachedLights();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets up the parameters to render one dynamic light onto one plane
|
||||
//
|
||||
//==========================================================================
|
||||
bool gl_GetLight(Plane & p, ADynamicLight * light, bool checkside, bool forceadditive, FDynLightData &ldata)
|
||||
{
|
||||
Vector fn, pos;
|
||||
int i = 0;
|
||||
|
||||
float x = FIXED2FLOAT(light->x);
|
||||
float y = FIXED2FLOAT(light->y);
|
||||
float z = FIXED2FLOAT(light->z);
|
||||
|
||||
float dist = fabsf(p.DistToPoint(x, z, y));
|
||||
float radius = (light->GetRadius() * gl_lights_size);
|
||||
|
||||
if (radius <= 0.f) return false;
|
||||
if (dist > radius) return false;
|
||||
if (checkside && gl_lights_checkside && p.PointOnSide(x, z, y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
float cs;
|
||||
if (gl_lights_additive || light->flags4&MF4_ADDITIVE || forceadditive)
|
||||
{
|
||||
cs = 0.2f;
|
||||
i = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
cs = 1.0f;
|
||||
}
|
||||
|
||||
float r = light->GetRed() / 255.0f * cs * gl_lights_intensity;
|
||||
float g = light->GetGreen() / 255.0f * cs * gl_lights_intensity;
|
||||
float b = light->GetBlue() / 255.0f * cs * gl_lights_intensity;
|
||||
|
||||
if (light->IsSubtractive())
|
||||
{
|
||||
Vector v;
|
||||
|
||||
v.Set(r, g, b);
|
||||
r = v.Length() - r;
|
||||
g = v.Length() - g;
|
||||
b = v.Length() - b;
|
||||
i = 1;
|
||||
}
|
||||
|
||||
float *data = &ldata.arrays[i][ldata.arrays[i].Reserve(8)];
|
||||
data[0] = x;
|
||||
data[1] = z;
|
||||
data[2] = y;
|
||||
data[3] = radius;
|
||||
data[4] = r;
|
||||
data[5] = g;
|
||||
data[6] = b;
|
||||
data[7] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
139
src/gl/dynlights/gl_glow.cpp
Normal file
139
src/gl/dynlights/gl_glow.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
** gl_glow.cpp
|
||||
** Glowing flats like Doomsday
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "w_wad.h"
|
||||
#include "sc_man.h"
|
||||
#include "v_video.h"
|
||||
#include "r_defs.h"
|
||||
#include "textures/textures.h"
|
||||
|
||||
#include "gl/dynlights/gl_glow.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Reads glow definitions from GLDEFS
|
||||
//
|
||||
//===========================================================================
|
||||
void gl_InitGlow(FScanner &sc)
|
||||
{
|
||||
sc.MustGetStringName("{");
|
||||
while (!sc.CheckString("}"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
if (sc.Compare("FLATS"))
|
||||
{
|
||||
sc.MustGetStringName("{");
|
||||
while (!sc.CheckString("}"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
FTextureID flump=TexMan.CheckForTexture(sc.String, FTexture::TEX_Flat,FTextureManager::TEXMAN_TryAny);
|
||||
FTexture *tex = TexMan[flump];
|
||||
if (tex) tex->gl_info.bGlowing = tex->gl_info.bFullbright = true;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("WALLS"))
|
||||
{
|
||||
sc.MustGetStringName("{");
|
||||
while (!sc.CheckString("}"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
FTextureID flump=TexMan.CheckForTexture(sc.String, FTexture::TEX_Wall,FTextureManager::TEXMAN_TryAny);
|
||||
FTexture *tex = TexMan[flump];
|
||||
if (tex) tex->gl_info.bGlowing = tex->gl_info.bFullbright = true;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("TEXTURE"))
|
||||
{
|
||||
sc.SetCMode(true);
|
||||
sc.MustGetString();
|
||||
FTextureID flump=TexMan.CheckForTexture(sc.String, FTexture::TEX_Flat,FTextureManager::TEXMAN_TryAny);
|
||||
FTexture *tex = TexMan[flump];
|
||||
sc.MustGetStringName(",");
|
||||
sc.MustGetString();
|
||||
PalEntry color = V_GetColor(NULL, sc.String);
|
||||
//sc.MustGetStringName(",");
|
||||
//sc.MustGetNumber();
|
||||
if (sc.CheckString(","))
|
||||
{
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
if (tex) tex->gl_info.GlowHeight = sc.Number;
|
||||
if (!sc.CheckString(",")) goto skip_fb;
|
||||
}
|
||||
|
||||
sc.MustGetStringName("fullbright");
|
||||
if (tex) tex->gl_info.bFullbright = true;
|
||||
}
|
||||
skip_fb:
|
||||
sc.SetCMode(false);
|
||||
|
||||
if (tex && color != 0)
|
||||
{
|
||||
tex->gl_info.bGlowing = true;
|
||||
tex->gl_info.GlowColor = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Checks whether a sprite should be affected by a glow
|
||||
//
|
||||
//==========================================================================
|
||||
int gl_CheckSpriteGlow(sector_t *sec, int lightlevel, int x, int y, int z)
|
||||
{
|
||||
FTextureID floorpic = sec->GetTexture(sector_t::floor);
|
||||
FTexture *tex = TexMan[floorpic];
|
||||
if (tex != NULL && tex->isGlowing())
|
||||
{
|
||||
fixed_t floordiff = z - sec->floorplane.ZatPoint(x, y);
|
||||
if (floordiff < tex->gl_info.GlowHeight*FRACUNIT && tex->gl_info.GlowHeight != 0)
|
||||
{
|
||||
int maxlight = (255+lightlevel)>>1;
|
||||
fixed_t lightfrac = floordiff / tex->gl_info.GlowHeight;
|
||||
if (lightfrac<0) lightfrac=0;
|
||||
lightlevel= (lightfrac*lightlevel + maxlight*(FRACUNIT-lightfrac))>>FRACBITS;
|
||||
}
|
||||
}
|
||||
return lightlevel;
|
||||
}
|
||||
|
10
src/gl/dynlights/gl_glow.h
Normal file
10
src/gl/dynlights/gl_glow.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
#ifndef __GL_GLOW
|
||||
#define __GL_GLOW
|
||||
|
||||
struct sector_t;
|
||||
|
||||
void gl_InitGlow(const char * lumpnm);
|
||||
int gl_CheckSpriteGlow(sector_t *sec, int lightlevel, int x, int y, int z);
|
||||
|
||||
#endif
|
224
src/gl/dynlights/gl_lightbuffer.cpp
Normal file
224
src/gl/dynlights/gl_lightbuffer.cpp
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
** gl_lightbuffer.cpp
|
||||
** Buffer data maintenance for dynamic lights
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2014 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/dynlights/gl_lightbuffer.h"
|
||||
#include "gl/dynlights/gl_dynlight.h"
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/utility//gl_clock.h"
|
||||
|
||||
static const int INITIAL_BUFFER_SIZE = 160000; // This means 80000 lights per frame and 160000*16 bytes == 2.56 MB.
|
||||
|
||||
float *mMap;
|
||||
|
||||
FLightBuffer::FLightBuffer()
|
||||
{
|
||||
|
||||
mBufferSize = INITIAL_BUFFER_SIZE;
|
||||
mByteSize = mBufferSize * sizeof(float);
|
||||
if (gl.flags & RFL_SHADER_STORAGE_BUFFER)
|
||||
{
|
||||
mBufferType = GL_SHADER_STORAGE_BUFFER;
|
||||
mBlockAlign = 0;
|
||||
mBlockSize = mBufferSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
mBufferType = GL_UNIFORM_BUFFER;
|
||||
mBlockSize = gl.maxuniformblock / 16;
|
||||
if (mBlockSize > 2048) mBlockSize = 2048; // we don't really need a larger buffer
|
||||
mBlockAlign = mBlockSize / 2;
|
||||
}
|
||||
|
||||
glGenBuffers(1, &mBufferId);
|
||||
glBindBufferBase(mBufferType, LIGHTBUF_BINDINGPOINT, mBufferId);
|
||||
glBindBuffer(mBufferType, mBufferId); // Note: Some older AMD drivers don't do that in glBindBufferBase, as they should.
|
||||
if (gl.flags & RFL_BUFFER_STORAGE)
|
||||
{
|
||||
glBufferStorage(mBufferType, mByteSize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBufferData(mBufferType, mByteSize, NULL, GL_DYNAMIC_DRAW);
|
||||
mBufferPointer = NULL;
|
||||
}
|
||||
|
||||
Clear();
|
||||
mLastMappedIndex = UINT_MAX;
|
||||
}
|
||||
|
||||
FLightBuffer::~FLightBuffer()
|
||||
{
|
||||
glBindBuffer(mBufferType, 0);
|
||||
glDeleteBuffers(1, &mBufferId);
|
||||
}
|
||||
|
||||
void FLightBuffer::Clear()
|
||||
{
|
||||
mIndex = 0;
|
||||
mIndices.Clear();
|
||||
mUploadIndex = 0;
|
||||
}
|
||||
|
||||
int FLightBuffer::UploadLights(FDynLightData &data)
|
||||
{
|
||||
int size0 = data.arrays[0].Size()/4;
|
||||
int size1 = data.arrays[1].Size()/4;
|
||||
int size2 = data.arrays[2].Size()/4;
|
||||
int totalsize = size0 + size1 + size2 + 1;
|
||||
|
||||
// pointless type casting because some compilers can't print enough warnings.
|
||||
if (mBlockAlign > 0 && (unsigned int)totalsize + (mIndex % mBlockAlign) > mBlockSize)
|
||||
{
|
||||
mIndex = ((mIndex + mBlockAlign) / mBlockAlign) * mBlockAlign;
|
||||
|
||||
// can't be rendered all at once.
|
||||
if ((unsigned int)totalsize > mBlockSize)
|
||||
{
|
||||
int diff = totalsize - (int)mBlockSize;
|
||||
|
||||
size2 -= diff;
|
||||
if (size2 < 0)
|
||||
{
|
||||
size1 += size2;
|
||||
size2 = 0;
|
||||
}
|
||||
if (size1 < 0)
|
||||
{
|
||||
size0 += size1;
|
||||
size1 = 0;
|
||||
}
|
||||
totalsize = size0 + size1 + size2 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalsize <= 1) return -1;
|
||||
|
||||
if (mIndex + totalsize > mBufferSize/4)
|
||||
{
|
||||
// reallocate the buffer with twice the size
|
||||
unsigned int newbuffer;
|
||||
|
||||
// first unmap the old buffer
|
||||
glBindBuffer(mBufferType, mBufferId);
|
||||
glUnmapBuffer(mBufferType);
|
||||
|
||||
// create and bind the new buffer, bind the old one to a copy target (too bad that DSA is not yet supported well enough to omit this crap.)
|
||||
glGenBuffers(1, &newbuffer);
|
||||
glBindBufferBase(mBufferType, LIGHTBUF_BINDINGPOINT, newbuffer);
|
||||
glBindBuffer(mBufferType, newbuffer); // Note: Some older AMD drivers don't do that in glBindBufferBase, as they should.
|
||||
glBindBuffer(GL_COPY_READ_BUFFER, mBufferId);
|
||||
|
||||
// create the new buffer's storage (twice as large as the old one)
|
||||
mBufferSize *= 2;
|
||||
mByteSize *= 2;
|
||||
if (gl.flags & RFL_BUFFER_STORAGE)
|
||||
{
|
||||
glBufferStorage(mBufferType, mByteSize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBufferData(mBufferType, mByteSize, NULL, GL_DYNAMIC_DRAW);
|
||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// copy contents and delete the old buffer.
|
||||
glCopyBufferSubData(GL_COPY_READ_BUFFER, mBufferType, 0, 0, mByteSize/2);
|
||||
glBindBuffer(GL_COPY_READ_BUFFER, 0);
|
||||
glDeleteBuffers(1, &mBufferId);
|
||||
mBufferId = newbuffer;
|
||||
}
|
||||
|
||||
float *copyptr;
|
||||
|
||||
assert(mBufferPointer != NULL);
|
||||
if (mBufferPointer == NULL) return -1;
|
||||
copyptr = mBufferPointer + mIndex * 4;
|
||||
|
||||
float parmcnt[] = { 0, float(size0), float(size0 + size1), float(size0 + size1 + size2) };
|
||||
|
||||
memcpy(©ptr[0], parmcnt, 4 * sizeof(float));
|
||||
memcpy(©ptr[4], &data.arrays[0][0], 4 * size0*sizeof(float));
|
||||
memcpy(©ptr[4 + 4*size0], &data.arrays[1][0], 4 * size1*sizeof(float));
|
||||
memcpy(©ptr[4 + 4*(size0 + size1)], &data.arrays[2][0], 4 * size2*sizeof(float));
|
||||
|
||||
unsigned int bufferindex = mIndex;
|
||||
mIndex += totalsize;
|
||||
draw_dlight += (totalsize-1) / 2;
|
||||
return bufferindex;
|
||||
}
|
||||
|
||||
void FLightBuffer::Begin()
|
||||
{
|
||||
if (!(gl.flags & RFL_BUFFER_STORAGE))
|
||||
{
|
||||
glBindBuffer(mBufferType, mBufferId);
|
||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void FLightBuffer::Finish()
|
||||
{
|
||||
if (!(gl.flags & RFL_BUFFER_STORAGE))
|
||||
{
|
||||
glBindBuffer(mBufferType, mBufferId);
|
||||
glUnmapBuffer(mBufferType);
|
||||
mBufferPointer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int FLightBuffer::BindUBO(unsigned int index)
|
||||
{
|
||||
unsigned int offset = (index / mBlockAlign) * mBlockAlign;
|
||||
|
||||
if (offset != mLastMappedIndex)
|
||||
{
|
||||
// this will only get called if a uniform buffer is used. For a shader storage buffer we only need to bind the buffer once at the start to all shader programs
|
||||
mLastMappedIndex = offset;
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, LIGHTBUF_BINDINGPOINT, mBufferId, offset*16, mBlockSize*16); // we go from counting vec4's to counting bytes here.
|
||||
}
|
||||
return (index - offset);
|
||||
}
|
||||
|
||||
|
||||
|
39
src/gl/dynlights/gl_lightbuffer.h
Normal file
39
src/gl/dynlights/gl_lightbuffer.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef __GL_LIGHTBUFFER_H
|
||||
#define __GL_LIGHTBUFFER_H
|
||||
|
||||
#include "tarray.h"
|
||||
struct FDynLightData;
|
||||
|
||||
class FLightBuffer
|
||||
{
|
||||
TArray<int> mIndices;
|
||||
unsigned int mBufferId;
|
||||
float * mBufferPointer;
|
||||
|
||||
unsigned int mBufferType;
|
||||
unsigned int mIndex;
|
||||
unsigned int mUploadIndex;
|
||||
unsigned int mLastMappedIndex;
|
||||
unsigned int mBlockAlign;
|
||||
unsigned int mBlockSize;
|
||||
unsigned int mBufferSize;
|
||||
unsigned int mByteSize;
|
||||
|
||||
public:
|
||||
|
||||
FLightBuffer();
|
||||
~FLightBuffer();
|
||||
void Clear();
|
||||
int UploadLights(FDynLightData &data);
|
||||
void Begin();
|
||||
void Finish();
|
||||
int BindUBO(unsigned int index);
|
||||
unsigned int GetBlockSize() const { return mBlockSize; }
|
||||
unsigned int GetBufferType() const { return mBufferType; }
|
||||
unsigned int GetIndexPtr() const { return mIndices.Size(); }
|
||||
void StoreIndex(int index) { mIndices.Push(index); }
|
||||
int GetIndex(int i) const { return mIndices[i]; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
594
src/gl/gl_builddraw.cpp
Normal file
594
src/gl/gl_builddraw.cpp
Normal file
|
@ -0,0 +1,594 @@
|
|||
/*
|
||||
** gl_builddraw.cpp
|
||||
** a build-like rendering algorithm
|
||||
** Uses the sections created in gl_sections.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "i_system.h"
|
||||
#include "p_local.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/scene/gl_clipper.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/data/gl_sections.h"
|
||||
#include "gl/scene/gl_wall.h"
|
||||
|
||||
#ifdef BUILD_TEST
|
||||
#define D(x) x
|
||||
#else
|
||||
#define D(x) do{}while(0)
|
||||
#endif
|
||||
|
||||
EXTERN_CVAR (Bool, dumpsections)
|
||||
|
||||
struct FBunch
|
||||
{
|
||||
int startline;
|
||||
int endline;
|
||||
angle_t startangle;
|
||||
angle_t endangle;
|
||||
fixed_t minviewdist;
|
||||
fixed_t maxviewdist;
|
||||
};
|
||||
|
||||
void DoSubsector(subsector_t * sub, bool handlelines);
|
||||
|
||||
EXTERN_CVAR(Bool, gl_render_walls)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// From Build but changed to use doubles to prevent overflows
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int WallInFront(FGLSectionLine *wal1, FGLSectionLine *wal2)
|
||||
{
|
||||
double x11, y11, x21, y21, x12, y12, x22, y22, dx, dy, t1, t2;
|
||||
|
||||
x11 = wal1->start->x;
|
||||
y11 = wal1->start->y;
|
||||
x21 = wal1->end->x;
|
||||
y21 = wal1->end->y;
|
||||
x12 = wal2->start->x;
|
||||
y12 = wal2->start->y;
|
||||
x22 = wal2->end->x;
|
||||
y22 = wal2->end->y;
|
||||
|
||||
dx = x21-x11; dy = y21-y11;
|
||||
|
||||
t1 = (x12-x11)*dy - (y12-y11)*dx;
|
||||
t2 = (x22-x11)*dy - (y22-y11)*dx;
|
||||
if (t1 == 0)
|
||||
{
|
||||
t1 = t2;
|
||||
if (t1 == 0) return(-1);
|
||||
}
|
||||
if (t2 == 0) t2 = t1;
|
||||
|
||||
if ((t1*t2) >= 0)
|
||||
{
|
||||
t2 = (double(viewx)-x11) * dy - (double(viewy)-y11)*dx;
|
||||
return((t2*t1) < 0);
|
||||
}
|
||||
|
||||
dx = x22-x12; dy = y22-y12;
|
||||
t1 = (x11-x12)*dy - (y11-y12)*dx;
|
||||
t2 = (x21-x12)*dy - (y21-y12)*dx;
|
||||
if (t1 == 0)
|
||||
{
|
||||
t1 = t2;
|
||||
if (t1 == 0) return(-1);
|
||||
}
|
||||
if (t2 == 0) t2 = t1;
|
||||
if ((t1*t2) >= 0)
|
||||
{
|
||||
t2 = (double(viewx)-x12) * dy - (double(viewy)-y12)*dx;
|
||||
return((t2*t1) >= 0);
|
||||
}
|
||||
return(-2);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This is a bit more complicated than it looks because angles can wrap
|
||||
// around so we can only compare angle differences.
|
||||
//
|
||||
// Rules:
|
||||
// 1. Any bunch can span at most 180°.
|
||||
// 2. 2 bunches can never overlap at both ends
|
||||
// 3. if there is an overlap one of the 2 starting points must be in the
|
||||
// overlapping area.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int BunchInFront(FBunch *b1, FBunch *b2)
|
||||
{
|
||||
angle_t anglecheck, endang;
|
||||
|
||||
if (b2->startangle - b1->startangle < b1->endangle - b1->startangle)
|
||||
{
|
||||
// we have an overlap at b2->startangle
|
||||
anglecheck = b2->startangle - b1->startangle;
|
||||
|
||||
// Find the wall in b1 that overlaps b2->startangle
|
||||
for(int i = b1->startline; i <= b1->endline; i++)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
angle_t startang = SectionLines[i].start->GetClipAngleInverse() - b1->startangle;
|
||||
#endif
|
||||
endang = SectionLines[i].end->GetClipAngleInverse() - b1->startangle;
|
||||
if (endang > anglecheck)
|
||||
{
|
||||
assert (startang <= anglecheck);
|
||||
|
||||
// found a line
|
||||
int ret = WallInFront(&SectionLines[b2->startline], &SectionLines[i]);
|
||||
|
||||
D(Printf (PRINT_LOG, "Line %d <-> line %d: Result = %d.\n",
|
||||
SectionLines[b2->startline].linedef-lines,
|
||||
SectionLines[i].linedef-lines, ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (b1->startangle - b2->startangle < b2->endangle - b2->startangle)
|
||||
{
|
||||
// we have an overlap at b1->startangle
|
||||
anglecheck = b1->startangle - b2->startangle;
|
||||
|
||||
// Find the wall in b2 that overlaps b1->startangle
|
||||
for(int i = b2->startline; i <= b2->endline; i++)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
angle_t startang = SectionLines[i].start->GetClipAngleInverse() - b2->startangle;
|
||||
#endif
|
||||
endang = SectionLines[i].end->GetClipAngleInverse() - b2->startangle;
|
||||
if (endang > anglecheck)
|
||||
{
|
||||
assert (startang <= anglecheck);
|
||||
|
||||
// found a line
|
||||
int ret = WallInFront(&SectionLines[i], &SectionLines[b1->startline]);
|
||||
|
||||
D(Printf (PRINT_LOG, "Line %d <-> line %d: Result = %d,\n",
|
||||
SectionLines[i].linedef-lines,
|
||||
SectionLines[b1->endline].linedef-lines, ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
// we have no overlap
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Bunches are groups of continuous lines
|
||||
// This array stores the amount of points per bunch,
|
||||
// the view angles for each point and the line index for the starting line
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BunchDrawer
|
||||
{
|
||||
int LastBunch;
|
||||
int StartTime;
|
||||
TArray<FBunch> Bunches;
|
||||
TArray<int> CompareData;
|
||||
sector_t fakebacksec;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
public:
|
||||
BunchDrawer()
|
||||
{
|
||||
StartScene();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
private:
|
||||
void StartScene()
|
||||
{
|
||||
LastBunch = 0;
|
||||
StartTime = I_MSTime();
|
||||
Bunches.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void StartBunch(int linenum, angle_t startan, angle_t endan, vertex_t *startpt, vertex_t *endpt)
|
||||
{
|
||||
FBunch *bunch = &Bunches[LastBunch = Bunches.Reserve(1)];
|
||||
|
||||
bunch->startline = bunch->endline = linenum;
|
||||
bunch->startangle = startan;
|
||||
bunch->endangle = endan;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void AddLineToBunch(int newan)
|
||||
{
|
||||
Bunches[LastBunch].endline++;
|
||||
Bunches[LastBunch].endangle = newan;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DeleteBunch(int index)
|
||||
{
|
||||
Bunches.Delete(index);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ClipLine
|
||||
// Clips the given segment
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum
|
||||
{
|
||||
CL_Skip = 0,
|
||||
CL_Draw = 1,
|
||||
CL_Pass = 2,
|
||||
};
|
||||
|
||||
|
||||
int ClipLine (FGLSectionLine *line, sector_t * sector, sector_t **pbacksector)
|
||||
{
|
||||
angle_t startAngle, endAngle;
|
||||
sector_t * backsector = NULL;
|
||||
bool blocking;
|
||||
|
||||
startAngle = line->end->GetClipAngle();
|
||||
endAngle = line->start->GetClipAngle();
|
||||
*pbacksector = NULL;
|
||||
|
||||
// Back side, i.e. backface culling - read: endAngle >= startAngle!
|
||||
if (startAngle-endAngle<ANGLE_180)
|
||||
{
|
||||
return CL_Skip;
|
||||
}
|
||||
|
||||
if (!clipper.SafeCheckRange(startAngle, endAngle))
|
||||
{
|
||||
return CL_Skip;
|
||||
}
|
||||
|
||||
if (line->otherside == -1)
|
||||
{
|
||||
// one-sided
|
||||
clipper.SafeAddClipRange(startAngle, endAngle);
|
||||
return CL_Draw;
|
||||
}
|
||||
else if (line->polysub == NULL)
|
||||
{
|
||||
// two sided and not a polyobject
|
||||
if (line->linedef == NULL)
|
||||
{
|
||||
// Miniseg
|
||||
return CL_Pass;
|
||||
}
|
||||
if (sector->sectornum == line->refseg->backsector->sectornum)
|
||||
{
|
||||
FTexture *tex = TexMan(line->sidedef->GetTexture(side_t::mid));
|
||||
if (!tex || tex->UseType==FTexture::TEX_Null)
|
||||
{
|
||||
// no mid texture: nothing to do here
|
||||
return CL_Pass;
|
||||
}
|
||||
*pbacksector = sector;
|
||||
return CL_Draw|CL_Pass;
|
||||
}
|
||||
else
|
||||
{
|
||||
// clipping checks are only needed when the backsector is not the same as the front sector
|
||||
gl_CheckViewArea(line->start, line->end, line->refseg->frontsector, line->refseg->backsector);
|
||||
|
||||
*pbacksector = backsector = gl_FakeFlat(line->refseg->backsector, &fakebacksec, true);
|
||||
|
||||
blocking = gl_CheckClip(line->sidedef, sector, backsector);
|
||||
if (blocking)
|
||||
{
|
||||
clipper.SafeAddClipRange(startAngle, endAngle);
|
||||
return CL_Draw;
|
||||
}
|
||||
return CL_Draw|CL_Pass;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*pbacksector = sector;
|
||||
return CL_Draw;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ProcessBunch(int bnch)
|
||||
{
|
||||
FBunch *bunch = &Bunches[bnch];
|
||||
|
||||
sector_t fake;
|
||||
sector_t *sec;
|
||||
sector_t *backsector;
|
||||
|
||||
D(Printf(PRINT_LOG, "------------------------------\nProcessing bunch %d (Startline %d)\n",bnch,SectionLines[bunch->startline].linedef-lines));
|
||||
ClipWall.Clock();
|
||||
for(int i=bunch->startline; i <= bunch->endline; i++)
|
||||
{
|
||||
FGLSectionLine *ln = &SectionLines[i];
|
||||
|
||||
|
||||
// Draw this line. todo: optimize
|
||||
sec = gl_FakeFlat(ln->refseg->frontsector, &fake, false);
|
||||
|
||||
int clipped = ClipLine(ln, sec, &backsector);
|
||||
|
||||
D(Printf(PRINT_LOG, "line %d clip result is %d\n", ln->linedef - lines, clipped));
|
||||
|
||||
if (clipped & CL_Draw)
|
||||
{
|
||||
ln->linedef->flags |= ML_MAPPED;
|
||||
|
||||
if (ln->linedef->validcount!=validcount)
|
||||
{
|
||||
ln->linedef->validcount=validcount;
|
||||
|
||||
#ifndef BUILD_TEST
|
||||
if (gl_render_walls)
|
||||
{
|
||||
SetupWall.Clock();
|
||||
|
||||
GLWall wall;
|
||||
wall.Process(ln->refseg, sec, backsector, ln->polysub);
|
||||
rendered_lines++;
|
||||
|
||||
SetupWall.Unclock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (clipped & CL_Pass)
|
||||
{
|
||||
ClipWall.Unclock();
|
||||
ProcessSection(ln->otherside);
|
||||
ClipWall.Clock();
|
||||
}
|
||||
}
|
||||
D(Printf(PRINT_LOG, "Bunch %d done\n------------------------------\n",bnch));
|
||||
ClipWall.Unclock();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FindClosestBunch()
|
||||
{
|
||||
int closest = 0; //Almost works, but not quite :(
|
||||
|
||||
CompareData.Clear();
|
||||
for(unsigned i = 1; i < Bunches.Size(); i++)
|
||||
{
|
||||
switch (BunchInFront(&Bunches[i], &Bunches[closest]))
|
||||
{
|
||||
case 0: // i is in front
|
||||
closest = i;
|
||||
continue;
|
||||
|
||||
case 1: // i is behind
|
||||
continue;
|
||||
|
||||
default: // can't determine
|
||||
CompareData.Push(i); // mark for later comparison
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// we need to do a second pass to see how the marked bunches relate to the currently closest one.
|
||||
for(unsigned i = 0; i < CompareData.Size(); i++)
|
||||
{
|
||||
switch (BunchInFront(&Bunches[CompareData[i]], &Bunches[closest]))
|
||||
{
|
||||
case 0: // is in front
|
||||
closest = i;
|
||||
CompareData.Delete(i);
|
||||
i = 0; // we need to recheck everything that's still marked.
|
||||
continue;
|
||||
|
||||
case 1: // is behind
|
||||
CompareData.Delete(i);
|
||||
i--;
|
||||
continue;
|
||||
|
||||
default:
|
||||
continue;
|
||||
|
||||
}
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ProcessSection(int sectnum)
|
||||
{
|
||||
FGLSection *sect = &Sections[sectnum];
|
||||
bool inbunch;
|
||||
angle_t startangle;
|
||||
|
||||
if (sect->validcount == StartTime) return;
|
||||
sect->validcount = StartTime;
|
||||
D(Printf(PRINT_LOG, "------------------------------\nProcessing section %d (sector %d)\n",sectnum, sect->sector->sectornum));
|
||||
|
||||
#ifndef BUILD_TEST
|
||||
for(unsigned i = 0; i < sect->subsectors.Size(); i++)
|
||||
{
|
||||
DoSubsector(sect->subsectors[i], false);
|
||||
if (sect->subsectors[i]->poly != NULL)
|
||||
{
|
||||
// ProcessPolyobject()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//Todo: process subsectors
|
||||
for(int i=0; i<sect->numloops; i++)
|
||||
{
|
||||
FGLSectionLoop *loop = sect->GetLoop(i);
|
||||
inbunch = false;
|
||||
|
||||
for(int j=0; j<loop->numlines; j++)
|
||||
{
|
||||
FGLSectionLine *ln = loop->GetLine(j);
|
||||
|
||||
angle_t ang1 = ln->start->GetClipAngle();
|
||||
angle_t ang2 = ln->end->GetClipAngle();
|
||||
|
||||
if (ang2 - ang1 < ANGLE_180)
|
||||
{
|
||||
// Backside
|
||||
D(Printf(PRINT_LOG, "line %d facing backwards\n", ln->linedef - lines));
|
||||
inbunch = false;
|
||||
}
|
||||
else if (!clipper.SafeCheckRange(ang2, ang1))
|
||||
{
|
||||
// is it visible?
|
||||
D(Printf(PRINT_LOG, "line %d not in view\n", ln->linedef - lines));
|
||||
inbunch = false;
|
||||
}
|
||||
else if (!inbunch || startangle - ang2 >= ANGLE_180)
|
||||
{
|
||||
// don't let a bunch span more than 180° to avoid problems.
|
||||
// This limitation ensures that the combined range of 2
|
||||
// bunches will always be less than 360° which simplifies
|
||||
// the distance comparison code because it prevents a
|
||||
// situation where 2 bunches may overlap at both ends.
|
||||
D(Printf(PRINT_LOG, "Starting bunch %d at line %d\n",Bunches.Size(), ln->linedef - lines));
|
||||
|
||||
startangle = ang2;
|
||||
// Clipping angles are backward which makes this code very hard to read so let's use the inverse
|
||||
StartBunch(loop->startline + j, 0 - ang1, 0 - ang2);
|
||||
inbunch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
D(Printf(PRINT_LOG, " Adding line %d\n", ln->linedef - lines));
|
||||
AddLineToBunch(0 - ang2);
|
||||
}
|
||||
}
|
||||
}
|
||||
D(Printf(PRINT_LOG, "Section %d done\n------------------------------\n",sectnum));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
public:
|
||||
void RenderScene(int viewsection)
|
||||
{
|
||||
ProcessSection(viewsection);
|
||||
while (Bunches.Size() > 0)
|
||||
{
|
||||
int closest = FindClosestBunch();
|
||||
ProcessBunch(closest);
|
||||
DeleteBunch(closest);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void gl_RenderBuild()
|
||||
{
|
||||
subsector_t *sub = R_PointInSubsector(viewx, viewy);
|
||||
|
||||
clipper.Clear();
|
||||
angle_t a1 = GLRenderer->FrustumAngle();
|
||||
clipper.SafeAddClipRangeRealAngles(viewangle+a1, viewangle-a1);
|
||||
if (Sections.Size() == 0) gl_CreateSections();
|
||||
|
||||
int startsection = SectionForSubsector[sub-subsectors];
|
||||
|
||||
BunchDrawer bd;
|
||||
bd.RenderScene(startsection);
|
||||
}
|
||||
|
||||
#ifdef BUILD_TEST
|
||||
CCMD(testrender)
|
||||
{
|
||||
gl_RenderBuild();
|
||||
}
|
||||
#endif
|
13
src/gl/gl_functions.h
Normal file
13
src/gl/gl_functions.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef __GL_FUNCT
|
||||
#define __GL_FUNCT
|
||||
|
||||
#include "v_palette.h"
|
||||
|
||||
class AActor;
|
||||
|
||||
void gl_PreprocessLevel();
|
||||
void gl_CleanLevelData();
|
||||
void gl_LinkLights();
|
||||
void gl_SetActorLights(AActor *);
|
||||
|
||||
#endif
|
141
src/gl/hqnx/common.h
Normal file
141
src/gl/hqnx/common.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (C) 2003 Maxim Stepin ( maxst@hiend3d.com )
|
||||
*
|
||||
* Copyright (C) 2010 Cameron Zemek ( grom@zeminvaders.net)
|
||||
* Copyright (C) 2011 Francois Gannaz <mytskine@gmail.com>
|
||||
*
|
||||
* 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 2.1 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __HQX_COMMON_H_
|
||||
#define __HQX_COMMON_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "mystdint.h"
|
||||
|
||||
#define MASK_2 0x0000FF00
|
||||
#define MASK_13 0x00FF00FF
|
||||
#define MASK_RGB 0x00FFFFFF
|
||||
#define MASK_ALPHA 0xFF000000
|
||||
|
||||
#define Ymask 0x00FF0000
|
||||
#define Umask 0x0000FF00
|
||||
#define Vmask 0x000000FF
|
||||
#define trY 0x00300000
|
||||
#define trU 0x00000700
|
||||
#define trV 0x00000006
|
||||
|
||||
/* RGB to YUV lookup table */
|
||||
extern uint32_t *RGBtoYUV;
|
||||
|
||||
static inline uint32_t rgb_to_yuv(uint32_t c)
|
||||
{
|
||||
// Mask against MASK_RGB to discard the alpha channel
|
||||
return RGBtoYUV[MASK_RGB & c];
|
||||
}
|
||||
|
||||
/* Test if there is difference in color */
|
||||
static inline int yuv_diff(uint32_t yuv1, uint32_t yuv2) {
|
||||
return (( abs((int64_t)(yuv1 & Ymask) - (int64_t)(yuv2 & Ymask)) > trY ) ||
|
||||
( abs((int64_t)(yuv1 & Umask) - (int64_t)(yuv2 & Umask)) > trU ) ||
|
||||
( abs((int64_t)(yuv1 & Vmask) - (int64_t)(yuv2 & Vmask)) > trV ) );
|
||||
}
|
||||
|
||||
static inline int Diff(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
return yuv_diff(rgb_to_yuv(c1), rgb_to_yuv(c2));
|
||||
}
|
||||
|
||||
/* Interpolate functions */
|
||||
static inline uint32_t Interpolate_2(uint32_t c1, int w1, uint32_t c2, int w2, int s)
|
||||
{
|
||||
if (c1 == c2) {
|
||||
return c1;
|
||||
}
|
||||
return
|
||||
(((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2) << (24-s)) & MASK_ALPHA) +
|
||||
((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2) >> s) & MASK_2) +
|
||||
((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2) >> s) & MASK_13);
|
||||
}
|
||||
|
||||
static inline uint32_t Interpolate_3(uint32_t c1, int w1, uint32_t c2, int w2, uint32_t c3, int w3, int s)
|
||||
{
|
||||
return
|
||||
(((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2 + ((c3 & MASK_ALPHA) >> 24) * w3) << (24-s)) & MASK_ALPHA) +
|
||||
((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2 + (c3 & MASK_2) * w3) >> s) & MASK_2) +
|
||||
((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2 + (c3 & MASK_13) * w3) >> s) & MASK_13);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp1(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
//(c1*3+c2) >> 2;
|
||||
return Interpolate_2(c1, 3, c2, 1, 2);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp2(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*2+c2+c3) >> 2;
|
||||
return Interpolate_3(c1, 2, c2, 1, c3, 1, 2);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp3(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
//(c1*7+c2)/8;
|
||||
return Interpolate_2(c1, 7, c2, 1, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp4(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*2+(c2+c3)*7)/16;
|
||||
return Interpolate_3(c1, 2, c2, 7, c3, 7, 4);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp5(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
//(c1+c2) >> 1;
|
||||
return Interpolate_2(c1, 1, c2, 1, 1);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp6(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*5+c2*2+c3)/8;
|
||||
return Interpolate_3(c1, 5, c2, 2, c3, 1, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp7(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*6+c2+c3)/8;
|
||||
return Interpolate_3(c1, 6, c2, 1, c3, 1, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp8(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
//(c1*5+c2*3)/8;
|
||||
return Interpolate_2(c1, 5, c2, 3, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp9(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*2+(c2+c3)*3)/8;
|
||||
return Interpolate_3(c1, 2, c2, 3, c3, 3, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp10(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*14+c2+c3)/16;
|
||||
return Interpolate_3(c1, 14, c2, 1, c3, 1, 4);
|
||||
}
|
||||
|
||||
#endif
|
2809
src/gl/hqnx/hq2x.cpp
Normal file
2809
src/gl/hqnx/hq2x.cpp
Normal file
File diff suppressed because it is too large
Load diff
3787
src/gl/hqnx/hq3x.cpp
Normal file
3787
src/gl/hqnx/hq3x.cpp
Normal file
File diff suppressed because it is too large
Load diff
5233
src/gl/hqnx/hq4x.cpp
Normal file
5233
src/gl/hqnx/hq4x.cpp
Normal file
File diff suppressed because it is too large
Load diff
55
src/gl/hqnx/hqx.h
Normal file
55
src/gl/hqnx/hqx.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2003 Maxim Stepin ( maxst@hiend3d.com )
|
||||
*
|
||||
* Copyright (C) 2010 Cameron Zemek ( grom@zeminvaders.net)
|
||||
*
|
||||
* 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 2.1 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __HQX_H_
|
||||
#define __HQX_H_
|
||||
|
||||
#include "mystdint.h"
|
||||
|
||||
#if defined( __GNUC__ )
|
||||
#ifdef __MINGW32__
|
||||
#define HQX_CALLCONV __stdcall
|
||||
#else
|
||||
#define HQX_CALLCONV
|
||||
#endif
|
||||
#else
|
||||
#define HQX_CALLCONV
|
||||
#endif
|
||||
|
||||
#if 0 //defined(_WIN32)
|
||||
#ifdef DLL_EXPORT
|
||||
#define HQX_API __declspec(dllexport)
|
||||
#else
|
||||
#define HQX_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define HQX_API
|
||||
#endif
|
||||
|
||||
HQX_API void HQX_CALLCONV hqxInit(void);
|
||||
HQX_API void HQX_CALLCONV hq2x_32( uint32_t * src, uint32_t * dest, int width, int height );
|
||||
HQX_API void HQX_CALLCONV hq3x_32( uint32_t * src, uint32_t * dest, int width, int height );
|
||||
HQX_API void HQX_CALLCONV hq4x_32( uint32_t * src, uint32_t * dest, int width, int height );
|
||||
|
||||
HQX_API void HQX_CALLCONV hq2x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height );
|
||||
HQX_API void HQX_CALLCONV hq3x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height );
|
||||
HQX_API void HQX_CALLCONV hq4x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height );
|
||||
|
||||
#endif
|
39
src/gl/hqnx/init.cpp
Normal file
39
src/gl/hqnx/init.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2010 Cameron Zemek ( grom@zeminvaders.net)
|
||||
*
|
||||
* 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 2.1 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "mystdint.h"
|
||||
#include "hqx.h"
|
||||
|
||||
uint32_t *RGBtoYUV;
|
||||
uint32_t YUV1, YUV2;
|
||||
|
||||
HQX_API void HQX_CALLCONV hqxInit(void)
|
||||
{
|
||||
/* Initalize RGB to YUV lookup table */
|
||||
uint32_t c, r, g, b, y, u, v;
|
||||
RGBtoYUV = new uint32_t[16777216];
|
||||
for (c = 0; c < 16777215; c++) {
|
||||
r = (c & 0xFF0000) >> 16;
|
||||
g = (c & 0x00FF00) >> 8;
|
||||
b = c & 0x0000FF;
|
||||
y = (uint32_t)(0.299*r + 0.587*g + 0.114*b);
|
||||
u = (uint32_t)(-0.169*r - 0.331*g + 0.5*b) + 128;
|
||||
v = (uint32_t)(0.5*r - 0.419*g - 0.081*b) + 128;
|
||||
RGBtoYUV[c] = (y << 16) + (u << 8) + v;
|
||||
}
|
||||
}
|
19
src/gl/hqnx/mystdint.h
Normal file
19
src/gl/hqnx/mystdint.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef __MYSTDINT_H
|
||||
#define __MYSTDINT_H
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#else
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef signed __int8 int8_t;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
2943
src/gl/hqnx_asm/hq2x_asm.cpp
Normal file
2943
src/gl/hqnx_asm/hq2x_asm.cpp
Normal file
File diff suppressed because it is too large
Load diff
3843
src/gl/hqnx_asm/hq3x_asm.cpp
Normal file
3843
src/gl/hqnx_asm/hq3x_asm.cpp
Normal file
File diff suppressed because it is too large
Load diff
5422
src/gl/hqnx_asm/hq4x_asm.cpp
Normal file
5422
src/gl/hqnx_asm/hq4x_asm.cpp
Normal file
File diff suppressed because it is too large
Load diff
234
src/gl/hqnx_asm/hqnx_asm.h
Normal file
234
src/gl/hqnx_asm/hqnx_asm.h
Normal file
|
@ -0,0 +1,234 @@
|
|||
//hqnx filter library
|
||||
//----------------------------------------------------------
|
||||
//Copyright (C) 2003 MaxSt ( maxst@hiend3d.com )
|
||||
//Copyright (C) 2009 Benjamin Berkels
|
||||
//Copyright (C) 2012-2014 Alexey Lysiuk
|
||||
//
|
||||
//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 2.1 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, write to the Free Software
|
||||
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#ifndef __HQNX_H__
|
||||
#define __HQNX_H__
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4799)
|
||||
#endif // _MSC_VER
|
||||
|
||||
#include "hqnx_asm_Image.h"
|
||||
|
||||
// IMPORTANT NOTE!
|
||||
// The following is not a generic vectorized math class
|
||||
// Each member function or overloaded operator does specific task to simplify client code
|
||||
// To re-implement this class for different platform you need check very carefully
|
||||
// the Intel C++ Intrinsic Reference at http://software.intel.com/file/18072/
|
||||
|
||||
#if defined _MSC_VER && defined _M_X64
|
||||
|
||||
// Implementation via SSE2 intrinsics
|
||||
// MSVC doesn't support MMX intrinsics on x64
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
class hq_vec
|
||||
{
|
||||
public:
|
||||
hq_vec(const int value)
|
||||
: m_value(_mm_cvtsi32_si128(value))
|
||||
{
|
||||
}
|
||||
|
||||
static hq_vec load(const int source)
|
||||
{
|
||||
return _mm_unpacklo_epi8(_mm_cvtsi32_si128(source), _mm_cvtsi32_si128(0));
|
||||
}
|
||||
|
||||
static hq_vec expand(const short source)
|
||||
{
|
||||
return _mm_set_epi16(source, source, source, source, source, source, source, source);
|
||||
}
|
||||
|
||||
void store(unsigned char* const destination) const
|
||||
{
|
||||
*reinterpret_cast<int*>(destination) = _mm_cvtsi128_si32(_mm_packus_epi16(m_value, _mm_cvtsi32_si128(0)));
|
||||
}
|
||||
|
||||
static void reset()
|
||||
{
|
||||
}
|
||||
|
||||
hq_vec& operator+=(const hq_vec& right)
|
||||
{
|
||||
m_value = _mm_add_epi16(m_value, right.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
hq_vec& operator*=(const hq_vec& right)
|
||||
{
|
||||
m_value = _mm_mullo_epi16(m_value, right.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
hq_vec& operator<<(const int count)
|
||||
{
|
||||
m_value = _mm_sll_epi16(m_value, _mm_cvtsi32_si128(count));
|
||||
return *this;
|
||||
}
|
||||
|
||||
hq_vec& operator>>(const int count)
|
||||
{
|
||||
m_value = _mm_srl_epi16(m_value, _mm_cvtsi32_si128(count));
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
__m128i m_value;
|
||||
|
||||
hq_vec(const __m128i value)
|
||||
: m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
friend hq_vec operator- (const hq_vec&, const hq_vec&);
|
||||
friend hq_vec operator* (const hq_vec&, const hq_vec&);
|
||||
friend hq_vec operator| (const hq_vec&, const hq_vec&);
|
||||
friend bool operator!=(const int, const hq_vec&);
|
||||
};
|
||||
|
||||
inline hq_vec operator-(const hq_vec& left, const hq_vec& right)
|
||||
{
|
||||
return _mm_subs_epu8(left.m_value, right.m_value);
|
||||
}
|
||||
|
||||
inline hq_vec operator*(const hq_vec& left, const hq_vec& right)
|
||||
{
|
||||
return _mm_mullo_epi16(left.m_value, right.m_value);
|
||||
}
|
||||
|
||||
inline hq_vec operator|(const hq_vec& left, const hq_vec& right)
|
||||
{
|
||||
return _mm_or_si128(left.m_value, right.m_value);
|
||||
}
|
||||
|
||||
inline bool operator!=(const int left, const hq_vec& right)
|
||||
{
|
||||
return left != _mm_cvtsi128_si32(right.m_value);
|
||||
}
|
||||
|
||||
#else // _M_X64
|
||||
|
||||
// Implementation via MMX intrinsics
|
||||
|
||||
#include <mmintrin.h>
|
||||
|
||||
class hq_vec
|
||||
{
|
||||
public:
|
||||
hq_vec(const int value)
|
||||
: m_value(_mm_cvtsi32_si64(value))
|
||||
{
|
||||
}
|
||||
|
||||
static hq_vec load(const int source)
|
||||
{
|
||||
return _mm_unpacklo_pi8(_mm_cvtsi32_si64(source), _mm_cvtsi32_si64(0));
|
||||
}
|
||||
|
||||
static hq_vec expand(const short source)
|
||||
{
|
||||
return _mm_set_pi16(source, source, source, source);
|
||||
}
|
||||
|
||||
void store(unsigned char* const destination) const
|
||||
{
|
||||
*reinterpret_cast<int*>(destination) = _mm_cvtsi64_si32(_mm_packs_pu16(m_value, _mm_cvtsi32_si64(0)));
|
||||
}
|
||||
|
||||
static void reset()
|
||||
{
|
||||
_mm_empty();
|
||||
}
|
||||
|
||||
hq_vec& operator+=(const hq_vec& right)
|
||||
{
|
||||
m_value = _mm_add_pi16(m_value, right.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
hq_vec& operator*=(const hq_vec& right)
|
||||
{
|
||||
m_value = _mm_mullo_pi16(m_value, right.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
hq_vec& operator<<(const int count)
|
||||
{
|
||||
m_value = _mm_sll_pi16(m_value, _mm_cvtsi32_si64(count));
|
||||
return *this;
|
||||
}
|
||||
|
||||
hq_vec& operator>>(const int count)
|
||||
{
|
||||
m_value = _mm_srl_pi16(m_value, _mm_cvtsi32_si64(count));
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
__m64 m_value;
|
||||
|
||||
hq_vec(const __m64 value)
|
||||
: m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
friend hq_vec operator- (const hq_vec&, const hq_vec&);
|
||||
friend hq_vec operator* (const hq_vec&, const hq_vec&);
|
||||
friend hq_vec operator| (const hq_vec&, const hq_vec&);
|
||||
friend bool operator!=(const int, const hq_vec&);
|
||||
};
|
||||
|
||||
inline hq_vec operator-(const hq_vec& left, const hq_vec& right)
|
||||
{
|
||||
return _mm_subs_pu8(left.m_value, right.m_value);
|
||||
}
|
||||
|
||||
inline hq_vec operator*(const hq_vec& left, const hq_vec& right)
|
||||
{
|
||||
return _mm_mullo_pi16(left.m_value, right.m_value);
|
||||
}
|
||||
|
||||
inline hq_vec operator|(const hq_vec& left, const hq_vec& right)
|
||||
{
|
||||
return _mm_or_si64(left.m_value, right.m_value);
|
||||
}
|
||||
|
||||
inline bool operator!=(const int left, const hq_vec& right)
|
||||
{
|
||||
return left != _mm_cvtsi64_si32(right.m_value);
|
||||
}
|
||||
|
||||
#endif // _MSC_VER && _M_X64
|
||||
|
||||
namespace HQnX_asm
|
||||
{
|
||||
void DLL hq2x_32( int * pIn, unsigned char * pOut, int Xres, int Yres, int BpL );
|
||||
void DLL hq3x_32( int * pIn, unsigned char * pOut, int Xres, int Yres, int BpL );
|
||||
void DLL hq4x_32( int * pIn, unsigned char * pOut, int Xres, int Yres, int BpL );
|
||||
int DLL hq4x_32 ( CImage &ImageIn, CImage &ImageOut );
|
||||
|
||||
void DLL InitLUTs();
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //__HQNX_H__
|
1183
src/gl/hqnx_asm/hqnx_asm_Image.cpp
Normal file
1183
src/gl/hqnx_asm/hqnx_asm_Image.cpp
Normal file
File diff suppressed because it is too large
Load diff
152
src/gl/hqnx_asm/hqnx_asm_Image.h
Normal file
152
src/gl/hqnx_asm/hqnx_asm_Image.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
//CImage class - loading and saving BMP and TGA files
|
||||
//----------------------------------------------------------
|
||||
//Copyright (C) 2003 MaxSt ( maxst@hiend3d.com )
|
||||
//
|
||||
//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 2.1 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, write to the Free Software
|
||||
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
//#ifdef WIN32
|
||||
//#define DLL __declspec(dllexport)
|
||||
//#else
|
||||
#define DLL
|
||||
//#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#pragma once
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4103)
|
||||
#endif // _MSC_VER
|
||||
#pragma pack(1)
|
||||
|
||||
namespace HQnX_asm
|
||||
{
|
||||
|
||||
typedef struct { unsigned char b, g, r; } _BGR;
|
||||
typedef struct { unsigned char b, g, r, a; } _BGRA;
|
||||
|
||||
class CImage
|
||||
{
|
||||
public:
|
||||
DLL CImage();
|
||||
DLL ~CImage();
|
||||
|
||||
enum CImageErrors
|
||||
{
|
||||
eConvUnknownFormat = 10,
|
||||
eConvSourceMemory = 11,
|
||||
eConvDestMemory = 12,
|
||||
|
||||
eSaveBmpFileOpen = 20,
|
||||
eSaveBmpFileWrite = 21,
|
||||
eSaveBmpSourceMemory = 22,
|
||||
eSaveBmpColorDepth = 23,
|
||||
|
||||
eLoadBmpFileOpen = 30,
|
||||
eLoadBmpFileRead = 31,
|
||||
eLoadBmpBadFormat = 32,
|
||||
eLoadBmpInit = 33,
|
||||
eLoadBmpColorDepth = 34,
|
||||
|
||||
eSaveTgaFileOpen = 40,
|
||||
eSaveTgaFileWrite = 41,
|
||||
eSaveTgaSourceMemory = 42,
|
||||
eSaveTgaColorDepth = 43,
|
||||
|
||||
eLoadTgaFileOpen = 50,
|
||||
eLoadTgaFileRead = 51,
|
||||
eLoadTgaBadFormat = 52,
|
||||
eLoadTgaInit = 53,
|
||||
eLoadTgaColorDepth = 54,
|
||||
|
||||
eLoadFilename = 60,
|
||||
eSaveFilename = 61,
|
||||
};
|
||||
|
||||
struct _BMPFILEHEADER
|
||||
{
|
||||
unsigned short bfType;
|
||||
long int bfSize, bfRes1, bfOffBits;
|
||||
};
|
||||
|
||||
struct _BMPIMAGEHEADEROLD
|
||||
{
|
||||
long int biSize;
|
||||
unsigned short biWidth, biHeight;
|
||||
unsigned short biPlanes, biBitCount;
|
||||
};
|
||||
|
||||
struct _BMPIMAGEHEADER
|
||||
{
|
||||
long int biSize, biWidth, biHeight;
|
||||
unsigned short biPlanes, biBitCount;
|
||||
long int biCompression, biSizeImage;
|
||||
long int biXPelsPerMeter, biYPelsPerMeter;
|
||||
long int biClrUsed, biClrImportant;
|
||||
};
|
||||
|
||||
struct _TGAHEADER
|
||||
{
|
||||
unsigned char tiIdentSize;
|
||||
unsigned char tiPaletteIncluded;
|
||||
unsigned char tiImageType;
|
||||
unsigned short tiPaletteStart;
|
||||
unsigned short tiPaletteSize;
|
||||
unsigned char tiPaletteBpp;
|
||||
unsigned short tiX0;
|
||||
unsigned short tiY0;
|
||||
unsigned short tiXres;
|
||||
unsigned short tiYres;
|
||||
unsigned char tiBitPerPixel;
|
||||
unsigned char tiAttrBits;
|
||||
};
|
||||
|
||||
public:
|
||||
int DLL Init( int Xres, int Yres, unsigned short BitPerPixel );
|
||||
int DLL SetImage(unsigned char *img, int width, int height, int bpp);
|
||||
int DLL Destroy();
|
||||
int DLL ConvertTo32( void );
|
||||
int DLL ConvertTo24( void );
|
||||
int DLL ConvertTo16( void );
|
||||
int DLL Convert8To17( int transindex );
|
||||
int DLL Convert32To17( void );
|
||||
int SaveBmp(char *szFilename);
|
||||
int LoadBmp(char *szFilename);
|
||||
int SaveTga(char *szFilename, bool bCompressed );
|
||||
int LoadTga(char *szFilename);
|
||||
int DLL Load(char *szFilename);
|
||||
int DLL Save(char *szFilename);
|
||||
|
||||
private:
|
||||
void Output( char * pcData, int nSize );
|
||||
void Output( char c );
|
||||
void Output( void );
|
||||
unsigned char Input( void );
|
||||
|
||||
public:
|
||||
int m_Xres, m_Yres;
|
||||
unsigned short m_BitPerPixel;
|
||||
unsigned short m_BytePerPixel;
|
||||
unsigned char * m_pBitmap;
|
||||
_BGR m_Pal[256];
|
||||
|
||||
private:
|
||||
int m_NumPixel;
|
||||
FILE * f;
|
||||
int m_nCount;
|
||||
char m_cBuf[32768];
|
||||
};
|
||||
|
||||
#pragma pack(8)
|
||||
|
||||
}
|
1013
src/gl/models/gl_models.cpp
Normal file
1013
src/gl/models/gl_models.cpp
Normal file
File diff suppressed because it is too large
Load diff
371
src/gl/models/gl_models.h
Normal file
371
src/gl/models/gl_models.h
Normal file
|
@ -0,0 +1,371 @@
|
|||
#ifndef __GL_MODELS_H_
|
||||
#define __GL_MODELS_H_
|
||||
|
||||
#include "gl/utility/gl_geometric.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "p_pspr.h"
|
||||
#include "r_data/voxels.h"
|
||||
|
||||
|
||||
#define MAX_LODS 4
|
||||
|
||||
enum { VX, VZ, VY };
|
||||
|
||||
#define MD2_MAGIC 0x32504449
|
||||
#define DMD_MAGIC 0x4D444D44
|
||||
#define MD3_MAGIC 0x33504449
|
||||
#define NUMVERTEXNORMALS 162
|
||||
|
||||
FTexture * LoadSkin(const char * path, const char * fn);
|
||||
|
||||
|
||||
class FModel
|
||||
{
|
||||
public:
|
||||
|
||||
FModel()
|
||||
{
|
||||
mVBuf = NULL;
|
||||
}
|
||||
virtual ~FModel();
|
||||
|
||||
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) = 0;
|
||||
virtual int FindFrame(const char * name) = 0;
|
||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0) = 0;
|
||||
virtual void BuildVertexBuffer() = 0;
|
||||
void DestroyVertexBuffer()
|
||||
{
|
||||
delete mVBuf;
|
||||
mVBuf = NULL;
|
||||
}
|
||||
virtual float getAspectFactor() { return 1.f; }
|
||||
|
||||
FModelVertexBuffer *mVBuf;
|
||||
FString mFileName;
|
||||
};
|
||||
|
||||
class FDMDModel : public FModel
|
||||
{
|
||||
protected:
|
||||
|
||||
struct FTriangle
|
||||
{
|
||||
unsigned short vertexIndices[3];
|
||||
unsigned short textureIndices[3];
|
||||
};
|
||||
|
||||
|
||||
struct DMDHeader
|
||||
{
|
||||
int magic;
|
||||
int version;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct DMDModelVertex
|
||||
{
|
||||
float xyz[3];
|
||||
};
|
||||
|
||||
struct FTexCoord
|
||||
{
|
||||
short s, t;
|
||||
};
|
||||
|
||||
struct FGLCommandVertex
|
||||
{
|
||||
float s, t;
|
||||
int index;
|
||||
};
|
||||
|
||||
struct DMDInfo
|
||||
{
|
||||
int skinWidth;
|
||||
int skinHeight;
|
||||
int frameSize;
|
||||
int numSkins;
|
||||
int numVertices;
|
||||
int numTexCoords;
|
||||
int numFrames;
|
||||
int numLODs;
|
||||
int offsetSkins;
|
||||
int offsetTexCoords;
|
||||
int offsetFrames;
|
||||
int offsetLODs;
|
||||
int offsetEnd;
|
||||
};
|
||||
|
||||
struct ModelFrame
|
||||
{
|
||||
char name[16];
|
||||
unsigned int vindex;
|
||||
};
|
||||
|
||||
struct ModelFrameVertexData
|
||||
{
|
||||
DMDModelVertex *vertices;
|
||||
DMDModelVertex *normals;
|
||||
};
|
||||
|
||||
struct DMDLoDInfo
|
||||
{
|
||||
int numTriangles;
|
||||
int numGlCommands;
|
||||
int offsetTriangles;
|
||||
int offsetGlCommands;
|
||||
};
|
||||
|
||||
struct DMDLoD
|
||||
{
|
||||
FTriangle * triangles;
|
||||
};
|
||||
|
||||
|
||||
int mLumpNum;
|
||||
DMDHeader header;
|
||||
DMDInfo info;
|
||||
FTexture ** skins;
|
||||
ModelFrame * frames;
|
||||
bool allowTexComp; // Allow texture compression with this.
|
||||
|
||||
// Temp data only needed for buffer construction
|
||||
FTexCoord * texCoords;
|
||||
ModelFrameVertexData *framevtx;
|
||||
DMDLoDInfo lodInfo[MAX_LODS];
|
||||
DMDLoD lods[MAX_LODS];
|
||||
|
||||
public:
|
||||
FDMDModel()
|
||||
{
|
||||
mLumpNum = -1;
|
||||
frames = NULL;
|
||||
skins = NULL;
|
||||
for (int i = 0; i < MAX_LODS; i++)
|
||||
{
|
||||
lods[i].triangles = NULL;
|
||||
}
|
||||
info.numLODs = 0;
|
||||
texCoords = NULL;
|
||||
framevtx = NULL;
|
||||
}
|
||||
virtual ~FDMDModel();
|
||||
|
||||
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length);
|
||||
virtual int FindFrame(const char * name);
|
||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
||||
virtual void LoadGeometry();
|
||||
void UnloadGeometry();
|
||||
void BuildVertexBuffer();
|
||||
|
||||
};
|
||||
|
||||
// This uses the same internal representation as DMD
|
||||
class FMD2Model : public FDMDModel
|
||||
{
|
||||
public:
|
||||
FMD2Model() {}
|
||||
virtual ~FMD2Model();
|
||||
|
||||
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length);
|
||||
virtual void LoadGeometry();
|
||||
|
||||
};
|
||||
|
||||
|
||||
class FMD3Model : public FModel
|
||||
{
|
||||
struct MD3Tag
|
||||
{
|
||||
// Currently I have no use for this
|
||||
};
|
||||
|
||||
struct MD3TexCoord
|
||||
{
|
||||
float s,t;
|
||||
};
|
||||
|
||||
struct MD3Vertex
|
||||
{
|
||||
float x,y,z;
|
||||
float nx,ny,nz;
|
||||
};
|
||||
|
||||
struct MD3Triangle
|
||||
{
|
||||
int VertIndex[3];
|
||||
};
|
||||
|
||||
struct MD3Surface
|
||||
{
|
||||
int numVertices;
|
||||
int numTriangles;
|
||||
int numSkins;
|
||||
|
||||
FTexture ** skins;
|
||||
MD3Triangle * tris;
|
||||
MD3TexCoord * texcoords;
|
||||
MD3Vertex * vertices;
|
||||
|
||||
unsigned int vindex; // contains numframes arrays of vertices
|
||||
unsigned int iindex;
|
||||
|
||||
MD3Surface()
|
||||
{
|
||||
tris=NULL;
|
||||
vertices=NULL;
|
||||
texcoords=NULL;
|
||||
vindex = iindex = UINT_MAX;
|
||||
}
|
||||
|
||||
~MD3Surface()
|
||||
{
|
||||
if (skins) delete [] skins;
|
||||
UnloadGeometry();
|
||||
}
|
||||
|
||||
void UnloadGeometry()
|
||||
{
|
||||
if (tris) delete [] tris;
|
||||
if (vertices) delete [] vertices;
|
||||
if (texcoords) delete [] texcoords;
|
||||
tris = NULL;
|
||||
vertices = NULL;
|
||||
texcoords = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
struct MD3Frame
|
||||
{
|
||||
// The bounding box information is of no use in the Doom engine
|
||||
// That will still be done with the actor's size information.
|
||||
char Name[16];
|
||||
float origin[3];
|
||||
};
|
||||
|
||||
int numFrames;
|
||||
int numTags;
|
||||
int numSurfaces;
|
||||
int mLumpNum;
|
||||
|
||||
MD3Frame * frames;
|
||||
MD3Surface * surfaces;
|
||||
|
||||
public:
|
||||
FMD3Model() { }
|
||||
virtual ~FMD3Model();
|
||||
|
||||
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length);
|
||||
virtual int FindFrame(const char * name);
|
||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
||||
void LoadGeometry();
|
||||
void BuildVertexBuffer();
|
||||
};
|
||||
|
||||
struct FVoxelVertexHash
|
||||
{
|
||||
// Returns the hash value for a key.
|
||||
hash_t Hash(const FModelVertex &key)
|
||||
{
|
||||
int ix = xs_RoundToInt(key.x);
|
||||
int iy = xs_RoundToInt(key.y);
|
||||
int iz = xs_RoundToInt(key.z);
|
||||
return (hash_t)(ix + (iy<<9) + (iz<<18));
|
||||
}
|
||||
|
||||
// Compares two keys, returning zero if they are the same.
|
||||
int Compare(const FModelVertex &left, const FModelVertex &right)
|
||||
{
|
||||
return left.x != right.x || left.y != right.y || left.z != right.z || left.u != right.u || left.v != right.v;
|
||||
}
|
||||
};
|
||||
|
||||
struct FIndexInit
|
||||
{
|
||||
void Init(unsigned int &value)
|
||||
{
|
||||
value = 0xffffffff;
|
||||
}
|
||||
};
|
||||
|
||||
typedef TMap<FModelVertex, unsigned int, FVoxelVertexHash, FIndexInit> FVoxelMap;
|
||||
|
||||
|
||||
class FVoxelModel : public FModel
|
||||
{
|
||||
protected:
|
||||
FVoxel *mVoxel;
|
||||
bool mOwningVoxel; // if created through MODELDEF deleting this object must also delete the voxel object
|
||||
FTexture *mPalette;
|
||||
unsigned int mNumIndices;
|
||||
TArray<FModelVertex> mVertices;
|
||||
TArray<unsigned int> mIndices;
|
||||
|
||||
void MakeSlabPolys(int x, int y, kvxslab_t *voxptr, FVoxelMap &check);
|
||||
void AddFace(int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3, int x4, int y4, int z4, BYTE color, FVoxelMap &check);
|
||||
unsigned int AddVertex(FModelVertex &vert, FVoxelMap &check);
|
||||
|
||||
public:
|
||||
FVoxelModel(FVoxel *voxel, bool owned);
|
||||
~FVoxelModel();
|
||||
bool Load(const char * fn, int lumpnum, const char * buffer, int length);
|
||||
void Initialize();
|
||||
virtual int FindFrame(const char * name);
|
||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
||||
FTexture *GetPaletteTexture() const { return mPalette; }
|
||||
void BuildVertexBuffer();
|
||||
float getAspectFactor();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define MAX_MODELS_PER_FRAME 4
|
||||
|
||||
//
|
||||
// [BB] Model rendering flags.
|
||||
//
|
||||
enum
|
||||
{
|
||||
// [BB] Color translations for the model skin are ignored. This is
|
||||
// useful if the skin texture is not using the game palette.
|
||||
MDL_IGNORETRANSLATION = 1,
|
||||
MDL_PITCHFROMMOMENTUM = 2,
|
||||
MDL_ROTATING = 4,
|
||||
MDL_INTERPOLATEDOUBLEDFRAMES = 8,
|
||||
MDL_NOINTERPOLATION = 16,
|
||||
MDL_INHERITACTORPITCH = 32,
|
||||
MDL_INHERITACTORROLL = 64, // useless for now
|
||||
};
|
||||
|
||||
struct FSpriteModelFrame
|
||||
{
|
||||
FModel * models[MAX_MODELS_PER_FRAME];
|
||||
FTexture * skins[MAX_MODELS_PER_FRAME];
|
||||
int modelframes[MAX_MODELS_PER_FRAME];
|
||||
float xscale, yscale, zscale;
|
||||
// [BB] Added zoffset, rotation parameters and flags.
|
||||
// Added xoffset, yoffset
|
||||
float xoffset, yoffset, zoffset;
|
||||
float xrotate, yrotate, zrotate;
|
||||
float rotationCenterX, rotationCenterY, rotationCenterZ;
|
||||
float rotationSpeed;
|
||||
unsigned int flags;
|
||||
const PClass * type;
|
||||
short sprite;
|
||||
short frame;
|
||||
FState * state; // for later!
|
||||
int hashnext;
|
||||
angle_t angleoffset;
|
||||
// added pithoffset, rolloffset.
|
||||
float pitchoffset, rolloffset; // I don't want to bother with type transformations, so I made this variables float.
|
||||
};
|
||||
|
||||
class GLSprite;
|
||||
|
||||
FSpriteModelFrame * gl_FindModelFrame(const PClass * ti, int sprite, int frame, bool dropped);
|
||||
|
||||
void gl_RenderModel(GLSprite * spr);
|
||||
// [BB] HUD weapon model rendering functions.
|
||||
void gl_RenderHUDModel(pspdef_t *psp, fixed_t ofsx, fixed_t ofsy);
|
||||
bool gl_IsHUDModelForPlayerAvailable (player_t * player);
|
||||
|
||||
#endif
|
554
src/gl/models/gl_models_md2.cpp
Normal file
554
src/gl/models/gl_models_md2.cpp
Normal file
|
@ -0,0 +1,554 @@
|
|||
/*
|
||||
** gl_models.cpp
|
||||
**
|
||||
** MD2/DMD model format code
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "w_wad.h"
|
||||
#include "cmdlib.h"
|
||||
#include "sc_man.h"
|
||||
#include "m_crc32.h"
|
||||
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
|
||||
static float avertexnormals[NUMVERTEXNORMALS][3] = {
|
||||
#include "tab_anorms.h"
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// UnpackVector
|
||||
// Packed: pppppppy yyyyyyyy. Yaw is on the XY plane.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static void UnpackVector(unsigned short packed, float vec[3])
|
||||
{
|
||||
float yaw = (packed & 511) / 512.0f * 2 * PI;
|
||||
float pitch = ((packed >> 9) / 127.0f - 0.5f) * PI;
|
||||
float cosp = (float) cos(pitch);
|
||||
|
||||
vec[VX] = (float) cos(yaw) * cosp;
|
||||
vec[VY] = (float) sin(yaw) * cosp;
|
||||
vec[VZ] = (float) sin(pitch);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// DMD file structure
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
struct dmd_chunk_t
|
||||
{
|
||||
int type;
|
||||
int length; // Next chunk follows...
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
struct dmd_packedVertex_t
|
||||
{
|
||||
byte vertex[3];
|
||||
unsigned short normal; // Yaw and pitch.
|
||||
};
|
||||
|
||||
struct dmd_packedFrame_t
|
||||
{
|
||||
float scale[3];
|
||||
float translate[3];
|
||||
char name[16];
|
||||
dmd_packedVertex_t vertices[1];
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
// Chunk types.
|
||||
enum
|
||||
{
|
||||
DMC_END, // Must be the last chunk.
|
||||
DMC_INFO // Required; will be expected to exist.
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDMDModel::Load
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FDMDModel::Load(const char * path, int lumpnum, const char * buffer, int length)
|
||||
{
|
||||
dmd_chunk_t * chunk = (dmd_chunk_t*)(buffer + 12);
|
||||
char *temp;
|
||||
ModelFrame *frame;
|
||||
int i;
|
||||
|
||||
int fileoffset = 12 + sizeof(dmd_chunk_t);
|
||||
|
||||
chunk->type = LittleLong(chunk->type);
|
||||
while (chunk->type != DMC_END)
|
||||
{
|
||||
switch (chunk->type)
|
||||
{
|
||||
case DMC_INFO: // Standard DMD information chunk.
|
||||
memcpy(&info, buffer + fileoffset, LittleLong(chunk->length));
|
||||
info.skinWidth = LittleLong(info.skinWidth);
|
||||
info.skinHeight = LittleLong(info.skinHeight);
|
||||
info.frameSize = LittleLong(info.frameSize);
|
||||
info.numSkins = LittleLong(info.numSkins);
|
||||
info.numVertices = LittleLong(info.numVertices);
|
||||
info.numTexCoords = LittleLong(info.numTexCoords);
|
||||
info.numFrames = LittleLong(info.numFrames);
|
||||
info.numLODs = LittleLong(info.numLODs);
|
||||
info.offsetSkins = LittleLong(info.offsetSkins);
|
||||
info.offsetTexCoords = LittleLong(info.offsetTexCoords);
|
||||
info.offsetFrames = LittleLong(info.offsetFrames);
|
||||
info.offsetLODs = LittleLong(info.offsetLODs);
|
||||
info.offsetEnd = LittleLong(info.offsetEnd);
|
||||
fileoffset += chunk->length;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Just skip all unknown chunks.
|
||||
fileoffset += chunk->length;
|
||||
break;
|
||||
}
|
||||
// Read the next chunk header.
|
||||
chunk = (dmd_chunk_t*)(buffer + fileoffset);
|
||||
chunk->type = LittleLong(chunk->type);
|
||||
fileoffset += sizeof(dmd_chunk_t);
|
||||
}
|
||||
|
||||
// Allocate and load in the data.
|
||||
skins = new FTexture *[info.numSkins];
|
||||
|
||||
for (i = 0; i < info.numSkins; i++)
|
||||
{
|
||||
skins[i] = LoadSkin(path, buffer + info.offsetSkins + i * 64);
|
||||
}
|
||||
temp = (char*)buffer + info.offsetFrames;
|
||||
frames = new ModelFrame[info.numFrames];
|
||||
|
||||
for (i = 0, frame = frames; i < info.numFrames; i++, frame++)
|
||||
{
|
||||
dmd_packedFrame_t *pfr = (dmd_packedFrame_t *)(temp + info.frameSize * i);
|
||||
|
||||
memcpy(frame->name, pfr->name, sizeof(pfr->name));
|
||||
frame->vindex = UINT_MAX;
|
||||
}
|
||||
mLumpNum = lumpnum;
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDMDModel::LoadGeometry
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FDMDModel::LoadGeometry()
|
||||
{
|
||||
static int axis[3] = { VX, VY, VZ };
|
||||
FMemLump lumpdata = Wads.ReadLump(mLumpNum);
|
||||
const char *buffer = (const char *)lumpdata.GetMem();
|
||||
texCoords = new FTexCoord[info.numTexCoords];
|
||||
memcpy(texCoords, buffer + info.offsetTexCoords, info.numTexCoords * sizeof(FTexCoord));
|
||||
|
||||
const char *temp = buffer + info.offsetFrames;
|
||||
framevtx= new ModelFrameVertexData[info.numFrames];
|
||||
|
||||
ModelFrameVertexData *framev;
|
||||
int i, k, c;
|
||||
for(i = 0, framev = framevtx; i < info.numFrames; i++, framev++)
|
||||
{
|
||||
dmd_packedFrame_t *pfr = (dmd_packedFrame_t *) (temp + info.frameSize * i);
|
||||
dmd_packedVertex_t *pVtx;
|
||||
|
||||
framev->vertices = new DMDModelVertex[info.numVertices];
|
||||
framev->normals = new DMDModelVertex[info.numVertices];
|
||||
|
||||
// Translate each vertex.
|
||||
for(k = 0, pVtx = pfr->vertices; k < info.numVertices; k++, pVtx++)
|
||||
{
|
||||
UnpackVector((unsigned short)(pVtx->normal), framev->normals[k].xyz);
|
||||
for(c = 0; c < 3; c++)
|
||||
{
|
||||
framev->vertices[k].xyz[axis[c]] =
|
||||
(pVtx->vertex[c] * FLOAT(pfr->scale[c]) + FLOAT(pfr->translate[c]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(lodInfo, buffer+info.offsetLODs, info.numLODs * sizeof(DMDLoDInfo));
|
||||
for(i = 0; i < info.numLODs; i++)
|
||||
{
|
||||
lodInfo[i].numTriangles = LittleLong(lodInfo[i].numTriangles);
|
||||
lodInfo[i].offsetTriangles = LittleLong(lodInfo[i].offsetTriangles);
|
||||
if (lodInfo[i].numTriangles > 0)
|
||||
{
|
||||
lods[i].triangles = new FTriangle[lodInfo[i].numTriangles];
|
||||
memcpy(lods[i].triangles, buffer + lodInfo[i].offsetTriangles, lodInfo[i].numTriangles * sizeof(FTriangle));
|
||||
for (int j = 0; j < lodInfo[i].numTriangles; j++)
|
||||
{
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
lods[i].triangles[j].textureIndices[k] = LittleShort(lods[i].triangles[j].textureIndices[k]);
|
||||
lods[i].triangles[j].vertexIndices[k] = LittleShort(lods[i].triangles[j].vertexIndices[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Deletes everything that's no longer needed after building the vertex buffer
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FDMDModel::UnloadGeometry()
|
||||
{
|
||||
int i;
|
||||
|
||||
if (framevtx != NULL)
|
||||
{
|
||||
for (i=0;i<info.numFrames;i++)
|
||||
{
|
||||
if (framevtx[i].vertices != NULL) delete [] framevtx[i].vertices;
|
||||
if (framevtx[i].normals != NULL) delete [] framevtx[i].normals;
|
||||
|
||||
framevtx[i].vertices = NULL;
|
||||
framevtx[i].normals = NULL;
|
||||
}
|
||||
delete[] framevtx;
|
||||
framevtx = NULL;
|
||||
}
|
||||
|
||||
for(i = 0; i < info.numLODs; i++)
|
||||
{
|
||||
if (lods[i].triangles != NULL) delete[] lods[i].triangles;
|
||||
lods[i].triangles = NULL;
|
||||
}
|
||||
|
||||
if (texCoords != NULL) delete[] texCoords;
|
||||
texCoords = NULL;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FDMDModel::~FDMDModel()
|
||||
{
|
||||
UnloadGeometry();
|
||||
|
||||
// skins are managed by the texture manager so they must not be deleted here.
|
||||
if (skins != NULL) delete [] skins;
|
||||
if (frames != NULL) delete [] frames;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FDMDModel::BuildVertexBuffer()
|
||||
{
|
||||
if (mVBuf == NULL)
|
||||
{
|
||||
LoadGeometry();
|
||||
|
||||
int VertexBufferSize = info.numFrames * lodInfo[0].numTriangles * 3;
|
||||
unsigned int vindex = 0;
|
||||
|
||||
mVBuf = new FModelVertexBuffer(false);
|
||||
FModelVertex *vertptr = mVBuf->LockVertexBuffer(VertexBufferSize);
|
||||
|
||||
for (int i = 0; i < info.numFrames; i++)
|
||||
{
|
||||
DMDModelVertex *vert = framevtx[i].vertices;
|
||||
DMDModelVertex *norm = framevtx[i].normals;
|
||||
|
||||
frames[i].vindex = vindex;
|
||||
|
||||
FTriangle *tri = lods[0].triangles;
|
||||
|
||||
for (int i = 0; i < lodInfo[0].numTriangles; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
|
||||
int ti = tri->textureIndices[j];
|
||||
int vi = tri->vertexIndices[j];
|
||||
|
||||
FModelVertex *bvert = &vertptr[vindex++];
|
||||
bvert->Set(vert[vi].xyz[0], vert[vi].xyz[1], vert[vi].xyz[2], (float)texCoords[ti].s / info.skinWidth, (float)texCoords[ti].t / info.skinHeight);
|
||||
bvert->SetNormal(norm[vi].xyz[0], norm[vi].xyz[1], norm[vi].xyz[2]);
|
||||
}
|
||||
tri++;
|
||||
}
|
||||
}
|
||||
mVBuf->UnlockVertexBuffer();
|
||||
UnloadGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDMDModel::FindFrame
|
||||
//
|
||||
//===========================================================================
|
||||
int FDMDModel::FindFrame(const char * name)
|
||||
{
|
||||
for (int i=0;i<info.numFrames;i++)
|
||||
{
|
||||
if (!stricmp(name, frames[i].name)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FDMDModel::RenderFrame(FTexture * skin, int frameno, int frameno2, double inter, int translation)
|
||||
{
|
||||
if (frameno >= info.numFrames || frameno2 >= info.numFrames) return;
|
||||
|
||||
if (!skin)
|
||||
{
|
||||
if (info.numSkins == 0) return;
|
||||
skin = skins[0];
|
||||
if (!skin) return;
|
||||
}
|
||||
|
||||
FMaterial * tex = FMaterial::ValidateTexture(skin, false);
|
||||
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_NONE, translation, -1, false);
|
||||
gl_RenderState.SetInterpolationFactor((float)inter);
|
||||
|
||||
gl_RenderState.Apply();
|
||||
mVBuf->SetupFrame(frames[frameno].vindex, frames[frameno2].vindex);
|
||||
glDrawArrays(GL_TRIANGLES, 0, lodInfo[0].numTriangles * 3);
|
||||
gl_RenderState.SetInterpolationFactor(0.f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Internal data structures of MD2 files - only used during loading
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
struct md2_header_t
|
||||
{
|
||||
int magic;
|
||||
int version;
|
||||
int skinWidth;
|
||||
int skinHeight;
|
||||
int frameSize;
|
||||
int numSkins;
|
||||
int numVertices;
|
||||
int numTexCoords;
|
||||
int numTriangles;
|
||||
int numGlCommands;
|
||||
int numFrames;
|
||||
int offsetSkins;
|
||||
int offsetTexCoords;
|
||||
int offsetTriangles;
|
||||
int offsetFrames;
|
||||
int offsetGlCommands;
|
||||
int offsetEnd;
|
||||
};
|
||||
|
||||
struct md2_triangleVertex_t
|
||||
{
|
||||
byte vertex[3];
|
||||
byte lightNormalIndex;
|
||||
};
|
||||
|
||||
struct md2_packedFrame_t
|
||||
{
|
||||
float scale[3];
|
||||
float translate[3];
|
||||
char name[16];
|
||||
md2_triangleVertex_t vertices[1];
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FMD2Model::Load
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FMD2Model::Load(const char * path, int lumpnum, const char * buffer, int length)
|
||||
{
|
||||
md2_header_t * md2header = (md2_header_t *)buffer;
|
||||
ModelFrame *frame;
|
||||
byte *md2_frames;
|
||||
int i;
|
||||
|
||||
// Convert it to DMD.
|
||||
header.magic = MD2_MAGIC;
|
||||
header.version = 8;
|
||||
header.flags = 0;
|
||||
info.skinWidth = LittleLong(md2header->skinWidth);
|
||||
info.skinHeight = LittleLong(md2header->skinHeight);
|
||||
info.frameSize = LittleLong(md2header->frameSize);
|
||||
info.numLODs = 1;
|
||||
info.numSkins = LittleLong(md2header->numSkins);
|
||||
info.numTexCoords = LittleLong(md2header->numTexCoords);
|
||||
info.numVertices = LittleLong(md2header->numVertices);
|
||||
info.numFrames = LittleLong(md2header->numFrames);
|
||||
info.offsetSkins = LittleLong(md2header->offsetSkins);
|
||||
info.offsetTexCoords = LittleLong(md2header->offsetTexCoords);
|
||||
info.offsetFrames = LittleLong(md2header->offsetFrames);
|
||||
info.offsetLODs = LittleLong(md2header->offsetEnd); // Doesn't exist.
|
||||
lodInfo[0].numTriangles = LittleLong(md2header->numTriangles);
|
||||
lodInfo[0].numGlCommands = LittleLong(md2header->numGlCommands);
|
||||
lodInfo[0].offsetTriangles = LittleLong(md2header->offsetTriangles);
|
||||
lodInfo[0].offsetGlCommands = LittleLong(md2header->offsetGlCommands);
|
||||
info.offsetEnd = LittleLong(md2header->offsetEnd);
|
||||
|
||||
if (info.offsetFrames + info.frameSize * info.numFrames > length)
|
||||
{
|
||||
Printf("LoadModel: Model '%s' file too short\n", path);
|
||||
return false;
|
||||
}
|
||||
if (lodInfo[0].numGlCommands <= 0)
|
||||
{
|
||||
Printf("LoadModel: Model '%s' invalid NumGLCommands\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
skins = new FTexture *[info.numSkins];
|
||||
|
||||
for (i = 0; i < info.numSkins; i++)
|
||||
{
|
||||
skins[i] = LoadSkin(path, buffer + info.offsetSkins + i * 64);
|
||||
}
|
||||
|
||||
// The frames need to be unpacked.
|
||||
md2_frames = (byte*)buffer + info.offsetFrames;
|
||||
frames = new ModelFrame[info.numFrames];
|
||||
|
||||
for (i = 0, frame = frames; i < info.numFrames; i++, frame++)
|
||||
{
|
||||
md2_packedFrame_t *pfr = (md2_packedFrame_t *)(md2_frames + info.frameSize * i);
|
||||
|
||||
memcpy(frame->name, pfr->name, sizeof(pfr->name));
|
||||
frame->vindex = UINT_MAX;
|
||||
}
|
||||
mLumpNum = lumpnum;
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FMD2Model::LoadGeometry
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FMD2Model::LoadGeometry()
|
||||
{
|
||||
static int axis[3] = { VX, VY, VZ };
|
||||
byte *md2_frames;
|
||||
FMemLump lumpdata = Wads.ReadLump(mLumpNum);
|
||||
const char *buffer = (const char *)lumpdata.GetMem();
|
||||
|
||||
texCoords = new FTexCoord[info.numTexCoords];
|
||||
memcpy(texCoords, (byte*)buffer + info.offsetTexCoords, info.numTexCoords * sizeof(FTexCoord));
|
||||
|
||||
md2_frames = (byte*)buffer + info.offsetFrames;
|
||||
framevtx = new ModelFrameVertexData[info.numFrames];
|
||||
ModelFrameVertexData *framev;
|
||||
int i, k, c;
|
||||
|
||||
for(i = 0, framev = framevtx; i < info.numFrames; i++, framev++)
|
||||
{
|
||||
md2_packedFrame_t *pfr = (md2_packedFrame_t *) (md2_frames + info.frameSize * i);
|
||||
md2_triangleVertex_t *pVtx;
|
||||
|
||||
framev->vertices = new DMDModelVertex[info.numVertices];
|
||||
framev->normals = new DMDModelVertex[info.numVertices];
|
||||
|
||||
// Translate each vertex.
|
||||
for(k = 0, pVtx = pfr->vertices; k < info.numVertices; k++, pVtx++)
|
||||
{
|
||||
memcpy(framev->normals[k].xyz,
|
||||
avertexnormals[pVtx->lightNormalIndex], sizeof(float) * 3);
|
||||
|
||||
for(c = 0; c < 3; c++)
|
||||
{
|
||||
framev->vertices[k].xyz[axis[c]] =
|
||||
(pVtx->vertex[c] * pfr->scale[c] + pfr->translate[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lods[0].triangles = new FTriangle[lodInfo[0].numTriangles];
|
||||
|
||||
int cnt = lodInfo[0].numTriangles;
|
||||
memcpy(lods[0].triangles, buffer + lodInfo[0].offsetTriangles, sizeof(FTriangle) * cnt);
|
||||
for (int j = 0; j < cnt; j++)
|
||||
{
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
lods[0].triangles[j].textureIndices[k] = LittleShort(lods[0].triangles[j].textureIndices[k]);
|
||||
lods[0].triangles[j].vertexIndices[k] = LittleShort(lods[0].triangles[j].vertexIndices[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FMD2Model::~FMD2Model()
|
||||
{
|
||||
}
|
||||
|
375
src/gl/models/gl_models_md3.cpp
Normal file
375
src/gl/models/gl_models_md3.cpp
Normal file
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
** gl_models_md3.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2006 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "w_wad.h"
|
||||
#include "cmdlib.h"
|
||||
#include "sc_man.h"
|
||||
#include "m_crc32.h"
|
||||
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
|
||||
#define MAX_QPATH 64
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// decode the lat/lng normal to a 3 float normal
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static void UnpackVector(unsigned short packed, float & nx, float & ny, float & nz)
|
||||
{
|
||||
double lat = ( packed >> 8 ) & 0xff;
|
||||
double lng = ( packed & 0xff );
|
||||
lat *= PI/128;
|
||||
lng *= PI/128;
|
||||
|
||||
nx = cos(lat) * sin(lng);
|
||||
ny = sin(lat) * sin(lng);
|
||||
nz = cos(lng);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// MD3 File structure
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
#pragma pack(4)
|
||||
struct md3_header_t
|
||||
{
|
||||
DWORD Magic;
|
||||
DWORD Version;
|
||||
char Name[MAX_QPATH];
|
||||
DWORD Flags;
|
||||
DWORD Num_Frames;
|
||||
DWORD Num_Tags;
|
||||
DWORD Num_Surfaces;
|
||||
DWORD Num_Skins;
|
||||
DWORD Ofs_Frames;
|
||||
DWORD Ofs_Tags;
|
||||
DWORD Ofs_Surfaces;
|
||||
DWORD Ofs_Eof;
|
||||
};
|
||||
|
||||
struct md3_surface_t
|
||||
{
|
||||
DWORD Magic;
|
||||
char Name[MAX_QPATH];
|
||||
DWORD Flags;
|
||||
DWORD Num_Frames;
|
||||
DWORD Num_Shaders;
|
||||
DWORD Num_Verts;
|
||||
DWORD Num_Triangles;
|
||||
DWORD Ofs_Triangles;
|
||||
DWORD Ofs_Shaders;
|
||||
DWORD Ofs_Texcoord;
|
||||
DWORD Ofs_XYZNormal;
|
||||
DWORD Ofs_End;
|
||||
};
|
||||
|
||||
struct md3_triangle_t
|
||||
{
|
||||
DWORD vt_index[3];
|
||||
};
|
||||
|
||||
struct md3_shader_t
|
||||
{
|
||||
char Name[MAX_QPATH];
|
||||
DWORD index;
|
||||
};
|
||||
|
||||
struct md3_texcoord_t
|
||||
{
|
||||
float s, t;
|
||||
};
|
||||
|
||||
struct md3_vertex_t
|
||||
{
|
||||
short x, y, z, n;
|
||||
};
|
||||
|
||||
struct md3_frame_t
|
||||
{
|
||||
float min_Bounds[3];
|
||||
float max_Bounds[3];
|
||||
float localorigin[3];
|
||||
float radius;
|
||||
char Name[16];
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FMD3Model::Load(const char * path, int lumpnum, const char * buffer, int length)
|
||||
{
|
||||
md3_header_t * hdr = (md3_header_t *)buffer;
|
||||
|
||||
numFrames = LittleLong(hdr->Num_Frames);
|
||||
numTags = LittleLong(hdr->Num_Tags);
|
||||
numSurfaces = LittleLong(hdr->Num_Surfaces);
|
||||
|
||||
md3_frame_t * frm = (md3_frame_t*)(buffer + LittleLong(hdr->Ofs_Frames));
|
||||
|
||||
frames = new MD3Frame[numFrames];
|
||||
for (int i = 0; i < numFrames; i++)
|
||||
{
|
||||
strncpy(frames[i].Name, frm[i].Name, 16);
|
||||
for (int j = 0; j < 3; j++) frames[i].origin[j] = frm[i].localorigin[j];
|
||||
}
|
||||
|
||||
md3_surface_t * surf = (md3_surface_t*)(buffer + LittleLong(hdr->Ofs_Surfaces));
|
||||
|
||||
surfaces = new MD3Surface[numSurfaces];
|
||||
|
||||
for (int i = 0; i < numSurfaces; i++)
|
||||
{
|
||||
MD3Surface * s = &surfaces[i];
|
||||
md3_surface_t * ss = surf;
|
||||
|
||||
surf = (md3_surface_t *)(((char*)surf) + LittleLong(surf->Ofs_End));
|
||||
|
||||
s->numSkins = LittleLong(ss->Num_Shaders);
|
||||
s->numTriangles = LittleLong(ss->Num_Triangles);
|
||||
s->numVertices = LittleLong(ss->Num_Verts);
|
||||
|
||||
// copy shaders (skins)
|
||||
md3_shader_t * shader = (md3_shader_t*)(((char*)ss) + LittleLong(ss->Ofs_Shaders));
|
||||
s->skins = new FTexture *[s->numSkins];
|
||||
|
||||
for (int i = 0; i < s->numSkins; i++)
|
||||
{
|
||||
// [BB] According to the MD3 spec, Name is supposed to include the full path.
|
||||
s->skins[i] = LoadSkin("", shader[i].Name);
|
||||
// [BB] Fall back and check if Name is relative.
|
||||
if (s->skins[i] == NULL)
|
||||
s->skins[i] = LoadSkin(path, shader[i].Name);
|
||||
}
|
||||
}
|
||||
mLumpNum = lumpnum;
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FMD3Model::LoadGeometry()
|
||||
{
|
||||
FMemLump lumpdata = Wads.ReadLump(mLumpNum);
|
||||
const char *buffer = (const char *)lumpdata.GetMem();
|
||||
md3_header_t * hdr = (md3_header_t *)buffer;
|
||||
md3_surface_t * surf = (md3_surface_t*)(buffer + LittleLong(hdr->Ofs_Surfaces));
|
||||
|
||||
for(int i=0;i<numSurfaces;i++)
|
||||
{
|
||||
MD3Surface * s = &surfaces[i];
|
||||
md3_surface_t * ss = surf;
|
||||
|
||||
surf = (md3_surface_t *)(((char*)surf) + LittleLong(surf->Ofs_End));
|
||||
|
||||
// copy triangle indices
|
||||
md3_triangle_t * tris = (md3_triangle_t*)(((char*)ss)+LittleLong(ss->Ofs_Triangles));
|
||||
s->tris = new MD3Triangle[s->numTriangles];
|
||||
|
||||
for(int i=0;i<s->numTriangles;i++) for (int j=0;j<3;j++)
|
||||
{
|
||||
s->tris[i].VertIndex[j]=LittleLong(tris[i].vt_index[j]);
|
||||
}
|
||||
|
||||
// Load texture coordinates
|
||||
md3_texcoord_t * tc = (md3_texcoord_t*)(((char*)ss)+LittleLong(ss->Ofs_Texcoord));
|
||||
s->texcoords = new MD3TexCoord[s->numVertices];
|
||||
|
||||
for(int i=0;i<s->numVertices;i++)
|
||||
{
|
||||
s->texcoords[i].s = tc[i].s;
|
||||
s->texcoords[i].t = tc[i].t;
|
||||
}
|
||||
|
||||
// Load vertices and texture coordinates
|
||||
md3_vertex_t * vt = (md3_vertex_t*)(((char*)ss)+LittleLong(ss->Ofs_XYZNormal));
|
||||
s->vertices = new MD3Vertex[s->numVertices * numFrames];
|
||||
|
||||
for(int i=0;i<s->numVertices * numFrames;i++)
|
||||
{
|
||||
s->vertices[i].x = LittleShort(vt[i].x)/64.f;
|
||||
s->vertices[i].y = LittleShort(vt[i].y)/64.f;
|
||||
s->vertices[i].z = LittleShort(vt[i].z)/64.f;
|
||||
UnpackVector( LittleShort(vt[i].n), s->vertices[i].nx, s->vertices[i].ny, s->vertices[i].nz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FMD3Model::BuildVertexBuffer()
|
||||
{
|
||||
if (mVBuf == NULL)
|
||||
{
|
||||
LoadGeometry();
|
||||
|
||||
unsigned int vbufsize = 0;
|
||||
unsigned int ibufsize = 0;
|
||||
|
||||
for (int i = 0; i < numSurfaces; i++)
|
||||
{
|
||||
MD3Surface * surf = &surfaces[i];
|
||||
vbufsize += numFrames * surf->numVertices;
|
||||
ibufsize += 3 * surf->numTriangles;
|
||||
}
|
||||
|
||||
mVBuf = new FModelVertexBuffer(true);
|
||||
FModelVertex *vertptr = mVBuf->LockVertexBuffer(vbufsize);
|
||||
unsigned int *indxptr = mVBuf->LockIndexBuffer(ibufsize);
|
||||
|
||||
assert(vertptr != NULL && indxptr != NULL);
|
||||
|
||||
unsigned int vindex = 0, iindex = 0;
|
||||
|
||||
for (int i = 0; i < numSurfaces; i++)
|
||||
{
|
||||
MD3Surface * surf = &surfaces[i];
|
||||
|
||||
surf->vindex = vindex;
|
||||
surf->iindex = iindex;
|
||||
for (int j = 0; j < numFrames * surf->numVertices; j++)
|
||||
{
|
||||
MD3Vertex* vert = surf->vertices + j;
|
||||
|
||||
FModelVertex *bvert = &vertptr[vindex++];
|
||||
|
||||
int tc = j % surf->numVertices;
|
||||
bvert->Set(vert->x, vert->z, vert->y, surf->texcoords[tc].s, surf->texcoords[tc].t);
|
||||
bvert->SetNormal(vert->nx, vert->nz, vert->ny);
|
||||
}
|
||||
|
||||
for (int k = 0; k < surf->numTriangles; k++)
|
||||
{
|
||||
for (int l = 0; l < 3; l++)
|
||||
{
|
||||
indxptr[iindex++] = surf->tris[k].VertIndex[l];
|
||||
}
|
||||
}
|
||||
surf->UnloadGeometry();
|
||||
}
|
||||
mVBuf->UnlockVertexBuffer();
|
||||
mVBuf->UnlockIndexBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FMD3Model::FindFrame(const char * name)
|
||||
{
|
||||
for (int i=0;i<numFrames;i++)
|
||||
{
|
||||
if (!stricmp(name, frames[i].Name)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double inter, int translation)
|
||||
{
|
||||
if (frameno>=numFrames || frameno2>=numFrames) return;
|
||||
|
||||
gl_RenderState.SetInterpolationFactor((float)inter);
|
||||
for(int i=0;i<numSurfaces;i++)
|
||||
{
|
||||
MD3Surface * surf = &surfaces[i];
|
||||
|
||||
// [BB] In case no skin is specified via MODELDEF, check if the MD3 has a skin for the current surface.
|
||||
// Note: Each surface may have a different skin.
|
||||
FTexture *surfaceSkin = skin;
|
||||
if (!surfaceSkin)
|
||||
{
|
||||
if (surf->numSkins==0) return;
|
||||
surfaceSkin = surf->skins[0];
|
||||
if (!surfaceSkin) return;
|
||||
}
|
||||
|
||||
FMaterial * tex = FMaterial::ValidateTexture(surfaceSkin, false);
|
||||
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_NONE, translation, -1, false);
|
||||
|
||||
gl_RenderState.Apply();
|
||||
mVBuf->SetupFrame(surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices);
|
||||
glDrawElements(GL_TRIANGLES, surf->numTriangles * 3, GL_UNSIGNED_INT, (void*)(intptr_t)(surf->iindex * sizeof(unsigned int)));
|
||||
}
|
||||
gl_RenderState.SetInterpolationFactor(0.f);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FMD3Model::~FMD3Model()
|
||||
{
|
||||
if (frames) delete [] frames;
|
||||
if (surfaces) delete [] surfaces;
|
||||
frames = NULL;
|
||||
surfaces = NULL;
|
||||
}
|
449
src/gl/models/gl_voxels.cpp
Normal file
449
src/gl/models/gl_voxels.cpp
Normal file
|
@ -0,0 +1,449 @@
|
|||
/*
|
||||
** gl_voxels.cpp
|
||||
**
|
||||
** Voxel management
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "w_wad.h"
|
||||
#include "cmdlib.h"
|
||||
#include "sc_man.h"
|
||||
#include "m_crc32.h"
|
||||
#include "c_console.h"
|
||||
#include "g_game.h"
|
||||
#include "doomstat.h"
|
||||
#include "g_level.h"
|
||||
#include "colormatcher.h"
|
||||
#include "textures/bitmap.h"
|
||||
//#include "gl/gl_intern.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/utility/gl_geometric.h"
|
||||
#include "gl/utility/gl_convert.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Creates a 16x16 texture from the palette so that we can
|
||||
// use the existing palette manipulation code to render the voxel
|
||||
// Otherwise all shaders had to be duplicated and the non-shader code
|
||||
// would be a lot less efficient.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
class FVoxelTexture : public FTexture
|
||||
{
|
||||
public:
|
||||
|
||||
FVoxelTexture(FVoxel *voxel);
|
||||
~FVoxelTexture();
|
||||
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
|
||||
const BYTE *GetPixels ();
|
||||
void Unload ();
|
||||
|
||||
int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf);
|
||||
bool UseBasePalette() { return false; }
|
||||
|
||||
protected:
|
||||
FVoxel *SourceVox;
|
||||
BYTE *Pixels;
|
||||
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FVoxelTexture::FVoxelTexture(FVoxel *vox)
|
||||
{
|
||||
SourceVox = vox;
|
||||
Width = 16;
|
||||
Height = 16;
|
||||
WidthBits = 4;
|
||||
HeightBits = 4;
|
||||
WidthMask = 15;
|
||||
Pixels = NULL;
|
||||
gl_info.bNoFilter = true;
|
||||
gl_info.bNoCompress = true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FVoxelTexture::~FVoxelTexture()
|
||||
{
|
||||
}
|
||||
|
||||
const BYTE *FVoxelTexture::GetColumn (unsigned int column, const Span **spans_out)
|
||||
{
|
||||
// not needed
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const BYTE *FVoxelTexture::GetPixels ()
|
||||
{
|
||||
// GetPixels gets called when a translated palette is used so we still need to implement it here.
|
||||
if (Pixels == NULL)
|
||||
{
|
||||
Pixels = new BYTE[256];
|
||||
|
||||
BYTE *pp = SourceVox->Palette;
|
||||
|
||||
if(pp != NULL)
|
||||
{
|
||||
for(int i=0;i<256;i++, pp+=3)
|
||||
{
|
||||
PalEntry pe;
|
||||
pe.r = (pp[0] << 2) | (pp[0] >> 4);
|
||||
pe.g = (pp[1] << 2) | (pp[1] >> 4);
|
||||
pe.b = (pp[2] << 2) | (pp[2] >> 4);
|
||||
Pixels[i] = ColorMatcher.Pick(pe);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i=0;i<256;i++, pp+=3)
|
||||
{
|
||||
Pixels[i] = (BYTE)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Pixels;
|
||||
}
|
||||
|
||||
void FVoxelTexture::Unload ()
|
||||
{
|
||||
if (Pixels != NULL)
|
||||
{
|
||||
delete[] Pixels;
|
||||
Pixels = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FVoxelTexture::CopyTrueColorPixels
|
||||
//
|
||||
// This creates a dummy 16x16 paletted bitmap and converts that using the
|
||||
// voxel palette
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FVoxelTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf)
|
||||
{
|
||||
PalEntry pe[256];
|
||||
BYTE bitmap[256];
|
||||
BYTE *pp = SourceVox->Palette;
|
||||
|
||||
if(pp != NULL)
|
||||
{
|
||||
for(int i=0;i<256;i++, pp+=3)
|
||||
{
|
||||
bitmap[i] = (BYTE)i;
|
||||
pe[i].r = (pp[0] << 2) | (pp[0] >> 4);
|
||||
pe[i].g = (pp[1] << 2) | (pp[1] >> 4);
|
||||
pe[i].b = (pp[2] << 2) | (pp[2] >> 4);
|
||||
pe[i].a = 255;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i=0;i<256;i++, pp+=3)
|
||||
{
|
||||
bitmap[i] = (BYTE)i;
|
||||
pe[i] = GPalette.BaseColors[i];
|
||||
pe[i].a = 255;
|
||||
}
|
||||
}
|
||||
bmp->CopyPixelData(x, y, bitmap, Width, Height, 1, 16, rotate, pe, inf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FVoxelModel::FVoxelModel(FVoxel *voxel, bool owned)
|
||||
{
|
||||
mVoxel = voxel;
|
||||
mOwningVoxel = owned;
|
||||
mPalette = new FVoxelTexture(voxel);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FVoxelModel::~FVoxelModel()
|
||||
{
|
||||
delete mPalette;
|
||||
if (mOwningVoxel) delete mVoxel;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
unsigned int FVoxelModel::AddVertex(FModelVertex &vert, FVoxelMap &check)
|
||||
{
|
||||
unsigned int index = check[vert];
|
||||
if (index == 0xffffffff)
|
||||
{
|
||||
index = check[vert] =mVertices.Push(vert);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FVoxelModel::AddFace(int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3, int x4, int y4, int z4, BYTE col, FVoxelMap &check)
|
||||
{
|
||||
float PivotX = mVoxel->Mips[0].PivotX / 256.f;
|
||||
float PivotY = mVoxel->Mips[0].PivotY / 256.f;
|
||||
float PivotZ = mVoxel->Mips[0].PivotZ / 256.f;
|
||||
int h = mVoxel->Mips[0].SizeZ;
|
||||
FModelVertex vert;
|
||||
unsigned int indx[4];
|
||||
|
||||
vert.u = (((col & 15) * 255 / 16) + 7) / 255.f;
|
||||
vert.v = (((col / 16) * 255 / 16) + 7) / 255.f;
|
||||
|
||||
vert.x = x1 - PivotX;
|
||||
vert.z = -y1 + PivotY;
|
||||
vert.y = -z1 + PivotZ;
|
||||
indx[0] = AddVertex(vert, check);
|
||||
|
||||
vert.x = x2 - PivotX;
|
||||
vert.z = -y2 + PivotY;
|
||||
vert.y = -z2 + PivotZ;
|
||||
indx[1] = AddVertex(vert, check);
|
||||
|
||||
vert.x = x4 - PivotX;
|
||||
vert.z = -y4 + PivotY;
|
||||
vert.y = -z4 + PivotZ;
|
||||
indx[2] = AddVertex(vert, check);
|
||||
|
||||
vert.x = x3 - PivotX;
|
||||
vert.z = -y3 + PivotY;
|
||||
vert.y = -z3 + PivotZ;
|
||||
indx[3] = AddVertex(vert, check);
|
||||
|
||||
mIndices.Push(indx[0]);
|
||||
mIndices.Push(indx[1]);
|
||||
mIndices.Push(indx[3]);
|
||||
mIndices.Push(indx[1]);
|
||||
mIndices.Push(indx[3]);
|
||||
mIndices.Push(indx[2]);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FVoxelModel::MakeSlabPolys(int x, int y, kvxslab_t *voxptr, FVoxelMap &check)
|
||||
{
|
||||
const BYTE *col = voxptr->col;
|
||||
int zleng = voxptr->zleng;
|
||||
int ztop = voxptr->ztop;
|
||||
int cull = voxptr->backfacecull;
|
||||
|
||||
if (cull & 16)
|
||||
{
|
||||
AddFace(x, y, ztop, x+1, y, ztop, x, y+1, ztop, x+1, y+1, ztop, *col, check);
|
||||
}
|
||||
int z = ztop;
|
||||
while (z < ztop+zleng)
|
||||
{
|
||||
int c = 0;
|
||||
while (z+c < ztop+zleng && col[c] == col[0]) c++;
|
||||
|
||||
if (cull & 1)
|
||||
{
|
||||
AddFace(x, y, z, x, y+1, z, x, y, z+c, x, y+1, z+c, *col, check);
|
||||
}
|
||||
if (cull & 2)
|
||||
{
|
||||
AddFace(x+1, y+1, z, x+1, y, z, x+1, y+1, z+c, x+1, y, z+c, *col, check);
|
||||
}
|
||||
if (cull & 4)
|
||||
{
|
||||
AddFace(x, y, z, x+1, y, z, x, y, z+c, x+1, y, z+c, *col, check);
|
||||
}
|
||||
if (cull & 8)
|
||||
{
|
||||
AddFace(x+1, y+1, z, x, y+1, z, x+1, y+1, z+c, x, y+1, z+c, *col, check);
|
||||
}
|
||||
z+=c;
|
||||
col+=c;
|
||||
}
|
||||
if (cull & 32)
|
||||
{
|
||||
int z = ztop+zleng-1;
|
||||
AddFace(x+1, y, z+1, x, y, z+1, x+1, y+1, z+1, x, y+1, z+1, voxptr->col[zleng-1], check);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FVoxelModel::Initialize()
|
||||
{
|
||||
FVoxelMap check;
|
||||
FVoxelMipLevel *mip = &mVoxel->Mips[0];
|
||||
for (int x = 0; x < mip->SizeX; x++)
|
||||
{
|
||||
BYTE *slabxoffs = &mip->SlabData[mip->OffsetX[x]];
|
||||
short *xyoffs = &mip->OffsetXY[x * (mip->SizeY + 1)];
|
||||
for (int y = 0; y < mip->SizeY; y++)
|
||||
{
|
||||
kvxslab_t *voxptr = (kvxslab_t *)(slabxoffs + xyoffs[y]);
|
||||
kvxslab_t *voxend = (kvxslab_t *)(slabxoffs + xyoffs[y+1]);
|
||||
for (; voxptr < voxend; voxptr = (kvxslab_t *)((BYTE *)voxptr + voxptr->zleng + 3))
|
||||
{
|
||||
MakeSlabPolys(x, y, voxptr, check);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FVoxelModel::BuildVertexBuffer()
|
||||
{
|
||||
if (mVBuf == NULL)
|
||||
{
|
||||
Initialize();
|
||||
|
||||
mVBuf = new FModelVertexBuffer(true);
|
||||
FModelVertex *vertptr = mVBuf->LockVertexBuffer(mVertices.Size());
|
||||
unsigned int *indxptr = mVBuf->LockIndexBuffer(mIndices.Size());
|
||||
|
||||
memcpy(vertptr, &mVertices[0], sizeof(FModelVertex)* mVertices.Size());
|
||||
memcpy(indxptr, &mIndices[0], sizeof(unsigned int)* mIndices.Size());
|
||||
|
||||
mVBuf->UnlockVertexBuffer();
|
||||
mVBuf->UnlockIndexBuffer();
|
||||
mNumIndices = mIndices.Size();
|
||||
|
||||
// delete our temporary buffers
|
||||
mVertices.Clear();
|
||||
mIndices.Clear();
|
||||
mVertices.ShrinkToFit();
|
||||
mIndices.ShrinkToFit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FVoxelModel::Load(const char * fn, int lumpnum, const char * buffer, int length)
|
||||
{
|
||||
return false; // not needed
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Voxels don't have frames so always return 0
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FVoxelModel::FindFrame(const char * name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Voxels need aspect ratio correction according to the current map's setting
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
float FVoxelModel::getAspectFactor()
|
||||
{
|
||||
return glset.pixelstretch;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Voxels never interpolate between frames, they only have one.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FVoxelModel::RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation)
|
||||
{
|
||||
FMaterial * tex = FMaterial::ValidateTexture(skin, false);
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_NOFILTER, translation, -1, false);
|
||||
|
||||
gl_RenderState.Apply();
|
||||
mVBuf->SetupFrame(0, 0);
|
||||
glDrawElements(GL_TRIANGLES, mNumIndices, GL_UNSIGNED_INT, (void*)(intptr_t)0);
|
||||
}
|
||||
|
489
src/gl/models/tab_anorms.h
Normal file
489
src/gl/models/tab_anorms.h
Normal file
|
@ -0,0 +1,489 @@
|
|||
#ifdef WIN32
|
||||
#pragma warning(disable:4305)
|
||||
#endif
|
||||
|
||||
{
|
||||
-0.525731, 0.000000, 0.850651},
|
||||
|
||||
{
|
||||
-0.442863, 0.238856, 0.864188},
|
||||
|
||||
{
|
||||
-0.295242, 0.000000, 0.955423},
|
||||
|
||||
{
|
||||
-0.309017, 0.500000, 0.809017},
|
||||
|
||||
{
|
||||
-0.162460, 0.262866, 0.951056},
|
||||
|
||||
{
|
||||
0.000000, 0.000000, 1.000000},
|
||||
|
||||
{
|
||||
0.000000, 0.850651, 0.525731},
|
||||
|
||||
{
|
||||
-0.147621, 0.716567, 0.681718},
|
||||
|
||||
{
|
||||
0.147621, 0.716567, 0.681718},
|
||||
|
||||
{
|
||||
0.000000, 0.525731, 0.850651},
|
||||
|
||||
{
|
||||
0.309017, 0.500000, 0.809017},
|
||||
|
||||
{
|
||||
0.525731, 0.000000, 0.850651},
|
||||
|
||||
{
|
||||
0.295242, 0.000000, 0.955423},
|
||||
|
||||
{
|
||||
0.442863, 0.238856, 0.864188},
|
||||
|
||||
{
|
||||
0.162460, 0.262866, 0.951056},
|
||||
|
||||
{
|
||||
-0.681718, 0.147621, 0.716567},
|
||||
|
||||
{
|
||||
-0.809017, 0.309017, 0.500000},
|
||||
|
||||
{
|
||||
-0.587785, 0.425325, 0.688191},
|
||||
|
||||
{
|
||||
-0.850651, 0.525731, 0.000000},
|
||||
|
||||
{
|
||||
-0.864188, 0.442863, 0.238856},
|
||||
|
||||
{
|
||||
-0.716567, 0.681718, 0.147621},
|
||||
|
||||
{
|
||||
-0.688191, 0.587785, 0.425325},
|
||||
|
||||
{
|
||||
-0.500000, 0.809017, 0.309017},
|
||||
|
||||
{
|
||||
-0.238856, 0.864188, 0.442863},
|
||||
|
||||
{
|
||||
-0.425325, 0.688191, 0.587785},
|
||||
|
||||
{
|
||||
-0.716567, 0.681718, -0.147621},
|
||||
|
||||
{
|
||||
-0.500000, 0.809017, -0.309017},
|
||||
|
||||
{
|
||||
-0.525731, 0.850651, 0.000000},
|
||||
|
||||
{
|
||||
0.000000, 0.850651, -0.525731},
|
||||
|
||||
{
|
||||
-0.238856, 0.864188, -0.442863},
|
||||
|
||||
{
|
||||
0.000000, 0.955423, -0.295242},
|
||||
|
||||
{
|
||||
-0.262866, 0.951056, -0.162460},
|
||||
|
||||
{
|
||||
0.000000, 1.000000, 0.000000},
|
||||
|
||||
{
|
||||
0.000000, 0.955423, 0.295242},
|
||||
|
||||
{
|
||||
-0.262866, 0.951056, 0.162460},
|
||||
|
||||
{
|
||||
0.238856, 0.864188, 0.442863},
|
||||
|
||||
{
|
||||
0.262866, 0.951056, 0.162460},
|
||||
|
||||
{
|
||||
0.500000, 0.809017, 0.309017},
|
||||
|
||||
{
|
||||
0.238856, 0.864188, -0.442863},
|
||||
|
||||
{
|
||||
0.262866, 0.951056, -0.162460},
|
||||
|
||||
{
|
||||
0.500000, 0.809017, -0.309017},
|
||||
|
||||
{
|
||||
0.850651, 0.525731, 0.000000},
|
||||
|
||||
{
|
||||
0.716567, 0.681718, 0.147621},
|
||||
|
||||
{
|
||||
0.716567, 0.681718, -0.147621},
|
||||
|
||||
{
|
||||
0.525731, 0.850651, 0.000000},
|
||||
|
||||
{
|
||||
0.425325, 0.688191, 0.587785},
|
||||
|
||||
{
|
||||
0.864188, 0.442863, 0.238856},
|
||||
|
||||
{
|
||||
0.688191, 0.587785, 0.425325},
|
||||
|
||||
{
|
||||
0.809017, 0.309017, 0.500000},
|
||||
|
||||
{
|
||||
0.681718, 0.147621, 0.716567},
|
||||
|
||||
{
|
||||
0.587785, 0.425325, 0.688191},
|
||||
|
||||
{
|
||||
0.955423, 0.295242, 0.000000},
|
||||
|
||||
{
|
||||
1.000000, 0.000000, 0.000000},
|
||||
|
||||
{
|
||||
0.951056, 0.162460, 0.262866},
|
||||
|
||||
{
|
||||
0.850651, -0.525731, 0.000000},
|
||||
|
||||
{
|
||||
0.955423, -0.295242, 0.000000},
|
||||
|
||||
{
|
||||
0.864188, -0.442863, 0.238856},
|
||||
|
||||
{
|
||||
0.951056, -0.162460, 0.262866},
|
||||
|
||||
{
|
||||
0.809017, -0.309017, 0.500000},
|
||||
|
||||
{
|
||||
0.681718, -0.147621, 0.716567},
|
||||
|
||||
{
|
||||
0.850651, 0.000000, 0.525731},
|
||||
|
||||
{
|
||||
0.864188, 0.442863, -0.238856},
|
||||
|
||||
{
|
||||
0.809017, 0.309017, -0.500000},
|
||||
|
||||
{
|
||||
0.951056, 0.162460, -0.262866},
|
||||
|
||||
{
|
||||
0.525731, 0.000000, -0.850651},
|
||||
|
||||
{
|
||||
0.681718, 0.147621, -0.716567},
|
||||
|
||||
{
|
||||
0.681718, -0.147621, -0.716567},
|
||||
|
||||
{
|
||||
0.850651, 0.000000, -0.525731},
|
||||
|
||||
{
|
||||
0.809017, -0.309017, -0.500000},
|
||||
|
||||
{
|
||||
0.864188, -0.442863, -0.238856},
|
||||
|
||||
{
|
||||
0.951056, -0.162460, -0.262866},
|
||||
|
||||
{
|
||||
0.147621, 0.716567, -0.681718},
|
||||
|
||||
{
|
||||
0.309017, 0.500000, -0.809017},
|
||||
|
||||
{
|
||||
0.425325, 0.688191, -0.587785},
|
||||
|
||||
{
|
||||
0.442863, 0.238856, -0.864188},
|
||||
|
||||
{
|
||||
0.587785, 0.425325, -0.688191},
|
||||
|
||||
{
|
||||
0.688191, 0.587785, -0.425325},
|
||||
|
||||
{
|
||||
-0.147621, 0.716567, -0.681718},
|
||||
|
||||
{
|
||||
-0.309017, 0.500000, -0.809017},
|
||||
|
||||
{
|
||||
0.000000, 0.525731, -0.850651},
|
||||
|
||||
{
|
||||
-0.525731, 0.000000, -0.850651},
|
||||
|
||||
{
|
||||
-0.442863, 0.238856, -0.864188},
|
||||
|
||||
{
|
||||
-0.295242, 0.000000, -0.955423},
|
||||
|
||||
{
|
||||
-0.162460, 0.262866, -0.951056},
|
||||
|
||||
{
|
||||
0.000000, 0.000000, -1.000000},
|
||||
|
||||
{
|
||||
0.295242, 0.000000, -0.955423},
|
||||
|
||||
{
|
||||
0.162460, 0.262866, -0.951056},
|
||||
|
||||
{
|
||||
-0.442863, -0.238856, -0.864188},
|
||||
|
||||
{
|
||||
-0.309017, -0.500000, -0.809017},
|
||||
|
||||
{
|
||||
-0.162460, -0.262866, -0.951056},
|
||||
|
||||
{
|
||||
0.000000, -0.850651, -0.525731},
|
||||
|
||||
{
|
||||
-0.147621, -0.716567, -0.681718},
|
||||
|
||||
{
|
||||
0.147621, -0.716567, -0.681718},
|
||||
|
||||
{
|
||||
0.000000, -0.525731, -0.850651},
|
||||
|
||||
{
|
||||
0.309017, -0.500000, -0.809017},
|
||||
|
||||
{
|
||||
0.442863, -0.238856, -0.864188},
|
||||
|
||||
{
|
||||
0.162460, -0.262866, -0.951056},
|
||||
|
||||
{
|
||||
0.238856, -0.864188, -0.442863},
|
||||
|
||||
{
|
||||
0.500000, -0.809017, -0.309017},
|
||||
|
||||
{
|
||||
0.425325, -0.688191, -0.587785},
|
||||
|
||||
{
|
||||
0.716567, -0.681718, -0.147621},
|
||||
|
||||
{
|
||||
0.688191, -0.587785, -0.425325},
|
||||
|
||||
{
|
||||
0.587785, -0.425325, -0.688191},
|
||||
|
||||
{
|
||||
0.000000, -0.955423, -0.295242},
|
||||
|
||||
{
|
||||
0.000000, -1.000000, 0.000000},
|
||||
|
||||
{
|
||||
0.262866, -0.951056, -0.162460},
|
||||
|
||||
{
|
||||
0.000000, -0.850651, 0.525731},
|
||||
|
||||
{
|
||||
0.000000, -0.955423, 0.295242},
|
||||
|
||||
{
|
||||
0.238856, -0.864188, 0.442863},
|
||||
|
||||
{
|
||||
0.262866, -0.951056, 0.162460},
|
||||
|
||||
{
|
||||
0.500000, -0.809017, 0.309017},
|
||||
|
||||
{
|
||||
0.716567, -0.681718, 0.147621},
|
||||
|
||||
{
|
||||
0.525731, -0.850651, 0.000000},
|
||||
|
||||
{
|
||||
-0.238856, -0.864188, -0.442863},
|
||||
|
||||
{
|
||||
-0.500000, -0.809017, -0.309017},
|
||||
|
||||
{
|
||||
-0.262866, -0.951056, -0.162460},
|
||||
|
||||
{
|
||||
-0.850651, -0.525731, 0.000000},
|
||||
|
||||
{
|
||||
-0.716567, -0.681718, -0.147621},
|
||||
|
||||
{
|
||||
-0.716567, -0.681718, 0.147621},
|
||||
|
||||
{
|
||||
-0.525731, -0.850651, 0.000000},
|
||||
|
||||
{
|
||||
-0.500000, -0.809017, 0.309017},
|
||||
|
||||
{
|
||||
-0.238856, -0.864188, 0.442863},
|
||||
|
||||
{
|
||||
-0.262866, -0.951056, 0.162460},
|
||||
|
||||
{
|
||||
-0.864188, -0.442863, 0.238856},
|
||||
|
||||
{
|
||||
-0.809017, -0.309017, 0.500000},
|
||||
|
||||
{
|
||||
-0.688191, -0.587785, 0.425325},
|
||||
|
||||
{
|
||||
-0.681718, -0.147621, 0.716567},
|
||||
|
||||
{
|
||||
-0.442863, -0.238856, 0.864188},
|
||||
|
||||
{
|
||||
-0.587785, -0.425325, 0.688191},
|
||||
|
||||
{
|
||||
-0.309017, -0.500000, 0.809017},
|
||||
|
||||
{
|
||||
-0.147621, -0.716567, 0.681718},
|
||||
|
||||
{
|
||||
-0.425325, -0.688191, 0.587785},
|
||||
|
||||
{
|
||||
-0.162460, -0.262866, 0.951056},
|
||||
|
||||
{
|
||||
0.442863, -0.238856, 0.864188},
|
||||
|
||||
{
|
||||
0.162460, -0.262866, 0.951056},
|
||||
|
||||
{
|
||||
0.309017, -0.500000, 0.809017},
|
||||
|
||||
{
|
||||
0.147621, -0.716567, 0.681718},
|
||||
|
||||
{
|
||||
0.000000, -0.525731, 0.850651},
|
||||
|
||||
{
|
||||
0.425325, -0.688191, 0.587785},
|
||||
|
||||
{
|
||||
0.587785, -0.425325, 0.688191},
|
||||
|
||||
{
|
||||
0.688191, -0.587785, 0.425325},
|
||||
|
||||
{
|
||||
-0.955423, 0.295242, 0.000000},
|
||||
|
||||
{
|
||||
-0.951056, 0.162460, 0.262866},
|
||||
|
||||
{
|
||||
-1.000000, 0.000000, 0.000000},
|
||||
|
||||
{
|
||||
-0.850651, 0.000000, 0.525731},
|
||||
|
||||
{
|
||||
-0.955423, -0.295242, 0.000000},
|
||||
|
||||
{
|
||||
-0.951056, -0.162460, 0.262866},
|
||||
|
||||
{
|
||||
-0.864188, 0.442863, -0.238856},
|
||||
|
||||
{
|
||||
-0.951056, 0.162460, -0.262866},
|
||||
|
||||
{
|
||||
-0.809017, 0.309017, -0.500000},
|
||||
|
||||
{
|
||||
-0.864188, -0.442863, -0.238856},
|
||||
|
||||
{
|
||||
-0.951056, -0.162460, -0.262866},
|
||||
|
||||
{
|
||||
-0.809017, -0.309017, -0.500000},
|
||||
|
||||
{
|
||||
-0.681718, 0.147621, -0.716567},
|
||||
|
||||
{
|
||||
-0.681718, -0.147621, -0.716567},
|
||||
|
||||
{
|
||||
-0.850651, 0.000000, -0.525731},
|
||||
|
||||
{
|
||||
-0.688191, 0.587785, -0.425325},
|
||||
|
||||
{
|
||||
-0.587785, 0.425325, -0.688191},
|
||||
|
||||
{
|
||||
-0.425325, 0.688191, -0.587785},
|
||||
|
||||
{
|
||||
-0.425325, -0.688191, -0.587785},
|
||||
|
||||
{
|
||||
-0.587785, -0.425325, -0.688191},
|
||||
|
||||
{
|
||||
-0.688191, -0.587785, -0.425325},
|
76
src/gl/renderer/gl_colormap.h
Normal file
76
src/gl/renderer/gl_colormap.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
#ifndef __GL_COLORMAP
|
||||
#define __GL_COLORMAP
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "v_palette.h"
|
||||
#include "r_data/colormaps.h"
|
||||
|
||||
extern DWORD gl_fixedcolormap;
|
||||
|
||||
|
||||
enum EColorManipulation
|
||||
{
|
||||
|
||||
CM_INVALID=-1,
|
||||
CM_DEFAULT=0, // untranslated
|
||||
CM_FIRSTSPECIALCOLORMAP, // first special fixed colormap
|
||||
|
||||
CM_FOGLAYER = 0x10000000, // Sprite shaped fog layer
|
||||
|
||||
// These are not to be passed to the texture manager
|
||||
CM_LITE = 0x20000000, // special values to handle these items without excessive hacking
|
||||
CM_TORCH= 0x20000010, // These are not real color manipulations
|
||||
};
|
||||
|
||||
#define CM_MAXCOLORMAP int(CM_FIRSTSPECIALCOLORMAP + SpecialColormaps.Size())
|
||||
|
||||
// for internal use
|
||||
struct FColormap
|
||||
{
|
||||
PalEntry LightColor; // a is saturation (0 full, 31=b/w, other=custom colormap)
|
||||
PalEntry FadeColor; // a is fadedensity>>1
|
||||
int desaturation;
|
||||
int blendfactor;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
LightColor=0xffffff;
|
||||
FadeColor=0;
|
||||
desaturation = 0;
|
||||
blendfactor=0;
|
||||
}
|
||||
|
||||
void ClearColor()
|
||||
{
|
||||
LightColor.r=LightColor.g=LightColor.b=0xff;
|
||||
blendfactor=0;
|
||||
desaturation = 0;
|
||||
}
|
||||
|
||||
|
||||
FColormap & operator=(FDynamicColormap * from)
|
||||
{
|
||||
LightColor = from->Color;
|
||||
desaturation = from->Desaturate;
|
||||
FadeColor = from->Fade;
|
||||
blendfactor = from->Color.a;
|
||||
return * this;
|
||||
}
|
||||
|
||||
void CopyLightColor(FDynamicColormap * from)
|
||||
{
|
||||
LightColor = from->Color;
|
||||
desaturation = from->Desaturate;
|
||||
blendfactor = from->Color.a;
|
||||
}
|
||||
|
||||
void Decolorize() // this for 'nocoloredspritelighting' and not the same as desaturation. The normal formula results in a value that's too dark.
|
||||
{
|
||||
int v = (LightColor.r + LightColor.g + LightColor.b) / 3;
|
||||
LightColor.r = LightColor.g = LightColor.b = (255 + v + v) / 3;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
559
src/gl/renderer/gl_lightdata.cpp
Normal file
559
src/gl/renderer/gl_lightdata.cpp
Normal file
|
@ -0,0 +1,559 @@
|
|||
/*
|
||||
** gl_light.cpp
|
||||
** Light level / fog management / dynamic lights
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/renderer/gl_colormap.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "p_local.h"
|
||||
#include "g_level.h"
|
||||
#include "r_sky.h"
|
||||
|
||||
// externally settable lighting properties
|
||||
static float distfogtable[2][256]; // light to fog conversion table for black fog
|
||||
static PalEntry outsidefogcolor;
|
||||
int fogdensity;
|
||||
int outsidefogdensity;
|
||||
int skyfog;
|
||||
|
||||
CUSTOM_CVAR (Int, gl_light_ambient, 20, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
// ambient of 0 does not work correctly because light level 0 is special.
|
||||
if (self < 1) self = 1;
|
||||
}
|
||||
|
||||
CVAR(Int, gl_weaponlight, 8, CVAR_ARCHIVE);
|
||||
CUSTOM_CVAR(Bool, gl_enhanced_nightvision, true, CVAR_ARCHIVE|CVAR_NOINITCALL)
|
||||
{
|
||||
// The fixed colormap state needs to be reset because if this happens when
|
||||
// a shader is set to CM_LITE or CM_TORCH it won't register the change in behavior caused by this CVAR.
|
||||
if (GLRenderer != NULL && GLRenderer->mShaderManager != NULL)
|
||||
{
|
||||
GLRenderer->mShaderManager->ResetFixedColormap();
|
||||
}
|
||||
}
|
||||
CVAR(Bool, gl_brightfog, false, CVAR_ARCHIVE);
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets up the fog tables
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CUSTOM_CVAR (Int, gl_distfog, 70, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
for (int i=0;i<256;i++)
|
||||
{
|
||||
|
||||
if (i<164)
|
||||
{
|
||||
distfogtable[0][i]= (gl_distfog>>1) + (gl_distfog)*(164-i)/164;
|
||||
}
|
||||
else if (i<230)
|
||||
{
|
||||
distfogtable[0][i]= (gl_distfog>>1) - (gl_distfog>>1)*(i-164)/(230-164);
|
||||
}
|
||||
else distfogtable[0][i]=0;
|
||||
|
||||
if (i<128)
|
||||
{
|
||||
distfogtable[1][i]= 6.f + (gl_distfog>>1) + (gl_distfog)*(128-i)/48;
|
||||
}
|
||||
else if (i<216)
|
||||
{
|
||||
distfogtable[1][i]= (216.f-i) / ((216.f-128.f)) * gl_distfog / 10;
|
||||
}
|
||||
else distfogtable[1][i]=0;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int,gl_fogmode,1,CVAR_ARCHIVE|CVAR_NOINITCALL)
|
||||
{
|
||||
if (self>2) self=2;
|
||||
if (self<0) self=0;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, gl_lightmode, 3 ,CVAR_ARCHIVE|CVAR_NOINITCALL)
|
||||
{
|
||||
int newself = self;
|
||||
if (newself > 4) newself=8; // use 8 for software lighting to avoid conflicts with the bit mask
|
||||
if (newself < 0) newself=0;
|
||||
if (self != newself) self = newself;
|
||||
glset.lightmode = newself;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets render state to draw the given render style
|
||||
// includes: Texture mode, blend equation and blend mode
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_GetRenderStyle(FRenderStyle style, bool drawopaque, bool allowcolorblending,
|
||||
int *tm, int *sb, int *db, int *be)
|
||||
{
|
||||
static int blendstyles[] = { GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA };
|
||||
static int renderops[] = { 0, GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
|
||||
int srcblend = blendstyles[style.SrcAlpha&3];
|
||||
int dstblend = blendstyles[style.DestAlpha&3];
|
||||
int blendequation = renderops[style.BlendOp&15];
|
||||
int texturemode = drawopaque? TM_OPAQUE : TM_MODULATE;
|
||||
|
||||
if (style.Flags & STYLEF_RedIsAlpha)
|
||||
{
|
||||
texturemode = TM_REDTOALPHA;
|
||||
}
|
||||
else if (style.Flags & STYLEF_ColorIsFixed)
|
||||
{
|
||||
texturemode = TM_MASK;
|
||||
}
|
||||
else if (style.Flags & STYLEF_InvertSource)
|
||||
{
|
||||
// The only place where InvertSource is used is for inverted sprites with the infrared powerup.
|
||||
texturemode = TM_INVERSE;
|
||||
}
|
||||
|
||||
if (blendequation == -1)
|
||||
{
|
||||
srcblend = GL_DST_COLOR;
|
||||
dstblend = GL_ONE_MINUS_SRC_ALPHA;
|
||||
blendequation = GL_FUNC_ADD;
|
||||
}
|
||||
|
||||
if (allowcolorblending && srcblend == GL_SRC_ALPHA && dstblend == GL_ONE && blendequation == GL_FUNC_ADD)
|
||||
{
|
||||
srcblend = GL_SRC_COLOR;
|
||||
}
|
||||
|
||||
*tm = texturemode;
|
||||
*be = blendequation;
|
||||
*sb = srcblend;
|
||||
*db = dstblend;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Set fog parameters for the level
|
||||
//
|
||||
//==========================================================================
|
||||
void gl_SetFogParams(int _fogdensity, PalEntry _outsidefogcolor, int _outsidefogdensity, int _skyfog)
|
||||
{
|
||||
fogdensity=_fogdensity;
|
||||
outsidefogcolor=_outsidefogcolor;
|
||||
outsidefogdensity=_outsidefogdensity;
|
||||
skyfog=_skyfog;
|
||||
|
||||
outsidefogdensity>>=1;
|
||||
fogdensity>>=1;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Get current light level
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int gl_CalcLightLevel(int lightlevel, int rellight, bool weapon)
|
||||
{
|
||||
int light;
|
||||
|
||||
if (lightlevel == 0) return 0;
|
||||
|
||||
if ((glset.lightmode & 2) && lightlevel < 192 && !weapon)
|
||||
{
|
||||
light = xs_CRoundToInt(192.f - (192-lightlevel)* 1.95f);
|
||||
}
|
||||
else
|
||||
{
|
||||
light=lightlevel;
|
||||
}
|
||||
|
||||
if (light<gl_light_ambient && glset.lightmode != 8) // ambient clipping only if not using software lighting model.
|
||||
{
|
||||
light = gl_light_ambient;
|
||||
if (rellight<0) rellight>>=1;
|
||||
}
|
||||
return clamp(light+rellight, 0, 255);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Get current light color
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static PalEntry gl_CalcLightColor(int light, PalEntry pe, int blendfactor)
|
||||
{
|
||||
int r,g,b;
|
||||
|
||||
if (glset.lightmode == 8)
|
||||
{
|
||||
return pe;
|
||||
}
|
||||
else if (blendfactor == 0)
|
||||
{
|
||||
r = pe.r * light / 255;
|
||||
g = pe.g * light / 255;
|
||||
b = pe.b * light / 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is what Legacy does with colored light in 3D volumes. No, it doesn't really make sense...
|
||||
// It also doesn't translate well to software style lighting.
|
||||
int mixlight = light * (255 - blendfactor);
|
||||
|
||||
r = (mixlight + pe.r * blendfactor) / 255;
|
||||
g = (mixlight + pe.g * blendfactor) / 255;
|
||||
b = (mixlight + pe.b * blendfactor) / 255;
|
||||
}
|
||||
return PalEntry(255, BYTE(r), BYTE(g), BYTE(b));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// set current light color
|
||||
//
|
||||
//==========================================================================
|
||||
void gl_SetColor(int sectorlightlevel, int rellight, const FColormap &cm, float alpha, bool weapon)
|
||||
{
|
||||
if (gl_fixedcolormap != CM_DEFAULT)
|
||||
{
|
||||
gl_RenderState.SetColorAlpha(0xffffff, alpha, 0);
|
||||
gl_RenderState.SetSoftLightLevel(255);
|
||||
}
|
||||
else
|
||||
{
|
||||
int hwlightlevel = gl_CalcLightLevel(sectorlightlevel, rellight, weapon);
|
||||
PalEntry pe = gl_CalcLightColor(hwlightlevel, cm.LightColor, cm.blendfactor);
|
||||
gl_RenderState.SetColorAlpha(pe, alpha, cm.desaturation);
|
||||
gl_RenderState.SetSoftLightLevel(gl_ClampLight(sectorlightlevel + rellight));
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// calculates the current fog density
|
||||
//
|
||||
// Rules for fog:
|
||||
//
|
||||
// 1. If bit 4 of gl_lightmode is set always use the level's fog density.
|
||||
// This is what Legacy's GL render does.
|
||||
// 2. black fog means no fog and always uses the distfogtable based on the level's fog density setting
|
||||
// 3. If outside fog is defined and the current fog color is the same as the outside fog
|
||||
// the engine always uses the outside fog density to make the fog uniform across the level.
|
||||
// If the outside fog's density is undefined it uses the level's fog density and if that is
|
||||
// not defined it uses a default of 70.
|
||||
// 4. If a global fog density is specified it is being used for all fog on the level
|
||||
// 5. If none of the above apply fog density is based on the light level as for the software renderer.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
float gl_GetFogDensity(int lightlevel, PalEntry fogcolor)
|
||||
{
|
||||
float density;
|
||||
|
||||
if (glset.lightmode&4)
|
||||
{
|
||||
// uses approximations of Legacy's default settings.
|
||||
density = fogdensity? fogdensity : 18;
|
||||
}
|
||||
else if ((fogcolor.d & 0xffffff) == 0)
|
||||
{
|
||||
// case 1: black fog
|
||||
if (glset.lightmode != 8)
|
||||
{
|
||||
density=distfogtable[glset.lightmode!=0][gl_ClampLight(lightlevel)];
|
||||
}
|
||||
else
|
||||
{
|
||||
density = 0;
|
||||
}
|
||||
}
|
||||
else if (outsidefogdensity != 0 && outsidefogcolor.a!=0xff && (fogcolor.d & 0xffffff) == (outsidefogcolor.d & 0xffffff))
|
||||
{
|
||||
// case 2. outsidefogdensity has already been set as needed
|
||||
density=outsidefogdensity;
|
||||
}
|
||||
else if (fogdensity!=0)
|
||||
{
|
||||
// case 3: level has fog density set
|
||||
density=fogdensity;
|
||||
}
|
||||
else if (lightlevel < 248)
|
||||
{
|
||||
// case 4: use light level
|
||||
density=clamp<int>(255-lightlevel,30,255);
|
||||
}
|
||||
else
|
||||
{
|
||||
density = 0.f;
|
||||
}
|
||||
return density;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Check fog by current lighting info
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool gl_CheckFog(FColormap *cm, int lightlevel)
|
||||
{
|
||||
// Check for fog boundaries. This needs a few more checks for the sectors
|
||||
bool frontfog;
|
||||
|
||||
PalEntry fogcolor = cm->FadeColor;
|
||||
|
||||
if ((fogcolor.d & 0xffffff) == 0)
|
||||
{
|
||||
frontfog = false;
|
||||
}
|
||||
else if (outsidefogdensity != 0 && outsidefogcolor.a!=0xff && (fogcolor.d & 0xffffff) == (outsidefogcolor.d & 0xffffff))
|
||||
{
|
||||
frontfog = true;
|
||||
}
|
||||
else if (fogdensity!=0 || (glset.lightmode & 4))
|
||||
{
|
||||
// case 3: level has fog density set
|
||||
frontfog = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// case 4: use light level
|
||||
frontfog = lightlevel < 248;
|
||||
}
|
||||
return frontfog;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Check if the current linedef is a candidate for a fog boundary
|
||||
//
|
||||
// Requirements for a fog boundary:
|
||||
// - front sector has no fog
|
||||
// - back sector has fog
|
||||
// - at least one of both does not have a sky ceiling.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool gl_CheckFog(sector_t *frontsector, sector_t *backsector)
|
||||
{
|
||||
if (gl_fixedcolormap) return false;
|
||||
if (frontsector == backsector) return false; // there can't be a boundary if both sides are in the same sector.
|
||||
|
||||
// Check for fog boundaries. This needs a few more checks for the sectors
|
||||
|
||||
PalEntry fogcolor = frontsector->ColorMap->Fade;
|
||||
|
||||
if ((fogcolor.d & 0xffffff) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (outsidefogdensity != 0 && outsidefogcolor.a!=0xff && (fogcolor.d & 0xffffff) == (outsidefogcolor.d & 0xffffff))
|
||||
{
|
||||
}
|
||||
else if (fogdensity!=0 || (glset.lightmode & 4))
|
||||
{
|
||||
// case 3: level has fog density set
|
||||
}
|
||||
else
|
||||
{
|
||||
// case 4: use light level
|
||||
if (frontsector->lightlevel >= 248) return false;
|
||||
}
|
||||
|
||||
fogcolor = backsector->ColorMap->Fade;
|
||||
|
||||
if ((fogcolor.d & 0xffffff) == 0)
|
||||
{
|
||||
}
|
||||
else if (outsidefogdensity != 0 && outsidefogcolor.a!=0xff && (fogcolor.d & 0xffffff) == (outsidefogcolor.d & 0xffffff))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (fogdensity!=0 || (glset.lightmode & 4))
|
||||
{
|
||||
// case 3: level has fog density set
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// case 4: use light level
|
||||
if (backsector->lightlevel < 248) return false;
|
||||
}
|
||||
|
||||
// in all other cases this might create more problems than it solves.
|
||||
return ((frontsector->GetTexture(sector_t::ceiling)!=skyflatnum ||
|
||||
backsector->GetTexture(sector_t::ceiling)!=skyflatnum));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Lighting stuff
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_SetShaderLight(float level, float olight)
|
||||
{
|
||||
const float MAXDIST = 256.f;
|
||||
const float THRESHOLD = 96.f;
|
||||
const float FACTOR = 0.75f;
|
||||
|
||||
if (level > 0)
|
||||
{
|
||||
float lightdist, lightfactor;
|
||||
|
||||
if (olight < THRESHOLD)
|
||||
{
|
||||
lightdist = (MAXDIST/2) + (olight * MAXDIST / THRESHOLD / 2);
|
||||
olight = THRESHOLD;
|
||||
}
|
||||
else lightdist = MAXDIST;
|
||||
|
||||
lightfactor = 1.f + ((olight/level) - 1.f) * FACTOR;
|
||||
if (lightfactor == 1.f) lightdist = 0.f; // save some code in the shader
|
||||
gl_RenderState.SetLightParms(lightfactor, lightdist);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_RenderState.SetLightParms(1.f, 0.f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets the fog for the current polygon
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_SetFog(int lightlevel, int rellight, const FColormap *cmap, bool isadditive)
|
||||
{
|
||||
PalEntry fogcolor;
|
||||
float fogdensity;
|
||||
|
||||
if (level.flags&LEVEL_HASFADETABLE)
|
||||
{
|
||||
fogdensity=70;
|
||||
fogcolor=0x808080;
|
||||
}
|
||||
else if (cmap != NULL && gl_fixedcolormap == 0)
|
||||
{
|
||||
fogcolor = cmap->FadeColor;
|
||||
fogdensity = gl_GetFogDensity(lightlevel, fogcolor);
|
||||
fogcolor.a=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fogcolor = 0;
|
||||
fogdensity = 0;
|
||||
}
|
||||
|
||||
// Make fog a little denser when inside a skybox
|
||||
if (GLPortal::inskybox) fogdensity+=fogdensity/2;
|
||||
|
||||
|
||||
// no fog in enhanced vision modes!
|
||||
if (fogdensity==0 || gl_fogmode == 0)
|
||||
{
|
||||
gl_RenderState.EnableFog(false);
|
||||
gl_RenderState.SetFog(0,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (glset.lightmode == 2 && fogcolor == 0)
|
||||
{
|
||||
float light = gl_CalcLightLevel(lightlevel, rellight, false);
|
||||
gl_SetShaderLight(light, lightlevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_RenderState.SetLightParms(1.f, 0.f);
|
||||
}
|
||||
|
||||
// For additive rendering using the regular fog color here would mean applying it twice
|
||||
// so always use black
|
||||
if (isadditive)
|
||||
{
|
||||
fogcolor=0;
|
||||
}
|
||||
|
||||
gl_RenderState.EnableFog(true);
|
||||
gl_RenderState.SetFog(fogcolor, fogdensity);
|
||||
|
||||
// Korshun: fullbright fog like in software renderer.
|
||||
if (glset.lightmode == 8 && glset.brightfog && fogdensity != 0 && fogcolor != 0)
|
||||
{
|
||||
gl_RenderState.SetSoftLightLevel(255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// For testing sky fog sheets
|
||||
//
|
||||
//==========================================================================
|
||||
CCMD(skyfog)
|
||||
{
|
||||
if (argv.argc()>1)
|
||||
{
|
||||
skyfog=strtol(argv[1],NULL,0);
|
||||
}
|
||||
}
|
||||
|
52
src/gl/renderer/gl_lightdata.h
Normal file
52
src/gl/renderer/gl_lightdata.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifndef __GL_LIGHTDATA
|
||||
#define __GL_LIGHTDATA
|
||||
|
||||
#include "v_palette.h"
|
||||
#include "r_data/renderstyle.h"
|
||||
#include "gl/renderer/gl_colormap.h"
|
||||
|
||||
inline int gl_ClampLight(int lightlevel)
|
||||
{
|
||||
return clamp(lightlevel, 0, 255);
|
||||
}
|
||||
|
||||
void gl_GetRenderStyle(FRenderStyle style, bool drawopaque, bool allowcolorblending,
|
||||
int *tm, int *sb, int *db, int *be);
|
||||
void gl_SetFogParams(int _fogdensity, PalEntry _outsidefogcolor, int _outsidefogdensity, int _skyfog);
|
||||
|
||||
int gl_CalcLightLevel(int lightlevel, int rellight, bool weapon);
|
||||
void gl_SetColor(int light, int rellight, const FColormap &cm, float alpha, bool weapon=false);
|
||||
|
||||
float gl_GetFogDensity(int lightlevel, PalEntry fogcolor);
|
||||
struct sector_t;
|
||||
bool gl_CheckFog(FColormap *cm, int lightlevel);
|
||||
bool gl_CheckFog(sector_t *frontsector, sector_t *backsector);
|
||||
|
||||
void gl_SetFog(int lightlevel, int rellight, const FColormap *cm, bool isadditive);
|
||||
|
||||
inline bool gl_isBlack(PalEntry color)
|
||||
{
|
||||
return color.r + color.g + color.b == 0;
|
||||
}
|
||||
|
||||
inline bool gl_isWhite(PalEntry color)
|
||||
{
|
||||
return color.r + color.g + color.b == 3*0xff;
|
||||
}
|
||||
|
||||
extern DWORD gl_fixedcolormap;
|
||||
|
||||
inline bool gl_isFullbright(PalEntry color, int lightlevel)
|
||||
{
|
||||
return gl_fixedcolormap || (gl_isWhite(color) && lightlevel==255);
|
||||
}
|
||||
|
||||
void gl_DeleteAllAttachedLights();
|
||||
void gl_RecreateAllAttachedLights();
|
||||
|
||||
extern int fogdensity;
|
||||
extern int outsidefogdensity;
|
||||
extern int skyfog;
|
||||
|
||||
|
||||
#endif
|
634
src/gl/renderer/gl_renderer.cpp
Normal file
634
src/gl/renderer/gl_renderer.cpp
Normal file
|
@ -0,0 +1,634 @@
|
|||
/*
|
||||
** gl1_renderer.cpp
|
||||
** Renderer interface
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "files.h"
|
||||
#include "m_swap.h"
|
||||
#include "v_video.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "m_png.h"
|
||||
#include "m_crc32.h"
|
||||
#include "w_wad.h"
|
||||
//#include "gl/gl_intern.h"
|
||||
#include "gl/gl_functions.h"
|
||||
#include "vectors.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_texture.h"
|
||||
#include "gl/textures/gl_translate.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/textures/gl_samplers.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/utility/gl_templates.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "gl/dynlights/gl_lightbuffer.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Renderer interface
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Initialize
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
|
||||
{
|
||||
framebuffer = fb;
|
||||
mCurrentPortal = NULL;
|
||||
mMirrorCount = 0;
|
||||
mPlaneMirrorCount = 0;
|
||||
mLightCount = 0;
|
||||
mAngles = FRotator(0,0,0);
|
||||
mViewVector = FVector2(0,0);
|
||||
mVBO = NULL;
|
||||
mSkyVBO = NULL;
|
||||
gl_spriteindex = 0;
|
||||
mShaderManager = NULL;
|
||||
glpart2 = glpart = mirrortexture = NULL;
|
||||
mLights = NULL;
|
||||
}
|
||||
|
||||
void gl_LoadModels();
|
||||
void gl_FlushModels();
|
||||
|
||||
void FGLRenderer::Initialize()
|
||||
{
|
||||
glpart2 = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/glpart2.png"), FTexture::TEX_MiscPatch);
|
||||
glpart = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/glpart.png"), FTexture::TEX_MiscPatch);
|
||||
mirrortexture = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/mirror.png"), FTexture::TEX_MiscPatch);
|
||||
|
||||
mVBO = new FFlatVertexBuffer;
|
||||
mSkyVBO = new FSkyVertexBuffer;
|
||||
mLights = new FLightBuffer();
|
||||
gl_RenderState.SetVertexBuffer(mVBO);
|
||||
mFBID = 0;
|
||||
SetupLevel();
|
||||
mShaderManager = new FShaderManager;
|
||||
mSamplerManager = new FSamplerManager;
|
||||
gl_LoadModels();
|
||||
}
|
||||
|
||||
FGLRenderer::~FGLRenderer()
|
||||
{
|
||||
gl_FlushModels();
|
||||
gl_DeleteAllAttachedLights();
|
||||
FMaterial::FlushAll();
|
||||
if (mShaderManager != NULL) delete mShaderManager;
|
||||
if (mSamplerManager != NULL) delete mSamplerManager;
|
||||
if (mVBO != NULL) delete mVBO;
|
||||
if (mSkyVBO != NULL) delete mSkyVBO;
|
||||
if (mLights != NULL) delete mLights;
|
||||
if (glpart2) delete glpart2;
|
||||
if (glpart) delete glpart;
|
||||
if (mirrortexture) delete mirrortexture;
|
||||
if (mFBID != 0) glDeleteFramebuffers(1, &mFBID);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::SetupLevel()
|
||||
{
|
||||
mVBO->CreateVBO();
|
||||
}
|
||||
|
||||
void FGLRenderer::Begin2D()
|
||||
{
|
||||
gl_RenderState.EnableFog(false);
|
||||
gl_RenderState.Set2DMode(true);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::ProcessLowerMiniseg(seg_t *seg, sector_t * frontsector, sector_t * backsector)
|
||||
{
|
||||
GLWall wall;
|
||||
wall.ProcessLowerMiniseg(seg, frontsector, backsector);
|
||||
rendered_lines++;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::ProcessSprite(AActor *thing, sector_t *sector)
|
||||
{
|
||||
GLSprite glsprite;
|
||||
glsprite.Process(thing, sector);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::ProcessParticle(particle_t *part, sector_t *sector)
|
||||
{
|
||||
GLSprite glsprite;
|
||||
glsprite.ProcessParticle(part, sector);//, 0, 0);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::ProcessSector(sector_t *fakesector)
|
||||
{
|
||||
GLFlat glflat;
|
||||
glflat.ProcessSector(fakesector);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::FlushTextures()
|
||||
{
|
||||
FMaterial::FlushAll();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FGLRenderer::StartOffscreen()
|
||||
{
|
||||
if (mFBID == 0) glGenFramebuffers(1, &mFBID);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBID);
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::EndOffscreen()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
unsigned char *FGLRenderer::GetTextureBuffer(FTexture *tex, int &w, int &h)
|
||||
{
|
||||
FMaterial * gltex = FMaterial::ValidateTexture(tex, false);
|
||||
if (gltex)
|
||||
{
|
||||
return gltex->CreateTexBuffer(0, w, h);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::ClearBorders()
|
||||
{
|
||||
OpenGLFrameBuffer *glscreen = static_cast<OpenGLFrameBuffer*>(screen);
|
||||
|
||||
// Letterbox time! Draw black top and bottom borders.
|
||||
int width = glscreen->GetWidth();
|
||||
int height = glscreen->GetHeight();
|
||||
int trueHeight = glscreen->GetTrueHeight();
|
||||
|
||||
int borderHeight = (trueHeight - height) / 2;
|
||||
|
||||
glViewport(0, 0, width, trueHeight);
|
||||
gl_RenderState.mProjectionMatrix.loadIdentity();
|
||||
gl_RenderState.mProjectionMatrix.ortho(0.0f, width * 1.0f, 0.0f, trueHeight, -1.0f, 1.0f);
|
||||
gl_RenderState.SetColor(0.f ,0.f ,0.f ,1.f);
|
||||
gl_RenderState.Set2DMode(true);
|
||||
gl_RenderState.EnableTexture(false);
|
||||
gl_RenderState.Apply();
|
||||
gl_RenderState.ApplyMatrices();
|
||||
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(0, borderHeight, 0, 0, 0); ptr++;
|
||||
ptr->Set(0, 0, 0, 0, 0); ptr++;
|
||||
ptr->Set(width, 0, 0, 0, 0); ptr++;
|
||||
ptr->Set(width, borderHeight, 0, 0, 0); ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
ptr->Set(0, trueHeight, 0, 0, 0); ptr++;
|
||||
ptr->Set(0, trueHeight - borderHeight, 0, 0, 0); ptr++;
|
||||
ptr->Set(width, trueHeight - borderHeight, 0, 0, 0); ptr++;
|
||||
ptr->Set(width, trueHeight, 0, 0, 0); ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
gl_RenderState.EnableTexture(true);
|
||||
|
||||
glViewport(0, (trueHeight - height) / 2, width, height);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Draws a texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderer::DrawTexture(FTexture *img, DCanvas::DrawParms &parms)
|
||||
{
|
||||
double xscale = parms.destwidth / parms.texwidth;
|
||||
double yscale = parms.destheight / parms.texheight;
|
||||
double x = parms.x - parms.left * xscale;
|
||||
double y = parms.y - parms.top * yscale;
|
||||
double w = parms.destwidth;
|
||||
double h = parms.destheight;
|
||||
float u1, v1, u2, v2;
|
||||
int light = 255;
|
||||
|
||||
FMaterial * gltex = FMaterial::ValidateTexture(img, false);
|
||||
|
||||
if (parms.colorOverlay && (parms.colorOverlay & 0xffffff) == 0)
|
||||
{
|
||||
// Right now there's only black. Should be implemented properly later
|
||||
light = 255 - APART(parms.colorOverlay);
|
||||
parms.colorOverlay = 0;
|
||||
}
|
||||
|
||||
gl_SetRenderStyle(parms.style, !parms.masked, false);
|
||||
if (!img->bHasCanvas)
|
||||
{
|
||||
int translation = 0;
|
||||
if (!parms.alphaChannel)
|
||||
{
|
||||
if (parms.remap != NULL && !parms.remap->Inactive)
|
||||
{
|
||||
GLTranslationPalette * pal = static_cast<GLTranslationPalette*>(parms.remap->GetNative());
|
||||
if (pal) translation = -pal->GetIndex();
|
||||
}
|
||||
}
|
||||
gl_RenderState.SetMaterial(gltex, CLAMP_XY_NOMIP, translation, 0, !!(parms.style.Flags & STYLEF_RedIsAlpha));
|
||||
|
||||
u1 = gltex->GetUL();
|
||||
v1 = gltex->GetVT();
|
||||
u2 = gltex->GetUR();
|
||||
v2 = gltex->GetVB();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_RenderState.SetMaterial(gltex, CLAMP_XY_NOMIP, 0, -1, false);
|
||||
u1 = 0.f;
|
||||
v1 = 1.f;
|
||||
u2 = 1.f;
|
||||
v2 = 0.f;
|
||||
gl_RenderState.SetTextureMode(TM_OPAQUE);
|
||||
}
|
||||
|
||||
if (parms.flipX)
|
||||
{
|
||||
float temp = u1;
|
||||
u1 = u2;
|
||||
u2 = temp;
|
||||
}
|
||||
|
||||
|
||||
if (parms.windowleft > 0 || parms.windowright < parms.texwidth)
|
||||
{
|
||||
x += parms.windowleft * xscale;
|
||||
w -= (parms.texwidth - parms.windowright + parms.windowleft) * xscale;
|
||||
|
||||
u1 = float(u1 + parms.windowleft / parms.texwidth);
|
||||
u2 = float(u2 - (parms.texwidth - parms.windowright) / parms.texwidth);
|
||||
}
|
||||
|
||||
PalEntry color;
|
||||
if (parms.style.Flags & STYLEF_ColorIsFixed)
|
||||
{
|
||||
color = parms.fillcolor;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = PalEntry(light, light, light);
|
||||
}
|
||||
color.a = Scale(parms.alpha, 255, FRACUNIT);
|
||||
|
||||
// scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates
|
||||
int btm = (SCREENHEIGHT - screen->GetHeight()) / 2;
|
||||
btm = SCREENHEIGHT - btm;
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
int space = (static_cast<OpenGLFrameBuffer*>(screen)->GetTrueHeight()-screen->GetHeight())/2;
|
||||
glScissor(parms.lclip, btm - parms.dclip + space, parms.rclip - parms.lclip, parms.dclip - parms.uclip);
|
||||
|
||||
gl_RenderState.SetColor(color);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
||||
gl_RenderState.Apply();
|
||||
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(x, y, 0, u1, v1); ptr++;
|
||||
ptr->Set(x, y + h, 0, u1, v2); ptr++;
|
||||
ptr->Set(x + w, y, 0, u2, v1); ptr++;
|
||||
ptr->Set(x + w, y + h, 0, u2, v2); ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
|
||||
if (parms.colorOverlay)
|
||||
{
|
||||
gl_RenderState.SetTextureMode(TM_MASK);
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
gl_RenderState.BlendEquation(GL_FUNC_ADD);
|
||||
gl_RenderState.SetColor(PalEntry(parms.colorOverlay));
|
||||
gl_RenderState.Apply();
|
||||
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(x, y, 0, u1, v1); ptr++;
|
||||
ptr->Set(x, y + h, 0, u1, v2); ptr++;
|
||||
ptr->Set(x + w, y, 0, u2, v1); ptr++;
|
||||
ptr->Set(x + w, y + h, 0, u2, v2); ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
}
|
||||
|
||||
glScissor(0, 0, screen->GetWidth(), screen->GetHeight());
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
gl_RenderState.SetTextureMode(TM_MODULATE);
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
gl_RenderState.BlendEquation(GL_FUNC_ADD);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void FGLRenderer::DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color)
|
||||
{
|
||||
PalEntry p = color? (PalEntry)color : GPalette.BaseColors[palcolor];
|
||||
gl_RenderState.EnableTexture(false);
|
||||
gl_RenderState.SetColorAlpha(p, 1.f);
|
||||
gl_RenderState.Apply();
|
||||
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(x1, y1, 0, 0, 0); ptr++;
|
||||
ptr->Set(x2, y2, 0, 0, 0); ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_LINES);
|
||||
|
||||
gl_RenderState.EnableTexture(true);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void FGLRenderer::DrawPixel(int x1, int y1, int palcolor, uint32 color)
|
||||
{
|
||||
PalEntry p = color? (PalEntry)color : GPalette.BaseColors[palcolor];
|
||||
gl_RenderState.EnableTexture(false);
|
||||
gl_RenderState.SetColorAlpha(p, 1.f);
|
||||
gl_RenderState.Apply();
|
||||
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(x1, y1, 0, 0, 0); ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_POINTS);
|
||||
|
||||
gl_RenderState.EnableTexture(true);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::Dim(PalEntry color, float damount, int x1, int y1, int w, int h)
|
||||
{
|
||||
gl_RenderState.EnableTexture(false);
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
gl_RenderState.AlphaFunc(GL_GREATER,0);
|
||||
gl_RenderState.SetColorAlpha(color, damount);
|
||||
gl_RenderState.Apply();
|
||||
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(x1, y1, 0, 0, 0); ptr++;
|
||||
ptr->Set(x1, y1+h, 0, 0, 0); ptr++;
|
||||
ptr->Set(x1+w, y1+h, 0, 0, 0); ptr++;
|
||||
ptr->Set(x1+w, y1, 0, 0, 0); ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN);
|
||||
|
||||
gl_RenderState.EnableTexture(true);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void FGLRenderer::FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin)
|
||||
{
|
||||
float fU1,fU2,fV1,fV2;
|
||||
|
||||
FMaterial *gltexture=FMaterial::ValidateTexture(src, false);
|
||||
|
||||
if (!gltexture) return;
|
||||
|
||||
gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false);
|
||||
|
||||
// scaling is not used here.
|
||||
if (!local_origin)
|
||||
{
|
||||
fU1 = float(left) / src->GetWidth();
|
||||
fV1 = float(top) / src->GetHeight();
|
||||
fU2 = float(right) / src->GetWidth();
|
||||
fV2 = float(bottom) / src->GetHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
fU1 = 0;
|
||||
fV1 = 0;
|
||||
fU2 = float(right-left) / src->GetWidth();
|
||||
fV2 = float(bottom-top) / src->GetHeight();
|
||||
}
|
||||
gl_RenderState.ResetColor();
|
||||
gl_RenderState.Apply();
|
||||
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(left, top, 0, fU1, fV1); ptr++;
|
||||
ptr->Set(left, bottom, 0, fU1, fV2); ptr++;
|
||||
ptr->Set(right, top, 0, fU2, fV1); ptr++;
|
||||
ptr->Set(right, bottom, 0, fU2, fV2); ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void FGLRenderer::Clear(int left, int top, int right, int bottom, int palcolor, uint32 color)
|
||||
{
|
||||
int rt;
|
||||
int offY = 0;
|
||||
PalEntry p = palcolor==-1 || color != 0? (PalEntry)color : GPalette.BaseColors[palcolor];
|
||||
int width = right-left;
|
||||
int height= bottom-top;
|
||||
|
||||
|
||||
rt = screen->GetHeight() - top;
|
||||
|
||||
int space = (static_cast<OpenGLFrameBuffer*>(screen)->GetTrueHeight()-screen->GetHeight())/2; // ugh...
|
||||
rt += space;
|
||||
/*
|
||||
if (!m_windowed && (m_trueHeight != m_height))
|
||||
{
|
||||
offY = (m_trueHeight - m_height) / 2;
|
||||
rt += offY;
|
||||
}
|
||||
*/
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(left, rt - height, width, height);
|
||||
|
||||
glClearColor(p.r/255.0f, p.g/255.0f, p.b/255.0f, 0.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// D3DFB :: FillSimplePoly
|
||||
//
|
||||
// Here, "simple" means that a simple triangle fan can draw it.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderer::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley,
|
||||
angle_t rotation, FDynamicColormap *colormap, int lightlevel)
|
||||
{
|
||||
if (npoints < 3)
|
||||
{ // This is no polygon.
|
||||
return;
|
||||
}
|
||||
|
||||
FMaterial *gltexture = FMaterial::ValidateTexture(texture, false);
|
||||
|
||||
if (gltexture == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FColormap cm;
|
||||
cm = colormap;
|
||||
|
||||
// We cannot use the software light mode here because it doesn't properly calculate the light for 2D rendering.
|
||||
SBYTE savedlightmode = glset.lightmode;
|
||||
if (glset.lightmode == 8) glset.lightmode = 0;
|
||||
|
||||
gl_SetColor(lightlevel, 0, cm, 1.f);
|
||||
|
||||
glset.lightmode = savedlightmode;
|
||||
|
||||
gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false);
|
||||
|
||||
int i;
|
||||
float rot = float(rotation * M_PI / float(1u << 31));
|
||||
bool dorotate = rot != 0;
|
||||
|
||||
float cosrot = cos(rot);
|
||||
float sinrot = sin(rot);
|
||||
|
||||
//float yoffs = GatheringWipeScreen ? 0 : LBOffset;
|
||||
float uscale = float(1.f / (texture->GetScaledWidth() * scalex));
|
||||
float vscale = float(1.f / (texture->GetScaledHeight() * scaley));
|
||||
if (gltexture->tex->bHasCanvas)
|
||||
{
|
||||
vscale = 0 - vscale;
|
||||
}
|
||||
float ox = float(originx);
|
||||
float oy = float(originy);
|
||||
|
||||
gl_RenderState.Apply();
|
||||
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
for (i = 0; i < npoints; ++i)
|
||||
{
|
||||
float u = points[i].X - 0.5f - ox;
|
||||
float v = points[i].Y - 0.5f - oy;
|
||||
if (dorotate)
|
||||
{
|
||||
float t = u;
|
||||
u = t * cosrot - v * sinrot;
|
||||
v = v * cosrot + t * sinrot;
|
||||
}
|
||||
ptr->Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale);
|
||||
ptr++;
|
||||
}
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN);
|
||||
}
|
||||
|
168
src/gl/renderer/gl_renderer.h
Normal file
168
src/gl/renderer/gl_renderer.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
#ifndef __GL_RENDERER_H
|
||||
#define __GL_RENDERER_H
|
||||
|
||||
#include "r_defs.h"
|
||||
#include "v_video.h"
|
||||
#include "vectors.h"
|
||||
#include "r_renderer.h"
|
||||
#include "gl/data/gl_matrix.h"
|
||||
|
||||
struct particle_t;
|
||||
class FCanvasTexture;
|
||||
class FFlatVertexBuffer;
|
||||
class FSkyVertexBuffer;
|
||||
class OpenGLFrameBuffer;
|
||||
struct FDrawInfo;
|
||||
struct pspdef_t;
|
||||
class FShaderManager;
|
||||
class GLPortal;
|
||||
class FLightBuffer;
|
||||
class FSamplerManager;
|
||||
|
||||
enum SectorRenderFlags
|
||||
{
|
||||
// This is used to avoid creating too many drawinfos
|
||||
SSRF_RENDERFLOOR = 1,
|
||||
SSRF_RENDERCEILING = 2,
|
||||
SSRF_RENDER3DPLANES = 4,
|
||||
SSRF_RENDERALL = 7,
|
||||
SSRF_PROCESSED = 8,
|
||||
SSRF_SEEN = 16,
|
||||
};
|
||||
|
||||
struct GL_IRECT
|
||||
{
|
||||
int left,top;
|
||||
int width,height;
|
||||
|
||||
|
||||
void Offset(int xofs,int yofs)
|
||||
{
|
||||
left+=xofs;
|
||||
top+=yofs;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class FGLRenderer
|
||||
{
|
||||
public:
|
||||
|
||||
OpenGLFrameBuffer *framebuffer;
|
||||
GLPortal *mCurrentPortal;
|
||||
int mMirrorCount;
|
||||
int mPlaneMirrorCount;
|
||||
int mLightCount;
|
||||
float mCurrentFoV;
|
||||
AActor *mViewActor;
|
||||
FShaderManager *mShaderManager;
|
||||
FSamplerManager *mSamplerManager;
|
||||
int gl_spriteindex;
|
||||
unsigned int mFBID;
|
||||
|
||||
FTexture *glpart2;
|
||||
FTexture *glpart;
|
||||
FTexture *mirrortexture;
|
||||
|
||||
float mSky1Pos, mSky2Pos;
|
||||
|
||||
FRotator mAngles;
|
||||
FVector2 mViewVector;
|
||||
|
||||
FFlatVertexBuffer *mVBO;
|
||||
FSkyVertexBuffer *mSkyVBO;
|
||||
FLightBuffer *mLights;
|
||||
|
||||
|
||||
FGLRenderer(OpenGLFrameBuffer *fb);
|
||||
~FGLRenderer() ;
|
||||
|
||||
angle_t FrustumAngle();
|
||||
void SetViewArea();
|
||||
void ResetViewport();
|
||||
void SetViewport(GL_IRECT *bounds);
|
||||
sector_t *RenderViewpoint (AActor * camera, GL_IRECT * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen);
|
||||
void RenderView(player_t *player);
|
||||
void SetViewAngle(angle_t viewangle);
|
||||
void SetupView(fixed_t viewx, fixed_t viewy, fixed_t viewz, angle_t viewangle, bool mirror, bool planemirror);
|
||||
|
||||
void Initialize();
|
||||
|
||||
void CreateScene();
|
||||
void RenderScene(int recursion);
|
||||
void RenderTranslucent();
|
||||
void DrawScene(bool toscreen = false);
|
||||
void DrawBlend(sector_t * viewsector);
|
||||
|
||||
void DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed_t sy, bool hudModelStep, int OverrideShader, bool alphatexture);
|
||||
void DrawPlayerSprites(sector_t * viewsector, bool hudModelStep);
|
||||
void DrawTargeterSprites();
|
||||
|
||||
void Begin2D();
|
||||
void ClearBorders();
|
||||
void DrawTexture(FTexture *img, DCanvas::DrawParms &parms);
|
||||
void DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color);
|
||||
void DrawPixel(int x1, int y1, int palcolor, uint32 color);
|
||||
void Dim(PalEntry color, float damount, int x1, int y1, int w, int h);
|
||||
void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin);
|
||||
void Clear(int left, int top, int right, int bottom, int palcolor, uint32 color);
|
||||
|
||||
void ProcessLowerMiniseg(seg_t *seg, sector_t * frontsector, sector_t * backsector);
|
||||
void ProcessSprite(AActor *thing, sector_t *sector);
|
||||
void ProcessParticle(particle_t *part, sector_t *sector);
|
||||
void ProcessSector(sector_t *fakesector);
|
||||
void FlushTextures();
|
||||
unsigned char *GetTextureBuffer(FTexture *tex, int &w, int &h);
|
||||
void SetupLevel();
|
||||
|
||||
void SetFixedColormap (player_t *player);
|
||||
void WriteSavePic (player_t *player, FILE *file, int width, int height);
|
||||
void EndDrawScene(sector_t * viewsector);
|
||||
void Flush() {}
|
||||
|
||||
void SetProjection(float fov, float ratio, float fovratio);
|
||||
void SetProjection(VSMatrix matrix); // raw matrix input from stereo 3d modes
|
||||
void SetViewMatrix(fixed_t viewx, fixed_t viewy, fixed_t viewz, bool mirror, bool planemirror);
|
||||
void ProcessScene(bool toscreen = false);
|
||||
|
||||
bool StartOffscreen();
|
||||
void EndOffscreen();
|
||||
|
||||
void FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley,
|
||||
angle_t rotation, FDynamicColormap *colormap, int lightlevel);
|
||||
};
|
||||
|
||||
// Global functions. Make them members of GLRenderer later?
|
||||
void gl_RenderBSPNode (void *node);
|
||||
bool gl_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsector);
|
||||
void gl_CheckViewArea(vertex_t *v1, vertex_t *v2, sector_t *frontsector, sector_t *backsector);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
area_normal,
|
||||
area_below,
|
||||
area_above,
|
||||
area_default
|
||||
} area_t;
|
||||
|
||||
extern area_t in_area;
|
||||
|
||||
|
||||
sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back);
|
||||
inline sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, bool back)
|
||||
{
|
||||
return gl_FakeFlat(sec, dest, in_area, back);
|
||||
}
|
||||
|
||||
struct TexFilter_s
|
||||
{
|
||||
int minfilter;
|
||||
int magfilter;
|
||||
bool mipmapping;
|
||||
} ;
|
||||
|
||||
|
||||
extern FGLRenderer *GLRenderer;
|
||||
|
||||
#endif
|
305
src/gl/renderer/gl_renderstate.cpp
Normal file
305
src/gl/renderer/gl_renderstate.cpp
Normal file
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
** gl_renderstate.cpp
|
||||
** Render state maintenance
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2009 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "templates.h"
|
||||
#include "gl/system/gl_system.h"
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/renderer/gl_colormap.h"
|
||||
#include "gl/dynlights//gl_lightbuffer.h"
|
||||
|
||||
void gl_SetTextureMode(int type);
|
||||
|
||||
FRenderState gl_RenderState;
|
||||
|
||||
CVAR(Bool, gl_direct_state_change, true, 0)
|
||||
|
||||
|
||||
static VSMatrix identityMatrix(1);
|
||||
TArray<VSMatrix> gl_MatrixStack;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FRenderState::Reset()
|
||||
{
|
||||
mTextureEnabled = true;
|
||||
mBrightmapEnabled = mFogEnabled = mGlowEnabled = false;
|
||||
mColorMask[0] = mColorMask[1] = mColorMask[2] = mColorMask[3] = true;
|
||||
currentColorMask[0] = currentColorMask[1] = currentColorMask[2] = currentColorMask[3] = true;
|
||||
mFogColor.d = -1;
|
||||
mTextureMode = -1;
|
||||
mLightIndex = -1;
|
||||
mDesaturation = 0;
|
||||
mSrcBlend = GL_SRC_ALPHA;
|
||||
mDstBlend = GL_ONE_MINUS_SRC_ALPHA;
|
||||
mAlphaThreshold = 0.5f;
|
||||
mBlendEquation = GL_FUNC_ADD;
|
||||
mObjectColor = 0xffffffff;
|
||||
m2D = true;
|
||||
mVertexBuffer = mCurrentVertexBuffer = NULL;
|
||||
mColormapState = CM_DEFAULT;
|
||||
mLightParms[3] = -1.f;
|
||||
mSpecialEffect = EFF_NONE;
|
||||
mClipHeightTop = 65536.f;
|
||||
mClipHeightBottom = -65536.f;
|
||||
ClearClipSplit();
|
||||
|
||||
stSrcBlend = stDstBlend = -1;
|
||||
stBlendEquation = -1;
|
||||
stAlphaThreshold = -1.f;
|
||||
mLastDepthClamp = true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Apply shader settings
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FRenderState::ApplyShader()
|
||||
{
|
||||
if (mSpecialEffect > EFF_NONE)
|
||||
{
|
||||
activeShader = GLRenderer->mShaderManager->BindEffect(mSpecialEffect);
|
||||
}
|
||||
else
|
||||
{
|
||||
activeShader = GLRenderer->mShaderManager->Get(mTextureEnabled ? mEffectState : 4, mAlphaThreshold >= 0.f);
|
||||
activeShader->Bind();
|
||||
}
|
||||
|
||||
int fogset = 0;
|
||||
|
||||
if (mFogEnabled)
|
||||
{
|
||||
if ((mFogColor & 0xffffff) == 0)
|
||||
{
|
||||
fogset = gl_fogmode;
|
||||
}
|
||||
else
|
||||
{
|
||||
fogset = -gl_fogmode;
|
||||
}
|
||||
}
|
||||
|
||||
glVertexAttrib4fv(VATTR_COLOR, mColor.vec);
|
||||
|
||||
activeShader->muDesaturation.Set(mDesaturation / 255.f);
|
||||
activeShader->muFogEnabled.Set(fogset);
|
||||
activeShader->muTextureMode.Set(mTextureMode);
|
||||
activeShader->muCameraPos.Set(mCameraPos.vec);
|
||||
activeShader->muLightParms.Set(mLightParms);
|
||||
activeShader->muFogColor.Set(mFogColor);
|
||||
activeShader->muObjectColor.Set(mObjectColor);
|
||||
activeShader->muDynLightColor.Set(mDynColor.vec);
|
||||
activeShader->muInterpolationFactor.Set(mInterpolationFactor);
|
||||
activeShader->muClipHeightTop.Set(mClipHeightTop);
|
||||
activeShader->muClipHeightBottom.Set(mClipHeightBottom);
|
||||
activeShader->muTimer.Set(gl_frameMS * mShaderTimer / 1000.f);
|
||||
activeShader->muAlphaThreshold.Set(mAlphaThreshold);
|
||||
activeShader->muLightIndex.Set(mLightIndex); // will always be -1 for now
|
||||
activeShader->muClipSplit.Set(mClipSplit);
|
||||
|
||||
if (mGlowEnabled)
|
||||
{
|
||||
activeShader->muGlowTopColor.Set(mGlowTop.vec);
|
||||
activeShader->muGlowBottomColor.Set(mGlowBottom.vec);
|
||||
activeShader->muGlowTopPlane.Set(mGlowTopPlane.vec);
|
||||
activeShader->muGlowBottomPlane.Set(mGlowBottomPlane.vec);
|
||||
activeShader->currentglowstate = 1;
|
||||
}
|
||||
else if (activeShader->currentglowstate)
|
||||
{
|
||||
// if glowing is on, disable it.
|
||||
static const float nulvec[] = { 0.f, 0.f, 0.f, 0.f };
|
||||
activeShader->muGlowTopColor.Set(nulvec);
|
||||
activeShader->muGlowBottomColor.Set(nulvec);
|
||||
activeShader->muGlowTopPlane.Set(nulvec);
|
||||
activeShader->muGlowBottomPlane.Set(nulvec);
|
||||
activeShader->currentglowstate = 0;
|
||||
}
|
||||
|
||||
if (mColormapState != activeShader->currentfixedcolormap)
|
||||
{
|
||||
float r, g, b;
|
||||
activeShader->currentfixedcolormap = mColormapState;
|
||||
if (mColormapState == CM_DEFAULT)
|
||||
{
|
||||
activeShader->muFixedColormap.Set(0);
|
||||
}
|
||||
else if (mColormapState < CM_MAXCOLORMAP)
|
||||
{
|
||||
FSpecialColormap *scm = &SpecialColormaps[gl_fixedcolormap - CM_FIRSTSPECIALCOLORMAP];
|
||||
float m[] = { scm->ColorizeEnd[0] - scm->ColorizeStart[0],
|
||||
scm->ColorizeEnd[1] - scm->ColorizeStart[1], scm->ColorizeEnd[2] - scm->ColorizeStart[2], 0.f };
|
||||
|
||||
activeShader->muFixedColormap.Set(1);
|
||||
activeShader->muColormapStart.Set(scm->ColorizeStart[0], scm->ColorizeStart[1], scm->ColorizeStart[2], 0.f);
|
||||
activeShader->muColormapRange.Set(m);
|
||||
}
|
||||
else if (mColormapState == CM_FOGLAYER)
|
||||
{
|
||||
activeShader->muFixedColormap.Set(3);
|
||||
}
|
||||
else if (mColormapState == CM_LITE)
|
||||
{
|
||||
if (gl_enhanced_nightvision)
|
||||
{
|
||||
r = 0.375f, g = 1.0f, b = 0.375f;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = g = b = 1.f;
|
||||
}
|
||||
activeShader->muFixedColormap.Set(2);
|
||||
activeShader->muColormapStart.Set(r, g, b, 1.f);
|
||||
}
|
||||
else if (mColormapState >= CM_TORCH)
|
||||
{
|
||||
int flicker = mColormapState - CM_TORCH;
|
||||
r = (0.8f + (7 - flicker) / 70.0f);
|
||||
if (r > 1.0f) r = 1.0f;
|
||||
b = g = r;
|
||||
if (gl_enhanced_nightvision) b = g * 0.75f;
|
||||
activeShader->muFixedColormap.Set(2);
|
||||
activeShader->muColormapStart.Set(r, g, b, 1.f);
|
||||
}
|
||||
}
|
||||
if (mTextureMatrixEnabled)
|
||||
{
|
||||
mTextureMatrix.matrixToGL(activeShader->texturematrix_index);
|
||||
activeShader->currentTextureMatrixState = true;
|
||||
}
|
||||
else if (activeShader->currentTextureMatrixState)
|
||||
{
|
||||
activeShader->currentTextureMatrixState = false;
|
||||
identityMatrix.matrixToGL(activeShader->texturematrix_index);
|
||||
}
|
||||
|
||||
if (mModelMatrixEnabled)
|
||||
{
|
||||
mModelMatrix.matrixToGL(activeShader->modelmatrix_index);
|
||||
activeShader->currentModelMatrixState = true;
|
||||
}
|
||||
else if (activeShader->currentModelMatrixState)
|
||||
{
|
||||
activeShader->currentModelMatrixState = false;
|
||||
identityMatrix.matrixToGL(activeShader->modelmatrix_index);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Apply State
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FRenderState::Apply()
|
||||
{
|
||||
if (!gl_direct_state_change)
|
||||
{
|
||||
if (mSrcBlend != stSrcBlend || mDstBlend != stDstBlend)
|
||||
{
|
||||
stSrcBlend = mSrcBlend;
|
||||
stDstBlend = mDstBlend;
|
||||
glBlendFunc(mSrcBlend, mDstBlend);
|
||||
}
|
||||
if (mBlendEquation != stBlendEquation)
|
||||
{
|
||||
stBlendEquation = mBlendEquation;
|
||||
glBlendEquation(mBlendEquation);
|
||||
}
|
||||
}
|
||||
|
||||
//ApplyColorMask(); I don't think this is needed.
|
||||
|
||||
if (mVertexBuffer != mCurrentVertexBuffer)
|
||||
{
|
||||
if (mVertexBuffer == NULL) glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
else mVertexBuffer->BindVBO();
|
||||
mCurrentVertexBuffer = mVertexBuffer;
|
||||
}
|
||||
ApplyShader();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FRenderState::ApplyColorMask()
|
||||
{
|
||||
if ((mColorMask[0] != currentColorMask[0]) ||
|
||||
(mColorMask[1] != currentColorMask[1]) ||
|
||||
(mColorMask[2] != currentColorMask[2]) ||
|
||||
(mColorMask[3] != currentColorMask[3]))
|
||||
{
|
||||
glColorMask(mColorMask[0], mColorMask[1], mColorMask[2], mColorMask[3]);
|
||||
currentColorMask[0] = mColorMask[0];
|
||||
currentColorMask[1] = mColorMask[1];
|
||||
currentColorMask[2] = mColorMask[2];
|
||||
currentColorMask[3] = mColorMask[3];
|
||||
}
|
||||
}
|
||||
|
||||
void FRenderState::ApplyMatrices()
|
||||
{
|
||||
if (GLRenderer->mShaderManager != NULL)
|
||||
{
|
||||
GLRenderer->mShaderManager->ApplyMatrices(&mProjectionMatrix, &mViewMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
void FRenderState::ApplyLightIndex(int index)
|
||||
{
|
||||
if (GLRenderer->mLights->GetBufferType() == GL_UNIFORM_BUFFER && index > -1)
|
||||
{
|
||||
index = GLRenderer->mLights->BindUBO(index);
|
||||
}
|
||||
activeShader->muLightIndex.Set(index);
|
||||
}
|
384
src/gl/renderer/gl_renderstate.h
Normal file
384
src/gl/renderer/gl_renderstate.h
Normal file
|
@ -0,0 +1,384 @@
|
|||
#ifndef __GL_RENDERSTATE_H
|
||||
#define __GL_RENDERSTATE_H
|
||||
|
||||
#include <string.h>
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_matrix.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "c_cvars.h"
|
||||
#include "r_defs.h"
|
||||
#include "r_data/r_translate.h"
|
||||
|
||||
class FVertexBuffer;
|
||||
class FShader;
|
||||
extern TArray<VSMatrix> gl_MatrixStack;
|
||||
|
||||
EXTERN_CVAR(Bool, gl_direct_state_change)
|
||||
|
||||
struct FStateVec4
|
||||
{
|
||||
float vec[4];
|
||||
|
||||
void Set(float r, float g, float b, float a)
|
||||
{
|
||||
vec[0] = r;
|
||||
vec[1] = g;
|
||||
vec[2] = b;
|
||||
vec[3] = a;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
enum EEffect
|
||||
{
|
||||
EFF_NONE=-1,
|
||||
EFF_FOGBOUNDARY,
|
||||
EFF_SPHEREMAP,
|
||||
EFF_BURN,
|
||||
EFF_STENCIL,
|
||||
|
||||
MAX_EFFECTS
|
||||
};
|
||||
|
||||
class FRenderState
|
||||
{
|
||||
bool mTextureEnabled;
|
||||
bool mFogEnabled;
|
||||
bool mGlowEnabled;
|
||||
bool mBrightmapEnabled;
|
||||
bool mColorMask[4];
|
||||
bool currentColorMask[4];
|
||||
int mLightIndex;
|
||||
int mSpecialEffect;
|
||||
int mTextureMode;
|
||||
int mDesaturation;
|
||||
int mSoftLight;
|
||||
float mLightParms[4];
|
||||
int mSrcBlend, mDstBlend;
|
||||
float mAlphaThreshold;
|
||||
int mBlendEquation;
|
||||
bool mAlphaTest;
|
||||
bool m2D;
|
||||
bool mModelMatrixEnabled;
|
||||
bool mTextureMatrixEnabled;
|
||||
float mInterpolationFactor;
|
||||
float mClipHeightTop, mClipHeightBottom;
|
||||
float mShaderTimer;
|
||||
bool mLastDepthClamp;
|
||||
|
||||
FVertexBuffer *mVertexBuffer, *mCurrentVertexBuffer;
|
||||
FStateVec4 mColor;
|
||||
FStateVec4 mCameraPos;
|
||||
FStateVec4 mGlowTop, mGlowBottom;
|
||||
FStateVec4 mGlowTopPlane, mGlowBottomPlane;
|
||||
PalEntry mFogColor;
|
||||
PalEntry mObjectColor;
|
||||
FStateVec4 mDynColor;
|
||||
float mClipSplit[2];
|
||||
|
||||
int mEffectState;
|
||||
int mColormapState;
|
||||
|
||||
float stAlphaThreshold;
|
||||
int stSrcBlend, stDstBlend;
|
||||
bool stAlphaTest;
|
||||
int stBlendEquation;
|
||||
|
||||
FShader *activeShader;
|
||||
|
||||
bool ApplyShader();
|
||||
|
||||
public:
|
||||
|
||||
VSMatrix mProjectionMatrix;
|
||||
VSMatrix mViewMatrix;
|
||||
VSMatrix mModelMatrix;
|
||||
VSMatrix mTextureMatrix;
|
||||
|
||||
FRenderState()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset();
|
||||
|
||||
void SetMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader, bool alphatexture)
|
||||
{
|
||||
// textures without their own palette are a special case for use as an alpha texture:
|
||||
// They use the color index directly as an alpha value instead of using the palette's red.
|
||||
// To handle this case, we need to set a special translation for such textures.
|
||||
if (alphatexture)
|
||||
{
|
||||
if (mat->tex->UseBasePalette()) translation = TRANSLATION(TRANSLATION_Standard, 8);
|
||||
}
|
||||
mEffectState = overrideshader >= 0? overrideshader : mat->mShaderIndex;
|
||||
mShaderTimer = mat->tex->gl_info.shaderspeed;
|
||||
mat->Bind(clampmode, translation);
|
||||
}
|
||||
|
||||
void Apply();
|
||||
void ApplyColorMask();
|
||||
void ApplyMatrices();
|
||||
void ApplyLightIndex(int index);
|
||||
|
||||
void SetVertexBuffer(FVertexBuffer *vb)
|
||||
{
|
||||
mVertexBuffer = vb;
|
||||
}
|
||||
|
||||
void ResetVertexBuffer()
|
||||
{
|
||||
// forces rebinding with the next 'apply' call.
|
||||
mCurrentVertexBuffer = NULL;
|
||||
}
|
||||
|
||||
void SetClipHeightTop(float clip)
|
||||
{
|
||||
mClipHeightTop = clip;
|
||||
}
|
||||
|
||||
float GetClipHeightTop()
|
||||
{
|
||||
return mClipHeightTop;
|
||||
}
|
||||
|
||||
void SetClipHeightBottom(float clip)
|
||||
{
|
||||
mClipHeightBottom = clip;
|
||||
}
|
||||
|
||||
float GetClipHeightBottom()
|
||||
{
|
||||
return mClipHeightBottom;
|
||||
}
|
||||
|
||||
void SetColor(float r, float g, float b, float a = 1.f, int desat = 0)
|
||||
{
|
||||
mColor.Set(r, g, b, a);
|
||||
mDesaturation = desat;
|
||||
}
|
||||
|
||||
void SetColor(PalEntry pe, int desat = 0)
|
||||
{
|
||||
mColor.Set(pe.r/255.f, pe.g/255.f, pe.b/255.f, pe.a/255.f);
|
||||
mDesaturation = desat;
|
||||
}
|
||||
|
||||
void SetColorAlpha(PalEntry pe, float alpha = 1.f, int desat = 0)
|
||||
{
|
||||
mColor.Set(pe.r/255.f, pe.g/255.f, pe.b/255.f, alpha);
|
||||
mDesaturation = desat;
|
||||
}
|
||||
|
||||
void ResetColor()
|
||||
{
|
||||
mColor.Set(1,1,1,1);
|
||||
mDesaturation = 0;
|
||||
}
|
||||
|
||||
void GetColorMask(bool& r, bool &g, bool& b, bool& a) const
|
||||
{
|
||||
r = mColorMask[0];
|
||||
g = mColorMask[1];
|
||||
b = mColorMask[2];
|
||||
a = mColorMask[3];
|
||||
}
|
||||
|
||||
void SetColorMask(bool r, bool g, bool b, bool a)
|
||||
{
|
||||
mColorMask[0] = r;
|
||||
mColorMask[1] = g;
|
||||
mColorMask[2] = b;
|
||||
mColorMask[3] = a;
|
||||
}
|
||||
|
||||
void ResetColorMask()
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
mColorMask[i] = true;
|
||||
}
|
||||
|
||||
void SetTextureMode(int mode)
|
||||
{
|
||||
mTextureMode = mode;
|
||||
}
|
||||
|
||||
int GetTextureMode()
|
||||
{
|
||||
return mTextureMode;
|
||||
}
|
||||
|
||||
void EnableTexture(bool on)
|
||||
{
|
||||
mTextureEnabled = on;
|
||||
}
|
||||
|
||||
void EnableFog(bool on)
|
||||
{
|
||||
mFogEnabled = on;
|
||||
}
|
||||
|
||||
void SetEffect(int eff)
|
||||
{
|
||||
mSpecialEffect = eff;
|
||||
}
|
||||
|
||||
void EnableGlow(bool on)
|
||||
{
|
||||
mGlowEnabled = on;
|
||||
}
|
||||
|
||||
void SetLightIndex(int n)
|
||||
{
|
||||
mLightIndex = n;
|
||||
}
|
||||
|
||||
void EnableBrightmap(bool on)
|
||||
{
|
||||
mBrightmapEnabled = on;
|
||||
}
|
||||
|
||||
void EnableModelMatrix(bool on)
|
||||
{
|
||||
mModelMatrixEnabled = on;
|
||||
}
|
||||
|
||||
void EnableTextureMatrix(bool on)
|
||||
{
|
||||
mTextureMatrixEnabled = on;
|
||||
}
|
||||
|
||||
void SetCameraPos(float x, float y, float z)
|
||||
{
|
||||
mCameraPos.Set(x, z, y, 0);
|
||||
}
|
||||
|
||||
void SetGlowParams(float *t, float *b)
|
||||
{
|
||||
mGlowTop.Set(t[0], t[1], t[2], t[3]);
|
||||
mGlowBottom.Set(b[0], b[1], b[2], b[3]);
|
||||
}
|
||||
|
||||
void SetSoftLightLevel(int level)
|
||||
{
|
||||
if (glset.lightmode == 8) mLightParms[3] = level / 255.f;
|
||||
else mLightParms[3] = -1.f;
|
||||
}
|
||||
|
||||
void SetGlowPlanes(const secplane_t &top, const secplane_t &bottom)
|
||||
{
|
||||
mGlowTopPlane.Set(FIXED2FLOAT(top.a), FIXED2FLOAT(top.b), FIXED2FLOAT(top.ic), FIXED2FLOAT(top.d));
|
||||
mGlowBottomPlane.Set(FIXED2FLOAT(bottom.a), FIXED2FLOAT(bottom.b), FIXED2FLOAT(bottom.ic), FIXED2FLOAT(bottom.d));
|
||||
}
|
||||
|
||||
void SetDynLight(float r, float g, float b)
|
||||
{
|
||||
mDynColor.Set(r, g, b, 0);
|
||||
}
|
||||
|
||||
void SetObjectColor(PalEntry pe)
|
||||
{
|
||||
mObjectColor = pe;
|
||||
}
|
||||
|
||||
void SetFog(PalEntry c, float d)
|
||||
{
|
||||
const float LOG2E = 1.442692f; // = 1/log(2)
|
||||
mFogColor = c;
|
||||
if (d >= 0.0f) mLightParms[2] = d * (-LOG2E / 64000.f);
|
||||
}
|
||||
|
||||
void SetLightParms(float f, float d)
|
||||
{
|
||||
mLightParms[1] = f;
|
||||
mLightParms[0] = d;
|
||||
}
|
||||
|
||||
void SetFixedColormap(int cm)
|
||||
{
|
||||
mColormapState = cm;
|
||||
}
|
||||
|
||||
PalEntry GetFogColor() const
|
||||
{
|
||||
return mFogColor;
|
||||
}
|
||||
|
||||
void SetClipSplit(float bottom, float top)
|
||||
{
|
||||
mClipSplit[0] = bottom;
|
||||
mClipSplit[1] = top;
|
||||
}
|
||||
|
||||
void SetClipSplit(float *vals)
|
||||
{
|
||||
memcpy(mClipSplit, vals, 2 * sizeof(float));
|
||||
}
|
||||
|
||||
void GetClipSplit(float *out)
|
||||
{
|
||||
memcpy(out, mClipSplit, 2 * sizeof(float));
|
||||
}
|
||||
|
||||
void ClearClipSplit()
|
||||
{
|
||||
mClipSplit[0] = -1000000.f;
|
||||
mClipSplit[1] = 1000000.f;
|
||||
}
|
||||
|
||||
void BlendFunc(int src, int dst)
|
||||
{
|
||||
if (!gl_direct_state_change)
|
||||
{
|
||||
mSrcBlend = src;
|
||||
mDstBlend = dst;
|
||||
}
|
||||
else
|
||||
{
|
||||
glBlendFunc(src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
void AlphaFunc(int func, float thresh)
|
||||
{
|
||||
if (func == GL_GREATER) mAlphaThreshold = thresh;
|
||||
else mAlphaThreshold = thresh - 0.001f;
|
||||
}
|
||||
|
||||
void BlendEquation(int eq)
|
||||
{
|
||||
if (!gl_direct_state_change)
|
||||
{
|
||||
mBlendEquation = eq;
|
||||
}
|
||||
else
|
||||
{
|
||||
glBlendEquation(eq);
|
||||
}
|
||||
}
|
||||
|
||||
// This wraps the depth clamp setting because we frequently need to read it which OpenGL is not particularly performant at...
|
||||
bool SetDepthClamp(bool on)
|
||||
{
|
||||
bool res = mLastDepthClamp;
|
||||
if (!on) glDisable(GL_DEPTH_CLAMP);
|
||||
else glEnable(GL_DEPTH_CLAMP);
|
||||
mLastDepthClamp = on;
|
||||
return res;
|
||||
}
|
||||
|
||||
void Set2DMode(bool on)
|
||||
{
|
||||
m2D = on;
|
||||
}
|
||||
|
||||
void SetInterpolationFactor(float fac)
|
||||
{
|
||||
mInterpolationFactor = fac;
|
||||
}
|
||||
};
|
||||
|
||||
extern FRenderState gl_RenderState;
|
||||
|
||||
#endif
|
525
src/gl/scene/gl_bsp.cpp
Normal file
525
src/gl/scene/gl_bsp.cpp
Normal file
|
@ -0,0 +1,525 @@
|
|||
/*
|
||||
** gl_bsp.cpp
|
||||
** Main rendering loop / BSP traversal / visibility clipping
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2000-2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "p_lnspec.h"
|
||||
#include "p_local.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "r_sky.h"
|
||||
#include "p_effect.h"
|
||||
#include "po_man.h"
|
||||
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/scene/gl_clipper.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/scene/gl_wall.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
|
||||
EXTERN_CVAR(Bool, gl_render_segs)
|
||||
|
||||
Clipper clipper;
|
||||
|
||||
|
||||
CVAR(Bool, gl_render_things, true, 0)
|
||||
CVAR(Bool, gl_render_walls, true, 0)
|
||||
CVAR(Bool, gl_render_flats, true, 0)
|
||||
|
||||
|
||||
static void UnclipSubsector(subsector_t *sub)
|
||||
{
|
||||
int count = sub->numlines;
|
||||
seg_t * seg = sub->firstline;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
angle_t startAngle = seg->v2->GetClipAngle();
|
||||
angle_t endAngle = seg->v1->GetClipAngle();
|
||||
|
||||
// Back side, i.e. backface culling - read: endAngle >= startAngle!
|
||||
if (startAngle-endAngle >= ANGLE_180)
|
||||
{
|
||||
clipper.SafeRemoveClipRange(startAngle, endAngle);
|
||||
}
|
||||
seg++;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_AddLine
|
||||
// Clips the given segment
|
||||
// and adds any visible pieces to the line list.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
// making these 2 variables global instead of passing them as function parameters is faster.
|
||||
static subsector_t *currentsubsector;
|
||||
static sector_t *currentsector;
|
||||
|
||||
static void AddLine (seg_t *seg)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (seg->linedef - lines == 38)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
angle_t startAngle, endAngle;
|
||||
sector_t * backsector = NULL;
|
||||
sector_t bs;
|
||||
|
||||
if (GLRenderer->mCurrentPortal)
|
||||
{
|
||||
int clipres = GLRenderer->mCurrentPortal->ClipSeg(seg);
|
||||
if (clipres == GLPortal::PClip_InFront) return;
|
||||
}
|
||||
|
||||
startAngle = seg->v2->GetClipAngle();
|
||||
endAngle = seg->v1->GetClipAngle();
|
||||
|
||||
// Back side, i.e. backface culling - read: endAngle >= startAngle!
|
||||
if (startAngle-endAngle<ANGLE_180)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (seg->sidedef == NULL)
|
||||
{
|
||||
if (!(currentsubsector->flags & SSECF_DRAWN))
|
||||
{
|
||||
if (clipper.SafeCheckRange(startAngle, endAngle))
|
||||
{
|
||||
currentsubsector->flags |= SSECF_DRAWN;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clipper.SafeCheckRange(startAngle, endAngle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
currentsubsector->flags |= SSECF_DRAWN;
|
||||
|
||||
if (!seg->backsector)
|
||||
{
|
||||
clipper.SafeAddClipRange(startAngle, endAngle);
|
||||
}
|
||||
else if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) // Two-sided polyobjects never obstruct the view
|
||||
{
|
||||
if (currentsector->sectornum == seg->backsector->sectornum)
|
||||
{
|
||||
FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::mid));
|
||||
if (!tex || tex->UseType==FTexture::TEX_Null)
|
||||
{
|
||||
// nothing to do here!
|
||||
seg->linedef->validcount=validcount;
|
||||
return;
|
||||
}
|
||||
backsector=currentsector;
|
||||
}
|
||||
else
|
||||
{
|
||||
// clipping checks are only needed when the backsector is not the same as the front sector
|
||||
gl_CheckViewArea(seg->v1, seg->v2, seg->frontsector, seg->backsector);
|
||||
|
||||
backsector = gl_FakeFlat(seg->backsector, &bs, true);
|
||||
|
||||
if (gl_CheckClip(seg->sidedef, currentsector, backsector))
|
||||
{
|
||||
clipper.SafeAddClipRange(startAngle, endAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backsector for polyobj segs is always the containing sector itself
|
||||
backsector = currentsector;
|
||||
}
|
||||
|
||||
seg->linedef->flags |= ML_MAPPED;
|
||||
|
||||
if ((seg->sidedef->Flags & WALLF_POLYOBJ) || seg->linedef->validcount!=validcount)
|
||||
{
|
||||
if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) seg->linedef->validcount=validcount;
|
||||
|
||||
if (gl_render_walls)
|
||||
{
|
||||
SetupWall.Clock();
|
||||
|
||||
GLWall wall;
|
||||
wall.sub = currentsubsector;
|
||||
wall.Process(seg, currentsector, backsector);
|
||||
rendered_lines++;
|
||||
|
||||
SetupWall.Unclock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_Subsector
|
||||
// Determine floor/ceiling planes.
|
||||
// Add sprites of things in sector.
|
||||
// Draw one or more line segments.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void PolySubsector(subsector_t * sub)
|
||||
{
|
||||
int count = sub->numlines;
|
||||
seg_t * line = sub->firstline;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
if (line->linedef)
|
||||
{
|
||||
AddLine (line);
|
||||
}
|
||||
line++;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// RenderBSPNode
|
||||
// Renders all subsectors below a given node,
|
||||
// traversing subtree recursively.
|
||||
// Just call with BSP root.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void RenderPolyBSPNode (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 = R_PointOnSide(viewx, viewy, bsp);
|
||||
|
||||
// Recursively divide front space (toward the viewer).
|
||||
RenderPolyBSPNode (bsp->children[side]);
|
||||
|
||||
// Possibly divide back space (away from the viewer).
|
||||
side ^= 1;
|
||||
|
||||
// It is not necessary to use the slower precise version here
|
||||
if (!clipper.CheckBox(bsp->bbox[side]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
node = bsp->children[side];
|
||||
}
|
||||
PolySubsector ((subsector_t *)((BYTE *)node - 1));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Unlilke the software renderer this function will only draw the walls,
|
||||
// not the flats. Those are handled as a whole by the parent subsector.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void AddPolyobjs(subsector_t *sub)
|
||||
{
|
||||
if (sub->BSP == NULL || sub->BSP->bDirty)
|
||||
{
|
||||
sub->BuildPolyBSP();
|
||||
for (unsigned i = 0; i < sub->BSP->Segs.Size(); i++)
|
||||
{
|
||||
sub->BSP->Segs[i].Subsector = sub;
|
||||
sub->BSP->Segs[i].PartnerSeg = NULL;
|
||||
}
|
||||
}
|
||||
if (sub->BSP->Nodes.Size() == 0)
|
||||
{
|
||||
PolySubsector(&sub->BSP->Subsectors[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderPolyBSPNode(&sub->BSP->Nodes.Last());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static inline void AddLines(subsector_t * sub, sector_t * sector)
|
||||
{
|
||||
currentsector = sector;
|
||||
currentsubsector = sub;
|
||||
|
||||
ClipWall.Clock();
|
||||
if (sub->polys != NULL)
|
||||
{
|
||||
AddPolyobjs(sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
int count = sub->numlines;
|
||||
seg_t * seg = sub->firstline;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
if (seg->linedef == NULL)
|
||||
{
|
||||
if (!(sub->flags & SSECF_DRAWN)) AddLine (seg);
|
||||
}
|
||||
else if (!(seg->sidedef->Flags & WALLF_POLYOBJ))
|
||||
{
|
||||
AddLine (seg);
|
||||
}
|
||||
seg++;
|
||||
}
|
||||
}
|
||||
ClipWall.Unclock();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_RenderThings
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static inline void RenderThings(subsector_t * sub, sector_t * sector)
|
||||
{
|
||||
|
||||
SetupSprite.Clock();
|
||||
sector_t * sec=sub->sector;
|
||||
if (sec->thinglist != NULL)
|
||||
{
|
||||
// Handle all things in sector.
|
||||
for (AActor * thing = sec->thinglist; thing; thing = thing->snext)
|
||||
{
|
||||
GLRenderer->ProcessSprite(thing, sector);
|
||||
}
|
||||
}
|
||||
SetupSprite.Unclock();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_Subsector
|
||||
// Determine floor/ceiling planes.
|
||||
// Add sprites of things in sector.
|
||||
// Draw one or more line segments.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void DoSubsector(subsector_t * sub)
|
||||
{
|
||||
unsigned int i;
|
||||
sector_t * sector;
|
||||
sector_t * fakesector;
|
||||
sector_t fake;
|
||||
|
||||
// check for visibility of this entire subsector. This requires GL nodes.
|
||||
// (disabled because it costs more time than it saves.)
|
||||
//if (!clipper.CheckBox(sub->bbox)) return;
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (sub->sector-sectors==931)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
sector=sub->sector;
|
||||
if (!sector) return;
|
||||
|
||||
// If the mapsections differ this subsector can't possibly be visible from the current view point
|
||||
if (!(currentmapsection[sub->mapsection>>3] & (1 << (sub->mapsection & 7)))) return;
|
||||
|
||||
if (gl_drawinfo->ss_renderflags[sub-subsectors] & SSRF_SEEN)
|
||||
{
|
||||
// This means that we have reached a subsector in a portal that has been marked 'seen'
|
||||
// from the other side of the portal. This means we must clear the clipper for the
|
||||
// range this subsector spans before going on.
|
||||
UnclipSubsector(sub);
|
||||
}
|
||||
|
||||
fakesector=gl_FakeFlat(sector, &fake, false);
|
||||
|
||||
if (sector->validcount != validcount)
|
||||
{
|
||||
GLRenderer->mVBO->CheckUpdate(sector);
|
||||
}
|
||||
|
||||
// [RH] Add particles
|
||||
//int shade = LIGHT2SHADE((floorlightlevel + ceilinglightlevel)/2 + r_actualextralight);
|
||||
if (gl_render_things)
|
||||
{
|
||||
SetupSprite.Clock();
|
||||
|
||||
for (i = ParticlesInSubsec[DWORD(sub-subsectors)]; i != NO_PARTICLE; i = Particles[i].snext)
|
||||
{
|
||||
GLRenderer->ProcessParticle(&Particles[i], fakesector);
|
||||
}
|
||||
SetupSprite.Unclock();
|
||||
}
|
||||
|
||||
AddLines(sub, fakesector);
|
||||
|
||||
// BSP is traversed by subsector.
|
||||
// A sector might have been split into several
|
||||
// subsectors during BSP building.
|
||||
// Thus we check whether it was already added.
|
||||
if (sector->validcount != validcount)
|
||||
{
|
||||
// Well, now it will be done.
|
||||
sector->validcount = validcount;
|
||||
|
||||
if (gl_render_things)
|
||||
{
|
||||
RenderThings(sub, fakesector);
|
||||
}
|
||||
sector->MoreFlags |= SECF_DRAWN;
|
||||
}
|
||||
|
||||
if (gl_render_flats)
|
||||
{
|
||||
// Subsectors with only 2 lines cannot have any area!
|
||||
if (sub->numlines>2 || (sub->hacked&1))
|
||||
{
|
||||
// Exclude the case when it tries to render a sector with a heightsec
|
||||
// but undetermined heightsec state. This can only happen if the
|
||||
// subsector is obstructed but not excluded due to a large bounding box.
|
||||
// Due to the way a BSP works such a subsector can never be visible
|
||||
if (!sector->heightsec || sector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC || in_area!=area_default)
|
||||
{
|
||||
if (sector != sub->render_sector)
|
||||
{
|
||||
sector = sub->render_sector;
|
||||
// the planes of this subsector are faked to belong to another sector
|
||||
// This means we need the heightsec parts and light info of the render sector, not the actual one.
|
||||
fakesector = gl_FakeFlat(sector, &fake, false);
|
||||
}
|
||||
|
||||
BYTE &srf = gl_drawinfo->sectorrenderflags[sub->render_sector->sectornum];
|
||||
if (!(srf & SSRF_PROCESSED))
|
||||
{
|
||||
srf |= SSRF_PROCESSED;
|
||||
|
||||
SetupFlat.Clock();
|
||||
GLRenderer->ProcessSector(fakesector);
|
||||
SetupFlat.Unclock();
|
||||
}
|
||||
// mark subsector as processed - but mark for rendering only if it has an actual area.
|
||||
gl_drawinfo->ss_renderflags[sub-subsectors] =
|
||||
(sub->numlines > 2) ? SSRF_PROCESSED|SSRF_RENDERALL : SSRF_PROCESSED;
|
||||
if (sub->hacked & 1) gl_drawinfo->AddHackedSubsector(sub);
|
||||
|
||||
FPortal *portal;
|
||||
|
||||
portal = fakesector->portals[sector_t::ceiling];
|
||||
if (portal != NULL)
|
||||
{
|
||||
GLSectorStackPortal *glportal = portal->GetGLPortal();
|
||||
glportal->AddSubsector(sub);
|
||||
}
|
||||
|
||||
portal = fakesector->portals[sector_t::floor];
|
||||
if (portal != NULL)
|
||||
{
|
||||
GLSectorStackPortal *glportal = portal->GetGLPortal();
|
||||
glportal->AddSubsector(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// RenderBSPNode
|
||||
// Renders all subsectors below a given node,
|
||||
// traversing subtree recursively.
|
||||
// Just call with BSP root.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_RenderBSPNode (void *node)
|
||||
{
|
||||
if (numnodes == 0)
|
||||
{
|
||||
DoSubsector (subsectors);
|
||||
return;
|
||||
}
|
||||
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 = R_PointOnSide(viewx, viewy, bsp);
|
||||
|
||||
// Recursively divide front space (toward the viewer).
|
||||
gl_RenderBSPNode (bsp->children[side]);
|
||||
|
||||
// Possibly divide back space (away from the viewer).
|
||||
side ^= 1;
|
||||
|
||||
// It is not necessary to use the slower precise version here
|
||||
if (!clipper.CheckBox(bsp->bbox[side]))
|
||||
{
|
||||
if (!(gl_drawinfo->no_renderflags[bsp-nodes] & SSRF_SEEN))
|
||||
return;
|
||||
}
|
||||
|
||||
node = bsp->children[side];
|
||||
}
|
||||
DoSubsector ((subsector_t *)((BYTE *)node - 1));
|
||||
}
|
||||
|
||||
|
458
src/gl/scene/gl_clipper.cpp
Normal file
458
src/gl/scene/gl_clipper.cpp
Normal file
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
*
|
||||
** gl_clipper.cpp
|
||||
**
|
||||
** Handles visibility checks.
|
||||
** Loosely based on the JDoom clipper.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2003 Tim Stump
|
||||
** 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 "gl/scene/gl_clipper.h"
|
||||
|
||||
|
||||
|
||||
ClipNode * ClipNode::freelist;
|
||||
int Clipper::anglecache;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Destructor
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Clipper::~Clipper()
|
||||
{
|
||||
Clear();
|
||||
while (ClipNode::freelist != NULL)
|
||||
{
|
||||
ClipNode * node = ClipNode::freelist;
|
||||
ClipNode::freelist = node->next;
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RemoveRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::RemoveRange(ClipNode * range)
|
||||
{
|
||||
if (range == cliphead)
|
||||
{
|
||||
cliphead = cliphead->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (range->prev) range->prev->next = range->next;
|
||||
if (range->next) range->next->prev = range->prev;
|
||||
}
|
||||
|
||||
range->Free();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Clear
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::Clear()
|
||||
{
|
||||
ClipNode *node = cliphead;
|
||||
ClipNode *temp;
|
||||
|
||||
while (node != NULL)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
temp->Free();
|
||||
}
|
||||
node = silhouette;
|
||||
|
||||
while (node != NULL)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
temp->Free();
|
||||
}
|
||||
|
||||
cliphead = NULL;
|
||||
silhouette = NULL;
|
||||
anglecache++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// SetSilhouette
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::SetSilhouette()
|
||||
{
|
||||
ClipNode *node = cliphead;
|
||||
ClipNode *last = NULL;
|
||||
|
||||
while (node != NULL)
|
||||
{
|
||||
ClipNode *snode = ClipNode::NewRange(node->start, node->end);
|
||||
if (silhouette == NULL) silhouette = snode;
|
||||
snode->prev = last;
|
||||
if (last != NULL) last->next = snode;
|
||||
last = snode;
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// IsRangeVisible
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool Clipper::IsRangeVisible(angle_t startAngle, angle_t endAngle)
|
||||
{
|
||||
ClipNode *ci;
|
||||
ci = cliphead;
|
||||
|
||||
if (endAngle==0 && ci && ci->start==0) return false;
|
||||
|
||||
while (ci != NULL && ci->start < endAngle)
|
||||
{
|
||||
if (startAngle >= ci->start && endAngle <= ci->end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ci = ci->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// AddClipRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::AddClipRange(angle_t start, angle_t end)
|
||||
{
|
||||
ClipNode *node, *temp, *prevNode;
|
||||
|
||||
if (cliphead)
|
||||
{
|
||||
//check to see if range contains any old ranges
|
||||
node = cliphead;
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
if (node->start >= start && node->end <= end)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
RemoveRange(temp);
|
||||
}
|
||||
else if (node->start<=start && node->end>=end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
//check to see if range overlaps a range (or possibly 2)
|
||||
node = cliphead;
|
||||
while (node != NULL && node->start <= end)
|
||||
{
|
||||
if (node->end >= start)
|
||||
{
|
||||
// we found the first overlapping node
|
||||
if (node->start > start)
|
||||
{
|
||||
// the new range overlaps with this node's start point
|
||||
node->start = start;
|
||||
}
|
||||
|
||||
if (node->end < end)
|
||||
{
|
||||
node->end = end;
|
||||
}
|
||||
|
||||
ClipNode *node2 = node->next;
|
||||
while (node2 && node2->start <= node->end)
|
||||
{
|
||||
if (node2->end > node->end) node->end = node2->end;
|
||||
ClipNode *delnode = node2;
|
||||
node2 = node2->next;
|
||||
RemoveRange(delnode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
//just add range
|
||||
node = cliphead;
|
||||
prevNode = NULL;
|
||||
temp = ClipNode::NewRange(start, end);
|
||||
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
prevNode = node;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
temp->next = node;
|
||||
if (node == NULL)
|
||||
{
|
||||
temp->prev = prevNode;
|
||||
if (prevNode) prevNode->next = temp;
|
||||
if (!cliphead) cliphead = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node == cliphead)
|
||||
{
|
||||
cliphead->prev = temp;
|
||||
cliphead = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp->prev = prevNode;
|
||||
prevNode->next = temp;
|
||||
node->prev = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = ClipNode::NewRange(start, end);
|
||||
cliphead = temp;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RemoveClipRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::RemoveClipRange(angle_t start, angle_t end)
|
||||
{
|
||||
ClipNode *node;
|
||||
|
||||
if (silhouette)
|
||||
{
|
||||
node = silhouette;
|
||||
while (node != NULL && node->end <= start)
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
if (node != NULL && node->start <= start)
|
||||
{
|
||||
if (node->end >= end) return;
|
||||
start = node->end;
|
||||
node = node->next;
|
||||
}
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
DoRemoveClipRange(start, node->start);
|
||||
start = node->end;
|
||||
node = node->next;
|
||||
}
|
||||
if (start >= end) return;
|
||||
}
|
||||
DoRemoveClipRange(start, end);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RemoveClipRange worker function
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::DoRemoveClipRange(angle_t start, angle_t end)
|
||||
{
|
||||
ClipNode *node, *temp;
|
||||
|
||||
if (cliphead)
|
||||
{
|
||||
//check to see if range contains any old ranges
|
||||
node = cliphead;
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
if (node->start >= start && node->end <= end)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
RemoveRange(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
//check to see if range overlaps a range (or possibly 2)
|
||||
node = cliphead;
|
||||
while (node != NULL)
|
||||
{
|
||||
if (node->start >= start && node->start <= end)
|
||||
{
|
||||
node->start = end;
|
||||
break;
|
||||
}
|
||||
else if (node->end >= start && node->end <= end)
|
||||
{
|
||||
node->end=start;
|
||||
}
|
||||
else if (node->start < start && node->end > end)
|
||||
{
|
||||
temp=ClipNode::NewRange(end, node->end);
|
||||
node->end=start;
|
||||
temp->next=node->next;
|
||||
temp->prev=node;
|
||||
node->next=temp;
|
||||
if (temp->next) temp->next->prev=temp;
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t Clipper::AngleToPseudo(angle_t ang)
|
||||
{
|
||||
double vecx = cos(ang * M_PI / ANGLE_180);
|
||||
double vecy = sin(ang * M_PI / ANGLE_180);
|
||||
|
||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||
if (vecx < 0)
|
||||
{
|
||||
result = 2.f - result;
|
||||
}
|
||||
return xs_Fix<30>::ToFix(result);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ! Returns the pseudoangle between the line p1 to (infinity, p1.y) and the
|
||||
// line from p1 to p2. The pseudoangle has the property that the ordering of
|
||||
// points by true angle anround p1 and ordering of points by pseudoangle are the
|
||||
// same.
|
||||
//
|
||||
// For clipping exact angles are not needed. Only the ordering matters.
|
||||
// This is about as fast as the fixed point R_PointToAngle2 but without
|
||||
// the precision issues associated with that function.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t R_PointToPseudoAngle (fixed_t viewx, fixed_t viewy, fixed_t x, fixed_t y)
|
||||
{
|
||||
// Note: float won't work here as it's less precise than the BAM values being passed as parameters
|
||||
double vecx = double(x-viewx);
|
||||
double vecy = double(y-viewy);
|
||||
|
||||
if (vecx == 0 && vecy == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||
if (vecx < 0)
|
||||
{
|
||||
result = 2.f - result;
|
||||
}
|
||||
return xs_Fix<30>::ToFix(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// R_CheckBBox
|
||||
// Checks BSP node/subtree bounding box.
|
||||
// Returns true
|
||||
// if some part of the bbox might be visible.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
static const int checkcoord[12][4] = // killough -- static const
|
||||
{
|
||||
{3,0,2,1},
|
||||
{3,0,2,0},
|
||||
{3,1,2,0},
|
||||
{0},
|
||||
{2,0,2,1},
|
||||
{0,0,0,0},
|
||||
{3,1,3,0},
|
||||
{0},
|
||||
{2,0,3,1},
|
||||
{2,1,3,1},
|
||||
{2,1,3,0}
|
||||
};
|
||||
|
||||
bool Clipper::CheckBox(const fixed_t *bspcoord)
|
||||
{
|
||||
angle_t angle1, angle2;
|
||||
|
||||
int boxpos;
|
||||
const int* check;
|
||||
|
||||
// Find the corners of the box
|
||||
// that define the edges from current viewpoint.
|
||||
boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT ] ? 1 : 2) +
|
||||
(viewy >= bspcoord[BOXTOP ] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8);
|
||||
|
||||
if (boxpos == 5) return true;
|
||||
|
||||
check = checkcoord[boxpos];
|
||||
angle1 = R_PointToPseudoAngle (viewx, viewy, bspcoord[check[0]], bspcoord[check[1]]);
|
||||
angle2 = R_PointToPseudoAngle (viewx, viewy, bspcoord[check[2]], bspcoord[check[3]]);
|
||||
|
||||
return SafeCheckRange(angle2, angle1);
|
||||
}
|
||||
|
152
src/gl/scene/gl_clipper.h
Normal file
152
src/gl/scene/gl_clipper.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
#ifndef __GL_CLIPPER
|
||||
#define __GL_CLIPPER
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "tables.h"
|
||||
#include "xs_Float.h"
|
||||
#include "r_utility.h"
|
||||
|
||||
class ClipNode
|
||||
{
|
||||
friend class Clipper;
|
||||
friend class ClipNodesFreer;
|
||||
|
||||
ClipNode *prev, *next;
|
||||
angle_t start, end;
|
||||
static ClipNode * freelist;
|
||||
|
||||
bool operator== (const ClipNode &other)
|
||||
{
|
||||
return other.start == start && other.end == end;
|
||||
}
|
||||
|
||||
void Free()
|
||||
{
|
||||
next=freelist;
|
||||
freelist=this;
|
||||
}
|
||||
|
||||
static ClipNode * GetNew()
|
||||
{
|
||||
if (freelist)
|
||||
{
|
||||
ClipNode * p=freelist;
|
||||
freelist=p->next;
|
||||
return p;
|
||||
}
|
||||
else return new ClipNode;
|
||||
}
|
||||
|
||||
static ClipNode * NewRange(angle_t start, angle_t end)
|
||||
{
|
||||
ClipNode * c=GetNew();
|
||||
|
||||
c->start=start;
|
||||
c->end=end;
|
||||
c->next=c->prev=NULL;
|
||||
return c;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class Clipper
|
||||
{
|
||||
ClipNode * clipnodes;
|
||||
ClipNode * cliphead;
|
||||
ClipNode * silhouette; // will be preserved even when RemoveClipRange is called
|
||||
|
||||
static angle_t AngleToPseudo(angle_t ang);
|
||||
bool IsRangeVisible(angle_t startangle, angle_t endangle);
|
||||
void RemoveRange(ClipNode * cn);
|
||||
void AddClipRange(angle_t startangle, angle_t endangle);
|
||||
void RemoveClipRange(angle_t startangle, angle_t endangle);
|
||||
void DoRemoveClipRange(angle_t start, angle_t end);
|
||||
|
||||
public:
|
||||
|
||||
static int anglecache;
|
||||
|
||||
Clipper()
|
||||
{
|
||||
clipnodes=cliphead=NULL;
|
||||
}
|
||||
|
||||
~Clipper();
|
||||
|
||||
void Clear();
|
||||
|
||||
|
||||
void SetSilhouette();
|
||||
|
||||
bool SafeCheckRange(angle_t startAngle, angle_t endAngle)
|
||||
{
|
||||
if(startAngle > endAngle)
|
||||
{
|
||||
return (IsRangeVisible(startAngle, ANGLE_MAX) || IsRangeVisible(0, endAngle));
|
||||
}
|
||||
|
||||
return IsRangeVisible(startAngle, endAngle);
|
||||
}
|
||||
|
||||
void SafeAddClipRange(angle_t startangle, angle_t endangle)
|
||||
{
|
||||
if(startangle > endangle)
|
||||
{
|
||||
// The range has to added in two parts.
|
||||
AddClipRange(startangle, ANGLE_MAX);
|
||||
AddClipRange(0, endangle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the range as usual.
|
||||
AddClipRange(startangle, endangle);
|
||||
}
|
||||
}
|
||||
|
||||
void SafeAddClipRangeRealAngles(angle_t startangle, angle_t endangle)
|
||||
{
|
||||
SafeAddClipRange(AngleToPseudo(startangle), AngleToPseudo(endangle));
|
||||
}
|
||||
|
||||
|
||||
void SafeRemoveClipRange(angle_t startangle, angle_t endangle)
|
||||
{
|
||||
if(startangle > endangle)
|
||||
{
|
||||
// The range has to added in two parts.
|
||||
RemoveClipRange(startangle, ANGLE_MAX);
|
||||
RemoveClipRange(0, endangle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the range as usual.
|
||||
RemoveClipRange(startangle, endangle);
|
||||
}
|
||||
}
|
||||
|
||||
void SafeRemoveClipRangeRealAngles(angle_t startangle, angle_t endangle)
|
||||
{
|
||||
SafeRemoveClipRange(AngleToPseudo(startangle), AngleToPseudo(endangle));
|
||||
}
|
||||
|
||||
bool CheckBox(const fixed_t *bspcoord);
|
||||
};
|
||||
|
||||
|
||||
extern Clipper clipper;
|
||||
|
||||
angle_t R_PointToPseudoAngle (fixed_t viewx, fixed_t viewy, fixed_t x, fixed_t y);
|
||||
|
||||
inline angle_t R_PointToAnglePrecise (fixed_t viewx, fixed_t viewy, fixed_t x, fixed_t y)
|
||||
{
|
||||
return xs_RoundToUInt(atan2(double(y-viewy), double(x-viewx)) * (ANGLE_180/M_PI));
|
||||
}
|
||||
|
||||
// Used to speed up angle calculations during clipping
|
||||
inline angle_t vertex_t::GetClipAngle()
|
||||
{
|
||||
return angletime == Clipper::anglecache? viewangle : (angletime = Clipper::anglecache, viewangle = R_PointToPseudoAngle(viewx, viewy, x,y));
|
||||
}
|
||||
|
||||
#endif
|
363
src/gl/scene/gl_decal.cpp
Normal file
363
src/gl/scene/gl_decal.cpp
Normal file
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
** gl_decal.cpp
|
||||
** OpenGL decal rendering code
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2003-2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "doomdata.h"
|
||||
#include "gl/system/gl_system.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "r_utility.h"
|
||||
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_texture.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
|
||||
struct DecalVertex
|
||||
{
|
||||
float x,y,z;
|
||||
float u,v;
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void GLWall::DrawDecal(DBaseDecal *decal)
|
||||
{
|
||||
line_t * line=seg->linedef;
|
||||
side_t * side=seg->sidedef;
|
||||
int i;
|
||||
fixed_t zpos;
|
||||
int light;
|
||||
int rel;
|
||||
float a;
|
||||
bool flipx, flipy;
|
||||
DecalVertex dv[4];
|
||||
FTextureID decalTile;
|
||||
|
||||
|
||||
if (decal->RenderFlags & RF_INVISIBLE) return;
|
||||
if (type==RENDERWALL_FFBLOCK && gltexture->isMasked()) return; // No decals on 3D floors with transparent textures.
|
||||
|
||||
//if (decal->sprite != 0xffff)
|
||||
{
|
||||
decalTile = decal->PicNum;
|
||||
flipx = !!(decal->RenderFlags & RF_XFLIP);
|
||||
flipy = !!(decal->RenderFlags & RF_YFLIP);
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
decalTile = SpriteFrames[sprites[decal->sprite].spriteframes + decal->frame].lump[0];
|
||||
flipx = SpriteFrames[sprites[decal->sprite].spriteframes + decal->frame].flip & 1;
|
||||
}
|
||||
*/
|
||||
|
||||
FTexture *texture = TexMan[decalTile];
|
||||
if (texture == NULL) return;
|
||||
|
||||
FMaterial *tex;
|
||||
|
||||
|
||||
tex = FMaterial::ValidateTexture(texture, true);
|
||||
|
||||
|
||||
// the sectors are only used for their texture origin coordinates
|
||||
// so we don't need the fake sectors for deep water etc.
|
||||
// As this is a completely split wall fragment no further splits are
|
||||
// necessary for the decal.
|
||||
sector_t *frontsector;
|
||||
|
||||
// for 3d-floor segments use the model sector as reference
|
||||
if ((decal->RenderFlags&RF_CLIPMASK)==RF_CLIPMID) frontsector=decal->Sector;
|
||||
else frontsector=seg->frontsector;
|
||||
|
||||
switch (decal->RenderFlags & RF_RELMASK)
|
||||
{
|
||||
default:
|
||||
// No valid decal can have this type. If one is encountered anyway
|
||||
// it is in some way invalid so skip it.
|
||||
return;
|
||||
//zpos = decal->z;
|
||||
//break;
|
||||
|
||||
case RF_RELUPPER:
|
||||
if (type!=RENDERWALL_TOP) return;
|
||||
if (line->flags & ML_DONTPEGTOP)
|
||||
{
|
||||
zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling);
|
||||
}
|
||||
else
|
||||
{
|
||||
zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::ceiling);
|
||||
}
|
||||
break;
|
||||
case RF_RELLOWER:
|
||||
if (type!=RENDERWALL_BOTTOM) return;
|
||||
if (line->flags & ML_DONTPEGBOTTOM)
|
||||
{
|
||||
zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling);
|
||||
}
|
||||
else
|
||||
{
|
||||
zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::floor);
|
||||
}
|
||||
break;
|
||||
case RF_RELMID:
|
||||
if (type==RENDERWALL_TOP || type==RENDERWALL_BOTTOM) return;
|
||||
if (line->flags & ML_DONTPEGBOTTOM)
|
||||
{
|
||||
zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::floor);
|
||||
}
|
||||
else
|
||||
{
|
||||
zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling);
|
||||
}
|
||||
}
|
||||
|
||||
if (decal->RenderFlags & RF_FULLBRIGHT)
|
||||
{
|
||||
light = 255;
|
||||
rel = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
light = lightlevel;
|
||||
rel = rellight + getExtraLight();
|
||||
}
|
||||
|
||||
FColormap p = Colormap;
|
||||
|
||||
if (glset.nocoloredspritelighting)
|
||||
{
|
||||
p.Decolorize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
a = FIXED2FLOAT(decal->Alpha);
|
||||
|
||||
// now clip the decal to the actual polygon
|
||||
float decalwidth = tex->TextureWidth() * FIXED2FLOAT(decal->ScaleX);
|
||||
float decalheight= tex->TextureHeight() * FIXED2FLOAT(decal->ScaleY);
|
||||
float decallefto = tex->GetLeftOffset() * FIXED2FLOAT(decal->ScaleX);
|
||||
float decaltopo = tex->GetTopOffset() * FIXED2FLOAT(decal->ScaleY);
|
||||
|
||||
|
||||
float leftedge = glseg.fracleft * side->TexelLength;
|
||||
float linelength = glseg.fracright * side->TexelLength - leftedge;
|
||||
|
||||
// texel index of the decal's left edge
|
||||
float decalpixpos = (float)side->TexelLength * decal->LeftDistance / (1<<30) - (flipx? decalwidth-decallefto : decallefto) - leftedge;
|
||||
|
||||
float left,right;
|
||||
float lefttex,righttex;
|
||||
|
||||
// decal is off the left edge
|
||||
if (decalpixpos < 0)
|
||||
{
|
||||
left = 0;
|
||||
lefttex = -decalpixpos;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = decalpixpos;
|
||||
lefttex = 0;
|
||||
}
|
||||
|
||||
// decal is off the right edge
|
||||
if (decalpixpos + decalwidth > linelength)
|
||||
{
|
||||
right = linelength;
|
||||
righttex = right - decalpixpos;
|
||||
}
|
||||
else
|
||||
{
|
||||
right = decalpixpos + decalwidth;
|
||||
righttex = decalwidth;
|
||||
}
|
||||
if (right<=left) return; // nothing to draw
|
||||
|
||||
// one texture unit on the wall as vector
|
||||
float vx=(glseg.x2-glseg.x1)/linelength;
|
||||
float vy=(glseg.y2-glseg.y1)/linelength;
|
||||
|
||||
dv[1].x=dv[0].x=glseg.x1+vx*left;
|
||||
dv[1].y=dv[0].y=glseg.y1+vy*left;
|
||||
|
||||
dv[3].x=dv[2].x=glseg.x1+vx*right;
|
||||
dv[3].y=dv[2].y=glseg.y1+vy*right;
|
||||
|
||||
zpos+= FRACUNIT*(flipy? decalheight-decaltopo : decaltopo);
|
||||
|
||||
dv[1].z=dv[2].z = FIXED2FLOAT(zpos);
|
||||
dv[0].z=dv[3].z = dv[1].z - decalheight;
|
||||
dv[1].v=dv[2].v = tex->GetVT();
|
||||
|
||||
dv[1].u=dv[0].u = tex->GetU(lefttex / FIXED2FLOAT(decal->ScaleX));
|
||||
dv[3].u=dv[2].u = tex->GetU(righttex / FIXED2FLOAT(decal->ScaleX));
|
||||
dv[0].v=dv[3].v = tex->GetVB();
|
||||
|
||||
|
||||
// now clip to the top plane
|
||||
float vzt=(ztop[1]-ztop[0])/linelength;
|
||||
float topleft=this->ztop[0]+vzt*left;
|
||||
float topright=this->ztop[0]+vzt*right;
|
||||
|
||||
// completely below the wall
|
||||
if (topleft<dv[0].z && topright<dv[3].z)
|
||||
return;
|
||||
|
||||
if (topleft<dv[1].z || topright<dv[2].z)
|
||||
{
|
||||
// decal has to be clipped at the top
|
||||
// let texture clamping handle all extreme cases
|
||||
dv[1].v=(dv[1].z-topleft)/(dv[1].z-dv[0].z)*dv[0].v;
|
||||
dv[2].v=(dv[2].z-topright)/(dv[2].z-dv[3].z)*dv[3].v;
|
||||
dv[1].z=topleft;
|
||||
dv[2].z=topright;
|
||||
}
|
||||
|
||||
// now clip to the bottom plane
|
||||
float vzb=(zbottom[1]-zbottom[0])/linelength;
|
||||
float bottomleft=this->zbottom[0]+vzb*left;
|
||||
float bottomright=this->zbottom[0]+vzb*right;
|
||||
|
||||
// completely above the wall
|
||||
if (bottomleft>dv[1].z && bottomright>dv[2].z)
|
||||
return;
|
||||
|
||||
if (bottomleft>dv[0].z || bottomright>dv[3].z)
|
||||
{
|
||||
// decal has to be clipped at the bottom
|
||||
// let texture clamping handle all extreme cases
|
||||
dv[0].v=(dv[1].z-bottomleft)/(dv[1].z-dv[0].z)*(dv[0].v-dv[1].v) + dv[1].v;
|
||||
dv[3].v=(dv[2].z-bottomright)/(dv[2].z-dv[3].z)*(dv[3].v-dv[2].v) + dv[2].v;
|
||||
dv[0].z=bottomleft;
|
||||
dv[3].z=bottomright;
|
||||
}
|
||||
|
||||
|
||||
if (flipx)
|
||||
{
|
||||
float ur = tex->GetUR();
|
||||
for(i=0;i<4;i++) dv[i].u=ur-dv[i].u;
|
||||
}
|
||||
if (flipy)
|
||||
{
|
||||
float vb = tex->GetVB();
|
||||
for(i=0;i<4;i++) dv[i].v=vb-dv[i].v;
|
||||
}
|
||||
|
||||
// calculate dynamic light effect.
|
||||
if (gl_lights && GLRenderer->mLightCount && !gl_fixedcolormap && gl_light_sprites)
|
||||
{
|
||||
// Note: This should be replaced with proper shader based lighting.
|
||||
fixed_t x, y;
|
||||
decal->GetXY(seg->sidedef, x, y);
|
||||
gl_SetDynSpriteLight(NULL, x, y, zpos, sub);
|
||||
}
|
||||
|
||||
// alpha color only has an effect when using an alpha texture.
|
||||
if (decal->RenderStyle.Flags & STYLEF_RedIsAlpha)
|
||||
{
|
||||
gl_RenderState.SetObjectColor(decal->AlphaColor|0xff000000);
|
||||
}
|
||||
|
||||
gl_SetColor(light, rel, p, a);
|
||||
|
||||
// for additively drawn decals we must temporarily set the fog color to black.
|
||||
PalEntry fc = gl_RenderState.GetFogColor();
|
||||
if (decal->RenderStyle.BlendOp == STYLEOP_Add && decal->RenderStyle.DestAlpha == STYLEALPHA_One)
|
||||
{
|
||||
gl_RenderState.SetFog(0,-1);
|
||||
}
|
||||
|
||||
|
||||
gl_SetRenderStyle(decal->RenderStyle, false, false);
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_XY, decal->Translation, 0, !!(decal->RenderStyle.Flags & STYLEF_RedIsAlpha));
|
||||
|
||||
|
||||
// If srcalpha is one it looks better with a higher alpha threshold
|
||||
if (decal->RenderStyle.SrcAlpha == STYLEALPHA_One) gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold);
|
||||
else gl_RenderState.AlphaFunc(GL_GREATER, 0.f);
|
||||
|
||||
gl_RenderState.Apply();
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
ptr->Set(dv[i].x, dv[i].z, dv[i].y, dv[i].u, dv[i].v);
|
||||
ptr++;
|
||||
}
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN);
|
||||
|
||||
rendered_decals++;
|
||||
gl_RenderState.SetTextureMode(TM_MODULATE);
|
||||
gl_RenderState.SetObjectColor(0xffffffff);
|
||||
gl_RenderState.SetFog(fc,-1);
|
||||
gl_RenderState.SetDynLight(0,0,0);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void GLWall::DoDrawDecals()
|
||||
{
|
||||
if (seg->sidedef && seg->sidedef->AttachedDecals)
|
||||
{
|
||||
gl_SetFog(lightlevel, rellight + getExtraLight(), &Colormap, false);
|
||||
DBaseDecal *decal = seg->sidedef->AttachedDecals;
|
||||
while (decal)
|
||||
{
|
||||
DrawDecal(decal);
|
||||
decal = decal->WallNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1254
src/gl/scene/gl_drawinfo.cpp
Normal file
1254
src/gl/scene/gl_drawinfo.cpp
Normal file
File diff suppressed because it is too large
Load diff
271
src/gl/scene/gl_drawinfo.h
Normal file
271
src/gl/scene/gl_drawinfo.h
Normal file
|
@ -0,0 +1,271 @@
|
|||
#ifndef __GL_DRAWINFO_H
|
||||
#define __GL_DRAWINFO_H
|
||||
|
||||
#include "gl/scene/gl_wall.h"
|
||||
|
||||
enum GLDrawItemType
|
||||
{
|
||||
GLDIT_WALL,
|
||||
GLDIT_FLAT,
|
||||
GLDIT_SPRITE,
|
||||
};
|
||||
|
||||
enum DrawListType
|
||||
{
|
||||
GLDL_PLAINWALLS,
|
||||
GLDL_PLAINFLATS,
|
||||
GLDL_MASKEDWALLS,
|
||||
GLDL_MASKEDFLATS,
|
||||
GLDL_MASKEDWALLSOFS,
|
||||
GLDL_MODELS,
|
||||
|
||||
GLDL_TRANSLUCENT,
|
||||
GLDL_TRANSLUCENTBORDER,
|
||||
|
||||
GLDL_TYPES,
|
||||
};
|
||||
|
||||
enum Drawpasses
|
||||
{
|
||||
GLPASS_ALL, // Main pass with dynamic lights
|
||||
GLPASS_LIGHTSONLY, // only collect dynamic lights
|
||||
GLPASS_PLAIN, // Main pass without dynamic lights
|
||||
GLPASS_DECALS, // Draws a decal
|
||||
GLPASS_TRANSLUCENT, // Draws translucent objects
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Intermediate struct to link one draw item into a draw list
|
||||
//
|
||||
// unfortunately this struct must not contain pointers because
|
||||
// the arrays may be reallocated!
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct GLDrawItem
|
||||
{
|
||||
GLDrawItemType rendertype;
|
||||
int index;
|
||||
|
||||
GLDrawItem(GLDrawItemType _rendertype,int _index) : rendertype(_rendertype),index(_index) {}
|
||||
};
|
||||
|
||||
struct SortNode
|
||||
{
|
||||
int itemindex;
|
||||
SortNode * parent;
|
||||
SortNode * next; // unsorted successor
|
||||
SortNode * left; // left side of this node
|
||||
SortNode * equal; // equal to this node
|
||||
SortNode * right; // right side of this node
|
||||
|
||||
|
||||
void UnlinkFromChain();
|
||||
void Link(SortNode * hook);
|
||||
void AddToEqual(SortNode * newnode);
|
||||
void AddToLeft (SortNode * newnode);
|
||||
void AddToRight(SortNode * newnode);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// One draw list. This contains all info for one type of rendering data
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct GLDrawList
|
||||
{
|
||||
//private:
|
||||
TArray<GLWall> walls;
|
||||
TArray<GLFlat> flats;
|
||||
TArray<GLSprite> sprites;
|
||||
TArray<GLDrawItem> drawitems;
|
||||
int SortNodeStart;
|
||||
SortNode * sorted;
|
||||
|
||||
public:
|
||||
GLDrawList()
|
||||
{
|
||||
next=NULL;
|
||||
SortNodeStart=-1;
|
||||
sorted=NULL;
|
||||
}
|
||||
|
||||
~GLDrawList()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
unsigned int Size()
|
||||
{
|
||||
return drawitems.Size();
|
||||
}
|
||||
|
||||
void AddWall(GLWall * wall);
|
||||
void AddFlat(GLFlat * flat);
|
||||
void AddSprite(GLSprite * sprite);
|
||||
void Reset();
|
||||
void SortWalls();
|
||||
void SortFlats();
|
||||
|
||||
|
||||
void MakeSortList();
|
||||
SortNode * FindSortPlane(SortNode * head);
|
||||
SortNode * FindSortWall(SortNode * head);
|
||||
void SortPlaneIntoPlane(SortNode * head,SortNode * sort);
|
||||
void SortWallIntoPlane(SortNode * head,SortNode * sort);
|
||||
void SortSpriteIntoPlane(SortNode * head,SortNode * sort);
|
||||
void SortWallIntoWall(SortNode * head,SortNode * sort);
|
||||
void SortSpriteIntoWall(SortNode * head,SortNode * sort);
|
||||
int CompareSprites(SortNode * a,SortNode * b);
|
||||
SortNode * SortSpriteList(SortNode * head);
|
||||
SortNode * DoSort(SortNode * head);
|
||||
|
||||
void DoDraw(int pass, int index, bool trans);
|
||||
void DoDrawSorted(SortNode * node);
|
||||
void DrawSorted();
|
||||
void Draw(int pass, bool trans = false);
|
||||
void DrawWalls(int pass);
|
||||
void DrawFlats(int pass);
|
||||
void DrawDecals();
|
||||
|
||||
GLDrawList * next;
|
||||
} ;
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// these are used to link faked planes due to missing textures to a sector
|
||||
//
|
||||
//==========================================================================
|
||||
struct gl_subsectorrendernode
|
||||
{
|
||||
gl_subsectorrendernode * next;
|
||||
subsector_t * sub;
|
||||
};
|
||||
|
||||
|
||||
struct FDrawInfo
|
||||
{
|
||||
struct wallseg
|
||||
{
|
||||
float x1, y1, z1, x2, y2, z2;
|
||||
};
|
||||
|
||||
bool temporary;
|
||||
|
||||
|
||||
|
||||
struct MissingTextureInfo
|
||||
{
|
||||
seg_t * seg;
|
||||
subsector_t * sub;
|
||||
fixed_t planez;
|
||||
fixed_t planezfront;
|
||||
};
|
||||
|
||||
struct MissingSegInfo
|
||||
{
|
||||
seg_t * seg;
|
||||
int MTI_Index; // tells us which MissingTextureInfo represents this seg.
|
||||
};
|
||||
|
||||
struct SubsectorHackInfo
|
||||
{
|
||||
subsector_t * sub;
|
||||
BYTE flags;
|
||||
};
|
||||
|
||||
TArray<BYTE> sectorrenderflags;
|
||||
TArray<BYTE> ss_renderflags;
|
||||
TArray<BYTE> no_renderflags;
|
||||
|
||||
TArray<MissingTextureInfo> MissingUpperTextures;
|
||||
TArray<MissingTextureInfo> MissingLowerTextures;
|
||||
|
||||
TArray<MissingSegInfo> MissingUpperSegs;
|
||||
TArray<MissingSegInfo> MissingLowerSegs;
|
||||
|
||||
TArray<SubsectorHackInfo> SubsectorHacks;
|
||||
|
||||
TArray<gl_subsectorrendernode*> otherfloorplanes;
|
||||
TArray<gl_subsectorrendernode*> otherceilingplanes;
|
||||
|
||||
TArray<sector_t *> CeilingStacks;
|
||||
TArray<sector_t *> FloorStacks;
|
||||
|
||||
TArray<subsector_t *> HandledSubsectors;
|
||||
|
||||
FDrawInfo * next;
|
||||
GLDrawList drawlists[GLDL_TYPES];
|
||||
|
||||
FDrawInfo();
|
||||
~FDrawInfo();
|
||||
void ClearBuffers();
|
||||
|
||||
bool DoOneSectorUpper(subsector_t * subsec, fixed_t planez);
|
||||
bool DoOneSectorLower(subsector_t * subsec, fixed_t planez);
|
||||
bool DoFakeBridge(subsector_t * subsec, fixed_t planez);
|
||||
bool DoFakeCeilingBridge(subsector_t * subsec, fixed_t planez);
|
||||
|
||||
bool CheckAnchorFloor(subsector_t * sub);
|
||||
bool CollectSubsectorsFloor(subsector_t * sub, sector_t * anchor);
|
||||
bool CheckAnchorCeiling(subsector_t * sub);
|
||||
bool CollectSubsectorsCeiling(subsector_t * sub, sector_t * anchor);
|
||||
void CollectSectorStacksCeiling(subsector_t * sub, sector_t * anchor);
|
||||
void CollectSectorStacksFloor(subsector_t * sub, sector_t * anchor);
|
||||
|
||||
void AddUpperMissingTexture(side_t * side, subsector_t *sub, fixed_t backheight);
|
||||
void AddLowerMissingTexture(side_t * side, subsector_t *sub, fixed_t backheight);
|
||||
void HandleMissingTextures();
|
||||
void DrawUnhandledMissingTextures();
|
||||
void AddHackedSubsector(subsector_t * sub);
|
||||
void HandleHackedSubsectors();
|
||||
void AddFloorStack(sector_t * sec);
|
||||
void AddCeilingStack(sector_t * sec);
|
||||
void ProcessSectorStacks();
|
||||
|
||||
void AddOtherFloorPlane(int sector, gl_subsectorrendernode * node);
|
||||
void AddOtherCeilingPlane(int sector, gl_subsectorrendernode * node);
|
||||
|
||||
void StartScene();
|
||||
void SetupFloodStencil(wallseg * ws);
|
||||
void ClearFloodStencil(wallseg * ws);
|
||||
void DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling);
|
||||
void FloodUpperGap(seg_t * seg);
|
||||
void FloodLowerGap(seg_t * seg);
|
||||
|
||||
static void StartDrawInfo();
|
||||
static void EndDrawInfo();
|
||||
|
||||
gl_subsectorrendernode * GetOtherFloorPlanes(unsigned int sector)
|
||||
{
|
||||
if (sector<otherfloorplanes.Size()) return otherfloorplanes[sector];
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
gl_subsectorrendernode * GetOtherCeilingPlanes(unsigned int sector)
|
||||
{
|
||||
if (sector<otherceilingplanes.Size()) return otherceilingplanes[sector];
|
||||
else return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
class FDrawInfoList
|
||||
{
|
||||
TDeletingArray<FDrawInfo *> mList;
|
||||
|
||||
public:
|
||||
|
||||
FDrawInfo *GetNew();
|
||||
void Release(FDrawInfo *);
|
||||
};
|
||||
|
||||
|
||||
extern FDrawInfo * gl_drawinfo;
|
||||
|
||||
void gl_SetPlaneTextureRotation(const GLSectorPlane * secplane, FMaterial * gltexture);
|
||||
void gl_SetRenderStyle(FRenderStyle style, bool drawopaque, bool allowcolorblending);
|
||||
|
||||
#endif
|
400
src/gl/scene/gl_fakeflat.cpp
Normal file
400
src/gl/scene/gl_fakeflat.cpp
Normal file
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
** gl_fakeflat.cpp
|
||||
** Fake flat functions to render stacked sectors
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2001-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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "p_lnspec.h"
|
||||
#include "p_local.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "r_sky.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/scene/gl_clipper.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Check whether the player can look beyond this line
|
||||
//
|
||||
//==========================================================================
|
||||
CVAR(Bool, gltest_slopeopt, false, 0)
|
||||
|
||||
bool gl_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsector)
|
||||
{
|
||||
line_t *linedef = sidedef->linedef;
|
||||
fixed_t bs_floorheight1;
|
||||
fixed_t bs_floorheight2;
|
||||
fixed_t bs_ceilingheight1;
|
||||
fixed_t bs_ceilingheight2;
|
||||
fixed_t fs_floorheight1;
|
||||
fixed_t fs_floorheight2;
|
||||
fixed_t fs_ceilingheight1;
|
||||
fixed_t fs_ceilingheight2;
|
||||
|
||||
// Mirrors and horizons always block the view
|
||||
//if (linedef->special==Line_Mirror || linedef->special==Line_Horizon) return true;
|
||||
|
||||
// Lines with stacked sectors must never block!
|
||||
|
||||
if (backsector->portals[sector_t::ceiling] != NULL || backsector->portals[sector_t::floor] != NULL ||
|
||||
frontsector->portals[sector_t::ceiling] != NULL || frontsector->portals[sector_t::floor] != NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// on large levels this distinction can save some time
|
||||
// That's a lot of avoided multiplications if there's a lot to see!
|
||||
|
||||
if (frontsector->ceilingplane.a | frontsector->ceilingplane.b)
|
||||
{
|
||||
fs_ceilingheight1=frontsector->ceilingplane.ZatPoint(linedef->v1);
|
||||
fs_ceilingheight2=frontsector->ceilingplane.ZatPoint(linedef->v2);
|
||||
}
|
||||
else
|
||||
{
|
||||
fs_ceilingheight2=fs_ceilingheight1=frontsector->ceilingplane.d;
|
||||
}
|
||||
|
||||
if (frontsector->floorplane.a | frontsector->floorplane.b)
|
||||
{
|
||||
fs_floorheight1=frontsector->floorplane.ZatPoint(linedef->v1);
|
||||
fs_floorheight2=frontsector->floorplane.ZatPoint(linedef->v2);
|
||||
}
|
||||
else
|
||||
{
|
||||
fs_floorheight2=fs_floorheight1=-frontsector->floorplane.d;
|
||||
}
|
||||
|
||||
if (backsector->ceilingplane.a | backsector->ceilingplane.b)
|
||||
{
|
||||
bs_ceilingheight1=backsector->ceilingplane.ZatPoint(linedef->v1);
|
||||
bs_ceilingheight2=backsector->ceilingplane.ZatPoint(linedef->v2);
|
||||
}
|
||||
else
|
||||
{
|
||||
bs_ceilingheight2=bs_ceilingheight1=backsector->ceilingplane.d;
|
||||
}
|
||||
|
||||
if (backsector->floorplane.a | backsector->floorplane.b)
|
||||
{
|
||||
bs_floorheight1=backsector->floorplane.ZatPoint(linedef->v1);
|
||||
bs_floorheight2=backsector->floorplane.ZatPoint(linedef->v2);
|
||||
}
|
||||
else
|
||||
{
|
||||
bs_floorheight2=bs_floorheight1=-backsector->floorplane.d;
|
||||
}
|
||||
|
||||
// now check for closed sectors!
|
||||
if (bs_ceilingheight1<=fs_floorheight1 && bs_ceilingheight2<=fs_floorheight2)
|
||||
{
|
||||
FTexture * tex = TexMan(sidedef->GetTexture(side_t::top));
|
||||
if (!tex || tex->UseType==FTexture::TEX_Null) return false;
|
||||
if (backsector->GetTexture(sector_t::ceiling)==skyflatnum &&
|
||||
frontsector->GetTexture(sector_t::ceiling)==skyflatnum) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fs_ceilingheight1<=bs_floorheight1 && fs_ceilingheight2<=bs_floorheight2)
|
||||
{
|
||||
FTexture * tex = TexMan(sidedef->GetTexture(side_t::bottom));
|
||||
if (!tex || tex->UseType==FTexture::TEX_Null) return false;
|
||||
|
||||
// properly render skies (consider door "open" if both floors are sky):
|
||||
if (backsector->GetTexture(sector_t::ceiling)==skyflatnum &&
|
||||
frontsector->GetTexture(sector_t::ceiling)==skyflatnum) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bs_ceilingheight1<=bs_floorheight1 && bs_ceilingheight2<=bs_floorheight2)
|
||||
{
|
||||
// preserve a kind of transparent door/lift special effect:
|
||||
if (bs_ceilingheight1 < fs_ceilingheight1 || bs_ceilingheight2 < fs_ceilingheight2)
|
||||
{
|
||||
FTexture * tex = TexMan(sidedef->GetTexture(side_t::top));
|
||||
if (!tex || tex->UseType==FTexture::TEX_Null) return false;
|
||||
}
|
||||
if (bs_floorheight1 > fs_floorheight1 || bs_floorheight2 > fs_floorheight2)
|
||||
{
|
||||
FTexture * tex = TexMan(sidedef->GetTexture(side_t::bottom));
|
||||
if (!tex || tex->UseType==FTexture::TEX_Null) return false;
|
||||
}
|
||||
if (backsector->GetTexture(sector_t::ceiling)==skyflatnum &&
|
||||
frontsector->GetTexture(sector_t::ceiling)==skyflatnum) return false;
|
||||
if (backsector->GetTexture(sector_t::floor)==skyflatnum && frontsector->GetTexture(sector_t::floor)
|
||||
==skyflatnum) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// check for levels with exposed lower areas
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_CheckViewArea(vertex_t *v1, vertex_t *v2, sector_t *frontsector, sector_t *backsector)
|
||||
{
|
||||
if (in_area==area_default &&
|
||||
(backsector->heightsec && !(backsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC)) &&
|
||||
(!frontsector->heightsec || frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC))
|
||||
{
|
||||
sector_t * s = backsector->heightsec;
|
||||
|
||||
fixed_t cz1 = frontsector->ceilingplane.ZatPoint(v1);
|
||||
fixed_t cz2 = frontsector->ceilingplane.ZatPoint(v2);
|
||||
fixed_t fz1 = s->floorplane.ZatPoint(v1);
|
||||
fixed_t fz2 = s->floorplane.ZatPoint(v2);
|
||||
|
||||
// allow some tolerance in case slopes are involved
|
||||
if (cz1 <= fz1 + FRACUNIT/100 && cz2<=fz2 + FRACUNIT/100)
|
||||
in_area=area_below;
|
||||
else
|
||||
in_area=area_normal;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This is mostly like R_FakeFlat but with a few alterations necessitated
|
||||
// by hardware rendering
|
||||
//
|
||||
//==========================================================================
|
||||
sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back)
|
||||
{
|
||||
if (!sec->heightsec || sec->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC || sec->heightsec==sec)
|
||||
{
|
||||
// check for backsectors with the ceiling lower than the floor. These will create
|
||||
// visual glitches because upper amd lower textures overlap.
|
||||
if (back && sec->planes[sector_t::floor].TexZ > sec->planes[sector_t::ceiling].TexZ)
|
||||
{
|
||||
if (!(sec->floorplane.a | sec->floorplane.b | sec->ceilingplane.a | sec->ceilingplane.b))
|
||||
{
|
||||
*dest = *sec;
|
||||
dest->ceilingplane=sec->floorplane;
|
||||
dest->ceilingplane.FlipVert();
|
||||
dest->planes[sector_t::ceiling].TexZ = dest->planes[sector_t::floor].TexZ;
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
return sec;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (sec-sectors==560)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (in_area==area_above)
|
||||
{
|
||||
if (sec->heightsec->MoreFlags&SECF_FAKEFLOORONLY /*|| sec->GetTexture(sector_t::ceiling)==skyflatnum*/) in_area=area_normal;
|
||||
}
|
||||
|
||||
int diffTex = (sec->heightsec->MoreFlags & SECF_CLIPFAKEPLANES);
|
||||
sector_t * s = sec->heightsec;
|
||||
|
||||
#if 0
|
||||
*dest=*sec; // This will invoke the copy operator which isn't really needed here. Memcpy is faster.
|
||||
#else
|
||||
memcpy(dest, sec, sizeof(sector_t));
|
||||
#endif
|
||||
|
||||
// Replace floor and ceiling height with control sector's heights.
|
||||
if (diffTex)
|
||||
{
|
||||
if (s->floorplane.CopyPlaneIfValid (&dest->floorplane, &sec->ceilingplane))
|
||||
{
|
||||
dest->SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
|
||||
dest->SetPlaneTexZ(sector_t::floor, s->GetPlaneTexZ(sector_t::floor));
|
||||
dest->vboindex[sector_t::floor] = sec->vboindex[sector_t::vbo_fakefloor];
|
||||
dest->vboheight[sector_t::floor] = s->vboheight[sector_t::floor];
|
||||
}
|
||||
else if (s->MoreFlags & SECF_FAKEFLOORONLY)
|
||||
{
|
||||
if (in_area==area_below)
|
||||
{
|
||||
dest->ColorMap=s->ColorMap;
|
||||
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
|
||||
{
|
||||
dest->lightlevel = s->lightlevel;
|
||||
dest->SetPlaneLight(sector_t::floor, s->GetPlaneLight(sector_t::floor));
|
||||
dest->SetPlaneLight(sector_t::ceiling, s->GetPlaneLight(sector_t::ceiling));
|
||||
dest->ChangeFlags(sector_t::floor, -1, s->GetFlags(sector_t::floor));
|
||||
dest->ChangeFlags(sector_t::ceiling, -1, s->GetFlags(sector_t::ceiling));
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
return sec;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dest->SetPlaneTexZ(sector_t::floor, s->GetPlaneTexZ(sector_t::floor));
|
||||
dest->floorplane = s->floorplane;
|
||||
|
||||
dest->vboindex[sector_t::floor] = sec->vboindex[sector_t::vbo_fakefloor];
|
||||
dest->vboheight[sector_t::floor] = s->vboheight[sector_t::floor];
|
||||
}
|
||||
|
||||
if (!(s->MoreFlags&SECF_FAKEFLOORONLY))
|
||||
{
|
||||
if (diffTex)
|
||||
{
|
||||
if (s->ceilingplane.CopyPlaneIfValid (&dest->ceilingplane, &sec->floorplane))
|
||||
{
|
||||
dest->SetTexture(sector_t::ceiling, s->GetTexture(sector_t::ceiling), false);
|
||||
dest->SetPlaneTexZ(sector_t::ceiling, s->GetPlaneTexZ(sector_t::ceiling));
|
||||
dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::vbo_fakeceiling];
|
||||
dest->vboheight[sector_t::ceiling] = s->vboheight[sector_t::ceiling];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dest->ceilingplane = s->ceilingplane;
|
||||
dest->SetPlaneTexZ(sector_t::ceiling, s->GetPlaneTexZ(sector_t::ceiling));
|
||||
dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::vbo_fakeceiling];
|
||||
dest->vboheight[sector_t::ceiling] = s->vboheight[sector_t::ceiling];
|
||||
}
|
||||
}
|
||||
|
||||
if (in_area==area_below)
|
||||
{
|
||||
dest->ColorMap=s->ColorMap;
|
||||
dest->SetPlaneTexZ(sector_t::floor, sec->GetPlaneTexZ(sector_t::floor));
|
||||
dest->SetPlaneTexZ(sector_t::ceiling, s->GetPlaneTexZ(sector_t::floor));
|
||||
dest->floorplane=sec->floorplane;
|
||||
dest->ceilingplane=s->floorplane;
|
||||
dest->ceilingplane.FlipVert();
|
||||
|
||||
dest->vboindex[sector_t::floor] = sec->vboindex[sector_t::floor];
|
||||
dest->vboheight[sector_t::floor] = sec->vboheight[sector_t::floor];
|
||||
|
||||
dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::vbo_fakefloor];
|
||||
dest->vboheight[sector_t::ceiling] = s->vboheight[sector_t::floor];
|
||||
|
||||
dest->portals[sector_t::ceiling] = NULL;
|
||||
|
||||
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
|
||||
{
|
||||
dest->lightlevel = s->lightlevel;
|
||||
}
|
||||
|
||||
if (!back)
|
||||
{
|
||||
dest->SetTexture(sector_t::floor, diffTex ? sec->GetTexture(sector_t::floor) : s->GetTexture(sector_t::floor), false);
|
||||
dest->planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
|
||||
|
||||
//dest->ceilingplane = s->floorplane;
|
||||
|
||||
if (s->GetTexture(sector_t::ceiling) == skyflatnum)
|
||||
{
|
||||
dest->SetTexture(sector_t::ceiling, dest->GetTexture(sector_t::floor), false);
|
||||
//dest->floorplane = dest->ceilingplane;
|
||||
//dest->floorplane.FlipVert ();
|
||||
//dest->floorplane.ChangeHeight (+1);
|
||||
dest->planes[sector_t::ceiling].xform = dest->planes[sector_t::floor].xform;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
dest->SetTexture(sector_t::ceiling, diffTex ? s->GetTexture(sector_t::floor) : s->GetTexture(sector_t::ceiling), false);
|
||||
dest->planes[sector_t::ceiling].xform = s->planes[sector_t::ceiling].xform;
|
||||
}
|
||||
|
||||
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
|
||||
{
|
||||
dest->SetPlaneLight(sector_t::floor, s->GetPlaneLight(sector_t::floor));
|
||||
dest->SetPlaneLight(sector_t::ceiling, s->GetPlaneLight(sector_t::ceiling));
|
||||
dest->ChangeFlags(sector_t::floor, -1, s->GetFlags(sector_t::floor));
|
||||
dest->ChangeFlags(sector_t::ceiling, -1, s->GetFlags(sector_t::ceiling));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (in_area == area_above)
|
||||
{
|
||||
dest->ColorMap = s->ColorMap;
|
||||
dest->SetPlaneTexZ(sector_t::ceiling, sec->GetPlaneTexZ(sector_t::ceiling));
|
||||
dest->SetPlaneTexZ(sector_t::floor, s->GetPlaneTexZ(sector_t::ceiling));
|
||||
dest->ceilingplane = sec->ceilingplane;
|
||||
dest->floorplane = s->ceilingplane;
|
||||
dest->floorplane.FlipVert();
|
||||
|
||||
dest->vboindex[sector_t::floor] = sec->vboindex[sector_t::vbo_fakeceiling];
|
||||
dest->vboheight[sector_t::floor] = s->vboheight[sector_t::ceiling];
|
||||
|
||||
dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::ceiling];
|
||||
dest->vboheight[sector_t::ceiling] = sec->vboheight[sector_t::ceiling];
|
||||
|
||||
dest->portals[sector_t::floor] = NULL;
|
||||
|
||||
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
|
||||
{
|
||||
dest->lightlevel = s->lightlevel;
|
||||
}
|
||||
|
||||
if (!back)
|
||||
{
|
||||
dest->SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false);
|
||||
dest->SetTexture(sector_t::floor, s->GetTexture(sector_t::ceiling), false);
|
||||
dest->planes[sector_t::ceiling].xform = dest->planes[sector_t::floor].xform = s->planes[sector_t::ceiling].xform;
|
||||
|
||||
if (s->GetTexture(sector_t::floor) != skyflatnum)
|
||||
{
|
||||
dest->SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
|
||||
dest->planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
|
||||
}
|
||||
|
||||
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
|
||||
{
|
||||
dest->lightlevel = s->lightlevel;
|
||||
dest->SetPlaneLight(sector_t::floor, s->GetPlaneLight(sector_t::floor));
|
||||
dest->SetPlaneLight(sector_t::ceiling, s->GetPlaneLight(sector_t::ceiling));
|
||||
dest->ChangeFlags(sector_t::floor, -1, s->GetFlags(sector_t::floor));
|
||||
dest->ChangeFlags(sector_t::ceiling, -1, s->GetFlags(sector_t::ceiling));
|
||||
}
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
725
src/gl/scene/gl_flats.cpp
Normal file
725
src/gl/scene/gl_flats.cpp
Normal file
|
@ -0,0 +1,725 @@
|
|||
/*
|
||||
** gl_flat.cpp
|
||||
** Flat rendering
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2000-2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "r_defs.h"
|
||||
#include "r_sky.h"
|
||||
#include "r_utility.h"
|
||||
#include "g_level.h"
|
||||
#include "doomstat.h"
|
||||
#include "d_player.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/dynlights/gl_dynlight.h"
|
||||
#include "gl/dynlights/gl_glow.h"
|
||||
#include "gl/dynlights/gl_lightbuffer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/utility/gl_convert.h"
|
||||
#include "gl/utility/gl_templates.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
CVAR(Int, gl_breaksec, -1, 0)
|
||||
#endif
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets the texture matrix according to the plane's texture positioning
|
||||
// information
|
||||
//
|
||||
//==========================================================================
|
||||
static float tics;
|
||||
void gl_SetPlaneTextureRotation(const GLSectorPlane * secplane, FMaterial * gltexture)
|
||||
{
|
||||
// only manipulate the texture matrix if needed.
|
||||
if (secplane->xoffs != 0 || secplane->yoffs != 0 ||
|
||||
secplane->xscale != FRACUNIT || secplane->yscale != FRACUNIT ||
|
||||
secplane->angle != 0 ||
|
||||
gltexture->TextureWidth() != 64 ||
|
||||
gltexture->TextureHeight() != 64)
|
||||
{
|
||||
float uoffs = FIXED2FLOAT(secplane->xoffs) / gltexture->TextureWidth();
|
||||
float voffs = FIXED2FLOAT(secplane->yoffs) / gltexture->TextureHeight();
|
||||
|
||||
float xscale1=FIXED2FLOAT(secplane->xscale);
|
||||
float yscale1=FIXED2FLOAT(secplane->yscale);
|
||||
if (gltexture->tex->bHasCanvas)
|
||||
{
|
||||
yscale1 = 0 - yscale1;
|
||||
}
|
||||
float angle=-ANGLE_TO_FLOAT(secplane->angle);
|
||||
|
||||
float xscale2=64.f/gltexture->TextureWidth();
|
||||
float yscale2=64.f/gltexture->TextureHeight();
|
||||
|
||||
gl_RenderState.mTextureMatrix.loadIdentity();
|
||||
gl_RenderState.mTextureMatrix.scale(xscale1 ,yscale1,1.0f);
|
||||
gl_RenderState.mTextureMatrix.translate(uoffs,voffs,0.0f);
|
||||
gl_RenderState.mTextureMatrix.scale(xscale2 ,yscale2,1.0f);
|
||||
gl_RenderState.mTextureMatrix.rotate(angle,0.0f,0.0f,1.0f);
|
||||
gl_RenderState.EnableTextureMatrix(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Flats
|
||||
//
|
||||
//==========================================================================
|
||||
extern FDynLightData lightdata;
|
||||
|
||||
void GLFlat::SetupSubsectorLights(int pass, subsector_t * sub, int *dli)
|
||||
{
|
||||
Plane p;
|
||||
|
||||
if (dli != NULL && *dli != -1)
|
||||
{
|
||||
gl_RenderState.ApplyLightIndex(GLRenderer->mLights->GetIndex(*dli));
|
||||
(*dli)++;
|
||||
return;
|
||||
}
|
||||
|
||||
lightdata.Clear();
|
||||
FLightNode * node = sub->lighthead;
|
||||
while (node)
|
||||
{
|
||||
ADynamicLight * light = node->lightsource;
|
||||
|
||||
if (light->flags2&MF2_DORMANT)
|
||||
{
|
||||
node=node->nextLight;
|
||||
continue;
|
||||
}
|
||||
iter_dlightf++;
|
||||
|
||||
// we must do the side check here because gl_SetupLight needs the correct plane orientation
|
||||
// which we don't have for Legacy-style 3D-floors
|
||||
fixed_t planeh = plane.plane.ZatPoint(light->x, light->y);
|
||||
if (gl_lights_checkside && ((planeh<light->z && ceiling) || (planeh>light->z && !ceiling)))
|
||||
{
|
||||
node=node->nextLight;
|
||||
continue;
|
||||
}
|
||||
|
||||
p.Set(plane.plane);
|
||||
gl_GetLight(p, light, false, false, lightdata);
|
||||
node = node->nextLight;
|
||||
}
|
||||
|
||||
int d = GLRenderer->mLights->UploadLights(lightdata);
|
||||
if (pass == GLPASS_LIGHTSONLY)
|
||||
{
|
||||
GLRenderer->mLights->StoreIndex(d);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_RenderState.ApplyLightIndex(d);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLFlat::DrawSubsector(subsector_t * sub)
|
||||
{
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
if (plane.plane.a | plane.plane.b)
|
||||
{
|
||||
for (unsigned int k = 0; k < sub->numlines; k++)
|
||||
{
|
||||
vertex_t *vt = sub->firstline[k].v1;
|
||||
ptr->x = vt->fx;
|
||||
ptr->y = vt->fy;
|
||||
ptr->z = plane.plane.ZatPoint(vt->fx, vt->fy) + dz;
|
||||
ptr->u = vt->fx / 64.f;
|
||||
ptr->v = -vt->fy / 64.f;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float zc = FIXED2FLOAT(plane.plane.Zat0()) + dz;
|
||||
for (unsigned int k = 0; k < sub->numlines; k++)
|
||||
{
|
||||
vertex_t *vt = sub->firstline[k].v1;
|
||||
ptr->x = vt->fx;
|
||||
ptr->y = vt->fy;
|
||||
ptr->z = zc;
|
||||
ptr->u = vt->fx / 64.f;
|
||||
ptr->v = -vt->fy / 64.f;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN);
|
||||
|
||||
flatvertices += sub->numlines;
|
||||
flatprimitives++;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLFlat::ProcessLights(bool istrans)
|
||||
{
|
||||
dynlightindex = GLRenderer->mLights->GetIndexPtr();
|
||||
|
||||
if (sub)
|
||||
{
|
||||
// This represents a single subsector
|
||||
SetupSubsectorLights(GLPASS_LIGHTSONLY, sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw the subsectors belonging to this sector
|
||||
for (int i=0; i<sector->subsectorcount; i++)
|
||||
{
|
||||
subsector_t * sub = sector->subsectors[i];
|
||||
if (gl_drawinfo->ss_renderflags[sub-subsectors]&renderflags || istrans)
|
||||
{
|
||||
SetupSubsectorLights(GLPASS_LIGHTSONLY, sub);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the subsectors assigned to it due to missing textures
|
||||
if (!(renderflags&SSRF_RENDER3DPLANES))
|
||||
{
|
||||
gl_subsectorrendernode * node = (renderflags&SSRF_RENDERFLOOR)?
|
||||
gl_drawinfo->GetOtherFloorPlanes(sector->sectornum) :
|
||||
gl_drawinfo->GetOtherCeilingPlanes(sector->sectornum);
|
||||
|
||||
while (node)
|
||||
{
|
||||
SetupSubsectorLights(GLPASS_LIGHTSONLY, node->sub);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLFlat::DrawSubsectors(int pass, bool processlights, bool istrans)
|
||||
{
|
||||
int dli = dynlightindex;
|
||||
|
||||
gl_RenderState.Apply();
|
||||
if (sub)
|
||||
{
|
||||
// This represents a single subsector
|
||||
if (processlights) SetupSubsectorLights(GLPASS_ALL, sub, &dli);
|
||||
DrawSubsector(sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vboindex >= 0)
|
||||
{
|
||||
int index = vboindex;
|
||||
for (int i=0; i<sector->subsectorcount; i++)
|
||||
{
|
||||
subsector_t * sub = sector->subsectors[i];
|
||||
|
||||
if (gl_drawinfo->ss_renderflags[sub-subsectors]&renderflags || istrans)
|
||||
{
|
||||
if (processlights) SetupSubsectorLights(GLPASS_ALL, sub, &dli);
|
||||
drawcalls.Clock();
|
||||
glDrawArrays(GL_TRIANGLE_FAN, index, sub->numlines);
|
||||
drawcalls.Unclock();
|
||||
flatvertices += sub->numlines;
|
||||
flatprimitives++;
|
||||
}
|
||||
index += sub->numlines;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw the subsectors belonging to this sector
|
||||
for (int i=0; i<sector->subsectorcount; i++)
|
||||
{
|
||||
subsector_t * sub = sector->subsectors[i];
|
||||
if (gl_drawinfo->ss_renderflags[sub-subsectors]&renderflags || istrans)
|
||||
{
|
||||
if (processlights) SetupSubsectorLights(GLPASS_ALL, sub, &dli);
|
||||
DrawSubsector(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the subsectors assigned to it due to missing textures
|
||||
if (!(renderflags&SSRF_RENDER3DPLANES))
|
||||
{
|
||||
gl_subsectorrendernode * node = (renderflags&SSRF_RENDERFLOOR)?
|
||||
gl_drawinfo->GetOtherFloorPlanes(sector->sectornum) :
|
||||
gl_drawinfo->GetOtherCeilingPlanes(sector->sectornum);
|
||||
|
||||
while (node)
|
||||
{
|
||||
if (processlights) SetupSubsectorLights(GLPASS_ALL, node->sub, &dli);
|
||||
DrawSubsector(node->sub);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void GLFlat::Draw(int pass, bool trans) // trans only has meaning for GLPASS_LIGHTSONLY
|
||||
{
|
||||
int rel = getExtraLight();
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (sector->sectornum == gl_breaksec)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
switch (pass)
|
||||
{
|
||||
case GLPASS_PLAIN: // Single-pass rendering
|
||||
case GLPASS_ALL:
|
||||
gl_SetColor(lightlevel, rel, Colormap,1.0f);
|
||||
gl_SetFog(lightlevel, rel, &Colormap, false);
|
||||
gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false);
|
||||
gl_SetPlaneTextureRotation(&plane, gltexture);
|
||||
DrawSubsectors(pass, (pass == GLPASS_ALL || dynlightindex > -1), false);
|
||||
gl_RenderState.EnableTextureMatrix(false);
|
||||
break;
|
||||
|
||||
case GLPASS_LIGHTSONLY:
|
||||
if (!trans || gltexture)
|
||||
{
|
||||
ProcessLights(trans);
|
||||
}
|
||||
break;
|
||||
|
||||
case GLPASS_TRANSLUCENT:
|
||||
if (renderstyle==STYLE_Add) gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
gl_SetColor(lightlevel, rel, Colormap, alpha);
|
||||
gl_SetFog(lightlevel, rel, &Colormap, false);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_threshold);
|
||||
if (!gltexture)
|
||||
{
|
||||
gl_RenderState.EnableTexture(false);
|
||||
DrawSubsectors(pass, false, true);
|
||||
gl_RenderState.EnableTexture(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false);
|
||||
gl_SetPlaneTextureRotation(&plane, gltexture);
|
||||
DrawSubsectors(pass, true, true);
|
||||
gl_RenderState.EnableTextureMatrix(false);
|
||||
}
|
||||
if (renderstyle==STYLE_Add) gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// GLFlat::PutFlat
|
||||
//
|
||||
// Checks texture, lighting and translucency settings and puts this
|
||||
// plane in the appropriate render list.
|
||||
//
|
||||
//==========================================================================
|
||||
inline void GLFlat::PutFlat(bool fog)
|
||||
{
|
||||
int list;
|
||||
|
||||
if (gl_fixedcolormap)
|
||||
{
|
||||
Colormap.Clear();
|
||||
}
|
||||
if (renderstyle!=STYLE_Translucent || alpha < 1.f - FLT_EPSILON || fog || gltexture == NULL)
|
||||
{
|
||||
// translucent 3D floors go into the regular translucent list, translucent portals go into the translucent border list.
|
||||
list = (renderflags&SSRF_RENDER3DPLANES) ? GLDL_TRANSLUCENT : GLDL_TRANSLUCENTBORDER;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool masked = gltexture->isMasked() && ((renderflags&SSRF_RENDER3DPLANES) || stack);
|
||||
list = masked ? GLDL_MASKEDFLATS : GLDL_PLAINFLATS;
|
||||
}
|
||||
gl_drawinfo->drawlists[list].AddFlat (this);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This draws one flat
|
||||
// The passed sector does not indicate the area which is rendered.
|
||||
// It is only used as source for the plane data.
|
||||
// The whichplane boolean indicates if the flat is a floor(false) or a ceiling(true)
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLFlat::Process(sector_t * model, int whichplane, bool fog)
|
||||
{
|
||||
plane.GetFromSector(model, whichplane);
|
||||
|
||||
if (!fog)
|
||||
{
|
||||
if (plane.texture==skyflatnum) return;
|
||||
|
||||
gltexture=FMaterial::ValidateTexture(plane.texture, false, true);
|
||||
if (!gltexture) return;
|
||||
if (gltexture->tex->isFullbright())
|
||||
{
|
||||
Colormap.LightColor.r = Colormap.LightColor.g = Colormap.LightColor.b = 0xff;
|
||||
lightlevel=255;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gltexture = NULL;
|
||||
lightlevel = abs(lightlevel);
|
||||
}
|
||||
|
||||
// get height from vplane
|
||||
if (whichplane == sector_t::floor && sector->transdoor) dz = -1;
|
||||
else dz = 0;
|
||||
|
||||
z = plane.plane.ZatPoint(0.f, 0.f);
|
||||
|
||||
PutFlat(fog);
|
||||
rendered_flats++;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets 3D floor info. Common code for all 4 cases
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLFlat::SetFrom3DFloor(F3DFloor *rover, bool top, bool underside)
|
||||
{
|
||||
F3DFloor::planeref & plane = top? rover->top : rover->bottom;
|
||||
|
||||
// FF_FOG requires an inverted logic where to get the light from
|
||||
lightlist_t *light = P_GetPlaneLight(sector, plane.plane, underside);
|
||||
lightlevel = *light->p_lightlevel;
|
||||
|
||||
if (rover->flags & FF_FOG) Colormap.LightColor = (light->extra_colormap)->Fade;
|
||||
else Colormap.CopyLightColor(light->extra_colormap);
|
||||
|
||||
alpha = rover->alpha/255.0f;
|
||||
renderstyle = rover->flags&FF_ADDITIVETRANS? STYLE_Add : STYLE_Translucent;
|
||||
if (plane.model->VBOHeightcheck(plane.isceiling))
|
||||
{
|
||||
vboindex = plane.vindex;
|
||||
}
|
||||
else
|
||||
{
|
||||
vboindex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Process a sector's flats for rendering
|
||||
// This function is only called once per sector.
|
||||
// Subsequent subsectors are just quickly added to the ss_renderflags array
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLFlat::ProcessSector(sector_t * frontsector)
|
||||
{
|
||||
lightlist_t * light;
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (frontsector->sectornum==gl_breaksec)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get the real sector for this one.
|
||||
sector=§ors[frontsector->sectornum];
|
||||
extsector_t::xfloor &x = sector->e->XFloor;
|
||||
this->sub=NULL;
|
||||
dynlightindex = -1;
|
||||
|
||||
byte &srf = gl_drawinfo->sectorrenderflags[sector->sectornum];
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// do floors
|
||||
//
|
||||
//
|
||||
//
|
||||
if (frontsector->floorplane.ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)) <= FIXED2FLOAT(viewz))
|
||||
{
|
||||
// process the original floor first.
|
||||
|
||||
srf |= SSRF_RENDERFLOOR;
|
||||
|
||||
lightlevel = gl_ClampLight(frontsector->GetFloorLight());
|
||||
Colormap=frontsector->ColorMap;
|
||||
if ((stack = (frontsector->portals[sector_t::floor] != NULL)))
|
||||
{
|
||||
gl_drawinfo->AddFloorStack(sector);
|
||||
alpha = frontsector->GetAlpha(sector_t::floor)/65536.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
alpha = 1.0f-frontsector->GetReflect(sector_t::floor);
|
||||
}
|
||||
if (frontsector->VBOHeightcheck(sector_t::floor))
|
||||
{
|
||||
vboindex = frontsector->vboindex[sector_t::floor];
|
||||
}
|
||||
else
|
||||
{
|
||||
vboindex = -1;
|
||||
}
|
||||
|
||||
ceiling=false;
|
||||
renderflags=SSRF_RENDERFLOOR;
|
||||
|
||||
if (x.ffloors.Size())
|
||||
{
|
||||
light = P_GetPlaneLight(sector, &frontsector->floorplane, false);
|
||||
if ((!(sector->GetFlags(sector_t::floor)&PLANEF_ABSLIGHTING) || !light->fromsector)
|
||||
&& (light->p_lightlevel != &frontsector->lightlevel))
|
||||
{
|
||||
lightlevel = *light->p_lightlevel;
|
||||
}
|
||||
|
||||
Colormap.CopyLightColor(light->extra_colormap);
|
||||
}
|
||||
renderstyle = STYLE_Translucent;
|
||||
if (alpha!=0.0f) Process(frontsector, false, false);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// do ceilings
|
||||
//
|
||||
//
|
||||
//
|
||||
if (frontsector->ceilingplane.ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)) >= FIXED2FLOAT(viewz))
|
||||
{
|
||||
// process the original ceiling first.
|
||||
|
||||
srf |= SSRF_RENDERCEILING;
|
||||
|
||||
lightlevel = gl_ClampLight(frontsector->GetCeilingLight());
|
||||
Colormap=frontsector->ColorMap;
|
||||
if ((stack = (frontsector->portals[sector_t::ceiling] != NULL)))
|
||||
{
|
||||
gl_drawinfo->AddCeilingStack(sector);
|
||||
alpha = frontsector->GetAlpha(sector_t::ceiling)/65536.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
alpha = 1.0f-frontsector->GetReflect(sector_t::ceiling);
|
||||
}
|
||||
|
||||
if (frontsector->VBOHeightcheck(sector_t::ceiling))
|
||||
{
|
||||
vboindex = frontsector->vboindex[sector_t::ceiling];
|
||||
}
|
||||
else
|
||||
{
|
||||
vboindex = -1;
|
||||
}
|
||||
|
||||
ceiling=true;
|
||||
renderflags=SSRF_RENDERCEILING;
|
||||
|
||||
if (x.ffloors.Size())
|
||||
{
|
||||
light = P_GetPlaneLight(sector, §or->ceilingplane, true);
|
||||
|
||||
if ((!(sector->GetFlags(sector_t::ceiling)&PLANEF_ABSLIGHTING))
|
||||
&& (light->p_lightlevel != &frontsector->lightlevel))
|
||||
{
|
||||
lightlevel = *light->p_lightlevel;
|
||||
}
|
||||
Colormap.CopyLightColor(light->extra_colormap);
|
||||
}
|
||||
renderstyle = STYLE_Translucent;
|
||||
if (alpha!=0.0f) Process(frontsector, true, false);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// do 3D floors
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
stack=false;
|
||||
if (x.ffloors.Size())
|
||||
{
|
||||
player_t * player=players[consoleplayer].camera->player;
|
||||
|
||||
renderflags=SSRF_RENDER3DPLANES;
|
||||
srf |= SSRF_RENDER3DPLANES;
|
||||
// 3d-floors must not overlap!
|
||||
fixed_t lastceilingheight=sector->CenterCeiling(); // render only in the range of the
|
||||
fixed_t lastfloorheight=sector->CenterFloor(); // current sector part (if applicable)
|
||||
F3DFloor * rover;
|
||||
int k;
|
||||
|
||||
// floors are ordered now top to bottom so scanning the list for the best match
|
||||
// is no longer necessary.
|
||||
|
||||
ceiling=true;
|
||||
for(k=0;k<(int)x.ffloors.Size();k++)
|
||||
{
|
||||
rover=x.ffloors[k];
|
||||
|
||||
if ((rover->flags&(FF_EXISTS|FF_RENDERPLANES|FF_THISINSIDE))==(FF_EXISTS|FF_RENDERPLANES))
|
||||
{
|
||||
if (rover->flags&FF_FOG && gl_fixedcolormap) continue;
|
||||
if (!rover->top.copied && rover->flags&(FF_INVERTPLANES|FF_BOTHPLANES))
|
||||
{
|
||||
fixed_t ff_top=rover->top.plane->ZatPoint(CenterSpot(sector));
|
||||
if (ff_top<lastceilingheight)
|
||||
{
|
||||
if (FIXED2FLOAT(viewz) <= rover->top.plane->ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)))
|
||||
{
|
||||
SetFrom3DFloor(rover, true, !!(rover->flags&FF_FOG));
|
||||
Colormap.FadeColor=frontsector->ColorMap->Fade;
|
||||
Process(rover->top.model, rover->top.isceiling, !!(rover->flags&FF_FOG));
|
||||
}
|
||||
lastceilingheight=ff_top;
|
||||
}
|
||||
}
|
||||
if (!rover->bottom.copied && !(rover->flags&FF_INVERTPLANES))
|
||||
{
|
||||
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(CenterSpot(sector));
|
||||
if (ff_bottom<lastceilingheight)
|
||||
{
|
||||
if (FIXED2FLOAT(viewz)<=rover->bottom.plane->ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)))
|
||||
{
|
||||
SetFrom3DFloor(rover, false, !(rover->flags&FF_FOG));
|
||||
Colormap.FadeColor=frontsector->ColorMap->Fade;
|
||||
Process(rover->bottom.model, rover->bottom.isceiling, !!(rover->flags&FF_FOG));
|
||||
}
|
||||
lastceilingheight=ff_bottom;
|
||||
if (rover->alpha<255) lastceilingheight++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ceiling=false;
|
||||
for(k=x.ffloors.Size()-1;k>=0;k--)
|
||||
{
|
||||
rover=x.ffloors[k];
|
||||
|
||||
if ((rover->flags&(FF_EXISTS|FF_RENDERPLANES|FF_THISINSIDE))==(FF_EXISTS|FF_RENDERPLANES))
|
||||
{
|
||||
if (rover->flags&FF_FOG && gl_fixedcolormap) continue;
|
||||
if (!rover->bottom.copied && rover->flags&(FF_INVERTPLANES|FF_BOTHPLANES))
|
||||
{
|
||||
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(CenterSpot(sector));
|
||||
if (ff_bottom>lastfloorheight || (rover->flags&FF_FIX))
|
||||
{
|
||||
if (FIXED2FLOAT(viewz) >= rover->bottom.plane->ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)))
|
||||
{
|
||||
SetFrom3DFloor(rover, false, !(rover->flags&FF_FOG));
|
||||
Colormap.FadeColor=frontsector->ColorMap->Fade;
|
||||
|
||||
if (rover->flags&FF_FIX)
|
||||
{
|
||||
lightlevel = gl_ClampLight(rover->model->lightlevel);
|
||||
Colormap = rover->GetColormap();
|
||||
}
|
||||
|
||||
Process(rover->bottom.model, rover->bottom.isceiling, !!(rover->flags&FF_FOG));
|
||||
}
|
||||
lastfloorheight=ff_bottom;
|
||||
}
|
||||
}
|
||||
if (!rover->top.copied && !(rover->flags&FF_INVERTPLANES))
|
||||
{
|
||||
fixed_t ff_top=rover->top.plane->ZatPoint(CenterSpot(sector));
|
||||
if (ff_top>lastfloorheight)
|
||||
{
|
||||
if (FIXED2FLOAT(viewz) >= rover->top.plane->ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)))
|
||||
{
|
||||
SetFrom3DFloor(rover, true, !!(rover->flags&FF_FOG));
|
||||
Colormap.FadeColor=frontsector->ColorMap->Fade;
|
||||
Process(rover->top.model, rover->top.isceiling, !!(rover->flags&FF_FOG));
|
||||
}
|
||||
lastfloorheight=ff_top;
|
||||
if (rover->alpha<255) lastfloorheight--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1090
src/gl/scene/gl_portal.cpp
Normal file
1090
src/gl/scene/gl_portal.cpp
Normal file
File diff suppressed because it is too large
Load diff
301
src/gl/scene/gl_portal.h
Normal file
301
src/gl/scene/gl_portal.h
Normal file
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
** gl_renderstruct.h
|
||||
** Generalized portal maintenance classes to make rendering special effects easier
|
||||
** and help add future extensions
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2005 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.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __GL_PORTAL_H
|
||||
#define __GL_PORTAL_H
|
||||
|
||||
#include "tarray.h"
|
||||
//#include "gl/gl_intern.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/utility/gl_templates.h"
|
||||
|
||||
class ASkyViewpoint;
|
||||
|
||||
struct GLHorizonInfo
|
||||
{
|
||||
GLSectorPlane plane;
|
||||
int lightlevel;
|
||||
FColormap colormap;
|
||||
};
|
||||
|
||||
struct GLSkyInfo
|
||||
{
|
||||
float x_offset[2];
|
||||
float y_offset; // doubleskies don't have a y-offset
|
||||
FMaterial * texture[2];
|
||||
FTextureID skytexno1;
|
||||
bool mirrored;
|
||||
bool doublesky;
|
||||
bool sky2;
|
||||
PalEntry fadecolor; // if this isn't made part of the dome things will become more complicated when sky fog is used.
|
||||
|
||||
bool operator==(const GLSkyInfo & inf)
|
||||
{
|
||||
return !memcmp(this, &inf, sizeof(*this));
|
||||
}
|
||||
bool operator!=(const GLSkyInfo & inf)
|
||||
{
|
||||
return !!memcmp(this, &inf, sizeof(*this));
|
||||
}
|
||||
};
|
||||
|
||||
extern UniqueList<GLSkyInfo> UniqueSkies;
|
||||
extern UniqueList<GLHorizonInfo> UniqueHorizons;
|
||||
extern UniqueList<secplane_t> UniquePlaneMirrors;
|
||||
|
||||
class GLPortal
|
||||
{
|
||||
static TArray<GLPortal *> portals;
|
||||
static int recursion;
|
||||
static unsigned int QueryObject;
|
||||
protected:
|
||||
static TArray<float> planestack;
|
||||
static int MirrorFlag;
|
||||
static int PlaneMirrorFlag;
|
||||
static int renderdepth;
|
||||
|
||||
public:
|
||||
static int PlaneMirrorMode;
|
||||
static int inupperstack;
|
||||
static int instack[2];
|
||||
static bool inskybox;
|
||||
|
||||
private:
|
||||
void DrawPortalStencil();
|
||||
|
||||
fixed_t savedviewx;
|
||||
fixed_t savedviewy;
|
||||
fixed_t savedviewz;
|
||||
angle_t savedviewangle;
|
||||
AActor * savedviewactor;
|
||||
area_t savedviewarea;
|
||||
GLPortal *NextPortal;
|
||||
TArray<BYTE> savedmapsection;
|
||||
TArray<unsigned int> mPrimIndices;
|
||||
|
||||
protected:
|
||||
TArray<GLWall> lines;
|
||||
int level;
|
||||
|
||||
GLPortal() { portals.Push(this); }
|
||||
virtual ~GLPortal() { }
|
||||
|
||||
bool Start(bool usestencil, bool doquery);
|
||||
void End(bool usestencil);
|
||||
virtual void DrawContents()=0;
|
||||
virtual void * GetSource() const =0; // GetSource MUST be implemented!
|
||||
void ClearClipper();
|
||||
virtual bool IsSky() { return false; }
|
||||
virtual bool NeedCap() { return true; }
|
||||
virtual bool NeedDepthBuffer() { return true; }
|
||||
void ClearScreen();
|
||||
virtual const char *GetName() = 0;
|
||||
void SaveMapSection();
|
||||
void RestoreMapSection();
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
PClip_InFront,
|
||||
PClip_Inside,
|
||||
PClip_Behind
|
||||
};
|
||||
|
||||
void RenderPortal(bool usestencil, bool doquery)
|
||||
{
|
||||
// Start may perform an occlusion query. If that returns 0 there
|
||||
// is no need to draw the stencil's contents and there's also no
|
||||
// need to restore the affected area becasue there is none!
|
||||
if (Start(usestencil, doquery))
|
||||
{
|
||||
DrawContents();
|
||||
End(usestencil);
|
||||
}
|
||||
}
|
||||
|
||||
void AddLine(GLWall * l)
|
||||
{
|
||||
lines.Push(*l);
|
||||
}
|
||||
|
||||
static int GetRecursion()
|
||||
{
|
||||
return recursion;
|
||||
}
|
||||
|
||||
virtual int ClipSeg(seg_t *seg) { return PClip_Inside; }
|
||||
virtual int ClipPoint(fixed_t x, fixed_t y) { return PClip_Inside; }
|
||||
|
||||
static void BeginScene();
|
||||
static void StartFrame();
|
||||
static bool RenderFirstSkyPortal(int recursion);
|
||||
static void EndFrame();
|
||||
static GLPortal * FindPortal(const void * src);
|
||||
};
|
||||
|
||||
|
||||
struct GLMirrorPortal : public GLPortal
|
||||
{
|
||||
// mirror portals always consist of single linedefs!
|
||||
line_t * linedef;
|
||||
|
||||
protected:
|
||||
virtual void DrawContents();
|
||||
virtual void * GetSource() const { return linedef; }
|
||||
virtual const char *GetName();
|
||||
|
||||
public:
|
||||
|
||||
GLMirrorPortal(line_t * line)
|
||||
{
|
||||
linedef=line;
|
||||
}
|
||||
|
||||
virtual bool NeedCap() { return false; }
|
||||
virtual int ClipSeg(seg_t *seg);
|
||||
virtual int ClipPoint(fixed_t x, fixed_t y);
|
||||
};
|
||||
|
||||
|
||||
struct GLSkyboxPortal : public GLPortal
|
||||
{
|
||||
AActor * origin;
|
||||
|
||||
protected:
|
||||
virtual void DrawContents();
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual bool IsSky() { return true; } // later!
|
||||
virtual const char *GetName();
|
||||
|
||||
public:
|
||||
|
||||
|
||||
GLSkyboxPortal(AActor * pt)
|
||||
{
|
||||
origin=pt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct GLSkyPortal : public GLPortal
|
||||
{
|
||||
GLSkyInfo * origin;
|
||||
|
||||
protected:
|
||||
virtual void DrawContents();
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual bool IsSky() { return true; }
|
||||
virtual bool NeedDepthBuffer() { return false; }
|
||||
virtual const char *GetName();
|
||||
|
||||
public:
|
||||
|
||||
|
||||
GLSkyPortal(GLSkyInfo * pt)
|
||||
{
|
||||
origin=pt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct GLSectorStackPortal : public GLPortal
|
||||
{
|
||||
TArray<subsector_t *> subsectors;
|
||||
protected:
|
||||
virtual ~GLSectorStackPortal();
|
||||
virtual void DrawContents();
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual bool IsSky() { return true; } // although this isn't a real sky it can be handled as one.
|
||||
virtual const char *GetName();
|
||||
FPortal *origin;
|
||||
|
||||
public:
|
||||
|
||||
GLSectorStackPortal(FPortal *pt)
|
||||
{
|
||||
origin=pt;
|
||||
}
|
||||
void SetupCoverage();
|
||||
void AddSubsector(subsector_t *sub)
|
||||
{
|
||||
subsectors.Push(sub);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct GLPlaneMirrorPortal : public GLPortal
|
||||
{
|
||||
protected:
|
||||
virtual void DrawContents();
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual const char *GetName();
|
||||
secplane_t * origin;
|
||||
|
||||
public:
|
||||
|
||||
GLPlaneMirrorPortal(secplane_t * pt)
|
||||
{
|
||||
origin=pt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct GLHorizonPortal : public GLPortal
|
||||
{
|
||||
GLHorizonInfo * origin;
|
||||
|
||||
protected:
|
||||
virtual void DrawContents();
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual bool NeedDepthBuffer() { return false; }
|
||||
virtual bool NeedCap() { return false; }
|
||||
virtual const char *GetName();
|
||||
|
||||
public:
|
||||
|
||||
GLHorizonPortal(GLHorizonInfo * pt)
|
||||
{
|
||||
origin=pt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
1238
src/gl/scene/gl_renderhacks.cpp
Normal file
1238
src/gl/scene/gl_renderhacks.cpp
Normal file
File diff suppressed because it is too large
Load diff
1232
src/gl/scene/gl_scene.cpp
Normal file
1232
src/gl/scene/gl_scene.cpp
Normal file
File diff suppressed because it is too large
Load diff
352
src/gl/scene/gl_sky.cpp
Normal file
352
src/gl/scene/gl_sky.cpp
Normal file
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
** gl_sky.cpp
|
||||
** Sky preparation code.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "g_level.h"
|
||||
#include "r_sky.h"
|
||||
#include "r_state.h"
|
||||
#include "r_utility.h"
|
||||
#include "doomdata.h"
|
||||
#include "gl/gl_functions.h"
|
||||
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/utility/gl_convert.h"
|
||||
|
||||
CVAR(Bool,gl_noskyboxes, false, 0)
|
||||
extern int skyfog;
|
||||
|
||||
enum
|
||||
{
|
||||
NoSkyDraw = 89
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Calculate sky texture
|
||||
//
|
||||
//==========================================================================
|
||||
void GLWall::SkyPlane(sector_t *sector, int plane, bool allowreflect)
|
||||
{
|
||||
FPortal *portal = sector->portals[plane];
|
||||
if (portal != NULL)
|
||||
{
|
||||
if (GLPortal::instack[1-plane]) return;
|
||||
type=RENDERWALL_SECTORSTACK;
|
||||
this->portal = portal;
|
||||
}
|
||||
else if (sector->GetTexture(plane)==skyflatnum)
|
||||
{
|
||||
GLSkyInfo skyinfo;
|
||||
ASkyViewpoint * skyboxx = sector->GetSkyBox(plane);
|
||||
|
||||
// JUSTHIT is used as an indicator that a skybox is in use.
|
||||
// This is to avoid recursion
|
||||
|
||||
if (!gl_noskyboxes && skyboxx && GLRenderer->mViewActor!=skyboxx && !(skyboxx->flags&MF_JUSTHIT))
|
||||
{
|
||||
type=RENDERWALL_SKYBOX;
|
||||
skybox=skyboxx;
|
||||
}
|
||||
else
|
||||
{
|
||||
int sky1 = sector->sky;
|
||||
memset(&skyinfo, 0, sizeof(skyinfo));
|
||||
if ((sky1 & PL_SKYFLAT) && (sky1 & (PL_SKYFLAT-1)))
|
||||
{
|
||||
const line_t *l = &lines[(sky1&(PL_SKYFLAT-1))-1];
|
||||
const side_t *s = l->sidedef[0];
|
||||
int pos;
|
||||
|
||||
if (level.flags & LEVEL_SWAPSKIES && s->GetTexture(side_t::bottom).isValid())
|
||||
{
|
||||
pos = side_t::bottom;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = side_t::top;
|
||||
}
|
||||
|
||||
FTextureID texno = s->GetTexture(pos);
|
||||
skyinfo.texture[0] = FMaterial::ValidateTexture(texno, false, true);
|
||||
if (!skyinfo.texture[0] || skyinfo.texture[0]->tex->UseType == FTexture::TEX_Null) goto normalsky;
|
||||
skyinfo.skytexno1 = texno;
|
||||
skyinfo.x_offset[0] = ANGLE_TO_FLOAT(s->GetTextureXOffset(pos));
|
||||
skyinfo.y_offset = FIXED2FLOAT(s->GetTextureYOffset(pos));
|
||||
skyinfo.mirrored = !l->args[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
normalsky:
|
||||
if (level.flags&LEVEL_DOUBLESKY)
|
||||
{
|
||||
skyinfo.texture[1]=FMaterial::ValidateTexture(sky1texture, false, true);
|
||||
skyinfo.x_offset[1] = GLRenderer->mSky1Pos;
|
||||
skyinfo.doublesky = true;
|
||||
}
|
||||
|
||||
if ((level.flags&LEVEL_SWAPSKIES || (sky1==PL_SKYFLAT) || (level.flags&LEVEL_DOUBLESKY)) &&
|
||||
sky2texture!=sky1texture) // If both skies are equal use the scroll offset of the first!
|
||||
{
|
||||
skyinfo.texture[0]=FMaterial::ValidateTexture(sky2texture, false, true);
|
||||
skyinfo.skytexno1=sky2texture;
|
||||
skyinfo.sky2 = true;
|
||||
skyinfo.x_offset[0] = GLRenderer->mSky2Pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
skyinfo.texture[0]=FMaterial::ValidateTexture(sky1texture, false, true);
|
||||
skyinfo.skytexno1=sky1texture;
|
||||
skyinfo.x_offset[0] = GLRenderer->mSky1Pos;
|
||||
}
|
||||
}
|
||||
if (skyfog>0)
|
||||
{
|
||||
skyinfo.fadecolor=Colormap.FadeColor;
|
||||
skyinfo.fadecolor.a=0;
|
||||
}
|
||||
else skyinfo.fadecolor=0;
|
||||
|
||||
type=RENDERWALL_SKY;
|
||||
sky=UniqueSkies.Get(&skyinfo);
|
||||
}
|
||||
}
|
||||
else if (allowreflect && sector->GetReflect(plane) > 0)
|
||||
{
|
||||
if ((plane == sector_t::ceiling && viewz > sector->ceilingplane.d) ||
|
||||
(plane == sector_t::floor && viewz < -sector->floorplane.d)) return;
|
||||
type=RENDERWALL_PLANEMIRROR;
|
||||
planemirror = plane == sector_t::ceiling? §or->ceilingplane : §or->floorplane;
|
||||
}
|
||||
else return;
|
||||
PutWall(0);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Skies on one sided walls
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::SkyNormal(sector_t * fs,vertex_t * v1,vertex_t * v2)
|
||||
{
|
||||
ztop[0]=ztop[1]=32768.0f;
|
||||
zbottom[0]=zceil[0];
|
||||
zbottom[1]=zceil[1];
|
||||
SkyPlane(fs, sector_t::ceiling, true);
|
||||
|
||||
ztop[0]=zfloor[0];
|
||||
ztop[1]=zfloor[1];
|
||||
zbottom[0]=zbottom[1]=-32768.0f;
|
||||
SkyPlane(fs, sector_t::floor, true);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Upper Skies on two sided walls
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2)
|
||||
{
|
||||
if (fs->GetTexture(sector_t::ceiling)==skyflatnum)
|
||||
{
|
||||
if ((bs->special&0xff) == NoSkyDraw) return;
|
||||
if (bs->GetTexture(sector_t::ceiling)==skyflatnum)
|
||||
{
|
||||
// if the back sector is closed the sky must be drawn!
|
||||
if (bs->ceilingplane.ZatPoint(v1) > bs->floorplane.ZatPoint(v1) ||
|
||||
bs->ceilingplane.ZatPoint(v2) > bs->floorplane.ZatPoint(v2) || bs->transdoor)
|
||||
return;
|
||||
|
||||
// one more check for some ugly transparent door hacks
|
||||
if (bs->floorplane.a==0 && bs->floorplane.b==0 && fs->floorplane.a==0 && fs->floorplane.b==0)
|
||||
{
|
||||
if (bs->GetPlaneTexZ(sector_t::floor)==fs->GetPlaneTexZ(sector_t::floor)+FRACUNIT)
|
||||
{
|
||||
FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::bottom));
|
||||
if (!tex || tex->UseType==FTexture::TEX_Null) return;
|
||||
|
||||
// very, very, very ugly special case (See Icarus MAP14)
|
||||
// It is VERY important that this is only done for a floor height difference of 1
|
||||
// or it will cause glitches elsewhere.
|
||||
tex = TexMan(seg->sidedef->GetTexture(side_t::mid));
|
||||
if (tex != NULL && !(seg->linedef->flags & ML_DONTPEGTOP) &&
|
||||
seg->sidedef->GetTextureYOffset(side_t::mid) > 0)
|
||||
{
|
||||
ztop[0]=ztop[1]=32768.0f;
|
||||
zbottom[0]=zbottom[1]=
|
||||
FIXED2FLOAT(bs->ceilingplane.ZatPoint(v2) + seg->sidedef->GetTextureYOffset(side_t::mid));
|
||||
SkyPlane(fs, sector_t::ceiling, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ztop[0]=ztop[1]=32768.0f;
|
||||
|
||||
FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::top));
|
||||
if (bs->GetTexture(sector_t::ceiling) != skyflatnum)
|
||||
|
||||
{
|
||||
zbottom[0]=zceil[0];
|
||||
zbottom[1]=zceil[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
zbottom[0]=FIXED2FLOAT(bs->ceilingplane.ZatPoint(v1));
|
||||
zbottom[1]=FIXED2FLOAT(bs->ceilingplane.ZatPoint(v2));
|
||||
flags|=GLWF_SKYHACK; // mid textures on such lines need special treatment!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FPortal *pfront = fs->portals[sector_t::ceiling];
|
||||
FPortal *pback = bs->portals[sector_t::ceiling];
|
||||
float frontreflect = fs->GetReflect(sector_t::ceiling);
|
||||
if (frontreflect > 0)
|
||||
{
|
||||
float backreflect = bs->GetReflect(sector_t::ceiling);
|
||||
if (backreflect > 0 && bs->ceilingplane.d == fs->ceilingplane.d)
|
||||
{
|
||||
// Don't add intra-portal line to the portal.
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (pfront == NULL || pfront == pback)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// stacked sectors
|
||||
fixed_t fsc1=fs->ceilingplane.ZatPoint(v1);
|
||||
fixed_t fsc2=fs->ceilingplane.ZatPoint(v2);
|
||||
|
||||
ztop[0]=ztop[1]=32768.0f;
|
||||
zbottom[0]=FIXED2FLOAT(fsc1);
|
||||
zbottom[1]=FIXED2FLOAT(fsc2);
|
||||
}
|
||||
|
||||
SkyPlane(fs, sector_t::ceiling, true);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Lower Skies on two sided walls
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::SkyBottom(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2)
|
||||
{
|
||||
if (fs->GetTexture(sector_t::floor)==skyflatnum)
|
||||
{
|
||||
if ((bs->special&0xff) == NoSkyDraw) return;
|
||||
FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::bottom));
|
||||
|
||||
// For lower skies the normal logic only applies to walls with no lower texture!
|
||||
if (tex->UseType==FTexture::TEX_Null)
|
||||
{
|
||||
if (bs->GetTexture(sector_t::floor)==skyflatnum)
|
||||
{
|
||||
// if the back sector is closed the sky must be drawn!
|
||||
if (bs->ceilingplane.ZatPoint(v1) > bs->floorplane.ZatPoint(v1) ||
|
||||
bs->ceilingplane.ZatPoint(v2) > bs->floorplane.ZatPoint(v2))
|
||||
return;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Special hack for Vrack2b
|
||||
if (bs->floorplane.ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)) > FIXED2FLOAT(viewz)) return;
|
||||
}
|
||||
}
|
||||
zbottom[0]=zbottom[1]=-32768.0f;
|
||||
|
||||
if ((tex && tex->UseType!=FTexture::TEX_Null) || bs->GetTexture(sector_t::floor)!=skyflatnum)
|
||||
{
|
||||
ztop[0]=zfloor[0];
|
||||
ztop[1]=zfloor[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
ztop[0]=FIXED2FLOAT(bs->floorplane.ZatPoint(v1));
|
||||
ztop[1]=FIXED2FLOAT(bs->floorplane.ZatPoint(v2));
|
||||
flags|=GLWF_SKYHACK; // mid textures on such lines need special treatment!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FPortal *pfront = fs->portals[sector_t::floor];
|
||||
FPortal *pback = bs->portals[sector_t::floor];
|
||||
float frontreflect = fs->GetReflect(sector_t::floor);
|
||||
if (frontreflect > 0)
|
||||
{
|
||||
float backreflect = bs->GetReflect(sector_t::floor);
|
||||
if (backreflect > 0 && bs->floorplane.d == fs->floorplane.d)
|
||||
{
|
||||
// Don't add intra-portal line to the portal.
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (pfront == NULL || pfront == pback)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// stacked sectors
|
||||
fixed_t fsc1=fs->floorplane.ZatPoint(v1);
|
||||
fixed_t fsc2=fs->floorplane.ZatPoint(v2);
|
||||
|
||||
zbottom[0]=zbottom[1]=-32768.0f;
|
||||
ztop[0]=FIXED2FLOAT(fsc1);
|
||||
ztop[1]=FIXED2FLOAT(fsc2);
|
||||
}
|
||||
|
||||
SkyPlane(fs, sector_t::floor, true);
|
||||
}
|
||||
|
539
src/gl/scene/gl_skydome.cpp
Normal file
539
src/gl/scene/gl_skydome.cpp
Normal file
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
** gl_sky.cpp
|
||||
**
|
||||
** Draws the sky. Loosely based on the JDoom sky and the ZDoomGL 0.66.2 sky.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2003 Tim Stump
|
||||
** Copyright 2005 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.
|
||||
** 4. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "doomtype.h"
|
||||
#include "g_level.h"
|
||||
#include "sc_man.h"
|
||||
#include "w_wad.h"
|
||||
#include "r_state.h"
|
||||
//#include "gl/gl_intern.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_bitmap.h"
|
||||
#include "gl/textures/gl_texture.h"
|
||||
#include "gl/textures/gl_skyboxtexture.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Shamelessly lifted from Doomsday (written by Jaakko Keränen)
|
||||
// also shamelessly lifted from ZDoomGL! ;)
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CVAR(Float, skyoffset, 0, 0) // for testing
|
||||
|
||||
extern int skyfog;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
FSkyVertexBuffer::FSkyVertexBuffer()
|
||||
{
|
||||
CreateDome();
|
||||
|
||||
glBindVertexArray(vao_id);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||||
glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FSkyVertex), &VSO->x);
|
||||
glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FSkyVertex), &VSO->u);
|
||||
glVertexAttribPointer(VATTR_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(FSkyVertex), &VSO->color);
|
||||
glEnableVertexAttribArray(VATTR_VERTEX);
|
||||
glEnableVertexAttribArray(VATTR_TEXCOORD);
|
||||
glEnableVertexAttribArray(VATTR_COLOR);
|
||||
glBindVertexArray(0);
|
||||
|
||||
}
|
||||
|
||||
FSkyVertexBuffer::~FSkyVertexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::SkyVertex(int r, int c, bool yflip)
|
||||
{
|
||||
static const angle_t maxSideAngle = ANGLE_180 / 3;
|
||||
static const fixed_t scale = 10000 << FRACBITS;
|
||||
|
||||
angle_t topAngle= (angle_t)(c / (float)mColumns * ANGLE_MAX);
|
||||
angle_t sideAngle = maxSideAngle * (mRows - r) / mRows;
|
||||
fixed_t height = finesine[sideAngle>>ANGLETOFINESHIFT];
|
||||
fixed_t realRadius = FixedMul(scale, finecosine[sideAngle>>ANGLETOFINESHIFT]);
|
||||
fixed_t x = FixedMul(realRadius, finecosine[topAngle>>ANGLETOFINESHIFT]);
|
||||
fixed_t y = (!yflip) ? FixedMul(scale, height) : FixedMul(scale, height) * -1;
|
||||
fixed_t z = FixedMul(realRadius, finesine[topAngle>>ANGLETOFINESHIFT]);
|
||||
|
||||
FSkyVertex vert;
|
||||
|
||||
vert.color = r == 0 ? 0xffffff : 0xffffffff;
|
||||
|
||||
// And the texture coordinates.
|
||||
if(!yflip) // Flipped Y is for the lower hemisphere.
|
||||
{
|
||||
vert.u = (-c / (float)mColumns) ;
|
||||
vert.v = (r / (float)mRows);
|
||||
}
|
||||
else
|
||||
{
|
||||
vert.u = (-c / (float)mColumns);
|
||||
vert.v = 1.0f + ((mRows - r) / (float)mRows);
|
||||
}
|
||||
|
||||
if (r != 4) y+=FRACUNIT*300;
|
||||
// And finally the vertex.
|
||||
vert.x =-FIXED2FLOAT(x); // Doom mirrors the sky vertically!
|
||||
vert.y = FIXED2FLOAT(y) - 1.f;
|
||||
vert.z = FIXED2FLOAT(z);
|
||||
|
||||
mVertices.Push(vert);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::CreateSkyHemisphere(int hemi)
|
||||
{
|
||||
int r, c;
|
||||
bool yflip = !!(hemi & SKYHEMI_LOWER);
|
||||
|
||||
mPrimStart.Push(mVertices.Size());
|
||||
|
||||
for (c = 0; c < mColumns; c++)
|
||||
{
|
||||
SkyVertex(1, c, yflip);
|
||||
}
|
||||
|
||||
// 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 + yflip, c, yflip);
|
||||
SkyVertex(r + 1 - yflip, c, yflip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::CreateDome()
|
||||
{
|
||||
// the first thing we put into the buffer is the fog layer object which is just 4 triangles around the viewpoint.
|
||||
|
||||
mVertices.Reserve(12);
|
||||
mVertices[0].Set( 1.0f, 1.0f, -1.0f);
|
||||
mVertices[1].Set( 1.0f, -1.0f, -1.0f);
|
||||
mVertices[2].Set(-1.0f, 0.0f, -1.0f);
|
||||
|
||||
mVertices[3].Set( 1.0f, 1.0f, -1.0f);
|
||||
mVertices[4].Set( 1.0f, -1.0f, -1.0f);
|
||||
mVertices[5].Set( 0.0f, 0.0f, 1.0f);
|
||||
|
||||
mVertices[6].Set(-1.0f, 0.0f, -1.0f);
|
||||
mVertices[7].Set( 1.0f, 1.0f, -1.0f);
|
||||
mVertices[8].Set( 0.0f, 0.0f, 1.0f);
|
||||
|
||||
mVertices[9].Set(1.0f, -1.0f, -1.0f);
|
||||
mVertices[10].Set(-1.0f, 0.0f, -1.0f);
|
||||
mVertices[11].Set( 0.0f, 0.0f, 1.0f);
|
||||
|
||||
mColumns = 128;
|
||||
mRows = 4;
|
||||
CreateSkyHemisphere(SKYHEMI_UPPER);
|
||||
CreateSkyHemisphere(SKYHEMI_LOWER);
|
||||
mPrimStart.Push(mVertices.Size());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||||
glBufferData(GL_ARRAY_BUFFER, mVertices.Size() * sizeof(FSkyVertex), &mVertices[0], GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline void FSkyVertexBuffer::RenderRow(int prim, int row)
|
||||
{
|
||||
glDrawArrays(prim, mPrimStart[row], mPrimStart[row + 1] - mPrimStart[row]);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FSkyVertexBuffer::RenderDome(FMaterial *tex, int mode)
|
||||
{
|
||||
int rc = mRows + 1;
|
||||
|
||||
// The caps only get drawn for the main layer but not for the overlay.
|
||||
if (mode == SKYMODE_MAINLAYER && tex != NULL)
|
||||
{
|
||||
PalEntry pe = tex->tex->GetSkyCapColor(false);
|
||||
gl_RenderState.SetObjectColor(pe);
|
||||
gl_RenderState.EnableTexture(false);
|
||||
gl_RenderState.Apply();
|
||||
RenderRow(GL_TRIANGLE_FAN, 0);
|
||||
|
||||
pe = tex->tex->GetSkyCapColor(true);
|
||||
gl_RenderState.SetObjectColor(pe);
|
||||
gl_RenderState.Apply();
|
||||
RenderRow(GL_TRIANGLE_FAN, rc);
|
||||
gl_RenderState.EnableTexture(true);
|
||||
}
|
||||
gl_RenderState.SetObjectColor(0xffffffff);
|
||||
gl_RenderState.Apply();
|
||||
for (int i = 1; i <= mRows; i++)
|
||||
{
|
||||
RenderRow(GL_TRIANGLE_STRIP, i);
|
||||
RenderRow(GL_TRIANGLE_STRIP, rc + i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void RenderDome(FMaterial * tex, float x_offset, float y_offset, bool mirror, int mode)
|
||||
{
|
||||
int texh = 0;
|
||||
int texw = 0;
|
||||
|
||||
// 57 world units roughly represent one sky texel for the glTranslate call.
|
||||
const float skyoffsetfactor = 57;
|
||||
|
||||
if (tex)
|
||||
{
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_NONE, 0, -1, false);
|
||||
texw = tex->TextureWidth();
|
||||
texh = tex->TextureHeight();
|
||||
gl_RenderState.EnableModelMatrix(true);
|
||||
|
||||
gl_RenderState.mModelMatrix.loadIdentity();
|
||||
gl_RenderState.mModelMatrix.rotate(-180.0f+x_offset, 0.f, 1.f, 0.f);
|
||||
|
||||
float xscale = 1024.f / float(texw);
|
||||
float yscale = 1.f;
|
||||
if (texh < 128)
|
||||
{
|
||||
// smaller sky textures must be tiled. We restrict it to 128 sky pixels, though
|
||||
gl_RenderState.mModelMatrix.translate(0.f, -1250.f, 0.f);
|
||||
gl_RenderState.mModelMatrix.scale(1.f, 128/230.f, 1.f);
|
||||
yscale = 128 / texh; // intentionally left as integer.
|
||||
}
|
||||
else if (texh < 200)
|
||||
{
|
||||
gl_RenderState.mModelMatrix.translate(0.f, -1250.f, 0.f);
|
||||
gl_RenderState.mModelMatrix.scale(1.f, texh/230.f, 1.f);
|
||||
}
|
||||
else if (texh <= 240)
|
||||
{
|
||||
gl_RenderState.mModelMatrix.translate(0.f, (200 - texh + tex->tex->SkyOffset + skyoffset)*skyoffsetfactor, 0.f);
|
||||
gl_RenderState.mModelMatrix.scale(1.f, 1.f + ((texh-200.f)/200.f) * 1.17f, 1.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_RenderState.mModelMatrix.translate(0.f, (-40 + tex->tex->SkyOffset + skyoffset)*skyoffsetfactor, 0.f);
|
||||
gl_RenderState.mModelMatrix.scale(1.f, 1.2f * 1.17f, 1.f);
|
||||
yscale = 240.f / texh;
|
||||
}
|
||||
gl_RenderState.EnableTextureMatrix(true);
|
||||
gl_RenderState.mTextureMatrix.loadIdentity();
|
||||
gl_RenderState.mTextureMatrix.scale(mirror? -xscale : xscale, yscale, 1.f);
|
||||
gl_RenderState.mTextureMatrix.translate(1.f, y_offset / texh, 1.f);
|
||||
}
|
||||
|
||||
GLRenderer->mSkyVBO->RenderDome(tex, mode);
|
||||
gl_RenderState.EnableTextureMatrix(false);
|
||||
gl_RenderState.EnableModelMatrix(false);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, bool sky2)
|
||||
{
|
||||
FSkyBox * sb = static_cast<FSkyBox*>(gltex->tex);
|
||||
int faces;
|
||||
FMaterial * tex;
|
||||
|
||||
gl_RenderState.EnableModelMatrix(true);
|
||||
gl_RenderState.mModelMatrix.loadIdentity();
|
||||
|
||||
if (!sky2)
|
||||
gl_RenderState.mModelMatrix.rotate(-180.0f+x_offset, glset.skyrotatevector.X, glset.skyrotatevector.Z, glset.skyrotatevector.Y);
|
||||
else
|
||||
gl_RenderState.mModelMatrix.rotate(-180.0f+x_offset, glset.skyrotatevector2.X, glset.skyrotatevector2.Z, glset.skyrotatevector2.Y);
|
||||
|
||||
FFlatVertex *ptr;
|
||||
if (sb->faces[5])
|
||||
{
|
||||
faces=4;
|
||||
|
||||
// north
|
||||
tex = FMaterial::ValidateTexture(sb->faces[0], false);
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
|
||||
gl_RenderState.Apply();
|
||||
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(128.f, 128.f, -128.f, 0, 0);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, 128.f, -128.f, 1, 0);
|
||||
ptr++;
|
||||
ptr->Set(128.f, -128.f, -128.f, 0, 1);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, -128.f, -128.f, 1, 1);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
|
||||
// east
|
||||
tex = FMaterial::ValidateTexture(sb->faces[1], false);
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
|
||||
gl_RenderState.Apply();
|
||||
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(-128.f, 128.f, -128.f, 0, 0);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, 128.f, 128.f, 1, 0);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, -128.f, -128.f, 0, 1);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, -128.f, 128.f, 1, 1);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
|
||||
// south
|
||||
tex = FMaterial::ValidateTexture(sb->faces[2], false);
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
|
||||
gl_RenderState.Apply();
|
||||
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(-128.f, 128.f, 128.f, 0, 0);
|
||||
ptr++;
|
||||
ptr->Set(128.f, 128.f, 128.f, 1, 0);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, -128.f, 128.f, 0, 1);
|
||||
ptr++;
|
||||
ptr->Set(128.f, -128.f, 128.f, 1, 1);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
|
||||
// west
|
||||
tex = FMaterial::ValidateTexture(sb->faces[3], false);
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
|
||||
gl_RenderState.Apply();
|
||||
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(128.f, 128.f, 128.f, 0, 0);
|
||||
ptr++;
|
||||
ptr->Set(128.f, 128.f, -128.f, 1, 0);
|
||||
ptr++;
|
||||
ptr->Set(128.f, -128.f, 128.f, 0, 1);
|
||||
ptr++;
|
||||
ptr->Set(128.f, -128.f, -128.f, 1, 1);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
}
|
||||
else
|
||||
{
|
||||
faces=1;
|
||||
tex = FMaterial::ValidateTexture(sb->faces[0], false);
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
|
||||
gl_RenderState.Apply();
|
||||
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(128.f, 128.f, -128.f, 0, 0);
|
||||
ptr++;
|
||||
ptr->Set(128.f, -128.f, -128.f, 0, 1);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, 128.f, -128.f, 0.25f, 0);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, -128.f, -128.f, 0.25f, 1);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, 128.f, 128.f, 0.5f, 0);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, -128.f, 128.f, 0.5f, 1);
|
||||
ptr++;
|
||||
ptr->Set(128.f, 128.f, 128.f, 0.75f, 0);
|
||||
ptr++;
|
||||
ptr->Set(128.f, -128.f, 128.f, 0.75f, 1);
|
||||
ptr++;
|
||||
ptr->Set(128.f, 128.f, -128.f, 1, 0);
|
||||
ptr++;
|
||||
ptr->Set(128.f, -128.f, -128.f, 1, 1);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
}
|
||||
|
||||
// top
|
||||
tex = FMaterial::ValidateTexture(sb->faces[faces], false);
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
|
||||
gl_RenderState.Apply();
|
||||
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(128.f, 128.f, -128.f, 0, sb->fliptop);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, 128.f, -128.f, 1, sb->fliptop);
|
||||
ptr++;
|
||||
ptr->Set(128.f, 128.f, 128.f, 0, !sb->fliptop);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, 128.f, 128.f, 1, !sb->fliptop);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
|
||||
// bottom
|
||||
tex = FMaterial::ValidateTexture(sb->faces[faces+1], false);
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
|
||||
gl_RenderState.Apply();
|
||||
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(128.f, -128.f, -128.f, 0, 0);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, -128.f, -128.f, 1, 0);
|
||||
ptr++;
|
||||
ptr->Set(128.f, -128.f, 128.f, 0, 1);
|
||||
ptr++;
|
||||
ptr->Set(-128.f, -128.f, 128.f, 1, 1);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
gl_RenderState.EnableModelMatrix(false);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void GLSkyPortal::DrawContents()
|
||||
{
|
||||
bool drawBoth = false;
|
||||
|
||||
// We have no use for Doom lighting special handling here, so disable it for this function.
|
||||
int oldlightmode = glset.lightmode;
|
||||
if (glset.lightmode == 8)
|
||||
{
|
||||
glset.lightmode = 2;
|
||||
gl_RenderState.SetSoftLightLevel(-1);
|
||||
}
|
||||
|
||||
|
||||
gl_RenderState.ResetColor();
|
||||
gl_RenderState.EnableFog(false);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
bool oldClamp = gl_RenderState.SetDepthClamp(true);
|
||||
|
||||
gl_MatrixStack.Push(gl_RenderState.mViewMatrix);
|
||||
GLRenderer->SetupView(0, 0, 0, viewangle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));
|
||||
|
||||
if (origin->texture[0] && origin->texture[0]->tex->gl_info.bSkybox)
|
||||
{
|
||||
RenderBox(origin->skytexno1, origin->texture[0], origin->x_offset[0], origin->sky2);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_RenderState.SetVertexBuffer(GLRenderer->mSkyVBO);
|
||||
if (origin->texture[0]==origin->texture[1] && origin->doublesky) origin->doublesky=false;
|
||||
|
||||
if (origin->texture[0])
|
||||
{
|
||||
gl_RenderState.SetTextureMode(TM_OPAQUE);
|
||||
RenderDome(origin->texture[0], origin->x_offset[0], origin->y_offset, origin->mirrored, FSkyVertexBuffer::SKYMODE_MAINLAYER);
|
||||
gl_RenderState.SetTextureMode(TM_MODULATE);
|
||||
}
|
||||
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.05f);
|
||||
|
||||
if (origin->doublesky && origin->texture[1])
|
||||
{
|
||||
RenderDome(origin->texture[1], origin->x_offset[1], origin->y_offset, false, FSkyVertexBuffer::SKYMODE_SECONDLAYER);
|
||||
}
|
||||
|
||||
if (skyfog>0 && gl_fixedcolormap == CM_DEFAULT && (origin->fadecolor & 0xffffff) != 0)
|
||||
{
|
||||
PalEntry FadeColor = origin->fadecolor;
|
||||
FadeColor.a = clamp<int>(skyfog, 0, 255);
|
||||
|
||||
gl_RenderState.EnableTexture(false);
|
||||
gl_RenderState.SetObjectColor(FadeColor);
|
||||
gl_RenderState.Apply();
|
||||
glDrawArrays(GL_TRIANGLES, 0, 12);
|
||||
gl_RenderState.EnableTexture(true);
|
||||
gl_RenderState.SetObjectColor(0xffffffff);
|
||||
}
|
||||
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
|
||||
}
|
||||
gl_MatrixStack.Pop(gl_RenderState.mViewMatrix);
|
||||
gl_RenderState.ApplyMatrices();
|
||||
glset.lightmode = oldlightmode;
|
||||
gl_RenderState.SetDepthClamp(oldClamp);
|
||||
}
|
||||
|
975
src/gl/scene/gl_sprite.cpp
Normal file
975
src/gl/scene/gl_sprite.cpp
Normal file
|
@ -0,0 +1,975 @@
|
|||
/*
|
||||
** gl_sprite.cpp
|
||||
** Sprite/Particle rendering
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "p_local.h"
|
||||
#include "p_effect.h"
|
||||
#include "g_level.h"
|
||||
#include "doomstat.h"
|
||||
#include "gl/gl_functions.h"
|
||||
#include "r_defs.h"
|
||||
#include "r_sky.h"
|
||||
#include "r_utility.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/dynlights/gl_glow.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
|
||||
CVAR(Bool, gl_usecolorblending, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR(Bool, gl_spritebrightfog, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
CVAR(Bool, gl_sprite_blend, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
CVAR(Int, gl_spriteclip, 1, CVAR_ARCHIVE)
|
||||
CVAR(Float, gl_sclipthreshold, 10.0, CVAR_ARCHIVE)
|
||||
CVAR(Float, gl_sclipfactor, 1.8, CVAR_ARCHIVE)
|
||||
CVAR(Int, gl_particles_style, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // 0 = square, 1 = round, 2 = smooth
|
||||
CVAR(Int, gl_billboard_mode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Bool, gl_billboard_particles, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Int, gl_enhanced_nv_stealth, 3, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CUSTOM_CVAR(Int, gl_fuzztype, 0, CVAR_ARCHIVE)
|
||||
{
|
||||
if (self < 0 || self > 7) self = 0;
|
||||
}
|
||||
|
||||
extern bool r_showviewer;
|
||||
EXTERN_CVAR (Float, transsouls)
|
||||
|
||||
extern TArray<spritedef_t> sprites;
|
||||
extern TArray<spriteframe_t> SpriteFrames;
|
||||
extern TArray<PalEntry> BloodTranslationColors;
|
||||
|
||||
enum HWRenderStyle
|
||||
{
|
||||
STYLEHW_Normal, // default
|
||||
STYLEHW_Solid, // drawn solid (needs special treatment for sprites)
|
||||
STYLEHW_NoAlphaTest, // disable alpha test
|
||||
};
|
||||
|
||||
|
||||
void gl_SetRenderStyle(FRenderStyle style, bool drawopaque, bool allowcolorblending)
|
||||
{
|
||||
int tm, sb, db, be;
|
||||
|
||||
gl_GetRenderStyle(style, drawopaque, allowcolorblending, &tm, &sb, &db, &be);
|
||||
gl_RenderState.BlendEquation(be);
|
||||
gl_RenderState.BlendFunc(sb, db);
|
||||
gl_RenderState.SetTextureMode(tm);
|
||||
}
|
||||
|
||||
CVAR(Bool, gl_nolayer, false, 0)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void GLSprite::Draw(int pass)
|
||||
{
|
||||
if (pass == GLPASS_DECALS || pass == GLPASS_LIGHTSONLY) return;
|
||||
|
||||
|
||||
|
||||
bool additivefog = false;
|
||||
bool foglayer = false;
|
||||
int rel = fullbright? 0 : getExtraLight();
|
||||
|
||||
if (pass==GLPASS_TRANSLUCENT)
|
||||
{
|
||||
// The translucent pass requires special setup for the various modes.
|
||||
|
||||
// for special render styles brightmaps would not look good - especially for subtractive.
|
||||
if (RenderStyle.BlendOp != STYLEOP_Add)
|
||||
{
|
||||
gl_RenderState.EnableBrightmap(false);
|
||||
}
|
||||
|
||||
gl_SetRenderStyle(RenderStyle, false,
|
||||
// The rest of the needed checks are done inside gl_SetRenderStyle
|
||||
trans > 1.f - FLT_EPSILON && gl_usecolorblending && gl_fixedcolormap == CM_DEFAULT && actor &&
|
||||
fullbright && gltexture && !gltexture->GetTransparent());
|
||||
|
||||
if (hw_styleflags == STYLEHW_NoAlphaTest)
|
||||
{
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold);
|
||||
}
|
||||
|
||||
if (RenderStyle.BlendOp == STYLEOP_Shadow)
|
||||
{
|
||||
float fuzzalpha=0.44f;
|
||||
float minalpha=0.1f;
|
||||
|
||||
// fog + fuzz don't work well without some fiddling with the alpha value!
|
||||
if (!gl_isBlack(Colormap.FadeColor))
|
||||
{
|
||||
float xcamera=FIXED2FLOAT(viewx);
|
||||
float ycamera=FIXED2FLOAT(viewy);
|
||||
|
||||
float dist=Dist2(xcamera,ycamera, x,y);
|
||||
|
||||
if (!Colormap.FadeColor.a) Colormap.FadeColor.a=clamp<int>(255-lightlevel,60,255);
|
||||
|
||||
// this value was determined by trial and error and is scale dependent!
|
||||
float factor=0.05f+exp(-Colormap.FadeColor.a*dist/62500.f);
|
||||
fuzzalpha*=factor;
|
||||
minalpha*=factor;
|
||||
}
|
||||
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold);
|
||||
gl_RenderState.SetColor(0.2f,0.2f,0.2f,fuzzalpha, Colormap.desaturation);
|
||||
additivefog = true;
|
||||
}
|
||||
else if (RenderStyle.BlendOp == STYLEOP_Add && RenderStyle.DestAlpha == STYLEALPHA_One)
|
||||
{
|
||||
additivefog = true;
|
||||
}
|
||||
}
|
||||
if (RenderStyle.BlendOp!=STYLEOP_Shadow)
|
||||
{
|
||||
if (gl_lights && GLRenderer->mLightCount && !gl_fixedcolormap && !fullbright)
|
||||
{
|
||||
gl_SetDynSpriteLight(gl_light_sprites ? actor : NULL, gl_light_particles ? particle : NULL);
|
||||
}
|
||||
gl_SetColor(lightlevel, rel, Colormap, trans);
|
||||
}
|
||||
gl_RenderState.SetObjectColor(ThingColor);
|
||||
|
||||
if (gl_isBlack(Colormap.FadeColor)) foglevel=lightlevel;
|
||||
|
||||
if (RenderStyle.Flags & STYLEF_FadeToBlack)
|
||||
{
|
||||
Colormap.FadeColor=0;
|
||||
additivefog = true;
|
||||
}
|
||||
|
||||
if (RenderStyle.BlendOp == STYLEOP_RevSub || RenderStyle.BlendOp == STYLEOP_Sub)
|
||||
{
|
||||
if (!modelframe)
|
||||
{
|
||||
// non-black fog with subtractive style needs special treatment
|
||||
if (!gl_isBlack(Colormap.FadeColor))
|
||||
{
|
||||
foglayer = true;
|
||||
// Due to the two-layer approach we need to force an alpha test that lets everything pass
|
||||
gl_RenderState.AlphaFunc(GL_GREATER, 0);
|
||||
}
|
||||
}
|
||||
else RenderStyle.BlendOp = STYLEOP_Fuzz; // subtractive with models is not going to work.
|
||||
}
|
||||
|
||||
if (!foglayer) gl_SetFog(foglevel, rel, &Colormap, additivefog);
|
||||
else
|
||||
{
|
||||
gl_RenderState.EnableFog(false);
|
||||
gl_RenderState.SetFog(0, 0);
|
||||
}
|
||||
|
||||
if (gltexture) gl_RenderState.SetMaterial(gltexture, CLAMP_XY, translation, OverrideShader, !!(RenderStyle.Flags & STYLEF_RedIsAlpha));
|
||||
else if (!modelframe) gl_RenderState.EnableTexture(false);
|
||||
|
||||
if (!modelframe)
|
||||
{
|
||||
// [BB] Billboard stuff
|
||||
const bool drawWithXYBillboard = ( (particle && gl_billboard_particles) || (!(actor && actor->renderflags & RF_FORCEYBILLBOARD)
|
||||
//&& GLRenderer->mViewActor != NULL
|
||||
&& (gl_billboard_mode == 1 || (actor && actor->renderflags & RF_FORCEXYBILLBOARD ))) );
|
||||
gl_RenderState.Apply();
|
||||
|
||||
Vector v1;
|
||||
Vector v2;
|
||||
Vector v3;
|
||||
Vector v4;
|
||||
|
||||
if (drawWithXYBillboard)
|
||||
{
|
||||
// Rotate the sprite about the vector starting at the center of the sprite
|
||||
// triangle strip and with direction orthogonal to where the player is looking
|
||||
// in the x/y plane.
|
||||
float xcenter = (x1 + x2)*0.5;
|
||||
float ycenter = (y1 + y2)*0.5;
|
||||
float zcenter = (z1 + z2)*0.5;
|
||||
float angleRad = DEG2RAD(270. - float(GLRenderer->mAngles.Yaw));
|
||||
|
||||
Matrix3x4 mat;
|
||||
mat.MakeIdentity();
|
||||
mat.Translate(xcenter, zcenter, ycenter);
|
||||
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -GLRenderer->mAngles.Pitch);
|
||||
mat.Translate(-xcenter, -zcenter, -ycenter);
|
||||
v1 = mat * Vector(x1, z1, y1);
|
||||
v2 = mat * Vector(x2, z1, y2);
|
||||
v3 = mat * Vector(x1, z2, y1);
|
||||
v4 = mat * Vector(x2, z2, y2);
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = Vector(x1, z1, y1);
|
||||
v2 = Vector(x2, z1, y2);
|
||||
v3 = Vector(x1, z2, y1);
|
||||
v4 = Vector(x2, z2, y2);
|
||||
}
|
||||
|
||||
FFlatVertex *ptr;
|
||||
unsigned int offset, count;
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(v1[0], v1[1], v1[2], ul, vt);
|
||||
ptr++;
|
||||
ptr->Set(v2[0], v2[1], v2[2], ur, vt);
|
||||
ptr++;
|
||||
ptr->Set(v3[0], v3[1], v3[2], ul, vb);
|
||||
ptr++;
|
||||
ptr->Set(v4[0], v4[1], v4[2], ur, vb);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP, &offset, &count);
|
||||
|
||||
if (foglayer)
|
||||
{
|
||||
// If we get here we know that we have colored fog and no fixed colormap.
|
||||
gl_SetFog(foglevel, rel, &Colormap, additivefog);
|
||||
gl_RenderState.SetFixedColormap(CM_FOGLAYER);
|
||||
gl_RenderState.BlendEquation(GL_FUNC_ADD);
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
gl_RenderState.Apply();
|
||||
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count);
|
||||
gl_RenderState.SetFixedColormap(CM_DEFAULT);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_RenderModel(this);
|
||||
}
|
||||
|
||||
if (pass==GLPASS_TRANSLUCENT)
|
||||
{
|
||||
gl_RenderState.EnableBrightmap(true);
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
gl_RenderState.BlendEquation(GL_FUNC_ADD);
|
||||
gl_RenderState.SetTextureMode(TM_MODULATE);
|
||||
}
|
||||
|
||||
gl_RenderState.SetObjectColor(0xffffffff);
|
||||
gl_RenderState.EnableTexture(true);
|
||||
gl_RenderState.SetDynLight(0,0,0);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
inline void GLSprite::PutSprite(bool translucent)
|
||||
{
|
||||
int list;
|
||||
// [BB] Allow models to be drawn in the GLDL_TRANSLUCENT pass.
|
||||
if (translucent || !modelframe)
|
||||
{
|
||||
list = GLDL_TRANSLUCENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
list = GLDL_MODELS;
|
||||
}
|
||||
gl_drawinfo->drawlists[list].AddSprite(this);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void GLSprite::SplitSprite(sector_t * frontsector, bool translucent)
|
||||
{
|
||||
GLSprite copySprite;
|
||||
fixed_t lightbottom;
|
||||
float maplightbottom;
|
||||
unsigned int i;
|
||||
bool put=false;
|
||||
TArray<lightlist_t> & lightlist=frontsector->e->XFloor.lightlist;
|
||||
|
||||
for(i=0;i<lightlist.Size();i++)
|
||||
{
|
||||
// Particles don't go through here so we can safely assume that actor is not NULL
|
||||
if (i<lightlist.Size()-1) lightbottom=lightlist[i+1].plane.ZatPoint(actor->x,actor->y);
|
||||
else lightbottom=frontsector->floorplane.ZatPoint(actor->x,actor->y);
|
||||
|
||||
maplightbottom=FIXED2FLOAT(lightbottom);
|
||||
if (maplightbottom<z2) maplightbottom=z2;
|
||||
|
||||
if (maplightbottom<z1)
|
||||
{
|
||||
copySprite=*this;
|
||||
copySprite.lightlevel = gl_ClampLight(*lightlist[i].p_lightlevel);
|
||||
copySprite.Colormap.CopyLightColor(lightlist[i].extra_colormap);
|
||||
|
||||
if (glset.nocoloredspritelighting)
|
||||
{
|
||||
int v = (copySprite.Colormap.LightColor.r + copySprite.Colormap.LightColor.g + copySprite.Colormap.LightColor.b )/3;
|
||||
copySprite.Colormap.LightColor.r=
|
||||
copySprite.Colormap.LightColor.g=
|
||||
copySprite.Colormap.LightColor.b=(255+v+v)/3;
|
||||
}
|
||||
|
||||
z1=copySprite.z2=maplightbottom;
|
||||
vt=copySprite.vb=copySprite.vt+
|
||||
(maplightbottom-copySprite.z1)*(copySprite.vb-copySprite.vt)/(z2-copySprite.z1);
|
||||
copySprite.PutSprite(translucent);
|
||||
put=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLSprite::SetSpriteColor(sector_t *sector, fixed_t center_y)
|
||||
{
|
||||
fixed_t lightbottom;
|
||||
float maplightbottom;
|
||||
unsigned int i;
|
||||
TArray<lightlist_t> & lightlist=actor->Sector->e->XFloor.lightlist;
|
||||
|
||||
for(i=0;i<lightlist.Size();i++)
|
||||
{
|
||||
// Particles don't go through here so we can safely assume that actor is not NULL
|
||||
if (i<lightlist.Size()-1) lightbottom=lightlist[i+1].plane.ZatPoint(actor->x,actor->y);
|
||||
else lightbottom=sector->floorplane.ZatPoint(actor->x,actor->y);
|
||||
|
||||
//maplighttop=FIXED2FLOAT(lightlist[i].height);
|
||||
maplightbottom=FIXED2FLOAT(lightbottom);
|
||||
if (maplightbottom<z2) maplightbottom=z2;
|
||||
|
||||
if (maplightbottom<center_y)
|
||||
{
|
||||
lightlevel=*lightlist[i].p_lightlevel;
|
||||
Colormap.CopyLightColor(lightlist[i].extra_colormap);
|
||||
|
||||
if (glset.nocoloredspritelighting)
|
||||
{
|
||||
int v = (Colormap.LightColor.r + Colormap.LightColor.g + Colormap.LightColor.b )/3;
|
||||
Colormap.LightColor.r=
|
||||
Colormap.LightColor.g=
|
||||
Colormap.LightColor.b=(255+v+v)/3;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLSprite::PerformSpriteClipAdjustment(AActor *thing, fixed_t thingx, fixed_t thingy, float spriteheight)
|
||||
{
|
||||
bool smarterclip = false; // Set to true if one condition triggers the test below
|
||||
if (((thing->player || thing->flags3&MF3_ISMONSTER ||
|
||||
thing->IsKindOf(RUNTIME_CLASS(AInventory))) && (thing->flags&MF_ICECORPSE ||
|
||||
!(thing->flags&MF_CORPSE))) || (gl_spriteclip == 3 && (smarterclip = true)) || gl_spriteclip > 1)
|
||||
{
|
||||
float btm = 1000000.0f;
|
||||
float top = -1000000.0f;
|
||||
extsector_t::xfloor &x = thing->Sector->e->XFloor;
|
||||
|
||||
if (x.ffloors.Size())
|
||||
{
|
||||
for (unsigned int i = 0; i < x.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor * ff = x.ffloors[i];
|
||||
fixed_t floorh = ff->top.plane->ZatPoint(thingx, thingy);
|
||||
fixed_t ceilingh = ff->bottom.plane->ZatPoint(thingx, thingy);
|
||||
if (floorh == thing->floorz)
|
||||
{
|
||||
btm = FIXED2FLOAT(floorh);
|
||||
}
|
||||
if (ceilingh == thing->ceilingz)
|
||||
{
|
||||
top = FIXED2FLOAT(ceilingh);
|
||||
}
|
||||
if (btm != 1000000.0f && top != -1000000.0f)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (thing->Sector->heightsec && !(thing->Sector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC))
|
||||
{
|
||||
if (thing->flags2&MF2_ONMOBJ && thing->floorz ==
|
||||
thing->Sector->heightsec->floorplane.ZatPoint(thingx, thingy))
|
||||
{
|
||||
btm = FIXED2FLOAT(thing->floorz);
|
||||
top = FIXED2FLOAT(thing->ceilingz);
|
||||
}
|
||||
}
|
||||
if (btm == 1000000.0f)
|
||||
btm = FIXED2FLOAT(thing->Sector->floorplane.ZatPoint(thingx, thingy) - thing->floorclip);
|
||||
if (top == -1000000.0f)
|
||||
top = FIXED2FLOAT(thing->Sector->ceilingplane.ZatPoint(thingx, thingy));
|
||||
|
||||
// +/-1 to account for the one pixel empty frame around the sprite.
|
||||
float diffb = (z2+1) - btm;
|
||||
float difft = (z1-1) - top;
|
||||
if (diffb >= 0 /*|| !gl_sprite_clip_to_floor*/) diffb = 0;
|
||||
// Adjust sprites clipping into ceiling and adjust clipping adjustment for tall graphics
|
||||
if (smarterclip)
|
||||
{
|
||||
// Reduce slightly clipping adjustment of corpses
|
||||
if (thing->flags & MF_CORPSE || spriteheight > fabs(diffb))
|
||||
{
|
||||
float ratio = clamp<float>((fabs(diffb) * (float)gl_sclipfactor / (spriteheight + 1)), 0.5, 1.0);
|
||||
diffb *= ratio;
|
||||
}
|
||||
if (!diffb)
|
||||
{
|
||||
if (difft <= 0) difft = 0;
|
||||
if (difft >= (float)gl_sclipthreshold)
|
||||
{
|
||||
// dumb copy of the above.
|
||||
if (!(thing->flags3&MF3_ISMONSTER) || (thing->flags&MF_NOGRAVITY) || (thing->flags&MF_CORPSE) || difft > (float)gl_sclipthreshold)
|
||||
{
|
||||
difft = 0;
|
||||
}
|
||||
}
|
||||
if (spriteheight > fabs(difft))
|
||||
{
|
||||
float ratio = clamp<float>((fabs(difft) * (float)gl_sclipfactor / (spriteheight + 1)), 0.5, 1.0);
|
||||
difft *= ratio;
|
||||
}
|
||||
z2 -= difft;
|
||||
z1 -= difft;
|
||||
}
|
||||
}
|
||||
if (diffb <= (0 - (float)gl_sclipthreshold)) // such a large displacement can't be correct!
|
||||
{
|
||||
// for living monsters standing on the floor allow a little more.
|
||||
if (!(thing->flags3&MF3_ISMONSTER) || (thing->flags&MF_NOGRAVITY) || (thing->flags&MF_CORPSE) || diffb < (-1.8*(float)gl_sclipthreshold))
|
||||
{
|
||||
diffb = 0;
|
||||
}
|
||||
}
|
||||
z2 -= diffb;
|
||||
z1 -= diffb;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLSprite::Process(AActor* thing,sector_t * sector)
|
||||
{
|
||||
sector_t rs;
|
||||
sector_t * rendersector;
|
||||
// don't draw the thing that's used as camera (for viewshifts during quakes!)
|
||||
if (thing==GLRenderer->mViewActor) return;
|
||||
|
||||
// Don't waste time projecting sprites that are definitely not visible.
|
||||
if (thing == NULL || thing->sprite == 0 || !thing->IsVisibleToPlayer())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int spritenum = thing->sprite;
|
||||
fixed_t spritescaleX = thing->scaleX;
|
||||
fixed_t spritescaleY = thing->scaleY;
|
||||
if (thing->player != NULL)
|
||||
{
|
||||
P_CheckPlayerSprite(thing, spritenum, spritescaleX, spritescaleY);
|
||||
}
|
||||
|
||||
if (thing->renderflags & RF_INVISIBLE || !thing->RenderStyle.IsVisible(thing->alpha))
|
||||
{
|
||||
if (!(thing->flags & MF_STEALTH) || !gl_fixedcolormap || !gl_enhanced_nightvision)
|
||||
return;
|
||||
}
|
||||
|
||||
// If this thing is in a map section that's not in view it can't possibly be visible
|
||||
if (!(currentmapsection[thing->subsector->mapsection>>3] & (1 << (thing->subsector->mapsection & 7)))) return;
|
||||
|
||||
// [RH] Interpolate the sprite's position to make it look smooth
|
||||
fixed_t thingx = thing->PrevX + FixedMul (r_TicFrac, thing->x - thing->PrevX);
|
||||
fixed_t thingy = thing->PrevY + FixedMul (r_TicFrac, thing->y - thing->PrevY);
|
||||
fixed_t thingz = thing->PrevZ + FixedMul (r_TicFrac, thing->z - thing->PrevZ);
|
||||
|
||||
// Too close to the camera. This doesn't look good if it is a sprite.
|
||||
if (P_AproxDistance(thingx-viewx, thingy-viewy)<2*FRACUNIT)
|
||||
{
|
||||
// exclude vertically moving objects from this check.
|
||||
if (!(thing->velx==0 && thing->vely==0 && thing->velz!=0))
|
||||
{
|
||||
if (!gl_FindModelFrame(RUNTIME_TYPE(thing), spritenum, thing->frame, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't draw first frame of a player missile
|
||||
if (thing->flags&MF_MISSILE && thing->target==GLRenderer->mViewActor && GLRenderer->mViewActor != NULL)
|
||||
{
|
||||
if (P_AproxDistance(thingx-viewx, thingy-viewy) < thing->Speed ) return;
|
||||
}
|
||||
|
||||
if (GLRenderer->mCurrentPortal)
|
||||
{
|
||||
int clipres = GLRenderer->mCurrentPortal->ClipPoint(thingx, thingy);
|
||||
if (clipres == GLPortal::PClip_InFront) return;
|
||||
}
|
||||
|
||||
player_t *player=&players[consoleplayer];
|
||||
FloatRect r;
|
||||
|
||||
if (sector->sectornum!=thing->Sector->sectornum)
|
||||
{
|
||||
rendersector=gl_FakeFlat(thing->Sector, &rs, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
rendersector=sector;
|
||||
}
|
||||
|
||||
|
||||
x = FIXED2FLOAT(thingx);
|
||||
z = FIXED2FLOAT(thingz-thing->floorclip);
|
||||
y = FIXED2FLOAT(thingy);
|
||||
|
||||
// [RH] Make floatbobbing a renderer-only effect.
|
||||
if (thing->flags2 & MF2_FLOATBOB)
|
||||
{
|
||||
float fz = FIXED2FLOAT(thing->GetBobOffset(r_TicFrac));
|
||||
z += fz;
|
||||
}
|
||||
|
||||
modelframe = gl_FindModelFrame(RUNTIME_TYPE(thing), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
|
||||
if (!modelframe)
|
||||
{
|
||||
angle_t ang = R_PointToAngle(thingx, thingy);
|
||||
|
||||
bool mirror;
|
||||
FTextureID patch = gl_GetSpriteFrame(spritenum, thing->frame, -1, ang - thing->angle, &mirror);
|
||||
if (!patch.isValid()) return;
|
||||
int type = thing->renderflags & RF_SPRITETYPEMASK;
|
||||
gltexture = FMaterial::ValidateTexture(patch, (type == RF_FACESPRITE), false);
|
||||
if (!gltexture) return;
|
||||
|
||||
vt = gltexture->GetSpriteVT();
|
||||
vb = gltexture->GetSpriteVB();
|
||||
gltexture->GetSpriteRect(&r);
|
||||
if (mirror)
|
||||
{
|
||||
r.left = -r.width - r.left; // mirror the sprite's x-offset
|
||||
ul = gltexture->GetSpriteUL();
|
||||
ur = gltexture->GetSpriteUR();
|
||||
}
|
||||
else
|
||||
{
|
||||
ul = gltexture->GetSpriteUR();
|
||||
ur = gltexture->GetSpriteUL();
|
||||
}
|
||||
|
||||
r.Scale(FIXED2FLOAT(spritescaleX), FIXED2FLOAT(spritescaleY));
|
||||
|
||||
float rightfac = -r.left;
|
||||
float leftfac = rightfac - r.width;
|
||||
|
||||
z1 = z - r.top;
|
||||
z2 = z1 - r.height;
|
||||
|
||||
float spriteheight = FIXED2FLOAT(spritescaleY) * r.height;
|
||||
|
||||
// Tests show that this doesn't look good for many decorations and corpses
|
||||
if (spriteheight > 0 && gl_spriteclip > 0 && (thing->renderflags & RF_SPRITETYPEMASK) == RF_FACESPRITE)
|
||||
{
|
||||
PerformSpriteClipAdjustment(thing, thingx, thingy, spriteheight);
|
||||
}
|
||||
|
||||
float viewvecX;
|
||||
float viewvecY;
|
||||
switch (thing->renderflags & RF_SPRITETYPEMASK)
|
||||
{
|
||||
case RF_FACESPRITE:
|
||||
viewvecX = GLRenderer->mViewVector.X;
|
||||
viewvecY = GLRenderer->mViewVector.Y;
|
||||
|
||||
x1 = x - viewvecY*leftfac;
|
||||
x2 = x - viewvecY*rightfac;
|
||||
y1 = y + viewvecX*leftfac;
|
||||
y2 = y + viewvecX*rightfac;
|
||||
break;
|
||||
|
||||
case RF_WALLSPRITE:
|
||||
viewvecX = FIXED2FLOAT(finecosine[thing->angle >> ANGLETOFINESHIFT]);
|
||||
viewvecY = FIXED2FLOAT(finesine[thing->angle >> ANGLETOFINESHIFT]);
|
||||
|
||||
x1 = x + viewvecY*leftfac;
|
||||
x2 = x + viewvecY*rightfac;
|
||||
y1 = y - viewvecX*leftfac;
|
||||
y2 = y - viewvecX*rightfac;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x1 = x2 = x;
|
||||
y1 = y2 = y;
|
||||
z1 = z2 = z;
|
||||
gltexture=NULL;
|
||||
}
|
||||
|
||||
depth = DMulScale20 (thing->x-viewx, viewtancos, thing->y-viewy, viewtansin);
|
||||
|
||||
// light calculation
|
||||
|
||||
bool enhancedvision=false;
|
||||
|
||||
// allow disabling of the fullbright flag by a brightmap definition
|
||||
// (e.g. to do the gun flashes of Doom's zombies correctly.
|
||||
fullbright = (thing->flags5 & MF5_BRIGHT) ||
|
||||
((thing->renderflags & RF_FULLBRIGHT) && (!gltexture || !gltexture->tex->gl_info.bDisableFullbright));
|
||||
|
||||
lightlevel=fullbright? 255 :
|
||||
gl_ClampLight(rendersector->GetTexture(sector_t::ceiling) == skyflatnum ?
|
||||
rendersector->GetCeilingLight() : rendersector->GetFloorLight());
|
||||
foglevel = (BYTE)clamp<short>(rendersector->lightlevel, 0, 255);
|
||||
|
||||
lightlevel = (byte)gl_CheckSpriteGlow(rendersector, lightlevel, thingx, thingy, thingz);
|
||||
|
||||
ThingColor = (thing->RenderStyle.Flags & STYLEF_ColorIsFixed) ? thing->fillcolor : 0xffffff;
|
||||
ThingColor.a = 255;
|
||||
RenderStyle = thing->RenderStyle;
|
||||
|
||||
// colormap stuff is a little more complicated here...
|
||||
if (gl_fixedcolormap)
|
||||
{
|
||||
if ((gl_enhanced_nv_stealth > 0 && gl_fixedcolormap == CM_LITE) // Infrared powerup only
|
||||
|| (gl_enhanced_nv_stealth == 2 && gl_fixedcolormap >= CM_TORCH)// Also torches
|
||||
|| (gl_enhanced_nv_stealth == 3)) // Any fixed colormap
|
||||
enhancedvision=true;
|
||||
|
||||
Colormap.Clear();
|
||||
|
||||
if (gl_fixedcolormap==CM_LITE)
|
||||
{
|
||||
if (gl_enhanced_nightvision &&
|
||||
(thing->IsKindOf(RUNTIME_CLASS(AInventory)) || thing->flags3&MF3_ISMONSTER || thing->flags&MF_MISSILE || thing->flags&MF_CORPSE))
|
||||
{
|
||||
RenderStyle.Flags |= STYLEF_InvertSource;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Colormap=rendersector->ColorMap;
|
||||
if (fullbright)
|
||||
{
|
||||
if (rendersector == §ors[rendersector->sectornum] || in_area != area_below)
|
||||
// under water areas keep their color for fullbright objects
|
||||
{
|
||||
// Only make the light white but keep everything else (fog, desaturation and Boom colormap.)
|
||||
Colormap.LightColor.r=
|
||||
Colormap.LightColor.g=
|
||||
Colormap.LightColor.b=0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
Colormap.LightColor.r = (3*Colormap.LightColor.r + 0xff)/4;
|
||||
Colormap.LightColor.g = (3*Colormap.LightColor.g + 0xff)/4;
|
||||
Colormap.LightColor.b = (3*Colormap.LightColor.b + 0xff)/4;
|
||||
}
|
||||
}
|
||||
else if (glset.nocoloredspritelighting)
|
||||
{
|
||||
Colormap.Decolorize();
|
||||
}
|
||||
}
|
||||
|
||||
translation=thing->Translation;
|
||||
|
||||
OverrideShader = -1;
|
||||
trans = FIXED2FLOAT(thing->alpha);
|
||||
hw_styleflags = STYLEHW_Normal;
|
||||
|
||||
if (RenderStyle.BlendOp >= STYLEOP_Fuzz && RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub)
|
||||
{
|
||||
RenderStyle.CheckFuzz();
|
||||
if (RenderStyle.BlendOp == STYLEOP_Fuzz)
|
||||
{
|
||||
if (gl_fuzztype != 0)
|
||||
{
|
||||
// Todo: implement shader selection here
|
||||
RenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
||||
OverrideShader = gl_fuzztype + 4;
|
||||
trans = 0.99f; // trans may not be 1 here
|
||||
hw_styleflags |= STYLEHW_NoAlphaTest;
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderStyle.BlendOp = STYLEOP_Shadow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (RenderStyle.Flags & STYLEF_TransSoulsAlpha)
|
||||
{
|
||||
trans = transsouls;
|
||||
}
|
||||
else if (RenderStyle.Flags & STYLEF_Alpha1)
|
||||
{
|
||||
trans = 1.f;
|
||||
}
|
||||
|
||||
if (trans >= 1.f-FLT_EPSILON && RenderStyle.BlendOp != STYLEOP_Shadow && (
|
||||
(RenderStyle.SrcAlpha == STYLEALPHA_One && RenderStyle.DestAlpha == STYLEALPHA_Zero) ||
|
||||
(RenderStyle.SrcAlpha == STYLEALPHA_Src && RenderStyle.DestAlpha == STYLEALPHA_InvSrc)
|
||||
))
|
||||
{
|
||||
// This is a non-translucent sprite (i.e. STYLE_Normal or equivalent)
|
||||
trans=1.f;
|
||||
|
||||
|
||||
if (!gl_sprite_blend || modelframe)
|
||||
{
|
||||
RenderStyle.SrcAlpha = STYLEALPHA_One;
|
||||
RenderStyle.DestAlpha = STYLEALPHA_Zero;
|
||||
hw_styleflags = STYLEHW_Solid;
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderStyle.SrcAlpha = STYLEALPHA_Src;
|
||||
RenderStyle.DestAlpha = STYLEALPHA_InvSrc;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if ((gltexture && gltexture->GetTransparent()) || (RenderStyle.Flags & STYLEF_RedIsAlpha))
|
||||
{
|
||||
if (hw_styleflags == STYLEHW_Solid)
|
||||
{
|
||||
RenderStyle.SrcAlpha = STYLEALPHA_Src;
|
||||
RenderStyle.DestAlpha = STYLEALPHA_InvSrc;
|
||||
}
|
||||
hw_styleflags = STYLEHW_NoAlphaTest;
|
||||
}
|
||||
|
||||
if (enhancedvision && gl_enhanced_nightvision)
|
||||
{
|
||||
if (RenderStyle.BlendOp == STYLEOP_Shadow)
|
||||
{
|
||||
// enhanced vision makes them more visible!
|
||||
trans=0.5f;
|
||||
FRenderStyle rs = RenderStyle;
|
||||
RenderStyle = STYLE_Translucent;
|
||||
RenderStyle.Flags = rs.Flags; // Flags must be preserved, at this point it can only be STYLEF_InvertSource
|
||||
}
|
||||
else if (thing->flags & MF_STEALTH)
|
||||
{
|
||||
// enhanced vision overcomes stealth!
|
||||
if (trans < 0.5f) trans = 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
if (trans==0.0f) return;
|
||||
|
||||
// end of light calculation
|
||||
|
||||
actor=thing;
|
||||
index = GLRenderer->gl_spriteindex++;
|
||||
particle=NULL;
|
||||
|
||||
const bool drawWithXYBillboard = ( !(actor->renderflags & RF_FORCEYBILLBOARD)
|
||||
&& (actor->renderflags & RF_SPRITETYPEMASK) == RF_FACESPRITE
|
||||
&& players[consoleplayer].camera
|
||||
&& (gl_billboard_mode == 1 || actor->renderflags & RF_FORCEXYBILLBOARD ) );
|
||||
|
||||
|
||||
if (drawWithXYBillboard || modelframe)
|
||||
{
|
||||
if (!gl_fixedcolormap && !fullbright) SetSpriteColor(actor->Sector, actor->y + (actor->height>>1));
|
||||
PutSprite(hw_styleflags != STYLEHW_Solid);
|
||||
}
|
||||
else if (thing->Sector->e->XFloor.lightlist.Size()==0 || gl_fixedcolormap || fullbright)
|
||||
{
|
||||
PutSprite(hw_styleflags != STYLEHW_Solid);
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitSprite(thing->Sector, hw_styleflags != STYLEHW_Solid);
|
||||
}
|
||||
rendered_sprites++;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLSprite::ProcessParticle (particle_t *particle, sector_t *sector)//, int shade, int fakeside)
|
||||
{
|
||||
if (GLRenderer->mCurrentPortal)
|
||||
{
|
||||
int clipres = GLRenderer->mCurrentPortal->ClipPoint(particle->x, particle->y);
|
||||
if (clipres == GLPortal::PClip_InFront) return;
|
||||
}
|
||||
|
||||
player_t *player=&players[consoleplayer];
|
||||
|
||||
if (particle->trans==0) return;
|
||||
|
||||
lightlevel = gl_ClampLight(sector->GetTexture(sector_t::ceiling) == skyflatnum ?
|
||||
sector->GetCeilingLight() : sector->GetFloorLight());
|
||||
foglevel = sector->lightlevel;
|
||||
|
||||
if (gl_fixedcolormap)
|
||||
{
|
||||
Colormap.Clear();
|
||||
}
|
||||
else if (!particle->bright)
|
||||
{
|
||||
TArray<lightlist_t> & lightlist=sector->e->XFloor.lightlist;
|
||||
int lightbottom;
|
||||
|
||||
Colormap = sector->ColorMap;
|
||||
for(unsigned int i=0;i<lightlist.Size();i++)
|
||||
{
|
||||
if (i<lightlist.Size()-1) lightbottom = lightlist[i+1].plane.ZatPoint(particle->x,particle->y);
|
||||
else lightbottom = sector->floorplane.ZatPoint(particle->x,particle->y);
|
||||
|
||||
if (lightbottom < particle->y)
|
||||
{
|
||||
lightlevel = *lightlist[i].p_lightlevel;
|
||||
Colormap.LightColor = (lightlist[i].extra_colormap)->Color;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lightlevel = 255;
|
||||
Colormap = sector->ColorMap;
|
||||
Colormap.ClearColor();
|
||||
}
|
||||
|
||||
trans=particle->trans/255.0f;
|
||||
RenderStyle = STYLE_Translucent;
|
||||
OverrideShader = 0;
|
||||
|
||||
ThingColor = particle->color;
|
||||
ThingColor.a = 255;
|
||||
|
||||
modelframe=NULL;
|
||||
gltexture=NULL;
|
||||
|
||||
// [BB] Load the texture for round or smooth particles
|
||||
if (gl_particles_style)
|
||||
{
|
||||
FTexture *lump = NULL;
|
||||
if (gl_particles_style == 1)
|
||||
{
|
||||
lump = GLRenderer->glpart2;
|
||||
}
|
||||
else if (gl_particles_style == 2)
|
||||
{
|
||||
lump = GLRenderer->glpart;
|
||||
}
|
||||
|
||||
if (lump != NULL)
|
||||
{
|
||||
gltexture = FMaterial::ValidateTexture(lump, true);
|
||||
translation = 0;
|
||||
|
||||
ul = gltexture->GetUL();
|
||||
ur = gltexture->GetUR();
|
||||
vt = gltexture->GetVT();
|
||||
vb = gltexture->GetVB();
|
||||
FloatRect r;
|
||||
gltexture->GetSpriteRect(&r);
|
||||
}
|
||||
}
|
||||
|
||||
x= FIXED2FLOAT(particle->x);
|
||||
y= FIXED2FLOAT(particle->y);
|
||||
z= FIXED2FLOAT(particle->z);
|
||||
|
||||
float scalefac=particle->size/4.0f;
|
||||
// [BB] The smooth particles are smaller than the other ones. Compensate for this here.
|
||||
if (gl_particles_style==2)
|
||||
scalefac *= 1.7;
|
||||
|
||||
float viewvecX = GLRenderer->mViewVector.X;
|
||||
float viewvecY = GLRenderer->mViewVector.Y;
|
||||
|
||||
x1=x+viewvecY*scalefac;
|
||||
x2=x-viewvecY*scalefac;
|
||||
y1=y-viewvecX*scalefac;
|
||||
y2=y+viewvecX*scalefac;
|
||||
z1=z-scalefac;
|
||||
z2=z+scalefac;
|
||||
|
||||
depth = DMulScale20 (particle->x-viewx, viewtancos, particle->y-viewy, viewtansin);
|
||||
|
||||
actor=NULL;
|
||||
this->particle=particle;
|
||||
|
||||
// [BB] Translucent particles have to be rendered without the alpha test.
|
||||
if (gl_particles_style != 2 && trans>=1.0f-FLT_EPSILON) hw_styleflags = STYLEHW_Solid;
|
||||
else hw_styleflags = STYLEHW_NoAlphaTest;
|
||||
|
||||
PutSprite(hw_styleflags != STYLEHW_Solid);
|
||||
rendered_sprites++;
|
||||
}
|
||||
|
||||
|
||||
|
126
src/gl/scene/gl_spritelight.cpp
Normal file
126
src/gl/scene/gl_spritelight.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
** gl_light.cpp
|
||||
** Light level / fog management / dynamic lights
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "p_local.h"
|
||||
#include "p_effect.h"
|
||||
#include "vectors.h"
|
||||
#include "gl/gl_functions.h"
|
||||
#include "g_level.h"
|
||||
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/dynlights/gl_dynlight.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets a single light value from all dynamic lights affecting the specified location
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_SetDynSpriteLight(AActor *self, fixed_t x, fixed_t y, fixed_t z, subsector_t * subsec)
|
||||
{
|
||||
ADynamicLight *light;
|
||||
float frac, lr, lg, lb;
|
||||
float radius;
|
||||
float out[3] = { 0.0f, 0.0f, 0.0f };
|
||||
|
||||
// Go through both light lists
|
||||
FLightNode * node = subsec->lighthead;
|
||||
while (node)
|
||||
{
|
||||
light=node->lightsource;
|
||||
//if (!light->owned || light->target == NULL || light->target->IsVisibleToPlayer())
|
||||
{
|
||||
if (!(light->flags2&MF2_DORMANT) &&
|
||||
(!(light->flags4&MF4_DONTLIGHTSELF) || light->target != self))
|
||||
{
|
||||
float dist = FVector3(FIXED2FLOAT(x - light->x), FIXED2FLOAT(y - light->y), FIXED2FLOAT(z - light->z)).Length();
|
||||
radius = light->GetRadius() * gl_lights_size;
|
||||
|
||||
if (dist < radius)
|
||||
{
|
||||
frac = 1.0f - (dist / radius);
|
||||
|
||||
if (frac > 0)
|
||||
{
|
||||
lr = light->GetRed() / 255.0f * gl_lights_intensity;
|
||||
lg = light->GetGreen() / 255.0f * gl_lights_intensity;
|
||||
lb = light->GetBlue() / 255.0f * gl_lights_intensity;
|
||||
if (light->IsSubtractive())
|
||||
{
|
||||
float bright = FVector3(lr, lg, lb).Length();
|
||||
FVector3 lightColor(lr, lg, lb);
|
||||
lr = (bright - lr) * -1;
|
||||
lg = (bright - lg) * -1;
|
||||
lb = (bright - lb) * -1;
|
||||
}
|
||||
|
||||
out[0] += lr * frac;
|
||||
out[1] += lg * frac;
|
||||
out[2] += lb * frac;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
node = node->nextLight;
|
||||
}
|
||||
gl_RenderState.SetDynLight(out[0], out[1], out[2]);
|
||||
}
|
||||
|
||||
void gl_SetDynSpriteLight(AActor *thing, particle_t *particle)
|
||||
{
|
||||
if (thing != NULL)
|
||||
{
|
||||
gl_SetDynSpriteLight(thing, thing->x, thing->y, thing->z + (thing->height >> 1), thing->subsector);
|
||||
}
|
||||
else if (particle != NULL)
|
||||
{
|
||||
gl_SetDynSpriteLight(NULL, particle->x, particle->y, particle->z, particle->subsector);
|
||||
}
|
||||
}
|
197
src/gl/scene/gl_vertex.cpp
Normal file
197
src/gl/scene/gl_vertex.cpp
Normal file
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
** gl_vertex.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2006 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "gl/gl_functions.h"
|
||||
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/dynlights/gl_glow.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/utility/gl_templates.h"
|
||||
|
||||
EXTERN_CVAR(Bool, gl_seamless)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Split upper edge of wall
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::SplitUpperEdge(texcoord * tcs, FFlatVertex *&ptr)
|
||||
{
|
||||
if (seg == NULL || seg->sidedef == NULL || (seg->sidedef->Flags & WALLF_POLYOBJ) || seg->sidedef->numsegs == 1) return;
|
||||
|
||||
side_t *sidedef = seg->sidedef;
|
||||
float polyw = glseg.fracright - glseg.fracleft;
|
||||
float facu = (tcs[2].u - tcs[1].u) / polyw;
|
||||
float facv = (tcs[2].v - tcs[1].v) / polyw;
|
||||
float fact = (ztop[1] - ztop[0]) / polyw;
|
||||
float facc = (zceil[1] - zceil[0]) / polyw;
|
||||
float facf = (zfloor[1] - zfloor[0]) / polyw;
|
||||
|
||||
for (int i = 0; i < sidedef->numsegs - 1; i++)
|
||||
{
|
||||
seg_t *cseg = sidedef->segs[i];
|
||||
float sidefrac = cseg->sidefrac;
|
||||
if (sidefrac <= glseg.fracleft) continue;
|
||||
if (sidefrac >= glseg.fracright) return;
|
||||
|
||||
float fracfac = sidefrac - glseg.fracleft;
|
||||
|
||||
ptr->x = cseg->v2->fx;
|
||||
ptr->y = cseg->v2->fy;
|
||||
ptr->z = ztop[0] + fact * fracfac;
|
||||
ptr->u = tcs[1].u + facu * fracfac;
|
||||
ptr->v = tcs[1].v + facv * fracfac;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Split upper edge of wall
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::SplitLowerEdge(texcoord * tcs, FFlatVertex *&ptr)
|
||||
{
|
||||
if (seg == NULL || seg->sidedef == NULL || (seg->sidedef->Flags & WALLF_POLYOBJ) || seg->sidedef->numsegs == 1) return;
|
||||
|
||||
side_t *sidedef = seg->sidedef;
|
||||
float polyw = glseg.fracright - glseg.fracleft;
|
||||
float facu = (tcs[3].u - tcs[0].u) / polyw;
|
||||
float facv = (tcs[3].v - tcs[0].v) / polyw;
|
||||
float facb = (zbottom[1] - zbottom[0]) / polyw;
|
||||
float facc = (zceil[1] - zceil[0]) / polyw;
|
||||
float facf = (zfloor[1] - zfloor[0]) / polyw;
|
||||
|
||||
for (int i = sidedef->numsegs - 2; i >= 0; i--)
|
||||
{
|
||||
seg_t *cseg = sidedef->segs[i];
|
||||
float sidefrac = cseg->sidefrac;
|
||||
if (sidefrac >= glseg.fracright) continue;
|
||||
if (sidefrac <= glseg.fracleft) return;
|
||||
|
||||
float fracfac = sidefrac - glseg.fracleft;
|
||||
|
||||
ptr->x = cseg->v2->fx;
|
||||
ptr->y = cseg->v2->fy;
|
||||
ptr->z = zbottom[0] + facb * fracfac;
|
||||
ptr->u = tcs[0].u + facu * fracfac;
|
||||
ptr->v = tcs[0].v + facv * fracfac;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Split left edge of wall
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::SplitLeftEdge(texcoord * tcs, FFlatVertex *&ptr)
|
||||
{
|
||||
if (vertexes[0] == NULL) return;
|
||||
|
||||
vertex_t * vi = vertexes[0];
|
||||
|
||||
if (vi->numheights)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
float polyh1 = ztop[0] - zbottom[0];
|
||||
float factv1 = polyh1 ? (tcs[1].v - tcs[0].v) / polyh1 : 0;
|
||||
float factu1 = polyh1 ? (tcs[1].u - tcs[0].u) / polyh1 : 0;
|
||||
|
||||
while (i<vi->numheights && vi->heightlist[i] <= zbottom[0]) i++;
|
||||
while (i<vi->numheights && vi->heightlist[i] < ztop[0])
|
||||
{
|
||||
ptr->x = glseg.x1;
|
||||
ptr->y = glseg.y1;
|
||||
ptr->z = vi->heightlist[i];
|
||||
ptr->u = factu1*(vi->heightlist[i] - ztop[0]) + tcs[1].u;
|
||||
ptr->v = factv1*(vi->heightlist[i] - ztop[0]) + tcs[1].v;
|
||||
ptr++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Split right edge of wall
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::SplitRightEdge(texcoord * tcs, FFlatVertex *&ptr)
|
||||
{
|
||||
if (vertexes[1] == NULL) return;
|
||||
|
||||
vertex_t * vi = vertexes[1];
|
||||
|
||||
if (vi->numheights)
|
||||
{
|
||||
int i = vi->numheights - 1;
|
||||
|
||||
float polyh2 = ztop[1] - zbottom[1];
|
||||
float factv2 = polyh2 ? (tcs[2].v - tcs[3].v) / polyh2 : 0;
|
||||
float factu2 = polyh2 ? (tcs[2].u - tcs[3].u) / polyh2 : 0;
|
||||
|
||||
while (i>0 && vi->heightlist[i] >= ztop[1]) i--;
|
||||
while (i>0 && vi->heightlist[i] > zbottom[1])
|
||||
{
|
||||
ptr->x = glseg.x2;
|
||||
ptr->y = glseg.y2;
|
||||
ptr->z = vi->heightlist[i];
|
||||
ptr->u = factu2*(vi->heightlist[i] - ztop[1]) + tcs[2].u;
|
||||
ptr->v = factv2*(vi->heightlist[i] - ztop[1]) + tcs[2].v;
|
||||
ptr++;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
361
src/gl/scene/gl_wall.h
Normal file
361
src/gl/scene/gl_wall.h
Normal file
|
@ -0,0 +1,361 @@
|
|||
#ifndef __GL_WALL_H
|
||||
#define __GL_WALL_H
|
||||
//==========================================================================
|
||||
//
|
||||
// One wall segment in the draw list
|
||||
//
|
||||
//==========================================================================
|
||||
#include "r_defs.h"
|
||||
#include "textures/textures.h"
|
||||
#include "gl/renderer/gl_colormap.h"
|
||||
|
||||
struct GLHorizonInfo;
|
||||
struct F3DFloor;
|
||||
struct model_t;
|
||||
struct FSpriteModelFrame;
|
||||
struct particle_t;
|
||||
class ADynamicLight;
|
||||
class FMaterial;
|
||||
struct GLDrawList;
|
||||
struct GLSkyInfo;
|
||||
struct FTexCoordInfo;
|
||||
struct FPortal;
|
||||
struct FFlatVertex;
|
||||
|
||||
|
||||
enum WallTypes
|
||||
{
|
||||
RENDERWALL_NONE,
|
||||
RENDERWALL_TOP,
|
||||
RENDERWALL_M1S,
|
||||
RENDERWALL_M2S,
|
||||
RENDERWALL_BOTTOM,
|
||||
RENDERWALL_SKY,
|
||||
RENDERWALL_FOGBOUNDARY,
|
||||
RENDERWALL_HORIZON,
|
||||
RENDERWALL_SKYBOX,
|
||||
RENDERWALL_SECTORSTACK,
|
||||
RENDERWALL_PLANEMIRROR,
|
||||
RENDERWALL_MIRROR,
|
||||
RENDERWALL_MIRRORSURFACE,
|
||||
RENDERWALL_M2SNF,
|
||||
RENDERWALL_COLOR,
|
||||
RENDERWALL_FFBLOCK,
|
||||
RENDERWALL_COLORLAYER,
|
||||
// Insert new types at the end!
|
||||
};
|
||||
|
||||
struct GLSeg
|
||||
{
|
||||
float x1,x2;
|
||||
float y1,y2;
|
||||
float fracleft, fracright; // fractional offset of the 2 vertices on the linedef
|
||||
};
|
||||
|
||||
struct texcoord
|
||||
{
|
||||
float u,v;
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// One sector plane, still in fixed point
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct GLSectorPlane
|
||||
{
|
||||
FTextureID texture;
|
||||
secplane_t plane;
|
||||
fixed_t texheight;
|
||||
fixed_t xoffs, yoffs;
|
||||
fixed_t xscale, yscale;
|
||||
angle_t angle;
|
||||
|
||||
void GetFromSector(sector_t * sec, int ceiling)
|
||||
{
|
||||
xoffs = sec->GetXOffset(ceiling);
|
||||
yoffs = sec->GetYOffset(ceiling);
|
||||
xscale = sec->GetXScale(ceiling);
|
||||
yscale = sec->GetYScale(ceiling);
|
||||
angle = sec->GetAngle(ceiling);
|
||||
texture = sec->GetTexture(ceiling);
|
||||
plane = sec->GetSecPlane(ceiling);
|
||||
texheight = (ceiling == sector_t::ceiling)? plane.d : -plane.d;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class GLWall
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
//GLWF_CLAMPX=1, use GLT_* for these!
|
||||
//GLWF_CLAMPY=2,
|
||||
GLWF_SKYHACK=4,
|
||||
GLWF_GLOW=8, // illuminated by glowing flats
|
||||
GLWF_NOSPLITUPPER=16,
|
||||
GLWF_NOSPLITLOWER=32,
|
||||
GLWF_NOSPLIT=64,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
RWF_BLANK = 0,
|
||||
RWF_TEXTURED = 1, // actually not being used anymore because with buffers it's even less efficient not writing the texture coordinates - but leave it here
|
||||
RWF_GLOW = 2,
|
||||
RWF_NOSPLIT = 4,
|
||||
RWF_NORENDER = 8,
|
||||
};
|
||||
|
||||
|
||||
friend struct GLDrawList;
|
||||
friend class GLPortal;
|
||||
|
||||
GLSeg glseg;
|
||||
vertex_t * vertexes[2]; // required for polygon splitting
|
||||
float ztop[2],zbottom[2];
|
||||
texcoord uplft, uprgt, lolft, lorgt;
|
||||
float alpha;
|
||||
FMaterial *gltexture;
|
||||
|
||||
FColormap Colormap;
|
||||
ERenderStyle RenderStyle;
|
||||
|
||||
fixed_t viewdistance;
|
||||
|
||||
int lightlevel;
|
||||
BYTE type;
|
||||
BYTE flags;
|
||||
short rellight;
|
||||
|
||||
float topglowcolor[4];
|
||||
float bottomglowcolor[4];
|
||||
|
||||
int dynlightindex;
|
||||
|
||||
union
|
||||
{
|
||||
// it's either one of them but never more!
|
||||
AActor * skybox; // for skyboxes
|
||||
GLSkyInfo * sky; // for normal sky
|
||||
GLHorizonInfo * horizon; // for horizon information
|
||||
FPortal * portal; // stacked sector portals
|
||||
secplane_t * planemirror; // for plane mirrors
|
||||
};
|
||||
|
||||
|
||||
FTextureID topflat,bottomflat;
|
||||
secplane_t topplane, bottomplane; // we need to save these to pass them to the shader for calculating glows.
|
||||
|
||||
// these are not the same as ytop and ybottom!!!
|
||||
float zceil[2];
|
||||
float zfloor[2];
|
||||
|
||||
public:
|
||||
seg_t * seg; // this gives the easiest access to all other structs involved
|
||||
subsector_t * sub; // For polyobjects
|
||||
private:
|
||||
|
||||
void CheckGlowing();
|
||||
void PutWall(bool translucent);
|
||||
void CheckTexturePosition();
|
||||
|
||||
void SetupLights();
|
||||
bool PrepareLight(texcoord * tcs, ADynamicLight * light);
|
||||
void RenderWall(int textured, unsigned int *store = NULL);
|
||||
|
||||
void FloodPlane(int pass);
|
||||
|
||||
void SkyPlane(sector_t *sector, int plane, bool allowmirror);
|
||||
void SkyNormal(sector_t * fs,vertex_t * v1,vertex_t * v2);
|
||||
void SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2);
|
||||
void SkyBottom(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2);
|
||||
|
||||
void Put3DWall(lightlist_t * lightlist, bool translucent);
|
||||
void SplitWall(sector_t * frontsector, bool translucent);
|
||||
void LightPass();
|
||||
void SetHorizon(vertex_t * ul, vertex_t * ur, vertex_t * ll, vertex_t * lr);
|
||||
bool DoHorizon(seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2);
|
||||
|
||||
bool SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float ceilingrefheight,
|
||||
int topleft,int topright, int bottomleft,int bottomright, int texoffset);
|
||||
|
||||
void DoTexture(int type,seg_t * seg,int peg,
|
||||
int ceilingrefheight,int floorrefheight,
|
||||
int CeilingHeightstart,int CeilingHeightend,
|
||||
int FloorHeightstart,int FloorHeightend,
|
||||
int v_offset);
|
||||
|
||||
void DoMidTexture(seg_t * seg, bool drawfogboundary,
|
||||
sector_t * front, sector_t * back,
|
||||
sector_t * realfront, sector_t * realback,
|
||||
fixed_t fch1, fixed_t fch2, fixed_t ffh1, fixed_t ffh2,
|
||||
fixed_t bch1, fixed_t bch2, fixed_t bfh1, fixed_t bfh2);
|
||||
|
||||
void GetPlanePos(F3DFloor::planeref *planeref, int &left, int &right);
|
||||
|
||||
void BuildFFBlock(seg_t * seg, F3DFloor * rover,
|
||||
fixed_t ff_topleft, fixed_t ff_topright,
|
||||
fixed_t ff_bottomleft, fixed_t ff_bottomright);
|
||||
void InverseFloors(seg_t * seg, sector_t * frontsector,
|
||||
fixed_t topleft, fixed_t topright,
|
||||
fixed_t bottomleft, fixed_t bottomright);
|
||||
void ClipFFloors(seg_t * seg, F3DFloor * ffloor, sector_t * frontsector,
|
||||
fixed_t topleft, fixed_t topright,
|
||||
fixed_t bottomleft, fixed_t bottomright);
|
||||
void DoFFloorBlocks(seg_t * seg, sector_t * frontsector, sector_t * backsector,
|
||||
fixed_t fch1, fixed_t fch2, fixed_t ffh1, fixed_t ffh2,
|
||||
fixed_t bch1, fixed_t bch2, fixed_t bfh1, fixed_t bfh2);
|
||||
|
||||
void DrawDecal(DBaseDecal *actor);
|
||||
void DoDrawDecals();
|
||||
|
||||
void RenderFogBoundary();
|
||||
void RenderMirrorSurface();
|
||||
void RenderTranslucentWall();
|
||||
|
||||
void SplitLeftEdge(texcoord * tcs, FFlatVertex *&ptr);
|
||||
void SplitRightEdge(texcoord * tcs, FFlatVertex *&ptr);
|
||||
void SplitUpperEdge(texcoord * tcs, FFlatVertex *&ptr);
|
||||
void SplitLowerEdge(texcoord * tcs, FFlatVertex *&ptr);
|
||||
|
||||
public:
|
||||
|
||||
void Process(seg_t *seg, sector_t *frontsector, sector_t *backsector);
|
||||
void ProcessLowerMiniseg(seg_t *seg, sector_t *frontsector, sector_t *backsector);
|
||||
void Draw(int pass);
|
||||
|
||||
float PointOnSide(float x,float y)
|
||||
{
|
||||
return -((y-glseg.y1)*(glseg.x2-glseg.x1)-(x-glseg.x1)*(glseg.y2-glseg.y1));
|
||||
}
|
||||
|
||||
// Lines start-end and fdiv must intersect.
|
||||
double CalcIntersectionVertex(GLWall * w2)
|
||||
{
|
||||
float ax = glseg.x1, ay=glseg.y1;
|
||||
float bx = glseg.x2, by=glseg.y2;
|
||||
float cx = w2->glseg.x1, cy=w2->glseg.y1;
|
||||
float dx = w2->glseg.x2, dy=w2->glseg.y2;
|
||||
return ((ay-cy)*(dx-cx)-(ax-cx)*(dy-cy)) / ((bx-ax)*(dy-cy)-(by-ay)*(dx-cx));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// One flat plane in the draw list
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class GLFlat
|
||||
{
|
||||
public:
|
||||
friend struct GLDrawList;
|
||||
|
||||
sector_t * sector;
|
||||
subsector_t * sub; // only used for translucent planes
|
||||
float dz; // z offset for rendering hacks
|
||||
float z; // the z position of the flat (only valid for non-sloped planes)
|
||||
FMaterial *gltexture;
|
||||
|
||||
FColormap Colormap; // light and fog
|
||||
ERenderStyle renderstyle;
|
||||
|
||||
float alpha;
|
||||
GLSectorPlane plane;
|
||||
int lightlevel;
|
||||
bool stack;
|
||||
bool foggy;
|
||||
bool ceiling;
|
||||
BYTE renderflags;
|
||||
int vboindex;
|
||||
int vboheight;
|
||||
|
||||
int dynlightindex;
|
||||
|
||||
void SetupSubsectorLights(int pass, subsector_t * sub, int *dli = NULL);
|
||||
void DrawSubsector(subsector_t * sub);
|
||||
void DrawSubsectorLights(subsector_t * sub, int pass);
|
||||
void DrawSubsectors(int pass, bool processlights, bool istrans);
|
||||
void ProcessLights(bool istrans);
|
||||
|
||||
void PutFlat(bool fog = false);
|
||||
void Process(sector_t * model, int whichplane, bool notexture);
|
||||
void SetFrom3DFloor(F3DFloor *rover, bool top, bool underside);
|
||||
void ProcessSector(sector_t * frontsector);
|
||||
void Draw(int pass, bool trans);
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// One sprite in the draw list
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
||||
class GLSprite
|
||||
{
|
||||
public:
|
||||
friend struct GLDrawList;
|
||||
friend void Mod_RenderModel(GLSprite * spr, model_t * mdl, int framenumber);
|
||||
|
||||
BYTE lightlevel;
|
||||
BYTE foglevel;
|
||||
BYTE hw_styleflags;
|
||||
bool fullbright;
|
||||
PalEntry ThingColor; // thing's own color
|
||||
FColormap Colormap;
|
||||
FSpriteModelFrame * modelframe;
|
||||
FRenderStyle RenderStyle;
|
||||
int OverrideShader;
|
||||
|
||||
int translation;
|
||||
int index;
|
||||
int depth;
|
||||
|
||||
float x,y,z; // needed for sorting!
|
||||
|
||||
float ul,ur;
|
||||
float vt,vb;
|
||||
float x1,y1,z1;
|
||||
float x2,y2,z2;
|
||||
|
||||
FMaterial *gltexture;
|
||||
float trans;
|
||||
AActor * actor;
|
||||
particle_t * particle;
|
||||
|
||||
void SplitSprite(sector_t * frontsector, bool translucent);
|
||||
void SetLowerParam();
|
||||
void PerformSpriteClipAdjustment(AActor *thing, fixed_t thingx, fixed_t thingy, float spriteheight);
|
||||
|
||||
public:
|
||||
|
||||
void Draw(int pass);
|
||||
void PutSprite(bool translucent);
|
||||
void Process(AActor* thing,sector_t * sector);
|
||||
void ProcessParticle (particle_t *particle, sector_t *sector);//, int shade, int fakeside)
|
||||
void SetThingColor(PalEntry);
|
||||
void SetSpriteColor(sector_t *sector, fixed_t y);
|
||||
|
||||
// Lines start-end and fdiv must intersect.
|
||||
double CalcIntersectionVertex(GLWall * w2);
|
||||
};
|
||||
|
||||
inline float Dist2(float x1,float y1,float x2,float y2)
|
||||
{
|
||||
return sqrtf((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
|
||||
}
|
||||
|
||||
// Light + color
|
||||
|
||||
void gl_SetDynSpriteLight(AActor *self, fixed_t x, fixed_t y, fixed_t z, subsector_t *subsec);
|
||||
void gl_SetDynSpriteLight(AActor *actor, particle_t *particle);
|
||||
|
||||
#endif
|
1790
src/gl/scene/gl_walls.cpp
Normal file
1790
src/gl/scene/gl_walls.cpp
Normal file
File diff suppressed because it is too large
Load diff
444
src/gl/scene/gl_walls_draw.cpp
Normal file
444
src/gl/scene/gl_walls_draw.cpp
Normal file
|
@ -0,0 +1,444 @@
|
|||
/*
|
||||
** gl_walls_draw.cpp
|
||||
** Wall rendering
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2000-2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "p_local.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "gl/gl_functions.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/dynlights/gl_dynlight.h"
|
||||
#include "gl/dynlights/gl_glow.h"
|
||||
#include "gl/dynlights/gl_lightbuffer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/utility/gl_templates.h"
|
||||
|
||||
EXTERN_CVAR(Bool, gl_seamless)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Collect lights for shader
|
||||
//
|
||||
//==========================================================================
|
||||
FDynLightData lightdata;
|
||||
|
||||
|
||||
void GLWall::SetupLights()
|
||||
{
|
||||
// check for wall types which cannot have dynamic lights on them (portal types never get here so they don't need to be checked.)
|
||||
switch (type)
|
||||
{
|
||||
case RENDERWALL_FOGBOUNDARY:
|
||||
case RENDERWALL_MIRRORSURFACE:
|
||||
case RENDERWALL_COLOR:
|
||||
case RENDERWALL_COLORLAYER:
|
||||
return;
|
||||
}
|
||||
|
||||
float vtx[]={glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2};
|
||||
Plane p;
|
||||
|
||||
lightdata.Clear();
|
||||
p.Init(vtx,4);
|
||||
|
||||
if (!p.ValidNormal())
|
||||
{
|
||||
return;
|
||||
}
|
||||
FLightNode *node;
|
||||
if (seg->sidedef == NULL)
|
||||
{
|
||||
node = NULL;
|
||||
}
|
||||
else if (!(seg->sidedef->Flags & WALLF_POLYOBJ))
|
||||
{
|
||||
node = seg->sidedef->lighthead;
|
||||
}
|
||||
else if (sub)
|
||||
{
|
||||
// Polobject segs cannot be checked per sidedef so use the subsector instead.
|
||||
node = sub->lighthead;
|
||||
}
|
||||
else node = NULL;
|
||||
|
||||
// Iterate through all dynamic lights which touch this wall and render them
|
||||
while (node)
|
||||
{
|
||||
if (!(node->lightsource->flags2&MF2_DORMANT))
|
||||
{
|
||||
iter_dlight++;
|
||||
|
||||
Vector fn, pos;
|
||||
|
||||
float x = FIXED2FLOAT(node->lightsource->x);
|
||||
float y = FIXED2FLOAT(node->lightsource->y);
|
||||
float z = FIXED2FLOAT(node->lightsource->z);
|
||||
float dist = fabsf(p.DistToPoint(x, z, y));
|
||||
float radius = (node->lightsource->GetRadius() * gl_lights_size);
|
||||
float scale = 1.0f / ((2.f * radius) - dist);
|
||||
|
||||
if (radius > 0.f && dist < radius)
|
||||
{
|
||||
Vector nearPt, up, right;
|
||||
|
||||
pos.Set(x,z,y);
|
||||
fn=p.Normal();
|
||||
fn.GetRightUp(right, up);
|
||||
|
||||
Vector tmpVec = fn * dist;
|
||||
nearPt = pos + tmpVec;
|
||||
|
||||
Vector t1;
|
||||
int outcnt[4]={0,0,0,0};
|
||||
texcoord tcs[4];
|
||||
|
||||
// do a quick check whether the light touches this polygon
|
||||
for(int i=0;i<4;i++)
|
||||
{
|
||||
t1.Set(&vtx[i*3]);
|
||||
Vector nearToVert = t1 - nearPt;
|
||||
tcs[i].u = (nearToVert.Dot(right) * scale) + 0.5f;
|
||||
tcs[i].v = (nearToVert.Dot(up) * scale) + 0.5f;
|
||||
|
||||
if (tcs[i].u<0) outcnt[0]++;
|
||||
if (tcs[i].u>1) outcnt[1]++;
|
||||
if (tcs[i].v<0) outcnt[2]++;
|
||||
if (tcs[i].v>1) outcnt[3]++;
|
||||
|
||||
}
|
||||
if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4)
|
||||
{
|
||||
gl_GetLight(p, node->lightsource, true, false, lightdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
node = node->nextLight;
|
||||
}
|
||||
|
||||
dynlightindex = GLRenderer->mLights->UploadLights(lightdata);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// General purpose wall rendering function
|
||||
// everything goes through here
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::RenderWall(int textured, unsigned int *store)
|
||||
{
|
||||
static texcoord tcs[4]; // making this variable static saves us a relatively costly stack integrity check.
|
||||
bool split = (gl_seamless && !(textured&RWF_NOSPLIT) && seg->sidedef != NULL && !(seg->sidedef->Flags & WALLF_POLYOBJ) && !(flags & GLWF_NOSPLIT));
|
||||
|
||||
tcs[0]=lolft;
|
||||
tcs[1]=uplft;
|
||||
tcs[2]=uprgt;
|
||||
tcs[3]=lorgt;
|
||||
if ((flags&GLWF_GLOW) && (textured & RWF_GLOW))
|
||||
{
|
||||
gl_RenderState.SetGlowPlanes(topplane, bottomplane);
|
||||
gl_RenderState.SetGlowParams(topglowcolor, bottomglowcolor);
|
||||
}
|
||||
|
||||
if (!(textured & RWF_NORENDER))
|
||||
{
|
||||
gl_RenderState.Apply();
|
||||
gl_RenderState.ApplyLightIndex(dynlightindex);
|
||||
}
|
||||
|
||||
// the rest of the code is identical for textured rendering and lights
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
unsigned int count, offset;
|
||||
|
||||
ptr->Set(glseg.x1, zbottom[0], glseg.y1, tcs[0].u, tcs[0].v);
|
||||
ptr++;
|
||||
if (split && glseg.fracleft == 0) SplitLeftEdge(tcs, ptr);
|
||||
ptr->Set(glseg.x1, ztop[0], glseg.y1, tcs[1].u, tcs[1].v);
|
||||
ptr++;
|
||||
if (split && !(flags & GLWF_NOSPLITUPPER)) SplitUpperEdge(tcs, ptr);
|
||||
ptr->Set(glseg.x2, ztop[1], glseg.y2, tcs[2].u, tcs[2].v);
|
||||
ptr++;
|
||||
if (split && glseg.fracright == 1) SplitRightEdge(tcs, ptr);
|
||||
ptr->Set(glseg.x2, zbottom[1], glseg.y2, tcs[3].u, tcs[3].v);
|
||||
ptr++;
|
||||
if (split && !(flags & GLWF_NOSPLITLOWER)) SplitLowerEdge(tcs, ptr);
|
||||
count = GLRenderer->mVBO->GetCount(ptr, &offset);
|
||||
if (!(textured & RWF_NORENDER))
|
||||
{
|
||||
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, offset, count);
|
||||
vertexcount += count;
|
||||
}
|
||||
if (store != NULL)
|
||||
{
|
||||
store[0] = offset;
|
||||
store[1] = count;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::RenderFogBoundary()
|
||||
{
|
||||
if (gl_fogmode && gl_fixedcolormap == 0)
|
||||
{
|
||||
int rel = rellight + getExtraLight();
|
||||
gl_SetFog(lightlevel, rel, &Colormap, false);
|
||||
gl_RenderState.SetEffect(EFF_FOGBOUNDARY);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-1.0f, -128.0f);
|
||||
RenderWall(RWF_BLANK);
|
||||
glPolygonOffset(0.0f, 0.0f);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
gl_RenderState.SetEffect(EFF_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void GLWall::RenderMirrorSurface()
|
||||
{
|
||||
if (GLRenderer->mirrortexture == NULL) return;
|
||||
|
||||
// For the sphere map effect we need a normal of the mirror surface,
|
||||
Vector v(glseg.y2-glseg.y1, 0 ,-glseg.x2+glseg.x1);
|
||||
v.Normalize();
|
||||
|
||||
// we use texture coordinates and texture matrix to pass the normal stuff to the shader so that the default vertex buffer format can be used as is.
|
||||
lolft.u = lorgt.u = uplft.u = uprgt.u = v.X();
|
||||
lolft.v = lorgt.v = uplft.v = uprgt.v = v.Z();
|
||||
|
||||
gl_RenderState.EnableTextureMatrix(true);
|
||||
gl_RenderState.mTextureMatrix.computeNormalMatrix(gl_RenderState.mViewMatrix);
|
||||
|
||||
// Use sphere mapping for this
|
||||
gl_RenderState.SetEffect(EFF_SPHEREMAP);
|
||||
|
||||
gl_SetColor(lightlevel, 0, Colormap ,0.1f);
|
||||
gl_SetFog(lightlevel, 0, &Colormap, true);
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA,GL_ONE);
|
||||
gl_RenderState.AlphaFunc(GL_GREATER,0);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
FMaterial * pat=FMaterial::ValidateTexture(GLRenderer->mirrortexture, false);
|
||||
gl_RenderState.SetMaterial(pat, CLAMP_NONE, 0, -1, false);
|
||||
|
||||
flags &= ~GLWF_GLOW;
|
||||
RenderWall(RWF_BLANK);
|
||||
|
||||
gl_RenderState.EnableTextureMatrix(false);
|
||||
gl_RenderState.SetEffect(EFF_NONE);
|
||||
|
||||
// Restore the defaults for the translucent pass
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold);
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
// This is drawn in the translucent pass which is done after the decal pass
|
||||
// As a result the decals have to be drawn here.
|
||||
if (seg->sidedef->AttachedDecals)
|
||||
{
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-1.0f, -128.0f);
|
||||
glDepthMask(false);
|
||||
DoDrawDecals();
|
||||
glDepthMask(true);
|
||||
glPolygonOffset(0.0f, 0.0f);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
gl_RenderState.SetTextureMode(TM_MODULATE);
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::RenderTranslucentWall()
|
||||
{
|
||||
bool transparent = gltexture? gltexture->GetTransparent() : false;
|
||||
|
||||
// currently the only modes possible are solid, additive or translucent
|
||||
// and until that changes I won't fix this code for the new blending modes!
|
||||
bool isadditive = RenderStyle == STYLE_Add;
|
||||
|
||||
if (gl_fixedcolormap == CM_DEFAULT && gl_lights && (gl.flags & RFL_BUFFER_STORAGE))
|
||||
{
|
||||
SetupLights();
|
||||
}
|
||||
|
||||
if (!transparent) gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_threshold);
|
||||
else gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
||||
if (isadditive) gl_RenderState.BlendFunc(GL_SRC_ALPHA,GL_ONE);
|
||||
|
||||
int extra;
|
||||
if (gltexture)
|
||||
{
|
||||
gl_RenderState.EnableGlow(!!(flags & GLWF_GLOW));
|
||||
gl_RenderState.SetMaterial(gltexture, flags & 3, 0, -1, false);
|
||||
extra = getExtraLight();
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_RenderState.EnableTexture(false);
|
||||
extra = 0;
|
||||
}
|
||||
int tmode = gl_RenderState.GetTextureMode();
|
||||
|
||||
gl_SetColor(lightlevel, extra, Colormap, fabsf(alpha));
|
||||
if (type!=RENDERWALL_M2SNF) gl_SetFog(lightlevel, extra, &Colormap, isadditive);
|
||||
else
|
||||
{
|
||||
if (flags & GLT_CLAMPY)
|
||||
{
|
||||
if (tmode == TM_MODULATE) gl_RenderState.SetTextureMode(TM_CLAMPY);
|
||||
}
|
||||
gl_SetFog(255, 0, NULL, false);
|
||||
}
|
||||
|
||||
RenderWall(RWF_TEXTURED|RWF_NOSPLIT);
|
||||
|
||||
// restore default settings
|
||||
if (isadditive) gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
if (!gltexture)
|
||||
{
|
||||
gl_RenderState.EnableTexture(true);
|
||||
}
|
||||
gl_RenderState.EnableGlow(false);
|
||||
gl_RenderState.SetTextureMode(tmode);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void GLWall::Draw(int pass)
|
||||
{
|
||||
int rel;
|
||||
int tmode;
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (seg->linedef-lines==879)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
switch (pass)
|
||||
{
|
||||
case GLPASS_LIGHTSONLY:
|
||||
SetupLights();
|
||||
break;
|
||||
|
||||
case GLPASS_ALL:
|
||||
SetupLights();
|
||||
// fall through
|
||||
case GLPASS_PLAIN:
|
||||
rel = rellight + getExtraLight();
|
||||
gl_SetColor(lightlevel, rel, Colormap,1.0f);
|
||||
tmode = gl_RenderState.GetTextureMode();
|
||||
if (type!=RENDERWALL_M2SNF) gl_SetFog(lightlevel, rel, &Colormap, false);
|
||||
else
|
||||
{
|
||||
if (flags & GLT_CLAMPY)
|
||||
{
|
||||
if (tmode == TM_MODULATE) gl_RenderState.SetTextureMode(TM_CLAMPY);
|
||||
}
|
||||
gl_SetFog(255, 0, NULL, false);
|
||||
}
|
||||
gl_RenderState.EnableGlow(!!(flags & GLWF_GLOW));
|
||||
gl_RenderState.SetMaterial(gltexture, flags & 3, false, -1, false);
|
||||
RenderWall(RWF_TEXTURED|RWF_GLOW);
|
||||
gl_RenderState.EnableGlow(false);
|
||||
gl_RenderState.SetTextureMode(tmode);
|
||||
break;
|
||||
|
||||
case GLPASS_TRANSLUCENT:
|
||||
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case RENDERWALL_MIRRORSURFACE:
|
||||
RenderMirrorSurface();
|
||||
break;
|
||||
|
||||
case RENDERWALL_FOGBOUNDARY:
|
||||
RenderFogBoundary();
|
||||
break;
|
||||
|
||||
case RENDERWALL_COLORLAYER:
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-1.0f, -128.0f);
|
||||
RenderTranslucentWall();
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(0, 0);
|
||||
|
||||
default:
|
||||
RenderTranslucentWall();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
437
src/gl/scene/gl_weapon.cpp
Normal file
437
src/gl/scene/gl_weapon.cpp
Normal file
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
** gl_weapon.cpp
|
||||
** Weapon sprite drawing
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2005 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "sbar.h"
|
||||
#include "r_utility.h"
|
||||
#include "v_video.h"
|
||||
#include "doomstat.h"
|
||||
#include "d_player.h"
|
||||
#include "g_level.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/dynlights/gl_glow.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
|
||||
EXTERN_CVAR (Bool, r_drawplayersprites)
|
||||
EXTERN_CVAR(Float, transsouls)
|
||||
EXTERN_CVAR (Bool, st_scale)
|
||||
EXTERN_CVAR(Int, gl_fuzztype)
|
||||
EXTERN_CVAR (Bool, r_deathcamera)
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_DrawPSprite
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed_t sy, bool hudModelStep, int OverrideShader, bool alphatexture)
|
||||
{
|
||||
float fU1,fV1;
|
||||
float fU2,fV2;
|
||||
float tx;
|
||||
float x1,y1,x2,y2;
|
||||
float scale;
|
||||
float scalex;
|
||||
float ftexturemid;
|
||||
// 4:3 16:9 16:10 17:10 5:4
|
||||
static float xratio[] = {1.f, 3.f/4, 5.f/6, 40.f/51, 1.f};
|
||||
|
||||
// [BB] In the HUD model step we just render the model and break out.
|
||||
if ( hudModelStep )
|
||||
{
|
||||
gl_RenderHUDModel( psp, sx, sy);
|
||||
return;
|
||||
}
|
||||
|
||||
// decide which patch to use
|
||||
bool mirror;
|
||||
FTextureID lump = gl_GetSpriteFrame(psp->sprite, psp->frame, 0, 0, &mirror);
|
||||
if (!lump.isValid()) return;
|
||||
|
||||
FMaterial * tex = FMaterial::ValidateTexture(lump, true, false);
|
||||
if (!tex) return;
|
||||
|
||||
gl_RenderState.SetMaterial(tex, CLAMP_XY_NOMIP, 0, OverrideShader, alphatexture);
|
||||
|
||||
float vw = (float)viewwidth;
|
||||
float vh = (float)viewheight;
|
||||
|
||||
FloatRect r;
|
||||
tex->GetSpriteRect(&r);
|
||||
|
||||
// calculate edges of the shape
|
||||
scalex = xratio[WidescreenRatio] * vw / 320;
|
||||
|
||||
tx = FIXED2FLOAT(sx) - (160 - r.left);
|
||||
x1 = tx * scalex + vw/2;
|
||||
if (x1 > vw) return; // off the right side
|
||||
x1 += viewwindowx;
|
||||
|
||||
tx += r.width;
|
||||
x2 = tx * scalex + vw / 2;
|
||||
if (x2 < 0) return; // off the left side
|
||||
x2 += viewwindowx;
|
||||
|
||||
|
||||
// killough 12/98: fix psprite positioning problem
|
||||
ftexturemid = 100.f - FIXED2FLOAT(sy) - r.top;
|
||||
|
||||
AWeapon * wi=player->ReadyWeapon;
|
||||
if (wi && wi->YAdjust)
|
||||
{
|
||||
float fYAd = FIXED2FLOAT(wi->YAdjust);
|
||||
if (screenblocks >= 11)
|
||||
{
|
||||
ftexturemid -= fYAd;
|
||||
}
|
||||
else if (!st_scale)
|
||||
{
|
||||
ftexturemid -= FIXED2FLOAT(StatusBar->GetDisplacement ()) * fYAd;
|
||||
}
|
||||
}
|
||||
|
||||
scale = (SCREENHEIGHT*vw) / (SCREENWIDTH * 200.0f);
|
||||
y1 = viewwindowy + vh / 2 - (ftexturemid * scale);
|
||||
y2 = y1 + (r.height * scale) + 1;
|
||||
|
||||
if (!mirror)
|
||||
{
|
||||
fU1=tex->GetSpriteUL();
|
||||
fV1=tex->GetSpriteVT();
|
||||
fU2=tex->GetSpriteUR();
|
||||
fV2=tex->GetSpriteVB();
|
||||
}
|
||||
else
|
||||
{
|
||||
fU2=tex->GetSpriteUL();
|
||||
fV1=tex->GetSpriteVT();
|
||||
fU1=tex->GetSpriteUR();
|
||||
fV2=tex->GetSpriteVB();
|
||||
}
|
||||
|
||||
if (tex->GetTransparent() || OverrideShader != -1)
|
||||
{
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
||||
}
|
||||
gl_RenderState.Apply();
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(x1, y1, 0, fU1, fV1);
|
||||
ptr++;
|
||||
ptr->Set(x1, y2, 0, fU1, fV2);
|
||||
ptr++;
|
||||
ptr->Set(x2, y1, 0, fU2, fV1);
|
||||
ptr++;
|
||||
ptr->Set(x2, y2, 0, fU2, fV2);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_DrawPlayerSprites
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
EXTERN_CVAR(Bool, gl_brightfog)
|
||||
|
||||
void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
|
||||
{
|
||||
bool statebright[2] = {false, false};
|
||||
unsigned int i;
|
||||
pspdef_t *psp;
|
||||
int lightlevel=0;
|
||||
fixed_t ofsx, ofsy;
|
||||
FColormap cm;
|
||||
sector_t * fakesec, fs;
|
||||
AActor * playermo=players[consoleplayer].camera;
|
||||
player_t * player=playermo->player;
|
||||
|
||||
// this is the same as the software renderer
|
||||
if (!player ||
|
||||
!r_drawplayersprites ||
|
||||
!camera->player ||
|
||||
(player->cheats & CF_CHASECAM) ||
|
||||
(r_deathcamera && camera->health <= 0))
|
||||
return;
|
||||
|
||||
P_BobWeapon (player, &player->psprites[ps_weapon], &ofsx, &ofsy);
|
||||
|
||||
// check for fullbright
|
||||
if (player->fixedcolormap==NOFIXEDCOLORMAP)
|
||||
{
|
||||
for (i = 0, psp = player->psprites; i <= ps_flash; i++, psp++)
|
||||
{
|
||||
if (psp->state != NULL)
|
||||
{
|
||||
bool disablefullbright = false;
|
||||
FTextureID lump = gl_GetSpriteFrame(psp->sprite, psp->frame, 0, 0, NULL);
|
||||
if (lump.isValid())
|
||||
{
|
||||
FMaterial * tex=FMaterial::ValidateTexture(lump, false, false);
|
||||
if (tex)
|
||||
disablefullbright = tex->tex->gl_info.bDisableFullbright;
|
||||
}
|
||||
statebright[i] = !!psp->state->GetFullbright() && !disablefullbright;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gl_fixedcolormap)
|
||||
{
|
||||
lightlevel=255;
|
||||
cm.Clear();
|
||||
statebright[0] = statebright[1] = true;
|
||||
fakesec = viewsector;
|
||||
}
|
||||
else
|
||||
{
|
||||
fakesec = gl_FakeFlat(viewsector, &fs, false);
|
||||
|
||||
// calculate light level for weapon sprites
|
||||
lightlevel = gl_ClampLight(fakesec->lightlevel);
|
||||
if (glset.lightmode == 8)
|
||||
{
|
||||
lightlevel = gl_CalcLightLevel(lightlevel, getExtraLight(), true);
|
||||
|
||||
// Korshun: the way based on max possible light level for sector like in software renderer.
|
||||
float min_L = 36.0/31.0 - ((lightlevel/255.0) * (63.0/31.0)); // Lightlevel in range 0-63
|
||||
if (min_L < 0)
|
||||
min_L = 0;
|
||||
else if (min_L > 1.0)
|
||||
min_L = 1.0;
|
||||
|
||||
lightlevel = (1.0 - min_L) * 255;
|
||||
}
|
||||
lightlevel = gl_CheckSpriteGlow(viewsector, lightlevel, playermo->x, playermo->y, playermo->z);
|
||||
|
||||
// calculate colormap for weapon sprites
|
||||
if (viewsector->e->XFloor.ffloors.Size() && !glset.nocoloredspritelighting)
|
||||
{
|
||||
TArray<lightlist_t> & lightlist = viewsector->e->XFloor.lightlist;
|
||||
for(i=0;i<lightlist.Size();i++)
|
||||
{
|
||||
int lightbottom;
|
||||
|
||||
if (i<lightlist.Size()-1)
|
||||
{
|
||||
lightbottom=lightlist[i+1].plane.ZatPoint(viewx,viewy);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightbottom=viewsector->floorplane.ZatPoint(viewx,viewy);
|
||||
}
|
||||
|
||||
if (lightbottom<player->viewz)
|
||||
{
|
||||
cm = lightlist[i].extra_colormap;
|
||||
lightlevel = *lightlist[i].p_lightlevel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cm=fakesec->ColorMap;
|
||||
if (glset.nocoloredspritelighting) cm.ClearColor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Korshun: fullbright fog in opengl, render weapon sprites fullbright (but don't cancel out the light color!)
|
||||
if (glset.brightfog && ((level.flags&LEVEL_HASFADETABLE) || cm.FadeColor != 0))
|
||||
{
|
||||
lightlevel = 255;
|
||||
}
|
||||
|
||||
PalEntry ThingColor = (playermo->RenderStyle.Flags & STYLEF_ColorIsFixed) ? playermo->fillcolor : 0xffffff;
|
||||
ThingColor.a = 255;
|
||||
|
||||
visstyle_t vis;
|
||||
|
||||
vis.RenderStyle=playermo->RenderStyle;
|
||||
vis.alpha=playermo->alpha;
|
||||
vis.colormap = NULL;
|
||||
if (playermo->Inventory)
|
||||
{
|
||||
playermo->Inventory->AlterWeaponSprite(&vis);
|
||||
if (vis.colormap >= SpecialColormaps[0].Colormap &&
|
||||
vis.colormap < SpecialColormaps[SpecialColormaps.Size()].Colormap &&
|
||||
gl_fixedcolormap == CM_DEFAULT)
|
||||
{
|
||||
// this only happens for Strife's inverted weapon sprite
|
||||
vis.RenderStyle.Flags |= STYLEF_InvertSource;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the render parameters
|
||||
|
||||
int OverrideShader = -1;
|
||||
float trans = 0.f;
|
||||
if (vis.RenderStyle.BlendOp >= STYLEOP_Fuzz && vis.RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub)
|
||||
{
|
||||
vis.RenderStyle.CheckFuzz();
|
||||
if (vis.RenderStyle.BlendOp == STYLEOP_Fuzz)
|
||||
{
|
||||
if (gl_fuzztype != 0)
|
||||
{
|
||||
// Todo: implement shader selection here
|
||||
vis.RenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
||||
OverrideShader = gl_fuzztype + 4;
|
||||
trans = 0.99f; // trans may not be 1 here
|
||||
}
|
||||
else
|
||||
{
|
||||
vis.RenderStyle.BlendOp = STYLEOP_Shadow;
|
||||
}
|
||||
}
|
||||
statebright[0] = statebright[1] = false;
|
||||
}
|
||||
|
||||
gl_SetRenderStyle(vis.RenderStyle, false, false);
|
||||
|
||||
if (vis.RenderStyle.Flags & STYLEF_TransSoulsAlpha)
|
||||
{
|
||||
trans = transsouls;
|
||||
}
|
||||
else if (vis.RenderStyle.Flags & STYLEF_Alpha1)
|
||||
{
|
||||
trans = 1.f;
|
||||
}
|
||||
else if (trans == 0.f)
|
||||
{
|
||||
trans = FIXED2FLOAT(vis.alpha);
|
||||
}
|
||||
|
||||
// now draw the different layers of the weapon
|
||||
gl_RenderState.EnableBrightmap(true);
|
||||
gl_RenderState.SetObjectColor(ThingColor);
|
||||
if (statebright[0] || statebright[1])
|
||||
{
|
||||
// brighten the weapon to reduce the difference between
|
||||
// normal sprite and fullbright flash.
|
||||
if (glset.lightmode != 8) lightlevel = (2*lightlevel+255)/3;
|
||||
}
|
||||
|
||||
// hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change
|
||||
// light mode here to draw the weapon sprite.
|
||||
int oldlightmode = glset.lightmode;
|
||||
if (glset.lightmode == 8) glset.lightmode = 2;
|
||||
|
||||
for (i=0, psp=player->psprites; i<=ps_flash; i++,psp++)
|
||||
{
|
||||
if (psp->state)
|
||||
{
|
||||
FColormap cmc = cm;
|
||||
if (statebright[i])
|
||||
{
|
||||
if (fakesec == viewsector || in_area != area_below)
|
||||
{
|
||||
cmc.LightColor.r=
|
||||
cmc.LightColor.g=
|
||||
cmc.LightColor.b=0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
// under water areas keep most of their color for fullbright objects
|
||||
cmc.LightColor.r = (3 * cmc.LightColor.r + 0xff) / 4;
|
||||
cmc.LightColor.g = (3*cmc.LightColor.g + 0xff)/4;
|
||||
cmc.LightColor.b = (3*cmc.LightColor.b + 0xff)/4;
|
||||
}
|
||||
}
|
||||
// set the lighting parameters
|
||||
if (vis.RenderStyle.BlendOp == STYLEOP_Shadow)
|
||||
{
|
||||
gl_RenderState.SetColor(0.2f, 0.2f, 0.2f, 0.33f, cmc.desaturation);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gl_lights && GLRenderer->mLightCount && !gl_fixedcolormap && gl_light_sprites)
|
||||
{
|
||||
gl_SetDynSpriteLight(playermo, NULL);
|
||||
}
|
||||
gl_SetColor(statebright[i] ? 255 : lightlevel, 0, cmc, trans, true);
|
||||
}
|
||||
DrawPSprite(player, psp, psp->sx + ofsx, psp->sy + ofsy, hudModelStep, OverrideShader, !!(vis.RenderStyle.Flags & STYLEF_RedIsAlpha));
|
||||
}
|
||||
}
|
||||
gl_RenderState.SetObjectColor(0xffffffff);
|
||||
gl_RenderState.SetDynLight(0, 0, 0);
|
||||
gl_RenderState.EnableBrightmap(false);
|
||||
glset.lightmode = oldlightmode;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_DrawPlayerSprites
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderer::DrawTargeterSprites()
|
||||
{
|
||||
int i;
|
||||
pspdef_t *psp;
|
||||
AActor * playermo=players[consoleplayer].camera;
|
||||
player_t * player=playermo->player;
|
||||
|
||||
if(!player || playermo->renderflags&RF_INVISIBLE || !r_drawplayersprites ||
|
||||
mViewActor!=playermo) return;
|
||||
|
||||
gl_RenderState.EnableBrightmap(false);
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL,gl_mask_sprite_threshold);
|
||||
gl_RenderState.BlendEquation(GL_FUNC_ADD);
|
||||
gl_RenderState.ResetColor();
|
||||
gl_RenderState.SetTextureMode(TM_MODULATE);
|
||||
|
||||
// The Targeter's sprites are always drawn normally.
|
||||
for (i=ps_targetcenter, psp = &player->psprites[ps_targetcenter]; i<NUMPSPRITES; i++,psp++)
|
||||
if (psp->state) DrawPSprite (player,psp,psp->sx, psp->sy, false, 0, false);
|
||||
}
|
630
src/gl/shaders/gl_shader.cpp
Normal file
630
src/gl/shaders/gl_shader.cpp
Normal file
|
@ -0,0 +1,630 @@
|
|||
/*
|
||||
** gl_shader.cpp
|
||||
**
|
||||
** GLSL shader handling
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2004-2009 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "c_cvars.h"
|
||||
#include "v_video.h"
|
||||
#include "name.h"
|
||||
#include "w_wad.h"
|
||||
#include "i_system.h"
|
||||
#include "doomerrors.h"
|
||||
#include "v_palette.h"
|
||||
#include "sc_man.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_matrix.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/dynlights/gl_lightbuffer.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FShader::Load(const char * name, const char * vert_prog_lump, const char * frag_prog_lump, const char * proc_prog_lump, const char * defines)
|
||||
{
|
||||
static char buffer[10000];
|
||||
FString error;
|
||||
|
||||
int i_lump = Wads.CheckNumForFullName("shaders/glsl/shaderdefs.i");
|
||||
if (i_lump == -1) I_Error("Unable to load 'shaders/glsl/shaderdefs.i'");
|
||||
FMemLump i_data = Wads.ReadLump(i_lump);
|
||||
|
||||
int vp_lump = Wads.CheckNumForFullName(vert_prog_lump);
|
||||
if (vp_lump == -1) I_Error("Unable to load '%s'", vert_prog_lump);
|
||||
FMemLump vp_data = Wads.ReadLump(vp_lump);
|
||||
|
||||
int fp_lump = Wads.CheckNumForFullName(frag_prog_lump);
|
||||
if (fp_lump == -1) I_Error("Unable to load '%s'", frag_prog_lump);
|
||||
FMemLump fp_data = Wads.ReadLump(fp_lump);
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The following code uses GetChars on the strings to get rid of terminating 0 characters. Do not remove or the code may break!
|
||||
//
|
||||
unsigned int lightbuffertype = GLRenderer->mLights->GetBufferType();
|
||||
unsigned int lightbuffersize = GLRenderer->mLights->GetBlockSize();
|
||||
|
||||
FString vp_comb;
|
||||
|
||||
if (lightbuffertype == GL_UNIFORM_BUFFER)
|
||||
{
|
||||
if (gl.glslversion < 1.4f || gl.version < 3.1f)
|
||||
{
|
||||
vp_comb.Format("#version 130\n#extension GL_ARB_uniform_buffer_object : require\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize);
|
||||
}
|
||||
else
|
||||
{
|
||||
vp_comb.Format("#version 140\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vp_comb = "#version 400 core\n#extension GL_ARB_shader_storage_buffer_object : require\n#define SHADER_STORAGE_LIGHTS\n";
|
||||
}
|
||||
|
||||
vp_comb << defines << i_data.GetString().GetChars();
|
||||
FString fp_comb = vp_comb;
|
||||
|
||||
vp_comb << vp_data.GetString().GetChars() << "\n";
|
||||
fp_comb << fp_data.GetString().GetChars() << "\n";
|
||||
|
||||
if (proc_prog_lump != NULL)
|
||||
{
|
||||
if (*proc_prog_lump != '#')
|
||||
{
|
||||
int pp_lump = Wads.CheckNumForFullName(proc_prog_lump);
|
||||
if (pp_lump == -1) I_Error("Unable to load '%s'", proc_prog_lump);
|
||||
FMemLump pp_data = Wads.ReadLump(pp_lump);
|
||||
|
||||
if (pp_data.GetString().IndexOf("ProcessTexel") < 0)
|
||||
{
|
||||
// this looks like an old custom hardware shader.
|
||||
// We need to replace the ProcessTexel call to make it work.
|
||||
|
||||
fp_comb.Substitute("vec4 frag = ProcessTexel();", "vec4 frag = Process(vec4(1.0));");
|
||||
}
|
||||
fp_comb << pp_data.GetString().GetChars();
|
||||
fp_comb.Substitute("gl_TexCoord[0]", "vTexCoord"); // fix old custom shaders.
|
||||
|
||||
if (pp_data.GetString().IndexOf("ProcessLight") < 0)
|
||||
{
|
||||
int pl_lump = Wads.CheckNumForFullName("shaders/glsl/func_defaultlight.fp");
|
||||
if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders/glsl/func_defaultlight.fp");
|
||||
FMemLump pl_data = Wads.ReadLump(pl_lump);
|
||||
fp_comb << "\n" << pl_data.GetString().GetChars();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Proc_prog_lump is not a lump name but the source itself (from generated shaders)
|
||||
fp_comb << proc_prog_lump + 1;
|
||||
}
|
||||
}
|
||||
|
||||
hVertProg = glCreateShader(GL_VERTEX_SHADER);
|
||||
hFragProg = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
|
||||
int vp_size = (int)vp_comb.Len();
|
||||
int fp_size = (int)fp_comb.Len();
|
||||
|
||||
const char *vp_ptr = vp_comb.GetChars();
|
||||
const char *fp_ptr = fp_comb.GetChars();
|
||||
|
||||
glShaderSource(hVertProg, 1, &vp_ptr, &vp_size);
|
||||
glShaderSource(hFragProg, 1, &fp_ptr, &fp_size);
|
||||
|
||||
glCompileShader(hVertProg);
|
||||
glCompileShader(hFragProg);
|
||||
|
||||
hShader = glCreateProgram();
|
||||
|
||||
glAttachShader(hShader, hVertProg);
|
||||
glAttachShader(hShader, hFragProg);
|
||||
|
||||
glBindAttribLocation(hShader, VATTR_VERTEX, "aPosition");
|
||||
glBindAttribLocation(hShader, VATTR_TEXCOORD, "aTexCoord");
|
||||
glBindAttribLocation(hShader, VATTR_COLOR, "aColor");
|
||||
glBindAttribLocation(hShader, VATTR_VERTEX2, "aVertex2");
|
||||
|
||||
glLinkProgram(hShader);
|
||||
|
||||
glGetShaderInfoLog(hVertProg, 10000, NULL, buffer);
|
||||
if (*buffer)
|
||||
{
|
||||
error << "Vertex shader:\n" << buffer << "\n";
|
||||
}
|
||||
glGetShaderInfoLog(hFragProg, 10000, NULL, buffer);
|
||||
if (*buffer)
|
||||
{
|
||||
error << "Fragment shader:\n" << buffer << "\n";
|
||||
}
|
||||
|
||||
glGetProgramInfoLog(hShader, 10000, NULL, buffer);
|
||||
if (*buffer)
|
||||
{
|
||||
error << "Linking:\n" << buffer << "\n";
|
||||
}
|
||||
int linked;
|
||||
glGetProgramiv(hShader, GL_LINK_STATUS, &linked);
|
||||
if (linked == 0)
|
||||
{
|
||||
// only print message if there's an error.
|
||||
I_Error("Init Shader '%s':\n%s\n", name, error.GetChars());
|
||||
}
|
||||
|
||||
|
||||
muDesaturation.Init(hShader, "uDesaturationFactor");
|
||||
muFogEnabled.Init(hShader, "uFogEnabled");
|
||||
muTextureMode.Init(hShader, "uTextureMode");
|
||||
muCameraPos.Init(hShader, "uCameraPos");
|
||||
muLightParms.Init(hShader, "uLightAttr");
|
||||
muClipSplit.Init(hShader, "uClipSplit");
|
||||
muColormapStart.Init(hShader, "uFixedColormapStart");
|
||||
muColormapRange.Init(hShader, "uFixedColormapRange");
|
||||
muLightIndex.Init(hShader, "uLightIndex");
|
||||
muFogColor.Init(hShader, "uFogColor");
|
||||
muDynLightColor.Init(hShader, "uDynLightColor");
|
||||
muObjectColor.Init(hShader, "uObjectColor");
|
||||
muGlowBottomColor.Init(hShader, "uGlowBottomColor");
|
||||
muGlowTopColor.Init(hShader, "uGlowTopColor");
|
||||
muGlowBottomPlane.Init(hShader, "uGlowBottomPlane");
|
||||
muGlowTopPlane.Init(hShader, "uGlowTopPlane");
|
||||
muFixedColormap.Init(hShader, "uFixedColormap");
|
||||
muInterpolationFactor.Init(hShader, "uInterpolationFactor");
|
||||
muClipHeightTop.Init(hShader, "uClipHeightTop");
|
||||
muClipHeightBottom.Init(hShader, "uClipHeightBottom");
|
||||
muAlphaThreshold.Init(hShader, "uAlphaThreshold");
|
||||
muTimer.Init(hShader, "timer");
|
||||
|
||||
lights_index = glGetUniformLocation(hShader, "lights");
|
||||
fakevb_index = glGetUniformLocation(hShader, "fakeVB");
|
||||
projectionmatrix_index = glGetUniformLocation(hShader, "ProjectionMatrix");
|
||||
viewmatrix_index = glGetUniformLocation(hShader, "ViewMatrix");
|
||||
modelmatrix_index = glGetUniformLocation(hShader, "ModelMatrix");
|
||||
texturematrix_index = glGetUniformLocation(hShader, "TextureMatrix");
|
||||
|
||||
int tempindex = glGetUniformBlockIndex(hShader, "LightBufferUBO");
|
||||
if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, LIGHTBUF_BINDINGPOINT);
|
||||
|
||||
glUseProgram(hShader);
|
||||
|
||||
// set up other texture units (if needed by the shader)
|
||||
for (int i = 2; i<16; i++)
|
||||
{
|
||||
char stringbuf[20];
|
||||
mysnprintf(stringbuf, 20, "texture%d", i);
|
||||
tempindex = glGetUniformLocation(hShader, stringbuf);
|
||||
if (tempindex > 0) glUniform1i(tempindex, i - 1);
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
return !!linked;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShader::~FShader()
|
||||
{
|
||||
glDeleteProgram(hShader);
|
||||
glDeleteShader(hVertProg);
|
||||
glDeleteShader(hFragProg);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FShader::Bind()
|
||||
{
|
||||
GLRenderer->mShaderManager->SetActiveShader(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Since all shaders are REQUIRED, any error here needs to be fatal
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShader *FShaderManager::Compile (const char *ShaderName, const char *ShaderPath, bool usediscard)
|
||||
{
|
||||
FString defines;
|
||||
// this can't be in the shader code due to ATI strangeness.
|
||||
if (gl.MaxLights() == 128) defines += "#define MAXLIGHTS128\n";
|
||||
if (!usediscard) defines += "#define NO_ALPHATEST\n";
|
||||
|
||||
FShader *shader = NULL;
|
||||
try
|
||||
{
|
||||
shader = new FShader(ShaderName);
|
||||
if (!shader->Load(ShaderName, "shaders/glsl/main.vp", "shaders/glsl/main.fp", ShaderPath, defines.GetChars()))
|
||||
{
|
||||
I_FatalError("Unable to load shader %s\n", ShaderName);
|
||||
}
|
||||
}
|
||||
catch(CRecoverableError &err)
|
||||
{
|
||||
if (shader != NULL) delete shader;
|
||||
shader = NULL;
|
||||
I_FatalError("Unable to load shader %s:\n%s\n", ShaderName, err.GetMessage());
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShader::ApplyMatrices(VSMatrix *proj, VSMatrix *view)
|
||||
{
|
||||
Bind();
|
||||
glUniformMatrix4fv(projectionmatrix_index, 1, false, proj->get());
|
||||
glUniformMatrix4fv(viewmatrix_index, 1, false, view->get());
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
struct FDefaultShader
|
||||
{
|
||||
const char * ShaderName;
|
||||
const char * gettexelfunc;
|
||||
};
|
||||
|
||||
// Note: the FIRST_USER_SHADER constant in gl_shader.h needs
|
||||
// to be updated whenever the size of this array is modified.
|
||||
static const FDefaultShader defaultshaders[]=
|
||||
{
|
||||
{"Default", "shaders/glsl/func_normal.fp"},
|
||||
{"Warp 1", "shaders/glsl/func_warp1.fp"},
|
||||
{"Warp 2", "shaders/glsl/func_warp2.fp"},
|
||||
{"Brightmap","shaders/glsl/func_brightmap.fp"},
|
||||
{"No Texture", "shaders/glsl/func_notexture.fp"},
|
||||
{"Basic Fuzz", "shaders/glsl/fuzz_standard.fp"},
|
||||
{"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp"},
|
||||
{"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp"},
|
||||
{"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp"},
|
||||
{"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp"},
|
||||
{"Noise Fuzz", "shaders/glsl/fuzz_noise.fp"},
|
||||
{"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp"},
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
static TArray<FString> usershaders;
|
||||
|
||||
struct FEffectShader
|
||||
{
|
||||
const char *ShaderName;
|
||||
const char *vp;
|
||||
const char *fp1;
|
||||
const char *fp2;
|
||||
const char *defines;
|
||||
};
|
||||
|
||||
static const FEffectShader effectshaders[]=
|
||||
{
|
||||
{ "fogboundary", "shaders/glsl/main.vp", "shaders/glsl/fogboundary.fp", NULL, "#define NO_ALPHATEST\n" },
|
||||
{ "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" },
|
||||
{ "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", NULL, "#define SIMPLE\n#define NO_ALPHATEST\n" },
|
||||
{ "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", NULL, "#define SIMPLE\n#define NO_ALPHATEST\n" },
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderManager::FShaderManager()
|
||||
{
|
||||
CompileShaders();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderManager::~FShaderManager()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShaderManager::CompileShaders()
|
||||
{
|
||||
mActiveShader = NULL;
|
||||
|
||||
mTextureEffects.Clear();
|
||||
mTextureEffectsNAT.Clear();
|
||||
for (int i = 0; i < MAX_EFFECTS; i++)
|
||||
{
|
||||
mEffectShaders[i] = NULL;
|
||||
}
|
||||
|
||||
for(int i=0;defaultshaders[i].ShaderName != NULL;i++)
|
||||
{
|
||||
FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, true);
|
||||
mTextureEffects.Push(shc);
|
||||
if (i <= 3)
|
||||
{
|
||||
FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, false);
|
||||
mTextureEffectsNAT.Push(shc);
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < usershaders.Size(); i++)
|
||||
{
|
||||
FString name = ExtractFileBase(usershaders[i]);
|
||||
FName sfn = name;
|
||||
|
||||
FShader *shc = Compile(sfn, usershaders[i], true);
|
||||
mTextureEffects.Push(shc);
|
||||
}
|
||||
|
||||
for(int i=0;i<MAX_EFFECTS;i++)
|
||||
{
|
||||
FShader *eff = new FShader(effectshaders[i].ShaderName);
|
||||
if (!eff->Load(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].fp1,
|
||||
effectshaders[i].fp2, effectshaders[i].defines))
|
||||
{
|
||||
delete eff;
|
||||
}
|
||||
else mEffectShaders[i] = eff;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShaderManager::Clean()
|
||||
{
|
||||
glUseProgram(0);
|
||||
mActiveShader = NULL;
|
||||
|
||||
for (unsigned int i = 0; i < mTextureEffectsNAT.Size(); i++)
|
||||
{
|
||||
if (mTextureEffectsNAT[i] != NULL) delete mTextureEffectsNAT[i];
|
||||
}
|
||||
for (unsigned int i = 0; i < mTextureEffects.Size(); i++)
|
||||
{
|
||||
if (mTextureEffects[i] != NULL) delete mTextureEffects[i];
|
||||
}
|
||||
for (int i = 0; i < MAX_EFFECTS; i++)
|
||||
{
|
||||
if (mEffectShaders[i] != NULL) delete mEffectShaders[i];
|
||||
mEffectShaders[i] = NULL;
|
||||
}
|
||||
mTextureEffects.Clear();
|
||||
mTextureEffectsNAT.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FShaderManager::Find(const char * shn)
|
||||
{
|
||||
FName sfn = shn;
|
||||
|
||||
for(unsigned int i=0;i<mTextureEffects.Size();i++)
|
||||
{
|
||||
if (mTextureEffects[i]->mName == sfn)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShaderManager::SetActiveShader(FShader *sh)
|
||||
{
|
||||
if (mActiveShader != sh)
|
||||
{
|
||||
glUseProgram(sh!= NULL? sh->GetHandle() : 0);
|
||||
mActiveShader = sh;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShader *FShaderManager::BindEffect(int effect)
|
||||
{
|
||||
if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[effect] != NULL)
|
||||
{
|
||||
mEffectShaders[effect]->Bind();
|
||||
return mEffectShaders[effect];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
EXTERN_CVAR(Int, gl_fuzztype)
|
||||
|
||||
void FShaderManager::ApplyMatrices(VSMatrix *proj, VSMatrix *view)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
mTextureEffects[i]->ApplyMatrices(proj, view);
|
||||
mTextureEffectsNAT[i]->ApplyMatrices(proj, view);
|
||||
}
|
||||
mTextureEffects[4]->ApplyMatrices(proj, view);
|
||||
if (gl_fuzztype != 0)
|
||||
{
|
||||
mTextureEffects[4+gl_fuzztype]->ApplyMatrices(proj, view);
|
||||
}
|
||||
for (unsigned i = 12; i < mTextureEffects.Size(); i++)
|
||||
{
|
||||
mTextureEffects[i]->ApplyMatrices(proj, view);
|
||||
}
|
||||
for (int i = 0; i < MAX_EFFECTS; i++)
|
||||
{
|
||||
mEffectShaders[i]->ApplyMatrices(proj, view);
|
||||
}
|
||||
if (mActiveShader != NULL) mActiveShader->Bind();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_DestroyUserShaders()
|
||||
{
|
||||
// todo
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Parses a shader definition
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_ParseHardwareShader(FScanner &sc, int deflump)
|
||||
{
|
||||
int type = FTexture::TEX_Any;
|
||||
bool disable_fullbright=false;
|
||||
bool thiswad = false;
|
||||
bool iwad = false;
|
||||
int maplump = -1;
|
||||
FString maplumpname;
|
||||
float speed = 1.f;
|
||||
|
||||
sc.MustGetString();
|
||||
if (sc.Compare("texture")) type = FTexture::TEX_Wall;
|
||||
else if (sc.Compare("flat")) type = FTexture::TEX_Flat;
|
||||
else if (sc.Compare("sprite")) type = FTexture::TEX_Sprite;
|
||||
else sc.UnGet();
|
||||
|
||||
sc.MustGetString();
|
||||
FTextureID no = TexMan.CheckForTexture(sc.String, type);
|
||||
FTexture *tex = TexMan[no];
|
||||
|
||||
sc.MustGetToken('{');
|
||||
while (!sc.CheckToken('}'))
|
||||
{
|
||||
sc.MustGetString();
|
||||
if (sc.Compare("shader"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
maplumpname = sc.String;
|
||||
}
|
||||
else if (sc.Compare("speed"))
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
speed = float(sc.Float);
|
||||
}
|
||||
}
|
||||
if (!tex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (maplumpname.IsNotEmpty())
|
||||
{
|
||||
if (tex->bWarped != 0)
|
||||
{
|
||||
Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->Name.GetChars());
|
||||
return;
|
||||
}
|
||||
tex->gl_info.shaderspeed = speed;
|
||||
for(unsigned i=0;i<usershaders.Size();i++)
|
||||
{
|
||||
if (!usershaders[i].CompareNoCase(maplumpname))
|
||||
{
|
||||
tex->gl_info.shaderindex = i + FIRST_USER_SHADER;
|
||||
return;
|
||||
}
|
||||
}
|
||||
tex->gl_info.shaderindex = usershaders.Push(maplumpname) + FIRST_USER_SHADER;
|
||||
}
|
||||
}
|
||||
|
330
src/gl/shaders/gl_shader.h
Normal file
330
src/gl/shaders/gl_shader.h
Normal file
|
@ -0,0 +1,330 @@
|
|||
|
||||
#ifndef __GL_SHADERS_H__
|
||||
#define __GL_SHADERS_H__
|
||||
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "name.h"
|
||||
|
||||
extern bool gl_shaderactive;
|
||||
|
||||
enum
|
||||
{
|
||||
VATTR_VERTEX = 0,
|
||||
VATTR_TEXCOORD = 1,
|
||||
VATTR_COLOR = 2,
|
||||
VATTR_VERTEX2 = 3
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FUniform1i
|
||||
{
|
||||
int mIndex;
|
||||
|
||||
public:
|
||||
void Init(GLuint hShader, const GLchar *name)
|
||||
{
|
||||
mIndex = glGetUniformLocation(hShader, name);
|
||||
}
|
||||
|
||||
void Set(int newvalue)
|
||||
{
|
||||
glUniform1i(mIndex, newvalue);
|
||||
}
|
||||
};
|
||||
|
||||
class FBufferedUniform1i
|
||||
{
|
||||
int mBuffer;
|
||||
int mIndex;
|
||||
|
||||
public:
|
||||
void Init(GLuint hShader, const GLchar *name)
|
||||
{
|
||||
mIndex = glGetUniformLocation(hShader, name);
|
||||
mBuffer = 0;
|
||||
}
|
||||
|
||||
void Set(int newvalue)
|
||||
{
|
||||
if (newvalue != mBuffer)
|
||||
{
|
||||
mBuffer = newvalue;
|
||||
glUniform1i(mIndex, newvalue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FBufferedUniform4i
|
||||
{
|
||||
int mBuffer[4];
|
||||
int mIndex;
|
||||
|
||||
public:
|
||||
void Init(GLuint hShader, const GLchar *name)
|
||||
{
|
||||
mIndex = glGetUniformLocation(hShader, name);
|
||||
memset(mBuffer, 0, sizeof(mBuffer));
|
||||
}
|
||||
|
||||
void Set(const int *newvalue)
|
||||
{
|
||||
if (memcmp(newvalue, mBuffer, sizeof(mBuffer)))
|
||||
{
|
||||
memcpy(mBuffer, newvalue, sizeof(mBuffer));
|
||||
glUniform4iv(mIndex, 1, newvalue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FBufferedUniform1f
|
||||
{
|
||||
float mBuffer;
|
||||
int mIndex;
|
||||
|
||||
public:
|
||||
void Init(GLuint hShader, const GLchar *name)
|
||||
{
|
||||
mIndex = glGetUniformLocation(hShader, name);
|
||||
mBuffer = 0;
|
||||
}
|
||||
|
||||
void Set(float newvalue)
|
||||
{
|
||||
if (newvalue != mBuffer)
|
||||
{
|
||||
mBuffer = newvalue;
|
||||
glUniform1f(mIndex, newvalue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FBufferedUniform2f
|
||||
{
|
||||
float mBuffer[2];
|
||||
int mIndex;
|
||||
|
||||
public:
|
||||
void Init(GLuint hShader, const GLchar *name)
|
||||
{
|
||||
mIndex = glGetUniformLocation(hShader, name);
|
||||
memset(mBuffer, 0, sizeof(mBuffer));
|
||||
}
|
||||
|
||||
void Set(const float *newvalue)
|
||||
{
|
||||
if (memcmp(newvalue, mBuffer, sizeof(mBuffer)))
|
||||
{
|
||||
memcpy(mBuffer, newvalue, sizeof(mBuffer));
|
||||
glUniform2fv(mIndex, 1, newvalue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FBufferedUniform4f
|
||||
{
|
||||
float mBuffer[4];
|
||||
int mIndex;
|
||||
|
||||
public:
|
||||
void Init(GLuint hShader, const GLchar *name)
|
||||
{
|
||||
mIndex = glGetUniformLocation(hShader, name);
|
||||
memset(mBuffer, 0, sizeof(mBuffer));
|
||||
}
|
||||
|
||||
void Set(const float *newvalue)
|
||||
{
|
||||
if (memcmp(newvalue, mBuffer, sizeof(mBuffer)))
|
||||
{
|
||||
memcpy(mBuffer, newvalue, sizeof(mBuffer));
|
||||
glUniform4fv(mIndex, 1, newvalue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FUniform4f
|
||||
{
|
||||
int mIndex;
|
||||
|
||||
public:
|
||||
void Init(GLuint hShader, const GLchar *name)
|
||||
{
|
||||
mIndex = glGetUniformLocation(hShader, name);
|
||||
}
|
||||
|
||||
void Set(const float *newvalue)
|
||||
{
|
||||
glUniform4fv(mIndex, 1, newvalue);
|
||||
}
|
||||
|
||||
void Set(float a, float b, float c, float d)
|
||||
{
|
||||
glUniform4f(mIndex, a, b, c, d);
|
||||
}
|
||||
};
|
||||
|
||||
class FBufferedUniformPE
|
||||
{
|
||||
PalEntry mBuffer;
|
||||
int mIndex;
|
||||
|
||||
public:
|
||||
void Init(GLuint hShader, const GLchar *name)
|
||||
{
|
||||
mIndex = glGetUniformLocation(hShader, name);
|
||||
mBuffer = 0;
|
||||
}
|
||||
|
||||
void Set(PalEntry newvalue)
|
||||
{
|
||||
if (newvalue != mBuffer)
|
||||
{
|
||||
mBuffer = newvalue;
|
||||
glUniform4f(mIndex, newvalue.r/255.f, newvalue.g/255.f, newvalue.b/255.f, newvalue.a/255.f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class FShader
|
||||
{
|
||||
friend class FShaderManager;
|
||||
friend class FRenderState;
|
||||
|
||||
unsigned int hShader;
|
||||
unsigned int hVertProg;
|
||||
unsigned int hFragProg;
|
||||
FName mName;
|
||||
|
||||
FBufferedUniform1f muDesaturation;
|
||||
FBufferedUniform1i muFogEnabled;
|
||||
FBufferedUniform1i muTextureMode;
|
||||
FBufferedUniform4f muCameraPos;
|
||||
FBufferedUniform4f muLightParms;
|
||||
FBufferedUniform2f muClipSplit;
|
||||
FUniform1i muFixedColormap;
|
||||
FUniform4f muColormapStart;
|
||||
FUniform4f muColormapRange;
|
||||
FBufferedUniform1i muLightIndex;
|
||||
FBufferedUniformPE muFogColor;
|
||||
FBufferedUniform4f muDynLightColor;
|
||||
FBufferedUniformPE muObjectColor;
|
||||
FUniform4f muGlowBottomColor;
|
||||
FUniform4f muGlowTopColor;
|
||||
FUniform4f muGlowBottomPlane;
|
||||
FUniform4f muGlowTopPlane;
|
||||
FBufferedUniform1f muInterpolationFactor;
|
||||
FBufferedUniform1f muClipHeightTop;
|
||||
FBufferedUniform1f muClipHeightBottom;
|
||||
FBufferedUniform1f muAlphaThreshold;
|
||||
FBufferedUniform1f muTimer;
|
||||
|
||||
int lights_index;
|
||||
int projectionmatrix_index;
|
||||
int viewmatrix_index;
|
||||
int modelmatrix_index;
|
||||
int texturematrix_index;
|
||||
public:
|
||||
int fakevb_index;
|
||||
private:
|
||||
int currentglowstate;
|
||||
int currentfixedcolormap;
|
||||
bool currentTextureMatrixState;
|
||||
bool currentModelMatrixState;
|
||||
|
||||
public:
|
||||
FShader(const char *name)
|
||||
: mName(name)
|
||||
{
|
||||
hShader = hVertProg = hFragProg = 0;
|
||||
currentglowstate = 0;
|
||||
currentfixedcolormap = 0;
|
||||
currentTextureMatrixState = true; // by setting the matrix state to 'true' it is guaranteed to be set the first time the render state gets applied.
|
||||
currentModelMatrixState = true;
|
||||
}
|
||||
|
||||
~FShader();
|
||||
|
||||
bool Load(const char * name, const char * vert_prog_lump, const char * fragprog, const char * fragprog2, const char *defines);
|
||||
|
||||
void SetColormapColor(float r, float g, float b, float r1, float g1, float b1);
|
||||
void SetGlowParams(float *topcolors, float topheight, float *bottomcolors, float bottomheight);
|
||||
void SetLightRange(int start, int end, int forceadd);
|
||||
|
||||
bool Bind();
|
||||
unsigned int GetHandle() const { return hShader; }
|
||||
|
||||
void ApplyMatrices(VSMatrix *proj, VSMatrix *view);
|
||||
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// The global shader manager
|
||||
//
|
||||
//==========================================================================
|
||||
class FShaderManager
|
||||
{
|
||||
TArray<FShader*> mTextureEffects;
|
||||
TArray<FShader*> mTextureEffectsNAT;
|
||||
FShader *mActiveShader;
|
||||
FShader *mEffectShaders[MAX_EFFECTS];
|
||||
|
||||
void Clean();
|
||||
void CompileShaders();
|
||||
|
||||
public:
|
||||
FShaderManager();
|
||||
~FShaderManager();
|
||||
FShader *Compile(const char *ShaderName, const char *ShaderPath, bool usediscard);
|
||||
int Find(const char *mame);
|
||||
FShader *BindEffect(int effect);
|
||||
void SetActiveShader(FShader *sh);
|
||||
void ApplyMatrices(VSMatrix *proj, VSMatrix *view);
|
||||
FShader *GetActiveShader() const
|
||||
{
|
||||
return mActiveShader;
|
||||
}
|
||||
|
||||
void ResetFixedColormap()
|
||||
{
|
||||
for (unsigned i = 0; i < mTextureEffects.Size(); i++)
|
||||
{
|
||||
mTextureEffects[i]->currentfixedcolormap = -1;
|
||||
}
|
||||
for (unsigned i = 0; i < mTextureEffectsNAT.Size(); i++)
|
||||
{
|
||||
mTextureEffectsNAT[i]->currentfixedcolormap = -1;
|
||||
}
|
||||
}
|
||||
|
||||
FShader *Get(unsigned int eff, bool alphateston)
|
||||
{
|
||||
// indices 0-2 match the warping modes, 3 is brightmap, 4 no texture, the following are custom
|
||||
if (!alphateston && eff <= 3)
|
||||
{
|
||||
return mTextureEffectsNAT[eff]; // Non-alphatest shaders are only created for default, warp1+2 and brightmap. The rest won't get used anyway
|
||||
}
|
||||
if (eff < mTextureEffects.Size())
|
||||
{
|
||||
return mTextureEffects[eff];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
#define FIRST_USER_SHADER 12
|
||||
|
||||
enum
|
||||
{
|
||||
LIGHTBUF_BINDINGPOINT = 1
|
||||
};
|
||||
|
||||
#endif
|
||||
|
698
src/gl/shaders/gl_texshader.cpp
Normal file
698
src/gl/shaders/gl_texshader.cpp
Normal file
|
@ -0,0 +1,698 @@
|
|||
/*
|
||||
** gl_shaders.cpp
|
||||
** Routines parsing/managing texture shaders.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2003 Timothy Stump
|
||||
** Copyright 2009 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 "gl/system/gl_system.h"
|
||||
#include "doomtype.h"
|
||||
#include "c_cvars.h"
|
||||
#include "sc_man.h"
|
||||
#include "textures/textures.h"
|
||||
#include "gl/shaders/gl_texshader.h"
|
||||
|
||||
CVAR(Bool, gl_texture_useshaders, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderLayer::FShaderLayer()
|
||||
{
|
||||
animate = false;
|
||||
emissive = false;
|
||||
blendFuncSrc = GL_SRC_ALPHA;
|
||||
blendFuncDst = GL_ONE_MINUS_SRC_ALPHA;
|
||||
offsetX = 0.f;
|
||||
offsetY = 0.f;
|
||||
centerX = 0.0f;
|
||||
centerY = 0.0f;
|
||||
rotate = 0.f;
|
||||
rotation = 0.f;
|
||||
adjustX.SetParams(0.f, 0.f, 0.f);
|
||||
adjustY.SetParams(0.f, 0.f, 0.f);
|
||||
scaleX.SetParams(1.f, 1.f, 0.f);
|
||||
scaleY.SetParams(1.f, 1.f, 0.f);
|
||||
alpha.SetParams(1.f, 1.f, 0.f);
|
||||
r.SetParams(1.f, 1.f, 0.f);
|
||||
g.SetParams(1.f, 1.f, 0.f);
|
||||
b.SetParams(1.f, 1.f, 0.f);
|
||||
flags = 0;
|
||||
layerMask = NULL;
|
||||
texgen = SHADER_TexGen_None;
|
||||
warp = false;
|
||||
warpspeed = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderLayer::FShaderLayer(const FShaderLayer &layer)
|
||||
{
|
||||
texture = layer.texture;
|
||||
animate = layer.animate;
|
||||
emissive = layer.emissive;
|
||||
adjustX = layer.adjustX;
|
||||
adjustY = layer.adjustY;
|
||||
blendFuncSrc = layer.blendFuncSrc;
|
||||
blendFuncDst = layer.blendFuncDst;
|
||||
offsetX = layer.offsetX;
|
||||
offsetY = layer.offsetY;
|
||||
centerX = layer.centerX;
|
||||
centerY = layer.centerX;
|
||||
rotate = layer.rotate;
|
||||
rotation = layer.rotation;
|
||||
scaleX = layer.scaleX;
|
||||
scaleY = layer.scaleY;
|
||||
vectorX = layer.vectorX;
|
||||
vectorY = layer.vectorY;
|
||||
alpha = layer.alpha;
|
||||
r = layer.r;
|
||||
g = layer.g;
|
||||
b = layer.b;
|
||||
flags = layer.flags;
|
||||
if (layer.layerMask)
|
||||
{
|
||||
layerMask = new FShaderLayer(*(layer.layerMask));
|
||||
}
|
||||
else
|
||||
{
|
||||
layerMask = NULL;
|
||||
}
|
||||
texgen = layer.texgen;
|
||||
warp = layer.warp;
|
||||
warpspeed = layer.warpspeed;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderLayer::~FShaderLayer()
|
||||
{
|
||||
if (layerMask)
|
||||
{
|
||||
delete layerMask;
|
||||
layerMask = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShaderLayer::Update(float diff)
|
||||
{
|
||||
r.Update(diff);
|
||||
g.Update(diff);
|
||||
b.Update(diff);
|
||||
alpha.Update(diff);
|
||||
vectorY.Update(diff);
|
||||
vectorX.Update(diff);
|
||||
scaleX.Update(diff);
|
||||
scaleY.Update(diff);
|
||||
adjustX.Update(diff);
|
||||
adjustY.Update(diff);
|
||||
srcFactor.Update(diff);
|
||||
dstFactor.Update(diff);
|
||||
|
||||
offsetX += vectorX * diff;
|
||||
if (offsetX >= 1.f) offsetX -= 1.f;
|
||||
if (offsetX < 0.f) offsetX += 1.f;
|
||||
|
||||
offsetY += vectorY * diff;
|
||||
if (offsetY >= 1.f) offsetY -= 1.f;
|
||||
if (offsetY < 0.f) offsetY += 1.f;
|
||||
|
||||
rotation += rotate * diff;
|
||||
if (rotation > 360.f) rotation -= 360.f;
|
||||
if (rotation < 0.f) rotation += 360.f;
|
||||
|
||||
if (layerMask != NULL) layerMask->Update(diff);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FParseKey
|
||||
{
|
||||
const char *name;
|
||||
int value;
|
||||
};
|
||||
|
||||
static const FParseKey CycleTags[]=
|
||||
{
|
||||
{"linear", CYCLE_Linear},
|
||||
{"sin", CYCLE_Sin},
|
||||
{"cos", CYCLE_Cos},
|
||||
{"sawtooth", CYCLE_SawTooth},
|
||||
{"square", CYCLE_Square},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static const FParseKey BlendTags[]=
|
||||
{
|
||||
{"GL_ZERO", GL_ZERO},
|
||||
{"GL_ONE", GL_ONE},
|
||||
|
||||
{"GL_DST_COLOR", GL_DST_COLOR},
|
||||
{"GL_ONE_MINUS_DST_COLOR", GL_ONE_MINUS_DST_COLOR},
|
||||
{"GL_DST_ALPHA", GL_DST_ALPHA},
|
||||
{"GL_ONE_MINUS_DST_ALPHA", GL_ONE_MINUS_DST_ALPHA},
|
||||
|
||||
{"GL_SRC_COLOR", GL_SRC_COLOR},
|
||||
{"GL_ONE_MINUS_SRC_COLOR", GL_ONE_MINUS_SRC_COLOR},
|
||||
{"GL_SRC_ALPHA", GL_SRC_ALPHA},
|
||||
{"GL_ONE_MINUS_SRC_ALPHA", GL_ONE_MINUS_SRC_ALPHA},
|
||||
|
||||
{"GL_SRC_ALPHA_SATURATE", GL_SRC_ALPHA_SATURATE},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CycleType FShaderLayer::ParseCycleType(FScanner &sc)
|
||||
{
|
||||
if (sc.GetString())
|
||||
{
|
||||
int t = sc.MatchString(&CycleTags[0].name, sizeof(CycleTags[0]));
|
||||
if (t > -1) return CycleType(CycleTags[t].value);
|
||||
sc.UnGet();
|
||||
}
|
||||
return CYCLE_Linear;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FShaderLayer::ParseLayer(FScanner &sc)
|
||||
{
|
||||
bool retval = true;
|
||||
float start, end, cycle, r1, r2, g1, g2, b1, b2;
|
||||
int type;
|
||||
|
||||
if (sc.GetString())
|
||||
{
|
||||
texture = TexMan.CheckForTexture(sc.String, FTexture::TEX_Wall);
|
||||
if (!texture.isValid())
|
||||
{
|
||||
sc.ScriptMessage("Unknown texture '%s'", sc.String);
|
||||
retval = false;
|
||||
}
|
||||
sc.MustGetStringName("{");
|
||||
while (!sc.CheckString("}"))
|
||||
{
|
||||
if (sc.End)
|
||||
{
|
||||
sc.ScriptError("Unexpected end of file encountered");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sc.Compare("alpha"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
alpha.ShouldCycle(true);
|
||||
alpha.SetCycleType(ParseCycleType(sc));
|
||||
|
||||
sc.GetFloat();
|
||||
start = sc.Float;
|
||||
sc.GetFloat();
|
||||
end = sc.Float;
|
||||
sc.GetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
alpha.SetParams(start, end, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
alpha.SetParams(float(sc.Float), float(sc.Float), 0.f);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("srcfactor"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
srcFactor.ShouldCycle(true);
|
||||
srcFactor.SetCycleType(ParseCycleType(sc));
|
||||
|
||||
sc.GetFloat();
|
||||
start = sc.Float;
|
||||
sc.GetFloat();
|
||||
end = sc.Float;
|
||||
sc.GetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
srcFactor.SetParams(start, end, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
srcFactor.SetParams(float(sc.Float), float(sc.Float), 0.f);
|
||||
}
|
||||
}
|
||||
if (sc.Compare("destfactor"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
dstFactor.ShouldCycle(true);
|
||||
dstFactor.SetCycleType(ParseCycleType(sc));
|
||||
|
||||
sc.GetFloat();
|
||||
start = sc.Float;
|
||||
sc.GetFloat();
|
||||
end = sc.Float;
|
||||
sc.GetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
dstFactor.SetParams(start, end, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
dstFactor.SetParams(float(sc.Float), float(sc.Float), 0.f);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("animate"))
|
||||
{
|
||||
sc.GetString();
|
||||
animate = sc.Compare("true");
|
||||
}
|
||||
else if (sc.Compare("blendfunc"))
|
||||
{
|
||||
sc.GetString();
|
||||
type = sc.MustMatchString(&BlendTags[0].name, sizeof(BlendTags[0]));
|
||||
blendFuncSrc = type;// BlendTags[type].value;
|
||||
|
||||
sc.GetString();
|
||||
type = sc.MustMatchString(&BlendTags[0].name, sizeof(BlendTags[0]));
|
||||
blendFuncDst = type; //BlendTags[type].value;
|
||||
}
|
||||
else if (sc.Compare("color"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
CycleType type = ParseCycleType(sc);
|
||||
r.ShouldCycle(true);
|
||||
g.ShouldCycle(true);
|
||||
b.ShouldCycle(true);
|
||||
r.SetCycleType(type);
|
||||
g.SetCycleType(type);
|
||||
b.SetCycleType(type);
|
||||
|
||||
sc.GetFloat();
|
||||
r1 = float(sc.Float);
|
||||
sc.GetFloat();
|
||||
g1 = float(sc.Float);
|
||||
sc.GetFloat();
|
||||
b1 = float(sc.Float);
|
||||
|
||||
// get color2
|
||||
sc.GetFloat();
|
||||
r2 = float(sc.Float);
|
||||
sc.GetFloat();
|
||||
g2 = float(sc.Float);
|
||||
sc.GetFloat();
|
||||
b2 = float(sc.Float);
|
||||
|
||||
// get cycle time
|
||||
sc.GetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
r.SetParams(r1, r2, cycle);
|
||||
g.SetParams(g1, g2, cycle);
|
||||
b.SetParams(b1, b2, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.GetFloat();
|
||||
r1 = float(sc.Float);
|
||||
sc.GetFloat();
|
||||
g1 = sc.Float;
|
||||
sc.GetFloat();
|
||||
b1 = sc.Float;
|
||||
|
||||
r.SetParams(r1, r1, 0.f);
|
||||
g.SetParams(g1, g1, 0.f);
|
||||
b.SetParams(b1, b1, 0.f);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("center"))
|
||||
{
|
||||
sc.GetFloat();
|
||||
centerX = sc.Float;
|
||||
sc.GetFloat();
|
||||
centerY = sc.Float;
|
||||
}
|
||||
else if (sc.Compare("emissive"))
|
||||
{
|
||||
sc.GetString();
|
||||
emissive = sc.Compare("true");
|
||||
}
|
||||
else if (sc.Compare("offset"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
adjustX.ShouldCycle(true);
|
||||
adjustY.ShouldCycle(true);
|
||||
|
||||
sc.GetFloat();
|
||||
r1 = sc.Float;
|
||||
sc.GetFloat();
|
||||
r2 = sc.Float;
|
||||
|
||||
sc.GetFloat();
|
||||
g1 = sc.Float;
|
||||
sc.GetFloat();
|
||||
g2 = sc.Float;
|
||||
|
||||
sc.GetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
offsetX = r1;
|
||||
offsetY = r2;
|
||||
|
||||
adjustX.SetParams(0.f, g1 - r1, cycle);
|
||||
adjustY.SetParams(0.f, g2 - r2, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.GetFloat();
|
||||
offsetX = sc.Float;
|
||||
sc.GetFloat();
|
||||
offsetY = sc.Float;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("offsetfunc"))
|
||||
{
|
||||
adjustX.SetCycleType(ParseCycleType(sc));
|
||||
adjustY.SetCycleType(ParseCycleType(sc));
|
||||
}
|
||||
else if (sc.Compare("mask"))
|
||||
{
|
||||
if (layerMask != NULL) delete layerMask;
|
||||
layerMask = new FShaderLayer;
|
||||
layerMask->ParseLayer(sc);
|
||||
}
|
||||
else if (sc.Compare("rotate"))
|
||||
{
|
||||
sc.GetFloat();
|
||||
rotate = sc.Float;
|
||||
}
|
||||
else if (sc.Compare("rotation"))
|
||||
{
|
||||
sc.GetFloat();
|
||||
rotation = sc.Float;
|
||||
}
|
||||
else if (sc.Compare("scale"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
scaleX.ShouldCycle(true);
|
||||
scaleY.ShouldCycle(true);
|
||||
|
||||
sc.GetFloat();
|
||||
r1 = sc.Float;
|
||||
sc.GetFloat();
|
||||
r2 = sc.Float;
|
||||
|
||||
sc.GetFloat();
|
||||
g1 = sc.Float;
|
||||
sc.GetFloat();
|
||||
g2 = sc.Float;
|
||||
|
||||
sc.GetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
scaleX.SetParams(r1, g1, cycle);
|
||||
scaleY.SetParams(r2, g2, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.GetFloat();
|
||||
scaleX.SetParams(sc.Float, sc.Float, 0.f);
|
||||
sc.GetFloat();
|
||||
scaleY.SetParams(sc.Float, sc.Float, 0.f);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("scalefunc"))
|
||||
{
|
||||
scaleX.SetCycleType(ParseCycleType(sc));
|
||||
scaleY.SetCycleType(ParseCycleType(sc));
|
||||
}
|
||||
else if (sc.Compare("texgen"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
if (sc.Compare("sphere"))
|
||||
{
|
||||
texgen = SHADER_TexGen_Sphere;
|
||||
}
|
||||
else
|
||||
{
|
||||
texgen = SHADER_TexGen_None;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("vector"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
vectorX.ShouldCycle(true);
|
||||
vectorY.ShouldCycle(true);
|
||||
|
||||
sc.GetFloat();
|
||||
r1 = sc.Float;
|
||||
sc.GetFloat();
|
||||
g1 = sc.Float;
|
||||
sc.GetFloat();
|
||||
r2 = sc.Float;
|
||||
sc.GetFloat();
|
||||
g2 = sc.Float;
|
||||
sc.GetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
vectorX.SetParams(r1, r2, cycle);
|
||||
vectorY.SetParams(g1, g2, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.GetFloat();
|
||||
vectorX.SetParams(sc.Float, sc.Float, 0.f);
|
||||
sc.GetFloat();
|
||||
vectorY.SetParams(sc.Float, sc.Float, 0.f);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("vectorfunc"))
|
||||
{
|
||||
vectorX.SetCycleType(ParseCycleType(sc));
|
||||
vectorY.SetCycleType(ParseCycleType(sc));
|
||||
}
|
||||
else if (sc.Compare("warp"))
|
||||
{
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
warp = sc.Number >= 0 && sc.Number <= 2? sc.Number : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// compatibility with ZDoomGL
|
||||
sc.MustGetString();
|
||||
warp = sc.Compare("true");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("Unknown keyword '%s' in shader layer", sc.String);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FTextureShader::FTextureShader()
|
||||
{
|
||||
layers.Clear();
|
||||
lastUpdate = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FTextureShader::ParseShader(FScanner &sc, TArray<FTextureID> &names)
|
||||
{
|
||||
bool retval = true;
|
||||
|
||||
if (sc.GetString())
|
||||
{
|
||||
name = sc.String;
|
||||
|
||||
sc.MustGetStringName("{");
|
||||
while (!sc.CheckString("}"))
|
||||
{
|
||||
if (sc.End)
|
||||
{
|
||||
sc.ScriptError("Unexpected end of file encountered");
|
||||
return false;
|
||||
}
|
||||
else if (sc.Compare("layer"))
|
||||
{
|
||||
FShaderLayer *lay = new FShaderLayer;
|
||||
if (lay->ParseLayer(sc))
|
||||
{
|
||||
if (layers.Size() < 8)
|
||||
{
|
||||
layers.Push(lay);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete lay;
|
||||
sc.ScriptMessage("Only 8 layers per texture allowed.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete lay;
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("Unknown keyword '%s' in shader", sc.String);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FTextureShader::Update(int framems)
|
||||
{
|
||||
float diff = (framems - lastUpdate) / 1000.f;
|
||||
|
||||
if (lastUpdate != 0) // && !paused && !bglobal.freeze)
|
||||
{
|
||||
for (unsigned int i = 0; i < layers.Size(); i++)
|
||||
{
|
||||
layers[i]->Update(diff);
|
||||
}
|
||||
}
|
||||
lastUpdate = framems;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FTextureShader::FakeUpdate(int framems)
|
||||
{
|
||||
lastUpdate = framems;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString FTextureShader::CreateName()
|
||||
{
|
||||
FString compose = "custom";
|
||||
for(unsigned i=0; i<layers.Size(); i++)
|
||||
{
|
||||
compose.AppendFormat("@%de%ds%ud%ut%dw%d", i, layers[i]->emissive,
|
||||
layers[i]->blendFuncSrc, layers[i]->blendFuncDst, layers[i]->texgen, layers[i]->warp);
|
||||
}
|
||||
return compose;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString FTextureShader::GenerateCode()
|
||||
{
|
||||
static const char *funcnames[] = {"gettexel", "getwarp1", "getwarp2" };
|
||||
static const char *srcblend[] = { "vec4(0.0)", "src", "src*dest", "1.0-src*dest", "src*dest.a", "1.0-src*dest.a",
|
||||
"src*src", "1.0-src*src", "src*src.a", "1.0-src*src", "vec4(src.rgb*src.a, 1)" };
|
||||
static const char *dstblend[] = { "vec4(0.0)", "dest", "dest*dest", "1.0-dest*dest", "dest*dest.a", "1.0-dest*dest.a",
|
||||
"dest*src", "1.0-dest*src", "dest*src.a", "1.0-dest*src", "vec4(dest.rgb*src.a, 1)" };
|
||||
FString compose;
|
||||
for(unsigned i=0; i<layers.Size(); i++)
|
||||
{
|
||||
compose.AppendFormat("src = %s(texture%d, glTexCoord[%d].st) * colors[%d];\n",
|
||||
funcnames[layers[i]->warp], i+1, i, i);
|
||||
if (!layers[i]->emissive) compose.AppendFormat("src.rgb *= gl_Color.rgb;\n");
|
||||
compose.AppendFormat("dest = (%s)*srcfactor + (%s)*dstfactor;\n",
|
||||
srcblend[layers[i]->blendFuncSrc], dstblend[layers[i]->blendFuncDst]);
|
||||
}
|
||||
return compose;
|
||||
}
|
||||
|
96
src/gl/shaders/gl_texshader.h
Normal file
96
src/gl/shaders/gl_texshader.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
|
||||
#ifndef __GL_TEXSHADERS_H__
|
||||
#define __GL_TEXSHADERS_H__
|
||||
|
||||
|
||||
#include "tarray.h"
|
||||
#include "zstring.h"
|
||||
#include "gl/utility/gl_cycler.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
SHADER_TexGen_None = 0,
|
||||
SHADER_TexGen_Sphere,
|
||||
NUM_TexGenTypes
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FShaderLayer
|
||||
{
|
||||
public:
|
||||
FShaderLayer();
|
||||
FShaderLayer(const FShaderLayer &layer);
|
||||
~FShaderLayer();
|
||||
void Update(float diff);
|
||||
CycleType ParseCycleType(FScanner &sc);
|
||||
bool ParseLayer(FScanner &sc);
|
||||
|
||||
FTextureID texture;
|
||||
int warpspeed;
|
||||
unsigned char warp;
|
||||
bool animate;
|
||||
bool emissive;
|
||||
unsigned char texgen;
|
||||
float centerX, centerY;
|
||||
float rotation;
|
||||
float rotate;
|
||||
float offsetX, offsetY;
|
||||
FCycler adjustX, adjustY;
|
||||
FCycler vectorX, vectorY;
|
||||
FCycler scaleX, scaleY;
|
||||
FCycler alpha;
|
||||
FCycler r, g, b;
|
||||
FCycler srcFactor, dstFactor;
|
||||
unsigned int flags;
|
||||
unsigned int blendFuncSrc, blendFuncDst;
|
||||
FShaderLayer *layerMask;
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FTextureShader
|
||||
{
|
||||
public:
|
||||
FTextureShader();
|
||||
bool ParseShader(FScanner &sc, TArray<FTextureID> &names);
|
||||
bool Available();
|
||||
bool Setup(float time);
|
||||
void Update(int framems);
|
||||
void FakeUpdate(int framems);
|
||||
FString CreateName();
|
||||
FString GenerateCode();
|
||||
|
||||
FName name;
|
||||
TDeletingArray <FShaderLayer *> layers; // layers for shader
|
||||
unsigned int lastUpdate;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
//extern TArray<FShader *> Shaders[NUM_ShaderClasses];
|
||||
//extern TArray<FShader *> ShaderLookup[NUM_ShaderClasses];
|
||||
|
||||
void GL_InitShaders();
|
||||
void GL_ReleaseShaders();
|
||||
void GL_UpdateShaders();
|
||||
void GL_FakeUpdateShaders();
|
||||
//void GL_UpdateShader(FShader *shader);
|
||||
void GL_DrawShaders();
|
||||
//FShader *GL_ShaderForTexture(FTexture *tex);
|
||||
|
||||
bool GL_ParseShader();
|
||||
*/
|
||||
|
||||
|
||||
#endif // __GL_TEXSHADERS_H__
|
64
src/gl/stereo3d/gl_anaglyph.cpp
Normal file
64
src/gl/stereo3d/gl_anaglyph.cpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
** gl_anaglyph.cpp
|
||||
** Color mask based stereoscopic 3D modes for GZDoom
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Christopher Bruns
|
||||
** 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 "gl_anaglyph.h"
|
||||
|
||||
namespace s3d {
|
||||
|
||||
MaskAnaglyph::MaskAnaglyph(const ColorMask& leftColorMask, double ipdMeters)
|
||||
: leftEye(leftColorMask, ipdMeters), rightEye(leftColorMask.inverse(), ipdMeters)
|
||||
{
|
||||
eye_ptrs.Push(&leftEye);
|
||||
eye_ptrs.Push(&rightEye);
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
const GreenMagenta& GreenMagenta::getInstance(FLOATTYPE ipd)
|
||||
{
|
||||
static GreenMagenta instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
const RedCyan& RedCyan::getInstance(FLOATTYPE ipd)
|
||||
{
|
||||
static RedCyan instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
} /* namespace s3d */
|
124
src/gl/stereo3d/gl_anaglyph.h
Normal file
124
src/gl/stereo3d/gl_anaglyph.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
** gl_anaglyph.h
|
||||
** Color mask based stereoscopic 3D modes for GZDoom
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Christopher Bruns
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_ANAGLYPH_H_
|
||||
#define GL_ANAGLYPH_H_
|
||||
|
||||
#include "gl_stereo3d.h"
|
||||
#include "gl_stereo_leftright.h"
|
||||
#include "gl/system/gl_system.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
|
||||
|
||||
namespace s3d {
|
||||
|
||||
|
||||
class ColorMask
|
||||
{
|
||||
public:
|
||||
ColorMask(bool r, bool g, bool b) : r(r), g(g), b(b) {}
|
||||
ColorMask inverse() const { return ColorMask(!r, !g, !b); }
|
||||
|
||||
bool r;
|
||||
bool g;
|
||||
bool b;
|
||||
};
|
||||
|
||||
|
||||
class AnaglyphLeftPose : public LeftEyePose
|
||||
{
|
||||
public:
|
||||
AnaglyphLeftPose(const ColorMask& colorMask, float ipd) : LeftEyePose(ipd), colorMask(colorMask) {}
|
||||
virtual void SetUp() const {
|
||||
gl_RenderState.SetColorMask(colorMask.r, colorMask.g, colorMask.b, true);
|
||||
gl_RenderState.ApplyColorMask();
|
||||
}
|
||||
virtual void TearDown() const {
|
||||
gl_RenderState.ResetColorMask();
|
||||
gl_RenderState.ApplyColorMask();
|
||||
}
|
||||
private:
|
||||
ColorMask colorMask;
|
||||
};
|
||||
|
||||
class AnaglyphRightPose : public RightEyePose
|
||||
{
|
||||
public:
|
||||
AnaglyphRightPose(const ColorMask& colorMask, float ipd) : RightEyePose(ipd), colorMask(colorMask) {}
|
||||
virtual void SetUp() const {
|
||||
gl_RenderState.SetColorMask(colorMask.r, colorMask.g, colorMask.b, true);
|
||||
gl_RenderState.ApplyColorMask();
|
||||
}
|
||||
virtual void TearDown() const {
|
||||
gl_RenderState.ResetColorMask();
|
||||
gl_RenderState.ApplyColorMask();
|
||||
}
|
||||
private:
|
||||
ColorMask colorMask;
|
||||
};
|
||||
|
||||
class MaskAnaglyph : public Stereo3DMode
|
||||
{
|
||||
public:
|
||||
MaskAnaglyph(const ColorMask& leftColorMask, double ipdMeters);
|
||||
private:
|
||||
AnaglyphLeftPose leftEye;
|
||||
AnaglyphRightPose rightEye;
|
||||
};
|
||||
|
||||
|
||||
class RedCyan : public MaskAnaglyph
|
||||
{
|
||||
public:
|
||||
static const RedCyan& getInstance(float ipd);
|
||||
|
||||
RedCyan(float ipd) : MaskAnaglyph(ColorMask(true, false, false), ipd) {}
|
||||
};
|
||||
|
||||
class GreenMagenta : public MaskAnaglyph
|
||||
{
|
||||
public:
|
||||
static const GreenMagenta& getInstance(float ipd);
|
||||
|
||||
GreenMagenta(float ipd) : MaskAnaglyph(ColorMask(false, true, false), ipd) {}
|
||||
};
|
||||
|
||||
// TODO matrix anaglyph
|
||||
|
||||
|
||||
} /* namespace st3d */
|
||||
|
||||
|
||||
#endif /* GL_ANAGLYPH_H_ */
|
91
src/gl/stereo3d/gl_stereo3d.cpp
Normal file
91
src/gl/stereo3d/gl_stereo3d.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
** gl_stereo3d.cpp
|
||||
** Stereoscopic 3D API
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Christopher Bruns
|
||||
** 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 "gl/stereo3d/gl_stereo3d.h"
|
||||
#include "vectors.h" // RAD2DEG
|
||||
#include "doomtype.h" // M_PI
|
||||
|
||||
namespace s3d {
|
||||
|
||||
|
||||
/* virtual */
|
||||
VSMatrix EyePose::GetProjection(FLOATTYPE fov, FLOATTYPE aspectRatio, FLOATTYPE fovRatio) const
|
||||
{
|
||||
VSMatrix result;
|
||||
|
||||
// Lifted from gl_scene.cpp FGLRenderer::SetProjection()
|
||||
float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)));
|
||||
result.perspective(fovy, aspectRatio, 5.f, 65536.f);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
Viewport EyePose::GetViewport(const Viewport& fullViewport) const
|
||||
{
|
||||
return fullViewport;
|
||||
}
|
||||
|
||||
|
||||
/* virtual */
|
||||
void EyePose::GetViewShift(FLOATTYPE yaw, FLOATTYPE outViewShift[3]) const
|
||||
{
|
||||
// pass-through for Mono view
|
||||
outViewShift[0] = 0;
|
||||
outViewShift[1] = 0;
|
||||
outViewShift[2] = 0;
|
||||
}
|
||||
|
||||
|
||||
Stereo3DMode::Stereo3DMode()
|
||||
{
|
||||
}
|
||||
|
||||
Stereo3DMode::~Stereo3DMode()
|
||||
{
|
||||
}
|
||||
|
||||
// Avoid static initialization order fiasco by declaring first Mode type (Mono) here in the
|
||||
// same source file as Stereo3DMode::getCurrentMode()
|
||||
// https://isocpp.org/wiki/faq/ctors#static-init-order
|
||||
|
||||
/* static */
|
||||
const MonoView& MonoView::getInstance()
|
||||
{
|
||||
static MonoView instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
} /* namespace s3d */
|
113
src/gl/stereo3d/gl_stereo3d.h
Normal file
113
src/gl/stereo3d/gl_stereo3d.h
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
** gl_stereo3d.h
|
||||
** Stereoscopic 3D API
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Christopher Bruns
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_STEREO3D_H_
|
||||
#define GL_STEREO3D_H_
|
||||
|
||||
#include <cstring> // needed for memcpy on linux, which is needed by VSMatrix copy ctor
|
||||
#include "tarray.h"
|
||||
#include "gl/data/gl_matrix.h"
|
||||
|
||||
|
||||
/* stereoscopic 3D API */
|
||||
namespace s3d {
|
||||
|
||||
|
||||
/* Subregion of current display window */
|
||||
class Viewport
|
||||
{
|
||||
public:
|
||||
int x, y;
|
||||
int width, height;
|
||||
};
|
||||
|
||||
|
||||
/* Viewpoint of one eye */
|
||||
class EyePose
|
||||
{
|
||||
public:
|
||||
EyePose() {}
|
||||
virtual ~EyePose() {}
|
||||
virtual VSMatrix GetProjection(FLOATTYPE fov, FLOATTYPE aspectRatio, FLOATTYPE fovRatio) const;
|
||||
virtual Viewport GetViewport(const Viewport& fullViewport) const;
|
||||
virtual void GetViewShift(FLOATTYPE yaw, FLOATTYPE outViewShift[3]) const;
|
||||
virtual void SetUp() const {};
|
||||
virtual void TearDown() const {};
|
||||
};
|
||||
|
||||
|
||||
/* Base class for stereoscopic 3D rendering modes */
|
||||
class Stereo3DMode
|
||||
{
|
||||
public:
|
||||
/* static methods for managing the selected stereoscopic view state */
|
||||
static const Stereo3DMode& getCurrentMode();
|
||||
|
||||
Stereo3DMode();
|
||||
virtual ~Stereo3DMode();
|
||||
virtual int eye_count() const { return eye_ptrs.Size(); }
|
||||
virtual const EyePose * getEyePose(int ix) const { return eye_ptrs(ix); }
|
||||
|
||||
/* hooks for setup and cleanup operations for each stereo mode */
|
||||
virtual void SetUp() const {};
|
||||
virtual void TearDown() const {};
|
||||
|
||||
protected:
|
||||
TArray<const EyePose *> eye_ptrs;
|
||||
|
||||
private:
|
||||
static Stereo3DMode const * currentStereo3DMode;
|
||||
static void setCurrentMode(const Stereo3DMode& mode);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Ordinary non-3D rendering
|
||||
*/
|
||||
class MonoView : public Stereo3DMode
|
||||
{
|
||||
public:
|
||||
static const MonoView& getInstance();
|
||||
|
||||
protected:
|
||||
MonoView() { eye_ptrs.Push(¢ralEye); }
|
||||
EyePose centralEye;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace st3d */
|
||||
|
||||
|
||||
#endif /* GL_STEREO3D_H_ */
|
92
src/gl/stereo3d/gl_stereo_cvars.cpp
Normal file
92
src/gl/stereo3d/gl_stereo_cvars.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
** gl_stereo_cvars.cpp
|
||||
** Console variables related to stereoscopic 3D in GZDoom
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Christopher Bruns
|
||||
** 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 "gl/stereo3d/gl_stereo3d.h"
|
||||
#include "gl/stereo3d/gl_stereo_leftright.h"
|
||||
#include "gl/stereo3d/gl_anaglyph.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
|
||||
// Set up 3D-specific console variables:
|
||||
CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG)
|
||||
|
||||
// intraocular distance in meters
|
||||
CVAR(Float, vr_ipd, 0.062f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // METERS
|
||||
|
||||
// distance between viewer and the display screen
|
||||
CVAR(Float, vr_screendist, 0.80f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS
|
||||
|
||||
// default conversion between (vertical) DOOM units and meters
|
||||
CVAR(Float, vr_hunits_per_meter, 41.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS
|
||||
|
||||
// Manage changing of 3D modes:
|
||||
namespace s3d {
|
||||
|
||||
// Initialize static member
|
||||
Stereo3DMode const * Stereo3DMode::currentStereo3DMode = 0; // "nullptr" not resolved on linux (presumably not C++11)
|
||||
|
||||
/* static */
|
||||
void Stereo3DMode::setCurrentMode(const Stereo3DMode& mode) {
|
||||
Stereo3DMode::currentStereo3DMode = &mode;
|
||||
}
|
||||
|
||||
/* static */
|
||||
const Stereo3DMode& Stereo3DMode::getCurrentMode()
|
||||
{
|
||||
// NOTE: Ensure that these vr_mode values correspond to the ones in wadsrc/static/menudef.z
|
||||
switch (vr_mode)
|
||||
{
|
||||
case 1:
|
||||
setCurrentMode(GreenMagenta::getInstance(vr_ipd));
|
||||
break;
|
||||
case 2:
|
||||
setCurrentMode(RedCyan::getInstance(vr_ipd));
|
||||
break;
|
||||
// TODO: missing indices 3, 4 for not-yet-implemented side-by-side modes, to match values from GZ3Doom
|
||||
case 5:
|
||||
setCurrentMode(LeftEyeView::getInstance(vr_ipd));
|
||||
break;
|
||||
case 6:
|
||||
setCurrentMode(RightEyeView::getInstance(vr_ipd));
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
setCurrentMode(MonoView::getInstance());
|
||||
break;
|
||||
}
|
||||
return *currentStereo3DMode;
|
||||
}
|
||||
|
||||
} /* namespace s3d */
|
||||
|
101
src/gl/stereo3d/gl_stereo_leftright.cpp
Normal file
101
src/gl/stereo3d/gl_stereo_leftright.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
** gl_stereo_leftright.cpp
|
||||
** Offsets for left and right eye views
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Christopher Bruns
|
||||
** 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 "gl_stereo_leftright.h"
|
||||
#include "vectors.h" // RAD2DEG
|
||||
#include "doomtype.h" // M_PI
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include <cmath>
|
||||
|
||||
EXTERN_CVAR(Float, vr_screendist)
|
||||
EXTERN_CVAR(Float, vr_hunits_per_meter)
|
||||
|
||||
namespace s3d {
|
||||
|
||||
|
||||
/* virtual */
|
||||
VSMatrix ShiftedEyePose::GetProjection(FLOATTYPE fov, FLOATTYPE aspectRatio, FLOATTYPE fovRatio) const
|
||||
{
|
||||
double zNear = 5.0;
|
||||
double zFar = 65536.0;
|
||||
|
||||
// For stereo 3D, use asymmetric frustum shift in projection matrix
|
||||
// Q: shouldn't shift vary with roll angle, at least for desktop display?
|
||||
// A: No. (lab) roll is not measured on desktop display (yet)
|
||||
double frustumShift = zNear * shift / vr_screendist; // meters cancel, leaving doom units
|
||||
// double frustumShift = 0; // Turning off shift for debugging
|
||||
double fH = zNear * tan(DEG2RAD(fov) / 2) / fovRatio;
|
||||
double fW = fH * aspectRatio;
|
||||
double left = -fW - frustumShift;
|
||||
double right = fW - frustumShift;
|
||||
double bottom = -fH;
|
||||
double top = fH;
|
||||
|
||||
VSMatrix result(1);
|
||||
result.frustum(left, right, bottom, top, zNear, zFar);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* virtual */
|
||||
void ShiftedEyePose::GetViewShift(FLOATTYPE yaw, FLOATTYPE outViewShift[3]) const
|
||||
{
|
||||
FLOATTYPE dx = cos(DEG2RAD(yaw)) * vr_hunits_per_meter * shift;
|
||||
FLOATTYPE dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * shift;
|
||||
outViewShift[0] = dx;
|
||||
outViewShift[1] = dy;
|
||||
outViewShift[2] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
const LeftEyeView& LeftEyeView::getInstance(FLOATTYPE ipd)
|
||||
{
|
||||
static LeftEyeView instance(ipd);
|
||||
instance.setIpd(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
const RightEyeView& RightEyeView::getInstance(FLOATTYPE ipd)
|
||||
{
|
||||
static RightEyeView instance(ipd);
|
||||
instance.setIpd(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
} /* namespace s3d */
|
106
src/gl/stereo3d/gl_stereo_leftright.h
Normal file
106
src/gl/stereo3d/gl_stereo_leftright.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
** gl_stereo_leftright.h
|
||||
** Offsets for left and right eye views
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Christopher Bruns
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_STEREO_LEFTRIGHT_H_
|
||||
#define GL_STEREO_LEFTRIGHT_H_
|
||||
|
||||
#include "gl_stereo3d.h"
|
||||
|
||||
namespace s3d {
|
||||
|
||||
|
||||
class ShiftedEyePose : public EyePose
|
||||
{
|
||||
public:
|
||||
ShiftedEyePose(FLOATTYPE shift) : shift(shift) {};
|
||||
FLOATTYPE getShift() const { return shift; }
|
||||
void setShift(FLOATTYPE shift) { this->shift = shift; }
|
||||
virtual VSMatrix GetProjection(FLOATTYPE fov, FLOATTYPE aspectRatio, FLOATTYPE fovRatio) const;
|
||||
virtual void GetViewShift(FLOATTYPE yaw, FLOATTYPE outViewShift[3]) const;
|
||||
protected:
|
||||
FLOATTYPE shift;
|
||||
};
|
||||
|
||||
|
||||
class LeftEyePose : public ShiftedEyePose
|
||||
{
|
||||
public:
|
||||
LeftEyePose(FLOATTYPE ipd) : ShiftedEyePose( FLOATTYPE(-0.5) * ipd) {}
|
||||
FLOATTYPE getIpd() const { return FLOATTYPE(-2.0)*getShift(); }
|
||||
void setIpd(FLOATTYPE ipd) { setShift(FLOATTYPE(-0.5)*ipd); }
|
||||
};
|
||||
|
||||
|
||||
class RightEyePose : public ShiftedEyePose
|
||||
{
|
||||
public:
|
||||
RightEyePose(FLOATTYPE ipd) : ShiftedEyePose(FLOATTYPE(+0.5)*ipd) {}
|
||||
FLOATTYPE getIpd() const { return FLOATTYPE(+2.0)*shift; }
|
||||
void setIpd(FLOATTYPE ipd) { setShift(FLOATTYPE(+0.5)*ipd); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* As if viewed through the left eye only
|
||||
*/
|
||||
class LeftEyeView : public Stereo3DMode
|
||||
{
|
||||
public:
|
||||
static const LeftEyeView& getInstance(FLOATTYPE ipd);
|
||||
|
||||
LeftEyeView(FLOATTYPE ipd) : eye(ipd) { eye_ptrs.Push(&eye); }
|
||||
FLOATTYPE getIpd() const { return eye.getIpd(); }
|
||||
void setIpd(FLOATTYPE ipd) { eye.setIpd(ipd); }
|
||||
protected:
|
||||
LeftEyePose eye;
|
||||
};
|
||||
|
||||
|
||||
class RightEyeView : public Stereo3DMode
|
||||
{
|
||||
public:
|
||||
static const RightEyeView& getInstance(FLOATTYPE ipd);
|
||||
|
||||
RightEyeView(FLOATTYPE ipd) : eye(ipd) { eye_ptrs.Push(&eye); }
|
||||
FLOATTYPE getIpd() const { return eye.getIpd(); }
|
||||
void setIpd(FLOATTYPE ipd) { eye.setIpd(ipd); }
|
||||
protected:
|
||||
RightEyePose eye;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace s3d */
|
||||
|
||||
#endif /* GL_STEREO_LEFTRIGHT_H_ */
|
62
src/gl/stereo3d/scoped_color_mask.h
Normal file
62
src/gl/stereo3d/scoped_color_mask.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
** scoped_color_mask.h
|
||||
** Stack-scoped class for temporarily changing the OpenGL color mask setting.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Christopher Bruns
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_STEREO3D_SCOPED_COLOR_MASK_H_
|
||||
#define GL_STEREO3D_SCOPED_COLOR_MASK_H_
|
||||
|
||||
#include "gl/system/gl_system.h"
|
||||
|
||||
/**
|
||||
* Temporarily change color mask
|
||||
*/
|
||||
class ScopedColorMask
|
||||
{
|
||||
public:
|
||||
ScopedColorMask(bool r, bool g, bool b, bool a)
|
||||
{
|
||||
gl_RenderState.GetColorMask(saved[0], saved[1], saved[2], saved[3]);
|
||||
gl_RenderState.SetColorMask(r, g, b, a);
|
||||
gl_RenderState.ApplyColorMask();
|
||||
}
|
||||
~ScopedColorMask() {
|
||||
gl_RenderState.SetColorMask(saved[0], saved[1], saved[2], saved[3]);
|
||||
gl_RenderState.ApplyColorMask();
|
||||
}
|
||||
private:
|
||||
bool saved[4];
|
||||
};
|
||||
|
||||
|
||||
#endif // GL_STEREO3D_SCOPED_COLOR_MASK_H_
|
65
src/gl/stereo3d/scoped_view_shifter.cpp
Normal file
65
src/gl/stereo3d/scoped_view_shifter.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
** scoped_view_shifter.cpp
|
||||
** Stack-scoped class for temporarily changing player viewpoint global variables viewx, viewy, viewz.
|
||||
** Used for stereoscopic 3D.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Christopher Bruns
|
||||
** 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 "scoped_view_shifter.h"
|
||||
#include "r_utility.h"
|
||||
|
||||
namespace s3d {
|
||||
|
||||
ScopedViewShifter::ScopedViewShifter(float dxyz[3]) // in meters
|
||||
{
|
||||
// save original values
|
||||
cachedViewx = viewx;
|
||||
cachedViewy = viewy;
|
||||
cachedViewz = viewz;
|
||||
// modify values
|
||||
float fViewx = FIXED2FLOAT(viewx) - dxyz[0];
|
||||
float fViewy = FIXED2FLOAT(viewy) + dxyz[1];
|
||||
float fViewz = FIXED2FLOAT(viewz) + dxyz[2];
|
||||
viewx = FLOAT2FIXED(fViewx);
|
||||
viewy = FLOAT2FIXED(fViewy);
|
||||
viewz = FLOAT2FIXED(fViewz);
|
||||
}
|
||||
|
||||
ScopedViewShifter::~ScopedViewShifter()
|
||||
{
|
||||
// restore original values
|
||||
viewx = cachedViewx;
|
||||
viewy = cachedViewy;
|
||||
viewz = cachedViewz;
|
||||
}
|
||||
|
||||
}
|
61
src/gl/stereo3d/scoped_view_shifter.h
Normal file
61
src/gl/stereo3d/scoped_view_shifter.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
** scoped_view_shifter.h
|
||||
** Stack-scoped class for temporarily changing player viewpoint global variables viewx, viewy, viewz.
|
||||
** Used for stereoscopic 3D.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2015 Christopher Bruns
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_
|
||||
#define GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_
|
||||
|
||||
#include "basictypes.h"
|
||||
|
||||
namespace s3d {
|
||||
|
||||
/**
|
||||
* Temporarily shift viewx, viewy, viewz
|
||||
*/
|
||||
class ScopedViewShifter
|
||||
{
|
||||
public:
|
||||
ScopedViewShifter(float dxyz[3]); // in meters
|
||||
~ScopedViewShifter();
|
||||
|
||||
private:
|
||||
fixed_t cachedViewx;
|
||||
fixed_t cachedViewy;
|
||||
fixed_t cachedViewz;
|
||||
};
|
||||
|
||||
} /* namespace s3d */
|
||||
|
||||
#endif // GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_
|
44
src/gl/system/gl_cvars.h
Normal file
44
src/gl/system/gl_cvars.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
|
||||
|
||||
#ifndef _GL_INTERN_H
|
||||
#define _GL_INTERN_H
|
||||
|
||||
#include "r_defs.h"
|
||||
#include "c_cvars.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
|
||||
EXTERN_CVAR(Bool,gl_enhanced_nightvision)
|
||||
EXTERN_CVAR(Int, screenblocks);
|
||||
EXTERN_CVAR(Bool, gl_texture)
|
||||
EXTERN_CVAR(Int, gl_texture_filter)
|
||||
EXTERN_CVAR(Float, gl_texture_filter_anisotropic)
|
||||
EXTERN_CVAR(Int, gl_texture_format)
|
||||
EXTERN_CVAR(Bool, gl_texture_usehires)
|
||||
EXTERN_CVAR(Bool, gl_usefb)
|
||||
|
||||
EXTERN_CVAR(Int, gl_weaponlight)
|
||||
|
||||
EXTERN_CVAR (Bool, gl_lights);
|
||||
EXTERN_CVAR (Bool, gl_attachedlights);
|
||||
EXTERN_CVAR (Bool, gl_lights_checkside);
|
||||
EXTERN_CVAR (Float, gl_lights_intensity);
|
||||
EXTERN_CVAR (Float, gl_lights_size);
|
||||
EXTERN_CVAR (Bool, gl_lights_additive);
|
||||
EXTERN_CVAR (Bool, gl_light_sprites);
|
||||
EXTERN_CVAR (Bool, gl_light_particles);
|
||||
|
||||
EXTERN_CVAR(Int, gl_fogmode)
|
||||
EXTERN_CVAR(Int, gl_lightmode)
|
||||
EXTERN_CVAR(Bool,gl_mirror_envmap)
|
||||
|
||||
EXTERN_CVAR(Bool,gl_mirrors)
|
||||
EXTERN_CVAR(Bool,gl_mirror_envmap)
|
||||
EXTERN_CVAR(Bool, gl_seamless)
|
||||
|
||||
EXTERN_CVAR(Float, gl_mask_threshold)
|
||||
EXTERN_CVAR(Float, gl_mask_sprite_threshold)
|
||||
|
||||
#endif // _GL_INTERN_H
|
541
src/gl/system/gl_framebuffer.cpp
Normal file
541
src/gl/system/gl_framebuffer.cpp
Normal file
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
** gl_framebuffer.cpp
|
||||
** Implementation of the non-hardware specific parts of the
|
||||
** OpenGL frame buffer
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2000-2007 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "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 "farchive.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/textures/gl_hwtexture.h"
|
||||
#include "gl/textures/gl_texture.h"
|
||||
#include "gl/textures/gl_translate.h"
|
||||
#include "gl/textures/gl_skyboxtexture.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/utility/gl_templates.h"
|
||||
#include "gl/gl_functions.h"
|
||||
|
||||
IMPLEMENT_CLASS(OpenGLFrameBuffer)
|
||||
EXTERN_CVAR (Float, vid_brightness)
|
||||
EXTERN_CVAR (Float, vid_contrast)
|
||||
EXTERN_CVAR (Bool, vid_vsync)
|
||||
|
||||
CVAR(Bool, gl_aalines, false, CVAR_ARCHIVE)
|
||||
|
||||
FGLRenderer *GLRenderer;
|
||||
|
||||
void gl_LoadExtensions();
|
||||
void gl_PrintStartupLog();
|
||||
void gl_SetupMenu();
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen) :
|
||||
Super(hMonitor, width, height, bits, refreshHz, fullscreen)
|
||||
{
|
||||
GLRenderer = new FGLRenderer(this);
|
||||
memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256);
|
||||
UpdatePalette ();
|
||||
ScreenshotBuffer = NULL;
|
||||
LastCamera = NULL;
|
||||
|
||||
InitializeState();
|
||||
gl_SetupMenu();
|
||||
gl_GenerateGlobalBrightmapFromColormap();
|
||||
DoSetGamma();
|
||||
needsetgamma = true;
|
||||
swapped = false;
|
||||
Accel2D = true;
|
||||
SetVSync(vid_vsync);
|
||||
}
|
||||
|
||||
OpenGLFrameBuffer::~OpenGLFrameBuffer()
|
||||
{
|
||||
delete GLRenderer;
|
||||
GLRenderer = NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Initializes the GL renderer
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void OpenGLFrameBuffer::InitializeState()
|
||||
{
|
||||
static bool first=true;
|
||||
|
||||
if (first)
|
||||
{
|
||||
ogl_LoadFunctions();
|
||||
}
|
||||
|
||||
gl_LoadExtensions();
|
||||
Super::InitializeState();
|
||||
|
||||
if (first)
|
||||
{
|
||||
first=false;
|
||||
// [BB] For some reason this crashes, if compiled with MinGW and optimization. Has to be investigated.
|
||||
#ifdef _MSC_VER
|
||||
gl_PrintStartupLog();
|
||||
#endif
|
||||
|
||||
}
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glClearDepth(1.0f);
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
glEnable(GL_DITHER);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glEnable(GL_POLYGON_OFFSET_LINE);
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_DEPTH_CLAMP);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
int trueH = GetTrueHeight();
|
||||
int h = GetHeight();
|
||||
glViewport(0, (trueH - h)/2, GetWidth(), GetHeight());
|
||||
|
||||
Begin2D(false);
|
||||
GLRenderer->Initialize();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Updates the screen
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
// Testing only for now.
|
||||
CVAR(Bool, gl_draw_sync, true, 0) //false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
void OpenGLFrameBuffer::Update()
|
||||
{
|
||||
if (!CanUpdate())
|
||||
{
|
||||
GLRenderer->Flush();
|
||||
return;
|
||||
}
|
||||
|
||||
Begin2D(false);
|
||||
|
||||
DrawRateStuff();
|
||||
GLRenderer->Flush();
|
||||
|
||||
if (GetTrueHeight() != GetHeight())
|
||||
{
|
||||
if (GLRenderer != NULL)
|
||||
GLRenderer->ClearBorders();
|
||||
|
||||
Begin2D(false);
|
||||
}
|
||||
if (gl_draw_sync || !swapped)
|
||||
{
|
||||
Swap();
|
||||
}
|
||||
swapped = false;
|
||||
Unlock();
|
||||
CheckBench();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Swap the buffers
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void OpenGLFrameBuffer::Swap()
|
||||
{
|
||||
Finish.Reset();
|
||||
Finish.Clock();
|
||||
glFinish();
|
||||
if (needsetgamma)
|
||||
{
|
||||
//DoSetGamma();
|
||||
needsetgamma = false;
|
||||
}
|
||||
SwapBuffers();
|
||||
Finish.Unclock();
|
||||
swapped = true;
|
||||
FHardwareTexture::UnbindAll();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// DoSetGamma
|
||||
//
|
||||
// (Unfortunately Windows has some safety precautions that block gamma ramps
|
||||
// that are considered too extreme. As a result this doesn't work flawlessly)
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void OpenGLFrameBuffer::DoSetGamma()
|
||||
{
|
||||
WORD gammaTable[768];
|
||||
|
||||
if (m_supportsGamma)
|
||||
{
|
||||
// This formula is taken from Doomsday
|
||||
float gamma = clamp<float>(Gamma, 0.1f, 4.f);
|
||||
float contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
|
||||
float bright = clamp<float>(vid_brightness, -0.8f, 0.8f);
|
||||
|
||||
double invgamma = 1 / gamma;
|
||||
double norm = pow(255., invgamma - 1);
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
double val = i * contrast - (contrast - 1) * 127;
|
||||
if(gamma != 1) val = pow(val, invgamma) / norm;
|
||||
val += bright * 128;
|
||||
|
||||
gammaTable[i] = gammaTable[i + 256] = gammaTable[i + 512] = (WORD)clamp<double>(val*256, 0, 0xffff);
|
||||
}
|
||||
SetGammaTable(gammaTable);
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenGLFrameBuffer::SetGamma(float gamma)
|
||||
{
|
||||
DoSetGamma();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLFrameBuffer::SetBrightness(float bright)
|
||||
{
|
||||
DoSetGamma();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLFrameBuffer::SetContrast(float contrast)
|
||||
{
|
||||
DoSetGamma();
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void OpenGLFrameBuffer::UpdatePalette()
|
||||
{
|
||||
int rr=0,gg=0,bb=0;
|
||||
for(int x=0;x<256;x++)
|
||||
{
|
||||
rr+=GPalette.BaseColors[x].r;
|
||||
gg+=GPalette.BaseColors[x].g;
|
||||
bb+=GPalette.BaseColors[x].b;
|
||||
}
|
||||
rr>>=8;
|
||||
gg>>=8;
|
||||
bb>>=8;
|
||||
|
||||
palette_brightness = (rr*77 + gg*143 + bb*35)/255;
|
||||
}
|
||||
|
||||
void OpenGLFrameBuffer::GetFlashedPalette (PalEntry pal[256])
|
||||
{
|
||||
memcpy(pal, SourcePalette, 256*sizeof(PalEntry));
|
||||
}
|
||||
|
||||
PalEntry *OpenGLFrameBuffer::GetPalette ()
|
||||
{
|
||||
return SourcePalette;
|
||||
}
|
||||
|
||||
bool OpenGLFrameBuffer::SetFlash(PalEntry rgb, int amount)
|
||||
{
|
||||
Flash = PalEntry(amount, rgb.r, rgb.g, rgb.b);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLFrameBuffer::GetFlash(PalEntry &rgb, int &amount)
|
||||
{
|
||||
rgb = Flash;
|
||||
rgb.a = 0;
|
||||
amount = Flash.a;
|
||||
}
|
||||
|
||||
int OpenGLFrameBuffer::GetPageCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void OpenGLFrameBuffer::GetHitlist(BYTE *hitlist)
|
||||
{
|
||||
Super::GetHitlist(hitlist);
|
||||
|
||||
// check skybox textures and mark the separate faces as used
|
||||
for(int i=0;i<TexMan.NumTextures(); i++)
|
||||
{
|
||||
// HIT_Wall must be checked for MBF-style sky transfers.
|
||||
if (hitlist[i] & (FTextureManager::HIT_Sky|FTextureManager::HIT_Wall))
|
||||
{
|
||||
FTexture *tex = TexMan.ByIndex(i);
|
||||
if (tex->gl_info.bSkybox)
|
||||
{
|
||||
FSkyBox *sb = static_cast<FSkyBox*>(tex);
|
||||
for(int i=0;i<6;i++)
|
||||
{
|
||||
if (sb->faces[i])
|
||||
{
|
||||
int index = sb->faces[i]->id.GetIndex();
|
||||
hitlist[index] |= FTextureManager::HIT_Flat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check model skins
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: CreatePalette
|
||||
//
|
||||
// Creates a native palette from a remap table, if supported.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FNativePalette *OpenGLFrameBuffer::CreatePalette(FRemapTable *remap)
|
||||
{
|
||||
return GLTranslationPalette::CreatePalette(remap);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
bool OpenGLFrameBuffer::Begin2D(bool)
|
||||
{
|
||||
gl_RenderState.mViewMatrix.loadIdentity();
|
||||
gl_RenderState.mProjectionMatrix.ortho(0, GetWidth(), GetHeight(), 0, -1.0f, 1.0f);
|
||||
gl_RenderState.ApplyMatrices();
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Korshun: ENABLE AUTOMAP ANTIALIASING!!!
|
||||
if (gl_aalines)
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
else
|
||||
{
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glLineWidth(1.0);
|
||||
}
|
||||
|
||||
if (GLRenderer != NULL)
|
||||
GLRenderer->Begin2D();
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Draws a texture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void STACK_ARGS OpenGLFrameBuffer::DrawTextureV(FTexture *img, double x0, double y0, uint32 tag, va_list tags)
|
||||
{
|
||||
DrawParms parms;
|
||||
|
||||
if (ParseDrawTextureTags(img, x0, y0, tag, tags, &parms, true))
|
||||
{
|
||||
if (GLRenderer != NULL) GLRenderer->DrawTexture(img, parms);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void OpenGLFrameBuffer::DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color)
|
||||
{
|
||||
if (GLRenderer != NULL)
|
||||
GLRenderer->DrawLine(x1, y1, x2, y2, palcolor, color);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void OpenGLFrameBuffer::DrawPixel(int x1, int y1, int palcolor, uint32 color)
|
||||
{
|
||||
if (GLRenderer != NULL)
|
||||
GLRenderer->DrawPixel(x1, y1, palcolor, color);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void OpenGLFrameBuffer::Dim(PalEntry)
|
||||
{
|
||||
// Unlike in the software renderer the color is being ignored here because
|
||||
// view blending only affects the actual view with the GL renderer.
|
||||
Super::Dim(0);
|
||||
}
|
||||
|
||||
void OpenGLFrameBuffer::Dim(PalEntry color, float damount, int x1, int y1, int w, int h)
|
||||
{
|
||||
if (GLRenderer != NULL)
|
||||
GLRenderer->Dim(color, damount, x1, y1, w, h);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void OpenGLFrameBuffer::FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin)
|
||||
{
|
||||
|
||||
if (GLRenderer != NULL)
|
||||
GLRenderer->FlatFill(left, top, right, bottom, src, local_origin);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void OpenGLFrameBuffer::Clear(int left, int top, int right, int bottom, int palcolor, uint32 color)
|
||||
{
|
||||
if (GLRenderer != NULL)
|
||||
GLRenderer->Clear(left, top, right, bottom, palcolor, color);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// D3DFB :: FillSimplePoly
|
||||
//
|
||||
// Here, "simple" means that a simple triangle fan can draw it.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void OpenGLFrameBuffer::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley,
|
||||
angle_t rotation, FDynamicColormap *colormap, int lightlevel)
|
||||
{
|
||||
if (GLRenderer != NULL)
|
||||
{
|
||||
GLRenderer->FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley,
|
||||
rotation, colormap, lightlevel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Takes a screenshot
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void OpenGLFrameBuffer::GetScreenshotBuffer(const BYTE *&buffer, int &pitch, ESSType &color_type)
|
||||
{
|
||||
int w = SCREENWIDTH;
|
||||
int h = SCREENHEIGHT;
|
||||
|
||||
ReleaseScreenshotBuffer();
|
||||
ScreenshotBuffer = new BYTE[w * h * 3];
|
||||
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(0,(GetTrueHeight() - GetHeight()) / 2,w,h,GL_RGB,GL_UNSIGNED_BYTE,ScreenshotBuffer);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
pitch = -w*3;
|
||||
color_type = SS_RGB;
|
||||
buffer = ScreenshotBuffer + w * 3 * (h - 1);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Releases the screenshot buffer.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void OpenGLFrameBuffer::ReleaseScreenshotBuffer()
|
||||
{
|
||||
if (ScreenshotBuffer != NULL) delete [] ScreenshotBuffer;
|
||||
ScreenshotBuffer = NULL;
|
||||
}
|
||||
|
||||
|
||||
void OpenGLFrameBuffer::GameRestart()
|
||||
{
|
||||
memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256);
|
||||
UpdatePalette ();
|
||||
ScreenshotBuffer = NULL;
|
||||
LastCamera = NULL;
|
||||
gl_GenerateGlobalBrightmapFromColormap();
|
||||
}
|
||||
|
117
src/gl/system/gl_framebuffer.h
Normal file
117
src/gl/system/gl_framebuffer.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
#ifndef __GL_FRAMEBUFFER
|
||||
#define __GL_FRAMEBUFFER
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "win32iface.h"
|
||||
#include "win32gliface.h"
|
||||
#endif
|
||||
|
||||
class FHardwareTexture;
|
||||
|
||||
extern long gl_frameMS;
|
||||
extern long gl_frameCount;
|
||||
#ifdef _WIN32
|
||||
class OpenGLFrameBuffer : public Win32GLFrameBuffer
|
||||
{
|
||||
typedef Win32GLFrameBuffer Super;
|
||||
DECLARE_CLASS(OpenGLFrameBuffer, Win32GLFrameBuffer)
|
||||
#else
|
||||
#include "sdlglvideo.h"
|
||||
class OpenGLFrameBuffer : public SDLGLFB
|
||||
{
|
||||
// typedef SDLGLFB Super; //[C]commented, DECLARE_CLASS defines this in linux
|
||||
DECLARE_CLASS(OpenGLFrameBuffer, SDLGLFB)
|
||||
#endif
|
||||
|
||||
|
||||
public:
|
||||
|
||||
explicit OpenGLFrameBuffer() {}
|
||||
OpenGLFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen) ;
|
||||
~OpenGLFrameBuffer();
|
||||
|
||||
void InitializeState();
|
||||
void Update();
|
||||
|
||||
// Color correction
|
||||
bool SetGamma (float gamma);
|
||||
bool SetBrightness(float bright);
|
||||
bool SetContrast(float contrast);
|
||||
void DoSetGamma();
|
||||
|
||||
void UpdatePalette();
|
||||
void GetFlashedPalette (PalEntry pal[256]);
|
||||
PalEntry *GetPalette ();
|
||||
bool SetFlash(PalEntry rgb, int amount);
|
||||
void GetFlash(PalEntry &rgb, int &amount);
|
||||
int GetPageCount();
|
||||
bool Begin2D(bool copy3d);
|
||||
void GetHitlist(BYTE *hitlist);
|
||||
void GameRestart();
|
||||
|
||||
// Retrieves a buffer containing image data for a screenshot.
|
||||
// Hint: Pitch can be negative for upside-down images, in which case buffer
|
||||
// points to the last row in the buffer, which will be the first row output.
|
||||
virtual void GetScreenshotBuffer(const BYTE *&buffer, int &pitch, ESSType &color_type);
|
||||
|
||||
// Releases the screenshot buffer.
|
||||
virtual void ReleaseScreenshotBuffer();
|
||||
|
||||
// 2D drawing
|
||||
void STACK_ARGS DrawTextureV(FTexture *img, double x, double y, uint32 tag, va_list tags);
|
||||
void DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color);
|
||||
void DrawPixel(int x1, int y1, int palcolor, uint32 color);
|
||||
void Clear(int left, int top, int right, int bottom, int palcolor, uint32 color);
|
||||
void Dim(PalEntry color=0);
|
||||
void Dim (PalEntry color, float damount, int x1, int y1, int w, int h);
|
||||
void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin=false);
|
||||
|
||||
void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley,
|
||||
angle_t rotation, FDynamicColormap *colormap, int lightlevel);
|
||||
|
||||
FNativePalette *CreatePalette(FRemapTable *remap);
|
||||
|
||||
bool WipeStartScreen(int type);
|
||||
void WipeEndScreen();
|
||||
bool WipeDo(int ticks);
|
||||
void WipeCleanup();
|
||||
void Swap();
|
||||
bool Is8BitMode() { return false; }
|
||||
|
||||
|
||||
private:
|
||||
PalEntry Flash;
|
||||
|
||||
// Texture creation info
|
||||
int cm;
|
||||
int translation;
|
||||
bool iscomplex;
|
||||
bool needsetgamma;
|
||||
bool swapped;
|
||||
|
||||
PalEntry SourcePalette[256];
|
||||
BYTE *ScreenshotBuffer;
|
||||
|
||||
class Wiper
|
||||
{
|
||||
public:
|
||||
virtual ~Wiper();
|
||||
virtual bool Run(int ticks, OpenGLFrameBuffer *fb) = 0;
|
||||
};
|
||||
|
||||
class Wiper_Melt; friend class Wiper_Melt;
|
||||
class Wiper_Burn; friend class Wiper_Burn;
|
||||
class Wiper_Crossfade; friend class Wiper_Crossfade;
|
||||
|
||||
Wiper *ScreenWipe;
|
||||
FHardwareTexture *wipestartscreen;
|
||||
FHardwareTexture *wipeendscreen;
|
||||
|
||||
public:
|
||||
AActor * LastCamera;
|
||||
int palette_brightness;
|
||||
};
|
||||
|
||||
|
||||
#endif //__GL_FRAMEBUFFER
|
211
src/gl/system/gl_interface.cpp
Normal file
211
src/gl/system/gl_interface.cpp
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
** r_opengl.cpp
|
||||
**
|
||||
** OpenGL system interface
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005 Tim Stump
|
||||
** Copyright 2005-2013 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.
|
||||
** 4. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "tarray.h"
|
||||
#include "doomtype.h"
|
||||
#include "m_argv.h"
|
||||
#include "zstring.h"
|
||||
#include "version.h"
|
||||
#include "i_system.h"
|
||||
#include "v_text.h"
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
|
||||
static TArray<FString> m_Extensions;
|
||||
|
||||
RenderContext gl;
|
||||
|
||||
int occlusion_type=0;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void CollectExtensions()
|
||||
{
|
||||
const char *extension;
|
||||
|
||||
int max = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &max);
|
||||
|
||||
for(int i = 0; i < max; i++)
|
||||
{
|
||||
extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||
m_Extensions.Push(FString(extension));
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static bool CheckExtension(const char *ext)
|
||||
{
|
||||
for (unsigned int i = 0; i < m_Extensions.Size(); ++i)
|
||||
{
|
||||
if (m_Extensions[i].CompareNoCase(ext) == 0) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void InitContext()
|
||||
{
|
||||
gl.flags=0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_LoadExtensions()
|
||||
{
|
||||
InitContext();
|
||||
CollectExtensions();
|
||||
|
||||
const char *version = Args->CheckValue("-glversion");
|
||||
if (version == NULL) version = (const char*)glGetString(GL_VERSION);
|
||||
else Printf("Emulating OpenGL v %s\n", version);
|
||||
|
||||
// Don't even start if it's lower than 3.0
|
||||
if (strcmp(version, "3.0") < 0)
|
||||
{
|
||||
I_FatalError("Unsupported OpenGL version.\nAt least OpenGL 3.0 is required to run " GAMENAME ".\n");
|
||||
}
|
||||
|
||||
// add 0.01 to account for roundoff errors making the number a tad smaller than the actual version
|
||||
gl.version = strtod(version, NULL) + 0.01f;
|
||||
gl.glslversion = strtod((char*)glGetString(GL_SHADING_LANGUAGE_VERSION), NULL) + 0.01f;
|
||||
|
||||
gl.vendorstring = (char*)glGetString(GL_VENDOR);
|
||||
|
||||
if (gl.version < 3.3f && !CheckExtension("GL_ARB_sampler_objects"))
|
||||
{
|
||||
I_FatalError("'GL_ARB_sampler_objects' extension not found. Please update your graphics driver.");
|
||||
}
|
||||
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 (!Args->CheckParm("-gl3"))
|
||||
{
|
||||
// don't use GL 4.x features when running in GL 3 emulation mode.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
int v;
|
||||
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &v);
|
||||
gl.maxuniforms = v;
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &v);
|
||||
gl.maxuniformblock = v;
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &v);
|
||||
gl.uniformblockalignment = v;
|
||||
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE,&gl.max_texturesize);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_PrintStartupLog()
|
||||
{
|
||||
int v = 0;
|
||||
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &v);
|
||||
|
||||
Printf ("GL_VENDOR: %s\n", glGetString(GL_VENDOR));
|
||||
Printf ("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
|
||||
Printf ("GL_VERSION: %s (%s profile)\n", glGetString(GL_VERSION), (v & GL_CONTEXT_CORE_PROFILE_BIT)? "Core" : "Compatibility");
|
||||
Printf ("GL_SHADING_LANGUAGE_VERSION: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
Printf ("GL_EXTENSIONS:");
|
||||
for (unsigned i = 0; i < m_Extensions.Size(); i++)
|
||||
{
|
||||
Printf(" %s", m_Extensions[i].GetChars());
|
||||
}
|
||||
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &v);
|
||||
Printf("\nMax. texture size: %d\n", v);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &v);
|
||||
Printf ("Max. texture units: %d\n", v);
|
||||
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &v);
|
||||
Printf ("Max. fragment uniforms: %d\n", v);
|
||||
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &v);
|
||||
Printf ("Max. vertex uniforms: %d\n", v);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &v);
|
||||
Printf ("Max. uniform block size: %d\n", v);
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &v);
|
||||
Printf ("Uniform block alignment: %d\n", v);
|
||||
|
||||
glGetIntegerv(GL_MAX_VARYING_FLOATS, &v);
|
||||
Printf ("Max. varying: %d\n", v);
|
||||
glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &v);
|
||||
Printf("Max. combined shader storage blocks: %d\n", v);
|
||||
glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &v);
|
||||
Printf("Max. vertex shader storage blocks: %d\n", v);
|
||||
|
||||
|
||||
}
|
||||
|
46
src/gl/system/gl_interface.h
Normal file
46
src/gl/system/gl_interface.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#ifndef R_RENDER
|
||||
#define R_RENDER
|
||||
|
||||
#include "basictypes.h"
|
||||
|
||||
enum RenderFlags
|
||||
{
|
||||
// [BB] Added texture compression flags.
|
||||
RFL_TEXTURE_COMPRESSION=1,
|
||||
RFL_TEXTURE_COMPRESSION_S3TC=2,
|
||||
|
||||
RFL_SHADER_STORAGE_BUFFER = 4,
|
||||
RFL_BUFFER_STORAGE = 8
|
||||
};
|
||||
|
||||
enum TexMode
|
||||
{
|
||||
TM_MODULATE = 0, // (r, g, b, a)
|
||||
TM_MASK, // (1, 1, 1, a)
|
||||
TM_OPAQUE, // (r, g, b, 1)
|
||||
TM_INVERSE, // (1-r, 1-g, 1-b, a)
|
||||
TM_REDTOALPHA, // (1, 1, 1, r)
|
||||
TM_CLAMPY, // (r, g, b, (t >= 0.0 && t <= 1.0)? a:0)
|
||||
};
|
||||
|
||||
struct RenderContext
|
||||
{
|
||||
unsigned int flags;
|
||||
unsigned int maxuniforms;
|
||||
unsigned int maxuniformblock;
|
||||
unsigned int uniformblockalignment;
|
||||
float version;
|
||||
float glslversion;
|
||||
int max_texturesize;
|
||||
char * vendorstring;
|
||||
|
||||
int MaxLights() const
|
||||
{
|
||||
return maxuniforms>=2048? 128:64;
|
||||
}
|
||||
};
|
||||
|
||||
extern RenderContext gl;
|
||||
|
||||
#endif
|
||||
|
1346
src/gl/system/gl_load.c
Normal file
1346
src/gl/system/gl_load.c
Normal file
File diff suppressed because it is too large
Load diff
1793
src/gl/system/gl_load.h
Normal file
1793
src/gl/system/gl_load.h
Normal file
File diff suppressed because it is too large
Load diff
74
src/gl/system/gl_menu.cpp
Normal file
74
src/gl/system/gl_menu.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
|
||||
|
||||
#include "gl/system/gl_system.h"
|
||||
#include "c_cvars.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "v_video.h"
|
||||
#include "version.h"
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "menu/menu.h"
|
||||
|
||||
|
||||
|
||||
// OpenGL stuff moved here
|
||||
// GL related CVARs
|
||||
CVAR(Bool, gl_portals, true, 0)
|
||||
CVAR(Bool, gl_noquery, false, 0)
|
||||
CVAR(Bool,gl_mirrors,true,0) // This is for debugging only!
|
||||
CVAR(Bool,gl_mirror_envmap, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
|
||||
CVAR(Bool, gl_seamless, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
CUSTOM_CVAR(Int, r_mirror_recursions,4,CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
|
||||
{
|
||||
if (self<0) self=0;
|
||||
if (self>10) self=10;
|
||||
}
|
||||
bool gl_plane_reflection_i; // This is needed in a header that cannot include the CVAR stuff...
|
||||
CUSTOM_CVAR(Bool, gl_plane_reflection, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
|
||||
{
|
||||
gl_plane_reflection_i = self;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, gl_render_precise, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
gl_seamless=self;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR (Float, vid_brightness, 0.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (screen != NULL)
|
||||
{
|
||||
screen->SetGamma(Gamma); //Brightness (self);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR (Float, vid_contrast, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (screen != NULL)
|
||||
{
|
||||
screen->SetGamma(Gamma); //SetContrast (self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Do some tinkering with the menus so that certain options only appear
|
||||
// when they are actually valid.
|
||||
void gl_SetupMenu()
|
||||
{
|
||||
#ifndef HAVE_MMX
|
||||
FOptionValues **opt = OptionValues.CheckKey("HqResizeModes");
|
||||
if (opt != NULL)
|
||||
{
|
||||
for(int i = (*opt)->mValues.Size()-1; i>=0; i--)
|
||||
{
|
||||
// Delete HQnX resize modes for non MSVC targets
|
||||
if ((*opt)->mValues[i].Value >= 7.0)
|
||||
{
|
||||
(*opt)->mValues.Delete(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
121
src/gl/system/gl_system.h
Normal file
121
src/gl/system/gl_system.h
Normal file
|
@ -0,0 +1,121 @@
|
|||
#ifndef __GL_PCH_H
|
||||
#define __GL_PCH_H
|
||||
#ifdef _WIN32
|
||||
//#define __RPCNDR_H__ // this header causes problems!
|
||||
//#define __wtypes_h__
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define _WIN32_WINDOWS 0x410
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501 // Support the mouse wheel and session notification.
|
||||
#define _WIN32_IE 0x0500
|
||||
#endif
|
||||
#define DIRECTINPUT_VERSION 0x800
|
||||
#define DIRECTDRAW_VERSION 0x0300
|
||||
|
||||
#define DWORD WINDOWS_DWORD // I don't want to depend on this throughout the GL code!
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4995) // MIPS
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <winsock.h>
|
||||
#ifndef __WINE__
|
||||
#include <dshow.h>
|
||||
#endif
|
||||
#include <d3d9.h>
|
||||
//#include <dsound.h>
|
||||
//#include <dinput.h>
|
||||
//#include <lmcons.h>
|
||||
//#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
#undef DWORD
|
||||
#ifndef CALLBACK
|
||||
#define CALLBACK
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
//#include <direct.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define F_OK 0 /* Check for file existence */
|
||||
#define W_OK 2 /* Check for write permission */
|
||||
#define R_OK 4 /* Check for read permission */
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
//GL headers
|
||||
#include "gl_load.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DWORD WINDOWS_DWORD // I don't want to depend on this throughout the GL code!
|
||||
//#include "gl/api/wglext.h"
|
||||
#ifndef __WINE__
|
||||
#undef DWORD
|
||||
#endif
|
||||
#else
|
||||
typedef unsigned char byte;
|
||||
typedef float FLOAT;
|
||||
template <typename T>
|
||||
inline T max( T a, T b) { return (((a)>(b)) ? (a) : (b)); }
|
||||
#define __cdecl
|
||||
#define _access(a,b) access(a,b)
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
#include <SDL.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef LoadMenu
|
||||
#undef LoadMenu
|
||||
#endif
|
||||
#ifdef DrawText
|
||||
#undef DrawText
|
||||
#endif
|
||||
#ifdef GetCharWidth
|
||||
#undef GetCharWidth
|
||||
#endif
|
||||
|
||||
#undef S_NORMAL
|
||||
#undef OPAQUE
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4244) // MIPS
|
||||
#pragma warning(disable : 4136) // X86
|
||||
#pragma warning(disable : 4051) // ALPHA
|
||||
|
||||
#pragma warning(disable : 4018) // signed/unsigned mismatch
|
||||
#pragma warning(disable : 4305) // truncate from double to float
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#undef WIN32
|
||||
#endif
|
||||
#endif //__GL_PCH_H
|
0
src/gl/system/gl_threads.cpp
Normal file
0
src/gl/system/gl_threads.cpp
Normal file
529
src/gl/system/gl_wipe.cpp
Normal file
529
src/gl/system/gl_wipe.cpp
Normal file
|
@ -0,0 +1,529 @@
|
|||
/*
|
||||
** gl_wipe.cpp
|
||||
** Screen wipe stuff
|
||||
** (This uses immediate mode and the fixed function pipeline
|
||||
** even if the new renderer is active)
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include "files.h"
|
||||
#include "f_wipe.h"
|
||||
#include "m_random.h"
|
||||
#include "w_wad.h"
|
||||
#include "v_palette.h"
|
||||
#include "templates.h"
|
||||
#include "vectors.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/textures/gl_translate.h"
|
||||
#include "gl/textures/gl_material.h"
|
||||
#include "gl/textures/gl_samplers.h"
|
||||
#include "gl/utility/gl_templates.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
struct POINT {
|
||||
SDWORD x;
|
||||
SDWORD y;
|
||||
};
|
||||
struct RECT {
|
||||
SDWORD left;
|
||||
SDWORD top;
|
||||
SDWORD right;
|
||||
SDWORD bottom;
|
||||
};
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Screen wipes
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
class OpenGLFrameBuffer::Wiper_Crossfade : public OpenGLFrameBuffer::Wiper
|
||||
{
|
||||
public:
|
||||
Wiper_Crossfade();
|
||||
bool Run(int ticks, OpenGLFrameBuffer *fb);
|
||||
|
||||
private:
|
||||
int Clock;
|
||||
};
|
||||
|
||||
class OpenGLFrameBuffer::Wiper_Melt : public OpenGLFrameBuffer::Wiper
|
||||
{
|
||||
public:
|
||||
Wiper_Melt();
|
||||
bool Run(int ticks, OpenGLFrameBuffer *fb);
|
||||
|
||||
private:
|
||||
static const int WIDTH = 320, HEIGHT = 200;
|
||||
int y[WIDTH];
|
||||
};
|
||||
|
||||
class OpenGLFrameBuffer::Wiper_Burn : public OpenGLFrameBuffer::Wiper
|
||||
{
|
||||
public:
|
||||
Wiper_Burn();
|
||||
~Wiper_Burn();
|
||||
bool Run(int ticks, OpenGLFrameBuffer *fb);
|
||||
|
||||
private:
|
||||
static const int WIDTH = 64, HEIGHT = 64;
|
||||
BYTE BurnArray[WIDTH * (HEIGHT + 5)];
|
||||
FHardwareTexture *BurnTexture;
|
||||
int Density;
|
||||
int BurnTime;
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: 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.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool OpenGLFrameBuffer::WipeStartScreen(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case wipe_Burn:
|
||||
ScreenWipe = new Wiper_Burn;
|
||||
break;
|
||||
|
||||
case wipe_Fade:
|
||||
ScreenWipe = new Wiper_Crossfade;
|
||||
break;
|
||||
|
||||
case wipe_Melt:
|
||||
ScreenWipe = new Wiper_Melt;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
wipestartscreen = new FHardwareTexture(Width, Height, true);
|
||||
wipestartscreen->CreateTexture(NULL, Width, Height, 0, false, 0);
|
||||
GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER);
|
||||
GLRenderer->mSamplerManager->Bind(1, CLAMP_NONE);
|
||||
glFinish();
|
||||
wipestartscreen->Bind(0, false, false);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: WipeEndScreen
|
||||
//
|
||||
// The screen we want to animate to has just been drawn.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void OpenGLFrameBuffer::WipeEndScreen()
|
||||
{
|
||||
wipeendscreen = new FHardwareTexture(Width, Height, true);
|
||||
wipeendscreen->CreateTexture(NULL, Width, Height, 0, false, 0);
|
||||
GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER);
|
||||
glFinish();
|
||||
wipeendscreen->Bind(0, false, false);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
Unlock();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: 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 OpenGLFrameBuffer::WipeDo(int ticks)
|
||||
{
|
||||
// Sanity checks.
|
||||
if (wipestartscreen == NULL || wipeendscreen == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Lock(true);
|
||||
|
||||
gl_RenderState.EnableTexture(true);
|
||||
gl_RenderState.EnableFog(false);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(false);
|
||||
|
||||
bool done = ScreenWipe->Run(ticks, this);
|
||||
glDepthMask(true);
|
||||
//DrawLetterbox();
|
||||
return done;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: WipeCleanup
|
||||
//
|
||||
// Release any resources that were specifically created for the wipe.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void OpenGLFrameBuffer::WipeCleanup()
|
||||
{
|
||||
if (ScreenWipe != NULL)
|
||||
{
|
||||
delete ScreenWipe;
|
||||
ScreenWipe = NULL;
|
||||
}
|
||||
if (wipestartscreen != NULL)
|
||||
{
|
||||
delete wipestartscreen;
|
||||
wipestartscreen = NULL;
|
||||
}
|
||||
if (wipeendscreen != NULL)
|
||||
{
|
||||
delete wipeendscreen;
|
||||
wipeendscreen = NULL;
|
||||
}
|
||||
FMaterial::ClearLastTexture();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: Wiper Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
OpenGLFrameBuffer::Wiper::~Wiper()
|
||||
{
|
||||
}
|
||||
|
||||
// WIPE: CROSSFADE ---------------------------------------------------------
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: Wiper_Crossfade Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
OpenGLFrameBuffer::Wiper_Crossfade::Wiper_Crossfade()
|
||||
: Clock(0)
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: Wiper_Crossfade :: Run
|
||||
//
|
||||
// Fades the old screen into the new one over 32 ticks.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool OpenGLFrameBuffer::Wiper_Crossfade::Run(int ticks, OpenGLFrameBuffer *fb)
|
||||
{
|
||||
Clock += ticks;
|
||||
|
||||
float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth());
|
||||
float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight());
|
||||
|
||||
gl_RenderState.SetTextureMode(TM_OPAQUE);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
||||
gl_RenderState.ResetColor();
|
||||
gl_RenderState.Apply();
|
||||
fb->wipestartscreen->Bind(0, 0, false);
|
||||
|
||||
FFlatVertex *ptr;
|
||||
unsigned int offset, count;
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(0, 0, 0, 0, vb);
|
||||
ptr++;
|
||||
ptr->Set(0, fb->Height, 0, 0, 0);
|
||||
ptr++;
|
||||
ptr->Set(fb->Width, 0, 0, ur, vb);
|
||||
ptr++;
|
||||
ptr->Set(fb->Width, fb->Height, 0, ur, 0);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP, &offset, &count);
|
||||
|
||||
fb->wipeendscreen->Bind(0, 0, false);
|
||||
gl_RenderState.SetColorAlpha(0xffffff, clamp(Clock/32.f, 0.f, 1.f));
|
||||
gl_RenderState.Apply();
|
||||
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f);
|
||||
gl_RenderState.SetTextureMode(TM_MODULATE);
|
||||
|
||||
return Clock >= 32;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: Wiper_Melt Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
OpenGLFrameBuffer::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);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: Wiper_Melt :: Run
|
||||
//
|
||||
// Fades the old screen into the new one over 32 ticks.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb)
|
||||
{
|
||||
float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth());
|
||||
float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight());
|
||||
|
||||
// Draw the new screen on the bottom.
|
||||
gl_RenderState.SetTextureMode(TM_OPAQUE);
|
||||
gl_RenderState.ResetColor();
|
||||
gl_RenderState.Apply();
|
||||
fb->wipeendscreen->Bind(0, 0, false);
|
||||
FFlatVertex *ptr;
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(0, 0, 0, 0, vb);
|
||||
ptr++;
|
||||
ptr->Set(0, fb->Height, 0, 0, 0);
|
||||
ptr++;
|
||||
ptr->Set(fb->Width, 0, 0, ur, vb);
|
||||
ptr++;
|
||||
ptr->Set(fb->Width, fb->Height, 0, ur, 0);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
|
||||
int i, dy;
|
||||
bool done = false;
|
||||
|
||||
fb->wipestartscreen->Bind(0, 0, false);
|
||||
// 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.
|
||||
// No need for optimization. Wipes won't ever be drawn with anything else.
|
||||
RECT rect;
|
||||
POINT dpt;
|
||||
|
||||
dpt.x = i * fb->Width / WIDTH;
|
||||
dpt.y = MAX(0, y[i] * fb->Height / HEIGHT);
|
||||
rect.left = dpt.x;
|
||||
rect.top = 0;
|
||||
rect.right = (i + 1) * fb->Width / WIDTH;
|
||||
rect.bottom = fb->Height - dpt.y;
|
||||
if (rect.bottom > rect.top)
|
||||
{
|
||||
float tw = (float)FHardwareTexture::GetTexDimension(fb->Width);
|
||||
float th = (float)FHardwareTexture::GetTexDimension(fb->Height);
|
||||
rect.bottom = fb->Height - rect.bottom;
|
||||
rect.top = fb->Height - rect.top;
|
||||
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(rect.left, rect.bottom, 0, rect.left / tw, rect.top / th);
|
||||
ptr++;
|
||||
ptr->Set(rect.left, rect.top, 0, rect.left / tw, rect.bottom / th);
|
||||
ptr++;
|
||||
ptr->Set(rect.right, rect.bottom, 0, rect.right / tw, rect.top / th);
|
||||
ptr++;
|
||||
ptr->Set(rect.right, rect.top, 0, rect.right / tw, rect.bottom / th);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gl_RenderState.SetTextureMode(TM_MODULATE);
|
||||
return done;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: Wiper_Burn Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
OpenGLFrameBuffer::Wiper_Burn::Wiper_Burn()
|
||||
{
|
||||
Density = 4;
|
||||
BurnTime = 0;
|
||||
memset(BurnArray, 0, sizeof(BurnArray));
|
||||
BurnTexture = NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: Wiper_Burn Destructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
OpenGLFrameBuffer::Wiper_Burn::~Wiper_Burn()
|
||||
{
|
||||
if (BurnTexture != NULL)
|
||||
{
|
||||
delete BurnTexture;
|
||||
BurnTexture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenGLFrameBuffer :: Wiper_Burn :: Run
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *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);
|
||||
}
|
||||
|
||||
if (BurnTexture != NULL) delete BurnTexture;
|
||||
BurnTexture = new FHardwareTexture(WIDTH, HEIGHT, true);
|
||||
|
||||
// Update the burn texture with the new burn data
|
||||
BYTE rgb_buffer[WIDTH*HEIGHT*4];
|
||||
|
||||
const BYTE *src = BurnArray;
|
||||
DWORD *dest = (DWORD *)rgb_buffer;
|
||||
for (int y = HEIGHT; y != 0; --y)
|
||||
{
|
||||
for (int x = WIDTH; x != 0; --x)
|
||||
{
|
||||
BYTE s = clamp<int>((*src++)*2, 0, 255);
|
||||
*dest++ = MAKEARGB(s,255,255,255);
|
||||
}
|
||||
}
|
||||
|
||||
float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth());
|
||||
float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight());
|
||||
|
||||
|
||||
// Put the initial screen back to the buffer.
|
||||
gl_RenderState.SetTextureMode(TM_OPAQUE);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
||||
gl_RenderState.ResetColor();
|
||||
gl_RenderState.Apply();
|
||||
fb->wipestartscreen->Bind(0, 0, false);
|
||||
FFlatVertex *ptr;
|
||||
unsigned int offset, count;
|
||||
ptr = GLRenderer->mVBO->GetBuffer();
|
||||
ptr->Set(0, 0, 0, 0, vb);
|
||||
ptr++;
|
||||
ptr->Set(0, fb->Height, 0, 0, 0);
|
||||
ptr++;
|
||||
ptr->Set(fb->Width, 0, 0, ur, vb);
|
||||
ptr++;
|
||||
ptr->Set(fb->Width, fb->Height, 0, ur, 0);
|
||||
ptr++;
|
||||
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP, &offset, &count);
|
||||
|
||||
gl_RenderState.SetTextureMode(TM_MODULATE);
|
||||
gl_RenderState.SetEffect(EFF_BURN);
|
||||
gl_RenderState.ResetColor();
|
||||
gl_RenderState.Apply();
|
||||
|
||||
// Burn the new screen on top of it.
|
||||
fb->wipeendscreen->Bind(0, 0, false);
|
||||
|
||||
BurnTexture->CreateTexture(rgb_buffer, WIDTH, HEIGHT, 1, true, 0);
|
||||
|
||||
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count);
|
||||
gl_RenderState.SetEffect(EFF_NONE);
|
||||
|
||||
// The fire may not always stabilize, so the wipe is forced to end
|
||||
// after an arbitrary maximum time.
|
||||
return done || (BurnTime > 40);
|
||||
}
|
156
src/gl/textures/gl_bitmap.cpp
Normal file
156
src/gl/textures/gl_bitmap.cpp
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
** gl_bitmap.cpp
|
||||
** Bitmap class for texture composition
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2004-2009 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
**
|
||||
** 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 "v_palette.h"
|
||||
#include "templates.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/textures/gl_translate.h"
|
||||
#include "gl/textures/gl_bitmap.h"
|
||||
#include "gl/system/gl_interface.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// multi-format pixel copy with colormap application
|
||||
// requires one of the previously defined conversion classes to work
|
||||
//
|
||||
//===========================================================================
|
||||
template<class T>
|
||||
void iCopyColors(unsigned char * pout, const unsigned char * pin, int count, int step)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0;i<count;i++)
|
||||
{
|
||||
if (T::A(pin) != 0)
|
||||
{
|
||||
pout[0]=T::R(pin);
|
||||
pout[1]=T::G(pin);
|
||||
pout[2]=T::B(pin);
|
||||
pout[3]=T::A(pin);
|
||||
}
|
||||
pout+=4;
|
||||
pin+=step;
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*CopyFunc)(unsigned char * pout, const unsigned char * pin, int count, int step);
|
||||
|
||||
static CopyFunc copyfuncs[]={
|
||||
iCopyColors<cRGB>,
|
||||
iCopyColors<cRGBA>,
|
||||
iCopyColors<cIA>,
|
||||
iCopyColors<cCMYK>,
|
||||
iCopyColors<cBGR>,
|
||||
iCopyColors<cBGRA>,
|
||||
iCopyColors<cI16>,
|
||||
iCopyColors<cRGB555>,
|
||||
iCopyColors<cPalEntry>
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// True Color texture copy function
|
||||
// This excludes all the cases that force downconversion to the
|
||||
// base palette because they wouldn't be used anyway.
|
||||
//
|
||||
//===========================================================================
|
||||
void FGLBitmap::CopyPixelDataRGB(int originx, int originy,
|
||||
const BYTE * patch, int srcwidth, int srcheight, int step_x, int step_y,
|
||||
int rotate, int ct, FCopyInfo *inf)
|
||||
{
|
||||
if (ClipCopyPixelRect(&ClipRect, originx, originy, patch, srcwidth, srcheight, step_x, step_y, rotate))
|
||||
{
|
||||
BYTE *buffer = GetPixels() + 4*originx + Pitch*originy;
|
||||
for (int y=0;y<srcheight;y++)
|
||||
{
|
||||
copyfuncs[ct](&buffer[y*Pitch], &patch[y*step_y], srcwidth, step_x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Paletted to True Color texture copy function
|
||||
//
|
||||
//===========================================================================
|
||||
void FGLBitmap::CopyPixelData(int originx, int originy, const BYTE * patch, int srcwidth, int srcheight,
|
||||
int step_x, int step_y, int rotate, PalEntry * palette, FCopyInfo *inf)
|
||||
{
|
||||
PalEntry penew[256];
|
||||
|
||||
int x,y,pos,i;
|
||||
|
||||
if (ClipCopyPixelRect(&ClipRect, originx, originy, patch, srcwidth, srcheight, step_x, step_y, rotate))
|
||||
{
|
||||
BYTE *buffer = GetPixels() + 4*originx + Pitch*originy;
|
||||
|
||||
if (translation > 0)
|
||||
{
|
||||
PalEntry *ptrans = GLTranslationPalette::GetPalette(translation);
|
||||
if (ptrans)
|
||||
{
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
penew[i] = (ptrans[i] & 0xffffff) | (palette[i] & 0xff000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(penew, palette, 256*sizeof(PalEntry));
|
||||
}
|
||||
|
||||
// convert the image according to the translated palette.
|
||||
for (y=0;y<srcheight;y++)
|
||||
{
|
||||
pos=(y*Pitch);
|
||||
for (x=0;x<srcwidth;x++,pos+=4)
|
||||
{
|
||||
int v=(unsigned char)patch[y*step_y+x*step_x];
|
||||
if (penew[v].a!=0)
|
||||
{
|
||||
buffer[pos] = penew[v].r;
|
||||
buffer[pos+1] = penew[v].g;
|
||||
buffer[pos+2] = penew[v].b;
|
||||
buffer[pos+3] = penew[v].a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue